[Zodb-checkins] CVS: Zope/lib/python/ZODB - ActivityMonitor.py:1.3.4.4 BaseStorage.py:1.20.4.10 ConflictResolution.py:1.13.4.3 Connection.py:1.72.4.9 DB.py:1.43.4.3 DemoStorage.py:1.12.4.10 ExportImport.py:1.14.4.1 FileStorage.py:1.95.4.9 POSException.py:1.12.4.12 StorageConfig.py:1.1.2.2 StorageTypes.py:1.1.2.4 TimeStamp.c:1.15.58.6 TmpStore.py:1.7.4.1 Transaction.py:1.37.4.8 UndoLogCompatible.py:1.6.4.1 cPersistence.c:1.62.8.6 cPickleCache.c:1.68.8.3 coptimizations.c:1.17.58.4 fsIndex.py:1.3.4.1 fsdump.py:1.3.68.3 lock_file.py:1.6.4.1 utils.py:1.12.4.2

Chris McDonough chrism@zope.com
Fri, 3 Jan 2003 01:38:04 -0500


Update of /cvs-repository/Zope/lib/python/ZODB
In directory cvs.zope.org:/tmp/cvs-serv28517

Modified Files:
      Tag: chrism-install-branch
	ActivityMonitor.py BaseStorage.py ConflictResolution.py 
	Connection.py DB.py DemoStorage.py ExportImport.py 
	FileStorage.py POSException.py StorageConfig.py 
	StorageTypes.py TimeStamp.c TmpStore.py Transaction.py 
	UndoLogCompatible.py cPersistence.c cPickleCache.c 
	coptimizations.c fsIndex.py fsdump.py lock_file.py utils.py 
Log Message:
Merging chrism-install-branch with HEAD (hopefully for one of the last
times).



=== Zope/lib/python/ZODB/ActivityMonitor.py 1.3.4.3 => 1.3.4.4 ===


=== Zope/lib/python/ZODB/BaseStorage.py 1.20.4.9 => 1.20.4.10 ===
--- Zope/lib/python/ZODB/BaseStorage.py:1.20.4.9	Sun Nov 24 19:22:53 2002
+++ Zope/lib/python/ZODB/BaseStorage.py	Fri Jan  3 01:37:19 2003
@@ -250,7 +250,7 @@
         Dictionary values should be None; this will be a handy place
         for extra marshalling information, should we need it
         """
-	return {}
+        return {}
 
     def copyTransactionsFrom(self, other, verbose=0):
         """Copy transactions from another storage.
@@ -295,7 +295,8 @@
                         print ('Time stamps back in order %s' % (t))
                         ok=1
 
-            if verbose: print _ts
+            if verbose:
+                print _ts
 
             self.tpc_begin(transaction, tid, transaction.status)
             for r in transaction:


=== Zope/lib/python/ZODB/ConflictResolution.py 1.13.4.2 => 1.13.4.3 ===
--- Zope/lib/python/ZODB/ConflictResolution.py:1.13.4.2	Sun Nov 24 19:10:12 2002
+++ Zope/lib/python/ZODB/ConflictResolution.py	Fri Jan  3 01:37:19 2003
@@ -92,16 +92,18 @@
         unpickler.persistent_load = prfactory.persistent_load
         class_tuple = unpickler.load()[0]
         if bad_class(class_tuple):
-            return 0
+            return None
         newstate = unpickler.load()
         klass = load_class(class_tuple)
+        if klass is None:
+            return None
         inst = klass.__basicnew__()
 
         try:
             resolve = inst._p_resolveConflict
         except AttributeError:
             bad_classes[class_tuple] = 1
-            return 0
+            return None
 
         old = state(self, oid, oldSerial, prfactory)
         committed = state(self, oid, committedSerial, prfactory, committedData)
@@ -115,7 +117,7 @@
         pickler.dump(resolved)
         return file.getvalue(1)
     except ConflictError:
-        return 0
+        return None
     except:
         # If anything else went wrong, catch it here and avoid passing an
         # arbitrary exception back to the client.  The error here will mask
@@ -124,7 +126,7 @@
         # the error so that any problems can be fixed.
         zLOG.LOG("Conflict Resolution", zLOG.ERROR,
                  "Unexpected error", error=sys.exc_info())
-        return 0
+        return None
 
 class ConflictResolvingStorage:
     "Mix-in class that provides conflict resolution handling for storages"


=== Zope/lib/python/ZODB/Connection.py 1.72.4.8 => 1.72.4.9 ===
--- Zope/lib/python/ZODB/Connection.py:1.72.4.8	Sun Nov 24 19:22:53 2002
+++ Zope/lib/python/ZODB/Connection.py	Fri Jan  3 01:37:19 2003
@@ -40,7 +40,7 @@
     global global_code_timestamp
     global_code_timestamp = time()
 
