Enabled both pruning/non-pruning dbg reprs, -t/--tree and -R/--rbyd

Now that altns/altas are more important structurally, including them in
our dbg script's tree renderers is valuable for debugging. On the other
hand, they do add quite a bit of visual noise when looking at large
multi-rbyd trees topologically.

This commit gives us the best of both worlds by making both tree
renderings available under different options:

-t/--tree, a simplified rbyd tree renderer with altn/alta pruning:

          .->   0 reg w1 4
        .-+->     uattr 0x01 2
        | .->     uattr 0x02 2
    .---+-+->     uattr 0x03 2
    |     .->     uattr 0x04 2
    |   .-+->     uattr 0x05 2
    | .-+--->     uattr 0x06 2
  +-+-+-+-+->   1 reg w1 4
  |     | '->   2 reg w1 4
  |     '--->     uattr 0x01 2
  '---+-+-+->     uattr 0x02 2
      | | '->     uattr 0x03 2
      | '-+->     uattr 0x04 2
      |   '->     uattr 0x05 2
      |   .->     uattr 0x06 2
      | .-+->     uattr 0x07 2
      | | .->     uattr 0x08 2
      '-+-+->     uattr 0x09 2

-R/--rbyd, a full rbyd tree renderer:

            .--->   0 reg w1 4
        .---+-+->     uattr 0x01 2
        |   .--->     uattr 0x02 2
      .-+-+-+-+->     uattr 0x03 2
      |     .--->     uattr 0x04 2
      |   .-+-+->     uattr 0x05 2
      | .-+---+->     uattr 0x06 2
  +---+-+-+-+-+->   1 reg w1 4
  |       |   '->   2 reg w1 4
  |       '----->     uattr 0x01 2
  '-+-+-+-+-+-+->     uattr 0x02 2
    |   |   '--->     uattr 0x03 2
    |   '---+-+->     uattr 0x04 2
    |       '--->     uattr 0x05 2
    |       .--->     uattr 0x06 2
    |     .-+-+->     uattr 0x07 2
    |     |   .->     uattr 0x08 2
    '-----+---+->     uattr 0x09 2

And of course -B/--btree, a simplified B-tree renderer (more useful for
multi-rbyds):

  +->   0 reg w1 4
  |       uattr 0x01 2
  |       uattr 0x02 2
  |       uattr 0x03 2
  |       uattr 0x04 2
  |       uattr 0x05 2
  |       uattr 0x06 2
  |->   1 reg w1 4
  '->   2 reg w1 4
          uattr 0x01 2
          uattr 0x02 2
          uattr 0x03 2
          uattr 0x04 2
          uattr 0x05 2
          uattr 0x06 2
          uattr 0x07 2
          uattr 0x08 2
          uattr 0x09 2
