Annotation of ExtFile/TM.py, revision 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>