Re: [ZODB-Dev] historicalRevision for subobjects

2005-05-05 Thread Dieter Maurer
Christian Heimes wrote at 2005-5-4 22:14 +0200:
>Dieter Maurer wrote:
>> It is possible (by means of a historical connection)
>> and I posted relevant code some time ago.
>> Search the archive for "HistoryJar".
>
>Sorry I can't find the code. Neither with historical jar zodb nor 
>historical jar dieter googles something useful for me.

Maybe, Google does not index attachments.

Here is the code again.

-- 
Dieter

#   $Id: History.py,v 1.8 2004/01/02 16:47:58 dieter Exp $
'''History extensions.'''

from OFS.History import HystoryJar, Historian, Historical
from struct import pack, unpack
from cStringIO import StringIO
from cPickle import Unpickler
from ZODB.Connection import Connection
from ZODB.POSException import POSKeyError
from ZODB.TimeStamp import TimeStamp
from sys import maxint


# Code mostly stolen from "OFS.History"
def historicalRevision(self,serial):
  '''return the state of *self* current at *serial* and set "_p_jar"
  up in a way that all subobject access has the same property.'''
  jar= HistoryJar(self._p_jar,serial)
  rev= jar[self._p_oid]
  parent= getattr(self,'aq_parent',None)
  of= getattr(rev,'__of__',None)
  if parent is not None and of is not None: rev= of(parent)
  return rev


class HistoryJar(HystoryJar):
  '''a relaying connection selecting an object current at a serial (representing a time).'''
  def __init__(self,base,serial):
HystoryJar.__init__(self,base)
self._jar= base; self._serial= serial
self._cache= {}

  def __getitem__(self,oid):
'''return the state for *oid* current for *_serial*.'''
# determine which history records are available
# ATT: this information should be cached
#  even better, when ZODB would support loading an object valid at serial
jar= self._jar; obj= jar[oid]
rev= obj.__class__.__basicnew__()
rev._p_jar= self
rev._p_oid= oid
self.setstate(rev)
return rev

  def setstate(self,obj):
serial= self._serial; jar= self._jar; oid= obj._p_oid
S= jar._storage
filter= lambda t, serial= serial: t['serial'] <= serial # this might need to become a picklable object, once ZEO supports 'filter'.
if _hasSmartHistory(S):
  ts= S.history(oid,None,1, filter= filter, )
else:
  hf= HistoryFetcher(jar,oid,None,last=1, filter=filter)
  ts= hf.next()
if not ts: raise POSKeyError, (oid,serial)
t= ts[0]
oserial= t['serial']
state= self.oldstate(obj,oserial)
obj._p_serial= oserial
obj.__setstate__(state)
ht= TimeStamp(unpack('8s',serial)[0]).timeTime()
try: obj._p_historical= ht
except AttributeError:
  # this may not be possible, e.g. for __dict__ less instances (such as "BTrees"
  pass
obj._p_changed= 0

  # take over methods from "Connection", because we do not derive
  #   from this class, we must use "im_func".
  oldstate= Connection.oldstate.im_func
  _persistent_load= Connection._persistent_load.im_func



class Historian(Historian):
  '''deliver historical revisions.'''
  def __getitem__(self,key):
self= self.aq_parent
serial=_decodeSerial(key)
# Note: we can not use the shortcut below, because
#   we would loose history information for subobjects
#   which may be newer.
# if serial == self._p_serial: return self
return historicalRevision(self,serial)

class Historical(Historical):
  HistoricalRevisions= Historian()

  # provide information on whether or not this is a historical version
  def isHistorical(self):
'''false (in fact 'None'), if *self* is not historical;
otherwise, the time for which *self* has been requested.'''
return getattr(self,'_p_historical',None)

  def getHistoricalSubpath(self):
'''returns an URL subpath to reference a historical version corresponding to this time.'''
ht= self.isHistorical()
if ht is None: return ''
return '/HistoricalRevisions/' + _encodeSerial(self._p_serial)


  # must override to use our "historicalRevision"
  def manage_historicalComparison(self, REQUEST, keys=[]):
"Compare two selected revisions"
if not keys:
raise HistorySelectionError, (
"No historical revision was selected.")
if len(keys) > 2:
raise HistorySelectionError, (
"Only two historical revision can be compared")

rev1=historicalRevision(self, _decodeSerial(keys[-1]))

if len(keys)==2:
rev2=historicalRevision(self, _decodeSerial(keys[0]))
else:
rev2=self

return self.manage_historyCompare(rev1, rev2, REQUEST)
  

class HistoryFetcher:
  '''auxiliary class to incrementally fetch history.'''
  _curr= 0
  _inc= 1
  _complete= 0

  def __init__(self,jar,oid,version=None,first=0,last=None,filter=None):
'''prepare fetching historical records for *oid* in *version*.

Tries to find records satisfying *filter*. Records *first*
through *last* are returned.
'''
S= jar._storage
history= S.history
if _hasSmartHistory(S): se

Re: [ZODB-Dev] historicalRevision for subobjects

2005-05-04 Thread Christian Heimes
Dieter Maurer wrote:
It is possible (by means of a historical connection)
and I posted relevant code some time ago.
Search the archive for "HistoryJar".
Sorry I can't find the code. Neither with historical jar zodb nor 
historical jar dieter googles something useful for me.

Christian
___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/
ZODB-Dev mailing list  -  ZODB-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zodb-dev


RE: [ZODB-Dev] historicalRevision for subobjects

2005-05-04 Thread Tim Peters
[Christian Heimes]
>>> 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
>>> possible?

...

[Dieter Maurer]
> It is possible (by means of a historical connection) and I posted
> relevant code some time ago. Search the archive for "HistoryJar".

Sorry, Google gets 0 hits on HistoryJar.  Maybe this is what you have in
mind (on the Zope-CMF list a couple years ago)?

http://mail.zope.org/pipermail/zope-cmf/2003-March/018073.html


___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

ZODB-Dev mailing list  -  ZODB-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zodb-dev


RE: [ZODB-Dev] historicalRevision for subobjects

2005-05-04 Thread Dieter Maurer
Tim Peters wrote at 2005-5-2 13:37 -0400:
> ...
>> 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
>> possible?
>
>Sorry, don't know.

It is possible (by means of a historical connection)
and I posted relevant code some time ago.
Search the archive for "HistoryJar".

-- 
Dieter
___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

ZODB-Dev mailing list  -  ZODB-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zodb-dev


RE: [ZODB-Dev] historicalRevision for subobjects

2005-05-02 Thread Tim Peters
[Christian Heimes]
> ...
> 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
code.

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
> possible?

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
Connection._txn_time.

___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

ZODB-Dev mailing list  -  ZODB-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zodb-dev


[ZODB-Dev] historicalRevision for subobjects

2005-04-29 Thread Christian Heimes
Hey :)
I need some guidance from ZODB gurus.
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.

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 possible?

The code for the feature including some tries is in:
http://svn.plone.org/collective/ATContentTypes/branches/tiran-ann-history-fix/lib/historyaware.py
Christian (Tiran)
___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/
ZODB-Dev mailing list  -  ZODB-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zodb-dev