b-tree: fix corruption bug when inserting an entry in the middle of a node

This commit is contained in:
2025-04-26 21:23:50 +01:00
parent 4b790d855f
commit d5df4d593f

View File

@@ -180,8 +180,10 @@ static void node_shift_entries(
unsigned long count = nr_entries - shift_from; unsigned long count = nr_entries - shift_from;
for (unsigned long i = 0; i < count; i++) { for (unsigned long i = 0; i < count; i++) {
b_tree_node_entry *entry = node_get_entry(tree, node, src + i); unsigned long from = (src + count - 1) - i;
node_set_entry(tree, node, dest + i, entry); 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) { if (shift_by < 0) {
@@ -323,15 +325,28 @@ static int node_put(
} }
int insert_at = -1; int insert_at = -1;
bool exact_match = false;
for (unsigned long i = 0; i < nr_entries; i++) { for (unsigned long i = 0; i < nr_entries; i++) {
const b_tree_node_entry *cur = node_get_entry(tree, n, i); const b_tree_node_entry *cur = node_get_entry(tree, n, i);
int cmp = entry_compare(tree, cur, e); int cmp = entry_compare(tree, cur, e);
if (cmp == 0) {
insert_at = i;
exact_match = true;
break;
}
if (cmp == 1) { if (cmp == 1) {
insert_at = i; insert_at = i;
break; break;
} }
} }
if (exact_match) {
node_set_entry(tree, n, insert_at, e);
return insert_at;
}
if (insert_at != -1) { if (insert_at != -1) {
node_shift_entries(tree, n, insert_at, 1); node_shift_entries(tree, n, insert_at, 1);
} else { } 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. */ /* this node is full, split it. */
/* half the nodes from `next` will be moved into `n3`. the other /* half the nodes from `next` will be moved into `n3`.
half will stay put. the median entry will be moved to the other half will stay put. the median entry will
`current`. be moved to `current`.
`n3` will become the right sibling of `next` */ `n3` will become the right sibling of `next` */
b_tree_node *n3 = cache_alloc_node(tree); b_tree_node *n3 = cache_alloc_node(tree);