-ExtensionKlass=Base.__class__
+ExtensionKlass = Base.__class__
 
 class Connection(ExportImport.ExportImport):
     """Object managers for individual object space.


=== Zope/lib/python/ZODB/DB.py 1.43.4.2 => 1.43.4.3 ===
--- Zope/lib/python/ZODB/DB.py:1.43.4.2	Sun Nov 24 19:22:53 2002
+++ Zope/lib/python/ZODB/DB.py	Fri Jan  3 01:37:19 2003
@@ -353,9 +353,6 @@
         Note that the connection pool is managed as a stack, to increate the
         likelihood that the connection's stack will include useful objects.
         """
-        if type(version) is not StringType:
-            raise POSException.Unimplemented, 'temporary versions'
-
         self._a()
         try:
 


=== Zope/lib/python/ZODB/DemoStorage.py 1.12.4.9 => 1.12.4.10 ===


=== Zope/lib/python/ZODB/ExportImport.py 1.14 => 1.14.4.1 ===
--- Zope/lib/python/ZODB/ExportImport.py:1.14	Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/ExportImport.py	Fri Jan  3 01:37:19 2003
@@ -21,7 +21,8 @@
 from referencesf import referencesf
 from cStringIO import StringIO
 from cPickle import Pickler, Unpickler
-TupleType=type(())
+from types import StringType, TupleType
+import zLOG
 
 class ExportImport:
 
@@ -42,8 +43,12 @@
             del oids[0]
             if done(oid): continue
             done_oids[oid]=1
-            try: p, serial = load(oid, version)
-            except: pass # Ick, a broken reference
+            try:
+                p, serial = load(oid, version)
+            except:
+                zLOG.LOG("ZODB", zLOG.DEBUG,
+                         "broken reference for oid %s" % `oid`,
+                         err=sys.exc_info())
             else:
                 ref(p, oids)
                 write(oid)
@@ -96,8 +101,8 @@
         read = file.read
 
         def persistent_load(ooid,
-                            Ghost=Ghost, StringType=StringType,
-                            atoi=string.atoi, TupleType=type(()),
+                            Ghost=Ghost,
+                            atoi=string.atoi,
                             oids=oids, wrote_oid=oids.has_key,
                             new_oid=storage.new_oid):
 
@@ -151,8 +156,6 @@
 
             store(oid, None, p, version, transaction)
 
-
-StringType=type('')
 
 def TemporaryFile():
     # This is sneaky suicide


=== Zope/lib/python/ZODB/FileStorage.py 1.95.4.8 => 1.95.4.9 === (713/813 lines abridged)
--- Zope/lib/python/ZODB/FileStorage.py:1.95.4.8	Sun Nov 24 19:22:53 2002
+++ Zope/lib/python/ZODB/FileStorage.py	Fri Jan  3 01:37:19 2003
@@ -133,20 +133,15 @@
     fsync = None
 
 from ZODB import BaseStorage, ConflictResolution, POSException
-from ZODB.POSException import UndoError, POSKeyError
+from ZODB.POSException import UndoError, POSKeyError, MultipleUndoErrors
 from ZODB.TimeStamp import TimeStamp
 from ZODB.lock_file import lock_file
-from ZODB.utils import t32, p64, U64, cp
+from ZODB.utils import p64, u64, cp, z64
+from ZODB.fsIndex import fsIndex
 
-try:
-    from ZODB.fsIndex import fsIndex
-except ImportError:
-    def fsIndex():
-        return {}
+from zLOG import LOG, BLATHER, WARNING, ERROR, PANIC
 
-from zLOG import LOG, BLATHER, WARNING, ERROR, PANIC, register_subsystem
-
-z64='\0'*8
+t32 = 1L << 32
 # the struct formats for the headers
 TRANS_HDR = ">8s8scHHH"
 DATA_HDR = ">8s8s8s8sH8s"
@@ -173,7 +168,7 @@
 def panic(message, *data):
     message = message % data
     LOG('ZODB FS', PANIC, "%s ERROR: %s\n" % (packed_version, message))
-    raise CorruptedTransactionError, message
+    raise CorruptedTransactionError(message)
 
 class FileStorageError(POSException.StorageError):
     pass
@@ -191,8 +186,11 @@
                                 POSException.StorageSystemError):
     """Corrupted file storage."""
 
-class CorruptedTransactionError(CorruptedFileStorageError): pass
-class CorruptedDataError(CorruptedFileStorageError): pass
+class CorruptedTransactionError(CorruptedFileStorageError):
+    pass
+
+class CorruptedDataError(CorruptedFileStorageError):
+    pass
 
 class FileStorageQuotaError(FileStorageError,

[-=- -=- -=- 713 lines omitted -=- -=- -=-]

-    """Iterate over the transactions in a FileStorage file.
-    """
+    """Iterate over the transactions in a FileStorage file."""
+    
     def __init__(self, tid, status, user, desc, ext, pos, tend, file, tpos):
         self.tid = tid
         self.status = status
@@ -2387,15 +2381,15 @@
             self._file.seek(pos)
             h = self._file.read(DATA_HDR_LEN)
             oid, serial, sprev, stloc, vlen, splen = unpack(DATA_HDR, h)
-            prev = U64(sprev)
-            tloc = U64(stloc)
-            plen = U64(splen)
+            prev = u64(sprev)
+            tloc = u64(stloc)
+            plen = u64(splen)
             dlen = DATA_HDR_LEN + (plen or 8)
 
             if vlen:
                 dlen += (16 + vlen)
                 tmp = self._file.read(16)
-                pv = U64(tmp[8:16])
+                pv = u64(tmp[8:16])
                 version = self._file.read(vlen)
             else:
                 version = ''
@@ -2468,7 +2462,7 @@
     def _readnext(self):
         """Read the next record from the storage."""
         self.file.seek(self.pos - 8)
-        self.pos -= U64(self.file.read(8)) + 8
+        self.pos -= u64(self.file.read(8)) + 8
         self.file.seek(self.pos)
         h = self.file.read(TRANS_HDR_LEN)
         tid, tl, status, ul, dl, el = struct.unpack(TRANS_HDR, h)
@@ -2494,3 +2488,13 @@
              'description': d}
         d.update(e)
         return d
