From d5df4d593f1cbaab82880981ce7605a428439748 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 26 Apr 2025 21:23:50 +0100 Subject: [PATCH] b-tree: fix corruption bug when inserting an entry in the middle of a node --- src/b-tree.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/b-tree.c b/src/b-tree.c index 304632b..3179962 100644 --- a/src/b-tree.c +++ b/src/b-tree.c @@ -180,8 +180,10 @@ static void node_shift_entries( unsigned long count = nr_entries - shift_from; for (unsigned long i = 0; i < count; i++) { - b_tree_node_entry *entry = node_get_entry(tree, node, src + i); - node_set_entry(tree, node, dest + i, entry); + unsigned long from = (src + count - 1) - i; + unsigned long to = (dest + count - 1) - i; + b_tree_node_entry *entry = node_get_entry(tree, node, from); + node_set_entry(tree, node, to, entry); } if (shift_by < 0) { @@ -323,15 +325,28 @@ static int node_put( } int insert_at = -1; + bool exact_match = false; + for (unsigned long i = 0; i < nr_entries; i++) { const b_tree_node_entry *cur = node_get_entry(tree, n, i); int cmp = entry_compare(tree, cur, e); + if (cmp == 0) { + insert_at = i; + exact_match = true; + break; + } + if (cmp == 1) { insert_at = i; break; } } + if (exact_match) { + node_set_entry(tree, n, insert_at, e); + return insert_at; + } + if (insert_at != -1) { node_shift_entries(tree, n, insert_at, 1); } else { @@ -443,9 +458,9 @@ int b_tree_put(struct b_tree *tree, const b_tree_node_entry *to_put) /* this node is full, split it. */ - /* half the nodes from `next` will be moved into `n3`. the other - half will stay put. the median entry will be moved to - `current`. + /* half the nodes from `next` will be moved into `n3`. + the other half will stay put. the median entry will + be moved to `current`. `n3` will become the right sibling of `next` */ b_tree_node *n3 = cache_alloc_node(tree);