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>