[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[minion-cvs] Add new database-backed writethrough dict class
Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.mit.edu:/tmp/cvs-serv7284/lib/mixminion
Modified Files:
Filestore.py
Log Message:
Add new database-backed writethrough dict class
Index: Filestore.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Filestore.py,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- Filestore.py 25 Apr 2004 00:22:37 -0000 1.18
+++ Filestore.py 14 May 2004 23:43:04 -0000 1.19
@@ -19,9 +19,11 @@
import dumbdbm
import errno
import os
+import shelve
import stat
import threading
import time
+import types
import whichdb
from mixminion.Common import MixError, MixFatalError, secureDelete, LOG, \
@@ -527,6 +529,49 @@
# ======================================================================
# Database wrappers
+def openDB(filename, purpose):
+ """DOCDOC"""
+ parent = os.path.split(filename)[0]
+ createPrivateDir(parent)
+
+ # If the file can't be read, bail.
+ try:
+ st = os.stat(filename)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ st = None
+ # If the file is empty, delete it and start over.
+ if st and st[stat.ST_SIZE] == 0:
+ LOG.warn("Half-created database %s found; cleaning up.", filename)
+ tryUnlink(filename)
+
+ LOG.debug("Opening %s database at %s", purpose, filename)
+ try:
+ db = anydbm.open(filename, 'c')
+ except anydbm.error, e:
+ raise MixFatalError("Can't open %s database: %s"%(purpose,e))
+ except ImportError:
+ dbtype = whichdb.whichdb(filename)
+ raise MixFatalError("Unsupported type for %s database: %s"
+ %(purpose, dbtype))
+
+ if hasattr(db, 'sync'):
+ syncLog = db.sync
+ elif hasattr(db, '_commit'):
+ # Workaround for dumbdbm to allow syncing. (Standard in
+ # Python 2.3.)
+ syncLog = db._commit
+ else:
+ # Otherwise, force a no-op sync method.
+ syncLog = lambda : None
+
+ if isinstance(db, dumbdbm._Database):
+ LOG.warn("Warning: using a flat file for %s database", purpose)
+
+ return db, syncLog
+
+
class DBBase:
"""A DBBase is a persistant store that maps keys to values, using
a Python anydbm object.
@@ -552,43 +597,8 @@
creating the underlying database if needed."""
self._lock = threading.RLock()
self.filename = filename
- parent = os.path.split(filename)[0]
- createPrivateDir(parent)
-
- # If the file can't be read, bail.
- try:
- st = os.stat(filename)
- except OSError, e:
- if e.errno != errno.ENOENT:
- raise
- st = None
- # If the file is empty, delete it and start over.
- if st and st[stat.ST_SIZE] == 0:
- LOG.warn("Half-created database %s found; cleaning up.", filename)
- tryUnlink(filename)
-
- LOG.debug("Opening %s database at %s", purpose, filename)
- try:
- self.log = anydbm.open(filename, 'c')
- except anydbm.error, e:
- raise MixFatalError("Can't open %s database: %s"%(purpose,e))
- except ImportError:
- dbtype = whichdb.whichdb(filename)
- raise MixFatalError("Unsupported type for %s database: %s"
- %(purpose, dbtype))
- if hasattr(self.log, 'sync'):
- self._syncLog = self.log.sync
- elif hasattr(self.log, '_commit'):
- # Workaround for dumbdbm to allow syncing. (Standard in
- # Python 2.3.)
- self._syncLog = self.log._commit
- else:
- # Otherwise, force a no-op sync method.
- self._syncLog = lambda : None
-
- if isinstance(self.log, dumbdbm._Database):
- LOG.warn("Warning: using a flat file for %s database", purpose)
+ self.log, self._syncLog = openDB(filename, purpose)
# Subclasses may want to check whether this is the right database,
# flush the journal, and so on.
@@ -819,3 +829,51 @@
return "1"
def _decodeVal(self, v):
return 1
+
+class WritethroughDict:
+ """DOCDOC"""
+ def __init__(self, filename, purpose):
+ self.db, self._syncLog = openDB(filename,purpose)
+ self.cache = {}
+ self.load()
+
+ def __setitem__(self, k, v):
+ assert type(k) == types.StringType
+ self.cache[k] = v
+ self.db[k] = cPickle.dumps(v,1)
+
+ def __getitem__(self, k):
+ assert type(k) == types.StringType
+ return self.cache[k]
+
+ def get(self, k, vOther=None):
+ try:
+ return self.cache[k]
+ except KeyError:
+ return vOther
+
+ def __delitem__(self, k):
+ del self.cache[k]
+ del self.db[k]
+
+ def has_key(self, k):
+ return self.cache.has_key(k)
+
+ def sync(self):
+ self._syncLog()
+
+ def close(self):
+ self._syncLog()
+ self.db.close()
+ del self.cache
+ del self.db
+ del self._syncLog
+
+ def keys(self):
+ return self.cache.keys()
+
+ def load(self):
+ keys = self.db.keys()
+ self.cache = cache = {}
+ for k in keys:
+ self.cache[k] = cPickle.loads(self.db[k])