Commit 7cf6f802 authored by Jeremy Hylton's avatar Jeremy Hylton

Finish synchronizing FileStorage and POSException between ZODB3 and ZODB4.

There are few differences between the two files, except for necessary
differences because of API changes.  This change involves backporting
the new UndoError style from ZODB4.
parent 899c8260
...@@ -92,7 +92,7 @@ def tryToResolveConflict(self, oid, committedSerial, oldSerial, newpickle, ...@@ -92,7 +92,7 @@ def tryToResolveConflict(self, oid, committedSerial, oldSerial, newpickle,
unpickler.persistent_load = prfactory.persistent_load unpickler.persistent_load = prfactory.persistent_load
class_tuple = unpickler.load()[0] class_tuple = unpickler.load()[0]
if bad_class(class_tuple): if bad_class(class_tuple):
return 0 return None
newstate = unpickler.load() newstate = unpickler.load()
klass = load_class(class_tuple) klass = load_class(class_tuple)
inst = klass.__basicnew__() inst = klass.__basicnew__()
...@@ -101,7 +101,7 @@ def tryToResolveConflict(self, oid, committedSerial, oldSerial, newpickle, ...@@ -101,7 +101,7 @@ def tryToResolveConflict(self, oid, committedSerial, oldSerial, newpickle,
resolve = inst._p_resolveConflict resolve = inst._p_resolveConflict
except AttributeError: except AttributeError:
bad_classes[class_tuple] = 1 bad_classes[class_tuple] = 1
return 0 return None
old = state(self, oid, oldSerial, prfactory) old = state(self, oid, oldSerial, prfactory)
committed = state(self, oid, committedSerial, prfactory, committedData) committed = state(self, oid, committedSerial, prfactory, committedData)
...@@ -115,7 +115,7 @@ def tryToResolveConflict(self, oid, committedSerial, oldSerial, newpickle, ...@@ -115,7 +115,7 @@ def tryToResolveConflict(self, oid, committedSerial, oldSerial, newpickle,
pickler.dump(resolved) pickler.dump(resolved)
return file.getvalue(1) return file.getvalue(1)
except ConflictError: except ConflictError:
return 0 return None
except: except:
# If anything else went wrong, catch it here and avoid passing an # If anything else went wrong, catch it here and avoid passing an
# arbitrary exception back to the client. The error here will mask # arbitrary exception back to the client. The error here will mask
...@@ -124,7 +124,7 @@ def tryToResolveConflict(self, oid, committedSerial, oldSerial, newpickle, ...@@ -124,7 +124,7 @@ def tryToResolveConflict(self, oid, committedSerial, oldSerial, newpickle,
# the error so that any problems can be fixed. # the error so that any problems can be fixed.
zLOG.LOG("Conflict Resolution", zLOG.ERROR, zLOG.LOG("Conflict Resolution", zLOG.ERROR,
"Unexpected error", error=sys.exc_info()) "Unexpected error", error=sys.exc_info())
return 0 return None
class ConflictResolvingStorage: class ConflictResolvingStorage:
"Mix-in class that provides conflict resolution handling for storages" "Mix-in class that provides conflict resolution handling for storages"
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
############################################################################## ##############################################################################
"""Database connection support """Database connection support
$Id: Connection.py,v 1.79 2002/11/18 23:17:40 jeremy Exp $""" $Id: Connection.py,v 1.80 2002/12/03 18:36:29 jeremy Exp $"""
from cPickleCache import PickleCache from cPickleCache import PickleCache
from POSException import ConflictError, ReadConflictError from POSException import ConflictError, ReadConflictError
...@@ -40,7 +40,7 @@ def updateCodeTimestamp(): ...@@ -40,7 +40,7 @@ def updateCodeTimestamp():
global global_code_timestamp global global_code_timestamp
global_code_timestamp = time() global_code_timestamp = time()
ExtensionKlass=Base.__class__ ExtensionKlass = Base.__class__
class Connection(ExportImport.ExportImport): class Connection(ExportImport.ExportImport):
"""Object managers for individual object space. """Object managers for individual object space.
......
...@@ -115,7 +115,7 @@ ...@@ -115,7 +115,7 @@
# may have a back pointer to a version record or to a non-version # may have a back pointer to a version record or to a non-version
# record. # record.
# #
__version__='$Revision: 1.118 $'[11:-2] __version__='$Revision: 1.119 $'[11:-2]
import base64 import base64
from cPickle import Pickler, Unpickler, loads from cPickle import Pickler, Unpickler, loads
...@@ -133,10 +133,10 @@ except: ...@@ -133,10 +133,10 @@ except:
fsync = None fsync = None
from ZODB import BaseStorage, ConflictResolution, POSException from ZODB import BaseStorage, ConflictResolution, POSException
from ZODB.POSException import UndoError, POSKeyError from ZODB.POSException import UndoError, POSKeyError, MultipleUndoErrors
from ZODB.TimeStamp import TimeStamp from ZODB.TimeStamp import TimeStamp
from ZODB.lock_file import lock_file from ZODB.lock_file import lock_file
from ZODB.utils import t32, p64, U64, cp from ZODB.utils import p64, u64, cp, z64
try: try:
from ZODB.fsIndex import fsIndex from ZODB.fsIndex import fsIndex
...@@ -144,9 +144,9 @@ except ImportError: ...@@ -144,9 +144,9 @@ except ImportError:
def fsIndex(): def fsIndex():
return {} return {}
from zLOG import LOG, BLATHER, WARNING, ERROR, PANIC, register_subsystem from zLOG import LOG, BLATHER, WARNING, ERROR, PANIC
z64='\0'*8 t32 = 1L << 32
# the struct formats for the headers # the struct formats for the headers
TRANS_HDR = ">8s8scHHH" TRANS_HDR = ">8s8scHHH"
DATA_HDR = ">8s8s8s8sH8s" DATA_HDR = ">8s8s8s8sH8s"
...@@ -173,7 +173,7 @@ def nearPanic(message, *data): ...@@ -173,7 +173,7 @@ def nearPanic(message, *data):
def panic(message, *data): def panic(message, *data):
message = message % data message = message % data
LOG('ZODB FS', PANIC, "%s ERROR: %s\n" % (packed_version, message)) LOG('ZODB FS', PANIC, "%s ERROR: %s\n" % (packed_version, message))
raise CorruptedTransactionError, message raise CorruptedTransactionError(message)
class FileStorageError(POSException.StorageError): class FileStorageError(POSException.StorageError):
pass pass
...@@ -191,8 +191,11 @@ class CorruptedFileStorageError(FileStorageError, ...@@ -191,8 +191,11 @@ class CorruptedFileStorageError(FileStorageError,
POSException.StorageSystemError): POSException.StorageSystemError):
"""Corrupted file storage.""" """Corrupted file storage."""
class CorruptedTransactionError(CorruptedFileStorageError): pass class CorruptedTransactionError(CorruptedFileStorageError):
class CorruptedDataError(CorruptedFileStorageError): pass pass
class CorruptedDataError(CorruptedFileStorageError):
pass
class FileStorageQuotaError(FileStorageError, class FileStorageQuotaError(FileStorageError,
POSException.StorageSystemError): POSException.StorageSystemError):
...@@ -317,11 +320,10 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -317,11 +320,10 @@ class FileStorage(BaseStorage.BaseStorage,
return {}, {}, {}, {} return {}, {}, {}, {}
def _save_index(self): def _save_index(self):
"""Write the database index to a file to support quick startup """Write the database index to a file to support quick startup."""
"""
index_name=self.__name__+'.index' index_name = self.__name__ + '.index'
tmp_name=index_name+'.index_tmp' tmp_name = index_name + '.index_tmp'
f=open(tmp_name,'wb') f=open(tmp_name,'wb')
p=Pickler(f,1) p=Pickler(f,1)
...@@ -341,7 +343,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -341,7 +343,7 @@ class FileStorage(BaseStorage.BaseStorage,
except: pass except: pass
def _clear_index(self): def _clear_index(self):
index_name=self.__name__+'.index' index_name = self.__name__ + '.index'
if os.path.exists(index_name): if os.path.exists(index_name):
try: try:
os.remove(index_name) os.remove(index_name)
...@@ -368,7 +370,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -368,7 +370,7 @@ class FileStorage(BaseStorage.BaseStorage,
while 1: while 1:
seek(pos-8) seek(pos-8)
rstl=read(8) rstl=read(8)
tl=U64(rstl) tl=u64(rstl)
pos=pos-tl-8 pos=pos-tl-8
if pos < 4: return 0 if pos < 4: return 0
seek(pos) seek(pos)
...@@ -388,8 +390,8 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -388,8 +390,8 @@ class FileStorage(BaseStorage.BaseStorage,
seek(opos) seek(opos)
h=read(DATA_HDR_LEN) h=read(DATA_HDR_LEN)
oid,serial,sprev,stloc,vlen,splen = unpack(DATA_HDR, h) oid,serial,sprev,stloc,vlen,splen = unpack(DATA_HDR, h)
tloc=U64(stloc) tloc=u64(stloc)
plen=U64(splen) plen=u64(splen)
dlen=DATA_HDR_LEN+(plen or 8) dlen=DATA_HDR_LEN+(plen or 8)
if vlen: dlen=dlen+(16+vlen) if vlen: dlen=dlen+(16+vlen)
...@@ -507,7 +509,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -507,7 +509,7 @@ class FileStorage(BaseStorage.BaseStorage,
# non-version data record. # non-version data record.
# XXX This might be the only time that the serialno # XXX This might be the only time that the serialno
# of a data record does not match the transaction id. # of a data record does not match the transaction id.
self._file.seek(U64(pnv)) self._file.seek(u64(pnv))
h_pnv = self._file.read(DATA_VERSION_HDR_LEN) h_pnv = self._file.read(DATA_VERSION_HDR_LEN)
newserial = h_pnv[8:16] newserial = h_pnv[8:16]
...@@ -538,16 +540,16 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -538,16 +540,16 @@ class FileStorage(BaseStorage.BaseStorage,
tloc = h[24:32] tloc = h[24:32]
if t != tloc: if t != tloc:
# We haven't checked this transaction before, # We haven't checked this transaction before,
# get it's status. # get its status.
t = tloc t = tloc
self._file.seek(U64(t) + 16) self._file.seek(u64(t) + 16)
tstatus = self._file.read(1) tstatus = self._file.read(1)
if tstatus != 'u': if tstatus != 'u':
# Yee ha! We can quit # Yee ha! We can quit
break break
spos = h[-8:] spos = h[-8:]
srcpos = U64(spos) srcpos = u64(spos)
return oids return oids
def getSize(self): return self._pos def getSize(self): return self._pos
...@@ -563,14 +565,14 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -563,14 +565,14 @@ class FileStorage(BaseStorage.BaseStorage,
h=read(DATA_HDR_LEN) h=read(DATA_HDR_LEN)
doid,serial,prev,tloc,vlen,plen = unpack(DATA_HDR, h) doid,serial,prev,tloc,vlen,plen = unpack(DATA_HDR, h)
if vlen: if vlen:
nv = read(8) != z64 assert read(8) != z64
file.seek(8,1) # Skip previous version record pointer read(8) # Skip previous version record pointer
version=read(vlen) version=read(vlen)
else: else:
version='' version=''
nv=0 nv=0
if plen != z64: return read(U64(plen)), version, nv if plen != z64: return read(u64(plen)), version, nv
return _loadBack(file, oid, read(8))[0], version, nv return _loadBack(file, oid, read(8))[0], version, nv
def _load(self, oid, version, _index, file): def _load(self, oid, version, _index, file):
...@@ -594,7 +596,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -594,7 +596,7 @@ class FileStorage(BaseStorage.BaseStorage,
# If we get here, then either this was not a version record, # If we get here, then either this was not a version record,
# or we've already read past the version data! # or we've already read past the version data!
if plen != z64: if plen != z64:
return read(U64(plen)), serial return read(u64(plen)), serial
pnv = read(8) pnv = read(8)
# We use the current serial, since that is the one that # We use the current serial, since that is the one that
# will get checked when we store. # will get checked when we store.
...@@ -621,10 +623,10 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -621,10 +623,10 @@ class FileStorage(BaseStorage.BaseStorage,
seek(pos) seek(pos)
h=read(DATA_HDR_LEN) h=read(DATA_HDR_LEN)
doid,dserial,prev,tloc,vlen,plen = unpack(DATA_HDR, h) doid,dserial,prev,tloc,vlen,plen = unpack(DATA_HDR, h)
if doid != oid: raise CorruptedDataError, h if doid != oid: raise CorruptedDataError(h)
if dserial == serial: break # Yeee ha! if dserial == serial: break # Yeee ha!
# Keep looking for serial # Keep looking for serial
pos=U64(prev) pos = u64(prev)
if not pos: if not pos:
raise POSKeyError(serial) raise POSKeyError(serial)
continue continue
...@@ -634,7 +636,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -634,7 +636,7 @@ class FileStorage(BaseStorage.BaseStorage,
read(8) # skip past version link read(8) # skip past version link
read(vlen) # skip version read(vlen) # skip version
if plen != z64: return read(U64(plen)) if plen != z64: return read(u64(plen))
# We got a backpointer, probably from a commit. # We got a backpointer, probably from a commit.
pnv=read(8) pnv=read(8)
...@@ -652,7 +654,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -652,7 +654,7 @@ class FileStorage(BaseStorage.BaseStorage,
file.seek(pos) file.seek(pos)
doid,serial,prev,tloc,vlen = unpack(">8s8s8s8sH", file.read(34)) doid,serial,prev,tloc,vlen = unpack(">8s8s8s8sH", file.read(34))
if doid != oid: if doid != oid:
raise CorruptedDataError, pos raise CorruptedDataError(pos)
if vlen: if vlen:
file.read(24) # skip plen, pnv, and pv file.read(24) # skip plen, pnv, and pv
return file.read(vlen) return file.read(vlen)
...@@ -673,7 +675,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -673,7 +675,7 @@ class FileStorage(BaseStorage.BaseStorage,
self._file.seek(old) self._file.seek(old)
h=self._file.read(DATA_HDR_LEN) h=self._file.read(DATA_HDR_LEN)
doid,oserial,sprev,stloc,vlen,splen = unpack(DATA_HDR, h) doid,oserial,sprev,stloc,vlen,splen = unpack(DATA_HDR, h)
if doid != oid: raise CorruptedDataError, h if doid != oid: raise CorruptedDataError(h)
if vlen: if vlen:
pnv=self._file.read(8) # non-version data pointer pnv=self._file.read(8) # non-version data pointer
self._file.read(8) # skip past version link self._file.read(8) # skip past version link
...@@ -683,8 +685,9 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -683,8 +685,9 @@ class FileStorage(BaseStorage.BaseStorage,
`oid`, locked_version) `oid`, locked_version)
if serial != oserial: if serial != oserial:
data=self.tryToResolveConflict(oid, oserial, serial, data) data = self.tryToResolveConflict(oid, oserial, serial,
if not data: data)
if data is None:
raise POSException.ConflictError(oid=oid, raise POSException.ConflictError(oid=oid,
serials=(oserial, serial)) serials=(oserial, serial))
else: else:
...@@ -733,12 +736,12 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -733,12 +736,12 @@ class FileStorage(BaseStorage.BaseStorage,
h = self._file.read(TRANS_HDR_LEN) h = self._file.read(TRANS_HDR_LEN)
tid, stl, status, ul, dl, el = struct.unpack(TRANS_HDR, h) tid, stl, status, ul, dl, el = struct.unpack(TRANS_HDR, h)
self._file.read(ul + dl + el) self._file.read(ul + dl + el)
tend = tpos + U64(stl) + 8 tend = tpos + u64(stl) + 8
pos = self._file.tell() pos = self._file.tell()
while pos < tend: while pos < tend:
h = self._file.read(DATA_HDR_LEN) h = self._file.read(DATA_HDR_LEN)
_oid, serial, sprev, stpos, vl, sdl = struct.unpack(DATA_HDR, h) _oid, serial, sprev, stpos, vl, sdl = struct.unpack(DATA_HDR, h)
dl = U64(sdl) dl = u64(sdl)
reclen = DATA_HDR_LEN + vl + dl reclen = DATA_HDR_LEN + vl + dl
if vl: if vl:
reclen += 16 reclen += 16
...@@ -841,7 +844,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -841,7 +844,7 @@ class FileStorage(BaseStorage.BaseStorage,
# If there is no previous record, there can't be a pnv. # If there is no previous record, there can't be a pnv.
if not prev: if not prev:
return None return None
pnv = None pnv = None
# Load the record pointed to be prev # Load the record pointed to be prev
...@@ -865,7 +868,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -865,7 +868,7 @@ class FileStorage(BaseStorage.BaseStorage,
self._file.seek(bp) self._file.seek(bp)
h2 = self._file.read(DATA_HDR_LEN) h2 = self._file.read(DATA_HDR_LEN)
doid2, x, y, z, vlen2, sdl = unpack(DATA_HDR, h2) doid2, x, y, z, vlen2, sdl = unpack(DATA_HDR, h2)
dl = U64(sdl) dl = u64(sdl)
if oid != doid2: if oid != doid2:
raise CorruptedDataError, h2 raise CorruptedDataError, h2
if vlen2 > 0: if vlen2 > 0:
...@@ -991,19 +994,20 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -991,19 +994,20 @@ class FileStorage(BaseStorage.BaseStorage,
file.seek(pos) file.seek(pos)
h=read(DATA_HDR_LEN) h=read(DATA_HDR_LEN)
roid,serial,sprev,stloc,vlen,splen = unpack(DATA_HDR, h) roid,serial,sprev,stloc,vlen,splen = unpack(DATA_HDR, h)
if roid != oid: raise UndoError('Invalid undo transaction id') if roid != oid:
raise UndoError(oid, 'Invalid undo transaction id')
if vlen: if vlen:
read(16) # skip nv pointer and version previous pointer read(16) # skip nv pointer and version previous pointer
version=read(vlen) version=read(vlen)
else: else:
version='' version=''
plen = U64(splen) plen = u64(splen)
if plen: if plen:
data = read(plen) data = read(plen)
else: else:
data='' data=''
pos=U64(read(8)) pos=u64(read(8))
if tpos: file.seek(tpos) # Restore temp file to end if tpos: file.seek(tpos) # Restore temp file to end
...@@ -1055,7 +1059,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1055,7 +1059,7 @@ class FileStorage(BaseStorage.BaseStorage,
oid, ipos, tpos) oid, ipos, tpos)
# Versions of undone record and current record *must* match! # Versions of undone record and current record *must* match!
if cver != version: if cver != version:
raise UndoError('Current and undone versions differ') raise UndoError(oid, 'Current and undone versions differ')
if cdataptr != pos: if cdataptr != pos:
# We aren't sure if we are talking about the same data # We aren't sure if we are talking about the same data
...@@ -1069,15 +1073,15 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1069,15 +1073,15 @@ class FileStorage(BaseStorage.BaseStorage,
_loadBackPOS(self._file, oid, p64(cdataptr)) _loadBackPOS(self._file, oid, p64(cdataptr))
): ):
if pre and not tpos: if pre and not tpos:
copy=0 # we'll try to do conflict resolution copy = 0 # we'll try to do conflict resolution
else: else:
# We bail if: # We bail if:
# - We don't have a previous record, which should # - We don't have a previous record, which should
# be impossible. # be impossible.
raise UndoError raise UndoError(oid, "no previous record")
except KeyError: except KeyError:
# LoadBack gave us a key error. Bail. # LoadBack gave us a key error. Bail.
raise UndoError raise UndoError(oid, "_loadBack() failed")
# Return the data that should be written in the undo record. # Return the data that should be written in the undo record.
if not pre: if not pre:
...@@ -1095,13 +1099,13 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1095,13 +1099,13 @@ class FileStorage(BaseStorage.BaseStorage,
bdata = _loadBack(self._file, oid, p64(pre))[0] bdata = _loadBack(self._file, oid, p64(pre))[0]
except KeyError: except KeyError:
# couldn't find oid; what's the real explanation for this? # couldn't find oid; what's the real explanation for this?
raise UndoError("_loadBack() failed for %s" % repr(oid)) raise UndoError(oid, "_loadBack() failed for %s")
data=self.tryToResolveConflict(oid, cserial, serial, bdata, cdata) data=self.tryToResolveConflict(oid, cserial, serial, bdata, cdata)
if data: if data:
return data, 0, version, snv, ipos return data, 0, version, snv, ipos
raise UndoError('Some data were modified by a later transaction') raise UndoError(oid, "Some data were modified by a later transaction")
# undoLog() returns a description dict that includes an id entry. # undoLog() returns a description dict that includes an id entry.
# The id is opaque to the client, but contains the transaction id. # The id is opaque to the client, but contains the transaction id.
...@@ -1170,7 +1174,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1170,7 +1174,7 @@ class FileStorage(BaseStorage.BaseStorage,
# XXX Why 39? Only because undoLog() uses it as a boundary. # XXX Why 39? Only because undoLog() uses it as a boundary.
while pos > 39: while pos > 39:
self._file.seek(pos - 8) self._file.seek(pos - 8)
pos = pos - U64(self._file.read(8)) - 8 pos = pos - u64(self._file.read(8)) - 8
self._file.seek(pos) self._file.seek(pos)
h = self._file.read(TRANS_HDR_LEN) h = self._file.read(TRANS_HDR_LEN)
_tid = h[:8] _tid = h[:8]
...@@ -1179,7 +1183,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1179,7 +1183,7 @@ class FileStorage(BaseStorage.BaseStorage,
status = h[16] # get the c in 8s8sc status = h[16] # get the c in 8s8sc
if status == 'p' or _tid < self._packt: if status == 'p' or _tid < self._packt:
break break
raise UndoError("Invalid transaction id") raise UndoError(None, "Invalid transaction id")
def _txn_undo_write(self, tpos): def _txn_undo_write(self, tpos):
# a helper function to write the data records for transactional undo # a helper function to write the data records for transactional undo
...@@ -1192,8 +1196,8 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1192,8 +1196,8 @@ class FileStorage(BaseStorage.BaseStorage,
if h[16] == 'u': if h[16] == 'u':
return return
if h[16] != ' ': if h[16] != ' ':
raise UndoError('non-undoable transaction') raise UndoError(None, 'non-undoable transaction')
tl = U64(h[8:16]) tl = u64(h[8:16])
ul, dl, el = struct.unpack(">HHH", h[17:TRANS_HDR_LEN]) ul, dl, el = struct.unpack(">HHH", h[17:TRANS_HDR_LEN])
tend = tpos + tl tend = tpos + tl
pos = tpos + (TRANS_HDR_LEN + ul + dl + el) pos = tpos + (TRANS_HDR_LEN + ul + dl + el)
...@@ -1207,8 +1211,8 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1207,8 +1211,8 @@ class FileStorage(BaseStorage.BaseStorage,
oid, serial, sprev, stloc, vlen, splen = struct.unpack(DATA_HDR, h) oid, serial, sprev, stloc, vlen, splen = struct.unpack(DATA_HDR, h)
if failed(oid): if failed(oid):
del failures[oid] # second chance! del failures[oid] # second chance!
plen = U64(splen) plen = u64(splen)
prev = U64(sprev) prev = u64(sprev)
if vlen: if vlen:
dlen = DATA_VERSION_HDR_LEN + vlen + (plen or 8) dlen = DATA_VERSION_HDR_LEN + vlen + (plen or 8)
self._file.seek(16, 1) self._file.seek(16, 1)
...@@ -1234,7 +1238,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1234,7 +1238,7 @@ class FileStorage(BaseStorage.BaseStorage,
self._tvindex[v] = here self._tvindex[v] = here
odlen = DATA_VERSION_HDR_LEN + len(v)+(plen or 8) odlen = DATA_VERSION_HDR_LEN + len(v)+(plen or 8)
else: else:
odlen = DATA_HDR_LEN+(plen or 8) odlen = DATA_HDR_LEN + (plen or 8)
if p: if p:
self._tfile.write(p) self._tfile.write(p)
...@@ -1245,10 +1249,10 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1245,10 +1249,10 @@ class FileStorage(BaseStorage.BaseStorage,
pos += dlen pos += dlen
if pos > tend: if pos > tend:
raise UndoError, 'non-undoable transaction' raise UndoError(None, "non-undoable transaction")
if failures: if failures:
raise UndoError(failures) raise MultipleUndoErrors(failures.items())
return tindex return tindex
...@@ -1277,15 +1281,15 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1277,15 +1281,15 @@ class FileStorage(BaseStorage.BaseStorage,
tloc=h[16:24] tloc=h[16:24]
if t != tloc: if t != tloc:
# We haven't checked this transaction before, # We haven't checked this transaction before,
# get it's status. # get its status.
t=tloc t=tloc
seek(U64(t)+16) seek(u64(t)+16)
tstatus=read(1) tstatus=read(1)
if tstatus != 'u': return 1 if tstatus != 'u': return 1
spos=h[-8:] spos=h[-8:]
srcpos=U64(spos) srcpos=u64(spos)
return 1 return 1
finally: self._lock_release() finally: self._lock_release()
...@@ -1317,7 +1321,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1317,7 +1321,7 @@ class FileStorage(BaseStorage.BaseStorage,
seek(pos) seek(pos)
h=read(DATA_HDR_LEN) h=read(DATA_HDR_LEN)
doid,serial,prev,tloc,vlen,plen = unpack(DATA_HDR, h) doid,serial,prev,tloc,vlen,plen = unpack(DATA_HDR, h)
prev=U64(prev) prev=u64(prev)
if vlen: if vlen:
read(16) read(16)
...@@ -1332,7 +1336,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1332,7 +1336,7 @@ class FileStorage(BaseStorage.BaseStorage,
version='' version=''
wantver=None wantver=None
seek(U64(tloc)) seek(u64(tloc))
h=read(TRANS_HDR_LEN) h=read(TRANS_HDR_LEN)
tid, stl, status, ul, dl, el = unpack(TRANS_HDR,h) tid, stl, status, ul, dl, el = unpack(TRANS_HDR,h)
user_name=read(ul) user_name=read(ul)
...@@ -1345,7 +1349,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1345,7 +1349,7 @@ class FileStorage(BaseStorage.BaseStorage,
d['description']=description d['description']=description
d['serial']=serial d['serial']=serial
d['version']=version d['version']=version
d['size']=U64(plen) d['size']=u64(plen)
if filter is None or filter(d): if filter is None or filter(d):
r.append(d) r.append(d)
...@@ -1357,7 +1361,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1357,7 +1361,7 @@ class FileStorage(BaseStorage.BaseStorage,
def _redundant_pack(self, file, pos): def _redundant_pack(self, file, pos):
assert pos > 8, pos assert pos > 8, pos
file.seek(pos - 8) file.seek(pos - 8)
p = U64(file.read(8)) p = u64(file.read(8))
file.seek(pos - p + 8) file.seek(pos - p + 8)
return file.read(1) not in ' u' return file.read(1) not in ' u'
...@@ -1499,7 +1503,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1499,7 +1503,7 @@ class FileStorage(BaseStorage.BaseStorage,
if status=='c': if status=='c':
# Oops. we found a checkpoint flag. # Oops. we found a checkpoint flag.
break break
tl=U64(stl) tl=u64(stl)
tpos=pos tpos=pos
tend=tpos+tl tend=tpos+tl
...@@ -1539,7 +1543,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1539,7 +1543,7 @@ class FileStorage(BaseStorage.BaseStorage,
h=read(DATA_HDR_LEN) h=read(DATA_HDR_LEN)
oid,serial,sprev,stloc,vlen,splen = unpack( oid,serial,sprev,stloc,vlen,splen = unpack(
DATA_HDR, h) DATA_HDR, h)
plen=U64(splen) plen=u64(splen)
dlen=DATA_HDR_LEN+(plen or 8) dlen=DATA_HDR_LEN+(plen or 8)
if vlen: if vlen:
...@@ -1550,7 +1554,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1550,7 +1554,7 @@ class FileStorage(BaseStorage.BaseStorage,
pos=pos+dlen pos=pos+dlen
continue continue
pnv=U64(read(8)) pnv=u64(read(8))
# skip position of previous version record # skip position of previous version record
seek(8,1) seek(8,1)
version=read(vlen) version=read(vlen)
...@@ -1613,7 +1617,7 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1613,7 +1617,7 @@ class FileStorage(BaseStorage.BaseStorage,
opos=opos+plen-8 opos=opos+plen-8
splen=p64(plen) splen=p64(plen)
else: else:
p=U64(p) p=u64(p)
if p < packpos: if p < packpos:
# We have a backpointer to a # We have a backpointer to a
# non-packed record. We have to be # non-packed record. We have to be
...@@ -1766,10 +1770,10 @@ class FileStorage(BaseStorage.BaseStorage, ...@@ -1766,10 +1770,10 @@ class FileStorage(BaseStorage.BaseStorage,
# first 8 bytes are oid, second 8 bytes are serialno # first 8 bytes are oid, second 8 bytes are serialno
h = self._file.read(16) h = self._file.read(16)
if len(h) < 16: if len(h) < 16:
raise CorruptedDataError, h raise CorruptedDataError(h)
if h[:8] != oid: if h[:8] != oid:
h = h + self._file.read(26) # get rest of header h = h + self._file.read(26) # get rest of header
raise CorruptedDataError, h raise CorruptedDataError(h)
return h[8:] return h[8:]
def shift_transactions_forward(index, vindex, tindex, file, pos, opos): def shift_transactions_forward(index, vindex, tindex, file, pos, opos):
...@@ -1809,7 +1813,7 @@ def shift_transactions_forward(index, vindex, tindex, file, pos, opos): ...@@ -1809,7 +1813,7 @@ def shift_transactions_forward(index, vindex, tindex, file, pos, opos):
if len(h) < TRANS_HDR_LEN: break if len(h) < TRANS_HDR_LEN: break
tid, stl, status, ul, dl, el = unpack(TRANS_HDR,h) tid, stl, status, ul, dl, el = unpack(TRANS_HDR,h)
if status=='c': break # Oops. we found a checkpoint flag. if status=='c': break # Oops. we found a checkpoint flag.
tl=U64(stl) tl=u64(stl)
tpos=pos tpos=pos
tend=tpos+tl tend=tpos+tl
...@@ -1834,12 +1838,12 @@ def shift_transactions_forward(index, vindex, tindex, file, pos, opos): ...@@ -1834,12 +1838,12 @@ def shift_transactions_forward(index, vindex, tindex, file, pos, opos):
seek(pos) seek(pos)
h=read(DATA_HDR_LEN) h=read(DATA_HDR_LEN)
oid,serial,sprev,stloc,vlen,splen = unpack(DATA_HDR, h) oid,serial,sprev,stloc,vlen,splen = unpack(DATA_HDR, h)
plen=U64(splen) plen=u64(splen)
dlen=DATA_HDR_LEN+(plen or 8) dlen=DATA_HDR_LEN+(plen or 8)
if vlen: if vlen:
dlen=dlen+(16+vlen) dlen=dlen+(16+vlen)
pnv=U64(read(8)) pnv=u64(read(8))
# skip position of previous version record # skip position of previous version record
seek(8,1) seek(8,1)
version=read(vlen) version=read(vlen)
...@@ -1851,7 +1855,7 @@ def shift_transactions_forward(index, vindex, tindex, file, pos, opos): ...@@ -1851,7 +1855,7 @@ def shift_transactions_forward(index, vindex, tindex, file, pos, opos):
if plen: p=read(plen) if plen: p=read(plen)
else: else:
p=read(8) p=read(8)
p=U64(p) p=u64(p)
if p >= p2: p=p-offset if p >= p2: p=p-offset
elif p >= p1: elif p >= p1:
# Ick, we're in trouble. Let's bail # Ick, we're in trouble. Let's bail
...@@ -1900,7 +1904,7 @@ def search_back(file, pos): ...@@ -1900,7 +1904,7 @@ def search_back(file, pos):
s=p=file.tell() s=p=file.tell()
while p > pos: while p > pos:
seek(p-8) seek(p-8)
l=U64(read(8)) l=u64(read(8))
if l <= 0: break if l <= 0: break
p=p-l-8 p=p-l-8
...@@ -1955,14 +1959,13 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8, ...@@ -1955,14 +1959,13 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8,
id in the data. The transaction id is the tid of the last id in the data. The transaction id is the tid of the last
transaction. transaction.
""" """
read = file.read read = file.read
seek = file.seek seek = file.seek
seek(0, 2) seek(0, 2)
file_size=file.tell() file_size=file.tell()
if file_size: if file_size:
if file_size < start: raise FileStorageFormatError, name if file_size < start: raise FileStorageFormatError, file.name
seek(0) seek(0)
if read(4) != packed_version: raise FileStorageFormatError, name if read(4) != packed_version: raise FileStorageFormatError, name
else: else:
...@@ -1993,7 +1996,7 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8, ...@@ -1993,7 +1996,7 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8,
warn("%s time-stamp reduction at %s", name, pos) warn("%s time-stamp reduction at %s", name, pos)
ltid=tid ltid=tid
tl=U64(stl) tl=u64(stl)
if pos+(tl+8) > file_size or status=='c': if pos+(tl+8) > file_size or status=='c':
# Hm, the data were truncated or the checkpoint flag wasn't # Hm, the data were truncated or the checkpoint flag wasn't
...@@ -2015,7 +2018,7 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8, ...@@ -2015,7 +2018,7 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8,
# Skip to the end and read what should be the transaction length # Skip to the end and read what should be the transaction length
# of the last transaction. # of the last transaction.
seek(-8, 2) seek(-8, 2)
rtl=U64(read(8)) rtl=u64(read(8))
# Now check to see if the redundant transaction length is # Now check to see if the redundant transaction length is
# reasonable: # reasonable:
if file_size - rtl < pos or rtl < TRANS_HDR_LEN: if file_size - rtl < pos or rtl < TRANS_HDR_LEN:
...@@ -2054,9 +2057,9 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8, ...@@ -2054,9 +2057,9 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8,
seek(pos) seek(pos)
h=read(DATA_HDR_LEN) h=read(DATA_HDR_LEN)
oid,serial,sprev,stloc,vlen,splen = unpack(DATA_HDR, h) oid,serial,sprev,stloc,vlen,splen = unpack(DATA_HDR, h)
prev=U64(sprev) prev=u64(sprev)
tloc=U64(stloc) tloc=u64(stloc)
plen=U64(splen) plen=u64(splen)
dlen=DATA_HDR_LEN+(plen or 8) dlen=DATA_HDR_LEN+(plen or 8)
tindex[oid]=pos tindex[oid]=pos
...@@ -2106,7 +2109,7 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8, ...@@ -2106,7 +2109,7 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8,
def _loadBack_impl(file, oid, back): def _loadBack_impl(file, oid, back):
# shared implementation used by various _loadBack methods # shared implementation used by various _loadBack methods
while 1: while 1:
old = U64(back) old = u64(back)
if not old: if not old:
# If the backpointer is 0, the object does not currently exist. # If the backpointer is 0, the object does not currently exist.
raise POSKeyError(oid) raise POSKeyError(oid)
...@@ -2118,7 +2121,7 @@ def _loadBack_impl(file, oid, back): ...@@ -2118,7 +2121,7 @@ def _loadBack_impl(file, oid, back):
file.read(16) file.read(16)
version = file.read(vlen) version = file.read(vlen)
if plen != z64: if plen != z64:
return file.read(U64(plen)), serial, old, tloc return file.read(u64(plen)), serial, old, tloc
back = file.read(8) # We got a back pointer! back = file.read(8) # We got a back pointer!
def _loadBack(file, oid, back): def _loadBack(file, oid, back):
...@@ -2133,7 +2136,7 @@ def _loadBackPOS(file, oid, back): ...@@ -2133,7 +2136,7 @@ def _loadBackPOS(file, oid, back):
def _loadBackTxn(file, oid, back): def _loadBackTxn(file, oid, back):
"""Return data, serial, and txn id for backpointer.""" """Return data, serial, and txn id for backpointer."""
data, serial, old, stloc = _loadBack_impl(file, oid, back) data, serial, old, stloc = _loadBack_impl(file, oid, back)
tloc = U64(stloc) tloc = u64(stloc)
file.seek(tloc) file.seek(tloc)
h = file.read(TRANS_HDR_LEN) h = file.read(TRANS_HDR_LEN)
tid = h[:8] tid = h[:8]
...@@ -2141,11 +2144,11 @@ def _loadBackTxn(file, oid, back): ...@@ -2141,11 +2144,11 @@ def _loadBackTxn(file, oid, back):
def getTxnFromData(file, oid, back): def getTxnFromData(file, oid, back):
"""Return transaction id for data at back.""" """Return transaction id for data at back."""
file.seek(U64(back)) file.seek(u64(back))
h = file.read(DATA_HDR_LEN) h = file.read(DATA_HDR_LEN)
doid, serial, prev, stloc, vlen, plen = unpack(DATA_HDR, h) doid, serial, prev, stloc, vlen, plen = unpack(DATA_HDR, h)
assert oid == doid assert oid == doid
tloc = U64(stloc) tloc = u64(stloc)
file.seek(tloc) file.seek(tloc)
# seek to transaction header, where tid is first 8 bytes # seek to transaction header, where tid is first 8 bytes
return file.read(8) return file.read(8)
...@@ -2229,7 +2232,7 @@ class FileIterator(Iterator): ...@@ -2229,7 +2232,7 @@ class FileIterator(Iterator):
tid, stl = unpack(">8s8s", h) tid, stl = unpack(">8s8s", h)
if tid >= start: if tid >= start:
return return
tl = U64(stl) tl = u64(stl)
try: try:
self._pos += tl + 8 self._pos += tl + 8
except OverflowError: except OverflowError:
...@@ -2242,7 +2245,7 @@ class FileIterator(Iterator): ...@@ -2242,7 +2245,7 @@ class FileIterator(Iterator):
pos = self._file.tell() - 8 pos = self._file.tell() - 8
panic("%s has inconsistent transaction length at %s " panic("%s has inconsistent transaction length at %s "
"(%s != %s)", "(%s != %s)",
self._file.name, pos, U64(rtl), U64(stl)) self._file.name, pos, u64(rtl), u64(stl))
def next(self, index=0): def next(self, index=0):
if self._file is None: if self._file is None:
...@@ -2267,7 +2270,7 @@ class FileIterator(Iterator): ...@@ -2267,7 +2270,7 @@ class FileIterator(Iterator):
warn("%s time-stamp reduction at %s", self._file.name, pos) warn("%s time-stamp reduction at %s", self._file.name, pos)
self._ltid=tid self._ltid=tid
tl=U64(stl) tl=u64(stl)
if pos+(tl+8) > self._file_size or status=='c': if pos+(tl+8) > self._file_size or status=='c':
# Hm, the data were truncated or the checkpoint flag wasn't # Hm, the data were truncated or the checkpoint flag wasn't
...@@ -2288,7 +2291,7 @@ class FileIterator(Iterator): ...@@ -2288,7 +2291,7 @@ class FileIterator(Iterator):
# the end and read what should be the transaction # the end and read what should be the transaction
# length of the last transaction. # length of the last transaction.
seek(-8, 2) seek(-8, 2)
rtl=U64(read(8)) rtl=u64(read(8))
# Now check to see if the redundant transaction length is # Now check to see if the redundant transaction length is
# reasonable: # reasonable:
if self._file_size - rtl < pos or rtl < TRANS_HDR_LEN: if self._file_size - rtl < pos or rtl < TRANS_HDR_LEN:
...@@ -2346,8 +2349,8 @@ class FileIterator(Iterator): ...@@ -2346,8 +2349,8 @@ class FileIterator(Iterator):
raise IndexError, index raise IndexError, index
class RecordIterator(Iterator, BaseStorage.TransactionRecord): class RecordIterator(Iterator, BaseStorage.TransactionRecord):
"""Iterate over the transactions in a FileStorage file. """Iterate over the transactions in a FileStorage file."""
"""
def __init__(self, tid, status, user, desc, ext, pos, tend, file, tpos): def __init__(self, tid, status, user, desc, ext, pos, tend, file, tpos):
self.tid = tid self.tid = tid
self.status = status self.status = status
...@@ -2366,15 +2369,15 @@ class RecordIterator(Iterator, BaseStorage.TransactionRecord): ...@@ -2366,15 +2369,15 @@ class RecordIterator(Iterator, BaseStorage.TransactionRecord):
self._file.seek(pos) self._file.seek(pos)
h = self._file.read(DATA_HDR_LEN) h = self._file.read(DATA_HDR_LEN)
oid, serial, sprev, stloc, vlen, splen = unpack(DATA_HDR, h) oid, serial, sprev, stloc, vlen, splen = unpack(DATA_HDR, h)
prev = U64(sprev) prev = u64(sprev)
tloc = U64(stloc) tloc = u64(stloc)
plen = U64(splen) plen = u64(splen)
dlen = DATA_HDR_LEN + (plen or 8) dlen = DATA_HDR_LEN + (plen or 8)
if vlen: if vlen:
dlen += (16 + vlen) dlen += (16 + vlen)
tmp = self._file.read(16) tmp = self._file.read(16)
pv = U64(tmp[8:16]) pv = u64(tmp[8:16])
version = self._file.read(vlen) version = self._file.read(vlen)
else: else:
version = '' version = ''
...@@ -2447,7 +2450,7 @@ class UndoSearch: ...@@ -2447,7 +2450,7 @@ class UndoSearch:
def _readnext(self): def _readnext(self):
"""Read the next record from the storage.""" """Read the next record from the storage."""
self.file.seek(self.pos - 8) self.file.seek(self.pos - 8)
self.pos -= U64(self.file.read(8)) + 8 self.pos -= u64(self.file.read(8)) + 8
self.file.seek(self.pos) self.file.seek(self.pos)
h = self.file.read(TRANS_HDR_LEN) h = self.file.read(TRANS_HDR_LEN)
tid, tl, status, ul, dl, el = struct.unpack(TRANS_HDR, h) tid, tl, status, ul, dl, el = struct.unpack(TRANS_HDR, h)
......
...@@ -11,23 +11,28 @@ ...@@ -11,23 +11,28 @@
# FOR A PARTICULAR PURPOSE # FOR A PARTICULAR PURPOSE
# #
############################################################################## ##############################################################################
"""BoboPOS-defined exceptions """ZODB-defined exceptions
$Id: POSException.py,v 1.14 2002/09/05 10:19:40 htrd Exp $""" $Id: POSException.py,v 1.15 2002/12/03 18:36:29 jeremy Exp $"""
__version__ = '$Revision: 1.14 $'.split()[-2:][0]
from string import join
from types import StringType, DictType from types import StringType, DictType
from ZODB import utils import ZODB.utils
class POSError(Exception): def _fmt_oid(oid):
return "%016x" % ZODB.utils.u64(oid)
def _fmt_undo(oid, reason):
s = reason and (": %s" % reason) or ""
return "Undo error %s%s" % (_fmt_oid(oid), s)
class POSError(StandardError):
"""Persistent object system error.""" """Persistent object system error."""
class POSKeyError(KeyError, POSError): class POSKeyError(KeyError, POSError):
"""Key not found in database.""" """Key not found in database."""
def __str__(self): def __str__(self):
return "%016x" % utils.U64(self.args[0]) return _fmt_oid(self.args[0])
class TransactionError(POSError): class TransactionError(POSError):
"""An error occured due to normal transaction processing.""" """An error occured due to normal transaction processing."""
...@@ -78,12 +83,12 @@ class ConflictError(TransactionError): ...@@ -78,12 +83,12 @@ class ConflictError(TransactionError):
def __str__(self): def __str__(self):
extras = [] extras = []
if self.oid: if self.oid:
extras.append("oid %016x" % utils.U64(self.oid)) extras.append("oid %s" % _fmt_oid(self.oid))
if self.class_name: if self.class_name:
extras.append("class %s" % self.class_name) extras.append("class %s" % self.class_name)
if self.serials: if self.serials:
extras.append("serial was %016x, now %016x" % extras.append("serial was %s, now %s" %
tuple(map(utils.U64, self.serials))) tuple(map(_fmt_oid, self.serials)))
if extras: if extras:
return "%s (%s)" % (self.message, ", ".join(extras)) return "%s (%s)" % (self.message, ", ".join(extras))
else: else:
...@@ -104,27 +109,8 @@ class ConflictError(TransactionError): ...@@ -104,27 +109,8 @@ class ConflictError(TransactionError):
def get_serials(self): def get_serials(self):
return self.serials return self.serials
class DanglingReferenceError(TransactionError):
"""The transaction stored an object A containing a reference to another
object B, but B does not exist
Instance attributes:
Aoid: oid of the object being written
Boid: referenced oid that does not have a corresponding object
"""
def __init__(self,Aoid,Boid):
self.Aoid = Aoid
self.Boid = Boid
def __str__(self):
return "from %r to %r" % (self.Aoid,self.Boid)
class ReadConflictError(ConflictError): class ReadConflictError(ConflictError):
"""A conflict was detected at read time. """Conflict detected when object was loaded.
An attempt was made to read an object that has changed in another An attempt was made to read an object that has changed in another
transaction (eg. another thread or process). transaction (eg. another thread or process).
...@@ -144,6 +130,27 @@ class BTreesConflictError(ConflictError): ...@@ -144,6 +130,27 @@ class BTreesConflictError(ConflictError):
ConflictError.__init__(self, message="BTrees conflict error") ConflictError.__init__(self, message="BTrees conflict error")
self.btree = btree_args self.btree = btree_args
class DanglingReferenceError(TransactionError):
"""An object has a persistent reference to a missing object.
If an object is stored and it has a reference to another object
that does not exist (for example, it was deleted by pack), this
exception may be raised. Whether a storage supports this feature,
it a quality of implementation issue.
Instance attributes:
referer: oid of the object being written
missing: referenced oid that does not have a corresponding object
"""
def __init__(self, Aoid, Boid):
self.referer = Aoid
self.missing = Boid
def __str__(self):
return "from %s to %s" % (_fmt_oid(self.referer),
_fmt_oid(self.missing))
class VersionError(POSError): class VersionError(POSError):
"""An error in handling versions occurred.""" """An error in handling versions occurred."""
...@@ -159,26 +166,24 @@ class VersionLockError(VersionError, TransactionError): ...@@ -159,26 +166,24 @@ class VersionLockError(VersionError, TransactionError):
class UndoError(POSError): class UndoError(POSError):
"""An attempt was made to undo a non-undoable transaction.""" """An attempt was made to undo a non-undoable transaction."""
def __init__(self, *reason):
if len(reason) == 1: reason=reason[0] def __init__(self, oid, reason=None):
self.__reason=reason self._oid = oid
self._reason = reason
def __repr__(self):
reason=self.__reason def __str__(self):
if type(reason) is not DictType: return _fmt_undo(self._oid, self._reason)
if reason: return str(reason)
return "non-undoable transaction" class MultipleUndoErrors(UndoError):
r=[] """Several undo errors occured during a single transaction."""
for oid, reason in reason.items():
if reason: def __init__(self, errs):
r.append("Couldn't undo change to %s because %s" # provide an oid and reason for clients that only look at that
% (`oid`, reason)) UndoError.__init__(self, *errs[0])
else: self._errs = errs
r.append("Couldn't undo change to %s" % (`oid`))
def __str__(self):
return join(r,'\n') return "\n".join([_fmt_undo(*pair) for pair in self._errs])
__str__=__repr__
class StorageError(POSError): class StorageError(POSError):
"""Base class for storage based exceptions.""" """Base class for storage based exceptions."""
...@@ -201,9 +206,6 @@ class TransactionTooLargeError(StorageTransactionError): ...@@ -201,9 +206,6 @@ class TransactionTooLargeError(StorageTransactionError):
class ExportError(POSError): class ExportError(POSError):
"""An export file doesn't have the right format.""" """An export file doesn't have the right format."""
class Unimplemented(POSError):
"""An unimplemented feature was used."""
class Unsupported(POSError): class Unsupported(POSError):
"""An feature that is unsupported bt the storage was used.""" """An feature that is unsupported bt the storage was used."""
......
...@@ -17,6 +17,8 @@ import TimeStamp, time ...@@ -17,6 +17,8 @@ import TimeStamp, time
from struct import pack, unpack from struct import pack, unpack
z64 = '\0'*8
if sys.version >= (2, 2): if sys.version >= (2, 2):
# Note that the distinction between ints and longs is blurred in # Note that the distinction between ints and longs is blurred in
......
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