[Checkins] SVN: zc.queue/trunk/s add some discussion of subtleties as footnotes

Gary Poster gary at zope.com
Wed May 30 15:34:56 EDT 2007


Log message for revision 76009:
  add some discussion of subtleties as footnotes

Changed:
  U   zc.queue/trunk/setup.py
  U   zc.queue/trunk/src/zc/queue/queue.txt

-=-
Modified: zc.queue/trunk/setup.py
===================================================================
--- zc.queue/trunk/setup.py	2007-05-30 19:34:45 UTC (rev 76008)
+++ zc.queue/trunk/setup.py	2007-05-30 19:34:55 UTC (rev 76009)
@@ -2,7 +2,7 @@
 
 setup(
     name="zc.queue",
-    version="1.0.1",
+    version="1.0.2-dev",
     license="ZPL 2.1",
     author="Zope Project",
     author_email="zope3-dev at zope.org",

Modified: zc.queue/trunk/src/zc/queue/queue.txt
===================================================================
--- zc.queue/trunk/src/zc/queue/queue.txt	2007-05-30 19:34:45 UTC (rev 76008)
+++ zc.queue/trunk/src/zc/queue/queue.txt	2007-05-30 19:34:55 UTC (rev 76009)
@@ -12,7 +12,7 @@
 hold more than one reference to any given equivalent item at a time.  For
 instance, some of the conflict resolution features will not perform
 desirably if it is reasonable for your application to hold two copies of the
-string "hello" within the same queue at once.
+string "hello" within the same queue at once [#why]_.
 
 The module provides two flavors: a simple persistent queue that keeps all
 contained objects in one persistent object (`PersistentQueue`), and a
@@ -143,9 +143,14 @@
 That's it--there's no additional way to add anything beyond `put`, and no
 additional way to remove anything beyond `pull`.
 
-The only other wrinkle is the conflict resolution code.  To show this, we
-will have to have two copies of the same queue, from two different connections.
+The only other wrinkle is the conflict resolution code.  Conflict
+resolution in ZODB has some general caveats of which you should be aware
+[#caveats]_.
 
+These general caveats aside, we'll now examine some examples of zc.queue
+conflict resolution at work.  To show this, we will have to have two
+copies of the same queue, from two different connections.
+
 NOTE: this testing approach has known weaknesses.  See discussion in tests.py.
 
     >>> import transaction
@@ -386,3 +391,64 @@
     [8, 9, 10, 11, 12, 13, 14, 15]
 
     >>> db.close() # cleanup
+
+.. [#why] The queue's `pull` method is actually the interesting part in why
+    this constraint is used, and it becomes more so when you allow an
+    arbitrary pull.  By asserting that you do not support having equal
+    items in the queue at once, you can simply say that when you remove
+    equal objects in the current state and the contemporary, conflicting
+    state, it's a conflict error.  Ideally you don't enter another equal
+    item in that queue again, or else in fact this is still an
+    error-prone heuristic:
+    
+      - start queue == [X];
+      - begin transactions A and B;
+      - B removes X and commits;
+      - transaction C adds X and Y and commits;
+      - transaction A removes X and tries to commit, and conflict resolution
+        code believes that it is ok to remove the new X from transaction C
+        because it looks like it was just an addition of Y).  Commit succeeds,
+        and should not.
+
+    If you don't assert that you can use equality to examine conflicts,
+    then you have to come up with another heuristic.  Given that the
+    conflict resolution code only gets three states to resolve, I don't
+    know of a reliable one.
+
+    Therefore, zc.queue has a policy of assuming that it can use
+    equality to distinguish items.  It's limiting, but the code can have
+    a better confidence of doing the right thing.
+
+    Also, FWIW, this is policy I want: for my use cases, it would be
+    possible to put in two items in a queue that handle the same issue. 
+    With the right equality code, this can be avoided with the policy
+    the queue has now.
+
+.. [#caveats] Here are a few caveats about the state (as of this
+    writing) of ZODB conflict resolution in general.
+
+    The biggest is that, if you store persistent.Persistent subclass
+    objects in a queue (or any other collection with conflict resolution
+    code, such as a BTree), the collection will get a placeholder object
+    (ZODB.ConflictResolution.PersistentReference), rather than the real
+    contained object.  This object has a standard Python __cmp__ based
+    on identity in memory (e.g. `id(obj)`).  The same oid will get the
+    same placeholder in the different states for conflict resolution, so
+    that may be sufficient for reasonable behavior in a queue as long as
+    only objects with the same oid may be considered equal.  (This is very
+    problematic behavior if your persistent object is a key in a BTree,
+    however.)
+
+    Another is that, in ZEO, conflict resolution is currently done on
+    the server, so the ZEO server must have a copy of the classes
+    (software) necessary to instantiate any non-persistent object in the
+    collection.
+
+    A corollary to the above is that objects such as
+    zope.app.keyreference.persistent, which are not persistent
+    themselves but rely on a persistent object for their __cmp__, will
+    fail during conflict resolution.  A reasonable solution in the case
+    of zope.app.keyreference.persistent code is to have the object store
+    the information it needs to do the comparison on itself, so the
+    absence of the persistent object during conflict resolution is
+    unimportant.



More information about the Checkins mailing list