Commit 3fa58ce7 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 cd426a86
...@@ -22,6 +22,15 @@ New Features ...@@ -22,6 +22,15 @@ New Features
XXX There are known issues with this implementation that need to be XXX There are known issues with this implementation that need to be
sorted out before it is "released". 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) 3.9.0a10 (2009-01-05)
===================== =====================
......
...@@ -501,8 +501,18 @@ class FileStoragePacker(FileStorageFormatter): ...@@ -501,8 +501,18 @@ class FileStoragePacker(FileStorageFormatter):
if data and ZODB.blob.is_blob_record(data): if data and ZODB.blob.is_blob_record(data):
# We need to remove the blob record. Maybe we # We need to remove the blob record. Maybe we
# need to remove oid: # 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: 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: else:
self.blob_removed.write( self.blob_removed.write(
(h.oid+h.tid).encode('hex')+'\n') (h.oid+h.tid).encode('hex')+'\n')
......
...@@ -14,10 +14,12 @@ ...@@ -14,10 +14,12 @@
from zope.testing import doctest from zope.testing import doctest
import cPickle
import os import os
import time import time
import transaction import transaction
import unittest import unittest
import ZODB.blob
import ZODB.FileStorage import ZODB.FileStorage
import ZODB.tests.util import ZODB.tests.util
...@@ -85,10 +87,43 @@ The pack_keep_old constructor argument controls whether a .old file (and .old di ...@@ -85,10 +87,43 @@ The pack_keep_old constructor argument controls whether a .old file (and .old di
>>> os.path.exists('blobs.old') >>> os.path.exists('blobs.old')
False False
>>> db.close() >>> 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(): def test_suite():
return unittest.TestSuite(( 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