Christian Theune and me have implemented a diffed history feature for
Archetypes based content types. It's part of ATContentTypes and is meant
to help reviewers to see the differences between different revisions of
an object. The code is using the method OFS.History.historicalRevision +
db().oldstate() to iterate over the ZODB revisions of the object.
The code was working very well because we were using AttributeStorage. AS
stores the data of Archetype fields as a simple attribute on the object.
For security and performance reasons I have implemented annotation
storage that is using Zope3 style attribute annotations to store the data
in an OOBTree attached to the object. With AnnotationStorage the history
isn't working any more because historicalRevision() returns only an older
version of the object but *not* older versions of its subobjects like the
btree. Even trying to get the different revisions of the oobtree didn't
help. The symptoms were the same. I assume I have to get the revisions of
the btree bucket or choose a different path.
Yes, under the covers a BTree is an arbitrarily large graph (rooted DAG --
directed and acyclic) of BTree and Bucket objects. Each such object in a
BTree graph has its own history (each is a distinct first-class persistent
object in its own right). The object most app code thinks of as being the
BTree is just the root of this arbitrarily large object graph, and the
other objects in the graph generally aren't directly visible to application
It's common as mud, e.g., that adding a new key to a BTree doesn't change
its root object; then fetching an older revision of the root will still
point to the current revision of the bucket to which that key was added.
Indeed, BTrees are designed to make this so: if every key addition mutated
the root object, any two transactions adding to a single BTree concurrently
would suffer a write conflict (as does indeed happen if using, e.g., a
PersistentMapping or PersistentList instead).
I had the idea of getting a snapshot of the entire ZODB for a given
transaction serial number but I don't know how to get it. Is this
Sorry, don't know. I don't expect a reasonable way exists in ZODB 3.2. It
may be possible to trick ZODB 3.3/3.4's MVCC machinery into delivering a
consistent past view (provided it hasn't been packed away!), but if so it's
not an exposed mechanism. You might want to stare at the code involving
For more information about ZODB, see the ZODB Wiki:
ZODB-Dev mailing list - ZODB-Dev@zope.org