from ConfigParser import ConfigParser import cPickle as pickle import base64 from threading import Lock #TODO replace ConfigParser for better performance class PersistentContainer(object): cfgparsers = dict() locks = dict() def __init__(self,namespace,path): self.namespace = namespace self.path = path self.trans_cache = dict() self.trans_del = [] if not path in PersistentContainer.locks: PersistentContainer.locks[path] = Lock() self.transaction = PersistentContainer.locks[path] if not path in PersistentContainer.cfgparsers: PersistentContainer.cfgparsers[path] = ConfigParser() PersistentContainer.cfgparsers[path].read([path]) self.cp = PersistentContainer.cfgparsers[path] if not self.cp.has_section(namespace): self.cp.add_section(namespace) def start_transaction(self,blocking=True): return self.transaction.acquire(blocking) def commit_transaction(self): self._write() self.transaction.release() def rollback(self): for k in self.trans_cache: del self.trans_cache[k] self.transaction.release() def is_owned(self): return self.transaction.locked() def __getitem__(self, name): if self.cp.has_option(self.namespace,name): b64 = self.cp.get(self.namespace,name) return pickle.loads(base64.b64decode(b64)) return None def __setitem__(self, name,val): self.trans_cache[name]=val if not self.is_owned(): self._write() def __delitem__(self, name): if name not in self.trans_del: self.trans_del.append(name) if name in self.trans_cache: del self.trans_cache[name] if not self.is_owned(): self._write() def __contains__(self,name): return self.cp.has_option(self.namespace,name) def _write(self): for k in self.trans_cache: val = self.trans_cache[k] ser = pickle.dumps(val) self.cp.set(self.namespace,k,base64.b64encode(ser)) while len(self.trans_del): n = self.trans_del.pop() self.cp.remove_option(self.namespace,n) f = open(self.path,'w') self.cp.write(f) f.close()