Commit 46c18cc8 authored by Jérome Perrin's avatar Jérome Perrin

junk

parent 31e7acde
from contextlib import closing from contextlib import closing
from ZODB.FileStorage import FileStorage from ZODB.FileStorage import FileStorage
from ZODB import DB, TimeStamp from ZODB import DB, TimeStamp
from ZODB._compat import Unpickler
import io
import persistent import persistent
import time import time
import transaction import transaction
...@@ -11,11 +13,21 @@ import logging ...@@ -11,11 +13,21 @@ import logging
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
class P(persistent.Persistent): class P(persistent.Persistent):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
def unpickle(data):
f = io.BytesIO(data)
up = Unpickler(f)
klass = up.load()
if klass is P:
return up.load()['value']
return None
def faketime(): def faketime():
# fake time to have a reproductible database # fake time to have a reproductible database
_xtime0 = time.mktime(time.strptime("04 Jan 1979", "%d %b %Y")) _xtime0 = time.mktime(time.strptime("04 Jan 1979", "%d %b %Y"))
...@@ -32,9 +44,10 @@ def faketime(): ...@@ -32,9 +44,10 @@ def faketime():
return _xtime return _xtime
time.time = xtime time.time = xtime
faketime()
def change_object(value): def change_object_value(value):
with closing(FileStorage(filename)) as stor, closing(DB(stor)) as db, closing( with closing(FileStorage(filename)) as stor, closing(DB(stor)) as db, closing(
db.open() db.open()
) as conn: ) as conn:
...@@ -44,6 +57,25 @@ def change_object(value): ...@@ -44,6 +57,25 @@ def change_object(value):
transaction.commit() transaction.commit()
def undo_transactions(expected_descriptions):
with closing(FileStorage(filename)) as stor, closing(DB(stor)) as db, closing(
db.open()
) as conn:
undo_log = db.undoInfo(0, len(expected_descriptions))
assert [u["description"] for u in undo_log] == expected_descriptions
transaction.get().note("undo %s" % " ".join(expected_descriptions))
db.undoMultiple([u["id"] for u in undo_log])
transaction.commit()
def assert_object_value(value):
with closing(FileStorage(filename)) as stor, closing(DB(stor)) as db, closing(
db.open()
) as conn:
assert obj.value == value, f"{obj.value} != {value}"
filename = "repro_initial.fs" filename = "repro_initial.fs"
filename_copy = "repro_copy.fs" filename_copy = "repro_copy.fs"
...@@ -52,87 +84,42 @@ with closing(FileStorage(filename, create=True)) as stor, closing( ...@@ -52,87 +84,42 @@ with closing(FileStorage(filename, create=True)) as stor, closing(
DB(stor) DB(stor)
) as db, closing(db.open()) as conn: ) as db, closing(db.open()) as conn:
root = conn.root() root = conn.root()
obj = P("__version_0__") obj = P("version 0")
root["obj"] = obj root["obj"] = obj
transaction.get().note("version 0") transaction.get().note("version 0")
transaction.commit() transaction.commit()
# make a first version of object change_object_value("version 1")
with closing(FileStorage(filename)) as stor, closing(DB(stor)) as db, closing( change_object_value("version 2")
db.open() undo_transactions(["version 2", "version 1"])
) as conn:
transaction.get().note("version 1")
obj = conn.root()["obj"]
obj.value = "__version_1__"
transaction.commit()
# make a second version of object
with closing(FileStorage(filename)) as stor, closing(DB(stor)) as db, closing(
db.open()
) as conn:
transaction.get().note("version 2")
obj = conn.root()["obj"]
obj.value = "__version_2__"
transaction.commit()
# undo these two changes ( go back to __version_0__)
with closing(FileStorage(filename)) as stor, closing(DB(stor)) as db, closing(
db.open()
) as conn:
undo_log = db.undoInfo(0, 2)
assert [u["description"] for u in undo_log] == ["version 2", "version 1"]
transaction.get().note("undo 2 and 1 (back to 0)")
db.undoMultiple([u["id"] for u in undo_log])
transaction.commit()
# make a third version of object
with closing(FileStorage(filename)) as stor, closing(DB(stor)) as db, closing(
db.open()
) as conn:
transaction.get().note("version 3")
obj = conn.root()["obj"]
assert obj.value == "__version_0__", obj.value # check undo was effective
obj.value = "__version_3__"
transaction.commit()
# undo version 3 ( go back to __version_0__)
with closing(FileStorage(filename)) as stor, closing(DB(stor)) as db, closing(
db.open()
) as conn:
undo_log = db.undoInfo(0, 1)
assert [u["description"] for u in undo_log] == [
"version 3",
]
transaction.get().note("undo 2 and 1 (back to 0)")
db.undoMultiple([u["id"] for u in undo_log])
transaction.commit()
change_object_value("version 3")
undo_transactions(["version 3"])
assert_object_value("version 0")
# check the state is OK
with closing(FileStorage(filename)) as stor, closing(DB(stor)) as db, closing(
db.open()
) as conn:
obj = conn.root()["obj"]
assert obj.value == "__version_0__", obj.value
# copy this to a new storage # copy all this to a new storage
with closing(FileStorage(filename)) as stor, closing( with closing(FileStorage(filename)) as stor, closing(
FileStorage(filename_copy, create=True) FileStorage(filename_copy, create=True)
) as stor_copy: ) as stor_copy:
stor_copy.copyTransactionsFrom(stor) stor_copy.copyTransactionsFrom(stor)
# dump for debugging
from ZODB.FileStorage.fsdump import Dumper
print("dump for original: ", filename)
Dumper(filename).dump()
print()
print("dump after copy: ", filename)
Dumper(filename_copy).dump()
# assert to show the error
with closing(FileStorage(filename_copy)) as stor, closing(DB(stor)) as db, closing( with closing(FileStorage(filename_copy)) as stor, closing(DB(stor)) as db, closing(
db.open() db.open()
) as conn: ) as conn:
obj = conn.root()["obj"] obj = conn.root()["obj"]
# AssertionError: __version_1__ # AssertionError: __version_1__
assert obj.value == "__version_0__", obj.value assert obj.value == "version 0", obj.value
...@@ -93,11 +93,10 @@ def zodbcommit(stor, at, txn): ...@@ -93,11 +93,10 @@ def zodbcommit(stor, at, txn):
copy_from = obj.copy_from copy_from = obj.copy_from
if hasattr(obj, 'data'): if hasattr(obj, 'data'):
data = obj.data data = obj.data
if ashex(txn.tid) == '03a6166ee64176bb' and ashex(obj.oid) == '0000000000083b45': #if ashex(txn.tid) == '03a6166ee64176bb' and ashex(obj.oid) == '0000000000083b45':
print("%s %s => %s" % (readable_tid_repr(txn.tid), ashex(obj.oid), ashex(sha1(obj.data)))) # print("%s %s => %s" % (readable_tid_repr(txn.tid), ashex(obj.oid), ashex(sha1(obj.data))))
import pdb; pdb.set_trace() # #import pdb; pdb.set_trace()
else: else:
boom
try: try:
xdata = stor.loadBefore(obj.oid, p64(u64(obj.copy_from)+1)) xdata = stor.loadBefore(obj.oid, p64(u64(obj.copy_from)+1))
except POSKeyError: except POSKeyError:
......
...@@ -108,8 +108,8 @@ def zodbdump(stor, tidmin, tidmax, hashonly=False, pretty='raw', out=asbinstream ...@@ -108,8 +108,8 @@ def zodbdump(stor, tidmin, tidmax, hashonly=False, pretty='raw', out=asbinstream
for txn in stor.iterator(tidmin, tidmax): for txn in stor.iterator(tidmin, tidmax):
# XXX .status not covered by IStorageTransactionInformation # XXX .status not covered by IStorageTransactionInformation
# XXX but covered by BaseStorage.TransactionRecord # XXX but covered by BaseStorage.TransactionRecord
if '0000000000083b45' not in [ashex(o.oid) for o in txn]: #if '0000000000083b45' not in [ashex(o.oid) for o in txn]:
continue # continue
out.write(b"txn %s %s\nuser %s\ndescription %s\n" % ( out.write(b"txn %s %s\nuser %s\ndescription %s\n" % (
ashex(txn.tid), qq(txn.status), ashex(txn.tid), qq(txn.status),
...@@ -139,8 +139,8 @@ def zodbdump(stor, tidmin, tidmax, hashonly=False, pretty='raw', out=asbinstream ...@@ -139,8 +139,8 @@ def zodbdump(stor, tidmin, tidmax, hashonly=False, pretty='raw', out=asbinstream
for obj in objv: for obj in objv:
entry = b"obj %s " % ashex(obj.oid) entry = b"obj %s " % ashex(obj.oid)
if b'0000000000083b45' not in entry: #if b'0000000000083b45' not in entry:
continue # continue
write_data = False write_data = False
......
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