[ZODB-Dev] Bug in cPersistence.c? Transaction.register(object) not called
John D. Heintz
jheintz@isogen.com
Tue, 8 May 2001 17:47:14 -0500
You didn't get two attachments? Well, here are two scripts embeded in the
email.
I think that the problem is something about the state of a Persistent object
and interaction with .....
Oh, wait! I know what the problem is! In the code below I replace the
global get_transaction() call with my own, but only after some Persistent
objects have already cached the PyFunction pointer to the old one. Doh!!!
Ok, here is the code anyway, but I know how to fix it.
John
#------------------START test.py-----------------------
import __main__
import sys
import thread
import threading
import time
import random
import traceback
from StringIO import StringIO
import ZODB
from Persistence import Persistent
from ZODB.Transaction import Transaction
from ZODB.FileStorage import FileStorage
from ZODB.POSException import ConflictError
from per_data import *
def tryCommitFunction(func, args):
"""
Uses _tryFunction to apply the given function to the arguments
and then performs a commit.
Throws an appropriate exception upon failure.
"""
sleepTime=.05
for i in range(10):
try:
result = apply(func, args)
t = get_transaction()
print "Committing %s" % t._objects
t.commit()
return result
except ConflictError:
if i == 10 - 1:
raise
get_transaction().abort()
time.sleep(sleepTime)
sleepTime = sleepTime * 1.5
# ------------
# Global getCorbaSession() support
# Implements Thread Specific Storage pattern from POSA2
_threadToSessionMap = {}
def getCorbaSession():
id = thread.get_ident()
return _threadToSessionMap[id]
def registerCorbaSession(corbaSession):
id = thread.get_ident()
_threadToSessionMap[id] = corbaSession
def unregisterCorbaSession(force = 1):
id = thread.get_ident()
if force or _threadToSessionMap.has_key(id):
del _threadToSessionMap[id]
__main__.__builtins__.getCorbaSession=getCorbaSession
# ------------
# Setup global get_transaction() to use getThorSession().get_transaction()
_threadToTransMap = {}
orig_get_transaction = __main__.__builtins__.get_transaction
def get_transaction():
try:
return getCorbaSession().get_transaction()
except KeyError:
return orig_get_transaction()
def install_get_transaction():
__main__.__builtins__.get_transaction=get_transaction
# ------------
class CorbaSession:
def __init__(self, db):
self.trans = Transaction(0)
self.conn = db.open()
registerCorbaSession(self)
def get_transaction(self):
return self.trans
def get_connection(self):
return self.conn
CONTAINER = 'Container'
storage = FileStorage('data.fs')
db = ZODB.DB(storage)
db.setPoolSize(10000)
#Setup db
connection = db.open()
if not connection.root().has_key(CONTAINER):
fc = FooContainer()
connection.root()[CONTAINER] = fc
get_transaction().commit()
fc.createFoo('b')
get_transaction().commit()
#connection.close()
install_get_transaction()
class TestThread(threading.Thread):
def __init__(self, db):
threading.Thread.__init__(self)
print "Starting %s" % self
self.db = db
self.conn = db.open()
def run(self):
self.session = CorbaSession(self.db)
for x in range(1):
tryCommitFunction(self._run, ())
#TestThread(self.db).start()
def _run(self):
print "*** get container"
fooContainer = self.conn.root()[CONTAINER]
print "*** create Foo"
foo = tryCommitFunction(fooContainer.createFoo,
('a',))
print "created %s" % foo
print "*** get all foos"
foos = tryCommitFunction(fooContainer.getAllFoos, ())
assert foo in foos, "%s not in %s" % (str(foo), str(foos))
print "*** len(foos)=%s" % len(foos)
for foo in foos:
print "*** get bar"
bar = tryCommitFunction(foo.getBar, ())
print "*** get bar's name"
tryCommitFunction(bar.getName, ())
for x in range(1):
TestThread(db).start()
#--------------------END test.py---------------------------------
#--------------------START per_data.py----------------------------
import ZODB
from Persistence import Persistent
def enter():
try:
getCorbaSession().get_connection().sync()
except:
print "!!!!!!!"
class Foo(Persistent):
def __init__(self):
self.bar = None
def setBar(self, bar):
enter()
self.bar = bar
def getBar(self):
enter()
return self.bar
class Bar(Persistent):
def __init__(self, name):
self.name = name
def getName(self):
enter()
return self.name
class FooContainer(Persistent):
def __init__(self):
self.list = []
def __setstate__(self, state):
Persistent.__setstate__(self, state)
print "__setstate__ %s %s %s" % (self, dir(self), state)
def __getstate__(self):
result = Persistent.__getstate__(self)
print "__getstate__ %s %s" % (self, result)
return result
def _p_deactivate(self):
print "_p_deactivate %s %s" % (self, dir(self))
Persistent._p_deactivate(self)
def createBar(self, name):
enter()
bar = Bar(name)
return bar
def createFoo(self, barName):
print "--- create Foo"
print "--- len(self.list)=%s" % len(self.list)
enter()
print "--- init Foo"
foo = Foo()
print "--- %s" % foo
bar = self.createBar(barName)
foo.setBar(bar)
self.list.append(foo)
print "self._p_changed=%s" % self._p_changed
self.list = self.list
print "self._p_changed=%s" % self._p_changed
# XXX This isn't called and should be!!
get_transaction().register(self)
assert self in get_transaction()._objects
print "--- len(self.list)=%s" % len(self.list)
return foo
def getAllFoos(self):
enter()
return self.list
#----------------------END per_data.py-------------------------
On Tuesday 08 May 2001 17:17, Jeremy Hylton wrote:
> >>>>> "JDH" == John D Heintz <jheintz@isogen.com> writes:
>
> JDH> Attached is a test file and persistent data structures file
> JDH> that demonstrates a problems we are having with using ZODB and
> JDH> CORBA.
>
> Is the text after your message all one script? Where is the data
> file? I don't think I understand how to execute this code to produce
> the error.
>
> My other question is: What do you think the problem is? It's hard to
> tell what has gone wrong by staring at the code <0.3 wink>. An
> explanation of the apparent problem would be helpful.
>
> Jeremy