Skip to content

Commit

Permalink
Clean up the the locmem cache backend and utils.synch by using contex…
Browse files Browse the repository at this point in the history
…t managers. Puch prettier.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17152 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
alex committed Nov 27, 2011
1 parent 1086a9a commit e4919f6
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 55 deletions.
60 changes: 20 additions & 40 deletions django/core/cache/backends/locmem.py
@@ -1,5 +1,7 @@
"Thread-safe in-memory cache backend." "Thread-safe in-memory cache backend."


from __future__ import with_statement

import time import time
try: try:
import cPickle as pickle import cPickle as pickle
Expand All @@ -26,8 +28,7 @@ def __init__(self, name, params):
def add(self, key, value, timeout=None, version=None): def add(self, key, value, timeout=None, version=None):
key = self.make_key(key, version=version) key = self.make_key(key, version=version)
self.validate_key(key) self.validate_key(key)
self._lock.writer_enters() with self._lock.writer():
try:
exp = self._expire_info.get(key) exp = self._expire_info.get(key)
if exp is None or exp <= time.time(): if exp is None or exp <= time.time():
try: try:
Expand All @@ -37,14 +38,11 @@ def add(self, key, value, timeout=None, version=None):
except pickle.PickleError: except pickle.PickleError:
pass pass
return False return False
finally:
self._lock.writer_leaves()


def get(self, key, default=None, version=None): def get(self, key, default=None, version=None):
key = self.make_key(key, version=version) key = self.make_key(key, version=version)
self.validate_key(key) self.validate_key(key)
self._lock.reader_enters() with self._lock.reader():
try:
exp = self._expire_info.get(key) exp = self._expire_info.get(key)
if exp is None: if exp is None:
return default return default
Expand All @@ -54,18 +52,13 @@ def get(self, key, default=None, version=None):
return pickle.loads(pickled) return pickle.loads(pickled)
except pickle.PickleError: except pickle.PickleError:
return default return default
finally: with self._lock.writer():
self._lock.reader_leaves()
self._lock.writer_enters()
try:
try: try:
del self._cache[key] del self._cache[key]
del self._expire_info[key] del self._expire_info[key]
except KeyError: except KeyError:
pass pass
return default return default
finally:
self._lock.writer_leaves()


def _set(self, key, value, timeout=None): def _set(self, key, value, timeout=None):
if len(self._cache) >= self._max_entries: if len(self._cache) >= self._max_entries:
Expand All @@ -78,54 +71,44 @@ def _set(self, key, value, timeout=None):
def set(self, key, value, timeout=None, version=None): def set(self, key, value, timeout=None, version=None):
key = self.make_key(key, version=version) key = self.make_key(key, version=version)
self.validate_key(key) self.validate_key(key)
self._lock.writer_enters() with self._lock.writer():
try: try:
pickled = pickle.dumps(value, pickle.HIGHEST_PROTOCOL) pickled = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
self._set(key, pickled, timeout) self._set(key, pickled, timeout)
except pickle.PickleError: except pickle.PickleError:
pass pass
finally:
self._lock.writer_leaves()


def incr(self, key, delta=1, version=None): def incr(self, key, delta=1, version=None):
value = self.get(key, version=version) value = self.get(key, version=version)
if value is None: if value is None:
raise ValueError("Key '%s' not found" % key) raise ValueError("Key '%s' not found" % key)
new_value = value + delta new_value = value + delta
key = self.make_key(key, version=version) key = self.make_key(key, version=version)
self._lock.writer_enters() with self._lock.writer():
try: try:
pickled = pickle.dumps(new_value, pickle.HIGHEST_PROTOCOL) pickled = pickle.dumps(new_value, pickle.HIGHEST_PROTOCOL)
self._cache[key] = pickled self._cache[key] = pickled
except pickle.PickleError: except pickle.PickleError:
pass pass
finally:
self._lock.writer_leaves()
return new_value return new_value


