File:  [Repository] / ExtFile / TM.py
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jan 24 16:53:50 2007 UTC (17 years, 5 months ago) by dwinter
Branches: first, MAIN
CVS tags: release, HEAD
Auf der Basis http://www.zope.org/Members/shh/ExtFile Version 1.5.4

mit zlog ersetzt durch logging


    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>