+
+
+def cleanup(filename):
+    """Remove all FileStorage related files."""
+    for ext in '', '.old', '.tmp', '.lock', '.index', '.pack':
+        try:
+            os.remove(filename + ext)
+        except OSError, e:
+            if e.errno != errno.ENOENT:
+                raise


=== Zope/lib/python/ZODB/POSException.py 1.12.4.11 => 1.12.4.12 ===
--- Zope/lib/python/ZODB/POSException.py:1.12.4.11	Sun Nov 24 19:22:53 2002
+++ Zope/lib/python/ZODB/POSException.py	Fri Jan  3 01:37:20 2003
@@ -11,23 +11,30 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-"""BoboPOS-defined exceptions
+"""ZODB-defined exceptions
 
 $Id$"""
-__version__ = '$Revision$'.split()[-2:][0]
 
-from string import join
 from types import StringType, DictType
-from ZODB import utils
+import ZODB.utils
 
-class POSError(Exception):
+def _fmt_oid(oid):
+    if oid:
+        return "%016x" % ZODB.utils.u64(oid)
+    return oid
+
+def _fmt_undo(oid, reason):
+    s = reason and (": %s" % reason) or ""
+    return "Undo error %s%s" % (_fmt_oid(oid), s)
+
+class POSError(StandardError):
     """Persistent object system error."""
 
 class POSKeyError(KeyError, POSError):
     """Key not found in database."""
 
     def __str__(self):
-        return "%016x" % utils.U64(self.args[0])
+        return _fmt_oid(self.args[0])
 
 class TransactionError(POSError):
     """An error occured due to normal transaction processing."""
@@ -78,12 +85,12 @@
     def __str__(self):
         extras = []
         if self.oid:
-            extras.append("oid %016x" % utils.U64(self.oid))
+            extras.append("oid %s" % _fmt_oid(self.oid))
         if self.class_name:
             extras.append("class %s" % self.class_name)
         if self.serials:
-            extras.append("serial was %016x, now %016x" %
-                          tuple(map(utils.U64, self.serials)))
+            extras.append("serial was %s, now %s" %
+                          tuple(map(_fmt_oid, self.serials)))
         if extras:
             return "%s (%s)" % (self.message, ", ".join(extras))
         else:
@@ -104,27 +111,8 @@
     def get_serials(self):
         return self.serials
 
-class DanglingReferenceError(TransactionError):
-    """The transaction stored an object A containing a reference to another
-    object B, but B does not exist
-
-    Instance attributes:
-
-    Aoid: oid of the object being written
-
-    Boid: referenced oid that does not have a corresponding object
-    """
-
-    def __init__(self,Aoid,Boid):
-        self.Aoid = Aoid
-        self.Boid = Boid
-
-    def __str__(self):
-        return "from %r to %r" % (self.Aoid,self.Boid)
-
-
 class ReadConflictError(ConflictError):
-    """A conflict was detected at read time.
+    """Conflict detected when object was loaded.
 
     An attempt was made to read an object that has changed in another
     transaction (eg. another thread or process).
@@ -144,6 +132,27 @@
         ConflictError.__init__(self, message="BTrees conflict error")
         self.btree = btree_args
 
+class DanglingReferenceError(TransactionError):
+    """An object has a persistent reference to a missing object.
+
+    If an object is stored and it has a reference to another object
+    that does not exist (for example, it was deleted by pack), this
+    exception may be raised.  Whether a storage supports this feature,
+    it a quality of implementation issue.
+
+    Instance attributes:
+    referer: oid of the object being written
+    missing: referenced oid that does not have a corresponding object
+    """
+
+    def __init__(self, Aoid, Boid):
+        self.referer = Aoid
+        self.missing = Boid
+
+    def __str__(self):
+        return "from %s to %s" % (_fmt_oid(self.referer),
+                                  _fmt_oid(self.missing))
+
 class VersionError(POSError):
     """An error in handling versions occurred."""
 
@@ -159,26 +168,24 @@
 
 class UndoError(POSError):
     """An attempt was made to undo a non-undoable transaction."""
-    def __init__(self, *reason):
-        if len(reason) == 1: reason=reason[0]
-        self.__reason=reason
-
-    def __repr__(self):
-        reason=self.__reason
-        if type(reason) is not DictType:
-            if reason: return str(reason)
-            return "non-undoable transaction"
-        r=[]
-        for oid, reason in reason.items():
-            if reason:
-                r.append("Couldn't undo change to %s because %s"
-                         % (`oid`, reason))
-            else:
-                r.append("Couldn't undo change to %s" % (`oid`))
 
-        return join(r,'\n')
+    def __init__(self, reason, oid=None):
+        self._reason = reason
+        self._oid = oid
+
+    def __str__(self):
+        return _fmt_undo(self._oid, self._reason)
+
+class MultipleUndoErrors(UndoError):
+    """Several undo errors occured during a single transaction."""
+    
+    def __init__(self, errs):
+        # provide a reason and oid for clients that only look at that
+        UndoError.__init__(self, *errs[0])
+        self._errs = errs
 
-    __str__=__repr__
+    def __str__(self):
+        return "\n".join([_fmt_undo(*pair) for pair in self._errs])
 
 class StorageError(POSError):
     """Base class for storage based exceptions."""
@@ -200,9 +207,6 @@
 
 class ExportError(POSError):
     """An export file doesn't have the right format."""
