Commit 53f912a8 authored by Joshua Woelfel's avatar Joshua Woelfel

Implemented zconn_at for zodb4 and zodb3

parent 87ac03a7
......@@ -27,6 +27,8 @@ from ZODB.utils import p64, u64
from persistent import Persistent
from weakref import WeakSet
import gc
from persistent.TimeStamp import TimeStamp
import time
import pkg_resources
......@@ -177,25 +179,41 @@ def zconn_at(zconn): # -> tid
raise AssertionError("zconn_at: TODO: add support for zstor %r" % zstor)
# ZODB4
#
# Connection:
# .before !None for historic connections
#
# ._txn_time - if !None - set to tid of _next_ transaction
# XXX set to None initially - what to do?
#
# # XXX do something like that ZODB5 is doing:
# zconn._start = zconn._storage.lastTransaction() + 1
# # XXX _and_ check out queued invalidations
elif zmajor == 4:
raise AssertionError("zconn_at: TODO: add support for ZODB4")
# ZODB3
# ZODB3, ZODB4
#
# If historic connection, convert and return zconn.before. Otherwise
# returns tid of last transaction, if viewing latest db state, or if
# later db state exists, returns tid of db state previous to later
# state
else:
raise AssertionError("zconn_at: TODO: add support for ZODB3")
if __isHistoricConnection(zconn):
return before2at(zconn.before)
else:
last_transaction = zconn.db().lastTransaction()
if __viewingLatestState(zconn):
return last_transaction
else:
return __tidOfDbStateBefore(zconn._storage, before2at(zconn._txn_time))
# looks through OOBTree storing all tids of storage to find the tid previous
# to before
def __tidOfDbStateBefore(storage, before):
# lookup should be O(log n) but unsure of the overhead space
# implication of this operation, perhaps there is a less
# expensive way of getting this value
return storage._transactions.maxKey(before)
# returns true/false if zconn is viewing latest db state at time of
# function call
def __viewingLatestState(zconn):
return True if zconn._txn_time is None else False
# returns true/false if zconn is a historical connection
def __isHistoricConnection(zconn):
if zmajor >= 5:
return isinstance(zconn._storage, ZODB.mvccadapter.HistoricalStorageAdapter)
else:
return True if not(zconn.before is None) else False
# before2at converts tid that specifies database state as "before" into tid that
# specifies database state as "at".
......@@ -264,6 +282,8 @@ ZODB.Connection.Connection.open = Connection_open
# patch for ZODB.Connection to support callback on after database view is changed
ZODB.Connection.Connection._onResyncCallbacks = None
def Connection_onResyncCallback(self, f):
if zmajor <= 4:
raise AssertionError("onResyncCallback: TODO: add support for ZODB34")
if self._onResyncCallbacks is None:
# NOTE WeakSet does not work for bound methods - they are always created
# anew for each obj.method access, and thus will go away almost immediately
......@@ -273,21 +293,44 @@ def Connection_onResyncCallback(self, f):
assert not hasattr(ZODB.Connection.Connection, 'onResyncCallback')
ZODB.Connection.Connection.onResyncCallback = Connection_onResyncCallback
# ZODB5: hook into Connection.newTransaction XXX .newTransaction .afterCompletion ?
# ZODB4: hook into Connection._storage_sync XXX .newTransaction .afterCompletion ?
# ZODB5: hook into Connection.newTransaction
if zmajor >= 5:
_orig_Connection_newTransaction = ZODB.Connection.Connection.newTransaction
def _ZConnection_newTransaction(self, transaction, sync=True):
_orig_Connection_newTransaction(self, transaction, sync)
# FIXME method name hardcoded. Better not do it and allow f to be general
# callable, but that does not work with bound method - see above.
# ( Something like WeakMethod from py3 could help )
if self._onResyncCallbacks:
for f in self._onResyncCallbacks:
f.on_connection_resync()
ZODB.Connection.Connection.newTransaction = _ZConnection_newTransaction
# ZODB4: hook into Connection._storage_sync
elif zmajor == 4:
pass # raises in onResyncCallback
# ZODB3: TODO
# XXX ZODB5 only for now
# XXX ERP5Type/patches/ZODBConnection.py overrides newTransaction without calling orig_newTransaction
# -> fix it there.
_orig_Connection_newTransaction = ZODB.Connection.Connection.newTransaction
def _ZConnection_newTransaction(self, transaction, sync=True):
_orig_Connection_newTransaction(self, transaction, sync)
else:
pass # raises in onResyncCallback
# FIXME method name hardcoded. Better not do it and allow f to be general
# callable, but that does not work with bound method - see above.
# ( Something like WeakMethod from py3 could help )
if self._onResyncCallbacks:
for f in self._onResyncCallbacks:
f.on_connection_resync()
ZODB.Connection.Connection.newTransaction = _ZConnection_newTransaction
# zstor_2zurl converts a ZODB storage to URL to access it.
def zstor_2zurl(zstor):
# There is, sadly, no unified way to do it, as even if storages are created via
# zodburi, after creation its uri is lost. And storages could be created not
# only through URI but e.g. via ZConfig and manually. We want to support all
# those cases...
#
# For this reason extract URL with important for wcfs use-case parameters in
# ad-hoc way.
if isinstance(zstor, FileStorage):
return "file://%s" % (zstor._file_name,)
# TODO ZEO + NEO support
raise NotImplementedError("don't know how to extract zurl from %r" % zstor)
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