Working on removing keys from B+ trees
This commit is contained in:
165
src/bplus_tree.c
165
src/bplus_tree.c
@@ -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
52
src/bplus_tree.helpers.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user