-
-class Unimplemented(POSError):
-    """An unimplemented feature was used."""
 
 class Unsupported(POSError):
     """An feature that is unsupported bt the storage was used."""


=== Zope/lib/python/ZODB/StorageConfig.py 1.1.2.1 => 1.1.2.2 ===
--- Zope/lib/python/ZODB/StorageConfig.py:1.1.2.1	Sun Nov 24 19:10:13 2002
+++ Zope/lib/python/ZODB/StorageConfig.py	Fri Jan  3 01:37:20 2003
@@ -65,6 +65,8 @@
     klass = getattr(m, type)
 
     args = {}
+    if section.name:
+        args["name"] = section.name
     for key in section.keys():
         if key.lower() != "type":
             args[key] = section.get(key)


=== Zope/lib/python/ZODB/StorageTypes.py 1.1.2.3 => 1.1.2.4 ===
--- Zope/lib/python/ZODB/StorageTypes.py:1.1.2.3	Fri Dec  6 11:07:06 2002
+++ Zope/lib/python/ZODB/StorageTypes.py	Fri Jan  3 01:37:20 2003
@@ -96,7 +96,7 @@
 
 
 def convertBDBStorageArgs(**kw):
-    from bsddb3Storage.BerkeleyBase import BerkeleyConfig
+    from BDBStorage.BerkeleyBase import BerkeleyConfig
     config = BerkeleyConfig()
     for name in dir(BerkeleyConfig):
         if name.startswith('_'):
@@ -119,6 +119,7 @@
     'MappingStorage': ('ZODB.MappingStorage', None),
     'TemporaryStorage': ('Products.TemporaryFolder.TemporaryStorage', None),
     'ClientStorage': ('ZEO.ClientStorage', convertClientStorageArgs),
-    'Full': ('bsddb3Storage.Full', convertBDBStorageArgs),
-    'Minimal': ('bsddb3Storage.Minimal', convertBDBStorageArgs),
+    'BDBFullStorage': ('BDBStorage.BDBFullStorage', convertBDBStorageArgs),
+    'BDBMinimalStorage': ('BDBStorage.BDBMinimalStorage',
+                          convertBDBStorageArgs),
     }


=== Zope/lib/python/ZODB/TimeStamp.c 1.15.58.5 => 1.15.58.6 ===


=== Zope/lib/python/ZODB/TmpStore.py 1.7 => 1.7.4.1 ===
--- Zope/lib/python/ZODB/TmpStore.py:1.7	Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/TmpStore.py	Fri Jan  3 01:37:20 2003
@@ -12,97 +12,117 @@
 #
 ##############################################################################
 
-import POSException
-from utils import p64, u64
+from ZODB import POSException
+from ZODB.utils import p64, u64, z64
+
+import tempfile
 
 class TmpStore:
-    _transaction=_isCommitting=None
+    """A storage to support subtransactions."""
+
+    _bver = ''
 
-    def __init__(self, base_version, file=None):
-        if file is None:
-            import tempfile
-            file=tempfile.TemporaryFile()
-
-        self._file=file
-        self._index={}
-        self._pos=self._tpos=0
-        self._bver=base_version
-        self._tindex=[]
-        self._db=None
-        self._creating=[]
+    def __init__(self, base_version):
+        self._transaction = None
+        if base_version:
+            self._bver = base_version
+        self._file = tempfile.TemporaryFile()
+        # _pos: current file position
+        # _tpos: file position at last commit point
+        self._pos = self._tpos = 0L
+        # _index: map oid to pos of last committed version
+        self._index = {}
+        # _tindex: map oid to pos for new updates
+        self._tindex = {}
+        self._db = None
+        self._creating = []
 
-    def __del__(self): self.close()
+    def __del__(self):
+        # XXX Is this necessary?
+        self._file.close()
 
     def close(self):
         self._file.close()
-        del self._file
-        del self._index
-        del self._db
 
