Bug fix: Memcached does not allow negative numbers passed to incr. Adding/using decr.

This commit is contained in:
David Goetz 2010-10-21 15:22:30 +00:00 committed by Tarmac
commit 358f3740d9
3 changed files with 37 additions and 1 deletions

View File

@ -190,6 +190,32 @@ 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.
If the key can't be found, it's added as 0. Memcached
will treat data values below 0 as 0 with incr/decr.
:param key: key
:param delta: amount to subtract to the value of key (or set
as the value if the key is not found)
:param timeout: ttl in memcache
"""
key = md5hash(key)
for (server, fp, sock) in self._get_conns(key):
try:
sock.sendall('decr %s %s\r\n' % (key, delta))
line = fp.readline().strip().split()
if line[0].upper() == 'NOT_FOUND':
line[0] = '0'
sock.sendall('add %s %d %d %s noreply\r\n%s\r\n' %
(key, 0, timeout, len(line[0]), line[0]))
ret = int(line[0].strip())
self._return_conn(server, fp, sock)
return ret
except Exception, e:
self._exception_occurred(server, e)
def delete(self, key):
"""
Deletes a key/value pair from memcache.

View File

@ -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)

View File

@ -36,9 +36,19 @@ class FakeMemcache(object):
return True
def incr(self, key, delta=1, timeout=0):
if delta < 0:
raise "Cannot incr by a negative number"
self.store[key] = int(self.store.setdefault(key, 0)) + delta
return int(self.store[key])
def decr(self, key, delta=1, timeout=0):
if delta < 0:
raise "Cannot decr by a negative number"
self.store[key] = int(self.store.setdefault(key, 0)) - delta
if self.store[key] < 0:
self.store[key] = 0
return int(self.store[key])
@contextmanager
def soft_lock(self, key, timeout=0, retries=5):
yield True