From 3ae1bca078686ad036b6f70b8299fc32117b0c64 Mon Sep 17 00:00:00 2001 From: HuangYi Date: Mon, 12 Dec 2022 15:47:01 +0800 Subject: [PATCH 1/6] simplify diff algorithm --- iavl/cli.py | 29 +++--- iavl/diff.py | 227 +++++++-------------------------------------- iavl/iavl.py | 67 ++++++++++--- iavl/utils.py | 41 ++++---- iavl/visualize.py | 10 +- tests/test_diff.py | 54 +---------- 6 files changed, 138 insertions(+), 290 deletions(-) diff --git a/iavl/cli.py b/iavl/cli.py index 4cbd887..9a29168 100644 --- a/iavl/cli.py +++ b/iavl/cli.py @@ -9,7 +9,7 @@ from hexbytes import HexBytes from . import dbm, diff -from .iavl import NodeDB, Tree +from .iavl import NodeDB, Tree, delete_version from .utils import (decode_fast_node, diff_iterators, encode_stdint, fast_node_key, get_node, get_root_node, iavl_latest_version, iter_fast_nodes, iter_iavl_tree, @@ -417,14 +417,14 @@ def test_state_round_trip(db, store, start_version): tree = Tree(ndb, pversion) diff.apply_change_set(tree, changeset) tmp = tree.save_version(dry_run=True) - if (root.hash or hashlib.sha256().digest()) == tmp: + if (root or hashlib.sha256().digest()) == tmp: print(v, len(changeset), "ok") else: print( v, len(changeset), "fail", - binascii.hexlify(root.hash).decode(), + binascii.hexlify(root).decode(), binascii.hexlify(tmp).decode(), ) @@ -433,7 +433,7 @@ def iter_state_changes( db: dbm.DBM, ndb: NodeDB, start_version=0, end_version=None, prefix=b"" ): pversion = ndb.prev_version(start_version) or 0 - prev_root = ndb.get_root_node(pversion) + prev_root = ndb.get_root_hash(pversion) it = db.iteritems() it.seek(prefix + root_key(start_version)) for k, hash in it: @@ -443,11 +443,12 @@ def iter_state_changes( if end_version is not None and v >= end_version: break - root = ndb.get(hash) - yield pversion, v, root, diff.state_changes(ndb.get, prev_root, root) + yield pversion, v, hash, diff.state_changes( + ndb.get, pversion, v, prev_root, hash + ) pversion = v - prev_root = root + prev_root = hash @cli.command() @@ -469,8 +470,8 @@ def visualize_pruning(db, store, version): ndb = NodeDB(db, prefix=prefix) predecessor = ndb.prev_version(version) or 0 successor = ndb.next_version(version) - root1 = ndb.get_root_node(version) - root2 = ndb.get_root_node(successor) + root1 = ndb.get_root_hash(version) + root2 = ndb.get_root_hash(successor) touched_nodes = set() @@ -479,14 +480,15 @@ def trace_get(hash): return ndb.get(hash) deleted = set() - for orphaned, _ in diff.diff_tree( + for n in delete_version( trace_get, + version, + predecessor, + successor, root1, root2, - diff.DiffOptions.for_pruning(predecessor), ): - for n in orphaned: - deleted.add(n.hash) + deleted.add(n.hash) print( "delete version:", @@ -504,7 +506,6 @@ def trace_get(hash): len(touched_nodes), file=sys.stderr, ) - touched_nodes.update([root1.hash, root2.hash]) g = visualize_pruned_nodes(successor, touched_nodes, deleted, ndb) print(g.source) diff --git a/iavl/diff.py b/iavl/diff.py index 4c79898..82912d7 100644 --- a/iavl/diff.py +++ b/iavl/diff.py @@ -2,16 +2,14 @@ tree diff algorithm between two versions """ import binascii -import itertools from dataclasses import dataclass, field from enum import IntEnum -from typing import Callable, List, NamedTuple, Optional, Tuple +from typing import List, NamedTuple, Tuple from cprotobuf import Field, ProtoEntity, decode_primitive, encode_primitive from .iavl import PersistedNode, Tree - -GetNode = Callable[bytes, Optional[PersistedNode]] +from .utils import GetNode, visit_iavl_nodes class Op(IntEnum): @@ -22,182 +20,6 @@ class Op(IntEnum): ChangeSet = List[Change] -@dataclass -class Layer: - """ - Represent one layer of nodes at the same height - - pending_nodes: because one of the children's height could be height-2, need to keep - it in the pending list temporarily. - """ - - height: int = 0 - nodes: List[PersistedNode] = field(default_factory=list) - pending_nodes: List[PersistedNode] = field(default_factory=list) - - @classmethod - def root(cls, root): - return cls( - height=root.height, - nodes=[root], - ) - - @classmethod - def empty(cls, height): - return cls(height=height) - - def next_layer(self, get_node: GetNode, predecessor): - """ - travel to next layer - """ - assert self.height > 0 - nodes = [] - pending_nodes = [] - for node in self.nodes: - left = get_node(node.left_node_ref) - if left.version > predecessor: - if left.height == self.height - 1: - nodes.append(left) - else: - pending_nodes.append(left) - - right = get_node(node.right_node_ref) - if right.version > predecessor: - if right.height == self.height - 1: - nodes.append(right) - else: - pending_nodes.append(right) - - self.height -= 1 - - # merge sorted lists - self.nodes = nodes - self.nodes += self.pending_nodes - self.nodes.sort(key=lambda n: n.key) - self.pending_nodes = pending_nodes - - def is_empty(self): - return not self.nodes and not self.pending_nodes - - -def diff_sorted(nodes1, nodes2): - """ - Contract: input list is sorted by node.key - return: (common, orphaned, new) - """ - i1 = i2 = 0 - common = [] - orphaned = [] - new = [] - while True: - if i1 > len(nodes1) - 1: - new += nodes2[i2:] - break - if i2 > len(nodes2) - 1: - orphaned += nodes1[i1:] - break - k1 = nodes1[i1].key - k2 = nodes2[i2].key - if nodes1[i1].hash == nodes2[i2].hash: - common.append(nodes1[i1]) - i1 += 1 - i2 += 1 - elif k1 == k2: - # overriden by same key - orphaned.append(nodes1[i1]) - new.append(nodes2[i2]) - i1 += 1 - i2 += 1 - elif k1 < k2: - # proceed to next node in nodes1 until catch up with nodes2 - orphaned.append(nodes1[i1]) - i1 += 1 - else: - # proceed to next node in nodes2 until catch up with nodes1 - new.append(nodes2[i2]) - i2 += 1 - return common, orphaned, new - - -class DiffOptions(NamedTuple): - # predecessor will skip the subtrees at or before the predecessor from both trees. - predecessor: int - # in prune mode, the diff process stop as soon as orphaned nodes becomes empty. - prune_mode: bool - - @classmethod - def full(cls): - "do a full diff, can be used for extracting state changes" - return cls(predecessor=0, prune_mode=False) - - @classmethod - def for_pruning(cls, predecessor: int): - "do an optimized diff for pruning versions" - return cls(predecessor=predecessor, prune_mode=True) - - -def diff_tree( - get_node: GetNode, root1: PersistedNode, root2: PersistedNode, opts: DiffOptions -): - """ - diff two versions of the iavl tree. - yields (orphaned, new) - - predecessor can help to skip more subtrees when finding orphaned nodes, we don't - need to traverse the subtrees that's created at or before predecessor in that case. - """ - - # skipping nodes created at or before predecessor - if root1 is not None and root1.version <= opts.predecessor: - root1 = None - if root2 is not None and root2.version <= opts.predecessor: - root2 = None - - # nothing to do if both tree are empty - if root1 is None and root2 is None: - return - - # if one is empty, create an empty layer with the same height as the other tree. - if root1 is None: - l1 = Layer.empty(root2.height) - l2 = Layer.root(root2) - elif root2 is None: - l1 = Layer.root(root1) - l2 = Layer.empty(root1.height) - else: - l1 = Layer.root(root1) - l2 = Layer.root(root2) - - while l1.height > l2.height: - yield l1.nodes, [] - l1.next_layer(get_node, opts.predecessor) - - while l2.height > l1.height: - yield [], l2.nodes - l2.next_layer(get_node, opts.predecessor) - - while True: - # l1 l2 at the same height now - _, orphaned, new = diff_sorted(l1.nodes, l2.nodes) - - yield orphaned, new - - if l1.height == 0: - break - - # don't visit the common sub-trees - l1.nodes = orphaned - l2.nodes = new - - if opts.prune_mode and l1.is_empty(): - # nothing else to see in tree1, no more orphaned nodes, only new ones, - # that's enough for pruning mode. - break - - l1.next_layer(get_node, opts.predecessor) - l2.next_layer(get_node, opts.predecessor) - - def split_operations(nodes1, nodes2) -> ChangeSet: """ Contract: input nodes are all leaf nodes, sorted by node.key @@ -237,25 +59,48 @@ def split_operations(nodes1, nodes2) -> ChangeSet: return result -def state_changes(get_node: GetNode, root1: PersistedNode, root2: PersistedNode): +def state_changes(get_node: GetNode, version, successor, root, successor_root): """ - extract state changes from the tree diff result + extract state changes from two versions of the iavl tree. + + first traverse the successor version to find the shared sub-root nodes + and new leaf nodes, then traverse the target version to find the orphaned leaf + nodes, then extract kv pair operations from it. return: [(key, op, arg)] arg: original value if op==Delete new value if op==Insert (original value, new value) if op==Update """ - for orphaned, new in diff_tree(get_node, root1, root2, DiffOptions.full()): - # the nodes are on the same height, and we only care about leaf nodes here - try: - node = next(itertools.chain(orphaned, new)) - except StopIteration: - continue - if node.height == 0: - return split_operations(orphaned, new) - return [] + shared = set() + new = [] + if successor_root: + + def successor_prune(n: PersistedNode) -> (bool, bool): + b = n.version <= version + return b, b + + for n in visit_iavl_nodes(get_node, successor_prune, successor_root): + if n.version <= version: + shared.add(n.hash) + elif n.is_leaf(): + new.append(n) + + def prune(n: PersistedNode) -> (bool, bool): + b = n.hash in shared + return b, b + + if root: + orphaned = [ + n + for n in visit_iavl_nodes(get_node, prune, root) + if n.is_leaf() and n.hash not in shared + ] + else: + orphaned = [] + + return split_operations(orphaned, new) def apply_change_set(tree: Tree, changeset: ChangeSet): diff --git a/iavl/iavl.py b/iavl/iavl.py index 521e38e..2c75641 100644 --- a/iavl/iavl.py +++ b/iavl/iavl.py @@ -9,8 +9,8 @@ import rocksdb -from .utils import Node as PersistedNode -from .utils import encode_bytes, node_key, root_key +from .utils import (GetNode, PersistedNode, encode_bytes, node_key, root_key, + visit_iavl_nodes) NodeRef = Union[bytes, "Node"] @@ -127,18 +127,21 @@ def delete_version(self, v: int) -> int: """ return how many nodes deleted """ - from .diff import DiffOptions, diff_tree + predecessor = self.prev_version(v) or 0 + successor = self.next_version(v) + assert successor is not None, "can't delete latest version" counter = 0 - prev_version = self.prev_version(v) or 0 - root1 = self.get_root_node(v) - root2 = self.get_root_node(self.next_version(v)) - for orphaned, _ in diff_tree( - self.get, root1, root2, DiffOptions.for_pruning(prev_version) + for n in delete_version( + self.get, + v, + predecessor, + successor, + self.get_root_hash(v), + self.get_root_hash(successor), ): - counter += len(orphaned) - for n in orphaned: - self.batch_remove_node(n.hash) + counter += 1 + self.batch_remove_node(n.hash) self.batch_remove_root_hash(v) self.batch_commit() @@ -491,3 +494,45 @@ def get_recursive( return get_recursive(ndb, key, node.left_node(ndb)) else: return get_recursive(ndb, key, node.right_node(ndb)) + + +def delete_version( + get_node: GetNode, + v: int, + predecessor: int, + successor: int, + root: bytes, + successor_root: bytes, +) -> int: + """ + yield the orphaned nodes to delete + + first traverse successor version to find the shared sub-root nodes, + then traverse the target version to find orphaned nodes who are not shared, + Skip nodes whose version <= predecessor from both traversal. + """ + if successor_root: + + def successor_prune(n: PersistedNode) -> (bool, bool): + b = n.version <= v + return b, b + + shared = set( + n.hash + for n in visit_iavl_nodes(get_node, successor_prune, successor_root) + if predecessor < n.version <= v + ) + else: + shared = set() + + def prune(n: PersistedNode) -> (bool, bool): + if n.hash in shared: + return True, True + elif n.version <= predecessor: + return True, True + return False, False + + if root: + for n in visit_iavl_nodes(get_node, prune, root): + if n.version > predecessor and n.hash not in shared: + yield n diff --git a/iavl/utils.py b/iavl/utils.py index 5a302ff..a77f67e 100644 --- a/iavl/utils.py +++ b/iavl/utils.py @@ -9,6 +9,7 @@ from .dbm import DBM EMPTY_HASH = hashlib.sha256().digest() +GetNode = Callable[bytes, Optional["PersistedNode"]] class CommitID(cprotobuf.ProtoEntity): @@ -30,7 +31,7 @@ class StdInt(cprotobuf.ProtoEntity): value = cprotobuf.Field("uint64", 1) -class Node(NamedTuple): +class PersistedNode(NamedTuple): """ immutable nodes that's loaded from and save to db """ @@ -179,7 +180,7 @@ def encode_bytes(bz: bytes) -> List[bytes]: ] -def encode_node(node: Node) -> bytes: +def encode_node(node: PersistedNode) -> bytes: chunks = [ cprotobuf.encode_primitive("sint64", node.height), cprotobuf.encode_primitive("sint64", node.size), @@ -192,7 +193,7 @@ def encode_node(node: Node) -> bytes: return b"".join(chunks) -def decode_node(bz: bytes, hash: bytes) -> (Node, int): +def decode_node(bz: bytes, hash: bytes) -> (PersistedNode, int): offset = 0 height, n = cprotobuf.decode_primitive(bz[offset:], "sint64") offset += n @@ -216,7 +217,7 @@ def decode_node(bz: bytes, hash: bytes) -> (Node, int): right_hash, n = decode_bytes(bz[offset:]) offset += n return ( - Node( + PersistedNode( height=height, size=size, version=version, @@ -239,7 +240,9 @@ def decode_fast_node(bz: bytes) -> (int, bytes, int): return version, value, offset -def get_node(db: DBM, hash: bytes, store: Optional[str] = None) -> Optional[Node]: +def get_node( + db: DBM, hash: bytes, store: Optional[str] = None +) -> Optional[PersistedNode]: prefix = store_prefix(store) if store is not None else b"" bz = db.get(prefix + node_key(hash)) if not bz: @@ -248,7 +251,9 @@ def get_node(db: DBM, hash: bytes, store: Optional[str] = None) -> Optional[Node return node -def get_root_node(db: DBM, version: int, store: Optional[str] = None) -> Optional[Node]: +def get_root_node( + db: DBM, version: int, store: Optional[str] = None +) -> Optional[PersistedNode]: prefix = store_prefix(store) if store is not None else b"" hash = db.get(prefix + root_key(version)) if not hash: @@ -301,23 +306,23 @@ def iter_iavl_tree( prefix = store_prefix(store) if store is not None else b"" - def get_node(hash: bytes) -> Node: + def get_node(hash: bytes) -> PersistedNode: n, _ = decode_node(db.get(prefix + node_key(hash)), hash) return n - def prune_check(key: bytes) -> (bool, bool): - prune_left = start is not None and key <= start - prune_right = end is not None and key >= end + def prune_check(node: PersistedNode) -> (bool, bool): + prune_left = start is not None and node.key <= start + prune_right = end is not None and node.key >= end return prune_left, prune_right - for _, node in visit_iavl_nodes(get_node, prune_check, node_hash): + for node in visit_iavl_nodes(get_node, prune_check, node_hash): if node.is_leaf() and within_range(node.key, start, end): yield node.key, node.value def visit_iavl_nodes( - get_node: Callable[bytes, Node], - prune_check: Callable[bytes, Tuple[bool, bool]], + get_node: GetNode, + prune_check: Callable[PersistedNode, Tuple[bool, bool]], hash: bytes, preorder: bool = True, ): @@ -330,8 +335,8 @@ def visit_iavl_nodes( stack: List[bytes] = [hash] while stack: hash = stack.pop() - if isinstance(hash, tuple): - # already expanded, (hash, node) + if isinstance(hash, PersistedNode): + # the postorder case, it's already expanded as PersistedNode yield hash continue @@ -339,17 +344,17 @@ def visit_iavl_nodes( if not preorder: # postorder, visit later - stack.append((hash, node)) + stack.append(node) if not node.is_leaf(): - prune_left, prune_right = prune_check(node.key) + prune_left, prune_right = prune_check(node) if not prune_right: stack.append(node.right_node_ref) if not prune_left: stack.append(node.left_node_ref) if preorder: - yield hash, node + yield node def diff_iterators(it1, it2): diff --git a/iavl/visualize.py b/iavl/visualize.py index 14ca141..01719ec 100644 --- a/iavl/visualize.py +++ b/iavl/visualize.py @@ -5,10 +5,10 @@ from hexbytes import HexBytes from .iavl import NodeDB -from .utils import Node, decode_node, node_key +from .utils import PersistedNode, decode_node, node_key -def label(node: Node): +def label(node: PersistedNode): s = binascii.hexlify(node.key).decode() if len(s) > 10: s = s[:4] + "..." + s[-4:] @@ -25,11 +25,11 @@ def visualize_iavl( ) -> Digraph: g = Digraph(comment="IAVL Tree") - def get_node(hash: bytes) -> Node: + def get_node(hash: bytes) -> PersistedNode: n, _ = decode_node(db.get(prefix + node_key(hash)), hash) return n - def vis_node(hash: bytes, n: Node): + def vis_node(hash: bytes, n: PersistedNode): style = "solid" if n.version == version else "filled" g.node(HexBytes(hash).hex(), label=label(node), style=style) @@ -80,7 +80,7 @@ def vis_node(hash: bytes, n: Node): def visualize_pruned_nodes(successor, hashes, pruned, ndb: NodeDB): g = Digraph(comment="IAVL Tree") - def vis_node(n: Node): + def vis_node(n: PersistedNode): if n.version == successor: style = "solid" elif n.hash in pruned: diff --git a/tests/test_diff.py b/tests/test_diff.py index 4b5de86..892c4a4 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -1,54 +1,6 @@ -from typing import NamedTuple - import rocksdb -from iavl.diff import DiffOptions, diff_sorted, diff_tree, state_changes -from iavl.iavl import NodeDB, Tree - - -def diff_tree_collect(ndb: NodeDB, v1: int, v2: int, opts: DiffOptions): - orphaned = [] - new = [] - - for o, n in diff_tree(ndb.get, ndb.get_root_node(v1), ndb.get_root_node(v2), opts): - orphaned += o - new += n - - return orphaned, new - - -def test_diff_sorted(): - class MockNode(NamedTuple): - key: int - hash: int - - def m(*xs): - return [MockNode(x, x) for x in xs] - - assert (m(3, 4), m(1, 2), m(5, 6)) == diff_sorted(m(1, 2, 3, 4), m(3, 4, 5, 6)) - assert (m(3, 4), m(1, 2, 7, 8), m(5, 6)) == diff_sorted( - m(1, 2, 3, 4, 7, 8), m(3, 4, 5, 6) - ) - - -def test_diff_tree(tmp_path): - dbpath = tmp_path / "basic_ops" - dbpath.mkdir() - print("db", dbpath) - kvdb = rocksdb.DB(str(dbpath), rocksdb.Options(create_if_missing=True)) - db = NodeDB(kvdb) - - tree = Tree(db, 0) - assert not tree.set(b"hello", b"world") - tree.save_version() - - tree = Tree(db, 1) - assert tree.set(b"hello", b"world1") - assert not tree.set(b"hello1", b"world1") - tree.save_version() - - orphaned, new = diff_tree_collect(db, 1, 2, DiffOptions.full()) - assert len(orphaned) == 1 - assert len(new) == 3 +from iavl.diff import state_changes +from iavl.iavl import NodeDB def test_state_changes(tmp_path): @@ -63,5 +15,5 @@ def test_state_changes(tmp_path): db = NodeDB(kvdb) for i, changes in enumerate(ChangeSets): assert changes == state_changes( - db.get, db.get_root_node(i), db.get_root_node(i + 1) + db.get, i, i + 1, db.get_root_hash(i), db.get_root_hash(i + 1) ) From e0bfa3f28bbd41c19c98207b8da827008f9f98e1 Mon Sep 17 00:00:00 2001 From: HuangYi Date: Mon, 12 Dec 2022 16:48:30 +0800 Subject: [PATCH 2/6] remove unused parameter --- iavl/cli.py | 4 +--- iavl/diff.py | 2 +- tests/test_diff.py | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/iavl/cli.py b/iavl/cli.py index 9a29168..2b03989 100644 --- a/iavl/cli.py +++ b/iavl/cli.py @@ -443,9 +443,7 @@ def iter_state_changes( if end_version is not None and v >= end_version: break - yield pversion, v, hash, diff.state_changes( - ndb.get, pversion, v, prev_root, hash - ) + yield pversion, v, hash, diff.state_changes(ndb.get, pversion, prev_root, hash) pversion = v prev_root = hash diff --git a/iavl/diff.py b/iavl/diff.py index 82912d7..4f8df81 100644 --- a/iavl/diff.py +++ b/iavl/diff.py @@ -59,7 +59,7 @@ def split_operations(nodes1, nodes2) -> ChangeSet: return result -def state_changes(get_node: GetNode, version, successor, root, successor_root): +def state_changes(get_node: GetNode, version, root, successor_root): """ extract state changes from two versions of the iavl tree. diff --git a/tests/test_diff.py b/tests/test_diff.py index 892c4a4..0140dd4 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -15,5 +15,5 @@ def test_state_changes(tmp_path): db = NodeDB(kvdb) for i, changes in enumerate(ChangeSets): assert changes == state_changes( - db.get, i, i + 1, db.get_root_hash(i), db.get_root_hash(i + 1) + db.get, i, db.get_root_hash(i), db.get_root_hash(i + 1) ) From be60c7b74fa9a15b53c94a0cdf14d69e9c366a95 Mon Sep 17 00:00:00 2001 From: HuangYi Date: Mon, 12 Dec 2022 16:49:09 +0800 Subject: [PATCH 3/6] fix lint --- iavl/cli.py | 18 ++++++++++++++---- iavl/diff.py | 3 +-- iavl/iavl.py | 10 ++++++++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/iavl/cli.py b/iavl/cli.py index 2b03989..5a658b5 100644 --- a/iavl/cli.py +++ b/iavl/cli.py @@ -10,10 +10,20 @@ from . import dbm, diff from .iavl import NodeDB, Tree, delete_version -from .utils import (decode_fast_node, diff_iterators, encode_stdint, - fast_node_key, get_node, get_root_node, - iavl_latest_version, iter_fast_nodes, iter_iavl_tree, - load_commit_infos, root_key, store_prefix) +from .utils import ( + decode_fast_node, + diff_iterators, + encode_stdint, + fast_node_key, + get_node, + get_root_node, + iavl_latest_version, + iter_fast_nodes, + iter_iavl_tree, + load_commit_infos, + root_key, + store_prefix, +) from .visualize import visualize_iavl, visualize_pruned_nodes diff --git a/iavl/diff.py b/iavl/diff.py index 4f8df81..fbd1d18 100644 --- a/iavl/diff.py +++ b/iavl/diff.py @@ -2,9 +2,8 @@ tree diff algorithm between two versions """ import binascii -from dataclasses import dataclass, field from enum import IntEnum -from typing import List, NamedTuple, Tuple +from typing import List, Tuple from cprotobuf import Field, ProtoEntity, decode_primitive, encode_primitive diff --git a/iavl/iavl.py b/iavl/iavl.py index 2c75641..b42f9f1 100644 --- a/iavl/iavl.py +++ b/iavl/iavl.py @@ -9,8 +9,14 @@ import rocksdb -from .utils import (GetNode, PersistedNode, encode_bytes, node_key, root_key, - visit_iavl_nodes) +from .utils import ( + GetNode, + PersistedNode, + encode_bytes, + node_key, + root_key, + visit_iavl_nodes, +) NodeRef = Union[bytes, "Node"] From 2a66b7cd5f56829e3db34cb6ace7e9160077ab1e Mon Sep 17 00:00:00 2001 From: HuangYi Date: Mon, 12 Dec 2022 16:50:28 +0800 Subject: [PATCH 4/6] cleanup --- iavl/iavl.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/iavl/iavl.py b/iavl/iavl.py index b42f9f1..cef2eb1 100644 --- a/iavl/iavl.py +++ b/iavl/iavl.py @@ -142,7 +142,6 @@ def delete_version(self, v: int) -> int: self.get, v, predecessor, - successor, self.get_root_hash(v), self.get_root_hash(successor), ): @@ -506,7 +505,6 @@ def delete_version( get_node: GetNode, v: int, predecessor: int, - successor: int, root: bytes, successor_root: bytes, ) -> int: From 20438aa2644943860e96d52519b7493f167840e2 Mon Sep 17 00:00:00 2001 From: yihuang Date: Tue, 13 Dec 2022 09:57:14 +0800 Subject: [PATCH 5/6] Update iavl/cli.py Co-authored-by: mmsqe Signed-off-by: yihuang --- iavl/cli.py | 1 - 1 file changed, 1 deletion(-) diff --git a/iavl/cli.py b/iavl/cli.py index 5a658b5..d7c8ecf 100644 --- a/iavl/cli.py +++ b/iavl/cli.py @@ -492,7 +492,6 @@ def trace_get(hash): trace_get, version, predecessor, - successor, root1, root2, ): From 90b0610e44f93e9a4b2f44be071f8c840d8429fc Mon Sep 17 00:00:00 2001 From: HuangYi Date: Tue, 13 Dec 2022 09:58:48 +0800 Subject: [PATCH 6/6] cleanup --- iavl/iavl.py | 2 +- iavl/utils.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iavl/iavl.py b/iavl/iavl.py index cef2eb1..d6166e3 100644 --- a/iavl/iavl.py +++ b/iavl/iavl.py @@ -507,7 +507,7 @@ def delete_version( predecessor: int, root: bytes, successor_root: bytes, -) -> int: +): """ yield the orphaned nodes to delete diff --git a/iavl/utils.py b/iavl/utils.py index a77f67e..fa3179a 100644 --- a/iavl/utils.py +++ b/iavl/utils.py @@ -334,13 +334,13 @@ def visit_iavl_nodes( """ stack: List[bytes] = [hash] while stack: - hash = stack.pop() - if isinstance(hash, PersistedNode): + hash_or_node = stack.pop() + if isinstance(hash_or_node, PersistedNode): # the postorder case, it's already expanded as PersistedNode - yield hash + yield hash_or_node continue - node = get_node(hash) + node = get_node(hash_or_node) if not preorder: # postorder, visit later