-    def getName(self): return self._db.getName()
-    def getSize(self): return self._pos
+    def getName(self):
+        return self._db.getName()
+    
+    def getSize(self):
+        return self._pos
 
     def load(self, oid, version):
-        #if version is not self: raise KeyError, oid
-        pos=self._index.get(oid, None)
+        pos = self._index.get(oid)
         if pos is None:
             return self._storage.load(oid, self._bver)
-        file=self._file
-        file.seek(pos)
-        h=file.read(24)
-        if h[:8] != oid:
-            raise POSException.StorageSystemError, 'Bad temporary storage'
-        return file.read(u64(h[16:])), h[8:16]
+        self._file.seek(pos)
+        h = self._file.read(8)
+        oidlen = u64(h)
+        read_oid = self._file.read(oidlen)
+        if read_oid != oid:
+            raise POSException.StorageSystemError('Bad temporary storage')
+        h = self._file.read(16)
+        size = u64(h[8:])
+        serial = h[:8]
+        return self._file.read(size), serial
+
+    # XXX clarify difference between self._storage & self._db._storage
 
     def modifiedInVersion(self, oid):
-        if self._index.has_key(oid): return 1
+        if self._index.has_key(oid):
+            return self._bver
         return self._db._storage.modifiedInVersion(oid)
 
-    def new_oid(self): return self._db._storage.new_oid()
+    def new_oid(self):
+        return self._db._storage.new_oid()
 
     def registerDB(self, db, limit):
-        self._db=db
-        self._storage=db._storage
+        self._db = db
+        self._storage = db._storage
 
     def store(self, oid, serial, data, version, transaction):
         if transaction is not self._transaction:
             raise POSException.StorageTransactionError(self, transaction)
-        file=self._file
-        pos=self._pos
-        file.seek(pos)
-        l=len(data)
+        self._file.seek(self._pos)
+        l = len(data)
         if serial is None:
-            serial = '\0\0\0\0\0\0\0\0'
-        file.write(oid+serial+p64(l))
-        file.write(data)
-        self._tindex.append((oid,pos))
-        self._pos=pos+l+24
+            serial = z64
+        header = p64(len(oid)) + oid + serial + p64(l)
+        self._file.write(header)
+        self._file.write(data)
+        self._tindex[oid] = self._pos
+        self._pos += l + len(header)
         return serial
 
     def tpc_abort(self, transaction):
-        if transaction is not self._transaction: return
-        del self._tindex[:]
-        self._transaction=None
-        self._pos=self._tpos
+        if transaction is not self._transaction:
+            return
+        self._tindex.clear()
+        self._transaction = None
+        self._pos = self._tpos
 
     def tpc_begin(self, transaction):
-        if self._transaction is transaction: return
-        self._transaction=transaction
-        del self._tindex[:]   # Just to be sure!
-        self._pos=self._tpos
+        if self._transaction is transaction:
+            return
+        self._transaction = transaction
+        self._tindex.clear() # Just to be sure!
+        self._pos = self._tpos
 
-    def tpc_vote(self, transaction): pass
+    def tpc_vote(self, transaction):
+        pass
 
     def tpc_finish(self, transaction, f=None):
-        if transaction is not self._transaction: return
-        if f is not None: f()
-        index=self._index
-        tindex=self._tindex
-        for oid, pos in tindex: index[oid]=pos
-        del tindex[:]
-        self._tpos=self._pos
+        if transaction is not self._transaction:
+            return
+        if f is not None:
+            f()
+        self._index.update(self._tindex)
+        self._tindex.clear()
+        self._tpos = self._pos
 
-    def undoLog(self, first, last, filter=None): return ()
+    def undoLog(self, first, last, filter=None):
+        return ()
 
     def versionEmpty(self, version):
-        if version is self: return len(self._index)
+        # XXX what is this supposed to do?
+        if version == self._bver:
+            return len(self._index)


=== Zope/lib/python/ZODB/Transaction.py 1.37.4.7 => 1.37.4.8 ===
--- Zope/lib/python/ZODB/Transaction.py:1.37.4.7	Sun Nov 24 19:22:53 2002
+++ Zope/lib/python/ZODB/Transaction.py	Fri Jan  3 01:37:20 2003
@@ -13,15 +13,14 @@
 ##############################################################################
 """Transaction management
 
-$Id$"""
-__version__='$Revision$'[11:-2]
+$Id$
+"""
 
 import time, sys, struct, POSException
 from struct import pack
 from string import split, strip, join
 from zLOG import LOG, ERROR, PANIC, INFO, BLATHER, WARNING
 from POSException import ConflictError
-from ZODB import utils
 
 # Flag indicating whether certain errors have occurred.
 hosed=0
@@ -48,12 +47,11 @@
     return cmp(k1, k2)
 
 class Transaction:
-    'Simple transaction objects for single-threaded applications.'
-    user=''
-    description=''
-    _connections=None
-    _extension=None
-    _sub=None # This is a subtrasaction flag
+    user = ''
+    description = ''
+    _connections = None
+    _extension = None
+    _sub = None # This is a subtrasaction flag
 
     # The _non_st_objects variable is either None or a list
     # of jars that do not support subtransactions. This is used to
@@ -93,15 +91,15 @@
             return "Transaction thread=%s user=%s" % (self._id, `self.user`)
 
     def __del__(self):
-        if self._objects: self.abort(freeme=0)
+        if self._objects:
+            self.abort(freeme=0)
 
     def abort(self, subtransaction=0, freeme=1):
-        '''Abort the transaction.
+        """Abort the transaction.
 