This commit is contained in:
Christopher Haster
2024-03-31 02:52:56 -05:00
parent abe68c0844
commit 54a03cfe3b
5 changed files with 178 additions and 345 deletions
-274
View File
@@ -792,85 +792,6 @@ class Rbyd:
yield rid, tag, w, j, d, data yield rid, tag, w, j, d, data
# create tree representation for debugging
def tree(self):
trunks = co.defaultdict(lambda: (-1, 0))
alts = co.defaultdict(lambda: {})
rid, tag = -1, 0
while True:
done, rid, tag, w, j, d, data, path = self.lookup(rid, tag+0x1)
# found end of tree?
if done:
break
# keep track of trunks/alts
trunks[j] = (rid, tag)
for j_, j__, followed, c in path:
if followed:
alts[j_] |= {'f': j__, 'c': c}
else:
alts[j_] |= {'nf': j__, 'c': c}
# treat unreachable alts as converging paths
for j_, alt in alts.items():
if 'f' not in alt:
alt['f'] = alt['nf']
elif 'nf' not in alt:
alt['nf'] = alt['f']
# find the trunk and depth of each alt
def rec_trunk(j_):
if j_ not in alts:
return trunks[j_]
else:
if 'nft' not in alts[j_]:
alts[j_]['nft'] = rec_trunk(alts[j_]['nf'])
return alts[j_]['nft']
for j_ in alts.keys():
rec_trunk(j_)
for j_, alt in alts.items():
if alt['f'] in alts:
alt['ft'] = alts[alt['f']]['nft']
else:
alt['ft'] = trunks[alt['f']]
def rec_height(j_):
if j_ not in alts:
return 0
else:
if 'h' not in alts[j_]:
alts[j_]['h'] = max(
rec_height(alts[j_]['f']),
rec_height(alts[j_]['nf'])) + 1
return alts[j_]['h']
for j_ in alts.keys():
rec_height(j_)
t_depth = max((alt['h']+1 for alt in alts.values()), default=0)
# convert to more general tree representation
tree = set()
for j, alt in alts.items():
# note all non-trunk edges should be black
tree.add(TBranch(
a=alt['nft'],
b=alt['nft'],
d=t_depth-1 - alt['h'],
c=alt['c'],
))
tree.add(TBranch(
a=alt['nft'],
b=alt['ft'],
d=t_depth-1 - alt['h'],
c='b',
))
return tree, t_depth
# btree lookup with this rbyd as the root # btree lookup with this rbyd as the root
def btree_lookup(self, f, block_size, bid, *, def btree_lookup(self, f, block_size, bid, *,
depth=None): depth=None):
@@ -927,201 +848,6 @@ class Rbyd:
else: else:
return not tags, bid + (rid_-rid), w, rbyd, rid_, tags, path return not tags, bid + (rid_-rid), w, rbyd, rid_, tags, path
# btree rbyd-tree generation for debugging
def btree_tree(self, f, block_size, *,
depth=None,
inner=False):
# find the max depth of each layer to nicely align trees
bdepths = {}
bid = -1
while True:
done, bid, w, rbyd, rid, tags, path = self.btree_lookup(
f, block_size, bid+1, depth=depth)
if done:
break
for d, (bid, w, rbyd, rid, tags) in enumerate(path):
_, rdepth = rbyd.tree()
bdepths[d] = max(bdepths.get(d, 0), rdepth)
# find all branches
tree = set()
root = None
branches = {}
bid = -1
while True:
done, bid, w, rbyd, rid, tags, path = self.btree_lookup(
f, block_size, bid+1, depth=depth)
if done:
break
d_ = 0
leaf = None
for d, (bid, w, rbyd, rid, tags) in enumerate(path):
if not tags:
continue
# map rbyd tree into B-tree space
rtree, rdepth = rbyd.tree()
# note we adjust our bid/rids to be left-leaning,
# this allows a global order and make tree rendering quite
# a bit easier
rtree_ = set()
for branch in rtree:
a_rid, a_tag = branch.a
b_rid, b_tag = branch.b
_, _, _, a_w, _, _, _, _ = rbyd.lookup(a_rid, 0)
_, _, _, b_w, _, _, _, _ = rbyd.lookup(b_rid, 0)
rtree_.add(TBranch(
a=(a_rid-(a_w-1), a_tag),
b=(b_rid-(b_w-1), b_tag),
d=branch.d,
c=branch.c,
))
rtree = rtree_
# connect our branch to the rbyd's root
if leaf is not None:
root = min(rtree,
key=lambda branch: branch.d,
default=None)
if root is not None:
r_rid, r_tag = root.a
else:
r_rid, r_tag = rid-(w-1), tags[0][0]
tree.add(TBranch(
a=leaf,
b=(bid-rid+r_rid, d, r_rid, r_tag),
d=d_-1,
c='b',
))
for branch in rtree:
# map rbyd branches into our btree space
a_rid, a_tag = branch.a
b_rid, b_tag = branch.b
tree.add(TBranch(
a=(bid-rid+a_rid, d, a_rid, a_tag),
b=(bid-rid+b_rid, d, b_rid, b_tag),
d=branch.d + d_ + bdepths.get(d, 0)-rdepth,
c=branch.c,
))
d_ += max(bdepths.get(d, 0), 1)
leaf = (bid-(w-1), d, rid-(w-1),
next((tag for tag, _, _, _ in tags
if tag & 0xfff == TAG_BRANCH),
TAG_BRANCH))
# remap branches to leaves if we aren't showing inner branches
if not inner:
# step through each layer backwards
b_depth = max((branch.a[1]+1 for branch in tree), default=0)
# keep track of the original bids, unfortunately because we
# store the bids in the branches we overwrite these
tree = {(branch.b[0] - branch.b[2], branch) for branch in tree}
for bd in reversed(range(b_depth-1)):
# find leaf-roots at this level
roots = {}
for bid, branch in tree:
# choose the highest node as the root
if (branch.b[1] == b_depth-1
and (bid not in roots
or branch.d < roots[bid].d)):
roots[bid] = branch
# remap branches to leaf-roots
tree_ = set()
for bid, branch in tree:
if branch.a[1] == bd and branch.a[0] in roots:
branch = TBranch(
a=roots[branch.a[0]].b,
b=branch.b,
d=branch.d,
c=branch.c,
)
if branch.b[1] == bd and branch.b[0] in roots:
branch = TBranch(
a=branch.a,
b=roots[branch.b[0]].b,
d=branch.d,
c=branch.c,
)
tree_.add((bid, branch))
tree = tree_
# strip out bids
tree = {branch for _, branch in tree}
return tree, max((branch.d+1 for branch in tree), default=0)
# btree B-tree generation for debugging
def btree_btree(self, f, block_size, *,
depth=None,
inner=False):
# find all branches
tree = set()
root = None
branches = {}
bid = -1
while True:
done, bid, w, rbyd, rid, tags, path = self.btree_lookup(
f, block_size, bid+1, depth=depth)
if done:
break
# if we're not showing inner nodes, prefer names higher in
# the tree since this avoids showing vestigial names
name = None
if not inner:
name = None
for bid_, w_, rbyd_, rid_, tags_ in reversed(path):
for tag_, j_, d_, data_ in tags_:
if tag_ & 0x7f00 == TAG_NAME:
name = (tag_, j_, d_, data_)
if rid_-(w_-1) != 0:
break
a = root
for d, (bid, w, rbyd, rid, tags) in enumerate(path):
if not tags:
continue
b = (bid-(w-1), d, rid-(w-1),
(name if name else tags[0])[0])
# remap branches to leaves if we aren't showing
# inner branches
if not inner:
if b not in branches:
bid, w, rbyd, rid, tags = path[-1]
if not tags:
continue
branches[b] = (
bid-(w-1), len(path)-1, rid-(w-1),
(name if name else tags[0])[0])
b = branches[b]
# found entry point?
if root is None:
root = b
a = root
tree.add(TBranch(
a=a,
b=b,
d=d,
c='b',
))
a = b
return tree, max((branch.d+1 for branch in tree), default=0)
# mtree lookup with this rbyd as the mroot # mtree lookup with this rbyd as the mroot
def mtree_lookup(self, f, block_size, mbid): def mtree_lookup(self, f, block_size, mbid):
# have mtree? # have mtree?
+32 -7
View File
@@ -456,7 +456,8 @@ class Rbyd:
yield rid, tag, w, j, d, data yield rid, tag, w, j, d, data
# create tree representation for debugging # create tree representation for debugging
def tree(self): def tree(self, *,
rbyd=False):
trunks = co.defaultdict(lambda: (-1, 0)) trunks = co.defaultdict(lambda: (-1, 0))
alts = co.defaultdict(lambda: {}) alts = co.defaultdict(lambda: {})
@@ -476,6 +477,7 @@ class Rbyd:
else: else:
alts[j_] |= {'nf': j__, 'c': c} alts[j_] |= {'nf': j__, 'c': c}
if rbyd:
# treat unreachable alts as converging paths # treat unreachable alts as converging paths
for j_, alt in alts.items(): for j_, alt in alts.items():
if 'f' not in alt: if 'f' not in alt:
@@ -483,6 +485,23 @@ class Rbyd:
elif 'nf' not in alt: elif 'nf' not in alt:
alt['nf'] = alt['f'] alt['nf'] = alt['f']
else:
# prune any alts with unreachable edges
pruned = {}
for j_, alt in alts.items():
if 'f' not in alt:
pruned[j_] = alt['nf']
elif 'nf' not in alt:
pruned[j_] = alt['f']
for j_ in pruned.keys():
del alts[j_]
for j_, alt in alts.items():
while alt['f'] in pruned:
alt['f'] = pruned[alt['f']]
while alt['nf'] in pruned:
alt['nf'] = pruned[alt['nf']]
# find the trunk and depth of each alt # find the trunk and depth of each alt
def rec_trunk(j_): def rec_trunk(j_):
if j_ not in alts: if j_ not in alts:
@@ -630,7 +649,7 @@ def main(disk, roots=None, *,
# precompute rbyd-trees if requested # precompute rbyd-trees if requested
t_width = 0 t_width = 0
if args.get('tree'): if args.get('tree') or args.get('rbyd'):
# find the max depth of each layer to nicely align trees # find the max depth of each layer to nicely align trees
bdepths = {} bdepths = {}
bid = -1 bid = -1
@@ -641,7 +660,7 @@ def main(disk, roots=None, *,
break break
for d, (bid, w, rbyd, rid, tags) in enumerate(path): for d, (bid, w, rbyd, rid, tags) in enumerate(path):
_, rdepth = rbyd.tree() _, rdepth = rbyd.tree(rbyd=args.get('rbyd'))
bdepths[d] = max(bdepths.get(d, 0), rdepth) bdepths[d] = max(bdepths.get(d, 0), rdepth)
# find all branches # find all branches
@@ -662,7 +681,7 @@ def main(disk, roots=None, *,
continue continue
# map rbyd tree into B-tree space # map rbyd tree into B-tree space
rtree, rdepth = rbyd.tree() rtree, rdepth = rbyd.tree(rbyd=args.get('rbyd'))
# note we adjust our bid/rids to be left-leaning, # note we adjust our bid/rids to be left-leaning,
# this allows a global order and make tree rendering quite # this allows a global order and make tree rendering quite
@@ -817,7 +836,7 @@ def main(disk, roots=None, *,
a = b a = b
# common tree renderer # common tree renderer
if args.get('tree') or args.get('btree'): if args.get('tree') or args.get('rbyd') or args.get('btree'):
# find the max depth from the tree # find the max depth from the tree
t_depth = max((branch.d+1 for branch in tree), default=0) t_depth = max((branch.d+1 for branch in tree), default=0)
if t_depth > 0: if t_depth > 0:
@@ -888,7 +907,9 @@ def main(disk, roots=None, *,
if prbyd is None or rbyd != prbyd if prbyd is None or rbyd != prbyd
else '', else '',
treerepr(bid, w, bd, rid, tag) treerepr(bid, w, bd, rid, tag)
if args.get('tree') or args.get('btree') else '', if args.get('tree')
or args.get('rbyd')
or args.get('btree') else '',
2*w_width+1, '' if i != 0 2*w_width+1, '' if i != 0
else '%d-%d' % (bid-(w-1), bid) if w > 1 else '%d-%d' % (bid-(w-1), bid) if w > 1
else bid if w > 0 else bid if w > 0
@@ -1039,7 +1060,11 @@ if __name__ == "__main__":
parser.add_argument( parser.add_argument(
'-B', '--btree', '-B', '--btree',
action='store_true', action='store_true',
help="Show the underlying B-tree.") help="Show the B-tree.")
parser.add_argument(
'-R', '--rbyd',
action='store_true',
help="Show the full underlying rbyd trees.")
parser.add_argument( parser.add_argument(
'-i', '--inner', '-i', '--inner',
action='store_true', action='store_true',
+46 -17
View File
@@ -487,7 +487,8 @@ class Rbyd:
yield rid, tag, w, j, d, data yield rid, tag, w, j, d, data
# create tree representation for debugging # create tree representation for debugging
def tree(self): def tree(self, *,
rbyd=False):
trunks = co.defaultdict(lambda: (-1, 0)) trunks = co.defaultdict(lambda: (-1, 0))
alts = co.defaultdict(lambda: {}) alts = co.defaultdict(lambda: {})
@@ -507,6 +508,7 @@ class Rbyd:
else: else:
alts[j_] |= {'nf': j__, 'c': c} alts[j_] |= {'nf': j__, 'c': c}
if rbyd:
# treat unreachable alts as converging paths # treat unreachable alts as converging paths
for j_, alt in alts.items(): for j_, alt in alts.items():
if 'f' not in alt: if 'f' not in alt:
@@ -514,6 +516,23 @@ class Rbyd:
elif 'nf' not in alt: elif 'nf' not in alt:
alt['nf'] = alt['f'] alt['nf'] = alt['f']
else:
# prune any alts with unreachable edges
pruned = {}
for j_, alt in alts.items():
if 'f' not in alt:
pruned[j_] = alt['nf']
elif 'nf' not in alt:
pruned[j_] = alt['f']
for j_ in pruned.keys():
del alts[j_]
for j_, alt in alts.items():
while alt['f'] in pruned:
alt['f'] = pruned[alt['f']]
while alt['nf'] in pruned:
alt['nf'] = pruned[alt['nf']]
# find the trunk and depth of each alt # find the trunk and depth of each alt
def rec_trunk(j_): def rec_trunk(j_):
if j_ not in alts: if j_ not in alts:
@@ -624,18 +643,19 @@ class Rbyd:
# btree rbyd-tree generation for debugging # btree rbyd-tree generation for debugging
def btree_tree(self, f, block_size, *, def btree_tree(self, f, block_size, *,
depth=None, depth=None,
inner=False): inner=False,
rbyd=False):
# find the max depth of each layer to nicely align trees # find the max depth of each layer to nicely align trees
bdepths = {} bdepths = {}
bid = -1 bid = -1
while True: while True:
done, bid, w, rbyd, rid, tags, path = self.btree_lookup( done, bid, w, rbyd_, rid, tags, path = self.btree_lookup(
f, block_size, bid+1, depth=depth) f, block_size, bid+1, depth=depth)
if done: if done:
break break
for d, (bid, w, rbyd, rid, tags) in enumerate(path): for d, (bid, w, rbyd_, rid, tags) in enumerate(path):
_, rdepth = rbyd.tree() _, rdepth = rbyd_.tree(rbyd=rbyd)
bdepths[d] = max(bdepths.get(d, 0), rdepth) bdepths[d] = max(bdepths.get(d, 0), rdepth)
# find all branches # find all branches
@@ -644,19 +664,19 @@ class Rbyd:
branches = {} branches = {}
bid = -1 bid = -1
while True: while True:
done, bid, w, rbyd, rid, tags, path = self.btree_lookup( done, bid, w, rbyd_, rid, tags, path = self.btree_lookup(
f, block_size, bid+1, depth=depth) f, block_size, bid+1, depth=depth)
if done: if done:
break break
d_ = 0 d_ = 0
leaf = None leaf = None
for d, (bid, w, rbyd, rid, tags) in enumerate(path): for d, (bid, w, rbyd_, rid, tags) in enumerate(path):
if not tags: if not tags:
continue continue
# map rbyd tree into B-tree space # map rbyd tree into B-tree space
rtree, rdepth = rbyd.tree() rtree, rdepth = rbyd_.tree(rbyd=rbyd)
# note we adjust our bid/rids to be left-leaning, # note we adjust our bid/rids to be left-leaning,
# this allows a global order and make tree rendering quite # this allows a global order and make tree rendering quite
@@ -665,8 +685,8 @@ class Rbyd:
for branch in rtree: for branch in rtree:
a_rid, a_tag = branch.a a_rid, a_tag = branch.a
b_rid, b_tag = branch.b b_rid, b_tag = branch.b
_, _, _, a_w, _, _, _, _ = rbyd.lookup(a_rid, 0) _, _, _, a_w, _, _, _, _ = rbyd_.lookup(a_rid, 0)
_, _, _, b_w, _, _, _, _ = rbyd.lookup(b_rid, 0) _, _, _, b_w, _, _, _, _ = rbyd_.lookup(b_rid, 0)
rtree_.add(TBranch( rtree_.add(TBranch(
a=(a_rid-(a_w-1), a_tag), a=(a_rid-(a_w-1), a_tag),
b=(b_rid-(b_w-1), b_tag), b=(b_rid-(b_w-1), b_tag),
@@ -1257,11 +1277,12 @@ def dbg_fstruct(f, block_size, mdir, rid, tag, j, d, data, *,
# precompute rbyd-trees if requested # precompute rbyd-trees if requested
t_width = 0 t_width = 0
if args.get('tree'): if args.get('tree') or args.get('rbyd'):
tree, tdepth = btree.btree_tree( tree, tdepth = btree.btree_tree(
f, block_size, f, block_size,
depth=args.get('struct_depth'), depth=args.get('struct_depth'),
inner=args.get('inner')) inner=args.get('inner'),
rbyd=args.get('rbyd'))
# precompute B-trees if requested # precompute B-trees if requested
elif args.get('btree'): elif args.get('btree'):
@@ -1270,7 +1291,7 @@ def dbg_fstruct(f, block_size, mdir, rid, tag, j, d, data, *,
depth=args.get('struct_depth'), depth=args.get('struct_depth'),
inner=args.get('inner')) inner=args.get('inner'))
if args.get('tree') or args.get('btree'): if args.get('tree') or args.get('rbyd') or args.get('btree'):
# map the tree into our block space # map the tree into our block space
tree_ = set() tree_ = set()
for branch in tree: for branch in tree:
@@ -1348,7 +1369,7 @@ def dbg_fstruct(f, block_size, mdir, rid, tag, j, d, data, *,
tree = tree_ tree = tree_
# common tree renderer # common tree renderer
if args.get('tree') or args.get('btree'): if args.get('tree') or args.get('rbyd') or args.get('btree'):
# find the max depth from the tree # find the max depth from the tree
t_depth = max((branch.d+1 for branch in tree), default=0) t_depth = max((branch.d+1 for branch in tree), default=0)
if t_depth > 0: if t_depth > 0:
@@ -1420,7 +1441,9 @@ def dbg_fstruct(f, block_size, mdir, rid, tag, j, d, data, *,
else '', else '',
m_width, '', m_width, '',
treerepr(bid, w, bd, rid, False, tag) treerepr(bid, w, bd, rid, False, tag)
if args.get('tree') or args.get('btree') else '', if args.get('tree')
or args.get('rbyd')
or args.get('btree') else '',
'%*s ' % (2*w_width+1, '' if i != 0 '%*s ' % (2*w_width+1, '' if i != 0
else '%d-%d' % (bid-(w-1), bid) if w > 1 else '%d-%d' % (bid-(w-1), bid) if w > 1
else bid if w > 0 else bid if w > 0
@@ -1474,7 +1497,9 @@ def dbg_fstruct(f, block_size, mdir, rid, tag, j, d, data, *,
'\x1b[0m' if color and notes else '', '\x1b[0m' if color and notes else '',
m_width, '', m_width, '',
treerepr(bid, w, bd, rid, True, tag) treerepr(bid, w, bd, rid, True, tag)
if args.get('tree') or args.get('btree') else '', if args.get('tree')
or args.get('rbyd')
or args.get('btree') else '',
'\x1b[31m' if color and notes else '', '\x1b[31m' if color and notes else '',
'%*s ' % (2*w_width+1, '%d-%d' % (bid-(w-1), bid) if w > 1 '%*s ' % (2*w_width+1, '%d-%d' % (bid-(w-1), bid) if w > 1
else bid if w > 0 else bid if w > 0
@@ -2231,7 +2256,11 @@ if __name__ == "__main__":
parser.add_argument( parser.add_argument(
'-B', '--btree', '-B', '--btree',
action='store_true', action='store_true',
help="Show the underlying B-tree.") help="Show the underlying B-trees.")
parser.add_argument(
'-R', '--rbyd',
action='store_true',
help="Show the full underlying rbyd trees.")
parser.add_argument( parser.add_argument(
'-i', '--inner', '-i', '--inner',
action='store_true', action='store_true',
+51 -21
View File
@@ -471,7 +471,8 @@ class Rbyd:
yield rid, tag, w, j, d, data yield rid, tag, w, j, d, data
# create tree representation for debugging # create tree representation for debugging
def tree(self): def tree(self, *,
rbyd=False):
trunks = co.defaultdict(lambda: (-1, 0)) trunks = co.defaultdict(lambda: (-1, 0))
alts = co.defaultdict(lambda: {}) alts = co.defaultdict(lambda: {})
@@ -491,6 +492,7 @@ class Rbyd:
else: else:
alts[j_] |= {'nf': j__, 'c': c} alts[j_] |= {'nf': j__, 'c': c}
if rbyd:
# treat unreachable alts as converging paths # treat unreachable alts as converging paths
for j_, alt in alts.items(): for j_, alt in alts.items():
if 'f' not in alt: if 'f' not in alt:
@@ -498,6 +500,23 @@ class Rbyd:
elif 'nf' not in alt: elif 'nf' not in alt:
alt['nf'] = alt['f'] alt['nf'] = alt['f']
else:
# prune any alts with unreachable edges
pruned = {}
for j_, alt in alts.items():
if 'f' not in alt:
pruned[j_] = alt['nf']
elif 'nf' not in alt:
pruned[j_] = alt['f']
for j_ in pruned.keys():
del alts[j_]
for j_, alt in alts.items():
while alt['f'] in pruned:
alt['f'] = pruned[alt['f']]
while alt['nf'] in pruned:
alt['nf'] = pruned[alt['nf']]
# find the trunk and depth of each alt # find the trunk and depth of each alt
def rec_trunk(j_): def rec_trunk(j_):
if j_ not in alts: if j_ not in alts:
@@ -608,18 +627,19 @@ class Rbyd:
# btree rbyd-tree generation for debugging # btree rbyd-tree generation for debugging
def btree_tree(self, f, block_size, *, def btree_tree(self, f, block_size, *,
depth=None, depth=None,
inner=False): inner=False,
rbyd=False):
# find the max depth of each layer to nicely align trees # find the max depth of each layer to nicely align trees
bdepths = {} bdepths = {}
bid = -1 bid = -1
while True: while True:
done, bid, w, rbyd, rid, tags, path = self.btree_lookup( done, bid, w, rbyd_, rid, tags, path = self.btree_lookup(
f, block_size, bid+1, depth=depth) f, block_size, bid+1, depth=depth)
if done: if done:
break break
for d, (bid, w, rbyd, rid, tags) in enumerate(path): for d, (bid, w, rbyd_, rid, tags) in enumerate(path):
_, rdepth = rbyd.tree() _, rdepth = rbyd_.tree(rbyd=rbyd)
bdepths[d] = max(bdepths.get(d, 0), rdepth) bdepths[d] = max(bdepths.get(d, 0), rdepth)
# find all branches # find all branches
@@ -628,19 +648,19 @@ class Rbyd:
branches = {} branches = {}
bid = -1 bid = -1
while True: while True:
done, bid, w, rbyd, rid, tags, path = self.btree_lookup( done, bid, w, rbyd_, rid, tags, path = self.btree_lookup(
f, block_size, bid+1, depth=depth) f, block_size, bid+1, depth=depth)
if done: if done:
break break
d_ = 0 d_ = 0
leaf = None leaf = None
for d, (bid, w, rbyd, rid, tags) in enumerate(path): for d, (bid, w, rbyd_, rid, tags) in enumerate(path):
if not tags: if not tags:
continue continue
# map rbyd tree into B-tree space # map rbyd tree into B-tree space
rtree, rdepth = rbyd.tree() rtree, rdepth = rbyd_.tree(rbyd=rbyd)
# note we adjust our bid/rids to be left-leaning, # note we adjust our bid/rids to be left-leaning,
# this allows a global order and make tree rendering quite # this allows a global order and make tree rendering quite
@@ -649,8 +669,8 @@ class Rbyd:
for branch in rtree: for branch in rtree:
a_rid, a_tag = branch.a a_rid, a_tag = branch.a
b_rid, b_tag = branch.b b_rid, b_tag = branch.b
_, _, _, a_w, _, _, _, _ = rbyd.lookup(a_rid, 0) _, _, _, a_w, _, _, _, _ = rbyd_.lookup(a_rid, 0)
_, _, _, b_w, _, _, _, _ = rbyd.lookup(b_rid, 0) _, _, _, b_w, _, _, _, _ = rbyd_.lookup(b_rid, 0)
rtree_.add(TBranch( rtree_.add(TBranch(
a=(a_rid-(a_w-1), a_tag), a=(a_rid-(a_w-1), a_tag),
b=(b_rid-(b_w-1), b_tag), b=(b_rid-(b_w-1), b_tag),
@@ -919,7 +939,7 @@ def main(disk, mroots=None, *,
# precompute rbyd-tree if requested # precompute rbyd-tree if requested
t_width = 0 t_width = 0
if args.get('tree'): if args.get('tree') or args.get('rbyd'):
# compute mroot chain "tree", prefix our actual mtree with this # compute mroot chain "tree", prefix our actual mtree with this
tree = set() tree = set()
d_ = 0 d_ = 0
@@ -931,7 +951,7 @@ def main(disk, mroots=None, *,
break break
# compute the mroots rbyd-tree # compute the mroots rbyd-tree
rtree, rdepth = mroot_.tree() rtree, rdepth = mroot_.tree(rbyd=args.get('rbyd'))
# connect branch to our root # connect branch to our root
if d > 0: if d > 0:
@@ -977,7 +997,7 @@ def main(disk, mroots=None, *,
# compute mdir's rbyd-tree if there is one # compute mdir's rbyd-tree if there is one
if mdir: if mdir:
rtree, rdepth = mdir.tree() rtree, rdepth = mdir.tree(rbyd=args.get('rbyd'))
# connect branch to our root # connect branch to our root
root = min(rtree, root = min(rtree,
@@ -1011,7 +1031,8 @@ def main(disk, mroots=None, *,
tree_, tdepth = mtree.btree_tree( tree_, tdepth = mtree.btree_tree(
f, block_size, f, block_size,
depth=args.get('depth', mdepth)-mdepth, depth=args.get('depth', mdepth)-mdepth,
inner=args.get('inner')) inner=args.get('inner'),
rbyd=args.get('rbyd'))
# connect a branch to the root of the tree # connect a branch to the root of the tree
root = min(tree_, key=lambda branch: branch.d, default=None) root = min(tree_, key=lambda branch: branch.d, default=None)
@@ -1063,7 +1084,7 @@ def main(disk, mroots=None, *,
blocks = frommdir(data) blocks = frommdir(data)
mdir_ = Rbyd.fetch(f, block_size, blocks) mdir_ = Rbyd.fetch(f, block_size, blocks)
rtree, rdepth = mdir_.tree() rtree, rdepth = mdir_.tree(rbyd=args.get('rbyd'))
mdepth_ = max(mdepth_, rdepth) mdepth_ = max(mdepth_, rdepth)
# compute the rbyd-tree for each mdir # compute the rbyd-tree for each mdir
@@ -1093,7 +1114,7 @@ def main(disk, mroots=None, *,
blocks = frommdir(data) blocks = frommdir(data)
mdir_ = Rbyd.fetch(f, block_size, blocks) mdir_ = Rbyd.fetch(f, block_size, blocks)
rtree, rdepth = mdir_.tree() rtree, rdepth = mdir_.tree(rbyd=args.get('rbyd'))
# connect the root to the mtree # connect the root to the mtree
branch = max( branch = max(
@@ -1230,7 +1251,8 @@ def main(disk, mroots=None, *,
tree_, tdepth = mtree.btree_btree( tree_, tdepth = mtree.btree_btree(
f, block_size, f, block_size,
depth=args.get('depth', mdepth)-mdepth, depth=args.get('depth', mdepth)-mdepth,
inner=args.get('inner')) inner=args.get('inner'),
rbyd=args.get('rbyd'))
# connect a branch to the root of the tree # connect a branch to the root of the tree
root = min(tree_, key=lambda branch: branch.d, default=None) root = min(tree_, key=lambda branch: branch.d, default=None)
@@ -1310,7 +1332,7 @@ def main(disk, mroots=None, *,
tree = tree_ tree = tree_
# common tree renderer # common tree renderer
if args.get('tree') or args.get('btree'): if args.get('tree') or args.get('rbyd') or args.get('btree'):
# find the max depth from the tree # find the max depth from the tree
t_depth = max((branch.d+1 for branch in tree), default=0) t_depth = max((branch.d+1 for branch in tree), default=0)
if t_depth > 0: if t_depth > 0:
@@ -1375,7 +1397,9 @@ def main(disk, mroots=None, *,
mdir.redund_blocks)) mdir.redund_blocks))
if i == 0 else '', if i == 0 else '',
treerepr(mbid-max(mw-1, 0), 0, md, 0, rid, tag) treerepr(mbid-max(mw-1, 0), 0, md, 0, rid, tag)
if args.get('tree') or args.get('btree') else '', if args.get('tree')
or args.get('rbyd')
or args.get('btree') else '',
'%*s %-*s%s' % ( '%*s %-*s%s' % (
2*w_width+1, '%d.%d-%d' % ( 2*w_width+1, '%d.%d-%d' % (
mbid//mleaf_weight, rid-(w-1), rid) mbid//mleaf_weight, rid-(w-1), rid)
@@ -1425,7 +1449,9 @@ def main(disk, mroots=None, *,
if prbyd is None or rbyd != prbyd if prbyd is None or rbyd != prbyd
else '', else '',
treerepr(bid, w, bd, rid, 0, tag) treerepr(bid, w, bd, rid, 0, tag)
if args.get('tree') or args.get('btree') else '', if args.get('tree')
or args.get('rbyd')
or args.get('btree') else '',
2*w_width+1, '' if i != 0 2*w_width+1, '' if i != 0
else '%d-%d' % ( else '%d-%d' % (
(bid-(w-1))//mleaf_weight, (bid-(w-1))//mleaf_weight,
@@ -1685,7 +1711,11 @@ if __name__ == "__main__":
parser.add_argument( parser.add_argument(
'-B', '--btree', '-B', '--btree',
action='store_true', action='store_true',
help="Show the underlying B-tree.") help="Show the underlying B-trees.")
parser.add_argument(
'-R', '--rbyd',
action='store_true',
help="Show the full underlying rbyd trees.")
parser.add_argument( parser.add_argument(
'-i', '--inner', '-i', '--inner',
action='store_true', action='store_true',
+25 -2
View File
@@ -676,7 +676,7 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
# precompute tree # precompute tree
t_width = 0 t_width = 0
if args.get('tree'): if args.get('tree') or args.get('rbyd'):
trunks = co.defaultdict(lambda: (-1, 0)) trunks = co.defaultdict(lambda: (-1, 0))
alts = co.defaultdict(lambda: {}) alts = co.defaultdict(lambda: {})
@@ -696,6 +696,7 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
else: else:
alts[j_] |= {'nf': j__, 'c': c} alts[j_] |= {'nf': j__, 'c': c}
if args.get('rbyd'):
# treat unreachable alts as converging paths # treat unreachable alts as converging paths
for j_, alt in alts.items(): for j_, alt in alts.items():
if 'f' not in alt: if 'f' not in alt:
@@ -703,6 +704,23 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
elif 'nf' not in alt: elif 'nf' not in alt:
alt['nf'] = alt['f'] alt['nf'] = alt['f']
else:
# prune any alts with unreachable edges
pruned = {}
for j_, alt in alts.items():
if 'f' not in alt:
pruned[j_] = alt['nf']
elif 'nf' not in alt:
pruned[j_] = alt['f']
for j_ in pruned.keys():
del alts[j_]
for j_, alt in alts.items():
while alt['f'] in pruned:
alt['f'] = pruned[alt['f']]
while alt['nf'] in pruned:
alt['nf'] = pruned[alt['nf']]
# find the trunk and depth of each alt # find the trunk and depth of each alt
def rec_trunk(j_): def rec_trunk(j_):
if j_ not in alts: if j_ not in alts:
@@ -819,7 +837,8 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
# show human-readable tag representation # show human-readable tag representation
print('%08x: %s%*s %-*s %s' % ( print('%08x: %s%*s %-*s %s' % (
j, j,
treerepr(rid, tag) if args.get('tree') else '', treerepr(rid, tag)
if args.get('tree') or args.get('rbyd') else '',
2*w_width+1, '%d-%d' % (rid-(w-1), rid) 2*w_width+1, '%d-%d' % (rid-(w-1), rid)
if w > 1 else rid if w > 1 else rid
if w > 0 or i == 0 else '', if w > 0 or i == 0 else '',
@@ -1070,6 +1089,10 @@ if __name__ == "__main__":
'-t', '--tree', '-t', '--tree',
action='store_true', action='store_true',
help="Show the rbyd tree.") help="Show the rbyd tree.")
parser.add_argument(
'-R', '--rbyd',
action='store_true',
help="Show the full rbyd tree.")
parser.add_argument( parser.add_argument(
'-j', '--jumps', '-j', '--jumps',
action='store_true', action='store_true',