b-tree: fix corruption bug when inserting an entry in the middle of a node
This commit is contained in:
25
src/b-tree.c
25
src/b-tree.c
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user