-        This is called from the application.  This means that we haven\'t
+        This is called from the application.  This means that we haven't
         entered two-phase commit yet, so no tpc_ messages are sent.
-        '''
-
+        """
         if subtransaction and (self._non_st_objects is not None):
             raise POSException.TransactionError, (
                 """Attempted to abort a sub-transaction, but a participating
@@ -139,8 +137,8 @@
                     if t is None:
                         t, v, tb = sys.exc_info()
                     else:
-                        self.log("Failed to abort object %016x" %
-                                 utils.U64(o._p_oid), error=sys.exc_info())
+                        self.log("Failed to abort object %s" %
+                                 repr(o._p_oid), error=sys.exc_info())
 
             # tpc_begin() was never called, so tpc_abort() should not be
             # called.
@@ -164,10 +162,10 @@
                 self._init()
 
     def begin(self, info=None, subtransaction=None):
-        '''Begin a new transaction.
+        """Begin a new transaction.
 
         This aborts any transaction in progres.
-        '''
+        """
         if self._objects:
             self.abort(subtransaction, 0)
         if info:
@@ -176,8 +174,7 @@
             self.description=strip(join(info[1:],'\t'))
 
     def commit(self, subtransaction=None):
-        'Finalize the transaction'
-
+        """Finalize the transaction."""
         objects = self._objects
 
         subjars = []
@@ -392,7 +389,7 @@
                     j.abort(o, self)
             except:
                 # nothing to do but log the error
-                self.log("Failed to abort object %016x" % utils.U64(o._p_oid),
+                self.log("Failed to abort object %s" % repr(o._p_oid),
                          error=sys.exc_info())
 
         # Abort the two-phase commit.  It's only necessary to abort the


=== Zope/lib/python/ZODB/UndoLogCompatible.py 1.6 => 1.6.4.1 ===
--- Zope/lib/python/ZODB/UndoLogCompatible.py:1.6	Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/UndoLogCompatible.py	Fri Jan  3 01:37:20 2003
@@ -11,7 +11,7 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-"""Provide backward compatability with storages that have undoLog, but not undoInfo."""
+"""Provide backward compatibility with storages that only have undoLog()."""
 
 
 class UndoLogCompatible:


=== Zope/lib/python/ZODB/cPersistence.c 1.62.8.5 => 1.62.8.6 ===


=== Zope/lib/python/ZODB/cPickleCache.c 1.68.8.2 => 1.68.8.3 ===
--- Zope/lib/python/ZODB/cPickleCache.c:1.68.8.2	Sun Nov 24 19:22:53 2002
+++ Zope/lib/python/ZODB/cPickleCache.c	Fri Jan  3 01:37:20 2003
@@ -329,7 +329,7 @@
 	if (PyObject_DelAttr(v, py__p_changed) < 0)
 	    PyErr_Clear();
     }
-    Py_DECREF(v);
+    Py_XDECREF(v);
 }
 
 static PyObject *


=== Zope/lib/python/ZODB/coptimizations.c 1.17.58.3 => 1.17.58.4 ===
--- Zope/lib/python/ZODB/coptimizations.c:1.17.58.3	Tue Oct  8 17:45:55 2002
+++ Zope/lib/python/ZODB/coptimizations.c	Fri Jan  3 01:37:20 2003
@@ -69,8 +69,8 @@
 /* Returns the klass of a persistent object.
    Returns NULL for other objects.
 */
-static PyObject *
-get_class(PyObject *object)
+int
+get_class(PyObject *object, PyObject **out_class)
 {
     PyObject *class = NULL;
 
@@ -79,19 +79,23 @@
 	    class = PyObject_GetAttr(object, py___class__);
 	    if (!class) {
 		PyErr_Clear();
-		return NULL;
+		return 0;
 	    }
-	    if (!PyExtensionClass_Check(class) ||
-		!(((PyExtensionClass*)class)->class_flags 
+	    /* The __class__ must be an extension class. */
+	    if (!(((PyExtensionClass*)class)->class_flags 
 		  & PERSISTENT_TYPE_FLAG)) {
 		Py_DECREF(class);
-		return NULL;
+		return 0;
 	    }
 	}
 	else
-	    return NULL;
+	    /* Most objects will exit via this path.  They are neither
+	       extension classes nor instances of them.
+	    */
+	    return 0;
     }
-    return class;
+    *out_class = class;
+    return 1;
 }
 
 /* Return a two-tuple of the class's module and name.
@@ -106,7 +110,7 @@
 	goto err;
     if (!PyObject_IsTrue(module)) {
 	Py_DECREF(module);
-	/* XXX Handle degenerate 1.x ZClass case. */
+	/* If the class has no __module__, it must be a degnerate ZClass. */
 	return oid;
     }
 
