Commit 312632fa authored by Tim Peters's avatar Tim Peters

Merge/port assorted ZODB changes checked into Zope3's ZODB copy.

Please don't do that:  ZODB changes need to be done in the ZODB
project.  Checkins to Zope3 have no effect on ZODB in reality.

This includes:

r26945 | jim | 2004-08-06 18:30:44 -0400 (Fri, 06 Aug 2004) | 6 lines
   M /Zope3/trunk/src/persistent/tests/test_persistent.py

Updated to work with the versions of doctest from Python with versions
  greater than or equal to 2.3.0 and less than 2.4.0.a2 and with
  versions greater than 2.4.0a2.

r26482 | srichter | 2004-07-13 13:07:03 -0400 (Tue, 13 Jul 2004) | 2 lines
   M /Zope3/trunk/src/transaction/__init__.py
   M /Zope3/trunk/src/transaction/_transaction.py
   M /Zope3/trunk/src/transaction/tests/test_transaction.py

Converted XXX to TODO.

r25953 | sidnei | 2004-06-23 13:14:20 -0400 (Wed, 23 Jun 2004) | 1 line
   M /Zope3/trunk/src/ZODB/interfaces.py
   M /Zope3/trunk/src/transaction/_transaction.py

Add missing sortKey method to ZopeDBTransactionManager and DataManagerAdapter,
and also add it to the interface.

r25273 | philikon | 2004-06-06 04:43:57 -0400 (Sun, 06 Jun 2004) | 4 lines
Changed paths:
   M /Zope3/trunk/src/BTrees
   M /Zope3/trunk/src/ZODB
   M /Zope3/trunk/src/persistent

Ignore .so files.

