Working on removing keys from B+ trees

This commit is contained in:
2018-06-30 18:53:59 +01:00
parent 1a3a2cfb6d
commit b2e27373f1
2 changed files with 157 additions and 60 deletions

View File

@@ -8,6 +8,8 @@
#include <stdio.h> #include <stdio.h>
#include "bplus_tree.h" #include "bplus_tree.h"
#include "bplus_tree.helpers.c"
#define APPEND_STR(str, size, _) { \ #define APPEND_STR(str, size, _) { \
if (strlen(_) + strlen(str) + 1 > (size)) { \ if (strlen(_) + strlen(str) + 1 > (size)) { \
(size) *= 2; \ (size) *= 2; \
@@ -313,15 +315,15 @@ 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 *node = bplus_tree_find_leaf(tree, key); BPlusNode *leaf = bplus_tree_find_leaf(tree, key);
assert(node != NULL && node->isInternal == false); assert(leaf != NULL && leaf->isInternal == false);
//Find and remove kv //Find and remove kv
bool removed = false; bool removed = false;
for (size_t i = 0; i < node->keyCount; i++) { for (size_t i = 0; i < leaf->keyCount; i++) {
if (node->keys[i]->key == key) { if (leaf->keys[i]->key == key) {
BPlusKV *kv = node->keys[i]; BPlusKV *kv = leaf->keys[i];
removed = bplus_node_remove_kv(node, node->keys[i]); removed = bplus_node_remove_kv(leaf, leaf->keys[i]);
assert(removed); assert(removed);
free_bplus_kv(kv); free_bplus_kv(kv);
break; break;
@@ -332,24 +334,24 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
return false; return false;
} }
if (node->keyCount >= tree->minFill || node->parent == NULL) { if (leaf->keyCount >= tree->minFill || leaf->parent == NULL) {
return true; return true;
} }
//Try and borrow a key from a neighbour //Try and borrow a key from a neighbour
//Check right leaf //Check right leaf
if (node->rightLeaf != NULL if (leaf->rightLeaf != NULL
&& node->rightLeaf->parent == node->parent && leaf->rightLeaf->parent == leaf->parent
&& node->rightLeaf->keyCount > tree->minFill) { && leaf->rightLeaf->keyCount > tree->minFill) {
//Move first kv on leaf to this node //Move first kv on leaf to this leaf
BPlusKV *kv = node->rightLeaf->keys[0]; BPlusKV *kv = leaf->rightLeaf->keys[0];
assert(bplus_node_remove_kv(node->rightLeaf, kv)); assert(bplus_node_remove_kv(leaf->rightLeaf, kv));
assert(bplus_node_insert_kv(node, kv)); assert(bplus_node_insert_kv(leaf, kv));
//Update the right leafs parent pointer //Update the right leafs parent pointer
for (size_t i = 0; i < node->parent->keyCount; i++) { for (size_t i = 0; i < leaf->parent->keyCount; i++) {
if (node->parent->keys[i]->rightPointer == node->rightLeaf) { if (leaf->parent->keys[i]->rightPointer == leaf->rightLeaf) {
node->parent->keys[i]->key = node->rightLeaf->keys[0]->key; leaf->parent->keys[i]->key = leaf->rightLeaf->keys[0]->key;
break; break;
} }
} }
@@ -357,17 +359,17 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
} }
//Check left leaf //Check left leaf
if (node->leftLeaf != NULL if (leaf->leftLeaf != NULL
&& node->leftLeaf->parent == node->parent && leaf->leftLeaf->parent == leaf->parent
&& node->leftLeaf->keyCount > tree->minFill) { && leaf->leftLeaf->keyCount > tree->minFill) {
//Move right most key from left leaf //Move right most key from left leaf
BPlusKV *kv = node->leftLeaf->keys[node->keyCount - 1]; BPlusKV *kv = leaf->leftLeaf->keys[leaf->keyCount - 1];
assert(bplus_node_remove_kv(node->leftLeaf, kv)); assert(bplus_node_remove_kv(leaf->leftLeaf, kv));
assert(bplus_node_insert_kv(node, kv)); assert(bplus_node_insert_kv(leaf, kv));
//Update the key pointing to this node //Update the key pointing to this leaf
for (size_t i = 0; i < node->parent->keyCount; i++) { for (size_t i = 0; i < leaf->parent->keyCount; i++) {
if (node->parent->keys[i]->rightPointer == node) { if (leaf->parent->keys[i]->rightPointer == leaf) {
node->parent->keys[i]->key = node->keys[0]->key; leaf->parent->keys[i]->key = leaf->keys[0]->key;
break; break;
} }
} }
@@ -378,26 +380,26 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
bool merged = false; bool merged = false;
//Try right leaf //Try right leaf
if (node->rightLeaf != NULL if (leaf->rightLeaf != NULL
&& node->parent == node->rightLeaf->parent && leaf->parent == leaf->rightLeaf->parent
&& node->keyCount + node->rightLeaf->keyCount < tree->order) { && leaf->keyCount + leaf->rightLeaf->keyCount < tree->order) {
//Move all keys from right leaf to this node //Move all keys from right leaf to this leaf
while(node->rightLeaf->keyCount > 0) { while (leaf->rightLeaf->keyCount > 0) {
assert(bplus_node_insert_kv(node, node->rightLeaf->keys[0])); assert(bplus_node_insert_kv(leaf, leaf->rightLeaf->keys[0]));
assert(bplus_node_remove_kv(node->rightLeaf, node->rightLeaf->keys[0])); assert(bplus_node_remove_kv(leaf->rightLeaf, leaf->rightLeaf->keys[0]));
} }
//Remove right leaf and parent pointer //Remove right leaf and parent pointer
for(size_t i=0; i<node->parent->keyCount; i++) { for (size_t i = 0; i < leaf->parent->keyCount; i++) {
BPlusKV *kv = node->parent->keys[i]; BPlusKV *kv = leaf->parent->keys[i];
if (kv->rightPointer == node->rightLeaf) { if (kv->rightPointer == leaf->rightLeaf) {
//Remove key //Remove key
bplus_node_remove_kv(node->parent, kv); bplus_node_remove_kv(leaf->parent, kv);
//Update leaf pointers //Update leaf pointers
node->rightLeaf = node->rightLeaf; leaf->rightLeaf = leaf->rightLeaf;
if (node->rightLeaf != NULL) { if (leaf->rightLeaf != NULL) {
node->rightLeaf->leftLeaf = node; leaf->rightLeaf->leftLeaf = leaf;
} }
//Free key and node //Free key and leaf
free_bplus_kv(kv); free_bplus_kv(kv);
break; break;
} }
@@ -406,27 +408,27 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
} }
//Try left leaf //Try left leaf
if (node->leftLeaf != NULL if (leaf->leftLeaf != NULL
&& node->parent == node->leftLeaf->parent && leaf->parent == leaf->leftLeaf->parent
&& node->keyCount + node->leftLeaf->keyCount < tree->order) { && leaf->keyCount + leaf->leftLeaf->keyCount < tree->order) {
//Move all keys into left leaf //Move all keys into left leaf
while(node->keyCount > 0) { while (leaf->keyCount > 0) {
assert(bplus_node_insert_kv(node->leftLeaf, node->keys[0])); assert(bplus_node_insert_kv(leaf->leftLeaf, leaf->keys[0]));
assert(bplus_node_remove_kv(node, node->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)
for(size_t i=0; i<node->parent->keyCount; i++) { for (size_t i = 0; i < leaf->parent->keyCount; i++) {
BPlusKV *kv = node->parent->keys[i]; BPlusKV *kv = leaf->parent->keys[i];
if (kv->rightPointer == node) { if (kv->rightPointer == leaf) {
//Remove key //Remove key
bplus_node_remove_kv(node->parent, kv); bplus_node_remove_kv(leaf->parent, kv);
//Update leaf pointers //Update leaf pointers
node->leftLeaf->rightLeaf = node->rightLeaf; leaf->leftLeaf->rightLeaf = leaf->rightLeaf;
if (node->leftLeaf->rightLeaf != NULL) { if (leaf->leftLeaf->rightLeaf != NULL) {
node->leftLeaf->rightLeaf->leftLeaf = node->leftLeaf; leaf->leftLeaf->rightLeaf->leftLeaf = leaf->leftLeaf;
} }
node = node->leftLeaf; leaf = leaf->leftLeaf;
//Free key and node //Free key and leaf
free_bplus_kv(kv); free_bplus_kv(kv);
break; break;
} }
@@ -438,17 +440,60 @@ bool bplus_tree_delete(BPlusTree *tree, uint64_t key) {
assert(merged == true); assert(merged == true);
//Start merging parents where key count <= 1 //Start merging parents where key count <= 1
BPlusNode *parent = node->parent; BPlusNode *node = leaf->parent;
while(parent != NULL) { while (node != NULL) {
if (parent->keyCount > 1) { //Dont need to do anything if node has enough keys or is the root
if (node->keyCount > 1 || node->parent == NULL) {
break; break;
} }
BPlusNode *left = _bplus_node_get_left_sibling(node);
BPlusNode *right = _bplus_node_get_right_sibling(node);
//Try and borrow a key from a sibling //Try and borrow a key from a sibling
if (right != NULL && right->keyCount > 1) {
//Take the left pointer and create a new key for it
BPlusKV *kv = new_bplus_kv(right->leftPointer->keys[0]->key, NULL, right->leftPointer);
right->leftPointer->parent = node;
bplus_node_insert_kv(node, kv);
//Consume first key to populate left pointer
right->leftPointer = right->keys[0]->rightPointer;
kv = right->keys[0];
bplus_node_remove_kv(right, kv);
kv->rightPointer = NULL;
free_bplus_kv(kv);
//Update pointer key to right
for (size_t i = 0; i < node->parent->keyCount; i++) {
if (node->parent->keys[i]->rightPointer == right) {
node->parent->keys[i]->key = right->keys[0]->key;
}
}
break;
}
if (left != NULL && left->keyCount > 1) {
//Push our left pointer to a new key
BPlusKV *newKV = new_bplus_kv(node->leftPointer->keys[0]->key, NULL, node->leftPointer);
bplus_node_insert_kv(node, newKV);
//Take the right key from the left sibling
BPlusKV *kv = left->keys[left->keyCount - 1];
bplus_node_remove_kv(left, kv);
node->leftPointer = kv->rightPointer;
node->leftPointer->parent = node;
kv->rightPointer = NULL;
free_bplus_kv(kv);
//Update our parent pointer
for (size_t i = 0; i < node->parent->keyCount; i++) {
if (node->parent->keys[i]->rightPointer == node) {
node->parent->keys[i]->key = node->keys[0]->key;
}
}
break;
}
//Couldn't borrow key, merge with a sibling
} }
} }

52
src/bplus_tree.helpers.c Normal file
View File

@@ -0,0 +1,52 @@
//
// Created by sam on 30/06/18.
//
BPlusNode *_bplus_node_get_left_sibling(BPlusNode *node) {
BPlusNode *parent = node->parent;
if (node->isInternal) {
if (parent == NULL) {
return NULL;
}
if (parent->leftLeaf == node) {
return NULL;
}
for (size_t i = 0; i < parent->keyCount; i++) {
if (parent->keys[i]->rightPointer == node) {
if (i == 0) {
return parent->leftPointer;
}
if (i + 1 < parent->keyCount) {
return parent->keys[i + 1]->rightPointer;
}
return NULL;
}
}
return NULL;
} else {
return node->leftLeaf;
}
}
BPlusNode *_bplus_node_get_right_sibling(BPlusNode *node) {
BPlusNode *parent = node->parent;
if (node->isInternal) {
if (parent == NULL) {
return NULL;
}
if (parent->leftPointer == node) {
return parent->keyCount > 0 ? parent->keys[0]->rightPointer : NULL;
}
for (size_t i = 0; i < parent->keyCount; i++) {
if (parent->keys[i]->rightPointer == node) {
if (i == 0) {
return parent->leftPointer;
}
return parent->keys[i - 1]->rightPointer;
}
}
return NULL;
} else {
return node->rightLeaf;
}
}