-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
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
Conversation
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) |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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:
- client loses control over cache keys (mcrouter uses key names for app-level routing)
- 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.
There was a problem hiding this comment.
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; }); |
There was a problem hiding this comment.
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.
All methods should encode/decode on read/write. Some are missing for now. |
(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() |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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?
6ce07dd
to
96c6cf9
Compare
{ | ||
$client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), array('binary_protocol' => false)) : self::$client; | ||
|
||
return new MemcachedCache($client, str_replace('\\', '.', __CLASS__), $defaultLifetime); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
…d connection in ascii mode
Thank you @palex-fpt. |
…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
TagAwareAdapter uses non-ascii symbols in key names. It breaks memcached connections in non-binary mode.