Skip to content

Commit

Permalink
Remove _ex_keys mapping
Browse files Browse the repository at this point in the history
Because they can get out of sync under python3 since
`_dict` entries are converted into bytes while `_ex_keys` aren't
and ```b'foo' != 'foo'``` under python 3.

Instead of trying to convert back and forth between `bytes` and `str`
in different places, this new implementation stores everything
in `_dict` and makes sure values and timestamp are always stored together.
  • Loading branch information
ticosax committed Sep 20, 2016
1 parent 4bfc7a2 commit 0811f2e
Showing 1 changed file with 15 additions and 29 deletions.
44 changes: 15 additions & 29 deletions fakeredis.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,17 @@ def timedelta_total_seconds(delta):
class _StrKeyDict(MutableMapping):
def __init__(self, *args, **kwargs):
self._dict = dict(*args, **kwargs)
self._ex_keys = {}

def __getitem__(self, key):
self._update_expired_keys()
return self._dict[to_bytes(key)]
now = datetime.now()
value, expiration = self._dict[to_bytes(key)]
if expiration is not None and now > expiration:
del self._dict[to_bytes(key)]
raise KeyError(key)
return value

def __setitem__(self, key, value):
self._dict[to_bytes(key)] = value
self._dict[to_bytes(key)] = (value, None)

def __delitem__(self, key):
del self._dict[to_bytes(key)]
Expand All @@ -132,36 +135,21 @@ def __iter__(self):
return iter(self._dict)

def expire(self, key, timestamp):
self._ex_keys[key] = timestamp
value = self._dict[to_bytes(key)][0]
self._dict[to_bytes(key)] = (value, timestamp)

def expiring(self, key):
if key not in self._ex_keys:
return None
return self._ex_keys[key]

def _update_expired_keys(self):
now = datetime.now()
deleted = []
for key in self._ex_keys:
if now > self._ex_keys[key]:
deleted.append(key)

for key in deleted:
del self._ex_keys[key]
del self[key]
return self._dict[to_bytes(key)][1]

def copy(self):
new_copy = _StrKeyDict()
for key, value in self._dict.items():
new_copy[key] = value
new_copy.update(self._dict)
return new_copy

def clear(self):
super(_StrKeyDict, self).clear()
self._ex_keys.clear()

def to_bare_dict(self):
return copy.deepcopy(self._dict)
# TODO transform to dict comprehension after droping support
# of python2.6
return dict((k, v[0]) for k, v in self._dict.items())


class _ZSet(_StrKeyDict):
Expand Down Expand Up @@ -433,6 +421,7 @@ def renamenx(self, src, dst):
def set(self, name, value, ex=None, px=None, nx=False, xx=False):
if (not nx and not xx) or (nx and self._db.get(name, None) is None) \
or (xx and not self._db.get(name, None) is None):
self._db[name] = to_bytes(value)
if ex is not None:
if isinstance(ex, timedelta):
ex = ex.seconds + ex.days * 24 * 3600
Expand All @@ -450,7 +439,6 @@ def set(self, name, value, ex=None, px=None, nx=False, xx=False):
if px > 0:
self._db.expire(name, datetime.now() +
timedelta(milliseconds=px))
self._db[name] = to_bytes(value)
return True
else:
return None
Expand Down Expand Up @@ -560,8 +548,6 @@ def delete(self, *names):
for name in names:
try:
del self._db[name]
if name in self._db._ex_keys:
del self._db._ex_keys[name]
deleted += 1
except KeyError:
continue
Expand Down

0 comments on commit 0811f2e

Please sign in to comment.