Another solution I've found is to implement a DiskStore which gets a lock on the pickled object before reading it, and releases the lock when saving:
class LockingDiskStore(web.session.Store):
"""
Store which uses lock files
"""
def __init__(self, root):
# if the storage root doesn't exists, create it.
if not os.path.exists(root):
os.makedirs(
os.path.abspath(root)
)
self.root = root
def _get_path(self, key):
if os.path.sep in key:
raise ValueError, "Bad key: %s" % repr(key)
return os.path.join(self.root, key)
def __contains__(self, key):
path = self._get_path(key)
return os.path.exists(path)
def __getitem__(self, key):
print "read ", key
lockfile = self._lockfile(key)
dt = 0
while os.path.exists(lockfile) and dt < 30: # 30 second time out
print "waiting for lock to release"
time.sleep(1)
dt += 1
f = open(lockfile, "w")
f.write("lock")
f.close()
path = self._get_path(key)
if os.path.exists(path):
pickled = open(path).read()
return self.decode(pickled)
else:
raise KeyError, key
def __setitem__(self, key, value):
print "write ", key
lockfile = self._lockfile(key)
if os.path.exists(lockfile) :
print "deleting lockfile"
os.remove(lockfile)
path = self._get_path(key)
pickled = self.encode(value)
try:
f = open(path, 'w')
try:
f.write(pickled)
finally:
f.close()
except IOError:
pass
def __delitem__(self, key):
path = self._get_path(key)
if os.path.exists(path):
os.remove(path)
def _lockfile(self, key):
return self._get_path(key) + ".lock"
def cleanup(self, timeout):
now = time.time()
for f in os.listdir(self.root):
path = self._get_path(f)
atime = os.stat(path).st_atime
if now - atime > timeout :
os.remove(path)