class Fixed(Float): fixed_digits = 1 fixed_scale = 0 def mdl_typeCode(klass): return TypeCode(kind=TCKind.Fixed, fixed_digits=klass.fixed_digits, fixed_scale=klass.fixed_scale) mdl_typeCode = binding.classAttr(binding.Make(mdl_typeCode))
class String(PrimitiveType): length = 0 def mdl_fromString(klass, value): return value mdl_typeKind = TCKind.tk_string def mdl_typeCode(klass): return TypeCode(kind=klass.mdl_typeKind, length=klass.length) mdl_typeCode = binding.classAttr(binding.Make(mdl_typeCode))
class FacadeDM(binding.Component): """DM that just returns objects from other DM(s) via a different key""" protocols.advise( instancesProvide=[IKeyableDM] ) def __getitem__(self, oid, state=None): ob = self.cache.get(oid,self) if ob is not self: # double-check identity if oid==self.oidFor(ob): return ob # Oops, key no longer valid, drop it del self.cache[oid] ob = self._retrieve(oid, state) if ob is not None: self.cache[oid] = ob return ob raise KeyError, oid preloadState = __getitem__ cache = binding.Make('peak.storage.caches:WeakCache') def _retrieve(self, oid, state=None): """Look up 'oid' in underlying storage and return it, or 'None'""" raise NotImplementedError def oidFor(self, ob): """Return this DM's OID for 'ob'; used to validate consistency""" raise NotImplementedError
class EntityDM(QueryDM): protocols.advise( instancesProvide=[IWritableDM] ) def oidFor(self, ob): if ob._p_jar is self: oid = ob._p_oid if oid is None: # force it to have an ID by saving it ob._p_changed = 1 self.flush(ob) return ob._p_oid else: return oid else: return self._thunk(ob) def newItem(self,klass=None): if klass is None: klass = self.defaultClass if klass is None: raise NotImplementedError ob=klass() ob.__setstate__(self._defaultState(ob)) self.add(ob) return ob # Set/state management dirty = binding.Make(dict) saved = binding.Make(dict) to_delete = binding.Make(list) def flush(self, ob=None): markSaved = self.saved.setdefault dirty = self.dirty orig_ob = ob if ob is None: obs = dirty.values() else: obs = [ob] for ob in obs: if ob._p_oid is None: # No oid, it's a new object that needs saving oid = ob._p_oid = self._new(ob) self.cache[oid]=ob else: # just save it the ordinary way self._save(ob) # Update status flags and object sets key = id(ob) markSaved(key,ob) if key in dirty: del dirty[key] ob._p_changed = False if orig_ob is None and self.to_delete: self._delete_oids(self.to_delete) del self.to_delete # Private abstract methods/attrs defaultClass = None def _save(self, ob): raise NotImplementedError def _new(self, ob): raise NotImplementedError def _defaultState(self, ob): return ob.__getstate__() def _thunk(self, ob): raise NotImplementedError def _delete_oids(self,oidList): raise NotImplementedError def _check(self,ob): """Override this to raise an error if 'ob' is unsuitable for storing""" # Persistence.IPersistentDataManager methods def register(self, ob): # Ensure that we have a transaction service and we've joined # the transaction in progress... self.joinedTxn # precondition: # object has been changed since last save # postcondition: # ob is in 'dirty' set # DM is registered w/transaction if not previously registered key = id(ob) # Ensure it's in the 'dirty' set self.dirty.setdefault(key,ob) return self.joinedTxn # ITransactionParticipant methods def readyToVote(self, txnService): if self.dirty or self.to_delete: self.flush() return False else: return True def voteForCommit(self, txnService): # Everything should have been written by now... If not, it's VERY BAD # because the DB we're storing to might've already gotten a tpc_vote(), # and won't accept writes any more. So raise holy hell if we're dirty! assert not self.dirty and not self.to_delete def commitTransaction(self, txnService): self.saved.clear() self._delBinding('to_delete') def abortTransaction(self, txnService): for ob in self.dirty.values(): ob._p_changed = False ob._p_deactivate() self.dirty.clear() for ob in self.saved.values(): if ob._p_jar is self: # don't deactivate formerly-owned objects ob._p_deactivate() self.saved.clear() self._delBinding('to_delete') def add(self,ob): if not isinstance(ob,Persistent): raise TypeError("Not a persistent object", ob) if ob._p_jar is self: return # Nothing needed here elif ob._p_jar is not None: raise ValueError("Already in another DM", ob, ob._p_jar) self._check(ob) if ob._p_oid is not None: if self.get(ob._p_oid) is not None: raise InvalidKeyError("Duplicate key", ob._p_oid) self.cache[ob._p_oid] = ob ob._p_jar = self self.register(ob) def remove(self,ob): if ob._p_jar is not self: raise ValueError("Doesn't belong to this DM", ob, ob._p_jar) key = id(ob) if key in self.dirty: del self.dirty[key] # note: don't delete from 'saved', because we might still need to roll # back the object's state if it gets re-added, but the txn aborts, and # we don't have 'resetStatesAfterTxn' set. del self.cache[ob._p_oid] ob._p_jar = None self.to_delete.append(ob._p_oid) # Ensure that we have a transaction service and we've joined # the transaction in progress... self.joinedTxn
class QueryDM(TransactionComponent): resetStatesAfterTxn = True protocols.advise( instancesProvide=[IDataManager] ) to_delete = () def __getitem__(self, oid, state=None): if self.resetStatesAfterTxn: # must always be used in a txn self.joinedTxn if oid in self.to_delete: raise InvalidKeyError("Reference to deleted key", oid) ob = self.cache.get(oid,self) if ob is not self: return ob ob = self._ghost(oid,state) if isinstance(ob,Persistent): ob._p_jar = self ob._p_oid = oid if state is None: ob._p_deactivate() else: ob.__setstate__(state) self.cache[oid] = ob return ob preloadState = __getitem__ # Private abstract methods/attrs cache = binding.Make('peak.storage.caches:WeakCache') defaultClass = PersistentQuery def _ghost(self, oid, state=None): klass = self.defaultClass if klass is None: raise NotImplementedError return klass() def _load(self, oid, ob): raise NotImplementedError # Persistence.IPersistentDataManager methods def setstate(self, ob): if self.resetStatesAfterTxn: # must always be used in a txn self.joinedTxn oid = ob._p_oid assert oid is not None ob.__setstate__(self._load(oid,ob)) def mtime(self, ob): pass # return None def register(self, ob): raise TypeError("Attempt to modify query result", ob) # ITransactionParticipant methods def finishTransaction(self, txnService, committed): if self.resetStatesAfterTxn: for oid, ob in self.cache.items(): if isinstance(ob,Persistent): ob._p_deactivate() super(QueryDM,self).finishTransaction(txnService,committed) # Misc. def __iter__(self): raise NotImplementedError def __contains__(self, ob): if isinstance(ob,Persistent): return ob._p_jar is self return self.get(ob) is not None def get(self,oid,default=None): if self.resetStatesAfterTxn: # must always be used in a txn self.joinedTxn if oid in self.cache: return self.cache[oid] elif oid in self.to_delete: return default try: state = self._load(oid,None) except InvalidKeyError: return default else: return self.preloadState(oid,state)