Commit 844fd710 authored by Jim Fulton's avatar Jim Fulton

Implement IStorageTransactionMetaDataExtensionBytes and use in in Connection

parent 76fe6271
...@@ -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.0',
'six', 'six',
'zc.lockfile', 'zc.lockfile',
'zope.interface', 'zope.interface',
......
...@@ -49,6 +49,7 @@ from ZODB import utils ...@@ -49,6 +49,7 @@ from ZODB import utils
import six import six
from .mvccadapter import HistoricalStorageAdapter from .mvccadapter import HistoricalStorageAdapter
from ._compat import dumps, loads, _protocol
from . import valuedoc from . import valuedoc
...@@ -458,15 +459,22 @@ class Connection(ExportImport, object): ...@@ -458,15 +459,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.extended_info)
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 +619,8 @@ class Connection(ExportImport, object): ...@@ -611,6 +619,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 +677,9 @@ class Connection(ExportImport, object): ...@@ -667,6 +677,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 +696,8 @@ class Connection(ExportImport, object): ...@@ -683,6 +696,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 +1285,54 @@ large_record_size option of the ZODB.DB constructor (or the ...@@ -1270,3 +1285,54 @@ 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.
""" """
class TransactionMetaData:
def __init__(self, user=u'', description=u'', extension=b''):
self.user = user
self.description = description
if isinstance(extension, bytes):
self.extension_bytes = extension
else:
self.extension = extension
@property
def user(self):
return self.__user
@user.setter
def user(self, user):
if not isinstance(user, bytes):
user = user.encode('utf-8')
self.__user = user
@property
def description(self):
return self.__description
@description.setter
def description(self, description):
if not isinstance(description, bytes):
description = description.encode('utf-8')
self.__description = description
@property
def extension(self):
return self.__extension
@extension.setter
def extension(self, v):
self.__extension = v
self.__extension_bytes = dumps(v, _protocol) if v else b''
_extension = extension
@property
def extension_bytes(self):
return self.__extension_bytes
@extension_bytes.setter
def extension_bytes(self, v):
d = loads(v) if v else {}
self.__extension_bytes = v if d else b''
self.__extension = d
...@@ -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
...@@ -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
......
...@@ -84,10 +84,10 @@ class MVCCTests: ...@@ -84,10 +84,10 @@ class MVCCTests:
storage = c1._storage storage = c1._storage
t = transaction.Transaction() t = transaction.Transaction()
t.description = 'isolation test 1' t.description = '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.
...@@ -110,10 +110,10 @@ class MVCCTests: ...@@ -110,10 +110,10 @@ class MVCCTests:
storage = c1._storage storage = c1._storage
t = transaction.Transaction() t = transaction.Transaction()
t.description = 'isolation test 2' t.description = '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.
......
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