Commit 4d5f3a94 authored by Tim Peters's avatar Tim Peters

Merge/port checkins to ZODB code made from Zope3.

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
   M /Zope3/trunk/src/zope/event/tests.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
   M /Zope3/trunk/src/zope/app/rdb/__init__.py
   M /Zope3/trunk/src/zope/app/rdb/tests/test_zopedbtransactionmanager.py

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

r25330 | alga | 2004-06-10 10:07:45 -0400 (Thu, 10 Jun 2004) | 4 lines
   M /Zope3/trunk/src/ZODB/Connection.py
   M /Zope3/trunk/src/ZODB/interfaces.py
   M /Zope3/trunk/src/ZODB/tests/testConnection.py

Added an IConnection interface declaration on ZODB Connection.

Jim says Tim Peters will be mad at him, but that's the right way to go.

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 216d7ff9
...@@ -28,7 +28,7 @@ ZoneAlarm. Many particularly slow tests are skipped unless you pass ...@@ -28,7 +28,7 @@ ZoneAlarm. Many particularly slow tests are skipped unless you pass
Compatibility Compatibility
------------- -------------
ZODB 3.3 is requires Python 2.3.4 or later. ZODB 3.3 requires Python 2.3.4 or later.
The Zope 2.8 release should be compatible with this version of ZODB. The Zope 2.8 release should be compatible with this version of ZODB.
Note that Zope 2.7 and higher includes ZEO, so this package should Note that Zope 2.7 and higher includes ZEO, so this package should
......
...@@ -35,6 +35,8 @@ from ZODB.POSException \ ...@@ -35,6 +35,8 @@ from ZODB.POSException \
from ZODB.TmpStore import TmpStore from ZODB.TmpStore import TmpStore
from ZODB.utils import oid_repr, z64, positive_id from ZODB.utils import oid_repr, z64, positive_id
from ZODB.serialize import ObjectWriter, ConnectionObjectReader, myhasattr from ZODB.serialize import ObjectWriter, ConnectionObjectReader, myhasattr
from ZODB.interfaces import IConnection
from ZODB.interfaces import implements
global_reset_counter = 0 global_reset_counter = 0
...@@ -147,6 +149,7 @@ class Connection(ExportImport, object): ...@@ -147,6 +149,7 @@ class Connection(ExportImport, object):
getTransferCounts getTransferCounts
""" """
implements(IConnection)
_tmp = None _tmp = None
_code_timestamp = 0 _code_timestamp = 0
......
...@@ -17,7 +17,8 @@ $Id$ ...@@ -17,7 +17,8 @@ $Id$
""" """
try: try:
from zope.interface import Interface, Attribute from zope.interface import Interface, Attribute, implements
from zope.interface.verify import verifyObject
except ImportError: except ImportError:
class Interface: class Interface:
pass pass
...@@ -27,6 +28,11 @@ except ImportError: ...@@ -27,6 +28,11 @@ except ImportError:
self.__name__ = __name__ self.__name__ = __name__
self.__doc__ = __doc__ self.__doc__ = __doc__
def implements(*args):
pass
def verifyObject(*args):
pass
class IDataManager(Interface): class IDataManager(Interface):
"""Objects that manage transactional storage. """Objects that manage transactional storage.
...@@ -144,6 +150,16 @@ class IDataManager(Interface): ...@@ -144,6 +150,16 @@ class IDataManager(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(Interface): class ITransaction(Interface):
"""Object representing a running transaction. """Object representing a running transaction.
...@@ -224,3 +240,26 @@ class ITransaction(Interface): ...@@ -224,3 +240,26 @@ class ITransaction(Interface):
""" """
# XXX is this this allowed to cause an exception here, during # XXX is this this allowed to cause an exception here, during
# the two-phase commit, or can it toss data silently? # the two-phase commit, or can it toss data silently?
class IConnection(Interface):
"""ZODB connection.
XXX: This interface is incomplete.
"""
def add(ob):
"""Add a new object 'obj' to the database and assign it an oid.
A persistent object is normally added to the database and
assigned an oid when it becomes reachable to an object already in
the database. In some cases, it is useful to create a new
object and use its oid (_p_oid) in a single transaction.
This method assigns a new oid regardless of whether the object
is reachable.
The object is added when the transaction commits. The object
must implement the IPersistent interface and must not
already be associated with a Connection.
"""
...@@ -22,6 +22,7 @@ import transaction ...@@ -22,6 +22,7 @@ import transaction
from ZODB.config import databaseFromString from ZODB.config import databaseFromString
from ZODB.utils import p64, u64 from ZODB.utils import p64, u64
from ZODB.tests.warnhook import WarningsHook from ZODB.tests.warnhook import WarningsHook
from ZODB.interfaces import verifyObject
class ConnectionDotAdd(unittest.TestCase): class ConnectionDotAdd(unittest.TestCase):
...@@ -595,6 +596,15 @@ class StubStorage: ...@@ -595,6 +596,15 @@ class StubStorage:
return None return None
class TestConnectionInterface(unittest.TestCase):
def test(self):
from ZODB.interfaces import IConnection
db = databaseFromString("<zodb>\n<mappingstorage/>\n</zodb>")
cn = db.open()
verifyObject(IConnection, cn)
class StubDatabase: class StubDatabase:
def __init__(self): def __init__(self):
...@@ -608,4 +618,5 @@ class StubDatabase: ...@@ -608,4 +618,5 @@ class StubDatabase:
def test_suite(): def test_suite():
s = unittest.makeSuite(ConnectionDotAdd, 'check') s = unittest.makeSuite(ConnectionDotAdd, 'check')
s.addTest(doctest.DocTestSuite()) s.addTest(doctest.DocTestSuite())
s.addTest(unittest.makeSuite(TestConnectionInterface))
return s return s
...@@ -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()
...@@ -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