Thanks to visit codestin.com
Credit goes to github.com

Skip to content

TagAwareAdapter over non-binary memcached connections corrupts memcache #27416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 8, 2018

Conversation

palex-fpt
Copy link

Q A
Branch? 3.4
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? no
Fixed tickets #27405
License MIT
Doc PR

TagAwareAdapter uses non-ascii symbols in key names. It breaks memcached connections in non-binary mode.

@nicolas-grekas
Copy link
Member

This approach doesn't work, eg. a simple space is also forbidden in keys when using the non binary protocol.

Instead of changing the prefix for all backends (which has the downside of invalidating all existing pools btw), we should consider encoding keys, only in the memcached adapter.

*
* @param $key
*/
private static function encodeKey($key)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to inline the function and remove the method.

@@ -49,6 +50,7 @@ private function init(\Memcached $client, $namespace, $defaultLifetime)
}
$this->maxIdLength -= strlen($client->getOption(\Memcached::OPT_PREFIX_KEY));
$this->client = $client;
$this->isTextProtocol = !$client->getOption(\Memcached::OPT_BINARY_PROTOCOL);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of always encoding the key, binary or not? That'd make the stored data independent from the actual protocol.

Copy link
Author

@palex-fpt palex-fpt May 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It adds some overhead. But it should not be high. There're two possible problems:

  1. client loses control over cache keys (mcrouter uses key names for app-level routing)
  2. non-symfony and/or non-php clients would have difficulties to share cache.

I don't share memcache with non-symfony apps, so I`m ok with it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's ok: the overhead should be negligible vs the network round-trips, and url encoding preserves most of the chars in the keys, making them still handleable.
Note that keys should be decoded on retrieval.

@@ -198,6 +200,12 @@ protected function doSave(array $values, $lifetime)
$lifetime += time();
}

if ($this->isTextProtocol) {
$encoded_values = array();
array_walk($values, function ($value, $key) use (&$encoded_values) { $encoded_values[rawurlencode($key)] = $value; });
Copy link
Member

@nicolas-grekas nicolas-grekas May 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I generally don't like array_walk(), too much references there. Should be done with a foreach instead.
The temp var should use camel case coding name also.

@nicolas-grekas
Copy link
Member

All methods should encode/decode on read/write. Some are missing for now.
LGTM otherwise thanks.

@nicolas-grekas
Copy link
Member

(but tests fail)

@@ -191,4 +192,29 @@ public function provideDsnWithOptions()
array(\Memcached::OPT_SOCKET_RECV_SIZE => 1, \Memcached::OPT_SOCKET_SEND_SIZE => 2, \Memcached::OPT_RETRY_TIMEOUT => 8),
);
}

public function testNonBinaryMemcachedMode()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding a few new tests for that, covering only a small part of the API, I think we should instead have a separate test case overriding createCachePool, to run the full adapter tests in non-binary mode

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MemcachedAdapterTest tests MemcachedAdapter::createConnection only. Should I add separate test classes to test MemcachedAdapter get, set, etc.. methods in text and binary modes?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like I should add key containing \0 and spaces into \Cache\IntegrationTests\SimpleCacheTest::validKeys

This way it would be tested against all cache implementations.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or rely on the namespace to do so?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added 'si\0mp le' key to \Cache\IntegrationTests\SimpleCacheTest::validKeys and ran tests local. All cache tests succeeded.

$encodedValues[rawurlencode($key)] = $value;
}

return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not decoding keys in the returned value. Can it have keys in it ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

\Memcached::setMulti returns bool. Did I missed something else?

@palex-fpt palex-fpt force-pushed the 27405 branch 2 times, most recently from 6ce07dd to 96c6cf9 Compare May 31, 2018 06:06
{
$client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), array('binary_protocol' => false)) : self::$client;

return new MemcachedCache($client, str_replace('\\', '.', __CLASS__), $defaultLifetime);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the 2nd arg here is the namespace and is part of the key passed to memcached, we could add \0 and spaces to test the encoding?

Copy link
Author

@palex-fpt palex-fpt Jun 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

base test \Symfony\Component\Cache\Tests\Simple\CacheTestCase::validKeys adds \0 to tested keys

@nicolas-grekas
Copy link
Member

Thank you @palex-fpt.

@nicolas-grekas nicolas-grekas merged commit 67d4e6d into symfony:3.4 Jun 8, 2018
nicolas-grekas added a commit that referenced this pull request Jun 8, 2018
…upts memcache (Aleksey Prilipko)

This PR was merged into the 3.4 branch.

Discussion
----------

TagAwareAdapter over non-binary memcached connections corrupts memcache

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | no
| Fixed tickets | #27405
| License       | MIT
| Doc PR        |

TagAwareAdapter uses non-ascii symbols in key names. It breaks memcached connections in non-binary mode.

Commits
-------

67d4e6d bug #27405 [Cache] TagAwareAdapter should not corrupt memcached connection in ascii mode
@palex-fpt palex-fpt deleted the 27405 branch June 9, 2018 00:03
This was referenced Jun 25, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants