Skip to content

Instantly share code, notes, and snippets.

@icemac

icemac/zodb_refmap.py

Forked from buchi/zodb_refmap.py
Last active Sep 29, 2020
Embed
What would you like to do?
ZODB: find oids of objects referencing a specific oid
"""
Usage
=====
First create a refmap of your ZODB:
>>> r = build_refmap('/path/to/Data.fs')
Now you can find out which objects reference an object you know the oid of:
>>> oid = '\x00\x00\x00\x00\x00uB\xf1'
>>> backrefs(oid, r)
['\x00\x00\x00\x00\x00uC\x1f']
To find out the object behind the gotten oid, get it from the ZODB:
>>> import ZODB
>>> db = ZODB.DB('/path/to/Data.fs', read_only=1)
>>> c = db.open()
>>> obj = c.get('\x00\x00\x00\x00\x00uC\x1f')
To load a pure pickle from the storage use:
>>> fs = FileStorage('/path/to/Data.fs', read_only=1)
>>> fs.load('\x00\x00\x00\x00\x00uC\x1f')
"""
from pprint import pprint
from ZODB.serialize import referencesf
from ZODB.FileStorage import FileStorage
def build_refmap(filename):
"""Build a refmap from a filestorage. Look in every record of every
transaction. Build a dict of oid -> list(referenced oids)
"""
refmap = {}
fs = FileStorage(filename, read_only=1)
fsi = fs.iterator()
for txn in fsi:
for rec in txn:
pickle, revid = fs.load(rec.oid, rec.version)
refs = referencesf(pickle)
refmap[rec.oid] = refs
return refmap
def backrefs(target, refmap):
"""Return a list of oids in the refmap who reference target.
"""
oidlist = []
for oid, refs in refmap.items():
if target in refs:
oidlist.append(oid)
return oidlist
def obj_path(target, refmap):
"""For a target oid find the path of objects that refer to it.
break if we reach no more references or find a cycle
"""
path = [target]
additionals = []
while True:
target = path[-1:].pop()
brefs = backrefs(target, refmap)
if not brefs:
break
bref = brefs[0]
if bref in path:
print('cyclic', bref)
break
if len(brefs) == 1:
path.append(bref)
print(bref)
continue
additionals.append((target, brefs[1:]))
print(bref, brefs[1:])
path.append(bref)
return (path, additionals)
known=[]
def step(refmap, conn, known, oid):
"""Step trough a database and keep track of the already seen oids."""
if oid in known:
print('cycle')
return
else:
known.append(oid)
brefs = backrefs(oid, refmap)
pprint(brefs)
pprint([conn.get(ref) for ref in brefs])
@dwt

This comment has been minimized.

Copy link

@dwt dwt commented May 15, 2020

This looks useful - can this be added to one of the zodbverify / zodbupgrade / zombi-whatever tools?

@icemac

This comment has been minimized.

Copy link
Owner Author

@icemac icemac commented Sep 23, 2020

@dwt zodbverify now has the ability to look at the references of an oid.

@dwt

This comment has been minimized.

Copy link

@dwt dwt commented Sep 23, 2020

@icemac: 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment