Commit 4c747b1b authored by Jim Fulton's avatar Jim Fulton

Fixed a serious bug:

  Packing a blob-enabled file storage in a ZEO server caused blob data
  to be lost.
parent 6dd1e1e1
......@@ -22,6 +22,15 @@ New Features
XXX There are known issues with this implementation that need to be
sorted out before it is "released".
3.9.0a11 (2009-02-17)
=====================
Bugs Fixed
----------
- Packing a blob-enabled file storage in a ZEO server caused blob data
to be lost.
3.9.0a10 (2009-01-05)
=====================
......
......@@ -501,8 +501,18 @@ class FileStoragePacker(FileStorageFormatter):
if data and ZODB.blob.is_blob_record(data):
# We need to remove the blob record. Maybe we
# need to remove oid:
# But first, we need to make sure the record
# we're looking at isn't a dup of the current
# record. There's a bug in ZEO blob support that causes
# duplicate data records.
rpos = self.gc.reachable.get(h.oid)
is_dup = (rpos
and self._read_data_header(rpos).tid == h.tid)
if not is_dup:
if h.oid not in self.gc.reachable:
self.blob_removed.write(h.oid.encode('hex')+'\n')
self.blob_removed.write(
h.oid.encode('hex')+'\n')
else:
self.blob_removed.write(
(h.oid+h.tid).encode('hex')+'\n')
......
......@@ -14,10 +14,12 @@
from zope.testing import doctest
import cPickle
import os
import time
import transaction
import unittest
import ZODB.blob
import ZODB.FileStorage
import ZODB.tests.util
......@@ -85,10 +87,43 @@ The pack_keep_old constructor argument controls whether a .old file (and .old di
>>> os.path.exists('blobs.old')
False
>>> db.close()
"""
def pack_with_repeated_blob_records():
"""
There is a bug in ZEO that causes duplicate bloc database records
to be written in a blob store operation. (Maybe this has been
fixed by the time you read this, but there might still be
transactions in the wild that have duplicate records.
>>> fs = ZODB.FileStorage.FileStorage('t', blob_dir='bobs')
>>> db = ZODB.DB(fs)
>>> conn = db.open()
>>> conn.root()[1] = ZODB.blob.Blob()
>>> transaction.commit()
>>> tm = transaction.TransactionManager()
>>> oid = conn.root()[1]._p_oid
>>> blob_record, oldserial = fs.load(oid)
Now, create a transaction with multiple saves:
>>> trans = tm.begin()
>>> fs.tpc_begin(trans)
>>> open('ablob', 'w').write('some data')
>>> _ = fs.store(oid, oldserial, blob_record, '', trans)
>>> _ = fs.storeBlob(oid, oldserial, blob_record, 'ablob', '', trans)
>>> fs.tpc_vote(trans)
>>> fs.tpc_finish(trans)
>>> time.sleep(.01)
>>> db.pack()
>>> conn.sync()
>>> conn.root()[1].open().read()
'some data'
>>> db.close()
"""
def test_suite():
return unittest.TestSuite((
......
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