def has_key(self, key, version=None): def has_key(self, key, version=None):
key = self.make_key(key, version=version) key = self.make_key(key, version=version)
self.validate_key(key) self.validate_key(key)
self._lock.reader_enters() with self._lock.reader():
try:
exp = self._expire_info.get(key) exp = self._expire_info.get(key)
if exp is None: if exp is None:
return False return False
elif exp > time.time(): elif exp > time.time():
return True return True
finally:
self._lock.reader_leaves()


self._lock.writer_enters() with self._lock.writer():
try:
try: try:
del self._cache[key] del self._cache[key]
del self._expire_info[key] del self._expire_info[key]
except KeyError: except KeyError:
pass pass
return False return False
finally:
self._lock.writer_leaves()


def _cull(self): def _cull(self):
if self._cull_frequency == 0: if self._cull_frequency == 0:
Expand All @@ -148,11 +131,8 @@ def _delete(self, key):
def delete(self, key, version=None): def delete(self, key, version=None):
key = self.make_key(key, version=version) key = self.make_key(key, version=version)
self.validate_key(key) self.validate_key(key)
self._lock.writer_enters() with self._lock.writer():
try:
self._delete(key) self._delete(key)
finally:
self._lock.writer_leaves()


def clear(self): def clear(self):
self._cache.clear() self._cache.clear()
Expand Down
38 changes: 23 additions & 15 deletions django/utils/synch.py
Expand Up @@ -6,12 +6,16 @@
(Contributed to Django by eugene@lazutkin.com) (Contributed to Django by eugene@lazutkin.com)
""" """


from __future__ import with_statement

import contextlib
try: try:
import threading import threading
except ImportError: except ImportError:
import dummy_threading as threading import dummy_threading as threading


class RWLock:
class RWLock(object):
""" """
Classic implementation of reader-writer lock with preference to writers. Classic implementation of reader-writer lock with preference to writers.
Expand All @@ -34,43 +38,41 @@ def __init__(self):
self.waiting_writers = 0 self.waiting_writers = 0


def reader_enters(self): def reader_enters(self):
self.mutex.acquire() with self.mutex:
try:
if self.active_writers == 0 and self.waiting_writers == 0: if self.active_writers == 0 and self.waiting_writers == 0:
self.active_readers += 1 self.active_readers += 1
self.can_read.release() self.can_read.release()
else: else:
self.waiting_readers += 1 self.waiting_readers += 1
finally:
self.mutex.release()
self.can_read.acquire() self.can_read.acquire()


def reader_leaves(self): def reader_leaves(self):
self.mutex.acquire() with self.mutex:
try:
self.active_readers -= 1 self.active_readers -= 1
if self.active_readers == 0 and self.waiting_writers != 0: if self.active_readers == 0 and self.waiting_writers != 0:
self.active_writers += 1 self.active_writers += 1
self.waiting_writers -= 1 self.waiting_writers -= 1
self.can_write.release() self.can_write.release()

@contextlib.contextmanager
def reader(self):
self.reader_enters()
try:
yield
finally: finally:
self.mutex.release() self.reader_leaves()


def writer_enters(self): def writer_enters(self):
self.mutex.acquire() with self.mutex:
try:
if self.active_writers == 0 and self.waiting_writers == 0 and self.active_readers == 0: if self.active_writers == 0 and self.waiting_writers == 0 and self.active_readers == 0:
self.active_writers += 1 self.active_writers += 1
self.can_write.release() self.can_write.release()
else: else:
self.waiting_writers += 1 self.waiting_writers += 1
finally:
self.mutex.release()
self.can_write.acquire() self.can_write.acquire()


def writer_leaves(self): def writer_leaves(self):
self.mutex.acquire() with self.mutex:
try:
self.active_writers -= 1 self.active_writers -= 1
if self.waiting_writers != 0: if self.waiting_writers != 0:
self.active_writers += 1 self.active_writers += 1
Expand All @@ -83,5 +85,11 @@ def writer_leaves(self):
while t > 0: while t > 0:
self.can_read.release() self.can_read.release()
t -= 1 t -= 1

@contextlib.contextmanager
def writer(self):
self.writer_enters()
try:
yield
finally: finally:
self.mutex.release() self.writer_leaves()

0 comments on commit e4919f6

Please sign in to comment.