]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/btree.c
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2007, Silicon Graphics, Inc. Barry Naujok <bnaujok@sgi.com>
11 * Maximum number of keys per node. Must be greater than 2 for the code
14 #define BTREE_KEY_MAX 7
15 #define BTREE_KEY_MIN (BTREE_KEY_MAX / 2)
17 #define BTREE_PTR_MAX (BTREE_KEY_MAX + 1)
20 unsigned long num_keys
;
21 unsigned long keys
[BTREE_KEY_MAX
];
22 struct btree_node
*ptrs
[BTREE_PTR_MAX
];
26 struct btree_node
*node
;
31 struct btree_node
*root_node
;
32 struct btree_cursor
*cursor
; /* track path to end leaf */
35 int keys_valid
; /* set if the cache is valid */
36 unsigned long cur_key
;
37 unsigned long next_key
;
39 unsigned long prev_key
;
43 unsigned long num_items
;
44 unsigned long max_items
;
68 static struct btree_node
*
69 btree_node_alloc(void)
71 return calloc(1, sizeof(struct btree_node
));
76 struct btree_node
*node
)
83 struct btree_node
*node
,
89 for (i
= 0; i
<= node
->num_keys
; i
++)
90 btree_free_nodes(node
->ptrs
[i
], level
- 1);
91 btree_node_free(node
);
96 struct btree_root
*root
)
98 memset(root
, 0, sizeof(struct btree_root
));
100 root
->cursor
= calloc(1, sizeof(struct btree_cursor
));
101 root
->root_node
= btree_node_alloc();
102 ASSERT(root
->root_node
);
104 root
->stats
.max_items
= 1;
105 root
->stats
.alloced
+= 1;
111 struct btree_root
*root
)
113 btree_free_nodes(root
->root_node
, root
->height
- 1);
117 root
->root_node
= NULL
;
122 struct btree_root
**root
)
124 *root
= calloc(1, sizeof(struct btree_root
));
130 struct btree_root
*root
)
138 struct btree_root
*root
)
146 struct btree_root
*root
)
148 return root
->root_node
->num_keys
== 0;
152 btree_invalidate_cursor(
153 struct btree_root
*root
)
155 root
->cursor
[0].node
= NULL
;
156 root
->keys_valid
= 0;
159 static inline unsigned long
161 struct btree_cursor
*cursor
,
164 while (cursor
->node
->num_keys
== cursor
->index
&& --height
> 0)
166 return cursor
->node
->keys
[cursor
->index
];
171 struct btree_root
*root
,
174 struct btree_cursor
*cur
= root
->cursor
;
176 struct btree_node
*node
;
178 if (cur
->index
> 0) {
180 *key
= cur
->node
->keys
[cur
->index
- 1];
181 return cur
->node
->ptrs
[cur
->index
- 1];
184 /* else need to go up and back down the tree to find the previous */
189 } while (++level
< root
->height
);
191 if (level
== root
->height
)
194 /* the key is in the current level */
196 *key
= cur
->node
->keys
[cur
->index
- 1];
198 /* descend back down the right side to get the pointer */
199 node
= cur
->node
->ptrs
[cur
->index
- 1];
201 node
= node
->ptrs
[node
->num_keys
];
207 struct btree_root
*root
,
210 struct btree_cursor
*cur
= root
->cursor
;
212 struct btree_node
*node
;
214 while (cur
->index
== cur
->node
->num_keys
) {
215 if (++level
== root
->height
)
222 *key
= btree_key_of_cursor(cur
, root
->height
);
225 return cur
->node
->ptrs
[cur
->index
+ 1];
228 node
= cur
->node
->ptrs
[cur
->index
+ 1];
230 node
= node
->ptrs
[0];
232 *key
= node
->keys
[0];
233 return node
->ptrs
[0];
237 * Lookup/Search functions
242 struct btree_root
*root
,
246 struct btree_cursor
*cur
= root
->cursor
+ root
->height
;
247 struct btree_node
*node
= root
->root_node
;
248 int height
= root
->height
;
252 while (--height
>= 0) {
254 for (i
= 0; i
< node
->num_keys
; i
++)
255 if (node
->keys
[i
] >= key
) {
262 node
= node
->ptrs
[i
];
264 root
->keys_valid
= key_found
;
269 root
->next_value
= NULL
; /* do on-demand next value lookup */
270 root
->prev_value
= btree_get_prev(root
, &root
->prev_key
);
276 struct btree_root
*root
,
279 if (root
->keys_valid
&& key
<= root
->cur_key
&&
280 (!root
->prev_value
|| key
> root
->prev_key
)) {
282 root
->stats
.cache_hits
++;
287 root
->stats
.cache_misses
++;
289 return btree_do_search(root
, key
);
294 struct btree_root
*root
,
296 unsigned long *actual_key
)
299 root
->stats
.find
+= 1;
301 if (!btree_search(root
, key
))
305 *actual_key
= root
->cur_key
;
306 return root
->cursor
->node
->ptrs
[root
->cursor
->index
];
311 struct btree_root
*root
,
315 root
->stats
.lookup
+= 1;
317 if (!btree_search(root
, key
) || root
->cur_key
!= key
)
319 return root
->cursor
->node
->ptrs
[root
->cursor
->index
];
324 struct btree_root
*root
,
327 if (!root
->keys_valid
)
330 *key
= root
->prev_key
;
331 return root
->prev_value
;
336 struct btree_root
*root
,
339 if (!root
->keys_valid
)
341 if (!root
->next_value
)
342 root
->next_value
= btree_get_next(root
, &root
->next_key
);
344 *key
= root
->next_key
;
345 return root
->next_value
;
349 btree_move_cursor_to_next(
350 struct btree_root
*root
,
353 struct btree_cursor
*cur
= root
->cursor
;
356 while (cur
->index
== cur
->node
->num_keys
) {
357 if (++level
== root
->height
)
364 *key
= btree_key_of_cursor(cur
, root
->height
);
365 return cur
->node
->ptrs
[cur
->index
];
368 while (--level
>= 0) {
369 root
->cursor
[level
].node
= cur
->node
->ptrs
[cur
->index
];
370 root
->cursor
[level
].index
= 0;
374 *key
= cur
->node
->keys
[0];
375 return cur
->node
->ptrs
[0];
380 struct btree_root
*root
,
385 if (!root
->keys_valid
)
388 root
->prev_key
= root
->cur_key
;
389 root
->prev_value
= root
->cursor
->node
->ptrs
[root
->cursor
->index
];
391 value
= btree_move_cursor_to_next(root
, &root
->cur_key
);
393 btree_invalidate_cursor(root
);
396 root
->next_value
= NULL
; /* on-demand next value fetch */
398 *key
= root
->cur_key
;
403 btree_move_cursor_to_prev(
404 struct btree_root
*root
,
407 struct btree_cursor
*cur
= root
->cursor
;
410 while (cur
->index
== 0) {
411 if (++level
== root
->height
)
416 if (key
) /* the key is in the current level */
417 *key
= cur
->node
->keys
[cur
->index
];
420 root
->cursor
[level
].node
= cur
->node
->ptrs
[cur
->index
];
421 root
->cursor
[level
].index
= root
->cursor
[level
].node
->num_keys
;
424 return cur
->node
->ptrs
[cur
->index
];
429 struct btree_root
*root
,
434 if (!root
->keys_valid
)
437 value
= btree_move_cursor_to_prev(root
, &root
->cur_key
);
440 root
->prev_value
= btree_get_prev(root
, &root
->prev_key
);
441 root
->next_value
= NULL
; /* on-demand next value fetch */
443 *key
= root
->cur_key
;
448 btree_uncached_lookup(
449 struct btree_root
*root
,
452 /* cursor-less (ie. uncached) lookup */
453 int height
= root
->height
- 1;
454 struct btree_node
*node
= root
->root_node
;
458 while (height
>= 0) {
459 for (i
= 0; i
< node
->num_keys
; i
++)
460 if (node
->keys
[i
] >= key
) {
461 key_found
= node
->keys
[i
] == key
;
464 node
= node
->ptrs
[i
];
467 return key_found
? node
: NULL
;
470 /* Update functions */
473 btree_update_node_key(
474 struct btree_root
*root
,
475 struct btree_cursor
*cursor
,
477 unsigned long new_key
)
482 root
->stats
.key_update
+= 1;
486 for (i
= level
; i
< root
->height
; i
++) {
487 if (cursor
->index
< cursor
->node
->num_keys
) {
488 cursor
->node
->keys
[cursor
->index
] = new_key
;
497 struct btree_root
*root
,
498 unsigned long old_key
,
499 unsigned long new_key
)
501 if (!btree_search(root
, old_key
) || root
->cur_key
!= old_key
)
504 if (root
->next_value
&& new_key
>= root
->next_key
)
507 if (root
->prev_value
&& new_key
<= root
->prev_key
)
510 btree_update_node_key(root
, root
->cursor
, 0, new_key
);
511 root
->cur_key
= new_key
;
518 struct btree_root
*root
,
525 if (!btree_search(root
, key
) || root
->cur_key
!= key
)
529 root
->stats
.value_update
+= 1;
531 root
->cursor
->node
->ptrs
[root
->cursor
->index
] = new_value
;
537 * Cursor modification functions - used for inserting and deleting
540 static struct btree_cursor
*
541 btree_copy_cursor_prev(
542 struct btree_root
*root
,
543 struct btree_cursor
*dest_cursor
,
546 struct btree_cursor
*src_cur
= root
->cursor
+ level
;
547 struct btree_cursor
*dst_cur
;
551 if (level
>= root
->height
)
554 while (src_cur
->index
== 0) {
555 if (++l
>= root
->height
)
559 for (i
= l
; i
< root
->height
; i
++)
560 dest_cursor
[i
] = *src_cur
++;
562 dst_cur
= dest_cursor
+ l
;
564 while (l
-- >= level
) {
565 dest_cursor
[l
].node
= dst_cur
->node
->ptrs
[dst_cur
->index
];
566 dest_cursor
[l
].index
= dest_cursor
[l
].node
->num_keys
;
572 static struct btree_cursor
*
573 btree_copy_cursor_next(
574 struct btree_root
*root
,
575 struct btree_cursor
*dest_cursor
,
578 struct btree_cursor
*src_cur
= root
->cursor
+ level
;
579 struct btree_cursor
*dst_cur
;
583 if (level
>= root
->height
)
586 while (src_cur
->index
== src_cur
->node
->num_keys
) {
587 if (++l
>= root
->height
)
591 for (i
= l
; i
< root
->height
; i
++)
592 dest_cursor
[i
] = *src_cur
++;
594 dst_cur
= dest_cursor
+ l
;
596 while (l
-- >= level
) {
597 dest_cursor
[l
].node
= dst_cur
->node
->ptrs
[dst_cur
->index
];
598 dest_cursor
[l
].index
= 0;
607 * Tries to move items in the current leaf to its sibling if it has space.
608 * Used in both insert and delete functions.
609 * Returns the number of items shifted.
614 struct btree_root
*root
,
616 struct btree_cursor
*prev_cursor
,
619 struct btree_node
*node
;
620 struct btree_node
*prev_node
;
621 int num_remain
; /* # of keys left in "node" */
625 if (!prev_cursor
|| !num_children
)
628 prev_node
= prev_cursor
[level
].node
;
629 node
= root
->cursor
[level
].node
;
631 ASSERT(num_children
> 0 && num_children
<= node
->num_keys
+ 1);
633 if ((prev_node
->num_keys
+ num_children
) > BTREE_KEY_MAX
)
637 root
->stats
.shift_prev
+= 1;
640 num_remain
= node
->num_keys
- num_children
;
641 ASSERT(num_remain
== -1 || num_remain
>= BTREE_KEY_MIN
);
643 /* shift parent keys around */
646 key
= node
->keys
[num_children
- 1];
648 key
= btree_key_of_cursor(root
->cursor
+ level
,
649 root
->height
- level
);
650 while (prev_cursor
[level
].index
== prev_cursor
[level
].node
->num_keys
) {
652 ASSERT(level
< root
->height
);
654 prev_node
->keys
[prev_node
->num_keys
] =
655 prev_cursor
[level
].node
->keys
[prev_cursor
[level
].index
];
656 prev_cursor
[level
].node
->keys
[prev_cursor
[level
].index
] = key
;
658 /* copy pointers and keys to the end of the prev node */
659 for (i
= 0; i
< num_children
- 1; i
++) {
660 prev_node
->keys
[prev_node
->num_keys
+ 1 + i
] = node
->keys
[i
];
661 prev_node
->ptrs
[prev_node
->num_keys
+ 1 + i
] = node
->ptrs
[i
];
663 prev_node
->ptrs
[prev_node
->num_keys
+ 1 + i
] = node
->ptrs
[i
];
664 prev_node
->num_keys
+= num_children
;
666 /* move remaining pointers/keys to start of node */
667 if (num_remain
>= 0) {
668 for (i
= 0; i
< num_remain
; i
++) {
669 node
->keys
[i
] = node
->keys
[num_children
+ i
];
670 node
->ptrs
[i
] = node
->ptrs
[num_children
+ i
];
672 node
->ptrs
[i
] = node
->ptrs
[num_children
+ i
];
673 node
->num_keys
= num_remain
;
682 struct btree_root
*root
,
684 struct btree_cursor
*next_cursor
,
687 struct btree_node
*node
;
688 struct btree_node
*next_node
;
689 int num_remain
; /* # of children left in node */
692 if (!next_cursor
|| !num_children
)
695 node
= root
->cursor
[level
].node
;
696 next_node
= next_cursor
[level
].node
;
698 ASSERT(num_children
> 0 && num_children
<= node
->num_keys
+ 1);
700 if ((next_node
->num_keys
+ num_children
) > BTREE_KEY_MAX
)
703 num_remain
= node
->num_keys
+ 1 - num_children
;
704 ASSERT(num_remain
== 0 || num_remain
> BTREE_KEY_MIN
);
707 root
->stats
.shift_next
+= 1;
710 /* make space for "num_children" items at beginning of next-leaf */
711 i
= next_node
->num_keys
;
712 next_node
->ptrs
[num_children
+ i
] = next_node
->ptrs
[i
];
714 next_node
->keys
[num_children
+ i
] = next_node
->keys
[i
];
715 next_node
->ptrs
[num_children
+ i
] = next_node
->ptrs
[i
];
718 /* update keys in parent and next node from parent */
721 ASSERT(level
< root
->height
);
722 } while (root
->cursor
[level
].index
==
723 root
->cursor
[level
].node
->num_keys
);
725 next_node
->keys
[num_children
- 1] =
726 root
->cursor
[level
].node
->keys
[root
->cursor
[level
].index
];
727 root
->cursor
[level
].node
->keys
[root
->cursor
[level
].index
] =
728 node
->keys
[node
->num_keys
- num_children
];
730 /* copy last "num_children" items from node into start of next-node */
731 for (i
= 0; i
< num_children
- 1; i
++) {
732 next_node
->keys
[i
] = node
->keys
[num_remain
+ i
];
733 next_node
->ptrs
[i
] = node
->ptrs
[num_remain
+ i
];
735 next_node
->ptrs
[i
] = node
->ptrs
[num_remain
+ i
];
736 next_node
->num_keys
+= num_children
;
739 node
->num_keys
-= num_children
;
747 * Insertion functions
750 static struct btree_node
*
751 btree_increase_height(
752 struct btree_root
*root
)
754 struct btree_node
*new_root
;
755 struct btree_cursor
*new_cursor
;
757 new_cursor
= realloc(root
->cursor
, (root
->height
+ 1) *
758 sizeof(struct btree_cursor
));
761 root
->cursor
= new_cursor
;
763 new_root
= btree_node_alloc();
768 root
->stats
.alloced
+= 1;
769 root
->stats
.inc_height
+= 1;
770 root
->stats
.max_items
*= BTREE_PTR_MAX
;
773 new_root
->ptrs
[0] = root
->root_node
;
774 root
->root_node
= new_root
;
776 root
->cursor
[root
->height
].node
= new_root
;
777 root
->cursor
[root
->height
].index
= 0;
786 struct btree_root
*root
,
792 static struct btree_node
*
794 struct btree_root
*root
,
799 struct btree_node
*node
= root
->cursor
[level
].node
;
800 struct btree_node
*new_node
;
803 new_node
= btree_node_alloc();
807 if (btree_insert_item(root
, level
+ 1, node
->keys
[BTREE_KEY_MIN
],
809 btree_node_free(new_node
);
814 root
->stats
.alloced
+= 1;
815 root
->stats
.split
+= 1;
818 for (i
= 0; i
< BTREE_KEY_MAX
- BTREE_KEY_MIN
- 1; i
++) {
819 new_node
->keys
[i
] = node
->keys
[BTREE_KEY_MIN
+ 1 + i
];
820 new_node
->ptrs
[i
] = node
->ptrs
[BTREE_KEY_MIN
+ 1 + i
];
822 new_node
->ptrs
[i
] = node
->ptrs
[BTREE_KEY_MIN
+ 1 + i
];
823 new_node
->num_keys
= BTREE_KEY_MAX
- BTREE_KEY_MIN
- 1;
825 node
->num_keys
= BTREE_KEY_MIN
;
826 if (key
< node
->keys
[BTREE_KEY_MIN
])
827 return node
; /* index doesn't change */
829 /* insertion point is in new node... */
830 *index
-= BTREE_KEY_MIN
+ 1;
835 btree_insert_shift_to_prev(
836 struct btree_root
*root
,
840 struct btree_cursor tmp_cursor
[root
->height
];
846 if (!btree_copy_cursor_prev(root
, tmp_cursor
, level
+ 1))
849 n
= MIN(*index
, (BTREE_PTR_MAX
- tmp_cursor
[level
].node
->num_keys
) / 2);
850 if (!n
|| !btree_shift_to_prev(root
, level
, tmp_cursor
, n
))
858 btree_insert_shift_to_next(
859 struct btree_root
*root
,
863 struct btree_cursor tmp_cursor
[root
->height
];
866 if (*index
>= BTREE_KEY_MAX
)
869 if (!btree_copy_cursor_next(root
, tmp_cursor
, level
+ 1))
872 n
= MIN(BTREE_KEY_MAX
- *index
,
873 (BTREE_PTR_MAX
- tmp_cursor
[level
].node
->num_keys
) / 2);
874 if (!n
|| !btree_shift_to_next(root
, level
, tmp_cursor
, n
))
881 struct btree_root
*root
,
886 struct btree_node
*node
= root
->cursor
[level
].node
;
887 int index
= root
->cursor
[level
].index
;
890 if (node
->num_keys
== BTREE_KEY_MAX
) {
891 if (btree_insert_shift_to_prev(root
, level
, &index
) == 0)
893 if (btree_insert_shift_to_next(root
, level
, &index
) == 0)
895 if (level
== root
->height
- 1) {
896 if (!btree_increase_height(root
))
899 node
= btree_split(root
, level
, key
, &index
);
904 ASSERT(index
<= node
->num_keys
);
907 node
->ptrs
[i
+ 1] = node
->ptrs
[i
];
908 while (--i
>= index
) {
909 node
->keys
[i
+ 1] = node
->keys
[i
];
910 node
->ptrs
[i
+ 1] = node
->ptrs
[i
];
914 node
->keys
[index
] = key
;
917 node
->ptrs
[index
] = value
;
919 node
->ptrs
[index
+ 1] = value
;
928 struct btree_root
*root
,
937 if (btree_search(root
, key
) && root
->cur_key
== key
)
941 root
->stats
.insert
+= 1;
942 root
->stats
.num_items
+= 1;
945 result
= btree_insert_item(root
, 0, key
, value
);
947 btree_invalidate_cursor(root
);
956 * Rather more complicated as deletions has 4 ways to go once a node
957 * ends up with less than the minimum number of keys:
958 * - move remainder to previous node
959 * - move remainder to next node
960 * (both will involve a parent deletion which may recurse)
961 * - balance by moving some items from previous node
962 * - balance by moving some items from next node
966 btree_decrease_height(
967 struct btree_root
*root
)
969 struct btree_node
*old_root
= root
->root_node
;
971 ASSERT(old_root
->num_keys
== 0);
974 root
->stats
.alloced
-= 1;
975 root
->stats
.dec_height
+= 1;
976 root
->stats
.max_items
/= BTREE_PTR_MAX
;
978 root
->root_node
= old_root
->ptrs
[0];
979 btree_node_free(old_root
);
984 btree_merge_with_prev(
985 struct btree_root
*root
,
987 struct btree_cursor
*prev_cursor
)
992 if (!btree_shift_to_prev(root
, level
, prev_cursor
,
993 root
->cursor
[level
].node
->num_keys
+ 1))
997 root
->stats
.merge_prev
+= 1;
1003 btree_merge_with_next(
1004 struct btree_root
*root
,
1006 struct btree_cursor
*next_cursor
)
1011 if (!btree_shift_to_next(root
, level
, next_cursor
,
1012 root
->cursor
[level
].node
->num_keys
+ 1))
1016 root
->stats
.merge_next
+= 1;
1022 btree_balance_with_prev(
1023 struct btree_root
*root
,
1025 struct btree_cursor
*prev_cursor
)
1027 struct btree_cursor
*root_cursor
= root
->cursor
;
1031 ASSERT(prev_cursor
[level
].node
->num_keys
> BTREE_KEY_MIN
);
1034 root
->stats
.balance_prev
+= 1;
1037 * Move some nodes from the prev node into the current node.
1038 * As the shift operation is a right shift and is relative to
1039 * the root cursor, make the root cursor the prev cursor and
1040 * pass in the root cursor as the next cursor.
1043 root
->cursor
= prev_cursor
;
1044 if (!btree_shift_to_next(root
, level
, root_cursor
,
1045 (prev_cursor
[level
].node
->num_keys
+ 1 - BTREE_KEY_MIN
) / 2))
1047 root
->cursor
= root_cursor
;
1053 btree_balance_with_next(
1054 struct btree_root
*root
,
1056 struct btree_cursor
*next_cursor
)
1058 struct btree_cursor
*root_cursor
= root
->cursor
;
1062 assert(next_cursor
[level
].node
->num_keys
> BTREE_KEY_MIN
);
1065 root
->stats
.balance_next
+= 1;
1068 * move some nodes from the next node into the current node.
1069 * as the shift operation is a left shift and is relative to
1070 * the root cursor, make the root cursor the next cursor and
1071 * pass in the root cursor as the prev cursor.
1074 root
->cursor
= next_cursor
;
1075 if (!btree_shift_to_prev(root
, level
, root_cursor
,
1076 (next_cursor
[level
].node
->num_keys
+ 1 - BTREE_KEY_MIN
) / 2))
1078 root
->cursor
= root_cursor
;
1086 struct btree_root
*root
,
1090 * btree_delete_node:
1092 * Return 0 if it's done or 1 if the next level needs to be collapsed
1096 struct btree_root
*root
,
1099 struct btree_cursor prev_cursor
[root
->height
];
1100 struct btree_cursor next_cursor
[root
->height
];
1101 struct btree_cursor
*pc
;
1102 struct btree_cursor
*nc
;
1105 * the node has underflowed, grab or merge keys/items from a
1106 * neighbouring node.
1109 if (level
== root
->height
- 1) {
1110 if (level
> 0 && root
->root_node
->num_keys
== 0)
1111 btree_decrease_height(root
);
1115 pc
= btree_copy_cursor_prev(root
, prev_cursor
, level
+ 1);
1116 if (!btree_merge_with_prev(root
, level
, pc
)) {
1117 nc
= btree_copy_cursor_next(root
, next_cursor
, level
+ 1);
1118 if (!btree_merge_with_next(root
, level
, nc
)) {
1119 /* merging failed, try redistrubution */
1120 if (!btree_balance_with_prev(root
, level
, pc
) &&
1121 !btree_balance_with_next(root
, level
, nc
))
1123 return; /* when balancing, then the node isn't freed */
1128 root
->stats
.alloced
-= 1;
1130 btree_node_free(root
->cursor
[level
].node
);
1132 btree_delete_key(root
, level
+ 1);
1137 struct btree_root
*root
,
1140 struct btree_node
*node
= root
->cursor
[level
].node
;
1141 int index
= root
->cursor
[level
].index
;
1144 if (index
<= node
->num_keys
) {
1146 * if not deleting the last item, shift higher items down
1147 * to cover the item being deleted
1149 while (index
< node
->num_keys
) {
1150 node
->keys
[index
] = node
->keys
[index
+ 1];
1151 node
->ptrs
[index
] = node
->ptrs
[index
+ 1];
1154 node
->ptrs
[index
] = node
->ptrs
[index
+ 1];
1157 * else update the associated parent key as the last key
1158 * in the leaf has changed
1160 btree_update_node_key(root
, root
->cursor
, level
+ 1,
1161 node
->keys
[node
->num_keys
]);
1164 * if node underflows, either merge with sibling or rebalance
1167 if (node
->num_keys
< BTREE_KEY_MIN
)
1168 btree_delete_node(root
, level
);
1173 struct btree_root
*root
,
1178 value
= btree_lookup(root
, key
);
1183 root
->stats
.delete += 1;
1184 root
->stats
.num_items
-= 1;
1187 btree_delete_key(root
, 0);
1189 btree_invalidate_cursor(root
);
1197 struct btree_root
*root
,
1200 unsigned long max_items
= root
->stats
.max_items
*
1201 (root
->root_node
->num_keys
+ 1);
1203 fprintf(f
, "\tnum_items = %lu, max_items = %lu (%lu%%)\n",
1204 root
->stats
.num_items
, max_items
,
1205 root
->stats
.num_items
* 100 / max_items
);
1206 fprintf(f
, "\talloced = %d nodes, %lu bytes, %lu bytes per item\n",
1207 root
->stats
.alloced
,
1208 root
->stats
.alloced
* sizeof(struct btree_node
),
1209 root
->stats
.alloced
* sizeof(struct btree_node
) /
1210 root
->stats
.num_items
);
1211 fprintf(f
, "\tlookup = %d\n", root
->stats
.lookup
);
1212 fprintf(f
, "\tfind = %d\n", root
->stats
.find
);
1213 fprintf(f
, "\tcache_hits = %d\n", root
->stats
.cache_hits
);
1214 fprintf(f
, "\tcache_misses = %d\n", root
->stats
.cache_misses
);
1215 fprintf(f
, "\tkey_update = %d\n", root
->stats
.key_update
);
1216 fprintf(f
, "\tvalue_update = %d\n", root
->stats
.value_update
);
1217 fprintf(f
, "\tinsert = %d\n", root
->stats
.insert
);
1218 fprintf(f
, "\tshift_prev = %d\n", root
->stats
.shift_prev
);
1219 fprintf(f
, "\tshift_next = %d\n", root
->stats
.shift_next
);
1220 fprintf(f
, "\tsplit = %d\n", root
->stats
.split
);
1221 fprintf(f
, "\tinc_height = %d\n", root
->stats
.inc_height
);
1222 fprintf(f
, "\tdelete = %d\n", root
->stats
.delete);
1223 fprintf(f
, "\tmerge_prev = %d\n", root
->stats
.merge_prev
);
1224 fprintf(f
, "\tmerge_next = %d\n", root
->stats
.merge_next
);
1225 fprintf(f
, "\tbalance_prev = %d\n", root
->stats
.balance_prev
);
1226 fprintf(f
, "\tbalance_next = %d\n", root
->stats
.balance_next
);
1227 fprintf(f
, "\tdec_height = %d\n", root
->stats
.dec_height
);