Skip to content

Commit

Permalink
Implement IStorageTransactionMetaDataExtensionBytes and use in in Con…
Browse files Browse the repository at this point in the history
…nection
  • Loading branch information
Jim Fulton committed Nov 14, 2016
1 parent 76fe627 commit 844fd71
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 13 deletions.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def read_file(*path):
'persistent >= 4.2.0',
'BTrees >= 4.2.0',
'ZConfig',
'transaction >= 1.6.1',
'transaction >= 2.0.0',
'six',
'zc.lockfile',
'zope.interface',
Expand Down
68 changes: 67 additions & 1 deletion src/ZODB/Connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import six

from .mvccadapter import HistoricalStorageAdapter
from ._compat import dumps, loads, _protocol

from . import valuedoc

Expand Down Expand Up @@ -458,15 +459,22 @@ def _tpc_cleanup(self):
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.extended_info)
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
Expand Down Expand Up @@ -611,6 +619,8 @@ def _store_objects(self, writer, transaction):
obj._p_serial = s

def tpc_abort(self, transaction):
transaction = transaction.data(self)

if self._import:
self._import = None

Expand Down Expand Up @@ -667,6 +677,9 @@ def tpc_vote(self, transaction):
vote = self._storage.tpc_vote
except AttributeError:
return

transaction = transaction.data(self)

try:
s = vote(transaction)
except ReadConflictError as v:
Expand All @@ -683,6 +696,8 @@ def tpc_vote(self, transaction):
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:
Expand Down Expand Up @@ -1270,3 +1285,54 @@ def __repr__(self):
large-record-size option in a configuration file) to specify a larger
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
8 changes: 3 additions & 5 deletions src/ZODB/tests/testConnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import unittest

import transaction
from transaction import Transaction

import ZODB.tests.util
from ZODB.config import databaseFromString
from ZODB.utils import p64, u64, z64
Expand Down Expand Up @@ -52,7 +54,7 @@ def setUp(self):
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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1192,9 +1193,6 @@ def test_cache_garbage_collection_shrinking_object(self):
class StubObject(Persistent):
pass

class StubTransaction:
pass

class ErrorOnGetstateException(Exception):
pass

Expand Down
12 changes: 6 additions & 6 deletions src/ZODB/tests/testMVCCMappingStorage.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ def checkCrossConnectionIsolation(self):
storage = c1._storage
t = transaction.Transaction()
t.description = 'isolation test 1'
storage.tpc_begin(t)
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.
Expand All @@ -110,10 +110,10 @@ def checkCrossConnectionIsolation(self):
storage = c1._storage
t = transaction.Transaction()
t.description = 'isolation test 2'
storage.tpc_begin(t)
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.
Expand Down

0 comments on commit 844fd71

Please sign in to comment.