[Zope-Checkins] CVS: Zope3/lib/python/ZODB - BaseStorage.py:1.15.10.1 ConflictResolution.py:1.7.30.1 Connection.py:1.60.6.1 DB.py:1.34.4.1 FileStorage.py:1.75.10.1 POSException.py:1.7.86.1 TimeStamp.c:1.8.4.1 __init__.py:1.10.60.1 DemoStorage.py:NONE PersistentMapping.py:NONE Setup:NONE Transaction.py:NONE bpthread.py:NONE cPersistence.c:NONE cPersistence.h:NONE cPickleCache.c:NONE conversionhack.py:NONE coptimizations.c:NONE
Jim Fulton
jim@zope.com
Sun, 25 Nov 2001 19:39:42 -0500
Update of /cvs-repository/Zope3/lib/python/ZODB
In directory cvs.zope.org:/tmp/cvs-serv18399
Modified Files:
Tag: Zope-3x-branch
BaseStorage.py ConflictResolution.py Connection.py DB.py
FileStorage.py POSException.py TimeStamp.c __init__.py
Removed Files:
Tag: Zope-3x-branch
DemoStorage.py PersistentMapping.py Setup Transaction.py
bpthread.py cPersistence.c cPersistence.h cPickleCache.c
conversionhack.py coptimizations.c
Log Message:
Refactored persistence and transactions out of ZODB.
Changed to use threading locks.
Removed temporarily:
- C optimizations
- DemoStorage, because it depends on not-yet-ported BTrees.
=== Zope3/lib/python/ZODB/BaseStorage.py 1.15 => 1.15.10.1 ===
__version__ = string.split('$Revision$')[-2:][0]
-import ThreadLock, bpthread
+import threading
import time, UndoLogCompatible
import POSException
from TimeStamp import TimeStamp
@@ -104,10 +104,10 @@
self.__name__=name
# Allocate locks:
- l=ThreadLock.allocate_lock()
+ l=threading.RLock()
self._lock_acquire=l.acquire
self._lock_release=l.release
- l=bpthread.allocate_lock()
+ l=threading.Lock()
self._commit_lock_acquire=l.acquire
self._commit_lock_release=l.release
=== Zope3/lib/python/ZODB/ConflictResolution.py 1.7 => 1.7.30.1 ===
from ZODB.POSException import ConflictError
+__new__=object.__new__
+
#import traceback
bad_classes={}
@@ -163,7 +165,11 @@
newstate=unpickler.load()
klass=_classFactory(class_tuple[0], class_tuple[1])
- inst=klass.__basicnew__()
+
+ #??? inst=klass.__basicnew__()
+ # CXX This isn't quite right, but I'm not sure what is.
+ # The contacts are a bit unclear.
+ inst=__new__(klass)
try:
resolve=inst._p_resolveConflict
=== Zope3/lib/python/ZODB/Connection.py 1.60 => 1.60.6.1 ===
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
-# Zope Public License (ZPL) Version 1.0
-# -------------------------------------
-#
-# Copyright (c) Digital Creations. All rights reserved.
-#
-# This license has been certified as Open Source(tm).
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# 1. Redistributions in source code must retain the above copyright
-# notice, this list of conditions, and the following disclaimer.
-#
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions, and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-#
-# 3. Digital Creations requests that attribution be given to Zope
-# in any manner possible. Zope includes a "Powered by Zope"
-# button that is installed by default. While it is not a license
-# violation to remove this button, it is requested that the
-# attribution remain. A significant investment has been put
-# into Zope, and this effort will continue if the Zope community
-# continues to grow. This is one way to assure that growth.
-#
-# 4. All advertising materials and documentation mentioning
-# features derived from or use of this software must display
-# the following acknowledgement:
-#
-# "This product includes software developed by Digital Creations
-# for use in the Z Object Publishing Environment
-# (http://www.zope.org/)."
-#
-# In the event that the product being advertised includes an
-# intact Zope distribution (with copyright and license included)
-# then this clause is waived.
-#
-# 5. Names associated with Zope or Digital Creations must not be used to
-# endorse or promote products derived from this software without
-# prior written permission from Digital Creations.
-#
-# 6. Modified redistributions of any form whatsoever must retain
-# the following acknowledgment:
-#
-# "This product includes software developed by Digital Creations
-# for use in the Z Object Publishing Environment
-# (http://www.zope.org/)."
-#
-# Intact (re-)distributions of any official Zope release do not
-# require an external acknowledgement.
-#
-# 7. Modifications are encouraged but must be packaged separately as
-# patches to official Zope releases. Distributions that do not
-# clearly separate the patches from the original work must be clearly
-# labeled as unofficial distributions. Modifications which do not
-# carry the name Zope may be packaged in any form, as long as they
-# conform to all of the clauses above.
-#
-#
-# Disclaimer
-#
-# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
-# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-#
-# This software consists of contributions made by Digital Creations and
-# many individuals on behalf of Digital Creations. Specific
-# attributions are listed in the accompanying credits file.
-#
+# This software is subject to the provisions of the Zope Public License,
+# Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
##############################################################################
"""Database connection support
$Id$"""
__version__='$Revision$'[11:-2]
-from cPickleCache import PickleCache
+from Persistence.Cache import Cache
from POSException import ConflictError
-from ExtensionClass import Base
import ExportImport, TmpStore
from zLOG import LOG, ERROR, BLATHER
-from coptimizations import new_persistent_id
from ConflictResolution import ResolvedSerial
from cPickle import Unpickler, Pickler
@@ -101,6 +25,10 @@
from time import time
from types import StringType, ClassType
+from Transaction import get_transaction
+
+__new__=object.__new__
+
global_code_timestamp = 0
def updateCodeTimestamp():
@@ -112,7 +40,7 @@
global global_code_timestamp
global_code_timestamp = time()
-ExtensionKlass=Base.__class__
+ExtensionKlass=object.__class__
class Connection(ExportImport.ExportImport):
"""Object managers for individual object space.
@@ -135,7 +63,7 @@
cache_deactivate_after=60):
"""Create a new Connection"""
self._version=version
- self._cache=cache=PickleCache(self, cache_size, cache_deactivate_after)
+ self._cache=cache=Cache(cache_size, cache_deactivate_after)
self._incrgc=self.cacheGC=cache.incrgc
self._invalidated=d={}
self._invalid=d.has_key
@@ -153,7 +81,8 @@
def __getitem__(self, oid,
tt=type(())):
cache=self._cache
- if cache.has_key(oid): return cache[oid]
+ object=cache.get(oid, self)
+ if object is not self: return object
__traceback_info__ = (oid)
p, serial = self._storage.load(oid, self._version)
@@ -176,7 +105,10 @@
if (args is None or
not args and not hasattr(klass,'__getinitargs__')):
- object=klass.__basicnew__()
+ #??? object=klass.__basicnew__()
+ # CXX This isn't quite right, but I'm not sure what is.
+ # The contacts are a bit unclear.
+ object=__new__(klass)
else:
object=apply(klass,args)
if klass is not ExtensionKlass:
@@ -191,8 +123,79 @@
if oid=='\0\0\0\0\0\0\0\0': self._root_=object # keep a ref
return object
- def _persistent_load(self,oid,
- tt=type(())):
+ ######################################################################
+ # IPersistentDataManager
+
+ def setstate(self, object):
+ try:
+ oid=object._p_oid
+
+ p, serial = self._storage.load(oid, self._version)
+
+ # XXX this is quite conservative!
+ # We need, however, to avoid reading data from a transaction
+ # that committed after the current "session" started, as
+ # that might lead to mixing of cached data from earlier
+ # transactions and new inconsistent data.
+ #
+ # Note that we (carefully) wait until after we call the
+ # storage to make sure that we don't miss an invaildation
+ # notifications between the time we check and the time we
+ # read.
+ invalid=self._invalid
+ if invalid(oid) or invalid(None):
+ if not hasattr(object.__class__, '_p_independent'):
+ get_transaction().register(self)
+ raise ConflictError(`oid`, `object.__class__`)
+ invalid=1
+ else:
+ invalid=0
+
+ file=StringIO(p)
+ unpickler=Unpickler(file)
+ unpickler.persistent_load=self._persistent_load
+ unpickler.load()
+ state = unpickler.load()
+
+ if hasattr(object, '__setstate__'):
+ object.__setstate__(state)
+ else:
+ d=object.__dict__
+ for k,v in state.items(): d[k]=v
+
+ object._p_serial=serial
+
+ if invalid:
+ if object._p_independent():
+ try: del self._invalidated[oid]
+ except KeyError: pass
+ else:
+ get_transaction().register(self)
+ raise ConflictError(`oid`, `object.__class__`)
+
+ except ConflictError:
+ raise
+ except:
+ LOG('ZODB',ERROR, "Couldn't load state for %s" % `oid`,
+ error=sys.exc_info())
+ raise
+
+ # Add the object to the cache active list:
+ self._cache.setstate(oid, object)
+
+ def register(self, object):
+ get_transaction().register(object)
+
+ def mtime(self, object):
+ try: mtime=self._storage.mtime
+ except AttributeError: return None
+ return mtime(object._p_oid, object._p_serial)
+
+ ######################################################################
+
+
+ def _persistent_load(self, oid,
+ tt=type(())):
__traceback_info__=oid
@@ -202,7 +205,8 @@
# Quick instance reference. We know all we need to know
# to create the instance wo hitting the db, so go for it!
oid, klass = oid
- if cache.has_key(oid): return cache[oid]
+ object=cache.get(oid, self)
+ if object is not self: return object
if type(klass) is tt:
module, name = klass
@@ -213,7 +217,10 @@
# object's actual record!
return self[oid]
- object=klass.__basicnew__()
+ # CXX This isn't quite right, but I'm not sure what is.
+ # The contacts are a bit unclear.
+ object=__new__(klass)
+
object._p_oid=oid
object._p_jar=self
object._p_changed=None
@@ -222,7 +229,8 @@
return object
- if cache.has_key(oid): return cache[oid]
+ object=cache.get(oid, self)
+ if object is not self: return object
return self[oid]
def _setDB(self, odb):
@@ -237,7 +245,7 @@
# New code is in place. Start a new cache.
self._resetCache()
else:
- self._cache.invalidate(self._invalidated)
+ self._cache.invalidateMany(self._invalidated)
self._opened=time()
return self
@@ -258,7 +266,7 @@
This just deactivates the thing.
"""
if object is self:
- self._cache.invalidate(self._invalidated)
+ self._cache.invalidateMany(self._invalidated)
else:
self._cache.invalidate(object._p_oid)
@@ -328,34 +336,6 @@
return
stack=[object]
-
- # Create a special persistent_id that passes T and the subobject
- # stack along:
- #
- # def persistent_id(object,
- # self=self,
- # stackup=stackup, new_oid=self.new_oid):
- # if (not hasattr(object, '_p_oid') or
- # type(object) is ClassType): return None
- #
- # oid=object._p_oid
- #
- # if oid is None or object._p_jar is not self:
- # oid = self.new_oid()
- # object._p_jar=self
- # object._p_oid=oid
- # stackup(object)
- #
- # klass=object.__class__
- #
- # if klass is ExtensionKlass: return oid
- #
- # if hasattr(klass, '__getinitargs__'): return oid
- #
- # module=getattr(klass,'__module__','')
- # if module: klass=module, klass.__name__
- #
- # return oid, klass
file=StringIO()
seek=file.seek
@@ -470,7 +450,7 @@
self._storage=tmp
- self._cache.invalidate(src._index.keys())
+ self._cache.invalidateMany(src._index.keys())
self._invalidate_creating(src._creating)
def _invalidate_creating(self, creating=None):
@@ -489,8 +469,6 @@
del o._p_oid
del cache[oid]
- #XXX
-
def db(self): return self._db
def getVersion(self): return self._version
@@ -511,61 +489,14 @@
def root(self): return self['\0\0\0\0\0\0\0\0']
- def setstate(self, object):
- try:
- oid=object._p_oid
-
- p, serial = self._storage.load(oid, self._version)
-
- # XXX this is quite conservative!
- # We need, however, to avoid reading data from a transaction
- # that committed after the current "session" started, as
- # that might lead to mixing of cached data from earlier
- # transactions and new inconsistent data.
- #
- # Note that we (carefully) wait until after we call the
- # storage to make sure that we don't miss an invaildation
- # notifications between the time we check and the time we
- # read.
- invalid=self._invalid
- if invalid(oid) or invalid(None):
- if not hasattr(object.__class__, '_p_independent'):
- get_transaction().register(self)
- raise ConflictError(`oid`, `object.__class__`)
- invalid=1
- else:
- invalid=0
-
- file=StringIO(p)
- unpickler=Unpickler(file)
- unpickler.persistent_load=self._persistent_load
- unpickler.load()
- state = unpickler.load()
-
- if hasattr(object, '__setstate__'):
- object.__setstate__(state)
- else:
- d=object.__dict__
- for k,v in state.items(): d[k]=v
-
- object._p_serial=serial
-
- if invalid:
- if object._p_independent():
- try: del self._invalidated[oid]
- except KeyError: pass
- else:
- get_transaction().register(self)
- raise ConflictError(`oid`, `object.__class__`)
+ def oldstate(self, object, serial):
+ """Return the state of an object as it existed in some time in the past
- except ConflictError:
- raise
- except:
- LOG('ZODB',ERROR, "Couldn't load state for %s" % `oid`,
- error=sys.exc_info())
- raise
+ The time is specified via a serial number.
- def oldstate(self, object, serial):
+ This routine is used by Zope's History facility.
+ """
+
oid=object._p_oid
p = self._storage.loadSerial(oid, serial)
file=StringIO(p)
@@ -610,8 +541,8 @@
del self.__onCommitActions
self._storage.tpc_abort(transaction)
cache=self._cache
- cache.invalidate(self._invalidated)
- cache.invalidate(self._invalidating)
+ cache.invalidateMany(self._invalidated)
+ cache.invalidateMany(self._invalidating)
self._invalidate_creating()
def tpc_begin(self, transaction, sub=None):
@@ -703,7 +634,7 @@
self._storage.tpc_finish(transaction,
self._invalidate_invalidating)
- self._cache.invalidate(self._invalidated)
+ self._cache.invalidateMany(self._invalidated)
self._incrgc() # This is a good time to do some GC
def _invalidate_invalidating(self):
@@ -716,7 +647,7 @@
get_transaction().abort()
sync=getattr(self._storage, 'sync', 0)
if sync != 0: sync()
- self._cache.invalidate(self._invalidated)
+ self._cache.invalidateMany(self._invalidated)
self._incrgc() # This is a good time to do some GC
def getDebugInfo(self): return self._debug_info
@@ -738,3 +669,35 @@
def close(self):
self._breakcr()
+def new_persistent_id(self, stackup):
+
+ # Create a special persistent_id that passes T and the subobject
+ # stack along:
+
+ def persistent_id(object, self=self, stackup=stackup):
+
+ new_oid = self.new_oid
+
+ if (not hasattr(object, '_p_oid') or
+ type(object) is ClassType): return None
+
+ oid=object._p_oid
+
+ if oid is None or object._p_jar is not self:
+ oid = self.new_oid()
+ object._p_jar=self
+ object._p_oid=oid
+ stackup(object)
+
+ klass=object.__class__
+
+ if klass is ExtensionKlass: return oid
+
+ if hasattr(klass, '__getinitargs__'): return oid
+
+ module=getattr(klass,'__module__','')
+ if module: klass=module, klass.__name__
+
+ return oid, klass
+
+ return persistent_id
=== Zope3/lib/python/ZODB/DB.py 1.34 => 1.34.4.1 ===
import cPickle, cStringIO, sys, POSException, UndoLogCompatible
from Connection import Connection
-from bpthread import allocate_lock
+from threading import Lock
from Transaction import Transaction
from referencesf import referencesf
from time import time, ctime
@@ -124,7 +124,7 @@
"""
# Allocate locks:
- l=allocate_lock()
+ l=Lock()
self._a=l.acquire
self._r=l.release
@@ -146,10 +146,10 @@
if not hasattr(storage,'tpc_vote'): storage.tpc_vote=lambda *args: None
try: storage.load('\0\0\0\0\0\0\0\0','')
except:
- import PersistentMapping
+ from Persistence import PersistentMapping
file=cStringIO.StringIO()
p=cPickle.Pickler(file,1)
- p.dump((PersistentMapping.PersistentMapping,None))
+ p.dump((PersistentMapping,None))
p.dump({'_container': {}})
t=Transaction()
t.description='initial database creation'
@@ -453,7 +453,7 @@
pool, allocated, pool_lock = pools[version]
else:
pool, allocated, pool_lock = pools[version] = (
- [], [], allocate_lock())
+ [], [], Lock())
pooll.append((pool, allocated))
pool_lock.acquire()
=== Zope3/lib/python/ZODB/FileStorage.py 1.75 => 1.75.10.1 ===
__version__='$Revision$'[11:-2]
-import struct, time, os, bpthread, string, base64, sys
+import struct, time, os, string, base64, sys
from struct import pack, unpack
from cPickle import loads
import POSException
=== Zope3/lib/python/ZODB/POSException.py 1.7 => 1.7.86.1 ===
__version__='$Revision$'[11:-2]
+from Transaction.Exceptions import TransactionError, ConflictError
+
from string import join
StringType=type('')
DictType=type({})
class POSError(Exception):
"""Persistent object system error
- """
-
-class TransactionError(POSError):
- """An error occured due to normal transaction processing
- """
-
-class ConflictError(TransactionError):
- """Two transactions tried to modify the same object at once
-
- This transaction should be resubmitted.
"""
class VersionError(POSError):
=== Zope3/lib/python/ZODB/TimeStamp.c 1.8 => 1.8.4.1 ===
#include <stdlib.h>
#include <time.h>
-#ifdef USE_EXTENSION_CLASS
-#include "ExtensionClass.h"
-#else
#include "Python.h"
-#endif
static PyObject *ErrorObject;
@@ -361,35 +357,12 @@
{"seconds", (PyCFunction)TimeStamp_second, METH_VARARGS, ""},
{"timeTime", (PyCFunction)TimeStamp_timeTime, METH_VARARGS, ""},
{"laterThan", (PyCFunction)TimeStamp_laterThan, METH_VARARGS, ""},
-#ifdef USE_EXTENSION_CLASS
- {"__init__", (PyCFunction)TimeStamp___init__, METH_VARARGS,
- ""},
-#endif
{NULL, NULL} /* sentinel */
};
-#ifndef USE_EXTENSION_CLASS
-static TimeStampobject *
-newTimeStamp(PyObject *ignored, PyObject *args)
-{
- TimeStamp *self;
-
- UNLESS(self = PyObject_NEW(TimeStamp, &TimeStampType)) return NULL;
-
- ignored=__init__(self, args);
- if (! ignored) return NULL;
-
- Py_DECREF(ignored);
- return self;
-}
-#endif
-
static void
TimeStamp_dealloc(TimeStamp *self)
{
-#ifdef USE_EXTENSION_CLASS
- Py_DECREF(self->ob_type);
-#endif
PyMem_DEL(self);
}
@@ -429,21 +402,13 @@
static PyObject *
TimeStamp_getattro(TimeStamp *self, PyObject *name)
{
-#ifndef USE_EXTENSION_CLASS
char *s;
if (! (s=PyString_AsString(name))) return NULL;
- return Py_FindMethod(TimeStamp_methods, self, s);
-#else
- return Py_FindAttr(OBJECT(self), name);
-#endif
+ return Py_FindMethod(TimeStamp_methods, OBJECT(self), s);
}
-#ifdef USE_EXTENSION_CLASS
-static PyExtensionClass
-#else
static PyTypeObject
-#endif
TimeStampType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
@@ -469,15 +434,24 @@
/* Space for future expansion */
0L,0L,
"Simple time stamps"
-#ifdef USE_EXTENSION_CLASS
- , METHOD_CHAIN(TimeStamp_methods),
-#endif
};
+static TimeStamp *
+newTimeStamp(PyObject *ignored, PyObject *args)
+{
+ TimeStamp *self;
+
+ UNLESS(self = PyObject_NEW(TimeStamp, &TimeStampType)) return NULL;
+
+ ignored=TimeStamp___init__(self, args);
+ if (! ignored) return NULL;
+
+ Py_DECREF(ignored);
+ return self;
+}
+
static struct PyMethodDef Module_Level__methods[] = {
-#ifndef USE_EXTENSION_CLASS
{"TimeStamp", (PyCFunction)newTimeStamp, METH_VARARGS, ""},
-#endif
{NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */
};
@@ -488,7 +462,6 @@
char *rev="$Revision$";
if (TimeStamp_init_gmoff() < 0) return;
- if (! ExtensionClassImported) return;
/* Create the module and add the functions */
m = Py_InitModule4("TimeStamp", Module_Level__methods,
@@ -498,11 +471,7 @@
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
-#ifndef USE_EXTENSION_CLASS
TimeStampType.ob_type=&PyType_Type;
-#else
- PyExtensionClass_Export(d, "TimeStamp", TimeStampType);
-#endif
PyDict_SetItemString(d,"TimeStampType", OBJECT(&TimeStampType));
=== Zope3/lib/python/ZODB/__init__.py 1.10 => 1.10.60.1 ===
#
##############################################################################
-import sys, ExtensionClass, TimeStamp, cPersistence, Persistence
-import cStringIO, cPickle
from zLOG import register_subsystem
register_subsystem('ZODB')
-
-# This is lame. Don't look. :(
-sys.modules['cPersistence']=cPersistence
-
-Persistent=cPersistence.Persistent
-
-# Install Persistent and PersistentMapping in Persistence
-if not hasattr(Persistence, 'Persistent'):
- Persistence.Persistent=Persistent
- Persistent.__module__='Persistence'
- Persistence.Overridable=cPersistence.Overridable
- Persistence.Overridable.__module__='Persistence'
- if not hasattr(Persistence, 'PersistentMapping'):
- import PersistentMapping
- sys.modules['PersistentMapping']=PersistentMapping
- sys.modules['BoboPOS']=sys.modules['ZODB']
- sys.modules['BoboPOS.PersistentMapping']=PersistentMapping
- PersistentMapping=PersistentMapping.PersistentMapping
- from PersistentMapping import PersistentMapping
- Persistence.PersistentMapping=PersistentMapping
- PersistentMapping.__module__='Persistence'
- del PersistentMapping
-
-del cPersistence
+del register_subsystem
from DB import DB
-import Transaction
+# The following provides some backward compat:
+from Transaction import get_transaction
+import __main__
+__main__.__builtins__.get_transaction=get_transaction
+del __main__
+del get_transaction
=== Removed File Zope3/lib/python/ZODB/DemoStorage.py ===
=== Removed File Zope3/lib/python/ZODB/PersistentMapping.py ===
=== Removed File Zope3/lib/python/ZODB/Setup ===
=== Removed File Zope3/lib/python/ZODB/Transaction.py ===
=== Removed File Zope3/lib/python/ZODB/bpthread.py ===
=== Removed File Zope3/lib/python/ZODB/cPersistence.c ===
=== Removed File Zope3/lib/python/ZODB/cPersistence.h ===
=== Removed File Zope3/lib/python/ZODB/cPickleCache.c ===
=== Removed File Zope3/lib/python/ZODB/conversionhack.py ===
=== Removed File Zope3/lib/python/ZODB/coptimizations.c ===