From fa00c2831fb43e3f1fe37d27eebd7e9a6176ad40 Mon Sep 17 00:00:00 2001 From: Kirill Smelkov Date: Tue, 16 Mar 2021 08:15:02 +0300 Subject: [PATCH] zodbcommit: Robustify copy handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When zodbdump input says to copy an object, we first load that object. However if object does not exist loadBefore raises POSKeyError, and when object at copied-from revision was deleted loadBefore returns None. -> Handle that explicitly to provide failure details to the user, so that instead of cryptic === RUN TestLoad/δstart=0285cbac75555580 Traceback (most recent call last): File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main "__main__", fname, loader, pkg_name) File "/usr/lib/python2.7/runpy.py", line 72, in _run_code exec code in run_globals File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 133, in main() File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 129, in main return command_module.main(argv) File "", line 2, in main File "/home/kirr/src/tools/go/pygolang/golang/__init__.py", line 103, in _ return f(*argv, **kw) File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 94, in main zodbrestore(stor, asbinstream(sys.stdin), _) File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 43, in zodbrestore zodbcommit(stor, at, txn) File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 122, in zodbcommit _() File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 91, in _ data, _, _ = stor.loadBefore(obj.oid, p64(u64(obj.copy_from)+1)) TypeError: 'NoneType' object is not iterable xtesting.go:483: /tmp/demo009767458/δ0285cbac75555580/δ.fs: zpyrestore: exit status 1 it fails with something more understandable: === RUN TestLoad/δstart=0285cbac75555580 Traceback (most recent call last): File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main "__main__", fname, loader, pkg_name) File "/usr/lib/python2.7/runpy.py", line 72, in _run_code exec code in run_globals File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 133, in main() File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 129, in main return command_module.main(argv) File "", line 2, in main File "/home/kirr/src/tools/go/pygolang/golang/__init__.py", line 103, in _ return f(*argv, **kw) File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 94, in main zodbrestore(stor, asbinstream(sys.stdin), _) File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 43, in zodbrestore zodbcommit(stor, at, txn) File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 129, in zodbcommit _() File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 97, in _ (stor.getName(), ashex(obj.oid), ashex(obj.copy_from))) ValueError: /tmp/demo358030847/δ0285cbac75555580/δ.fs: object 0000000000000003: copy from @0285cbac70a3d733: no data xtesting.go:483: /tmp/demo358030847/δ0285cbac75555580/δ.fs: zpyrestore: exit status 1 For the implementation it would be easier to use loadAt (https://github.com/zopefoundation/ZODB/pull/323), but we don't have that yet. /reviewed-by @jerome /reviewed-on https://lab.nexedi.com/nexedi/zodbtools/merge_requests/20 --- zodbtools/zodbcommit.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/zodbtools/zodbcommit.py b/zodbtools/zodbcommit.py index a18ffe4..1c01425 100644 --- a/zodbtools/zodbcommit.py +++ b/zodbtools/zodbcommit.py @@ -88,7 +88,14 @@ def current_serial(oid): copy_from = None if isinstance(obj, zodbdump.ObjectCopy): copy_from = obj.copy_from - data, _, _ = stor.loadBefore(obj.oid, p64(u64(obj.copy_from)+1)) + try: + xdata = stor.loadBefore(obj.oid, p64(u64(obj.copy_from)+1)) + except POSKeyError: + xdata = None + if xdata is None: + raise ValueError("%s: object %s: copy from @%s: no data" % + (stor.getName(), ashex(obj.oid), ashex(obj.copy_from))) + data, _, _ = xdata elif isinstance(obj, zodbdump.ObjectDelete): data = None