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 @@
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)
==================
......
......@@ -139,7 +139,7 @@ statement. Transaction managers are context managers, so we can use
them with the ``with`` statement directly::
with my_transaction_manager as trans:
trans.note("incrementing x")
trans.note(u"incrementing x")
conn.root.x += 1
.. -> src
......@@ -181,14 +181,15 @@ So, for example, if we wanted to set a transaction note::
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
.. -> src
>>> exec(src)
>>> str(db.history(conn.root()._p_oid)[0]['description'])
'incrementing x again'
>>> (db.history(conn.root()._p_oid)[0]['description'] ==
... u'incrementing x again')
True
Here, we used the
:meth:`~transaction.interfaces.ITransactionManager.get` method to get
......
......@@ -141,7 +141,7 @@ setup(name="ZODB",
'persistent >= 4.2.0',
'BTrees >= 4.2.0',
'ZConfig',
'transaction >= 1.6.1',
'transaction >= 2.0.3',
'six',
'zc.lockfile',
'zope.interface',
......
......@@ -191,7 +191,7 @@ class BaseStorage(UndoLogCompatible):
user = transaction.user
desc = transaction.description
ext = transaction._extension
ext = transaction.extension
if ext:
ext = dumps(ext, _protocol)
else:
......
......@@ -27,6 +27,7 @@ from persistent import PickleCache
from persistent.interfaces import IPersistentDataManager
from ZODB.interfaces import IConnection
from ZODB.interfaces import IBlobStorage
from ZODB.interfaces import IStorageTransactionMetaData
from ZODB.blob import Blob, rename_or_copy_blob, remove_committed_dir
from transaction.interfaces import ISavepointDataManager
from transaction.interfaces import IDataManagerSavepoint
......@@ -51,6 +52,7 @@ import six
from .mvccadapter import HistoricalStorageAdapter
from . import valuedoc
from . import _compat
global_reset_counter = 0
......@@ -458,15 +460,22 @@ class Connection(ExportImport, object):
def tpc_begin(self, transaction):
"""Begin commit of a transaction, starting the two-phase commit."""
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
# remove them from the cache if a transaction aborts.
self._creating.clear()
self._normal_storage.tpc_begin(transaction)
self._normal_storage.tpc_begin(meta_data)
def commit(self, transaction):
"""Commit changes to an object"""
transaction = transaction.data(self)
if self._savepoint_storage is not None:
# We first checkpoint the current changes to the savepoint
......@@ -611,6 +620,8 @@ class Connection(ExportImport, object):
obj._p_serial = s
def tpc_abort(self, transaction):
transaction = transaction.data(self)
if self._import:
self._import = None
......@@ -667,6 +678,9 @@ class Connection(ExportImport, object):
vote = self._storage.tpc_vote
except AttributeError:
return
transaction = transaction.data(self)
try:
s = vote(transaction)
except ReadConflictError as v:
......@@ -683,6 +697,8 @@ class Connection(ExportImport, object):
def tpc_finish(self, transaction):
"""Indicate confirmation that the transaction is done.
"""
transaction = transaction.data(self)
serial = self._storage.tpc_finish(transaction)
assert type(serial) is bytes, repr(serial)
for oid_iterator in self._modified, self._creating:
......@@ -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
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
from ZODB.broken import find_global
from ZODB.utils import z64
from ZODB.Connection import Connection
from ZODB.Connection import Connection, TransactionMetaData
from ZODB._compat import Pickler, _protocol, BytesIO
import ZODB.serialize
......@@ -469,7 +469,7 @@ class DB(object):
self.large_record_size = large_record_size
# Make sure we have a root:
with self.transaction('initial database creation') as conn:
with self.transaction(u'initial database creation') as conn:
try:
conn.get(z64)
except KeyError:
......@@ -901,7 +901,7 @@ class DB(object):
See :meth:`ZODB.interfaces.IStorage.history`.
"""
return self.storage.history(oid, size)
return _text_transaction_info(self.storage.history(oid, size))
def supportsUndo(self):
"""Return whether the database supports undo.
......@@ -920,7 +920,7 @@ class DB(object):
if not self.supportsUndo():
return ()
return self.storage.undoLog(*args, **kw)
return _text_transaction_info(self.storage.undoLog(*args, **kw))
def undoInfo(self, *args, **kw):
"""Return a sequence of descriptions for transactions.
......@@ -929,7 +929,7 @@ class DB(object):
"""
if not self.supportsUndo():
return ()
return self.storage.undoInfo(*args, **kw)
return _text_transaction_info(self.storage.undoInfo(*args, **kw))
def undoMultiple(self, ids, txn=None):
"""Undo multiple transactions identified by ids.
......@@ -1037,19 +1037,28 @@ class TransactionalUndo(object):
pass
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):
transaction = transaction.data(self)
for tid in self._tids:
self._storage.undo(tid, transaction)
def tpc_vote(self, transaction):
transaction = transaction.data(self)
self._storage.tpc_vote(transaction)
def tpc_finish(self, transaction):
transaction = transaction.data(self)
self._storage.tpc_finish(transaction)
def tpc_abort(self, transaction):
transaction = transaction.data(self)
self._storage.tpc_abort(transaction)
def sortKey(self):
......@@ -1064,3 +1073,12 @@ def connection(*args, **kw):
managing a separate database object.
"""
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
import ZODB.blob
import ZODB.FileStorage
import ZODB.tests.util
from ZODB.Connection import TransactionMetaData
from zope.testing import renormalizing
checker = renormalizing.RENormalizing([
......@@ -124,7 +125,7 @@ def pack_with_repeated_blob_records():
Now, create a transaction with multiple saves:
>>> trans = tm.begin()
>>> trans = TransactionMetaData()
>>> fs.tpc_begin(trans)
>>> with open('ablob', 'w') as file:
... _ = file.write('some data')
......@@ -151,7 +152,7 @@ _save_index can fail for large indexes.
>>> import ZODB.utils
>>> fs = ZODB.FileStorage.FileStorage('data.fs')
>>> t = transaction.begin()
>>> t = TransactionMetaData()
>>> fs.tpc_begin(t)
>>> oid = 0
>>> for i in range(5000):
......
......@@ -340,7 +340,7 @@ class TransactionRecord:
self.tid = tid
self.user = transaction.user
self.description = transaction.description
extension = transaction._extension
extension = transaction.extension
self.extension = extension
self.data = data
......
This diff is collapsed.
......@@ -19,12 +19,12 @@ http://www.zope.org/Documentation/Developer/Models/ZODB/ZODB_Architecture_Storag
All storages should be able to pass these tests.
"""
from ZODB import POSException
from ZODB.Connection import TransactionMetaData
from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle
import threading
import time
import transaction
import zope.interface
import zope.interface.verify
......@@ -36,7 +36,7 @@ class BasicStorage:
def checkBasics(self):
self.assertEqual(self._storage.lastTransaction(), ZERO)
t = transaction.Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self.assertRaises(POSException.StorageTransactionError,
self._storage.tpc_begin, t)
......@@ -48,22 +48,22 @@ class BasicStorage:
self.assertRaises(
POSException.StorageTransactionError,
self._storage.store,
ZERO, ZERO, b'', '', transaction.Transaction())
ZERO, ZERO, b'', '', TransactionMetaData())
self.assertRaises(
POSException.StorageTransactionError,
self._storage.store,
ZERO, 1, b'2', '', transaction.Transaction())
ZERO, 1, b'2', '', TransactionMetaData())
self.assertRaises(
POSException.StorageTransactionError,
self._storage.tpc_vote, transaction.Transaction())
self._storage.tpc_vote, TransactionMetaData())
self._storage.tpc_abort(t)
def checkSerialIsNoneForInitialRevision(self):
eq = self.assertEqual
oid = self._storage.new_oid()
txn = transaction.Transaction()
txn = TransactionMetaData()
self._storage.tpc_begin(txn)
# Use None for serial. Don't use _dostore() here because that coerces
# serial=None to serial=ZERO.
......@@ -106,7 +106,7 @@ class BasicStorage:
def checkWriteAfterAbort(self):
oid = self._storage.new_oid()
t = transaction.Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), '', t)
# Now abort this transaction
......@@ -119,7 +119,7 @@ class BasicStorage:
oid1 = self._storage.new_oid()
revid1 = self._dostore(oid=oid1, data=MinPO(-2))
oid = self._storage.new_oid()
t = transaction.Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), '', t)
# Now abort this transaction
......@@ -180,9 +180,9 @@ class BasicStorage:
def checkNote(self):
oid = self._storage.new_oid()
t = transaction.Transaction()
t = TransactionMetaData()
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.tpc_vote(t)
self._storage.tpc_finish(t)
......@@ -194,18 +194,14 @@ class BasicStorage:
def checkMultipleEmptyTransactions(self):
# There was a bug in handling empty transactions in mapping
# storage that caused the commit lock not to be released. :(
transaction.begin()
t = transaction.get()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
t.commit()
transaction.begin()
t = transaction.get()
t = TransactionMetaData()
self._storage.tpc_begin(t) # Hung here before
self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
t.commit()
def _do_store_in_separate_thread(self, oid, revid, voted):
# We'll run the competing trans in a separate thread:
......@@ -224,8 +220,7 @@ class BasicStorage:
#----------------------------------------------------------------------
# stale read
transaction.begin()
t = transaction.get()
t = TransactionMetaData()
self._storage.tpc_begin(t)
try:
self._storage.store(b'\0\0\0\0\0\0\0\xf1',
......@@ -243,8 +238,7 @@ class BasicStorage:
#----------------------------------------------------------------------
# non-stale read, no stress. :)
transaction.begin()
t = transaction.get()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(b'\0\0\0\0\0\0\0\xf2',
b'\0\0\0\0\0\0\0\0', data, '', t)
......@@ -255,8 +249,7 @@ class BasicStorage:
#----------------------------------------------------------------------
# non-stale read, competition after vote. The competing
# transaction must produce a tid > this transaction's tid
transaction.begin()
t = transaction.get()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(b'\0\0\0\0\0\0\0\xf3',
b'\0\0\0\0\0\0\0\0', data, '', t)
......@@ -275,8 +268,7 @@ class BasicStorage:
#----------------------------------------------------------------------
# non-stale competing trans after checkCurrentSerialInTransaction
transaction.begin()
t = transaction.get()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(b'\0\0\0\0\0\0\0\xf4',
b'\0\0\0\0\0\0\0\0', data, '', t)
......@@ -312,7 +304,7 @@ class BasicStorage:
# verify that a storage gets it right.
# First, some initial data.
t = transaction.get()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(ZERO, ZERO, b'x', '', t)
self._storage.tpc_vote(t)
......@@ -322,7 +314,7 @@ class BasicStorage:
# OK, now we'll start a new transaction, take it to finish,
# and then block finish while we do some other operations.
t = transaction.get()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(ZERO, tids[0], b'y', '', t)
self._storage.tpc_vote(t)
......
......@@ -14,9 +14,10 @@
"""Tests for application-level conflict resolution."""
from ZODB import DB
from ZODB.Connection import TransactionMetaData
from ZODB.POSException import ConflictError, UndoError
from persistent import Persistent
from transaction import Transaction, TransactionManager
from transaction import TransactionManager
from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle
......@@ -148,7 +149,7 @@ class ConflictResolvingTransUndoStorage:
# Start the undo
info = self._storage.undoInfo()
tid = info[1]['id']
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.undo(tid, t)
self._storage.tpc_vote(t)
......@@ -170,6 +171,6 @@ class ConflictResolvingTransUndoStorage:
# Start the undo
info = self._storage.undoInfo()
tid = info[1]['id']
t = Transaction()
t = TransactionMetaData()
self.assertRaises(UndoError, self._begin_undos_vote, t, tid)
self._storage.tpc_abort(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
transaction ourselves.
>>> txn = transaction.begin()
>>> from ZODB.Connection import TransactionMetaData
>>> txn = TransactionMetaData()
>>> storage.tpc_begin(txn)
>>> storage.deleteObject(oid0, s0, txn)
>>> storage.deleteObject(oid1, s1, txn)
......@@ -116,7 +117,7 @@ isn't current:
>>> conn.root()[0].x = 1
>>> transaction.commit()
>>> txn = transaction.begin()
>>> txn = TransactionMetaData()
>>> storage.tpc_begin(txn)
>>> storage.deleteObject(oid, bad_serial, txn); storage.tpc_vote(txn)
... # doctest: +ELLIPSIS
......
......@@ -18,12 +18,11 @@ all these tests.
"""
from ZODB.Connection import TransactionMetaData
from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle
from ZODB.utils import U64, p64, load_current
from transaction import Transaction
import ZODB.blob
try:
......@@ -67,7 +66,7 @@ class IteratorStorage(IteratorCompare):
info = self._storage.undoInfo()
tid = info[0]['id']
# Undo the creation of the object, rendering it a zombie
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
oids = self._storage.undo(tid, t)
self._storage.tpc_vote(t)
......@@ -105,7 +104,7 @@ class IteratorStorage(IteratorCompare):
# Then the code in FileIterator.next() hasn't yet been fixed.
# Should automate that check.
oid = self._storage.new_oid()
t = Transaction()
t = TransactionMetaData()
data = zodb_pickle(MinPO(0))
try:
self._storage.tpc_begin(t)
......
......@@ -8,6 +8,7 @@ import six
import transaction
import ZODB
from ZODB.Connection import TransactionMetaData
from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle
from ZODB.tests.MinPO import MinPO
from ZODB.POSException import ConflictError
......@@ -140,7 +141,7 @@ class StorageClientThread(TestThread):
def dostore(self, i):
data = zodb_pickle(MinPO((self.getName(), i)))
t = transaction.Transaction()
t = TransactionMetaData()
oid = self.oid()
self.pause()
......
......@@ -144,13 +144,13 @@ class PackableStorageBase:
try:
load_current(self._storage, ZERO)
except KeyError:
from transaction import Transaction
from ZODB.Connection import TransactionMetaData
file = BytesIO()
p = Pickler(file, _protocol)
p.dump((PersistentMapping, None))
p.dump({'_container': {}})
t=Transaction()
t.description='initial database creation'
t = TransactionMetaData()
t.description = u'initial database creation'
self._storage.tpc_begin(t)
self._storage.store(ZERO, None, file.getvalue(), '', t)
self._storage.tpc_vote(t)
......@@ -575,7 +575,7 @@ class PackableUndoStorage(PackableStorageBase):
root = conn.root()
txn = transaction.get()
txn.note('root')
txn.note(u'root')
txn.commit()
now = packtime = time.time()
......@@ -587,12 +587,12 @@ class PackableUndoStorage(PackableStorageBase):
root['obj'] = obj
txn = transaction.get()
txn.note('root -> o1')
txn.note(u'root -> o1')
txn.commit()
del root['obj']
txn = transaction.get()
txn.note('root -x-> o1')
txn.note(u'root -x-> o1')
txn.commit()
self._storage.pack(packtime, referencesf)
......@@ -601,7 +601,7 @@ class PackableUndoStorage(PackableStorageBase):
tid = log[0]['id']
db.undo(tid)
txn = transaction.get()
txn.note('undo root -x-> o1')
txn.note(u'undo root -x-> o1')
txn.commit()
conn.sync()
......
......@@ -11,8 +11,8 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
from ZODB.Connection import TransactionMetaData
from ZODB.POSException import ReadOnlyError, Unsupported
import transaction
from ZODB.utils import load_current
......@@ -48,7 +48,7 @@ class ReadOnlyStorage:
def checkWriteMethods(self):
self._make_readonly()
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.store,
......
......@@ -14,7 +14,7 @@
"""More recovery and iterator tests."""
import transaction
from transaction import Transaction
from ZODB.Connection import TransactionMetaData
from ZODB.tests.IteratorStorage import IteratorDeepCompare
from ZODB.tests.StorageTestBase import MinPO, snooze
from ZODB import DB
......@@ -73,15 +73,15 @@ class RecoveryStorage(IteratorDeepCompare):
root = conn.root()
root.obj = obj1 = MinPO(1)
txn = transaction.get()
txn.note('root -> obj')
txn.note(u'root -> obj')
txn.commit()
root.obj.obj = obj2 = MinPO(2)
txn = transaction.get()
txn.note('root -> obj -> obj')
txn.note(u'root -> obj -> obj')
txn.commit()
del root.obj
txn = transaction.get()
txn.note('root -X->')
txn.note(u'root -X->')
txn.commit()
# Now copy the transactions to the destination
self._dst.copyTransactionsFrom(self._storage)
......@@ -147,7 +147,7 @@ class RecoveryStorage(IteratorDeepCompare):
# Undo the attribute creation.
info = self._storage.undoInfo()
tid = info[0]['id']
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
oids = self._storage.undo(tid, t)
self._storage.tpc_vote(t)
......@@ -171,7 +171,7 @@ class RecoveryStorage(IteratorDeepCompare):
# Undo the undo (restore the attributes).
info = self._storage.undoInfo()
tid = info[0]['id']
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
oids = self._storage.undo(tid, t)
self._storage.tpc_vote(t)
......
......@@ -13,12 +13,11 @@
##############################################################################
"""Check loadSerial() on storages that support historical revisions."""
from ZODB.Connection import TransactionMetaData
from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_unpickle, zodb_pickle, snooze
from ZODB.utils import p64, u64, load_current
import transaction
ZERO = '\0'*8
class RevisionStorage:
......@@ -142,7 +141,7 @@ class RevisionStorage:
oid = self._storage.new_oid()
def helper(tid, revid, x):
data = zodb_pickle(MinPO(x))
t = transaction.Transaction()
t = TransactionMetaData()
try:
self._storage.tpc_begin(t, p64(tid))
self._storage.store(oid, revid, data, '', t)
......
......@@ -21,8 +21,8 @@ single object revision.
from __future__ import print_function
import sys
import time
import transaction
from ZODB.Connection import TransactionMetaData
from ZODB.utils import u64, z64
from ZODB.tests.MinPO import MinPO
from ZODB._compat import PersistentPickler, Unpickler, BytesIO, _protocol
......@@ -144,7 +144,7 @@ class StorageTestBase(ZODB.tests.util.TestCase):
if not already_pickled:
data = zodb_pickle(data)
# Begin the transaction
t = transaction.Transaction()
t = TransactionMetaData()
if user is not None:
t.user = user
if description is not None:
......@@ -170,8 +170,8 @@ class StorageTestBase(ZODB.tests.util.TestCase):
def _undo(self, tid, expected_oids=None, note=None):
# Undo a tid that affects a single object (oid).
# This is very specialized.
t = transaction.Transaction()
t.note(note or "undo")
t = TransactionMetaData()
t.note(note or u"undo")
self._storage.tpc_begin(t)
undo_result = self._storage.undo(tid, t)
vote_result = self._storage.tpc_vote(t)
......
......@@ -62,7 +62,7 @@ tested? Is it a general restriction?
"""
from transaction import Transaction
from ZODB.Connection import TransactionMetaData
from ZODB.POSException import StorageTransactionError
OID = "\000" * 8
......@@ -75,43 +75,43 @@ class SynchronizedStorage:
self.assertRaises(StorageTransactionError, callable, *args)
def verifyWrongTrans(self, callable, *args):
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self.assertRaises(StorageTransactionError, callable, *args)
self._storage.tpc_abort(t)
def checkStoreNotCommitting(self):
self.verifyNotCommitting(self._storage.store,
OID, SERIALNO, b"", "", Transaction())
OID, SERIALNO, b"", "", TransactionMetaData())
def checkStoreWrongTrans(self):
self.verifyWrongTrans(self._storage.store,
OID, SERIALNO, b"", "", Transaction())
OID, SERIALNO, b"", "", TransactionMetaData())
def checkAbortNotCommitting(self):
self._storage.tpc_abort(Transaction())
self._storage.tpc_abort(TransactionMetaData())
def checkAbortWrongTrans(self):
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.tpc_abort(Transaction())
self._storage.tpc_abort(TransactionMetaData())
self._storage.tpc_abort(t)
def checkFinishNotCommitting(self):
t = Transaction()
t = TransactionMetaData()
self.assertRaises(StorageTransactionError,
self._storage.tpc_finish, t)
self._storage.tpc_abort(t)
def checkFinishWrongTrans(self):
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self.assertRaises(StorageTransactionError,
self._storage.tpc_finish, Transaction())
self._storage.tpc_finish, TransactionMetaData())
self._storage.tpc_abort(t)
def checkBeginCommitting(self):
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.tpc_abort(t)
......
......@@ -17,11 +17,14 @@ Any storage that supports undo() must pass these tests.
"""
import time
from six import PY3
from persistent import Persistent
import transaction
from transaction import Transaction
from ZODB import POSException
from ZODB.Connection import TransactionMetaData
from ZODB.serialize import referencesf
from ZODB.utils import p64, load_current
from ZODB import DB
......@@ -53,7 +56,7 @@ def listeq(L1, L2):
class TransactionalUndoStorage:
def _multi_obj_transaction(self, objs):
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
for oid, rev, data in objs:
self._storage.store(oid, rev, data, '', t)
......@@ -82,7 +85,7 @@ class TransactionalUndoStorage:
return oids
def undo(self, tid, note=None):
t = Transaction()
t = TransactionMetaData()
if note is not None:
t.note(note)
oids = self._begin_undos_vote(t, tid)
......@@ -182,7 +185,7 @@ class TransactionalUndoStorage:
oid2 = self._storage.new_oid()
revid1 = revid2 = ZERO
# Store two objects in the same transaction
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(oid1, revid1, p31, '', t)
self._storage.store(oid2, revid2, p51, '', t)
......@@ -190,7 +193,7 @@ class TransactionalUndoStorage:
self._storage.tpc_vote(t)
tid = self._storage.tpc_finish(t)
# Update those same two objects
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(oid1, tid, p32, '', t)
self._storage.store(oid2, tid, p52, '', t)
......@@ -242,7 +245,7 @@ class TransactionalUndoStorage:
info = self._storage.undoInfo()
tid = info[0]['id']
tid1 = info[1]['id']
t = Transaction()
t = TransactionMetaData()
oids = self._begin_undos_vote(t, tid, tid1)
serial = self._storage.tpc_finish(t)
# We may get the finalization stuff called an extra time,
......@@ -275,7 +278,7 @@ class TransactionalUndoStorage:
revid1 = self._dostore(oid1, data=p31, already_pickled=1)
revid2 = self._dostore(oid2, data=p51, already_pickled=1)
# Update those same two objects
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(oid1, revid1, p32, '', t)
self._storage.store(oid2, revid2, p52, '', t)
......@@ -291,7 +294,7 @@ class TransactionalUndoStorage:
eq(zodb_unpickle(data), MinPO(51))
# Like the above, but this time, the second transaction contains only
# one object.
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(oid1, revid1, p33, '', t)
self._storage.store(oid2, revid2, p53, '', t)
......@@ -320,7 +323,7 @@ class TransactionalUndoStorage:
# Start the undo
info = self._storage.undoInfo()
tid = info[1]['id']
t = Transaction()
t = TransactionMetaData()
self.assertRaises(POSException.UndoError,
self._begin_undos_vote, t, tid)
self._storage.tpc_abort(t)
......@@ -334,7 +337,7 @@ class TransactionalUndoStorage:
p81, p82, p91, p92 = map(zodb_pickle,
map(MinPO, (81, 82, 91, 92)))
t = Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.store(oid1, revid1, p81, '', t)
self._storage.store(oid2, revid2, p91, '', t)
......@@ -352,7 +355,7 @@ class TransactionalUndoStorage:
self.assertNotEqual(tid, revid2)
info = self._storage.undoInfo()
tid = info[1]['id']
t = Transaction()
t = TransactionMetaData()
self.assertRaises(POSException.UndoError,
self._begin_undos_vote, t, tid)
self._storage.tpc_abort(t)
......@@ -411,7 +414,7 @@ class TransactionalUndoStorage:
root['obj'] = o1
o1.obj = o2
txn = transaction.get()
txn.note('o1 -> o2')
txn.note(u'o1 -> o2')
txn.commit()
now = packtime = time.time()
while packtime <= now:
......@@ -420,12 +423,12 @@ class TransactionalUndoStorage:
o3 = C()
o2.obj = o3
txn = transaction.get()
txn.note('o1 -> o2 -> o3')
txn.note(u'o1 -> o2 -> o3')
txn.commit()
o1.obj = o3
txn = transaction.get()
txn.note('o1 -> o3')
txn.note(u'o1 -> o3')
txn.commit()
log = self._storage.undoLog()
......@@ -443,7 +446,7 @@ class TransactionalUndoStorage:
tid = log[0]['id']
db.undo(tid)
txn = transaction.get()
txn.note('undo')
txn.note(u'undo')
txn.commit()
# undo does a txn-undo, but doesn't invalidate
conn.sync()
......@@ -470,14 +473,14 @@ class TransactionalUndoStorage:
root["key1"] = MinPO(1)
root["key2"] = MinPO(2)
txn = transaction.get()
txn.note("create 3 keys")
txn.note(u"create 3 keys")
txn.commit()
set_pack_time()
del root["key1"]
txn = transaction.get()
txn.note("delete 1 key")
txn.note(u"delete 1 key")
txn.commit()
set_pack_time()
......@@ -489,7 +492,7 @@ class TransactionalUndoStorage:
L = db.undoInfo()
db.undo(L[0]["id"])
txn = transaction.get()
txn.note("undo deletion")
txn.note(u"undo deletion")
txn.commit()
set_pack_time()
......@@ -521,7 +524,7 @@ class TransactionalUndoStorage:
transaction.commit()
rt["test"] = MinPO(3)
txn = transaction.get()
txn.note("root of undo")
txn.note(u"root of undo")
txn.commit()
packtimes = []
......@@ -529,7 +532,7 @@ class TransactionalUndoStorage:
L = db.undoInfo()
db.undo(L[0]["id"])
txn = transaction.get()
txn.note("undo %d" % i)
txn.note(u"undo %d" % i)
txn.commit()
rt._p_deactivate()
cn.sync()
......@@ -570,7 +573,7 @@ class TransactionalUndoStorage:
orig = []
for i in range(BATCHES):
t = Transaction()
t = TransactionMetaData()
tid = p64(i + 1)
s.tpc_begin(t, tid)
for j in range(OBJECTS):
......@@ -593,7 +596,7 @@ class TransactionalUndoStorage:
def undo(i):
info = s.undoInfo()
t = Transaction()
t = TransactionMetaData()
s.tpc_begin(t)
base = i * OBJECTS + i
for j in range(OBJECTS):
......@@ -646,9 +649,9 @@ class TransactionalUndoStorage:
def checkUndoLogMetadata(self):
# test that the metadata is correct in the undo log
t = transaction.get()
t.note('t1')
t.note(u't1')
t.setExtendedInfo('k2', 'this is transaction metadata')
t.setUser('u3',path='p3')
t.setUser(u'u3',path=u'p3')
db = DB(self._storage)
conn = db.open()
root = conn.root()
......@@ -733,7 +736,8 @@ class TransactionalUndoStorage:
for i in range(4):
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()
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
stored are discarded.
>>> olddata, oldserial = blob_storage.load(blob._p_oid, '')
>>> t = transaction.get()
>>> from ZODB.Connection import TransactionMetaData
>>> t = TransactionMetaData()
>>> blob_storage.tpc_begin(t)
>>> with open('blobfile', 'wb') as file:
... _ = file.write(b'This data should go away')
......
......@@ -30,19 +30,19 @@ def create_dangling_ref(db):
rt = db.open().root()
rt[1] = o1 = P()
transaction.get().note("create o1")
transaction.get().note(u"create o1")
transaction.commit()
rt[2] = o2 = P()
transaction.get().note("create o2")
transaction.get().note(u"create o2")
transaction.commit()
c = o1.child = P()
transaction.get().note("set child on o1")
transaction.get().note(u"set child on o1")
transaction.commit()
o1.child = P()
transaction.get().note("replace child on o1")
transaction.get().note(u"replace child on o1")
transaction.commit()
time.sleep(2)
......@@ -53,11 +53,11 @@ def create_dangling_ref(db):
print(repr(c._p_oid))
o2.child = c
transaction.get().note("set child on o2")
transaction.get().note(u"set child on o2")
transaction.commit()
def main():
fs = FileStorage("dangle.fs")
fs = FileStorage(u"dangle.fs")
db = DB(fs)
create_dangling_ref(db)
db.close()
......
......@@ -21,6 +21,8 @@ import sys
import unittest
import transaction
from transaction import Transaction
import ZODB.tests.util
from ZODB.config import databaseFromString
from ZODB.utils import p64, u64, z64
......@@ -52,7 +54,7 @@ class ConnectionDotAdd(ZODB.tests.util.TestCase):
self.db = StubDatabase()
self.datamgr = Connection(self.db)
self.datamgr.open()
self.transaction = StubTransaction()
self.transaction = Transaction()
def test_add(self):
from ZODB.POSException import InvalidObjectReference
......@@ -492,7 +494,7 @@ def doctest_transaction_retry_convenience():
>>> import ZODB.POSException
>>> for attempt in transaction.manager.attempts():
... with attempt as t:
... t.note('test')
... t.note(u'test')
... six.print_(dm['ntry'], ntry)
... ntry += 1
... dm['ntry'] = ntry
......@@ -700,7 +702,6 @@ def doctest_readCurrent():
>>> bad = set()
>>> def checkCurrentSerialInTransaction(oid, serial, trans):
... six.print_('checkCurrentSerialInTransaction', repr(oid))
... if trans != transaction.get(): print('oops')
... if oid in bad:
... raise ReadConflictError(oid=oid)
......@@ -1192,9 +1193,6 @@ class EstimatedSizeTests(ZODB.tests.util.TestCase):
class StubObject(Persistent):
pass
class StubTransaction:
pass
class ErrorOnGetstateException(Exception):
pass
......
......@@ -11,6 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
from six import PY2
from ZODB.tests.MinPO import MinPO
import doctest
......@@ -75,6 +76,39 @@ class DBTests(ZODB.tests.util.TestCase):
import ZODB.serialize
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():
"""The invalidateCache method invalidates a connection caches for all of
......
......@@ -24,6 +24,7 @@ import ZODB.tests.testblob
import zope.testing.setupstack
from ZODB import POSException
from ZODB import DB
from ZODB.Connection import TransactionMetaData
from ZODB.fsIndex import fsIndex
from ZODB.utils import U64, p64, z64, load_current
......@@ -182,7 +183,7 @@ class FileStorageTests(
# If .store() is handed an oid bigger than the storage knows
# about already, it's crucial that the storage bump its notion
# of the largest oid in use.
t = transaction.Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
giant_oid = b'\xee' * 8
# Store an object.
......@@ -199,7 +200,7 @@ class FileStorageTests(
# knows about already, it's crucial that the storage bump its notion
# of the largest oid in use. Because copyTransactionsFrom(), and
# ZRS recovery, use the .restore() method, this is plain critical.
t = transaction.Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
giant_oid = b'\xee' * 8
# Store an object.
......@@ -289,7 +290,7 @@ class FileStorageTests(
def checkFlushAfterTruncate(self, fail=False):
r0 = self._dostore(z64)
storage = self._storage
t = transaction.Transaction()
t = TransactionMetaData()
storage.tpc_begin(t)
storage.store(z64, r0, b'foo', b'', t)
storage.tpc_vote(t)
......@@ -421,7 +422,7 @@ class AnalyzeDotPyTest(StorageTestBase.StorageTestBase):
self._storage.store(oid, revid, data, "", t)
for i in range(2):
t = transaction.Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
# sometimes data is in this format
......
......@@ -16,6 +16,7 @@ import unittest
from persistent.mapping import PersistentMapping
import transaction
from ZODB.Connection import TransactionMetaData
from ZODB.DB import DB
from ZODB.tests.MVCCMappingStorage import MVCCMappingStorage
import ZODB.blob
......@@ -83,11 +84,11 @@ class MVCCTests:
storage = c1._storage
t = transaction.Transaction()
t.description = 'isolation test 1'
storage.tpc_begin(t)
t.description = u'isolation test 1'
c1.tpc_begin(t)
c1.commit(t)
storage.tpc_vote(t)
storage.tpc_finish(t)
storage.tpc_vote(t.data(c1))
storage.tpc_finish(t.data(c1))
# The second connection will now load root['alpha'], but due to
# MVCC, it should continue to see the old state.
......@@ -109,11 +110,11 @@ class MVCCTests:
storage = c1._storage
t = transaction.Transaction()
t.description = 'isolation test 2'
storage.tpc_begin(t)
t.description = u'isolation test 2'
c1.tpc_begin(t)
c1.commit(t)
storage.tpc_vote(t)
storage.tpc_finish(t)
storage.tpc_vote(t.data(c1))
storage.tpc_finish(t.data(c1))
# The second connection will now load root[3], but due to MVCC,
# it should continue to see the old state.
......@@ -161,7 +162,7 @@ class MVCCMappingStorageTests(
import time
from ZODB.utils import newTid
from ZODB.TimeStamp import TimeStamp
t = transaction.Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
......@@ -173,7 +174,7 @@ class MVCCMappingStorageTests(
transactions[fake_timestamp] = transactions.values()[0]
# Verify the next transaction comes after the fake transaction
t = transaction.Transaction()
t = TransactionMetaData()
self._storage.tpc_begin(t)
self.assertEqual(self._storage._tid, b'zzzzzzzz')
......
......@@ -23,9 +23,8 @@ old code, developers will have a hard time testing the new code.
import unittest
import sys
from transaction import Transaction
import ZODB
from ZODB.Connection import TransactionMetaData
from ZODB.MappingStorage import MappingStorage
from six import PY2
......@@ -47,7 +46,7 @@ class PMTests(unittest.TestCase):
return
# insert the pickle in place of the root
s = MappingStorage()
t = Transaction()
t = TransactionMetaData()
s.tpc_begin(t)
s.store('\000' * 8, None, pickle, '', t)
s.tpc_vote(t)
......
......@@ -48,7 +48,7 @@ class ZODBTests(ZODB.tests.util.TestCase):
root['test'] = pm = PersistentMapping()
for n in range(100):
pm[n] = PersistentMapping({0: 100 - n})
transaction.get().note('created test data')
transaction.get().note(u'created test data')
transaction.commit()
conn.close()
......@@ -67,7 +67,7 @@ class ZODBTests(ZODB.tests.util.TestCase):
def duplicate(self, conn, abort_it):
transaction.begin()
transaction.get().note('duplication')
transaction.get().note(u'duplication')
root = conn.root()
ob = root['test']
assert len(ob) > 10, 'Insufficient test data'
......@@ -424,7 +424,7 @@ class ZODBTests(ZODB.tests.util.TestCase):
for state_num in range(6):
transaction.begin()
root['state'] = state_num
transaction.get().note('root["state"] = %d' % state_num)
transaction.get().note(u'root["state"] = %d' % state_num)
transaction.commit()
# Undo all but the first. Note that no work is actually
......@@ -433,7 +433,7 @@ class ZODBTests(ZODB.tests.util.TestCase):
log = self._db.undoLog()
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.
transaction.commit()
......
......@@ -49,7 +49,7 @@ Let's add a BTree:
>>> root = db.open().root()
>>> root['tree'] = OOBTree()
>>> txn.get().note('added an OOBTree')
>>> txn.get().note(u'added an OOBTree')
>>> txn.get().commit()
>>> fsdump(path) #doctest: +ELLIPSIS
Trans #00000 tid=... time=... offset=<OFFSET>
......
......@@ -76,7 +76,7 @@ Let's add a BTree and try again:
>>> root = db.open().root()
>>> root['tree'] = OOBTree()
>>> txn.get().note('added an OOBTree')
>>> txn.get().note(u'added an OOBTree')
>>> txn.get().commit()
>>> t = Tracer(path)
>>> t.register_oids(0, 1)
......@@ -104,7 +104,7 @@ One more, storing a reference in the BTree back to the root object:
>>> tree = root['tree']
>>> tree['root'] = root
>>> txn.get().note('circling back to the root')
>>> txn.get().note(u'circling back to the root')
>>> txn.get().commit()
>>> t = Tracer(path)
>>> t.register_oids(0, 1, 2)
......
......@@ -25,6 +25,7 @@ import transaction
import unittest
import warnings
import ZODB.utils
from ZODB.Connection import TransactionMetaData
import zope.testing.setupstack
from zope.testing import renormalizing
......@@ -161,7 +162,7 @@ def store(storage, oid, value='x', serial=ZODB.utils.z64):
oid = ZODB.utils.p64(oid)
if not isinstance(serial, bytes):
serial = ZODB.utils.p64(serial)
t = transaction.get()
t = TransactionMetaData()
storage.tpc_begin(t)
storage.store(oid, serial, value, '', 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