Ok, I have the asyncore loop in, I've added explicit transaction begin and aborts, and cleaned up the test case a bit:
import thread import asyncore import random from ZEO.ClientStorage import ClientStorage from ZODB import DB from persistent.list import PersistentList from ZODB.POSException import ConflictError import transaction storage = ClientStorage(('bw64node01', 12345)) db = DB(storage) conn = db.open() root = conn.root() conn.sync() thread.start_new_thread(asyncore.loop,()) if 'test' not in root: try: transaction.begin() root['test'] = PersistentList([0,1]) transaction.commit() except ConflictError: transaction.abort() g = root['test'] y = PersistentList() while 1: try: transaction.begin() g[g.index(random.choice(g))] = y # g[g.index(random.choice(g))] = PersistentList() transaction.commit() except ConflictError: transaction.abort() Now, when 4 or so instances are run in parallel, this will fail with POSKeyError corruption of the ZODB database. However, if you uncomment the commented out line, it's fine. Maybe I'm missing something - why can't I create a PersistentList outside of the transaction, and then add multiple entries inside root['test'] pointing to it? Another interesting thing; if I add time.sleep(1) to the end of the while loop, then the problem goes away. Possibly there is some kind of cache race condition, where the ZEO server sends invalidations immediately after the client has commited? _______________________________________________ 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