[Checkins] SVN: zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/ refactor: PersistentReferenceProxy instead of PersistentReferenceSet
Andrew Sung
asung at zope.com
Wed Jan 11 00:12:15 UTC 2012
Log message for revision 124025:
refactor: PersistentReferenceProxy instead of PersistentReferenceSet
Changed:
U zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/_queue.py
U zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/queue.txt
U zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/tests.py
-=-
Modified: zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/_queue.py
===================================================================
--- zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/_queue.py 2012-01-10 23:32:13 UTC (rev 124024)
+++ zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/_queue.py 2012-01-11 00:12:14 UTC (rev 124025)
@@ -52,8 +52,8 @@
PersistentQueue = BucketQueue # for legacy instances, be conservative
-class PersistentReferenceSet(object):
- """PersistentReferenceSet
+class PersistentReferenceProxy(object):
+ """PersistentReferenceProxy
`ZODB.ConflictResolution.PersistentReference` doesn't get handled correctly
in the resolveQueueConflict function due to lack of the `__hash__` method.
@@ -61,95 +61,23 @@
`PersistentReference`.
"""
- def __init__(self, seq):
- assert isinstance(seq, tuple)
- self._data = self._dedup(seq)
+ def __init__(self, pr):
+ assert isinstance(pr, PersistentReference)
+ self.pr = pr
- def _dedup(self, seq):
- seq = list(seq)
- cnt = 0
- while len(seq) > cnt:
- remove = []
- for idx, item in enumerate(seq[cnt + 1:]):
- try:
- if item == seq[cnt]:
- remove.append(cnt + idx + 1)
- except ValueError:
- pass
- for idx in reversed(remove):
- seq.pop(idx)
- cnt += 1
- return tuple(seq)
+ def __hash__(self):
+ return 1
- def __cmp__(self, other):
- if len(self._data) == len(other._data):
- other_data = list(other._data[:])
- for item in self._data:
- for index, other_item in enumerate(other_data):
- try:
- if item == other_item:
- other_data.pop(index)
- except ValueError:
- pass
- else:
- break
- else:
- break
- else:
- assert len(other_data) == 0
- return 0
- raise ValueError(
- "can't reliably compare against different "
- "PersistentReferences")
+ def __eq__(self, other):
+ try:
+ return self.pr == other.pr
+ except ValueError:
+ return False
- def __sub__(self, other):
- self_data = list(self._data[:])
- for other_item in other._data:
- for index, item in enumerate(self_data):
- try:
- if other_item == item:
- self_data.pop(index)
- except ValueError:
- pass
- else:
- break
- return PersistentReferenceSet(tuple(self_data))
-
- def __and__(self, other):
- self_data = list(self._data[:])
- intersection = []
- for other_item in other._data:
- for index, item in enumerate(self_data):
- try:
- if other_item == item:
- self_data.pop(index)
- intersection.append(item)
- except ValueError:
- pass
- else:
- break
- return PersistentReferenceSet(tuple(intersection))
-
- def __iter__(self):
- for item in self._data:
- yield item
-
- def __len__(self):
- return len(self._data)
-
def __repr__(self):
- return "PRSet(%s)" % str(self._data)
+ return str(self.pr)
- def __contains__(self, item):
- for data in self._data:
- try:
- if item == data:
- return True
- except ValueError:
- pass
- return False
-
def resolveQueueConflict(oldstate, committedstate, newstate, bucket=False):
# we only know how to merge _data. If anything else is different,
# puke.
@@ -161,22 +89,18 @@
# basically, we are ok with anything--willing to merge--
# unless committedstate and newstate have one or more of the
# same deletions or additions in comparison to the oldstate.
- old = oldstate['_data']
- committed = committedstate['_data']
- new = newstate['_data']
- # If items in the queue are persistent object, we can't use set().
- # see 'queue.txt'
- for item in (old + committed + new):
- if not isinstance(item, PersistentReference):
- Set = set
- break
- else:
- Set = PersistentReferenceSet
+ # If items in the queue are persistent object, we need to wrap
+ # PersistentReference objects. See 'queue.txt'
+ wrap = lambda x: (
+ PersistentReferenceProxy(x) if isinstance(x, PersistentReference) else x)
+ old = map(wrap, oldstate['_data'])
+ committed = map(wrap, committedstate['_data'])
+ new = map(wrap, newstate['_data'])
- old_set = Set(old)
- committed_set = Set(committed)
- new_set = Set(new)
+ old_set = set(old)
+ committed_set = set(committed)
+ new_set = set(new)
if bucket and bool(old_set) and (bool(committed_set) ^ bool(new_set)):
# This is a bucket, part of a CompositePersistentQueue. The old set
@@ -201,13 +125,14 @@
# Now we do the merge. We'll merge into the committed state and
# return it.
mod_committed = []
+ unwrap = lambda x: x.pr if isinstance(x, PersistentReferenceProxy) else x
for v in committed:
if v not in new_removed:
- mod_committed.append(v)
+ mod_committed.append(unwrap(v))
if new_added:
ordered_new_added = new[-len(new_added):]
- assert Set(ordered_new_added) == new_added
- mod_committed.extend(ordered_new_added)
+ assert set(ordered_new_added) == new_added
+ mod_committed.extend(map(unwrap, ordered_new_added))
committedstate['_data'] = tuple(mod_committed)
return committedstate
Modified: zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/queue.txt
===================================================================
--- zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/queue.txt 2012-01-10 23:32:13 UTC (rev 124024)
+++ zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/queue.txt 2012-01-11 00:12:14 UTC (rev 124025)
@@ -398,28 +398,26 @@
>>> db.close() # cleanup
-======================
-PersistentReferenceSet
-======================
+========================
+PersistentReferenceProxy
+========================
As `ZODB.ConflictResolution.PersistentReference` doesn't get handled
properly in `set` due to lack of `__hash__` method, we define a class
utilizing `__cmp__` method of contained items [#workaround]_.
-Let's make some Stubbed persistent reference object.
+Let's make some stub persistent reference objects. Also make some
+objects that have same oid to simulate different transaction states.
>>> from zc.queue.tests import StubPersistentReference
>>> pr1 = StubPersistentReference(1)
>>> pr2 = StubPersistentReference(2)
>>> pr3 = StubPersistentReference(3)
+ >>> pr_c1 = StubPersistentReference(1)
+ >>> pr_c2 = StubPersistentReference(2)
+ >>> pr_c3 = StubPersistentReference(3)
-Let's make copy of them to simulate different transaction states.
-
- >>> import copy
- >>> pr_c1 = copy.copy(pr1)
- >>> pr_c2 = copy.copy(pr2)
- >>> pr_c3 = copy.copy(pr3)
>>> pr1 == pr_c1
True
>>> pr2 == pr_c2
@@ -433,19 +431,37 @@
>>> id(pr3) == id(pr_c3)
False
-`set` doesn't handle persistent reference objects properly. All
-following set operations produce wrong results.
-
>>> set1 = set((pr1, pr2))
+ >>> set1
+ set([SPR (1), SPR (2)])
>>> len(set1)
2
>>> set2 = set((pr_c1, pr_c3))
+ >>> set2
+ set([SPR (1), SPR (3)])
>>> len(set2)
2
>>> set_c1 = set((pr_c1, pr_c2))
+ >>> set_c1
+ set([SPR (1), SPR (2)])
>>> len(set_c1)
2
+`set` doesn't handle persistent reference objects properly. All
+following set operations produce wrong results.
+
+Deduplication:
+
+ >>> set((pr1, pr_c1))
+ set([SPR (1), SPR (1)])
+ >>> set((pr2, pr_c2))
+ set([SPR (2), SPR (2)])
+ >>> set((pr1, pr_c1, pr2))
+ set([SPR (1), SPR (1), SPR (2)])
+ >>> set4 = set((pr1, pr2, pr3, pr_c1, pr_c2, pr_c3))
+ >>> len(set4)
+ 6
+
Minus operation:
>>> set3 = set1 - set2
@@ -454,12 +470,6 @@
>>> set3
set([SPR (1), SPR (2)])
-Deduplication:
-
- >>> set4 = set((pr1, pr2, pr3, pr_c1, pr_c2, pr_c3))
- >>> len(set4)
- 6
-
Contains:
>>> pr3 in set2
@@ -475,77 +485,104 @@
>>> set1 == set_c1
False
-So we made `PersistentReferenceSet` acting as `set`.
+So we made `PersistentReferenceProxy` wrapping `PersistentReference`
+to work with sets.
- >>> from zc.queue._queue import PersistentReferenceSet
- >>> pr_set1 = PersistentReferenceSet((pr1, pr2))
- >>> len(pr_set1)
+ >>> from zc.queue._queue import PersistentReferenceProxy
+ >>> prp1 = PersistentReferenceProxy(pr1)
+ >>> prp2 = PersistentReferenceProxy(pr2)
+ >>> prp3 = PersistentReferenceProxy(pr3)
+ >>> prp_c1 = PersistentReferenceProxy(pr_c1)
+ >>> prp_c2 = PersistentReferenceProxy(pr_c2)
+ >>> prp_c3 = PersistentReferenceProxy(pr_c3)
+ >>> prp1 == prp_c1
+ True
+ >>> prp2 == prp_c2
+ True
+ >>> prp3 == prp_c3
+ True
+ >>> id(prp1) == id(prp_c1)
+ False
+ >>> id(prp2) == id(prp_c2)
+ False
+ >>> id(prp3) == id(prp_c3)
+ False
+
+ >>> set1 = set((prp1, prp2))
+ >>> set1
+ set([SPR (1), SPR (2)])
+ >>> len(set1)
2
- >>> pr_set2 = PersistentReferenceSet((pr_c1, pr_c3))
- >>> len(pr_set1)
+ >>> set2 = set((prp_c1, prp_c3))
+ >>> set2
+ set([SPR (1), SPR (3)])
+ >>> len(set2)
2
- >>> pr_set_c1 = PersistentReferenceSet((pr_c1, pr_c2))
- >>> len(pr_set1)
+ >>> set_c1 = set((prp_c1, prp_c2))
+ >>> set_c1
+ set([SPR (1), SPR (2)])
+ >>> len(set_c1)
2
-Minus operation:
+`set` handles persistent reference properly now. All following set
+operations produce correct results.
- >>> pr_set3 = pr_set1 - pr_set2
- >>> len(pr_set3)
- 1
- >>> pr_set3
- PRSet((SPR (2),))
- >>> pr_set1 - pr_set1
- PRSet(())
- >>> pr_set2 - pr_set3
- PRSet((SPR (1), SPR (3)))
- >>> pr_set3 - pr_set2
- PRSet((SPR (2),))
-
Deduplication:
- >>> pr_set4 = PersistentReferenceSet(
- ... (pr1, pr2, pr3, pr_c1, pr_c2, pr_c3))
- >>> len(pr_set4)
+ >>> set4 = set((prp1, prp2, prp3, prp_c1, prp_c2, prp_c3))
+ >>> len(set4)
3
- >>> pr_set4
- PRSet((SPR (1), SPR (2), SPR (3)))
+ >>> set((prp1, prp_c1))
+ set([SPR (1)])
+ >>> set((prp2, prp_c2))
+ set([SPR (2)])
+ >>> set((prp1, prp_c1, prp2))
+ set([SPR (1), SPR (2)])
+Minus operation:
+
+ >>> set3 = set1 - set2
+ >>> len(set3)
+ 1
+ >>> set3
+ set([SPR (2)])
+ >>> set1 - set1
+ set([])
+ >>> set2 - set3
+ set([SPR (1), SPR (3)])
+ >>> set3 - set2
+ set([SPR (2)])
+
Contains:
- >>> pr3 in pr_set2
+ >>> prp3 in set2
True
- >>> pr1 in pr_set2
+ >>> prp1 in set2
True
- >>> pr_c1 in pr_set2
+ >>> prp_c1 in set2
True
- >>> pr2 not in pr_set2
+ >>> prp2 not in set2
True
Intersection:
- >>> pr_set1 & pr_set2
- PRSet((SPR (1),))
- >>> pr_set1 & pr_set_c1
- PRSet((SPR (1), SPR (2)))
- >>> pr_set2 & pr_set3
- PRSet(())
+ >>> set1 & set2
+ set([SPR (1)])
+ >>> set1 & set_c1
+ set([SPR (1), SPR (2)])
+ >>> set2 & set3
+ set([])
Compare:
- >>> pr_set1 == pr_set_c1
+ >>> set1 == set_c1
True
- >>> pr_set1 == pr_set2
- Traceback (most recent call last):
- ...
- ValueError: can't reliably compare against different PersistentReferences
+ >>> set1 == set2
+ False
+ >>> set1 == set4
+ False
- >>> pr_set1 == pr_set4
- Traceback (most recent call last):
- ...
- ValueError: can't reliably compare against different PersistentReferences
-
-----
.. [#why] The queue's `pull` method is actually the interesting part in why
@@ -607,6 +644,6 @@
unimportant.
.. [#workaround] The reason why we defined
- `PersistentReferenceSet` is that there would be a significant risk
+ `PersistentReferenceProxy` is that there would be a significant risk
of unintended consequenses for some ZODB users if we add __hash__
method to PersistentReference.
Modified: zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/tests.py
===================================================================
--- zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/tests.py 2012-01-10 23:32:13 UTC (rev 124024)
+++ zc.queue/branches/andrew-conflict-resolution-persistent/src/zc/queue/tests.py 2012-01-11 00:12:14 UTC (rev 124025)
@@ -170,7 +170,7 @@
"""
-class StubPersistentReference(object):
+class StubPersistentReference(ConflictResolution.PersistentReference):
def __init__(self, oid):
self.oid = oid
More information about the checkins
mailing list