# Fixes a bug introduced in zope-2.6.1 in ZODB/FileStorage.py # Problem is that new files added in a version don't get committed when the # version is saved/committed. The version is emptied but the locks are still # around. Bad mojo. # # I'm going to submit a bug report on this to zope.org. I'll add the bug number # once its in their system. # Bug #817: http://collector.zope.org/Zope/817 from ZODB import FileStorage import struct from ZODB.utils import p64, U64 # constants copied from FileStorage z64='\0'*8 # the struct formats for the headers TRANS_HDR = ">8s8scHHH" DATA_HDR = ">8s8s8s8sH8s" # constants to support various header sizes TRANS_HDR_LEN = 23 DATA_HDR_LEN = 42 DATA_VERSION_HDR_LEN = 58 if 1: # keep indent level consistent with original code def _commitVersion(self, src, dest, transaction, abort=None): # call after checking arguments and acquiring lock srcpos = self._vindex_get(src, 0) spos = p64(srcpos) # middle holds bytes 16:34 of a data record: # pos of transaction, len of version name, data length # commit version never writes data, so data length is always 0 middle = struct.pack(">8sH8s", p64(self._pos), len(dest), z64) if dest: sd = p64(self._vindex_get(dest, 0)) heredelta = 66 + len(dest) else: sd = '' heredelta = 50 here = self._pos + (self._tfile.tell() + self._thl) oids = [] current_oids = {} t = None tstatus = ' ' if abort is None: newserial = self._serial while srcpos: self._file.seek(srcpos) h = self._file.read(DATA_VERSION_HDR_LEN) # h -> oid, serial, prev(oid), tloc, vlen, plen, pnv, pv oid = h[:8] pnv = h[-16:-8] if abort: # If we are aborting, the serialno in the new data # record should be the same as the serialno in the last # non-version data record. # XXX This might be the only time that the serialno # of a data record does not match the transaction id. self._file.seek(U64(pnv)) h_pnv = self._file.read(DATA_VERSION_HDR_LEN) newserial = h_pnv[8:16] if self._index.get(oid) == srcpos: # This is a current record! self._tindex[oid] = here oids.append(oid) self._tfile.write(oid + newserial + spos + middle) if dest: self._tvindex[dest] = here self._tfile.write(pnv + sd + dest) sd = p64(here) self._tfile.write(abort and pnv or spos) # data backpointer to src data here += heredelta current_oids[oid] = 1 # XXX jae - changed this # # Once we've found the data we are looking for, # # we can stop chasing backpointers. # break else: # Hm. This is a non-current record. Is there a # current record for this oid? if not current_oids.has_key(oid): # Nope. We're done *if* this transaction wasn't undone. tloc = h[24:32] if t != tloc: # We haven't checked this transaction before, # get it's status. t = tloc self._file.seek(U64(t) + 16) tstatus = self._file.read(1) if tstatus != 'u': # Yee ha! We can quit break spos = h[-8:] srcpos = U64(spos) return oids # apply hotfix from zLOG import LOG, INFO LOG('Hotfix', INFO, 'Applying %s.' % 'Version commit Fix (2.6.1)') FileStorage.FileStorage._commitVersion = _commitVersion