Annotation of ExtFile/TM.py, revision 1.1.1.1

1.1       dwinter     1: """
                      2: TMRegistry and ProxyTM
                      3: 
                      4: Use case
                      5: --------
                      6: 
                      7: Persistent objects (ExtFiles) need to participate in ZODB transactions.
                      8: ExtFiles perform all operations using temporary files which are saved on
                      9: commit or deleted on abort.
                     10: 
                     11: Constraints
                     12: -----------
                     13: 
                     14: - TransactionManagers (TM) must not be persistent themselves, i.e. must
                     15:   not have a _p_jar attribute.
                     16: 
                     17: - We have to make sure the ExtFile's _abort is called *before* the ZODB
                     18:   destroys the attributes of the persistent object.
                     19: 
                     20: Solution
                     21: --------
                     22: 
                     23: - ProxyTM is a subclass of TM.TM that keeps a (hard) reference to the
                     24:   (wrapped) persistent object it manages. Calls to _begin, _finish, and
                     25:   _abort are forwarded to the target object.
                     26: 
                     27: - TMRegistry is a module-level container for ProxyTMs. It creates and
                     28:   holds ProxyTMs keyed by (target_id, thread_id).
                     29: 
                     30: - ExtFiles implement _finish and _abort and register with the machinery
                     31:   by calling TM.register(self).
                     32: 
                     33: - On commit (or abort) the ProxyTM notifies its target object and removes
                     34:   itself from the registry.
                     35: 
                     36: Hacks
                     37: -----
                     38: 
                     39: - We manipulate the transaction's _resources attribute directly. This is
                     40:   to guarantee the ProxyTM is processed before other resources. There may
                     41:   be a way to achieve this using official APIs only, but I can't seem to
                     42:   find one.
                     43: 
                     44: """
                     45: 
                     46: from Shared.DC.ZRDB.TM import TM
                     47: from Acquisition import aq_base
                     48: from thread import get_ident
                     49: from Products.ExtFile import transaction
                     50: 
                     51: 
                     52: class TMRegistry:
                     53: 
                     54:     def __init__(self):
                     55:         self._tms = {}
                     56: 
                     57:     def getid(self, target):
                     58:         return (id(aq_base(target)), get_ident())
                     59: 
                     60:     def register(self, target):
                     61:         if not self.contains(target):
                     62:             id = self.getid(target)
                     63:             tm = ProxyTM(target)
                     64:             tm._register()
                     65:             self._tms[id] = tm
                     66:             return 1
                     67:         return 0
                     68: 
                     69:     def remove(self, target):
                     70:         if self.contains(target):
                     71:             id = self.getid(target)
                     72:             del self._tms[id]
                     73:             return 1
                     74:         return 0
                     75: 
                     76:     def contains(self, target):
                     77:         id = self.getid(target)
                     78:         return self._tms.has_key(id)
                     79: 
                     80:     def get(self, target):
                     81:         id = self.getid(target)
                     82:         return self._tms.get(id)
                     83: 
                     84:     def __len__(self):
                     85:         return len(self._tms)
                     86: 
                     87:     def count(self):
                     88:         return len(self)
                     89: 
                     90: 
                     91: class ProxyTM(TM):
                     92: 
                     93:     def __init__(self, target):
                     94:         self._target = target
                     95: 
                     96:     def _register(self):
                     97:         TM._register(self)
                     98:         # XXX Make sure we are called before the
                     99:         # persistent ExtFile object is destroyed.
                    100:         t = transaction.get()
                    101:         if hasattr(t, '_resources'):
                    102:             r = t._resources.pop()
                    103:             t._resources.insert(0, r)
                    104: 
                    105:     def _begin(self):
                    106:         return self._target._begin()
                    107: 
                    108:     def _finish(self):
                    109:         if registry.remove(self._target):
                    110:             return self._target._finish()
                    111: 
                    112:     def _abort(self):
                    113:         if registry.remove(self._target):
                    114:             return self._target._abort()
                    115: 
                    116: 
                    117: registry = TMRegistry()
                    118: register = registry.register
                    119: remove = registry.remove
                    120: contains = registry.contains
                    121: count = registry.count
                    122: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>