Finished implementing B+ trees
This commit is contained in:
108
src/bplus_tree.c
108
src/bplus_tree.c
@@ -234,6 +234,9 @@ BPlusNode *bplus_tree_find_leaf(BPlusTree *tree, uint64_t key) {
|
|||||||
bool bplus_tree_insert(BPlusTree *tree, uint64_t newKey, void *newValue) {
|
bool bplus_tree_insert(BPlusTree *tree, uint64_t newKey, void *newValue) {
|
||||||
BPlusNode *node = bplus_tree_find_leaf(tree, newKey);
|
BPlusNode *node = bplus_tree_find_leaf(tree, newKey);
|
||||||
assert(node != NULL && node->isInternal == false);
|
assert(node != NULL && node->isInternal == false);
|
||||||
|
#ifdef BTREE_DEBUG
|
||||||
|
_bplus_tree_check_parents(tree);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (node->keyCount < node->order - 1) {
|
if (node->keyCount < node->order - 1) {
|
||||||
//Can insert at this node
|
//Can insert at this node
|
||||||
@@ -317,6 +320,9 @@ bool bplus_tree_insert(BPlusTree *tree, uint64_t newKey, void *newValue) {
|
|||||||
bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
|
bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
|
||||||
BPlusNode *leaf = bplus_tree_find_leaf(tree, key);
|
BPlusNode *leaf = bplus_tree_find_leaf(tree, key);
|
||||||
assert(leaf != NULL && leaf->isInternal == false);
|
assert(leaf != NULL && leaf->isInternal == false);
|
||||||
|
#ifdef BTREE_DEBUG
|
||||||
|
_bplus_tree_check_parents(tree);
|
||||||
|
#endif
|
||||||
|
|
||||||
//Find and remove kv
|
//Find and remove kv
|
||||||
bool removed = false;
|
bool removed = false;
|
||||||
@@ -348,6 +354,9 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
|
|||||||
BPlusKV *kv = leaf->rightLeaf->keys[0];
|
BPlusKV *kv = leaf->rightLeaf->keys[0];
|
||||||
assert(bplus_node_remove_kv(leaf->rightLeaf, kv));
|
assert(bplus_node_remove_kv(leaf->rightLeaf, kv));
|
||||||
assert(bplus_node_insert_kv(leaf, kv));
|
assert(bplus_node_insert_kv(leaf, kv));
|
||||||
|
if (kv->rightPointer != NULL) {
|
||||||
|
kv->rightPointer->parent = leaf;
|
||||||
|
}
|
||||||
//Update the right leafs parent pointer
|
//Update the right leafs parent pointer
|
||||||
for (size_t i = 0; i < leaf->parent->keyCount; i++) {
|
for (size_t i = 0; i < leaf->parent->keyCount; i++) {
|
||||||
if (leaf->parent->keys[i]->rightPointer == leaf->rightLeaf) {
|
if (leaf->parent->keys[i]->rightPointer == leaf->rightLeaf) {
|
||||||
@@ -366,6 +375,9 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
|
|||||||
BPlusKV *kv = leaf->leftLeaf->keys[leaf->keyCount - 1];
|
BPlusKV *kv = leaf->leftLeaf->keys[leaf->keyCount - 1];
|
||||||
assert(bplus_node_remove_kv(leaf->leftLeaf, kv));
|
assert(bplus_node_remove_kv(leaf->leftLeaf, kv));
|
||||||
assert(bplus_node_insert_kv(leaf, kv));
|
assert(bplus_node_insert_kv(leaf, kv));
|
||||||
|
if (kv->rightPointer != NULL) {
|
||||||
|
kv->rightPointer->parent = leaf;
|
||||||
|
}
|
||||||
//Update the key pointing to this leaf
|
//Update the key pointing to this leaf
|
||||||
for (size_t i = 0; i < leaf->parent->keyCount; i++) {
|
for (size_t i = 0; i < leaf->parent->keyCount; i++) {
|
||||||
if (leaf->parent->keys[i]->rightPointer == leaf) {
|
if (leaf->parent->keys[i]->rightPointer == leaf) {
|
||||||
@@ -385,8 +397,12 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
|
|||||||
&& leaf->keyCount + leaf->rightLeaf->keyCount < tree->order) {
|
&& leaf->keyCount + leaf->rightLeaf->keyCount < tree->order) {
|
||||||
//Move all keys from right leaf to this leaf
|
//Move all keys from right leaf to this leaf
|
||||||
while (leaf->rightLeaf->keyCount > 0) {
|
while (leaf->rightLeaf->keyCount > 0) {
|
||||||
assert(bplus_node_insert_kv(leaf, leaf->rightLeaf->keys[0]));
|
BPlusKV *kv = leaf->rightLeaf->keys[0];
|
||||||
assert(bplus_node_remove_kv(leaf->rightLeaf, leaf->rightLeaf->keys[0]));
|
assert(bplus_node_insert_kv(leaf, kv));
|
||||||
|
if (kv->rightPointer != NULL) {
|
||||||
|
kv->rightPointer = leaf;
|
||||||
|
}
|
||||||
|
assert(bplus_node_remove_kv(leaf->rightLeaf, kv));
|
||||||
}
|
}
|
||||||
//Remove right leaf and parent pointer
|
//Remove right leaf and parent pointer
|
||||||
for (size_t i = 0; i < leaf->parent->keyCount; i++) {
|
for (size_t i = 0; i < leaf->parent->keyCount; i++) {
|
||||||
@@ -395,7 +411,7 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
|
|||||||
//Remove key
|
//Remove key
|
||||||
bplus_node_remove_kv(leaf->parent, kv);
|
bplus_node_remove_kv(leaf->parent, kv);
|
||||||
//Update leaf pointers
|
//Update leaf pointers
|
||||||
leaf->rightLeaf = leaf->rightLeaf;
|
leaf->rightLeaf = leaf->rightLeaf->rightLeaf;
|
||||||
if (leaf->rightLeaf != NULL) {
|
if (leaf->rightLeaf != NULL) {
|
||||||
leaf->rightLeaf->leftLeaf = leaf;
|
leaf->rightLeaf->leftLeaf = leaf;
|
||||||
}
|
}
|
||||||
@@ -406,14 +422,16 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
|
|||||||
}
|
}
|
||||||
merged = true;
|
merged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Try left leaf
|
//Try left leaf
|
||||||
if (leaf->leftLeaf != NULL
|
else if (leaf->leftLeaf != NULL
|
||||||
&& leaf->parent == leaf->leftLeaf->parent
|
&& leaf->parent == leaf->leftLeaf->parent
|
||||||
&& leaf->keyCount + leaf->leftLeaf->keyCount < tree->order) {
|
&& leaf->keyCount + leaf->leftLeaf->keyCount < tree->order) {
|
||||||
//Move all keys into left leaf
|
//Move all keys into left leaf
|
||||||
while (leaf->keyCount > 0) {
|
while (leaf->keyCount > 0) {
|
||||||
assert(bplus_node_insert_kv(leaf->leftLeaf, leaf->keys[0]));
|
assert(bplus_node_insert_kv(leaf->leftLeaf, leaf->keys[0]));
|
||||||
|
if (leaf->keys[0]->rightPointer != NULL) {
|
||||||
|
leaf->keys[0]->rightPointer->parent = leaf->leftLeaf;
|
||||||
|
}
|
||||||
assert(bplus_node_remove_kv(leaf, leaf->keys[0]));
|
assert(bplus_node_remove_kv(leaf, leaf->keys[0]));
|
||||||
}
|
}
|
||||||
//Remove this leaf and parent pointer (if any)
|
//Remove this leaf and parent pointer (if any)
|
||||||
@@ -443,6 +461,31 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
|
|||||||
BPlusNode *node = leaf->parent;
|
BPlusNode *node = leaf->parent;
|
||||||
|
|
||||||
while (node != NULL) {
|
while (node != NULL) {
|
||||||
|
//Merge has emptied the parent, promote keys from left pointer to this node
|
||||||
|
if (node->keyCount == 0) {
|
||||||
|
BPlusNode *leftChild = node->leftPointer;
|
||||||
|
if (leftChild->keyCount > 0) {
|
||||||
|
while (leftChild->keyCount > 0) {
|
||||||
|
BPlusKV *moveKV = leftChild->keys[0];
|
||||||
|
bplus_node_insert_kv(node, moveKV);
|
||||||
|
if (moveKV->rightPointer != NULL) {
|
||||||
|
moveKV->rightPointer->parent = node;
|
||||||
|
}
|
||||||
|
bplus_node_remove_kv(leftChild, moveKV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node->leftPointer = leftChild->leftPointer;
|
||||||
|
if (node->leftPointer != NULL) {
|
||||||
|
node->leftPointer->parent = node;
|
||||||
|
}
|
||||||
|
leftChild->leftPointer = NULL;
|
||||||
|
free_bplus_node(leftChild);
|
||||||
|
if (node == tree->root && node->leftPointer == NULL) {
|
||||||
|
node->isInternal = false;
|
||||||
|
}
|
||||||
|
node = node->parent;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//Dont need to do anything if node has enough keys or is the root
|
//Dont need to do anything if node has enough keys or is the root
|
||||||
if (node->keyCount > 1 || node->parent == NULL) {
|
if (node->keyCount > 1 || node->parent == NULL) {
|
||||||
@@ -484,7 +527,7 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
|
|||||||
node->leftPointer->parent = node;
|
node->leftPointer->parent = node;
|
||||||
kv->rightPointer = NULL;
|
kv->rightPointer = NULL;
|
||||||
free_bplus_kv(kv);
|
free_bplus_kv(kv);
|
||||||
//Update our parent pointer
|
//Update our parent pointer key
|
||||||
for (size_t i = 0; i < node->parent->keyCount; i++) {
|
for (size_t i = 0; i < node->parent->keyCount; i++) {
|
||||||
if (node->parent->keys[i]->rightPointer == node) {
|
if (node->parent->keys[i]->rightPointer == node) {
|
||||||
node->parent->keys[i]->key = node->keys[0]->key;
|
node->parent->keys[i]->key = node->keys[0]->key;
|
||||||
@@ -495,8 +538,61 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
|
|||||||
|
|
||||||
//Couldn't borrow key, merge with a sibling
|
//Couldn't borrow key, merge with a sibling
|
||||||
|
|
||||||
|
if (right != NULL && right->keyCount <= 1) {
|
||||||
|
//Take left pointer and add a key for it
|
||||||
|
BPlusKV *newKV = new_bplus_kv(right->leftPointer->keys[0]->key, NULL, right->leftPointer);
|
||||||
|
newKV->rightPointer->parent = node;
|
||||||
|
bplus_node_insert_kv(node, newKV);
|
||||||
|
right->leftPointer = NULL;
|
||||||
|
//Move keys
|
||||||
|
while (right->keyCount > 0) {
|
||||||
|
BPlusKV *moveKV = right->keys[0];
|
||||||
|
bplus_node_remove_kv(right, moveKV);
|
||||||
|
bplus_node_insert_kv(node, moveKV);
|
||||||
|
if (moveKV->rightPointer != NULL) {
|
||||||
|
moveKV->rightPointer->parent = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//Remove right node
|
||||||
|
for (size_t i = 0; i < node->parent->keyCount; i++) {
|
||||||
|
if (node->parent->keys[i]->rightPointer == right) {
|
||||||
|
BPlusKV *kv = node->parent->keys[i];
|
||||||
|
bplus_node_remove_kv(node->parent, kv);
|
||||||
|
free_bplus_kv(kv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = node->parent;
|
||||||
|
} else if (left != NULL && left->keyCount <= 1) {
|
||||||
|
//Merge us into the left node
|
||||||
|
//Create new key from left pointer
|
||||||
|
BPlusKV *newKV = new_bplus_kv(node->leftPointer->keys[0]->key, NULL, node->leftPointer);
|
||||||
|
newKV->rightPointer->parent = left;
|
||||||
|
bplus_node_insert_kv(left, newKV);
|
||||||
|
node->leftPointer = NULL;
|
||||||
|
//Move keys
|
||||||
|
while (node->keyCount > 0) {
|
||||||
|
BPlusKV *moveKV = node->keys[0];
|
||||||
|
bplus_node_remove_kv(node, moveKV);
|
||||||
|
bplus_node_insert_kv(left, moveKV);
|
||||||
|
if (moveKV->rightPointer != NULL) {
|
||||||
|
moveKV->rightPointer->parent = leaf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Remove node
|
||||||
|
BPlusNode *parent = node->parent;
|
||||||
|
for (size_t i = 0; i < node->parent->keyCount; i++) {
|
||||||
|
if (node->parent->keys[i]->rightPointer == node) {
|
||||||
|
BPlusKV *kv = node->parent->keys[i];
|
||||||
|
bplus_node_remove_kv(node->parent, kv);
|
||||||
|
free_bplus_kv(kv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
BPlusKV *bplus_tree_find(BPlusTree *tree, uint64_t key) {
|
BPlusKV *bplus_tree_find(BPlusTree *tree, uint64_t key) {
|
||||||
BPlusNode *leaf = bplus_tree_find_leaf(tree, key);
|
BPlusNode *leaf = bplus_tree_find_leaf(tree, key);
|
||||||
|
|||||||
@@ -50,3 +50,22 @@ BPlusNode *_bplus_node_get_right_sibling(BPlusNode *node) {
|
|||||||
return node->rightLeaf;
|
return node->rightLeaf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _bplus_node_check_parents(BPlusNode *parent) {
|
||||||
|
if (parent->leftPointer != NULL) {
|
||||||
|
assert(parent->leftPointer->parent == parent);
|
||||||
|
_bplus_node_check_parents(parent->leftPointer);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < parent->keyCount; i++) {
|
||||||
|
if (parent->keys[i]->rightPointer != NULL) {
|
||||||
|
assert(parent->keys[i]->rightPointer->parent == parent);
|
||||||
|
_bplus_node_check_parents(parent->keys[i]->rightPointer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _bplus_tree_check_parents(BPlusTree *tree) {
|
||||||
|
assert(tree->root != NULL);
|
||||||
|
assert(tree->root->parent == NULL);
|
||||||
|
_bplus_node_check_parents(tree->root);
|
||||||
|
}
|
||||||
@@ -3,11 +3,14 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "InputBuffer.h"
|
#include "InputBuffer.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
|
#include "bplus_tree.h"
|
||||||
|
|
||||||
void prompt() {
|
void prompt() {
|
||||||
printf("SDB> ");
|
printf("SDB> ");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,17 @@ START_TEST(find_keys_4)
|
|||||||
free_bplus_tree(tree);
|
free_bplus_tree(tree);
|
||||||
}END_TEST
|
}END_TEST
|
||||||
|
|
||||||
|
START_TEST(delete_key_leaf) {
|
||||||
|
BPlusTree *tree = new_bplus_tree(4);
|
||||||
|
for(uint64_t i=1;i<=16;i++) {
|
||||||
|
ck_assert(bplus_tree_insert(tree, i, NULL) == true);
|
||||||
|
}
|
||||||
|
for(uint64_t i=1;i<=16;i++) {
|
||||||
|
ck_assert(bplus_tree_delete(tree, i) == true);
|
||||||
|
}
|
||||||
|
free_bplus_tree(tree);
|
||||||
|
}END_TEST;
|
||||||
|
|
||||||
Suite *blus_tree_suite(void) {
|
Suite *blus_tree_suite(void) {
|
||||||
Suite *s = suite_create("B+ Tree");
|
Suite *s = suite_create("B+ Tree");
|
||||||
|
|
||||||
@@ -71,6 +82,7 @@ Suite *blus_tree_suite(void) {
|
|||||||
|
|
||||||
tcase_add_test(core, insert_keys_4);
|
tcase_add_test(core, insert_keys_4);
|
||||||
tcase_add_test(core, find_keys_4);
|
tcase_add_test(core, find_keys_4);
|
||||||
|
tcase_add_test(core, delete_key_leaf);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user