diff --git a/swift/common/memcached.py b/swift/common/memcached.py index 15b9a193f0..d40d86c21e 100644 --- a/swift/common/memcached.py +++ b/swift/common/memcached.py @@ -209,6 +209,19 @@ class MemcacheRing(object): except Exception, e: self._exception_occurred(server, e) + def decr(self, key, delta=1, timeout=0): + """ + Decrements a key which has a numeric value by delta. Calls incr with + -delta. + + :param key: key + :param delta: amount to subtract to the value of key (or set the + value to 0 if the key is not found) will be cast to + an int + :param timeout: ttl in memcache + """ + self.incr(key, delta=-delta, timeout=timeout) + def delete(self, key): """ Deletes a key/value pair from memcache. diff --git a/swift/common/middleware/ratelimit.py b/swift/common/middleware/ratelimit.py index ca0cd6e427..fea11ae811 100644 --- a/swift/common/middleware/ratelimit.py +++ b/swift/common/middleware/ratelimit.py @@ -148,7 +148,7 @@ class RateLimitMiddleware(object): max_sleep_m = self.max_sleep_time_seconds * self.clock_accuracy if max_sleep_m - need_to_sleep_m <= self.clock_accuracy * 0.01: # treat as no-op decrement time - self.memcache_client.incr(key, delta=-time_per_request_m) + self.memcache_client.decr(key, delta=time_per_request_m) raise MaxSleepTimeHit("Max Sleep Time Exceeded: %s" % need_to_sleep_m) diff --git a/test/unit/common/middleware/test_ratelimit.py b/test/unit/common/middleware/test_ratelimit.py index a6c1047389..bd19444f70 100644 --- a/test/unit/common/middleware/test_ratelimit.py +++ b/test/unit/common/middleware/test_ratelimit.py @@ -41,6 +41,9 @@ class FakeMemcache(object): self.store[key] = 0 return int(self.store[key]) + def decr(self, key, delta=1, timeout=0): + return self.incr(key, delta=-delta, timeout=timeout) + @contextmanager def soft_lock(self, key, timeout=0, retries=5): yield True diff --git a/test/unit/common/test_memcached.py b/test/unit/common/test_memcached.py index ccb40b3922..d17f0089a3 100644 --- a/test/unit/common/test_memcached.py +++ b/test/unit/common/test_memcached.py @@ -167,6 +167,19 @@ class TestMemcached(unittest.TestCase): memcache_client.incr('some_key', delta=-15) self.assertEquals(memcache_client.get('some_key'), '0') + def test_decr(self): + memcache_client = memcached.MemcacheRing(['1.2.3.4:11211']) + mock = MockMemcached() + memcache_client._client_cache['1.2.3.4:11211'] = [(mock, mock)] * 2 + memcache_client.decr('some_key', delta=5) + self.assertEquals(memcache_client.get('some_key'), '0') + memcache_client.incr('some_key', delta=15) + self.assertEquals(memcache_client.get('some_key'), '15') + memcache_client.decr('some_key', delta=4) + self.assertEquals(memcache_client.get('some_key'), '11') + memcache_client.decr('some_key', delta=15) + self.assertEquals(memcache_client.get('some_key'), '0') + def test_retry(self): logging.getLogger().addHandler(NullLoggingHandler()) memcache_client = memcached.MemcacheRing(['1.2.3.4:11211', '1.2.3.5:11211'])