Commit 09675411 authored by Jim Fulton's avatar Jim Fulton

Removed some extraneous doumentation.

Removed undo and version support.

Removed close, cleanup, and pack. Storages should implement these and
providing stubs encourages broken implementations.

history should return a sequence.

Renamed getSerial to getTid.

Added a ZEO-required storage tpc_transaction method to get a storage's
current transaction, if any.

Reduced loadBefore to an empty method.  This produces the same output
as before. :)  There was an elaborate implementation that only worked
with an implementation that didn't need it. :)

Removed getExtensionMethods, which is not part of the storage API.

Created a copy *function* from copyTransactionsFrom. Now
copyTransactionsFrom just uses that.  Now this logic, such as it is,
can be reused without inheritence.
parent 9f58b800
...@@ -54,20 +54,6 @@ class BaseStorage(UndoLogCompatible): ...@@ -54,20 +54,6 @@ class BaseStorage(UndoLogCompatible):
If it stores multiple revisions, it should implement If it stores multiple revisions, it should implement
loadSerial() loadSerial()
loadBefore() loadBefore()
iterator()
If the subclass wants to implement undo, it should implement the
multiple revision methods and:
undo()
undoInfo()
undoLog()
If the subclass wants to implement versions, it must implement:
abortVersion()
commitVersion()
modifiedInVersion()
versionEmpty()
versions()
Each storage will have two locks that are accessed via lock Each storage will have two locks that are accessed via lock
acquire and release methods bound to the instance. (Yuck.) acquire and release methods bound to the instance. (Yuck.)
...@@ -112,22 +98,6 @@ class BaseStorage(UndoLogCompatible): ...@@ -112,22 +98,6 @@ class BaseStorage(UndoLogCompatible):
else: else:
self._oid = oid self._oid = oid
def abortVersion(self, src, transaction):
if transaction is not self._transaction:
raise POSException.StorageTransactionError(self, transaction)
return self._tid, []
def commitVersion(self, src, dest, transaction):
if transaction is not self._transaction:
raise POSException.StorageTransactionError(self, transaction)
return self._tid, []
def close(self):
pass
def cleanup(self):
pass
def sortKey(self): def sortKey(self):
"""Return a string that can be used to sort storage instances. """Return a string that can be used to sort storage instances.
...@@ -144,10 +114,7 @@ class BaseStorage(UndoLogCompatible): ...@@ -144,10 +114,7 @@ class BaseStorage(UndoLogCompatible):
return len(self)*300 # WAG! return len(self)*300 # WAG!
def history(self, oid, version, length=1, filter=None): def history(self, oid, version, length=1, filter=None):
pass return ()
def modifiedInVersion(self, oid):
return ''
def new_oid(self): def new_oid(self):
if self._is_read_only: if self._is_read_only:
...@@ -183,12 +150,6 @@ class BaseStorage(UndoLogCompatible): ...@@ -183,12 +150,6 @@ class BaseStorage(UndoLogCompatible):
def isReadOnly(self): def isReadOnly(self):
return self._is_read_only return self._is_read_only
def supportsUndo(self):
return 0
def supportsVersions(self):
return 0
def tpc_abort(self, transaction): def tpc_abort(self, transaction):
self._lock_acquire() self._lock_acquire()
try: try:
...@@ -243,6 +204,9 @@ class BaseStorage(UndoLogCompatible): ...@@ -243,6 +204,9 @@ class BaseStorage(UndoLogCompatible):
finally: finally:
self._lock_release() self._lock_release()
def tpc_transaction(self):
return self._transaction
def _begin(self, tid, u, d, e): def _begin(self, tid, u, d, e):
"""Subclasses should redefine this to supply transaction start actions. """Subclasses should redefine this to supply transaction start actions.
""" """
...@@ -292,28 +256,17 @@ class BaseStorage(UndoLogCompatible): ...@@ -292,28 +256,17 @@ class BaseStorage(UndoLogCompatible):
""" """
pass pass
def undo(self, transaction_id, txn): def getTid(self, oid):
if self._is_read_only:
raise POSException.ReadOnlyError()
raise POSException.UndoError('non-undoable transaction')
def undoLog(self, first, last, filter=None):
return ()
def versionEmpty(self, version):
return 1
def versions(self, max=None):
return ()
def pack(self, t, referencesf):
if self._is_read_only:
raise POSException.ReadOnlyError()
def getSerial(self, oid):
self._lock_acquire() self._lock_acquire()
try: try:
v = self.modifiedInVersion(oid) v = ''
try:
supportsVersions = self.supportsVersions
except AttributeError:
pass
else:
if supportsVersions():
v = self.modifiedInVersion(oid)
pickledata, serial = self.load(oid, v) pickledata, serial = self.load(oid, v)
return serial return serial
finally: finally:
...@@ -325,57 +278,7 @@ class BaseStorage(UndoLogCompatible): ...@@ -325,57 +278,7 @@ class BaseStorage(UndoLogCompatible):
def loadBefore(self, oid, tid): def loadBefore(self, oid, tid):
"""Return most recent revision of oid before tid committed.""" """Return most recent revision of oid before tid committed."""
return None
# Unsure: Is it okay for loadBefore() to return current data?
# There doesn't seem to be a good reason to forbid it, even
# though the typical use of this method will never find
# current data. But maybe we should call it loadByTid()?
n = 2
start_time = None
end_time = None
while start_time is None:
# The history() approach is a hack, because the dict
# returned by history() doesn't contain a tid. It
# contains a serialno, which is often the same, but isn't
# required to be. We'll pretend it is for now.
# A second problem is that history() doesn't say anything
# about whether the transaction status. If it falls before
# the pack time, we can't honor the MVCC request.
# Note: history() returns the most recent record first.
# TODO: The filter argument to history() only appears to be
# supported by FileStorage. Perhaps it shouldn't be used.
L = self.history(oid, "", n, lambda d: not d["version"])
if not L:
return
for d in L:
if d["serial"] < tid:
start_time = d["serial"]
break
else:
end_time = d["serial"]
if len(L) < n:
break
n *= 2
if start_time is None:
return None
data = self.loadSerial(oid, start_time)
return data, start_time, end_time
def getExtensionMethods(self):
"""getExtensionMethods
This returns a dictionary whose keys are names of extra methods
provided by this storage. Storage proxies (such as ZEO) should
call this method to determine the extra methods that they need
to proxy in addition to the standard storage methods.
Dictionary values should be None; this will be a handy place
for extra marshalling information, should we need it
"""
return {}
def copyTransactionsFrom(self, other, verbose=0): def copyTransactionsFrom(self, other, verbose=0):
"""Copy transactions from another storage. """Copy transactions from another storage.
...@@ -383,61 +286,69 @@ class BaseStorage(UndoLogCompatible): ...@@ -383,61 +286,69 @@ class BaseStorage(UndoLogCompatible):
This is typically used for converting data from one storage to This is typically used for converting data from one storage to
another. `other` must have an .iterator() method. another. `other` must have an .iterator() method.
""" """
_ts=None copy(other, self, verbose)
ok=1
preindex={}; def copy(source, dest, verbose=0):
preget=preindex.get # waaaa """Copy transactions from a source to a destination storage
# restore() is a new storage API method which has an identical
# signature to store() except that it does not return anything. This is typically used for converting data from one storage to
# Semantically, restore() is also identical to store() except that it another. `source` must have an .iterator() method.
# doesn't do the ConflictError or VersionLockError consistency """
# checks. The reason to use restore() over store() in this method is _ts = None
# that store() cannot be used to copy transactions spanning a version ok = 1
# commit or abort, or over transactional undos. preindex = {};
# preget = preindex.get
# We'll use restore() if it's available, otherwise we'll fall back to # restore() is a new storage API method which has an identical
# using store(). However, if we use store, then # signature to store() except that it does not return anything.
# copyTransactionsFrom() may fail with VersionLockError or # Semantically, restore() is also identical to store() except that it
# ConflictError. # doesn't do the ConflictError or VersionLockError consistency
restoring = hasattr(self, 'restore') # checks. The reason to use restore() over store() in this method is
fiter = other.iterator() # that store() cannot be used to copy transactions spanning a version
for transaction in fiter: # commit or abort, or over transactional undos.
tid=transaction.tid #
if _ts is None: # We'll use restore() if it's available, otherwise we'll fall back to
_ts=TimeStamp(tid) # using store(). However, if we use store, then
# copyTransactionsFrom() may fail with VersionLockError or
# ConflictError.
restoring = hasattr(dest, 'restore')
fiter = source.iterator()
for transaction in fiter:
tid = transaction.tid
if _ts is None:
_ts = TimeStamp(tid)
else:
t = TimeStamp(tid)
if t <= _ts:
if ok: print ('Time stamps out of order %s, %s' % (_ts, t))
ok = 0
_ts = t.laterThan(_ts)
tid = `_ts`
else: else:
t=TimeStamp(tid) _ts = t
if t <= _ts: if not ok:
if ok: print ('Time stamps out of order %s, %s' % (_ts, t)) print ('Time stamps back in order %s' % (t))
ok=0 ok = 1
_ts=t.laterThan(_ts)
tid=`_ts`
else:
_ts = t
if not ok:
print ('Time stamps back in order %s' % (t))
ok=1
if verbose:
print _ts
dest.tpc_begin(transaction, tid, transaction.status)
for r in transaction:
oid = r.oid
if verbose: if verbose:
print _ts print oid_repr(oid), r.version, len(r.data)
if restoring:
self.tpc_begin(transaction, tid, transaction.status) dest.restore(oid, r.tid, r.data, r.version,
for r in transaction: r.data_txn, transaction)
oid=r.oid else:
if verbose: pre = preget(oid, None)
print oid_repr(oid), r.version, len(r.data) s = dest.store(oid, pre, r.data, r.version, transaction)
if restoring: preindex[oid] = s
self.restore(oid, r.tid, r.data, r.version,
r.data_txn, transaction) dest.tpc_vote(transaction)
else: dest.tpc_finish(transaction)
pre=preget(oid, None)
s=self.store(oid, pre, r.data, r.version, transaction) fiter.close()
preindex[oid]=s
self.tpc_vote(transaction)
self.tpc_finish(transaction)
fiter.close()
class TransactionRecord: class TransactionRecord:
"""Abstract base class for iterator protocol""" """Abstract base class for iterator protocol"""
......
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