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."

from __future__ import with_statement

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

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

def _set(self, key, value, timeout=None):
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):
key = self.make_key(key, version=version)
self.validate_key(key)
self._lock.writer_enters()
try:
pickled = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
self._set(key, pickled, timeout)
except pickle.PickleError:
pass
finally:
self._lock.writer_leaves()
with self._lock.writer():
try:
pickled = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
self._set(key, pickled, timeout)
except pickle.PickleError:
pass

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

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

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

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

def clear(self):
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)
"""

from __future__ import with_statement

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

class RWLock:

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

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

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

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

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

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

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

0 comments on commit e4919f6

Please sign in to comment.