This fix should probably be merged to the original ZODB tree.
parent a523f837
...@@ -25,23 +25,30 @@ class P(Persistent): ...@@ -25,23 +25,30 @@ class P(Persistent):
def inc(self): def inc(self):
self.x += 1 self.x += 1
def DocFileSuite(path, globs=None): try:
# It's not entirely obvious how to connection this single string DocFileSuite = doctest.DocFileSuite # >= Python 2.4.0a2
# with unittest. For now, re-use the _utest() function that comes except AttributeError:
# standard with doctest in Python 2.3. One problem is that the # <= Python 2.4.0a1
# error indicator doesn't point to the line of the doctest file def DocFileSuite(path, globs=None):
# that failed. # It's not entirely obvious how to connection this single string
source = open(path).read() # with unittest. For now, re-use the _utest() function that comes
if globs is None: # standard with doctest in Python 2.3. One problem is that the
globs = sys._getframe(1).f_globals # error indicator doesn't point to the line of the doctest file
t = doctest.Tester(globs=globs) # that failed.
def runit():
doctest._utest(t, path, source, path, 0) path = os.path.join(persistent.tests.__path__[0], path)
f = unittest.FunctionTestCase(runit, description="doctest from %s" % path)
suite = unittest.TestSuite() source = open(path).read()
suite.addTest(f) if globs is None:
return suite globs = sys._getframe(1).f_globals
t = doctest.Tester(globs=globs)
def runit():
doctest._utest(t, path, source, path, 0)
f = unittest.FunctionTestCase(runit,
description="doctest from %s" % path)
suite = unittest.TestSuite()
suite.addTest(f)
return suite
def test_suite(): def test_suite():
path = os.path.join(persistent.tests.__path__[0], "persistent.txt") return DocFileSuite("persistent.txt", globs={"P": P})
return DocFileSuite(path, {"P": P})
...@@ -11,6 +11,10 @@ ...@@ -11,6 +11,10 @@
# FOR A PARTICULAR PURPOSE. # FOR A PARTICULAR PURPOSE.
# #
############################################################################ ############################################################################
"""Exported transaction functions.
$Id$
"""
from transaction._transaction import Transaction from transaction._transaction import Transaction
from transaction._manager import TransactionManager, ThreadTransactionManager from transaction._manager import TransactionManager, ThreadTransactionManager
...@@ -29,5 +33,5 @@ def commit(sub=False): ...@@ -29,5 +33,5 @@ def commit(sub=False):
def abort(sub=False): def abort(sub=False):
manager.get().abort(sub) manager.get().abort(sub)
# XXX Issue deprecation warning if this variant is used? # TODO: Issue deprecation warning if this variant is used?
get_transaction = get get_transaction = get
...@@ -25,7 +25,7 @@ Transaction has two methods for a resource manager to call to ...@@ -25,7 +25,7 @@ Transaction has two methods for a resource manager to call to
participate in a transaction -- register() and join(). join() takes a participate in a transaction -- register() and join(). join() takes a
resource manager and adds it to the list of resources. register() is resource manager and adds it to the list of resources. register() is
for backwards compatibility. It takes a persistent object and for backwards compatibility. It takes a persistent object and
registers its _p_jar attribute. XXX explain adapter registers its _p_jar attribute. TODO: explain adapter
Subtransactions Subtransactions
--------------- ---------------
...@@ -54,7 +54,7 @@ methods and support a second argument to tpc_begin(). ...@@ -54,7 +54,7 @@ methods and support a second argument to tpc_begin().
The second argument to tpc_begin() indicates that a subtransaction The second argument to tpc_begin() indicates that a subtransaction
commit is beginning (if it is true). In a subtransaction, there is no commit is beginning (if it is true). In a subtransaction, there is no
tpc_vote() call. (XXX I don't have any idea why.) The tpc_finish() tpc_vote() call. (XXX: I don't have any idea why.) The tpc_finish()
or tpc_abort() call applies just to that subtransaction. or tpc_abort() call applies just to that subtransaction.
Once a resource manager is involved in a subtransaction, all Once a resource manager is involved in a subtransaction, all
...@@ -187,11 +187,11 @@ class Transaction(object): ...@@ -187,11 +187,11 @@ class Transaction(object):
def join(self, resource): def join(self, resource):
if self.status != Status.ACTIVE: if self.status != Status.ACTIVE:
# XXX Should it be possible to join a committing transaction? # TODO: Should it be possible to join a committing transaction?
# I think some users want it. # I think some users want it.
raise ValueError("expected txn status %r, but it's %r" % ( raise ValueError("expected txn status %r, but it's %r" % (
Status.ACTIVE, self.status)) Status.ACTIVE, self.status))
# XXX the prepare check is a bit of a hack, perhaps it would # TODO: the prepare check is a bit of a hack, perhaps it would
# be better to use interfaces. If this is a ZODB4-style # be better to use interfaces. If this is a ZODB4-style
# resource manager, it needs to be adapted, too. # resource manager, it needs to be adapted, too.
if myhasattr(resource, "prepare"): if myhasattr(resource, "prepare"):
...@@ -219,7 +219,7 @@ class Transaction(object): ...@@ -219,7 +219,7 @@ class Transaction(object):
self._adapters[manager] = adapter self._adapters[manager] = adapter
self.join(adapter) self.join(adapter)
else: else:
# XXX comment out this expensive assert later # TODO: comment out this expensive assert later
# Use id() to guard against proxies. # Use id() to guard against proxies.
assert id(obj) not in map(id, adapter.objects) assert id(obj) not in map(id, adapter.objects)
adapter.objects.append(obj) adapter.objects.append(obj)
...@@ -230,7 +230,7 @@ class Transaction(object): ...@@ -230,7 +230,7 @@ class Transaction(object):
self._resources.append(adapter) self._resources.append(adapter)
def begin(self): def begin(self):
# XXX I'm not sure how this should be implemented. Not doing # TODO: I'm not sure how this should be implemented. Not doing
# anything now, but my best guess is: If nothing has happened # anything now, but my best guess is: If nothing has happened
# yet, it's fine. Otherwise, abort this transaction and let # yet, it's fine. Otherwise, abort this transaction and let
# the txn manager create a new one. # the txn manager create a new one.
...@@ -293,8 +293,8 @@ class Transaction(object): ...@@ -293,8 +293,8 @@ class Transaction(object):
for rm in L: for rm in L:
rm.tpc_finish(self) rm.tpc_finish(self)
except: except:
# XXX do we need to make this warning stronger? # TODO: do we need to make this warning stronger?
# XXX It would be nice if the system could be configured # TODO: It would be nice if the system could be configured
# to stop committing transactions at this point. # to stop committing transactions at this point.
self.log.critical("A storage error occured during the second " self.log.critical("A storage error occured during the second "
"phase of the two-phase commit. Resources " "phase of the two-phase commit. Resources "
...@@ -365,8 +365,8 @@ class Transaction(object): ...@@ -365,8 +365,8 @@ class Transaction(object):
# Merge all of _sub, _nonsub, and _resources. # Merge all of _sub, _nonsub, and _resources.
d = dict(self._sub) d = dict(self._sub)
d.update(self._nonsub) d.update(self._nonsub)
# XXX I think _sub and _nonsub are disjoint, and that # TODO: I think _sub and _nonsub are disjoint, and that
# XXX _resources is empty. If so, we can simplify this code. # _resources is empty. If so, we can simplify this code.
assert len(d) == len(self._sub) + len(self._nonsub) assert len(d) == len(self._sub) + len(self._nonsub)
assert not self._resources assert not self._resources
for rm in self._resources: for rm in self._resources:
...@@ -430,7 +430,7 @@ class Transaction(object): ...@@ -430,7 +430,7 @@ class Transaction(object):
def setExtendedInfo(self, name, value): def setExtendedInfo(self, name, value):
self._extension[name] = value self._extension[name] = value
# XXX We need a better name for the adapters. # TODO: We need a better name for the adapters.
class MultiObjectResourceAdapter(object): class MultiObjectResourceAdapter(object):
"""Adapt the old-style register() call to the new-style join(). """Adapt the old-style register() call to the new-style join().
...@@ -538,7 +538,7 @@ class DataManagerAdapter(object): ...@@ -538,7 +538,7 @@ class DataManagerAdapter(object):
self._datamanager = datamanager self._datamanager = datamanager
self._rollback = None self._rollback = None
# XXX I'm not sure why commit() doesn't do anything # TODO: I'm not sure why commit() doesn't do anything
def commit(self, transaction): def commit(self, transaction):
pass pass
...@@ -580,3 +580,7 @@ class DataManagerAdapter(object): ...@@ -580,3 +580,7 @@ class DataManagerAdapter(object):
def tpc_vote(self, transaction): def tpc_vote(self, transaction):
if not self._sub: if not self._sub:
self._datamanager.prepare(transaction) self._datamanager.prepare(transaction)
def sortKey(self):
return self._datamanager.sortKey()
...@@ -235,6 +235,16 @@ class IDataManagerOriginal(zope.interface.Interface): ...@@ -235,6 +235,16 @@ class IDataManagerOriginal(zope.interface.Interface):
""" """
def sortKey():
"""
Return a key to use for ordering registered DataManagers
ZODB uses a global sort order to prevent deadlock when it commits
transactions involving multiple resource managers. The resource
manager must define a sortKey() method that provides a global ordering
for resource managers.
"""
class IDataManager(zope.interface.Interface): class IDataManager(zope.interface.Interface):
"""Data management interface for storing objects transactionally. """Data management interface for storing objects transactionally.
...@@ -314,6 +324,16 @@ class IDataManager(zope.interface.Interface): ...@@ -314,6 +324,16 @@ class IDataManager(zope.interface.Interface):
""" """
def sortKey():
"""
Return a key to use for ordering registered DataManagers
ZODB uses a global sort order to prevent deadlock when it commits
transactions involving multiple resource managers. The resource
manager must define a sortKey() method that provides a global ordering
for resource managers.
"""
class ITransaction(zope.interface.Interface): class ITransaction(zope.interface.Interface):
"""Object representing a running transaction. """Object representing a running transaction.
......
...@@ -203,7 +203,7 @@ class TransactionTests(unittest.TestCase): ...@@ -203,7 +203,7 @@ class TransactionTests(unittest.TestCase):
assert self.nosub1._p_jar.ctpc_finish == 0 assert self.nosub1._p_jar.ctpc_finish == 0
assert self.nosub1._p_jar.cabort == 1 assert self.nosub1._p_jar.cabort == 1
# XXX # XXX:
def BUGtestNSJSubTransactionCommitAbort(self): def BUGtestNSJSubTransactionCommitAbort(self):
""" """
this reveals a bug in transaction.py this reveals a bug in transaction.py
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment