[Zope-Checkins] CVS: ZODB3/BDBStorage - BDBMinimalStorage.py:1.12.6.2
Barry Warsaw
barry@wooz.org
Tue, 21 Jan 2003 17:29:36 -0500
Update of /cvs-repository/ZODB3/BDBStorage
In directory cvs.zope.org:/tmp/cvs-serv27095
Modified Files:
Tag: ZODB3-3_1-branch
BDBMinimalStorage.py
Log Message:
Backporting of various changes from the 3.2 branch. Specifically:
- generalize the table for storage metadata, i.e. packtime -> info
- get ZERO from the package
- close the pack race condition
=== ZODB3/BDBStorage/BDBMinimalStorage.py 1.12.6.1 => 1.12.6.2 ===
--- ZODB3/BDBStorage/BDBMinimalStorage.py:1.12.6.1 Tue Jan 7 14:38:52 2003
+++ ZODB3/BDBStorage/BDBMinimalStorage.py Tue Jan 21 17:29:34 2003
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# Copyright (c) 2001 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -13,22 +13,21 @@
##############################################################################
"""Berkeley storage without undo or versioning.
-"""
-__version__ = '$Revision$'[-2:][0]
+$Revision$
+"""
from ZODB import POSException
from ZODB.utils import p64, U64
from ZODB.referencesf import referencesf
from ZODB.ConflictResolution import ConflictResolvingStorage, ResolvedSerial
-from BDBStorage import db
+from BDBStorage import db, ZERO
from BerkeleyBase import BerkeleyBase, PackStop, _WorkThread
ABORT = 'A'
COMMIT = 'C'
PRESENT = 'X'
-ZERO = '\0'*8
try:
True, False
@@ -78,6 +77,13 @@
# no pending entry. It is a database invariant that if the
# pending table is empty, the oids table must also be empty.
#
+ # info -- {key -> value}
+ # This table contains storage metadata information. The keys and
+ # values are simple strings of variable length. Here are the
+ # valid keys:
+ #
+ # version - the version of the database (reserved for ZODB4)
+ #
# packmark -- [oid]
# Every object reachable from the root during a classic pack
# operation will have its oid present in this table.
@@ -89,6 +95,8 @@
# references exist, such that the objects can be completely packed
# away.
#
+ self._packing = False
+ self._info = self._setupDB('info')
self._serials = self._setupDB('serials', db.DB_DUP)
self._pickles = self._setupDB('pickles')
self._refcounts = self._setupDB('refcounts')
@@ -170,6 +178,8 @@
if soid <> oid:
break
if stid <> tid:
+ # This is the previous revision of the object, so
+ # decref its referents and clean up its pickles.
cs.delete()
data = self._pickles.get(oid+stid, txn=txn)
assert data is not None
@@ -187,8 +197,16 @@
if co: co.close()
if cs: cs.close()
# We're done with this table
- self._oids.truncate(txn)
self._pending.truncate(txn)
+ # If we're in the middle of a pack, we need to add to the packmark
+ # table any objects that were modified in this transaction.
+ # Otherwise, there's a race condition where mark might have happened,
+ # then the object is added, then sweep runs, deleting the object
+ # created in the interrim.
+ if self._packing:
+ for oid in self._oids.keys():
+ self._packmark.put(oid, PRESENT, txn=txn)
+ self._oids.truncate(txn)
# Now, to finish up, we need apply the refcount deltas to the
# refcounts table, and do recursive collection of all refcount == 0
# objects.
@@ -350,6 +368,7 @@
# A simple wrapper around the bulk of packing, but which acquires a
# lock that prevents multiple packs from running at the same time.
self._packlock.acquire()
+ self._packing = True
try:
# We don't wrap this in _withtxn() because we're going to do the
# operation across several Berkeley transactions, which allows
@@ -360,6 +379,7 @@
# collect object revisions
self._dopack()
finally:
+ self._packing = False
self._packlock.release()
self.log('classic pack finished')
@@ -394,7 +414,6 @@
# we'll save the mark data in the packmark table. The oidqueue is a
# BerkeleyDB Queue that holds the list of object ids to look at next,
# and by using this we don't need to keep an in-memory dictionary.
- assert len(self._packmark) == 0
assert len(self._oidqueue) == 0
# Quick exit for empty storages
if not self._serials: