diff --git a/swift/common/memcached.py b/swift/common/memcached.py index b7187da0e4..a80fa0fb6a 100644 --- a/swift/common/memcached.py +++ b/swift/common/memcached.py @@ -399,14 +399,17 @@ class MemcacheRing(object): """ return self.incr(key, delta=-delta, time=time) - def delete(self, key): + def delete(self, key, server_key=None): """ Deletes a key/value pair from memcache. :param key: key to be deleted + :param server_key: key to use in determining which server in the ring + is used """ key = md5hash(key) - for (server, fp, sock) in self._get_conns(key): + server_key = md5hash(server_key) if server_key else key + for (server, fp, sock) in self._get_conns(server_key): try: with Timeout(self._io_timeout): sock.sendall(b'delete ' + key + b'\r\n') diff --git a/test/unit/common/test_memcached.py b/test/unit/common/test_memcached.py index 3cbc698f40..26cfab555b 100644 --- a/test/unit/common/test_memcached.py +++ b/test/unit/common/test_memcached.py @@ -558,6 +558,44 @@ class TestMemcached(unittest.TestCase): None) self.assertFalse(not_expected in mock_stderr.getvalue()) + def test_multi_delete(self): + memcache_client = memcached.MemcacheRing(['1.2.3.4:11211', + '1.2.3.5:11211']) + mock1 = MockMemcached() + mock2 = MockMemcached() + memcache_client._client_cache['1.2.3.4:11211'] = MockedMemcachePool( + [(mock1, mock1)] * 2) + memcache_client._client_cache['1.2.3.5:11211'] = MockedMemcachePool( + [(mock2, mock2)] * 2) + + # MemcacheRing will put 'some_key0' on server 1.2.3.5:11211 and + # 'some_key1' and 'multi_key' on '1.2.3.4:11211' + memcache_client.set_multi( + {'some_key0': [1, 2, 3], 'some_key1': [4, 5, 6]}, 'multi_key') + self.assertEqual( + memcache_client.get_multi(('some_key1', 'some_key0'), 'multi_key'), + [[4, 5, 6], [1, 2, 3]]) + for key in (b'some_key0', b'some_key1'): + key = md5(key).hexdigest().encode('ascii') + self.assertIn(key, mock1.cache) + _junk, cache_timeout, _junk = mock1.cache[key] + self.assertEqual(cache_timeout, b'0') + + memcache_client.set('some_key0', [7, 8, 9]) + self.assertEqual(memcache_client.get('some_key0'), [7, 8, 9]) + key = md5(b'some_key0').hexdigest().encode('ascii') + self.assertIn(key, mock2.cache) + + # Delete 'some_key0' with server_key='multi_key' + memcache_client.delete('some_key0', server_key='multi_key') + self.assertEqual(memcache_client.get_multi( + ('some_key0', 'some_key1'), 'multi_key'), + [None, [4, 5, 6]]) + + # 'some_key0' have to be available on 1.2.3.5:11211 + self.assertEqual(memcache_client.get('some_key0'), [7, 8, 9]) + self.assertIn(key, mock2.cache) + def test_serialization(self): memcache_client = memcached.MemcacheRing(['1.2.3.4:11211'], allow_pickle=True)