[ZODB-Dev] Help: ZODB undo problem

Mike C. Fletcher mcfletch@rogers.com
Tue, 18 Jun 2002 21:30:52 -0400


Thanks Shane and Christian,

Unfortunately, I am already using a sync, reset and _resetCache, 
combination which was what got me from "no objects update" to "only 
objects with explicit references fail to update".  The code I'm 
currently using does this:

     undoInfo = self.database.undoInfo( 0, sys.maxint )
     if undoInfo:
         ID = undoInfo[0]['id']
         self.database.undo(ID)
         get_transaction().commit()
         for item in APPLICATION.GetTables():
             item._v_indices_initialised = 0
             item.GetIndices()
         self.connection.reset()
         self.connection.sync()
         self.connection._resetCache()

Given that this seems to be an "outside common experience" problem, I've 
decided to implement (and am almost done integrating) database weakref 
objects (option 2), and punt on trying to figure out why it's failing (I 
want to ship this beta before Monday, and there's lots of other todo 
items).  I'm guessing it might be a problem with the 
indexed-object-collection classes I'm using, though I don't see why 
that's the case at the moment.

With the weakref class, I'm able to avoid the problems with the dialogs 
holding objects, at the expense of explicitly coding every object to use 
weak database references for all run-time references to objects in the 
database (which is taking a while, but isn't killing me I suppose :o/ ).

For the curious, here's the weak reference class:

import weakref

def ref( object ):
     if hasattr( object, '_p_oid'):
         return DBObjectWeakRef( object )
     else:
         return weakref.ref( object )

class DBObjectWeakRef( object ):
     """Reference to a particular object in the database

     Basically this is a weakref that tries to re-connect
     when the original reference is cleaned up.

     Note: assumes use in ConflictSolver, where APPLICATION
     gives us a pointer to the application with the same
     structure as the ConflictSolver application.
     """
     def __init__( self, object ):
         self.object = weakref.ref( object )
         try:
             self.oid = object._p_oid
         except AttributeError:
             raise TypeError( """Attempt to create a DBObjectWeakRef to 
a non-database object %s"""%(repr(object)))
     def __call__( self ):
         """We try to act like a weakreference as much as possible"""
         object = self.object()
         if object is not None:
             return object
         else:
             return self.loadFromDatabase()
     def loadFromDatabase( self ):
         """Attempt to load from database, storing a weakref if 
successful"""
         database = APPLICATION.database
         if database:
             try:
                 connection = APPLICATION.database.connection
                 if connection:
                     object = connection[ self.oid ]
                     if object is not None:
                         self.object = weakref.ref( object )
                     return object
             except:
                 return None
         return None
     def __nonzero__( self ):
         """Test whether we're still valid"""
         return self() is not None

With thanks to you both,
Mike

Christian Reis wrote:
...
> get_connection().sync() IIRC - have you tried it?
...
> Well, you have to call connection.sync() to do this manually. It was
> decided (IIRC) that updating all the objects automatically wouldn't be
> the Right Thing (tm) to do since it would break all the references the
> application held locally; it could elect to update them when it wanted.
...
> Well, we do undo in Stoq, using the ZODB, so I don't think it should be
> a problem. All you do is roll the transaction back and re-show the
> object.
> 
> Take care,
> --
> Christian Reis, Senior Engineer, Async Open Source, Brazil.
> http://async.com.br/~kiko/ | [+55 16] 261 2331 | NMFL
...
_______________________________________
   Mike C. Fletcher
   http://members.rogers.com/mcfletch/