Commit 89999e98 authored by Jim Fulton's avatar Jim Fulton Committed by GitHub

Merge pull request #129 from zopefoundation/storage-byte-appreciation

transaction user and description: text above, bytes below
parents 14aa616f 83992521
...@@ -2,6 +2,15 @@ ...@@ -2,6 +2,15 @@
Change History Change History
================ ================
- ZODB now translates transaction meta data, ``user`` and
``description`` from text to bytes before passing them to storages,
and converts them back to text when retrieving them from storages in
the ``history``, ``undoLog`` and ``undoInfo`` methods.
The ``IDatabase`` interface was updated to reflect that ``history``,
``undoLog`` and ``undoInfo`` are available on database objects.
(They were always available, but not documented in the interface.)
5.0.1 (2016-11-17) 5.0.1 (2016-11-17)
================== ==================
......
...@@ -139,7 +139,7 @@ statement. Transaction managers are context managers, so we can use ...@@ -139,7 +139,7 @@ statement. Transaction managers are context managers, so we can use
them with the ``with`` statement directly:: them with the ``with`` statement directly::
with my_transaction_manager as trans: with my_transaction_manager as trans:
trans.note("incrementing x") trans.note(u"incrementing x")
conn.root.x += 1 conn.root.x += 1
.. -> src .. -> src
...@@ -181,14 +181,15 @@ So, for example, if we wanted to set a transaction note:: ...@@ -181,14 +181,15 @@ So, for example, if we wanted to set a transaction note::
with db.transaction() as conn2: with db.transaction() as conn2:
conn2.transaction_manager.get().note("incrementing x again") conn2.transaction_manager.get().note(u"incrementing x again")
conn2.root.x += 1 conn2.root.x += 1
.. -> src .. -> src
>>> exec(src) >>> exec(src)
>>> str(db.history(conn.root()._p_oid)[0]['description']) >>> (db.history(conn.root()._p_oid)[0]['description'] ==
'incrementing x again' ... u'incrementing x again')
True
Here, we used the Here, we used the
:meth:`~transaction.interfaces.ITransactionManager.get` method to get :meth:`~transaction.interfaces.ITransactionManager.get` method to get
......
...@@ -141,7 +141,7 @@ setup(name="ZODB", ...@@ -141,7 +141,7 @@ setup(name="ZODB",
'persistent >= 4.2.0', 'persistent >= 4.2.0',
'BTrees >= 4.2.0', 'BTrees >= 4.2.0',
'ZConfig', 'ZConfig',
'transaction >= 1.6.1', 'transaction >= 2.0.3',
'six', 'six',
'zc.lockfile', 'zc.lockfile',
'zope.interface', 'zope.interface',
......
...@@ -191,7 +191,7 @@ class BaseStorage(UndoLogCompatible): ...@@ -191,7 +191,7 @@ class BaseStorage(UndoLogCompatible):
user = transaction.user user = transaction.user
desc = transaction.description desc = transaction.description
ext = transaction._extension ext = transaction.extension
if ext: if ext:
ext = dumps(ext, _protocol) ext = dumps(ext, _protocol)
else: else:
......
...@@ -27,6 +27,7 @@ from persistent import PickleCache ...@@ -27,6 +27,7 @@ from persistent import PickleCache
from persistent.interfaces import IPersistentDataManager from persistent.interfaces import IPersistentDataManager
from ZODB.interfaces import IConnection from ZODB.interfaces import IConnection
from ZODB.interfaces import IBlobStorage from ZODB.interfaces import IBlobStorage
from ZODB.interfaces import IStorageTransactionMetaData
from ZODB.blob import Blob, rename_or_copy_blob, remove_committed_dir from ZODB.blob import Blob, rename_or_copy_blob, remove_committed_dir
from transaction.interfaces import ISavepointDataManager from transaction.interfaces import ISavepointDataManager
from transaction.interfaces import IDataManagerSavepoint from transaction.interfaces import IDataManagerSavepoint
...@@ -51,6 +52,7 @@ import six ...@@ -51,6 +52,7 @@ import six
from .mvccadapter import HistoricalStorageAdapter from .mvccadapter import HistoricalStorageAdapter
from . import valuedoc from . import valuedoc
from . import _compat
global_reset_counter = 0 global_reset_counter = 0
...@@ -458,15 +460,22 @@ class Connection(ExportImport, object): ...@@ -458,15 +460,22 @@ class Connection(ExportImport, object):
def tpc_begin(self, transaction): def tpc_begin(self, transaction):
"""Begin commit of a transaction, starting the two-phase commit.""" """Begin commit of a transaction, starting the two-phase commit."""
self._modified = [] self._modified = []
meta_data = TransactionMetaData(
transaction.user,
transaction.description,
transaction.extension)
transaction.set_data(self, meta_data)
# _creating is a list of oids of new objects, which is used to # _creating is a list of oids of new objects, which is used to
# remove them from the cache if a transaction aborts. # remove them from the cache if a transaction aborts.
self._creating.clear() self._creating.clear()
self._normal_storage.tpc_begin(transaction) self._normal_storage.tpc_begin(meta_data)
def commit(self, transaction): def commit(self, transaction):
"""Commit changes to an object""" """Commit changes to an object"""
transaction = transaction.data(self)
if self._savepoint_storage is not None: if self._savepoint_storage is not None:
# We first checkpoint the current changes to the savepoint # We first checkpoint the current changes to the savepoint
...@@ -611,6 +620,8 @@ class Connection(ExportImport, object): ...@@ -611,6 +620,8 @@ class Connection(ExportImport, object):
obj._p_serial = s obj._p_serial = s
def tpc_abort(self, transaction): def tpc_abort(self, transaction):
transaction = transaction.data(self)
if self._import: if self._import:
self._import = None self._import = None
...@@ -667,6 +678,9 @@ class Connection(ExportImport, object): ...@@ -667,6 +678,9 @@ class Connection(ExportImport, object):
vote = self._storage.tpc_vote vote = self._storage.tpc_vote
except AttributeError: except AttributeError:
return return
transaction = transaction.data(self)
try: try:
s = vote(transaction) s = vote(transaction)
except ReadConflictError as v: except ReadConflictError as v:
...@@ -683,6 +697,8 @@ class Connection(ExportImport, object): ...@@ -683,6 +697,8 @@ class Connection(ExportImport, object):
def tpc_finish(self, transaction): def tpc_finish(self, transaction):
"""Indicate confirmation that the transaction is done. """Indicate confirmation that the transaction is done.
""" """
transaction = transaction.data(self)
serial = self._storage.tpc_finish(transaction) serial = self._storage.tpc_finish(transaction)
assert type(serial) is bytes, repr(serial) assert type(serial) is bytes, repr(serial)
for oid_iterator in self._modified, self._creating: for oid_iterator in self._modified, self._creating:
...@@ -1270,3 +1286,38 @@ large_record_size option of the ZODB.DB constructor (or the ...@@ -1270,3 +1286,38 @@ large_record_size option of the ZODB.DB constructor (or the
large-record-size option in a configuration file) to specify a larger large-record-size option in a configuration file) to specify a larger
size. size.
""" """
@implementer(IStorageTransactionMetaData)
class TransactionMetaData(object):
def __init__(self, user=u'', description=u'', extension=b''):
if not isinstance(user, bytes):
user = user.encode('utf-8')
self.user = user
if not isinstance(description, bytes):
description = description.encode('utf-8')
self.description = description
if not isinstance(extension, dict):
extension = _compat.loads(extension) if extension else {}
self.extension = extension
def note(self, text): # for tests
text = text.strip()
if not isinstance(text, bytes):
text = text.encode('utf-8')
if self.description:
self.description = self.description.strip() + b' ' + text
else:
self.description = text
@property
def _extension(self):
warnings.warn("_extension is deprecated, use extension",
DeprecationWarning)
return self.extension
@_extension.setter
def _extension(self, v):
self.extension = v
...@@ -24,7 +24,7 @@ from . import utils ...@@ -24,7 +24,7 @@ from . import utils
from ZODB.broken import find_global from ZODB.broken import find_global
from ZODB.utils import z64 from ZODB.utils import z64
from ZODB.Connection import Connection from ZODB.Connection import Connection, TransactionMetaData
from ZODB._compat import Pickler, _protocol, BytesIO from ZODB._compat import Pickler, _protocol, BytesIO
import ZODB.serialize import ZODB.serialize
...@@ -469,7 +469,7 @@ class DB(object): ...@@ -469,7 +469,7 @@ class DB(object):
self.large_record_size = large_record_size self.large_record_size = large_record_size
# Make sure we have a root: # Make sure we have a root:
with self.transaction('initial database creation') as conn: with self.transaction(u'initial database creation') as conn:
try: try:
conn.get(z64) conn.get(z64)
except KeyError: except KeyError:
...@@ -901,7 +901,7 @@ class DB(object): ...@@ -901,7 +901,7 @@ class DB(object):
See :meth:`ZODB.interfaces.IStorage.history`. See :meth:`ZODB.interfaces.IStorage.history`.
""" """
return self.storage.history(oid, size) return _text_transaction_info(self.storage.history(oid, size))
def supportsUndo(self): def supportsUndo(self):
"""Return whether the database supports undo. """Return whether the database supports undo.
...@@ -920,7 +920,7 @@ class DB(object): ...@@ -920,7 +920,7 @@ class DB(object):
if not self.supportsUndo(): if not self.supportsUndo():
return () return ()
return self.storage.undoLog(*args, **kw) return _text_transaction_info(self.storage.undoLog(*args, **kw))
def undoInfo(self, *args, **kw): def undoInfo(self, *args, **kw):
"""Return a sequence of descriptions for transactions. """Return a sequence of descriptions for transactions.
...@@ -929,7 +929,7 @@ class DB(object): ...@@ -929,7 +929,7 @@ class DB(object):
""" """
if not self.supportsUndo(): if not self.supportsUndo():
return () return ()
return self.storage.undoInfo(*args, **kw) return _text_transaction_info(self.storage.undoInfo(*args, **kw))
def undoMultiple(self, ids, txn=None): def undoMultiple(self, ids, txn=None):
"""Undo multiple transactions identified by ids. """Undo multiple transactions identified by ids.
...@@ -1037,19 +1037,28 @@ class TransactionalUndo(object): ...@@ -1037,19 +1037,28 @@ class TransactionalUndo(object):
pass pass
def tpc_begin(self, transaction): def tpc_begin(self, transaction):
self._storage.tpc_begin(transaction) tdata = TransactionMetaData(
transaction.user,
transaction.description,
transaction.extension)
transaction.set_data(self, tdata)
self._storage.tpc_begin(tdata)
def commit(self, transaction): def commit(self, transaction):
transaction = transaction.data(self)
for tid in self._tids: for tid in self._tids:
self._storage.undo(tid, transaction) self._storage.undo(tid, transaction)
def tpc_vote(self, transaction): def tpc_vote(self, transaction):
transaction = transaction.data(self)
self._storage.tpc_vote(transaction) self._storage.tpc_vote(transaction)
def tpc_finish(self, transaction): def tpc_finish(self, transaction):
transaction = transaction.data(self)
self._storage.tpc_finish(transaction) self._storage.tpc_finish(transaction)
def tpc_abort(self, transaction): def tpc_abort(self, transaction):
transaction = transaction.data(self)
self._storage.tpc_abort(transaction) self._storage.tpc_abort(transaction)
def sortKey(self): def sortKey(self):
...@@ -1064,3 +1073,12 @@ def connection(*args, **kw): ...@@ -1064,3 +1073,12 @@ def connection(*args, **kw):
managing a separate database object. managing a separate database object.
""" """
return DB(*args, **kw).open_then_close_db_when_connection_closes() return DB(*args, **kw).open_then_close_db_when_connection_closes()
_transaction_meta_data_text_variables = 'user_name', 'description'
def _text_transaction_info(info):
for d in info:
for name in _transaction_meta_data_text_variables:
if name in d:
d[name] = d[name].decode('utf-8')
return info
...@@ -20,6 +20,7 @@ import unittest ...@@ -20,6 +20,7 @@ import unittest
import ZODB.blob import ZODB.blob
import ZODB.FileStorage import ZODB.FileStorage
import ZODB.tests.util import ZODB.tests.util
from ZODB.Connection import TransactionMetaData
from zope.testing import renormalizing from zope.testing import renormalizing
checker = renormalizing.RENormalizing([ checker = renormalizing.RENormalizing([
...@@ -124,7 +125,7 @@ def pack_with_repeated_blob_records(): ...@@ -124,7 +125,7 @@ def pack_with_repeated_blob_records():
Now, create a transaction with multiple saves: Now, create a transaction with multiple saves:
>>> trans = tm.begin() >>> trans = TransactionMetaData()
>>> fs.tpc_begin(trans) >>> fs.tpc_begin(trans)
>>> with open('ablob', 'w') as file: >>> with open('ablob', 'w') as file:
... _ = file.write('some data') ... _ = file.write('some data')
...@@ -151,7 +152,7 @@ _save_index can fail for large indexes. ...@@ -151,7 +152,7 @@ _save_index can fail for large indexes.
>>> import ZODB.utils >>> import ZODB.utils
>>> fs = ZODB.FileStorage.FileStorage('data.fs') >>> fs = ZODB.FileStorage.FileStorage('data.fs')
>>> t = transaction.begin() >>> t = TransactionMetaData()
>>> fs.tpc_begin(t) >>> fs.tpc_begin(t)
>>> oid = 0 >>> oid = 0
>>> for i in range(5000): >>> for i in range(5000):
......
...@@ -340,7 +340,7 @@ class TransactionRecord: ...@@ -340,7 +340,7 @@ class TransactionRecord:
self.tid = tid self.tid = tid
self.user = transaction.user self.user = transaction.user
self.description = transaction.description self.description = transaction.description
extension = transaction._extension extension = transaction.extension
self.extension = extension self.extension = extension
self.data = data self.data = data
......
...@@ -383,7 +383,41 @@ class IDatabase(IStorageDB): ...@@ -383,7 +383,41 @@ class IDatabase(IStorageDB):
include useful objects. include useful objects.
""" """
# TODO: Should this method be moved into some subinterface? def history(oid, size=1):
"""Return a sequence of history information dictionaries.
Up to size objects (including no objects) may be returned.
The information provides a log of the changes made to the
object. Data are reported in reverse chronological order.
Each dictionary has the following keys:
time
UTC seconds since the epoch (as in time.time) that the
object revision was committed.
tid
The transaction identifier of the transaction that
committed the version.
user_name
The text (unicode) user identifier, if any (or an empty
string) of the user on whos behalf the revision was
committed.
description
The text (unicode) transaction description for the
transaction that committed the revision.
size
The size of the revision data record.
If the transaction had extension items, then these items are
also included if they don't conflict with the keys above.
"""
def pack(t=None, days=0): def pack(t=None, days=0):
"""Pack the storage, deleting unused object revisions. """Pack the storage, deleting unused object revisions.
...@@ -400,7 +434,76 @@ class IDatabase(IStorageDB): ...@@ -400,7 +434,76 @@ class IDatabase(IStorageDB):
time if t is not specified. time if t is not specified.
""" """
# TODO: Should this method be moved into some subinterface? def undoLog(first, last, filter=None):
"""Return a sequence of descriptions for undoable transactions.
Application code should call undoLog() on a DB instance instead of on
the storage directly.
A transaction description is a mapping with at least these keys:
"time": The time, as float seconds since the epoch, when
the transaction committed.
"user_name": The text value of the `.user` attribute on that
transaction.
"description": The text value of the `.description` attribute on
that transaction.
"id`" A bytes uniquely identifying the transaction to the
storage. If it's desired to undo this transaction,
this is the `transaction_id` to pass to `undo()`.
In addition, if any name+value pairs were added to the transaction
by `setExtendedInfo()`, those may be added to the transaction
description mapping too (for example, FileStorage's `undoLog()` does
this).
`filter` is a callable, taking one argument. A transaction
description mapping is passed to `filter` for each potentially
undoable transaction. The sequence returned by `undoLog()` excludes
descriptions for which `filter` returns a false value. By default,
`filter` always returns a true value.
ZEO note: Arbitrary callables cannot be passed from a ZEO client
to a ZEO server, and a ZEO client's implementation of `undoLog()`
ignores any `filter` argument that may be passed. ZEO clients
should use the related `undoInfo()` method instead (if they want
to do filtering).
Now picture a list containing descriptions of all undoable
transactions that pass the filter, most recent transaction first (at
index 0). The `first` and `last` arguments specify the slice of this
(conceptual) list to be returned:
`first`: This is the index of the first transaction description
in the slice. It must be >= 0.
`last`: If >= 0, first:last acts like a Python slice, selecting
the descriptions at indices `first`, first+1, ..., up to
but not including index `last`. At most last-first
descriptions are in the slice, and `last` should be at
least as large as `first` in this case. If `last` is
less than 0, then abs(last) is taken to be the maximum
number of descriptions in the slice (which still begins
at index `first`). When `last` < 0, the same effect
could be gotten by passing the positive first-last for
`last` instead.
"""
def undoInfo(first=0, last=-20, specification=None):
"""Return a sequence of descriptions for undoable transactions.
This is like `undoLog()`, except for the `specification` argument.
If given, `specification` is a dictionary, and `undoInfo()`
synthesizes a `filter` function `f` for `undoLog()` such that
`f(desc)` returns true for a transaction description mapping
`desc` if and only if `desc` maps each key in `specification` to
the same value `specification` maps that key to. In other words,
only extensions (or supersets) of `specification` match.
ZEO note: `undoInfo()` passes the `specification` argument from a
ZEO client to its ZEO server (while a ZEO client ignores any `filter`
argument passed to `undoLog()`).
"""
def undo(id, txn=None): def undo(id, txn=None):
"""Undo a transaction identified by id. """Undo a transaction identified by id.
...@@ -432,6 +535,16 @@ class IDatabase(IStorageDB): ...@@ -432,6 +535,16 @@ class IDatabase(IStorageDB):
should also close all the Connections. should also close all the Connections.
""" """
class IStorageTransactionMetaData(Interface):
"""Provide storage transaction meta data.
Note that unlike transaction.interfaces.ITransaction, the ``user``
and ``description`` attributes are bytes, not text.
"""
user = Attribute("Bytes transaction user")
description = Attribute("Bytes transaction Description")
extension = Attribute(
"A dictionary carrying a transaction's extended_info data")
class IStorage(Interface): class IStorage(Interface):
"""A storage is responsible for storing and retrieving data of objects. """A storage is responsible for storing and retrieving data of objects.
...@@ -513,11 +626,11 @@ class IStorage(Interface): ...@@ -513,11 +626,11 @@ class IStorage(Interface):
An alias for tid, which expected by older clients. An alias for tid, which expected by older clients.
user_name user_name
The user identifier, if any (or an empty string) of the The bytes user identifier, if any (or an empty string) of the
user on whos behalf the revision was committed. user on whos behalf the revision was committed.
description description
The transaction description for the transaction that The bytes transaction description for the transaction that
committed the revision. committed the revision.
size size
...@@ -652,8 +765,7 @@ class IStorage(Interface): ...@@ -652,8 +765,7 @@ class IStorage(Interface):
This must be an empty string. It exists for backward compatibility. This must be an empty string. It exists for backward compatibility.
transaction transaction
A transaction object. This should match the current The object passed to tpc_begin
transaction for the storage, set by tpc_begin.
Several different exceptions may be raised when an error occurs. Several different exceptions may be raised when an error occurs.
...@@ -675,6 +787,8 @@ class IStorage(Interface): ...@@ -675,6 +787,8 @@ class IStorage(Interface):
def tpc_abort(transaction): def tpc_abort(transaction):
"""Abort the transaction. """Abort the transaction.
The argument is the same object passed to tpc_begin.
Any changes made by the transaction are discarded. Any changes made by the transaction are discarded.
This call is ignored is the storage is not participating in This call is ignored is the storage is not participating in
...@@ -685,6 +799,8 @@ class IStorage(Interface): ...@@ -685,6 +799,8 @@ class IStorage(Interface):
def tpc_begin(transaction): def tpc_begin(transaction):
"""Begin the two-phase commit process. """Begin the two-phase commit process.
The argument provides IStorageTransactionMetaData.
If storage is already participating in a two-phase commit If storage is already participating in a two-phase commit
using the same transaction, a StorageTransactionError is raised. using the same transaction, a StorageTransactionError is raised.
...@@ -703,6 +819,8 @@ class IStorage(Interface): ...@@ -703,6 +819,8 @@ class IStorage(Interface):
a different transaction. Failure of this method is extremely a different transaction. Failure of this method is extremely
serious. serious.
The first argument is the same object passed to tpc_begin.
The second argument is a call-back function that must be The second argument is a call-back function that must be
called while the storage transaction lock is held. It takes called while the storage transaction lock is held. It takes
the new transaction id generated by the transaction. the new transaction id generated by the transaction.
...@@ -714,6 +832,8 @@ class IStorage(Interface): ...@@ -714,6 +832,8 @@ class IStorage(Interface):
def tpc_vote(transaction): def tpc_vote(transaction):
"""Provide a storage with an opportunity to veto a transaction """Provide a storage with an opportunity to veto a transaction
The argument is the same object passed to tpc_begin.
This call raises a StorageTransactionError if the storage This call raises a StorageTransactionError if the storage
isn't participating in two-phase commit or if it is commiting isn't participating in two-phase commit or if it is commiting
a different transaction. a different transaction.
...@@ -790,6 +910,8 @@ class IStorageRestoreable(IStorage): ...@@ -790,6 +910,8 @@ class IStorageRestoreable(IStorage):
using a different transaction, the call blocks until the using a different transaction, the call blocks until the
current transaction ends (commits or aborts). current transaction ends (commits or aborts).
The first argument provides IStorageTransactionMetaData.
If a transaction id is given, then the transaction will use If a transaction id is given, then the transaction will use
the given id rather than generating a new id. This is used the given id rather than generating a new id. This is used
when copying already committed transactions from another when copying already committed transactions from another
...@@ -841,26 +963,22 @@ class IStorageRecordInformation(Interface): ...@@ -841,26 +963,22 @@ class IStorageRecordInformation(Interface):
"""Provide information about a single storage record """Provide information about a single storage record
""" """
oid = Attribute("The object id") oid = Attribute("The object id, bytes")
tid = Attribute("The transaction id") tid = Attribute("The transaction id, bytes")
data = Attribute("The data record") data = Attribute("The data record, bytes")
version = Attribute("The version id") data_txn = Attribute("The previous transaction id, bytes")
data_txn = Attribute("The previous transaction id")
class IStorageTransactionInformation(IStorageTransactionMetaData):
class IStorageTransactionInformation(Interface):
"""Provide information about a storage transaction. """Provide information about a storage transaction.
Can be iterated over to retrieve the records modified in the transaction. Can be iterated over to retrieve the records modified in the transaction.
Note that this may contain a status field used by FileStorage to
support packing. At some point, this will go away when FileStorage
has a better pack algoritm.
""" """
tid = Attribute("Transaction id") tid = Attribute("Transaction id")
status = Attribute("Transaction Status") # XXX what are valid values?
user = Attribute("Transaction user")
description = Attribute("Transaction Description")
extension = Attribute(
"A dictionary carrying the transaction's extension data")
def __iter__(): def __iter__():
"""Iterate over the transaction's records given as """Iterate over the transaction's records given as
...@@ -888,7 +1006,6 @@ class IStorageIteration(Interface): ...@@ -888,7 +1006,6 @@ class IStorageIteration(Interface):
""" """
class IStorageUndoable(IStorage): class IStorageUndoable(IStorage):
"""A storage supporting transactional undo. """A storage supporting transactional undo.
""" """
...@@ -922,11 +1039,11 @@ class IStorageUndoable(IStorage): ...@@ -922,11 +1039,11 @@ class IStorageUndoable(IStorage):
"time": The time, as float seconds since the epoch, when "time": The time, as float seconds since the epoch, when
the transaction committed. the transaction committed.
"user_name": The value of the `.user` attribute on that "user_name": The bytes value of the `.user` attribute on that
transaction. transaction.
"description": The value of the `.description` attribute on "description": The bytes value of the `.description` attribute on
that transaction. that transaction.
"id`" A string uniquely identifying the transaction to the "id`" A bytes uniquely identifying the transaction to the
storage. If it's desired to undo this transaction, storage. If it's desired to undo this transaction,
this is the `transaction_id` to pass to `undo()`. this is the `transaction_id` to pass to `undo()`.
...@@ -965,7 +1082,6 @@ class IStorageUndoable(IStorage): ...@@ -965,7 +1082,6 @@ class IStorageUndoable(IStorage):
could be gotten by passing the positive first-last for could be gotten by passing the positive first-last for
`last` instead. `last` instead.
""" """
# DB pass through
def undoInfo(first=0, last=-20, specification=None): def undoInfo(first=0, last=-20, specification=None):
"""Return a sequence of descriptions for undoable transactions. """Return a sequence of descriptions for undoable transactions.
...@@ -982,7 +1098,6 @@ class IStorageUndoable(IStorage): ...@@ -982,7 +1098,6 @@ class IStorageUndoable(IStorage):
ZEO client to its ZEO server (while a ZEO client ignores any `filter` ZEO client to its ZEO server (while a ZEO client ignores any `filter`
argument passed to `undoLog()`). argument passed to `undoLog()`).
""" """
# DB pass-through
class IMVCCStorage(IStorage): class IMVCCStorage(IStorage):
......
...@@ -19,12 +19,12 @@ http://www.zope.org/Documentation/Developer/Models/ZODB/ZODB_Architecture_Storag ...@@ -19,12 +19,12 @@ http://www.zope.org/Documentation/Developer/Models/ZODB/ZODB_Architecture_Storag
All storages should be able to pass these tests. All storages should be able to pass these tests.
""" """
from ZODB import POSException from ZODB import POSException
from ZODB.Connection import TransactionMetaData
from ZODB.tests.MinPO import MinPO from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle
import threading import threading
import time import time
import transaction
import zope.interface import zope.interface
import zope.interface.verify import zope.interface.verify
...@@ -36,7 +36,7 @@ class BasicStorage: ...@@ -36,7 +36,7 @@ class BasicStorage:
def checkBasics(self): def checkBasics(self):
self.assertEqual(self._storage.lastTransaction(), ZERO) self.assertEqual(self._storage.lastTransaction(), ZERO)
t = transaction.Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self.assertRaises(POSException.StorageTransactionError, self.assertRaises(POSException.StorageTransactionError,
self._storage.tpc_begin, t) self._storage.tpc_begin, t)
...@@ -48,22 +48,22 @@ class BasicStorage: ...@@ -48,22 +48,22 @@ class BasicStorage:
self.assertRaises( self.assertRaises(
POSException.StorageTransactionError, POSException.StorageTransactionError,
self._storage.store, self._storage.store,
ZERO, ZERO, b'', '', transaction.Transaction()) ZERO, ZERO, b'', '', TransactionMetaData())
self.assertRaises( self.assertRaises(
POSException.StorageTransactionError, POSException.StorageTransactionError,
self._storage.store, self._storage.store,
ZERO, 1, b'2', '', transaction.Transaction()) ZERO, 1, b'2', '', TransactionMetaData())
self.assertRaises( self.assertRaises(
POSException.StorageTransactionError, POSException.StorageTransactionError,
self._storage.tpc_vote, transaction.Transaction()) self._storage.tpc_vote, TransactionMetaData())
self._storage.tpc_abort(t) self._storage.tpc_abort(t)
def checkSerialIsNoneForInitialRevision(self): def checkSerialIsNoneForInitialRevision(self):
eq = self.assertEqual eq = self.assertEqual
oid = self._storage.new_oid() oid = self._storage.new_oid()
txn = transaction.Transaction() txn = TransactionMetaData()
self._storage.tpc_begin(txn) self._storage.tpc_begin(txn)
# Use None for serial. Don't use _dostore() here because that coerces # Use None for serial. Don't use _dostore() here because that coerces
# serial=None to serial=ZERO. # serial=None to serial=ZERO.
...@@ -106,7 +106,7 @@ class BasicStorage: ...@@ -106,7 +106,7 @@ class BasicStorage:
def checkWriteAfterAbort(self): def checkWriteAfterAbort(self):
oid = self._storage.new_oid() oid = self._storage.new_oid()
t = transaction.Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), '', t) self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), '', t)
# Now abort this transaction # Now abort this transaction
...@@ -119,7 +119,7 @@ class BasicStorage: ...@@ -119,7 +119,7 @@ class BasicStorage:
oid1 = self._storage.new_oid() oid1 = self._storage.new_oid()
revid1 = self._dostore(oid=oid1, data=MinPO(-2)) revid1 = self._dostore(oid=oid1, data=MinPO(-2))
oid = self._storage.new_oid() oid = self._storage.new_oid()
t = transaction.Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), '', t) self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), '', t)
# Now abort this transaction # Now abort this transaction
...@@ -180,9 +180,9 @@ class BasicStorage: ...@@ -180,9 +180,9 @@ class BasicStorage:
def checkNote(self): def checkNote(self):
oid = self._storage.new_oid() oid = self._storage.new_oid()
t = transaction.Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
t.note('this is a test') t.note(u'this is a test')
self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), '', t) self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), '', t)
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
self._storage.tpc_finish(t) self._storage.tpc_finish(t)
...@@ -194,18 +194,14 @@ class BasicStorage: ...@@ -194,18 +194,14 @@ class BasicStorage:
def checkMultipleEmptyTransactions(self): def checkMultipleEmptyTransactions(self):
# There was a bug in handling empty transactions in mapping # There was a bug in handling empty transactions in mapping
# storage that caused the commit lock not to be released. :( # storage that caused the commit lock not to be released. :(
transaction.begin() t = TransactionMetaData()
t = transaction.get()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
self._storage.tpc_finish(t) self._storage.tpc_finish(t)
t.commit() t = TransactionMetaData()
transaction.begin()
t = transaction.get()
self._storage.tpc_begin(t) # Hung here before self._storage.tpc_begin(t) # Hung here before
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
self._storage.tpc_finish(t) self._storage.tpc_finish(t)
t.commit()
def _do_store_in_separate_thread(self, oid, revid, voted): def _do_store_in_separate_thread(self, oid, revid, voted):
# We'll run the competing trans in a separate thread: # We'll run the competing trans in a separate thread:
...@@ -224,8 +220,7 @@ class BasicStorage: ...@@ -224,8 +220,7 @@ class BasicStorage:
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# stale read # stale read
transaction.begin() t = TransactionMetaData()
t = transaction.get()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
try: try:
self._storage.store(b'\0\0\0\0\0\0\0\xf1', self._storage.store(b'\0\0\0\0\0\0\0\xf1',
...@@ -243,8 +238,7 @@ class BasicStorage: ...@@ -243,8 +238,7 @@ class BasicStorage:
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# non-stale read, no stress. :) # non-stale read, no stress. :)
transaction.begin() t = TransactionMetaData()
t = transaction.get()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(b'\0\0\0\0\0\0\0\xf2', self._storage.store(b'\0\0\0\0\0\0\0\xf2',
b'\0\0\0\0\0\0\0\0', data, '', t) b'\0\0\0\0\0\0\0\0', data, '', t)
...@@ -255,8 +249,7 @@ class BasicStorage: ...@@ -255,8 +249,7 @@ class BasicStorage:
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# non-stale read, competition after vote. The competing # non-stale read, competition after vote. The competing
# transaction must produce a tid > this transaction's tid # transaction must produce a tid > this transaction's tid
transaction.begin() t = TransactionMetaData()
t = transaction.get()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(b'\0\0\0\0\0\0\0\xf3', self._storage.store(b'\0\0\0\0\0\0\0\xf3',
b'\0\0\0\0\0\0\0\0', data, '', t) b'\0\0\0\0\0\0\0\0', data, '', t)
...@@ -275,8 +268,7 @@ class BasicStorage: ...@@ -275,8 +268,7 @@ class BasicStorage:
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# non-stale competing trans after checkCurrentSerialInTransaction # non-stale competing trans after checkCurrentSerialInTransaction
transaction.begin() t = TransactionMetaData()
t = transaction.get()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(b'\0\0\0\0\0\0\0\xf4', self._storage.store(b'\0\0\0\0\0\0\0\xf4',
b'\0\0\0\0\0\0\0\0', data, '', t) b'\0\0\0\0\0\0\0\0', data, '', t)
...@@ -312,7 +304,7 @@ class BasicStorage: ...@@ -312,7 +304,7 @@ class BasicStorage:
# verify that a storage gets it right. # verify that a storage gets it right.
# First, some initial data. # First, some initial data.
t = transaction.get() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(ZERO, ZERO, b'x', '', t) self._storage.store(ZERO, ZERO, b'x', '', t)
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
...@@ -322,7 +314,7 @@ class BasicStorage: ...@@ -322,7 +314,7 @@ class BasicStorage:
# OK, now we'll start a new transaction, take it to finish, # OK, now we'll start a new transaction, take it to finish,
# and then block finish while we do some other operations. # and then block finish while we do some other operations.
t = transaction.get() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(ZERO, tids[0], b'y', '', t) self._storage.store(ZERO, tids[0], b'y', '', t)
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
......
...@@ -14,9 +14,10 @@ ...@@ -14,9 +14,10 @@
"""Tests for application-level conflict resolution.""" """Tests for application-level conflict resolution."""
from ZODB import DB from ZODB import DB
from ZODB.Connection import TransactionMetaData
from ZODB.POSException import ConflictError, UndoError from ZODB.POSException import ConflictError, UndoError
from persistent import Persistent from persistent import Persistent
from transaction import Transaction, TransactionManager from transaction import TransactionManager
from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle
...@@ -148,7 +149,7 @@ class ConflictResolvingTransUndoStorage: ...@@ -148,7 +149,7 @@ class ConflictResolvingTransUndoStorage:
# Start the undo # Start the undo
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[1]['id'] tid = info[1]['id']
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.undo(tid, t) self._storage.undo(tid, t)
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
...@@ -170,6 +171,6 @@ class ConflictResolvingTransUndoStorage: ...@@ -170,6 +171,6 @@ class ConflictResolvingTransUndoStorage:
# Start the undo # Start the undo
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[1]['id'] tid = info[1]['id']
t = Transaction() t = TransactionMetaData()
self.assertRaises(UndoError, self._begin_undos_vote, t, tid) self.assertRaises(UndoError, self._begin_undos_vote, t, tid)
self._storage.tpc_abort(t) self._storage.tpc_abort(t)
...@@ -41,7 +41,8 @@ Now we'll use the new deleteObject API to delete the objects. We can't ...@@ -41,7 +41,8 @@ Now we'll use the new deleteObject API to delete the objects. We can't
go through the database to do this, so we'll have to manage the go through the database to do this, so we'll have to manage the
transaction ourselves. transaction ourselves.
>>> txn = transaction.begin() >>> from ZODB.Connection import TransactionMetaData
>>> txn = TransactionMetaData()
>>> storage.tpc_begin(txn) >>> storage.tpc_begin(txn)
>>> storage.deleteObject(oid0, s0, txn) >>> storage.deleteObject(oid0, s0, txn)
>>> storage.deleteObject(oid1, s1, txn) >>> storage.deleteObject(oid1, s1, txn)
...@@ -116,7 +117,7 @@ isn't current: ...@@ -116,7 +117,7 @@ isn't current:
>>> conn.root()[0].x = 1 >>> conn.root()[0].x = 1
>>> transaction.commit() >>> transaction.commit()
>>> txn = transaction.begin() >>> txn = TransactionMetaData()
>>> storage.tpc_begin(txn) >>> storage.tpc_begin(txn)
>>> storage.deleteObject(oid, bad_serial, txn); storage.tpc_vote(txn) >>> storage.deleteObject(oid, bad_serial, txn); storage.tpc_vote(txn)
... # doctest: +ELLIPSIS ... # doctest: +ELLIPSIS
......
...@@ -18,12 +18,11 @@ all these tests. ...@@ -18,12 +18,11 @@ all these tests.
""" """
from ZODB.Connection import TransactionMetaData
from ZODB.tests.MinPO import MinPO from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle
from ZODB.utils import U64, p64, load_current from ZODB.utils import U64, p64, load_current
from transaction import Transaction
import ZODB.blob import ZODB.blob
try: try:
...@@ -67,7 +66,7 @@ class IteratorStorage(IteratorCompare): ...@@ -67,7 +66,7 @@ class IteratorStorage(IteratorCompare):
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
# Undo the creation of the object, rendering it a zombie # Undo the creation of the object, rendering it a zombie
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
oids = self._storage.undo(tid, t) oids = self._storage.undo(tid, t)
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
...@@ -105,7 +104,7 @@ class IteratorStorage(IteratorCompare): ...@@ -105,7 +104,7 @@ class IteratorStorage(IteratorCompare):
# Then the code in FileIterator.next() hasn't yet been fixed. # Then the code in FileIterator.next() hasn't yet been fixed.
# Should automate that check. # Should automate that check.
oid = self._storage.new_oid() oid = self._storage.new_oid()
t = Transaction() t = TransactionMetaData()
data = zodb_pickle(MinPO(0)) data = zodb_pickle(MinPO(0))
try: try:
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
......
...@@ -8,6 +8,7 @@ import six ...@@ -8,6 +8,7 @@ import six
import transaction import transaction
import ZODB import ZODB
from ZODB.Connection import TransactionMetaData
from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle
from ZODB.tests.MinPO import MinPO from ZODB.tests.MinPO import MinPO
from ZODB.POSException import ConflictError from ZODB.POSException import ConflictError
...@@ -140,7 +141,7 @@ class StorageClientThread(TestThread): ...@@ -140,7 +141,7 @@ class StorageClientThread(TestThread):
def dostore(self, i): def dostore(self, i):
data = zodb_pickle(MinPO((self.getName(), i))) data = zodb_pickle(MinPO((self.getName(), i)))
t = transaction.Transaction() t = TransactionMetaData()
oid = self.oid() oid = self.oid()
self.pause() self.pause()
......
...@@ -144,13 +144,13 @@ class PackableStorageBase: ...@@ -144,13 +144,13 @@ class PackableStorageBase:
try: try:
load_current(self._storage, ZERO) load_current(self._storage, ZERO)
except KeyError: except KeyError:
from transaction import Transaction from ZODB.Connection import TransactionMetaData
file = BytesIO() file = BytesIO()
p = Pickler(file, _protocol) p = Pickler(file, _protocol)
p.dump((PersistentMapping, None)) p.dump((PersistentMapping, None))
p.dump({'_container': {}}) p.dump({'_container': {}})
t=Transaction() t = TransactionMetaData()
t.description='initial database creation' t.description = u'initial database creation'
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(ZERO, None, file.getvalue(), '', t) self._storage.store(ZERO, None, file.getvalue(), '', t)
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
...@@ -575,7 +575,7 @@ class PackableUndoStorage(PackableStorageBase): ...@@ -575,7 +575,7 @@ class PackableUndoStorage(PackableStorageBase):
root = conn.root() root = conn.root()
txn = transaction.get() txn = transaction.get()
txn.note('root') txn.note(u'root')
txn.commit() txn.commit()
now = packtime = time.time() now = packtime = time.time()
...@@ -587,12 +587,12 @@ class PackableUndoStorage(PackableStorageBase): ...@@ -587,12 +587,12 @@ class PackableUndoStorage(PackableStorageBase):
root['obj'] = obj root['obj'] = obj
txn = transaction.get() txn = transaction.get()
txn.note('root -> o1') txn.note(u'root -> o1')
txn.commit() txn.commit()
del root['obj'] del root['obj']
txn = transaction.get() txn = transaction.get()
txn.note('root -x-> o1') txn.note(u'root -x-> o1')
txn.commit() txn.commit()
self._storage.pack(packtime, referencesf) self._storage.pack(packtime, referencesf)
...@@ -601,7 +601,7 @@ class PackableUndoStorage(PackableStorageBase): ...@@ -601,7 +601,7 @@ class PackableUndoStorage(PackableStorageBase):
tid = log[0]['id'] tid = log[0]['id']
db.undo(tid) db.undo(tid)
txn = transaction.get() txn = transaction.get()
txn.note('undo root -x-> o1') txn.note(u'undo root -x-> o1')
txn.commit() txn.commit()
conn.sync() conn.sync()
......
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
# FOR A PARTICULAR PURPOSE. # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
from ZODB.Connection import TransactionMetaData
from ZODB.POSException import ReadOnlyError, Unsupported from ZODB.POSException import ReadOnlyError, Unsupported
import transaction
from ZODB.utils import load_current from ZODB.utils import load_current
...@@ -48,7 +48,7 @@ class ReadOnlyStorage: ...@@ -48,7 +48,7 @@ class ReadOnlyStorage:
def checkWriteMethods(self): def checkWriteMethods(self):
self._make_readonly() self._make_readonly()
self.assertRaises(ReadOnlyError, self._storage.new_oid) self.assertRaises(ReadOnlyError, self._storage.new_oid)
t = transaction.Transaction() t = TransactionMetaData()
self.assertRaises(ReadOnlyError, self._storage.tpc_begin, t) self.assertRaises(ReadOnlyError, self._storage.tpc_begin, t)
self.assertRaises(ReadOnlyError, self._storage.store, self.assertRaises(ReadOnlyError, self._storage.store,
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
"""More recovery and iterator tests.""" """More recovery and iterator tests."""
import transaction import transaction
from transaction import Transaction from ZODB.Connection import TransactionMetaData
from ZODB.tests.IteratorStorage import IteratorDeepCompare from ZODB.tests.IteratorStorage import IteratorDeepCompare
from ZODB.tests.StorageTestBase import MinPO, snooze from ZODB.tests.StorageTestBase import MinPO, snooze
from ZODB import DB from ZODB import DB
...@@ -73,15 +73,15 @@ class RecoveryStorage(IteratorDeepCompare): ...@@ -73,15 +73,15 @@ class RecoveryStorage(IteratorDeepCompare):
root = conn.root() root = conn.root()
root.obj = obj1 = MinPO(1) root.obj = obj1 = MinPO(1)
txn = transaction.get() txn = transaction.get()
txn.note('root -> obj') txn.note(u'root -> obj')
txn.commit() txn.commit()
root.obj.obj = obj2 = MinPO(2) root.obj.obj = obj2 = MinPO(2)
txn = transaction.get() txn = transaction.get()
txn.note('root -> obj -> obj') txn.note(u'root -> obj -> obj')
txn.commit() txn.commit()
del root.obj del root.obj
txn = transaction.get() txn = transaction.get()
txn.note('root -X->') txn.note(u'root -X->')
txn.commit() txn.commit()
# Now copy the transactions to the destination # Now copy the transactions to the destination
self._dst.copyTransactionsFrom(self._storage) self._dst.copyTransactionsFrom(self._storage)
...@@ -147,7 +147,7 @@ class RecoveryStorage(IteratorDeepCompare): ...@@ -147,7 +147,7 @@ class RecoveryStorage(IteratorDeepCompare):
# Undo the attribute creation. # Undo the attribute creation.
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
oids = self._storage.undo(tid, t) oids = self._storage.undo(tid, t)
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
...@@ -171,7 +171,7 @@ class RecoveryStorage(IteratorDeepCompare): ...@@ -171,7 +171,7 @@ class RecoveryStorage(IteratorDeepCompare):
# Undo the undo (restore the attributes). # Undo the undo (restore the attributes).
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
oids = self._storage.undo(tid, t) oids = self._storage.undo(tid, t)
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
......
...@@ -13,12 +13,11 @@ ...@@ -13,12 +13,11 @@
############################################################################## ##############################################################################
"""Check loadSerial() on storages that support historical revisions.""" """Check loadSerial() on storages that support historical revisions."""
from ZODB.Connection import TransactionMetaData
from ZODB.tests.MinPO import MinPO from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle, snooze from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle, snooze
from ZODB.utils import p64, u64, load_current from ZODB.utils import p64, u64, load_current
import transaction
ZERO = '\0'*8 ZERO = '\0'*8
class RevisionStorage: class RevisionStorage:
...@@ -142,7 +141,7 @@ class RevisionStorage: ...@@ -142,7 +141,7 @@ class RevisionStorage:
oid = self._storage.new_oid() oid = self._storage.new_oid()
def helper(tid, revid, x): def helper(tid, revid, x):
data = zodb_pickle(MinPO(x)) data = zodb_pickle(MinPO(x))
t = transaction.Transaction() t = TransactionMetaData()
try: try:
self._storage.tpc_begin(t, p64(tid)) self._storage.tpc_begin(t, p64(tid))
self._storage.store(oid, revid, data, '', t) self._storage.store(oid, revid, data, '', t)
......
...@@ -21,8 +21,8 @@ single object revision. ...@@ -21,8 +21,8 @@ single object revision.
from __future__ import print_function from __future__ import print_function
import sys import sys
import time import time
import transaction
from ZODB.Connection import TransactionMetaData
from ZODB.utils import u64, z64 from ZODB.utils import u64, z64
from ZODB.tests.MinPO import MinPO from ZODB.tests.MinPO import MinPO
from ZODB._compat import PersistentPickler, Unpickler, BytesIO, _protocol from ZODB._compat import PersistentPickler, Unpickler, BytesIO, _protocol
...@@ -144,7 +144,7 @@ class StorageTestBase(ZODB.tests.util.TestCase): ...@@ -144,7 +144,7 @@ class StorageTestBase(ZODB.tests.util.TestCase):
if not already_pickled: if not already_pickled:
data = zodb_pickle(data) data = zodb_pickle(data)
# Begin the transaction # Begin the transaction
t = transaction.Transaction() t = TransactionMetaData()
if user is not None: if user is not None:
t.user = user t.user = user
if description is not None: if description is not None:
...@@ -170,8 +170,8 @@ class StorageTestBase(ZODB.tests.util.TestCase): ...@@ -170,8 +170,8 @@ class StorageTestBase(ZODB.tests.util.TestCase):
def _undo(self, tid, expected_oids=None, note=None): def _undo(self, tid, expected_oids=None, note=None):
# Undo a tid that affects a single object (oid). # Undo a tid that affects a single object (oid).
# This is very specialized. # This is very specialized.
t = transaction.Transaction() t = TransactionMetaData()
t.note(note or "undo") t.note(note or u"undo")
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
undo_result = self._storage.undo(tid, t) undo_result = self._storage.undo(tid, t)
vote_result = self._storage.tpc_vote(t) vote_result = self._storage.tpc_vote(t)
......
...@@ -62,7 +62,7 @@ tested? Is it a general restriction? ...@@ -62,7 +62,7 @@ tested? Is it a general restriction?
""" """
from transaction import Transaction from ZODB.Connection import TransactionMetaData
from ZODB.POSException import StorageTransactionError from ZODB.POSException import StorageTransactionError
OID = "\000" * 8 OID = "\000" * 8
...@@ -75,43 +75,43 @@ class SynchronizedStorage: ...@@ -75,43 +75,43 @@ class SynchronizedStorage:
self.assertRaises(StorageTransactionError, callable, *args) self.assertRaises(StorageTransactionError, callable, *args)
def verifyWrongTrans(self, callable, *args): def verifyWrongTrans(self, callable, *args):
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self.assertRaises(StorageTransactionError, callable, *args) self.assertRaises(StorageTransactionError, callable, *args)
self._storage.tpc_abort(t) self._storage.tpc_abort(t)
def checkStoreNotCommitting(self): def checkStoreNotCommitting(self):
self.verifyNotCommitting(self._storage.store, self.verifyNotCommitting(self._storage.store,
OID, SERIALNO, b"", "", Transaction()) OID, SERIALNO, b"", "", TransactionMetaData())
def checkStoreWrongTrans(self): def checkStoreWrongTrans(self):
self.verifyWrongTrans(self._storage.store, self.verifyWrongTrans(self._storage.store,
OID, SERIALNO, b"", "", Transaction()) OID, SERIALNO, b"", "", TransactionMetaData())
def checkAbortNotCommitting(self): def checkAbortNotCommitting(self):
self._storage.tpc_abort(Transaction()) self._storage.tpc_abort(TransactionMetaData())
def checkAbortWrongTrans(self): def checkAbortWrongTrans(self):
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.tpc_abort(Transaction()) self._storage.tpc_abort(TransactionMetaData())
self._storage.tpc_abort(t) self._storage.tpc_abort(t)
def checkFinishNotCommitting(self): def checkFinishNotCommitting(self):
t = Transaction() t = TransactionMetaData()
self.assertRaises(StorageTransactionError, self.assertRaises(StorageTransactionError,
self._storage.tpc_finish, t) self._storage.tpc_finish, t)
self._storage.tpc_abort(t) self._storage.tpc_abort(t)
def checkFinishWrongTrans(self): def checkFinishWrongTrans(self):
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self.assertRaises(StorageTransactionError, self.assertRaises(StorageTransactionError,
self._storage.tpc_finish, Transaction()) self._storage.tpc_finish, TransactionMetaData())
self._storage.tpc_abort(t) self._storage.tpc_abort(t)
def checkBeginCommitting(self): def checkBeginCommitting(self):
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.tpc_abort(t) self._storage.tpc_abort(t)
......
...@@ -17,11 +17,14 @@ Any storage that supports undo() must pass these tests. ...@@ -17,11 +17,14 @@ Any storage that supports undo() must pass these tests.
""" """
import time import time
from six import PY3
from persistent import Persistent from persistent import Persistent
import transaction import transaction
from transaction import Transaction from transaction import Transaction
from ZODB import POSException from ZODB import POSException
from ZODB.Connection import TransactionMetaData
from ZODB.serialize import referencesf from ZODB.serialize import referencesf
from ZODB.utils import p64, load_current from ZODB.utils import p64, load_current
from ZODB import DB from ZODB import DB
...@@ -53,7 +56,7 @@ def listeq(L1, L2): ...@@ -53,7 +56,7 @@ def listeq(L1, L2):
class TransactionalUndoStorage: class TransactionalUndoStorage:
def _multi_obj_transaction(self, objs): def _multi_obj_transaction(self, objs):
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
for oid, rev, data in objs: for oid, rev, data in objs:
self._storage.store(oid, rev, data, '', t) self._storage.store(oid, rev, data, '', t)
...@@ -82,7 +85,7 @@ class TransactionalUndoStorage: ...@@ -82,7 +85,7 @@ class TransactionalUndoStorage:
return oids return oids
def undo(self, tid, note=None): def undo(self, tid, note=None):
t = Transaction() t = TransactionMetaData()
if note is not None: if note is not None:
t.note(note) t.note(note)
oids = self._begin_undos_vote(t, tid) oids = self._begin_undos_vote(t, tid)
...@@ -182,7 +185,7 @@ class TransactionalUndoStorage: ...@@ -182,7 +185,7 @@ class TransactionalUndoStorage:
oid2 = self._storage.new_oid() oid2 = self._storage.new_oid()
revid1 = revid2 = ZERO revid1 = revid2 = ZERO
# Store two objects in the same transaction # Store two objects in the same transaction
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(oid1, revid1, p31, '', t) self._storage.store(oid1, revid1, p31, '', t)
self._storage.store(oid2, revid2, p51, '', t) self._storage.store(oid2, revid2, p51, '', t)
...@@ -190,7 +193,7 @@ class TransactionalUndoStorage: ...@@ -190,7 +193,7 @@ class TransactionalUndoStorage:
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
tid = self._storage.tpc_finish(t) tid = self._storage.tpc_finish(t)
# Update those same two objects # Update those same two objects
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(oid1, tid, p32, '', t) self._storage.store(oid1, tid, p32, '', t)
self._storage.store(oid2, tid, p52, '', t) self._storage.store(oid2, tid, p52, '', t)
...@@ -242,7 +245,7 @@ class TransactionalUndoStorage: ...@@ -242,7 +245,7 @@ class TransactionalUndoStorage:
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
tid1 = info[1]['id'] tid1 = info[1]['id']
t = Transaction() t = TransactionMetaData()
oids = self._begin_undos_vote(t, tid, tid1) oids = self._begin_undos_vote(t, tid, tid1)
serial = self._storage.tpc_finish(t) serial = self._storage.tpc_finish(t)
# We may get the finalization stuff called an extra time, # We may get the finalization stuff called an extra time,
...@@ -275,7 +278,7 @@ class TransactionalUndoStorage: ...@@ -275,7 +278,7 @@ class TransactionalUndoStorage:
revid1 = self._dostore(oid1, data=p31, already_pickled=1) revid1 = self._dostore(oid1, data=p31, already_pickled=1)
revid2 = self._dostore(oid2, data=p51, already_pickled=1) revid2 = self._dostore(oid2, data=p51, already_pickled=1)
# Update those same two objects # Update those same two objects
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(oid1, revid1, p32, '', t) self._storage.store(oid1, revid1, p32, '', t)
self._storage.store(oid2, revid2, p52, '', t) self._storage.store(oid2, revid2, p52, '', t)
...@@ -291,7 +294,7 @@ class TransactionalUndoStorage: ...@@ -291,7 +294,7 @@ class TransactionalUndoStorage:
eq(zodb_unpickle(data), MinPO(51)) eq(zodb_unpickle(data), MinPO(51))
# Like the above, but this time, the second transaction contains only # Like the above, but this time, the second transaction contains only
# one object. # one object.
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(oid1, revid1, p33, '', t) self._storage.store(oid1, revid1, p33, '', t)
self._storage.store(oid2, revid2, p53, '', t) self._storage.store(oid2, revid2, p53, '', t)
...@@ -320,7 +323,7 @@ class TransactionalUndoStorage: ...@@ -320,7 +323,7 @@ class TransactionalUndoStorage:
# Start the undo # Start the undo
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[1]['id'] tid = info[1]['id']
t = Transaction() t = TransactionMetaData()
self.assertRaises(POSException.UndoError, self.assertRaises(POSException.UndoError,
self._begin_undos_vote, t, tid) self._begin_undos_vote, t, tid)
self._storage.tpc_abort(t) self._storage.tpc_abort(t)
...@@ -334,7 +337,7 @@ class TransactionalUndoStorage: ...@@ -334,7 +337,7 @@ class TransactionalUndoStorage:
p81, p82, p91, p92 = map(zodb_pickle, p81, p82, p91, p92 = map(zodb_pickle,
map(MinPO, (81, 82, 91, 92))) map(MinPO, (81, 82, 91, 92)))
t = Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.store(oid1, revid1, p81, '', t) self._storage.store(oid1, revid1, p81, '', t)
self._storage.store(oid2, revid2, p91, '', t) self._storage.store(oid2, revid2, p91, '', t)
...@@ -352,7 +355,7 @@ class TransactionalUndoStorage: ...@@ -352,7 +355,7 @@ class TransactionalUndoStorage:
self.assertNotEqual(tid, revid2) self.assertNotEqual(tid, revid2)
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[1]['id'] tid = info[1]['id']
t = Transaction() t = TransactionMetaData()
self.assertRaises(POSException.UndoError, self.assertRaises(POSException.UndoError,
self._begin_undos_vote, t, tid) self._begin_undos_vote, t, tid)
self._storage.tpc_abort(t) self._storage.tpc_abort(t)
...@@ -411,7 +414,7 @@ class TransactionalUndoStorage: ...@@ -411,7 +414,7 @@ class TransactionalUndoStorage:
root['obj'] = o1 root['obj'] = o1
o1.obj = o2 o1.obj = o2
txn = transaction.get() txn = transaction.get()
txn.note('o1 -> o2') txn.note(u'o1 -> o2')
txn.commit() txn.commit()
now = packtime = time.time() now = packtime = time.time()
while packtime <= now: while packtime <= now:
...@@ -420,12 +423,12 @@ class TransactionalUndoStorage: ...@@ -420,12 +423,12 @@ class TransactionalUndoStorage:
o3 = C() o3 = C()
o2.obj = o3 o2.obj = o3
txn = transaction.get() txn = transaction.get()
txn.note('o1 -> o2 -> o3') txn.note(u'o1 -> o2 -> o3')
txn.commit() txn.commit()
o1.obj = o3 o1.obj = o3
txn = transaction.get() txn = transaction.get()
txn.note('o1 -> o3') txn.note(u'o1 -> o3')
txn.commit() txn.commit()
log = self._storage.undoLog() log = self._storage.undoLog()
...@@ -443,7 +446,7 @@ class TransactionalUndoStorage: ...@@ -443,7 +446,7 @@ class TransactionalUndoStorage:
tid = log[0]['id'] tid = log[0]['id']
db.undo(tid) db.undo(tid)
txn = transaction.get() txn = transaction.get()
txn.note('undo') txn.note(u'undo')
txn.commit() txn.commit()
# undo does a txn-undo, but doesn't invalidate # undo does a txn-undo, but doesn't invalidate
conn.sync() conn.sync()
...@@ -470,14 +473,14 @@ class TransactionalUndoStorage: ...@@ -470,14 +473,14 @@ class TransactionalUndoStorage:
root["key1"] = MinPO(1) root["key1"] = MinPO(1)
root["key2"] = MinPO(2) root["key2"] = MinPO(2)
txn = transaction.get() txn = transaction.get()
txn.note("create 3 keys") txn.note(u"create 3 keys")
txn.commit() txn.commit()
set_pack_time() set_pack_time()
del root["key1"] del root["key1"]
txn = transaction.get() txn = transaction.get()
txn.note("delete 1 key") txn.note(u"delete 1 key")
txn.commit() txn.commit()
set_pack_time() set_pack_time()
...@@ -489,7 +492,7 @@ class TransactionalUndoStorage: ...@@ -489,7 +492,7 @@ class TransactionalUndoStorage:
L = db.undoInfo() L = db.undoInfo()
db.undo(L[0]["id"]) db.undo(L[0]["id"])
txn = transaction.get() txn = transaction.get()
txn.note("undo deletion") txn.note(u"undo deletion")
txn.commit() txn.commit()
set_pack_time() set_pack_time()
...@@ -521,7 +524,7 @@ class TransactionalUndoStorage: ...@@ -521,7 +524,7 @@ class TransactionalUndoStorage:
transaction.commit() transaction.commit()
rt["test"] = MinPO(3) rt["test"] = MinPO(3)
txn = transaction.get() txn = transaction.get()
txn.note("root of undo") txn.note(u"root of undo")
txn.commit() txn.commit()
packtimes = [] packtimes = []
...@@ -529,7 +532,7 @@ class TransactionalUndoStorage: ...@@ -529,7 +532,7 @@ class TransactionalUndoStorage:
L = db.undoInfo() L = db.undoInfo()
db.undo(L[0]["id"]) db.undo(L[0]["id"])
txn = transaction.get() txn = transaction.get()
txn.note("undo %d" % i) txn.note(u"undo %d" % i)
txn.commit() txn.commit()
rt._p_deactivate() rt._p_deactivate()
cn.sync() cn.sync()
...@@ -570,7 +573,7 @@ class TransactionalUndoStorage: ...@@ -570,7 +573,7 @@ class TransactionalUndoStorage:
orig = [] orig = []
for i in range(BATCHES): for i in range(BATCHES):
t = Transaction() t = TransactionMetaData()
tid = p64(i + 1) tid = p64(i + 1)
s.tpc_begin(t, tid) s.tpc_begin(t, tid)
for j in range(OBJECTS): for j in range(OBJECTS):
...@@ -593,7 +596,7 @@ class TransactionalUndoStorage: ...@@ -593,7 +596,7 @@ class TransactionalUndoStorage:
def undo(i): def undo(i):
info = s.undoInfo() info = s.undoInfo()
t = Transaction() t = TransactionMetaData()
s.tpc_begin(t) s.tpc_begin(t)
base = i * OBJECTS + i base = i * OBJECTS + i
for j in range(OBJECTS): for j in range(OBJECTS):
...@@ -646,9 +649,9 @@ class TransactionalUndoStorage: ...@@ -646,9 +649,9 @@ class TransactionalUndoStorage:
def checkUndoLogMetadata(self): def checkUndoLogMetadata(self):
# test that the metadata is correct in the undo log # test that the metadata is correct in the undo log
t = transaction.get() t = transaction.get()
t.note('t1') t.note(u't1')
t.setExtendedInfo('k2', 'this is transaction metadata') t.setExtendedInfo('k2', 'this is transaction metadata')
t.setUser('u3',path='p3') t.setUser(u'u3',path=u'p3')
db = DB(self._storage) db = DB(self._storage)
conn = db.open() conn = db.open()
root = conn.root() root = conn.root()
...@@ -733,7 +736,8 @@ class TransactionalUndoStorage: ...@@ -733,7 +736,8 @@ class TransactionalUndoStorage:
for i in range(4): for i in range(4):
with db.transaction() as conn: with db.transaction() as conn:
conn.transaction_manager.get().note(str(i)) conn.transaction_manager.get().note(
(str if PY3 else unicode)(i))
conn.root.x.inc() conn.root.x.inc()
ids = [l['id'] for l in db.undoLog(1, 3)] ids = [l['id'] for l in db.undoLog(1, 3)]
......
...@@ -377,7 +377,8 @@ If a transaction is aborted in the middle of 2-phase commit, any data ...@@ -377,7 +377,8 @@ If a transaction is aborted in the middle of 2-phase commit, any data
stored are discarded. stored are discarded.
>>> olddata, oldserial = blob_storage.load(blob._p_oid, '') >>> olddata, oldserial = blob_storage.load(blob._p_oid, '')
>>> t = transaction.get() >>> from ZODB.Connection import TransactionMetaData
>>> t = TransactionMetaData()
>>> blob_storage.tpc_begin(t) >>> blob_storage.tpc_begin(t)
>>> with open('blobfile', 'wb') as file: >>> with open('blobfile', 'wb') as file:
... _ = file.write(b'This data should go away') ... _ = file.write(b'This data should go away')
......
...@@ -30,19 +30,19 @@ def create_dangling_ref(db): ...@@ -30,19 +30,19 @@ def create_dangling_ref(db):
rt = db.open().root() rt = db.open().root()
rt[1] = o1 = P() rt[1] = o1 = P()
transaction.get().note("create o1") transaction.get().note(u"create o1")
transaction.commit() transaction.commit()
rt[2] = o2 = P() rt[2] = o2 = P()
transaction.get().note("create o2") transaction.get().note(u"create o2")
transaction.commit() transaction.commit()
c = o1.child = P() c = o1.child = P()
transaction.get().note("set child on o1") transaction.get().note(u"set child on o1")
transaction.commit() transaction.commit()
o1.child = P() o1.child = P()
transaction.get().note("replace child on o1") transaction.get().note(u"replace child on o1")
transaction.commit() transaction.commit()
time.sleep(2) time.sleep(2)
...@@ -53,11 +53,11 @@ def create_dangling_ref(db): ...@@ -53,11 +53,11 @@ def create_dangling_ref(db):
print(repr(c._p_oid)) print(repr(c._p_oid))
o2.child = c o2.child = c
transaction.get().note("set child on o2") transaction.get().note(u"set child on o2")
transaction.commit() transaction.commit()
def main(): def main():
fs = FileStorage("dangle.fs") fs = FileStorage(u"dangle.fs")
db = DB(fs) db = DB(fs)
create_dangling_ref(db) create_dangling_ref(db)
db.close() db.close()
......
...@@ -21,6 +21,8 @@ import sys ...@@ -21,6 +21,8 @@ import sys
import unittest import unittest
import transaction import transaction
from transaction import Transaction
import ZODB.tests.util import ZODB.tests.util
from ZODB.config import databaseFromString from ZODB.config import databaseFromString
from ZODB.utils import p64, u64, z64 from ZODB.utils import p64, u64, z64
...@@ -52,7 +54,7 @@ class ConnectionDotAdd(ZODB.tests.util.TestCase): ...@@ -52,7 +54,7 @@ class ConnectionDotAdd(ZODB.tests.util.TestCase):
self.db = StubDatabase() self.db = StubDatabase()
self.datamgr = Connection(self.db) self.datamgr = Connection(self.db)
self.datamgr.open() self.datamgr.open()
self.transaction = StubTransaction() self.transaction = Transaction()
def test_add(self): def test_add(self):
from ZODB.POSException import InvalidObjectReference from ZODB.POSException import InvalidObjectReference
...@@ -492,7 +494,7 @@ def doctest_transaction_retry_convenience(): ...@@ -492,7 +494,7 @@ def doctest_transaction_retry_convenience():
>>> import ZODB.POSException >>> import ZODB.POSException
>>> for attempt in transaction.manager.attempts(): >>> for attempt in transaction.manager.attempts():
... with attempt as t: ... with attempt as t:
... t.note('test') ... t.note(u'test')
... six.print_(dm['ntry'], ntry) ... six.print_(dm['ntry'], ntry)
... ntry += 1 ... ntry += 1
... dm['ntry'] = ntry ... dm['ntry'] = ntry
...@@ -700,7 +702,6 @@ def doctest_readCurrent(): ...@@ -700,7 +702,6 @@ def doctest_readCurrent():
>>> bad = set() >>> bad = set()
>>> def checkCurrentSerialInTransaction(oid, serial, trans): >>> def checkCurrentSerialInTransaction(oid, serial, trans):
... six.print_('checkCurrentSerialInTransaction', repr(oid)) ... six.print_('checkCurrentSerialInTransaction', repr(oid))
... if trans != transaction.get(): print('oops')
... if oid in bad: ... if oid in bad:
... raise ReadConflictError(oid=oid) ... raise ReadConflictError(oid=oid)
...@@ -1192,9 +1193,6 @@ class EstimatedSizeTests(ZODB.tests.util.TestCase): ...@@ -1192,9 +1193,6 @@ class EstimatedSizeTests(ZODB.tests.util.TestCase):
class StubObject(Persistent): class StubObject(Persistent):
pass pass
class StubTransaction:
pass
class ErrorOnGetstateException(Exception): class ErrorOnGetstateException(Exception):
pass pass
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
# FOR A PARTICULAR PURPOSE. # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
from six import PY2
from ZODB.tests.MinPO import MinPO from ZODB.tests.MinPO import MinPO
import doctest import doctest
...@@ -75,6 +76,39 @@ class DBTests(ZODB.tests.util.TestCase): ...@@ -75,6 +76,39 @@ class DBTests(ZODB.tests.util.TestCase):
import ZODB.serialize import ZODB.serialize
self.assertTrue(self.db.references is ZODB.serialize.referencesf) self.assertTrue(self.db.references is ZODB.serialize.referencesf)
def test_history_and_undo_meta_data_text_handlinf(self):
db = self.db
conn = db.open()
for i in range(3):
with conn.transaction_manager as t:
t.note(u'work %s' % i)
t.setUser(u'user%s' % i)
conn.root()[i] = 42
conn.close()
from ZODB.utils import z64
def check(info, text):
for i, h in enumerate(reversed(info)):
for (name, expect) in (('description', 'work %s'),
('user_name', '/ user%s')):
expect = expect % i
if not text:
expect = expect.encode('ascii')
self.assertEqual(h[name], expect)
if PY2:
expect = unicode if text else str
for name in 'description', 'user_name':
self.assertTrue(isinstance(h[name], expect))
check(db.storage.history(z64, 3), False)
check(db.storage.undoLog(0, 3) , False)
check(db.storage.undoInfo(0, 3) , False)
check(db.history(z64, 3), True)
check(db.undoLog(0, 3) , True)
check(db.undoInfo(0, 3) , True)
def test_invalidateCache(): def test_invalidateCache():
"""The invalidateCache method invalidates a connection caches for all of """The invalidateCache method invalidates a connection caches for all of
......
...@@ -24,6 +24,7 @@ import ZODB.tests.testblob ...@@ -24,6 +24,7 @@ import ZODB.tests.testblob
import zope.testing.setupstack import zope.testing.setupstack
from ZODB import POSException from ZODB import POSException
from ZODB import DB from ZODB import DB
from ZODB.Connection import TransactionMetaData
from ZODB.fsIndex import fsIndex from ZODB.fsIndex import fsIndex
from ZODB.utils import U64, p64, z64, load_current from ZODB.utils import U64, p64, z64, load_current
...@@ -182,7 +183,7 @@ class FileStorageTests( ...@@ -182,7 +183,7 @@ class FileStorageTests(
# If .store() is handed an oid bigger than the storage knows # If .store() is handed an oid bigger than the storage knows
# about already, it's crucial that the storage bump its notion # about already, it's crucial that the storage bump its notion
# of the largest oid in use. # of the largest oid in use.
t = transaction.Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
giant_oid = b'\xee' * 8 giant_oid = b'\xee' * 8
# Store an object. # Store an object.
...@@ -199,7 +200,7 @@ class FileStorageTests( ...@@ -199,7 +200,7 @@ class FileStorageTests(
# knows about already, it's crucial that the storage bump its notion # knows about already, it's crucial that the storage bump its notion
# of the largest oid in use. Because copyTransactionsFrom(), and # of the largest oid in use. Because copyTransactionsFrom(), and
# ZRS recovery, use the .restore() method, this is plain critical. # ZRS recovery, use the .restore() method, this is plain critical.
t = transaction.Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
giant_oid = b'\xee' * 8 giant_oid = b'\xee' * 8
# Store an object. # Store an object.
...@@ -289,7 +290,7 @@ class FileStorageTests( ...@@ -289,7 +290,7 @@ class FileStorageTests(
def checkFlushAfterTruncate(self, fail=False): def checkFlushAfterTruncate(self, fail=False):
r0 = self._dostore(z64) r0 = self._dostore(z64)
storage = self._storage storage = self._storage
t = transaction.Transaction() t = TransactionMetaData()
storage.tpc_begin(t) storage.tpc_begin(t)
storage.store(z64, r0, b'foo', b'', t) storage.store(z64, r0, b'foo', b'', t)
storage.tpc_vote(t) storage.tpc_vote(t)
...@@ -421,7 +422,7 @@ class AnalyzeDotPyTest(StorageTestBase.StorageTestBase): ...@@ -421,7 +422,7 @@ class AnalyzeDotPyTest(StorageTestBase.StorageTestBase):
self._storage.store(oid, revid, data, "", t) self._storage.store(oid, revid, data, "", t)
for i in range(2): for i in range(2):
t = transaction.Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
# sometimes data is in this format # sometimes data is in this format
......
...@@ -16,6 +16,7 @@ import unittest ...@@ -16,6 +16,7 @@ import unittest
from persistent.mapping import PersistentMapping from persistent.mapping import PersistentMapping
import transaction import transaction
from ZODB.Connection import TransactionMetaData
from ZODB.DB import DB from ZODB.DB import DB
from ZODB.tests.MVCCMappingStorage import MVCCMappingStorage from ZODB.tests.MVCCMappingStorage import MVCCMappingStorage
import ZODB.blob import ZODB.blob
...@@ -83,11 +84,11 @@ class MVCCTests: ...@@ -83,11 +84,11 @@ class MVCCTests:
storage = c1._storage storage = c1._storage
t = transaction.Transaction() t = transaction.Transaction()
t.description = 'isolation test 1' t.description = u'isolation test 1'
storage.tpc_begin(t) c1.tpc_begin(t)
c1.commit(t) c1.commit(t)
storage.tpc_vote(t) storage.tpc_vote(t.data(c1))
storage.tpc_finish(t) storage.tpc_finish(t.data(c1))
# The second connection will now load root['alpha'], but due to # The second connection will now load root['alpha'], but due to
# MVCC, it should continue to see the old state. # MVCC, it should continue to see the old state.
...@@ -109,11 +110,11 @@ class MVCCTests: ...@@ -109,11 +110,11 @@ class MVCCTests:
storage = c1._storage storage = c1._storage
t = transaction.Transaction() t = transaction.Transaction()
t.description = 'isolation test 2' t.description = u'isolation test 2'
storage.tpc_begin(t) c1.tpc_begin(t)
c1.commit(t) c1.commit(t)
storage.tpc_vote(t) storage.tpc_vote(t.data(c1))
storage.tpc_finish(t) storage.tpc_finish(t.data(c1))
# The second connection will now load root[3], but due to MVCC, # The second connection will now load root[3], but due to MVCC,
# it should continue to see the old state. # it should continue to see the old state.
...@@ -161,7 +162,7 @@ class MVCCMappingStorageTests( ...@@ -161,7 +162,7 @@ class MVCCMappingStorageTests(
import time import time
from ZODB.utils import newTid from ZODB.utils import newTid
from ZODB.TimeStamp import TimeStamp from ZODB.TimeStamp import TimeStamp
t = transaction.Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
self._storage.tpc_finish(t) self._storage.tpc_finish(t)
...@@ -173,7 +174,7 @@ class MVCCMappingStorageTests( ...@@ -173,7 +174,7 @@ class MVCCMappingStorageTests(
transactions[fake_timestamp] = transactions.values()[0] transactions[fake_timestamp] = transactions.values()[0]
# Verify the next transaction comes after the fake transaction # Verify the next transaction comes after the fake transaction
t = transaction.Transaction() t = TransactionMetaData()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
self.assertEqual(self._storage._tid, b'zzzzzzzz') self.assertEqual(self._storage._tid, b'zzzzzzzz')
......
...@@ -23,9 +23,8 @@ old code, developers will have a hard time testing the new code. ...@@ -23,9 +23,8 @@ old code, developers will have a hard time testing the new code.
import unittest import unittest
import sys import sys
from transaction import Transaction
import ZODB import ZODB
from ZODB.Connection import TransactionMetaData
from ZODB.MappingStorage import MappingStorage from ZODB.MappingStorage import MappingStorage
from six import PY2 from six import PY2
...@@ -47,7 +46,7 @@ class PMTests(unittest.TestCase): ...@@ -47,7 +46,7 @@ class PMTests(unittest.TestCase):
return return
# insert the pickle in place of the root # insert the pickle in place of the root
s = MappingStorage() s = MappingStorage()
t = Transaction() t = TransactionMetaData()
s.tpc_begin(t) s.tpc_begin(t)
s.store('\000' * 8, None, pickle, '', t) s.store('\000' * 8, None, pickle, '', t)
s.tpc_vote(t) s.tpc_vote(t)
......
...@@ -48,7 +48,7 @@ class ZODBTests(ZODB.tests.util.TestCase): ...@@ -48,7 +48,7 @@ class ZODBTests(ZODB.tests.util.TestCase):
root['test'] = pm = PersistentMapping() root['test'] = pm = PersistentMapping()
for n in range(100): for n in range(100):
pm[n] = PersistentMapping({0: 100 - n}) pm[n] = PersistentMapping({0: 100 - n})
transaction.get().note('created test data') transaction.get().note(u'created test data')
transaction.commit() transaction.commit()
conn.close() conn.close()
...@@ -67,7 +67,7 @@ class ZODBTests(ZODB.tests.util.TestCase): ...@@ -67,7 +67,7 @@ class ZODBTests(ZODB.tests.util.TestCase):
def duplicate(self, conn, abort_it): def duplicate(self, conn, abort_it):
transaction.begin() transaction.begin()
transaction.get().note('duplication') transaction.get().note(u'duplication')
root = conn.root() root = conn.root()
ob = root['test'] ob = root['test']
assert len(ob) > 10, 'Insufficient test data' assert len(ob) > 10, 'Insufficient test data'
...@@ -424,7 +424,7 @@ class ZODBTests(ZODB.tests.util.TestCase): ...@@ -424,7 +424,7 @@ class ZODBTests(ZODB.tests.util.TestCase):
for state_num in range(6): for state_num in range(6):
transaction.begin() transaction.begin()
root['state'] = state_num root['state'] = state_num
transaction.get().note('root["state"] = %d' % state_num) transaction.get().note(u'root["state"] = %d' % state_num)
transaction.commit() transaction.commit()
# Undo all but the first. Note that no work is actually # Undo all but the first. Note that no work is actually
...@@ -433,7 +433,7 @@ class ZODBTests(ZODB.tests.util.TestCase): ...@@ -433,7 +433,7 @@ class ZODBTests(ZODB.tests.util.TestCase):
log = self._db.undoLog() log = self._db.undoLog()
self._db.undoMultiple([log[i]['id'] for i in range(5)]) self._db.undoMultiple([log[i]['id'] for i in range(5)])
transaction.get().note('undo states 1 through 5') transaction.get().note(u'undo states 1 through 5')
# Now attempt all those undo operations. # Now attempt all those undo operations.
transaction.commit() transaction.commit()
......
...@@ -49,7 +49,7 @@ Let's add a BTree: ...@@ -49,7 +49,7 @@ Let's add a BTree:
>>> root = db.open().root() >>> root = db.open().root()
>>> root['tree'] = OOBTree() >>> root['tree'] = OOBTree()
>>> txn.get().note('added an OOBTree') >>> txn.get().note(u'added an OOBTree')
>>> txn.get().commit() >>> txn.get().commit()
>>> fsdump(path) #doctest: +ELLIPSIS >>> fsdump(path) #doctest: +ELLIPSIS
Trans #00000 tid=... time=... offset=<OFFSET> Trans #00000 tid=... time=... offset=<OFFSET>
......
...@@ -76,7 +76,7 @@ Let's add a BTree and try again: ...@@ -76,7 +76,7 @@ Let's add a BTree and try again:
>>> root = db.open().root() >>> root = db.open().root()
>>> root['tree'] = OOBTree() >>> root['tree'] = OOBTree()
>>> txn.get().note('added an OOBTree') >>> txn.get().note(u'added an OOBTree')
>>> txn.get().commit() >>> txn.get().commit()
>>> t = Tracer(path) >>> t = Tracer(path)
>>> t.register_oids(0, 1) >>> t.register_oids(0, 1)
...@@ -104,7 +104,7 @@ One more, storing a reference in the BTree back to the root object: ...@@ -104,7 +104,7 @@ One more, storing a reference in the BTree back to the root object:
>>> tree = root['tree'] >>> tree = root['tree']
>>> tree['root'] = root >>> tree['root'] = root
>>> txn.get().note('circling back to the root') >>> txn.get().note(u'circling back to the root')
>>> txn.get().commit() >>> txn.get().commit()
>>> t = Tracer(path) >>> t = Tracer(path)
>>> t.register_oids(0, 1, 2) >>> t.register_oids(0, 1, 2)
......
...@@ -25,6 +25,7 @@ import transaction ...@@ -25,6 +25,7 @@ import transaction
import unittest import unittest
import warnings import warnings
import ZODB.utils import ZODB.utils
from ZODB.Connection import TransactionMetaData
import zope.testing.setupstack import zope.testing.setupstack
from zope.testing import renormalizing from zope.testing import renormalizing
...@@ -161,7 +162,7 @@ def store(storage, oid, value='x', serial=ZODB.utils.z64): ...@@ -161,7 +162,7 @@ def store(storage, oid, value='x', serial=ZODB.utils.z64):
oid = ZODB.utils.p64(oid) oid = ZODB.utils.p64(oid)
if not isinstance(serial, bytes): if not isinstance(serial, bytes):
serial = ZODB.utils.p64(serial) serial = ZODB.utils.p64(serial)
t = transaction.get() t = TransactionMetaData()
storage.tpc_begin(t) storage.tpc_begin(t)
storage.store(oid, serial, value, '', t) storage.store(oid, serial, value, '', t)
storage.tpc_vote(t) storage.tpc_vote(t)
......
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