Allowed "alta" (altbgt 0) to terminate rbyd trunks, dropped rm bit

This replaces unr with null on disk, though note both the rm bit and unr
are used in-device still, they just don't get written to disk.

This removes the need for the rm bit on disk. Since we no longer need to
figure out what's been removed during fetch, we can save this bit for both
internal and future on-disk use.

Special handling of alta allows us to avoid emitting an unr tag (now null) if
the current trunk is truly unreachable. This is minor now, but important
for a theoretical rbyd rebalance operation (planned), which brings the
rbyd overhead down from ~3x to ~2x.

These changes give us two ways to terminate trunks without a tag:

1. With an alta, if the current trunk is unreachable:

     altbgt 0x403 w0 0x7b
     altbgt 0x402 w0 0x29
     alta w0 0x4

2. With a null, if the current trunk is reachable, either for
   code convenience or because emitting an alta is impossible (an empty
   rbyd for example):

     altbgt 0x403 w0 0x7b
     altbgt 0x402 w0 0x29
     altbgt 0x401 w0 0x4
     null
This commit is contained in:
Christopher Haster
2023-06-17 18:11:45 -05:00
parent aa559d30b0
commit 7180b70c9c
4 changed files with 275 additions and 250 deletions
+89 -79
View File
@@ -17,7 +17,7 @@ COLORS = [
]
TAG_UNR = 0x1000
TAG_NULL = 0x0000
TAG_SUPERMAGIC = 0x0003
TAG_SUPERCONFIG = 0x0004
TAG_MROOT = 0x0304
@@ -32,9 +32,11 @@ TAG_BTREE = 0x0303
TAG_MDIR = 0x0305
TAG_UATTR = 0x0400
TAG_ALT = 0x4000
TAG_ALTA = 0x6000
TAG_CRC = 0x2000
TAG_FCRC = 0x2100
# parse some rbyd addr encodings
# 0xa -> [0xa]
# 0xa.b -> ([0xa], b)
@@ -111,55 +113,56 @@ def xxd(data, width=16, crc=False):
for b in map(chr, data[i:i+width])))
def tagrepr(tag, w, size, off=None):
if (tag & 0x7fff) == TAG_UNR:
return 'unr%s%s' % (
if tag == TAG_NULL:
return 'null%s%s' % (
' w%d' % w if w else '',
' %d' % size if size else '')
elif (tag & 0x6fff) == TAG_SUPERMAGIC:
return '%ssupermagic%s%s' % (
'rm' if tag & 0x1000 else '',
elif tag == TAG_SUPERMAGIC:
return 'supermagic%s %d' % (
' w%d' % w if w else '',
' %d' % size if not tag & 0x1000 or size else '')
elif (tag & 0x6fff) == TAG_SUPERCONFIG:
return '%ssuperconfig%s%s' % (
'rm' if tag & 0x1000 else '',
size)
elif tag == TAG_SUPERCONFIG:
return 'superconfig%s %d' % (
' w%d' % w if w else '',
' %d' % size if not tag & 0x1000 or size else '')
elif (tag & 0x6f00) == TAG_NAME:
return '%s%s%s%s' % (
'rm' if tag & 0x1000 else '',
'branch' if (tag & 0xfffe) == TAG_BRANCH
else 'reg' if (tag & 0xfffe) == TAG_REG
else 'dir' if (tag & 0xfffe) == TAG_DIR
else 'name 0x%02x' % ((tag & 0x0ff0) >> 4),
size)
elif (tag & 0xff00) == TAG_NAME:
return '%s%s %d' % (
'branch' if tag == TAG_BRANCH
else 'reg' if tag == TAG_REG
else 'dir' if tag == TAG_DIR
else 'name 0x%02x' % (tag & 0xff),
' w%d' % w if w else '',
' %d' % size if not tag & 0x1000 or size else '')
elif (tag & 0x6f00) == TAG_STRUCT:
return '%s%s%s%s' % (
'rm' if tag & 0x1000 else '',
'inlined' if (tag & 0x6fff) == TAG_INLINED
else 'block' if (tag & 0x6fff) == TAG_BLOCK
else 'btree' if (tag & 0x6fff) == TAG_BTREE
else 'mdir' if (tag & 0x6fff) == TAG_MROOT
else 'mdir' if (tag & 0x6fff) == TAG_MDIR
else 'struct 0x%02x' % ((tag & 0x0ff0) >> 4),
size)
elif (tag & 0xff00) == TAG_STRUCT:
return '%s%s %d' % (
'inlined' if tag == TAG_INLINED
else 'block' if tag == TAG_BLOCK
else 'btree' if tag == TAG_BTREE
else 'mdir' if tag == TAG_MROOT
else 'mdir' if tag == TAG_MDIR
else 'struct 0x%02x' % (tag & 0xff),
' w%d' % w if w else '',
' %d' % size if not tag & 0x1000 or size else '')
elif (tag & 0x6f00) == TAG_UATTR:
return '%suattr 0x%02x%s%s' % (
'rm' if tag & 0x1000 else '',
size)
elif (tag & 0xff00) == TAG_UATTR:
return 'uattr 0x%02x%s %d' % (
tag & 0xff,
' w%d' % w if w else '',
' %d' % size if not tag & 0x1000 or size else '')
elif (tag & 0x7f00) == TAG_CRC:
size)
elif (tag & 0xff00) == TAG_CRC:
return 'crc%x%s %d' % (
1 if tag & 0x1 else 0,
' 0x%x' % w if w > 0 else '',
size)
elif (tag & 0x7fff) == TAG_FCRC:
elif tag == TAG_FCRC:
return 'fcrc%s %d' % (
' 0x%x' % w if w > 0 else '',
size)
elif tag == TAG_ALTA:
return 'alta w%d %s' % (
w,
'0x%x' % (0xffffffff & (off-size))
if off is not None
else '-%d' % off)
elif tag & 0x4000:
return 'alt%s%s 0x%x w%d %s' % (
'r' if tag & 0x1000 else 'b',
@@ -172,6 +175,7 @@ def tagrepr(tag, w, size, off=None):
else:
return '0x%04x w%d %d' % (tag, w, size)
def dbg_log(data, block_size, rev, off, weight, *,
color=False,
**args):
@@ -285,22 +289,26 @@ def dbg_log(data, block_size, rev, off, weight, *,
if not tag & 0x4000:
j_ += size
# find trunk
if not wastrunk and (tag & 0x6000) != 0x2000:
lower_, upper_ = 0, 0
wastrunk = not not tag & 0x4000
# evaluate trunks
if (tag & 0xe000) != 0x2000:
if not wastrunk:
wastrunk = True
lower_, upper_ = 0, 0
# keep track of weight
if tag & 0x4000:
if tag & 0x2000:
upper_ += w
else:
if (tag & 0xe000) == 0x4000:
lower_ += w
elif (tag & 0x6000) == 0x2000:
delta = (lower_+upper_+w) - weight_
weight_ = lower_+upper_+w
id = lower_+w-1
else:
upper_ += w
if not tag & 0x4000 or tag == TAG_ALTA:
wastrunk = False
# derive the current tag's id from alt weights
delta = (lower_+upper_) - weight_
weight_ = lower_+upper_
id = lower_ + w-1
if ((tag & 0xe000) != 0x2000
and (not tag & 0x4000 or tag == TAG_ALTA)):
# note we ignore out-of-bounds here for debugging
if delta > 0:
# grow lifetimes
@@ -339,7 +347,7 @@ def dbg_log(data, block_size, rev, off, weight, *,
weights = weights_
lifetimes = lifetimes_
if not tag & 0x1000 and id >= 0:
if id >= 0:
# attach tag to lifetime
i, id_ = index(weights, id)
if i < len(weights):
@@ -427,23 +435,9 @@ def dbg_log(data, block_size, rev, off, weight, *,
crc = crc32c(data[j_:j_+d], crc)
j_ += d
# find trunk
if not wastrunk and (tag & 0x6000) != 0x2000:
lower_, upper_ = 0, 0
wastrunk = not not tag & 0x4000
# calculate id from alt weights
if tag & 0x4000:
if tag & 0x2000:
upper_ += w
else:
lower_ += w
elif (tag & 0x6000) == 0x0:
weight_ = lower_+upper_+w
id = lower_+w-1
# take care of crcs
if not tag & 0x4000:
if (tag & 0x7f00) != TAG_CRC:
if (tag & 0xff00) != TAG_CRC:
crc = crc32c(data[j_:j_+size], crc)
# found a crc?
else:
@@ -452,6 +446,22 @@ def dbg_log(data, block_size, rev, off, weight, *,
notes.append('crc!=%08x' % crc)
j_ += size
# evaluate trunks
if (tag & 0xe000) != 0x2000:
if not wastrunk:
wastrunk = True
lower_, upper_ = 0, 0
if (tag & 0xe000) == 0x4000:
lower_ += w
else:
upper_ += w
if not tag & 0x4000 or tag == TAG_ALTA:
wastrunk = False
# derive the current tag's id from alt weights
id = lower_ + w-1
# show human-readable tag representation
print('%s%08x:%s %*s%s%*s %-57s%s%s' % (
'\x1b[90m' if color and j >= off else '',
@@ -459,7 +469,8 @@ def dbg_log(data, block_size, rev, off, weight, *,
'\x1b[m' if color and j >= off else '',
lifetime_width, lifetimerepr(j) if args.get('lifetimes') else '',
'\x1b[90m' if color and j >= off else '',
w_width, '' if (tag & 0x6000) != 0x0
w_width, '-' if tag == TAG_ALTA
else '' if (tag & 0xe000) != 0x0000
else '%d-%d' % (id-(w-1), id) if w > 1
else id,
'%-22s%s' % (
@@ -576,7 +587,7 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
tag_ = alt
w_ = id_-lower
done = (id_, tag_) < (id, tag) or tag_ & 0x1000
done = not tag_ or (id_, tag_) < (id, tag)
return done, id_, tag_, w_, j, d, jump, path
@@ -835,8 +846,8 @@ def main(disk, blocks=None, *,
trunk_ = 0
trunk__ = 0
weight = 0
lower_, upper_ = 0, 0
weight_ = 0
weight__ = 0
wastrunk = False
trunkoff = None
while j_ < len(data) and (not trunk or off <= trunk):
@@ -850,7 +861,7 @@ def main(disk, blocks=None, *,
# take care of crcs
if not tag & 0x4000:
if (tag & 0x7f00) != TAG_CRC:
if (tag & 0xff00) != TAG_CRC:
crc_ = crc32c(data[j_:j_+size], crc_)
# found a crc?
else:
@@ -864,23 +875,22 @@ def main(disk, blocks=None, *,
weight = weight_
# evaluate trunks
if (tag & 0x6000) != 0x2000 and (
if (tag & 0xe000) != 0x2000 and (
not trunk or trunk >= j_-d or wastrunk):
# new trunk?
if not wastrunk:
trunk__ = j_-d
lower_, upper_ = 0, 0
wastrunk = True
trunk__ = j_-d
weight__ = 0
# keep track of weight
if tag & 0x4000:
if tag & 0x2000:
upper_ += w
else:
lower_ += w
else:
weight_ = lower_+upper_+w
weight__ += w
# end of trunk?
if not tag & 0x4000 or tag == TAG_ALTA:
wastrunk = False
# update weight
weight_ = weight__
# keep track of off for best matching trunk
if trunk and j_ + size > trunk:
trunkoff = j_ + size