Implemented find/find closest for B+ tree.

Added test suite.
Fixed some b+ tree bugs.
This commit is contained in:
2018-06-23 16:21:12 +01:00
parent 777697d9ab
commit 566bf94225
12 changed files with 360 additions and 3 deletions

7
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,7 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../lib)
add_library(SDBLib STATIC InputBuffer.c InputBuffer.h SQL.c SQL.h scanner.c scanner.h parser.c parser.h bplus_tree.c bplus_tree.h)
add_executable(SDB main.c)
target_link_libraries(SDB SDBLib)

View File

@@ -7,6 +7,14 @@
#include <assert.h>
#include "bplus_tree.h"
#define APPEND_STR(str, size, _) { \
if (strlen(_) + strlen(str) + 1 > (size)) { \
(size) *= 2; \
(str) = realloc(str, (size) * sizeof(char)); \
} \
strcat(str, _);\
}
BPlusKV *new_bplus_kv(uint64_t key, void *value, BPlusNode *leftPointer) {
BPlusKV *kv = malloc(sizeof(BPlusKV));
kv->key = key;
@@ -93,6 +101,9 @@ void print_bplus_node(BPlusNode *node, size_t indent) {
} else {
printf("%sLEAF #%ld (%ld/%ld)\n", indentStr, node->id, node->keyCount, node->order);
}
if (node->parent != NULL) {
printf("%s Parent #%ld\n", indentStr, node->parent->id);
}
if (node->leftPointer != NULL) {
print_bplus_node(node->leftPointer, indent + 4);
@@ -115,6 +126,24 @@ void print_bplus_node(BPlusNode *node, size_t indent) {
free(indentStr);
}
char *debug_bplus_node_str(BPlusNode *node, char *str, size_t *strSize) {
APPEND_STR(str, *strSize, "[");
if (node->leftPointer != NULL) {
str = debug_bplus_node_str(node->leftPointer, str, strSize);
}
char buffer[32] = {0};
for (size_t i = 0; i < node->keyCount; i++) {
snprintf(buffer, 32, node->isInternal ? "{%ld}" : "{%ld*}", node->keys[i]->key);
APPEND_STR(str, *strSize, buffer);
if (node->keys[i]->rightPointer != NULL) {
str = debug_bplus_node_str(node->keys[i]->rightPointer, str, strSize);
}
}
APPEND_STR(str, *strSize, "]");
return str;
}
BPlusTree *new_bplus_tree(size_t order) {
BPlusTree *tree = malloc(sizeof(BPlusTree));
tree->order = order;
@@ -143,6 +172,18 @@ void print_bplus_tree(BPlusTree *tree) {
}
}
char *debug_bplus_tree_str(BPlusTree *tree, char *str) {
size_t strSize = 32;
str = realloc(str, strSize * sizeof(char));
memset(str, 0, strSize * sizeof(char));
snprintf(str, 32, "B+<%ld>", tree->order);
str = debug_bplus_node_str(tree->root, str, &strSize);
return str;
}
BPlusNode *bplus_tree_find_leaf(BPlusTree *tree, uint64_t key) {
BPlusNode *node = tree->root;
@@ -232,6 +273,7 @@ bool bplus_tree_insert(BPlusTree *tree, uint64_t newKey, void *newValue) {
//Move midpoint up and move keys > midpoint to new node
k = 0;
for (size_t i = midpointIndex + 1; i < node->order; i++) {
node->keys[i]->rightPointer->parent = newNode;
newNode->keys[k++] = node->keys[i];
node->keys[i] = NULL;
newNode->keyCount++;
@@ -241,6 +283,7 @@ bool bplus_tree_insert(BPlusTree *tree, uint64_t newKey, void *newValue) {
node->keys[midpointIndex] = NULL;
node->keyCount--;
newNode->leftPointer = ascendingKV->rightPointer;
newNode->leftPointer->parent = newNode;
ascendingKV->rightPointer = newNode;
}
}
@@ -248,4 +291,71 @@ bool bplus_tree_insert(BPlusTree *tree, uint64_t newKey, void *newValue) {
}
}
BPlusKV *bplus_tree_find(BPlusTree *tree, uint64_t key) {
BPlusNode *leaf = bplus_tree_find_leaf(tree, key);
if (leaf == NULL) {
return NULL;
}
for (size_t i = 0; i < leaf->keyCount; i++) {
if (leaf->keys[i]->key == key) {
return leaf->keys[i];
}
}
}
BPlusKV *bplus_tree_find_closest(BPlusTree *tree, uint64_t key, BPlusFindComp dir) {
//Do regular find if we are only looking for key
if (dir == FIND_EQ) {
return bplus_tree_find(tree, key);
}
BPlusNode *leaf = bplus_tree_find_leaf(tree, key);
if (leaf == NULL) {
return NULL;
}
//Scan right until we find a value >= key
ssize_t i;
do {
bool done = false;
for (i = 0; i < leaf->keyCount; i++) {
if (leaf->keys[i]->key == key && (dir & FIND_EQ) == FIND_EQ) {
//Return the value if we are looking for value = key
done = true;
break;
} else if (leaf->keys[i]->key > key) {
//Return the value if we are looking for value > key
if ((dir & FIND_GT) == FIND_GT) {
return leaf->keys[i];
} else {
done = true;
break;
}
}
}
if (done) {
break;
}
if (leaf->rightLeaf == NULL) {
break;
}
leaf = leaf->rightLeaf;
} while (leaf != NULL);
//Didn't find an acceptable value >= key and we are not looking for value < key
if ((dir & FIND_LT) == 0) {
return NULL;
}
//Scan left until we find a value < key
do {
for (i = leaf->keyCount - 1; i >= 0; i--) {
if (leaf->keys[i]->key < key) {
return leaf->keys[i];
}
}
leaf = leaf->leftLeaf;
} while (leaf != NULL);
return NULL;
}

View File

@@ -43,6 +43,8 @@ bool bplus_node_insert_kv(BPlusNode *node, BPlusKV *kv);
void print_bplus_node(BPlusNode *node, size_t indent);
char * debug_bplus_node_str(BPlusNode *node, char *str, size_t *strSize);
struct BPlusTree_t {
size_t order;
size_t minFill;
@@ -56,10 +58,21 @@ BPlusTree *new_bplus_tree(size_t order);
void free_bplus_tree(BPlusTree *tree);
void print_bplus_tree(BPlusTree *tree);
char *debug_bplus_tree_str(BPlusTree *tree, char *str);
BPlusNode * bplus_tree_find_leaf(BPlusTree *tree, uint64_t key);
bool bplus_tree_insert(BPlusTree *tree, uint64_t key, void *value);
BPlusKV * bplus_tree_find(BPlusTree *tree, uint64_t key);
enum BPlusFindComp_t {
FIND_NONE = 0,
FIND_LT = 1,
FIND_EQ = 2,
FIND_GT = 4
};
typedef enum BPlusFindComp_t BPlusFindComp;
BPlusKV * bplus_tree_find_closest(BPlusTree *tree, uint64_t key, BPlusFindComp dir);
#endif //SDB_BPLUS_TREE_H