@@ -152,24 +156,39 @@
     return NULL;
 }
 
+/* persistent_id_call()
+
+   Returns a reference to a persistent object, appending it to the the
+   persistent_id's list of objects.  If a non-persistent object is
+   found, return None.
+
+   The returned reference can be either class info, oid pair or a
+   plain old oid.  If it is a pair, the class info is the module and
+   the name of the class.  The class info can be used to create a
+   ghost without loading the class.
+
+   For unusual objects, e.g. ZClasses, return just the oid.  An object
+   is unusual if it isn't an ExtensionClass, because that means it
+   doesn't inherit from Persistence, or if it has __getinitargs__().
+*/
+
 static PyObject *
 persistent_id_call(persistent_id *self, PyObject *args, PyObject *kwargs)
 {
-    PyObject *object, *oid, *klass=NULL;
+    PyObject *object, *oid=NULL, *klass=NULL;
     PyObject *t1, *t2;
     int setjar = 0;
 
     if (!PyArg_ParseTuple(args, "O", &object))
 	return NULL;
 
-    klass = get_class(object);
-    if (!klass)
+    /* If it is not an extension class, get the object's class. */
+    if (!get_class(object, &klass))
 	goto return_none;
 
     oid = PyObject_GetAttr(object, py__p_oid);
     if (!oid) {
 	PyErr_Clear();
-	Py_DECREF(klass);
 	goto return_none;
     }
 
@@ -205,7 +224,7 @@
     t2 = get_class_tuple(klass, oid);
     if (!t2)
 	goto err;
-    if (t2 == oid) /* pass through ZClass special case */
+    if (t2 == oid) /* Couldn't find class info, just used oid. */
 	goto return_oid;
     t1 = PyTuple_New(2);
     if (!t1) {
@@ -229,6 +248,8 @@
     return oid;
 
  return_none:
+    Py_XDECREF(oid);
+    Py_XDECREF(klass);
     Py_INCREF(Py_None);
     return Py_None;
 }


=== Zope/lib/python/ZODB/fsIndex.py 1.3 => 1.3.4.1 ===
--- Zope/lib/python/ZODB/fsIndex.py:1.3	Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/fsIndex.py	Fri Jan  3 01:37:20 2003
@@ -93,6 +93,15 @@
         v=self.get(key, self)
         return v is not self
 
+    def __contains__(self, key):
+        tree = self._data.get(key[:6])
+        if tree is None:
+            return 0
+        v = tree.get(key[6:], None)
+        if v is None:
+            return 0
+        return 1
+
     def clear(self):
         self._data.clear()
 


=== Zope/lib/python/ZODB/fsdump.py 1.3.68.2 => 1.3.68.3 ===
--- Zope/lib/python/ZODB/fsdump.py:1.3.68.2	Sun Nov 24 19:10:13 2002
+++ Zope/lib/python/ZODB/fsdump.py	Fri Jan  3 01:37:20 2003
@@ -1,6 +1,6 @@
 from ZODB.FileStorage import FileIterator
 from ZODB.TimeStamp import TimeStamp
-from ZODB.utils import U64
+from ZODB.utils import u64
 from ZODB.tests.StorageTestBase import zodb_unpickle
 
 from cPickle import Unpickler
@@ -42,10 +42,10 @@
     for trans in iter:
         if with_offset:
             print >> file, "Trans #%05d tid=%016x time=%s offset=%d" % \
-                  (i, U64(trans.tid), str(TimeStamp(trans.tid)), trans._pos)
+                  (i, u64(trans.tid), str(TimeStamp(trans.tid)), trans._pos)
         else:
             print >> file, "Trans #%05d tid=%016x time=%s" % \
-                  (i, U64(trans.tid), str(TimeStamp(trans.tid)))
+                  (i, u64(trans.tid), str(TimeStamp(trans.tid)))
         print >> file, "\tstatus=%s user=%s description=%s" % \
               (`trans.status`, trans.user, trans.description)
         j = 0
@@ -67,11 +67,11 @@
             if rec.data_txn:
                 # XXX It would be nice to print the transaction number
                 # (i) but it would be too expensive to keep track of.
-                bp = "bp=%016x" % U64(rec.data_txn)
+                bp = "bp=%016x" % u64(rec.data_txn)
             else:
                 bp = ""
             print >> file, "  data #%05d oid=%016x %sclass=%s %s" % \
-                  (j, U64(rec.oid), version, fullclass, bp)
+                  (j, u64(rec.oid), version, fullclass, bp)
             j += 1
         print >> file
         i += 1
@@ -83,7 +83,7 @@
 
 def fmt(p64):
     # Return a nicely formatted string for a packaged 64-bit value
-    return "%016x" % U64(p64)
+    return "%016x" % u64(p64)
 
 class Dumper:
     """A very verbose dumper for debuggin FileStorage problems."""
@@ -105,12 +105,12 @@
         if not h:
             return False
         tid, stlen, status, ul, dl, el = struct.unpack(TRANS_HDR, h)
-        end = pos + U64(stlen)
+        end = pos + u64(stlen)
         print >> self.dest, "=" * 60
         print >> self.dest, "offset: %d" % pos
         print >> self.dest, "end pos: %d" % end
         print >> self.dest, "transaction id: %s" % fmt(tid)
-        print >> self.dest, "trec len: %d" % U64(stlen)
+        print >> self.dest, "trec len: %d" % u64(stlen)
         print >> self.dest, "status: %r" % status
         user = descr = extra = ""
         if ul:
@@ -125,7 +125,7 @@
         while self.file.tell() < end:
             self.dump_data(pos)
         stlen2 = self.file.read(8)
-        print >> self.dest, "redundant trec len: %d" % U64(stlen2)
+        print >> self.dest, "redundant trec len: %d" % u64(stlen2)
         return True
 
     def dump_data(self, tloc):
@@ -133,23 +133,23 @@
         h = self.file.read(DATA_HDR_LEN)
         assert len(h) == DATA_HDR_LEN
         oid, revid, sprev, stloc, vlen, sdlen = struct.unpack(DATA_HDR, h)
-        dlen = U64(sdlen)
+        dlen = u64(sdlen)
         print >> self.dest, "-" * 60
         print >> self.dest, "offset: %d" % pos
         print >> self.dest, "oid: %s" % fmt(oid)
         print >> self.dest, "revid: %s" % fmt(revid)
-        print >> self.dest, "previous record offset: %d" % U64(sprev)
-        print >> self.dest, "transaction offset: %d" % U64(stloc)
+        print >> self.dest, "previous record offset: %d" % u64(sprev)
+        print >> self.dest, "transaction offset: %d" % u64(stloc)
         if vlen:
             pnv = self.file.read(8)
             sprevdata = self.file.read(8)
             version = self.file.read(vlen)
             print >> self.dest, "version: %r" % version
-            print >> self.dest, "non-version data offset: %d" % U64(pnv)
+            print >> self.dest, "non-version data offset: %d" % u64(pnv)
             print >> self.dest, \
-                  "previous version data offset: %d" % U64(sprevdata)
+                  "previous version data offset: %d" % u64(sprevdata)
         print >> self.dest, "len(data): %d" % dlen
         self.file.read(dlen)
         if not dlen:
             sbp = self.file.read(8)
-            print >> self.dest, "backpointer: %d" % U64(sbp)
+            print >> self.dest, "backpointer: %d" % u64(sbp)


=== Zope/lib/python/ZODB/lock_file.py 1.6 => 1.6.4.1 ===
--- Zope/lib/python/ZODB/lock_file.py:1.6	Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/lock_file.py	Fri Jan  3 01:37:20 2003
@@ -12,25 +12,24 @@
 #
 ##############################################################################
 
-import POSException
+from ZODB.POSException import StorageSystemError
 
-# Try to create a function that creates Unix file locks.  On windows
-# this will fail.
+# Try to create a function that creates Unix file locks.
 try:
     import fcntl
 
     lock_file_FLAG = fcntl.LOCK_EX | fcntl.LOCK_NB
 
-    def lock_file(file, error=POSException.StorageSystemError):
+    def lock_file(file):
         try:
-            un=file.fileno()
+            un = file.fileno()
         except:
             return # don't care if not a real file
 
         try:
-            fcntl.flock(un,lock_file_FLAG)
+            fcntl.flock(un, lock_file_FLAG)
         except:
-            raise error, (
+            raise StorageSystemError, (
                 "Could not lock the database file.  There must be\n"
                 "another process that has opened the file.\n"
                 "<p>")
@@ -39,19 +38,21 @@
     # Try windows-specific code:
     try:
         from winlock import LockFile
-        def lock_file(file, error=POSException.StorageSystemError):
+        def lock_file(file):
             try:
                 un=file.fileno()
             except:
                 return # don't care if not a real file
 
             try:
-                LockFile(un,0,0,1,0) # just lock the first byte, who cares
+                LockFile(un, 0, 0, 1, 0) # just lock the first byte, who cares
             except:
-                raise error, (
+                raise StorageSystemError, (
                     "Could not lock the database file.  There must be\n"
                     "another process that has opened the file.\n"
                     "<p>")
     except:
-        def lock_file(file, error=None):
-            pass
+        import zLOG
+        def lock_file(file):
+            zLOG.LOG("FS", zLOG.INFO,
+                     "No file-locking support on this platform")


=== Zope/lib/python/ZODB/utils.py 1.12.4.1 => 1.12.4.2 ===
--- Zope/lib/python/ZODB/utils.py:1.12.4.1	Sun Nov 24 19:10:13 2002
+++ Zope/lib/python/ZODB/utils.py	Fri Jan  3 01:37:20 2003
@@ -17,7 +17,9 @@
 
 from struct import pack, unpack
 
-if sys.version >= (2, 2):
+z64 = '\0'*8
+
+if sys.version_info >= (2, 2):
 
     # Note that the distinction between ints and longs is blurred in
     # Python 2.2.  So make u64() and U64() the same.