Implemented find/find closest for B+ tree.
Added test suite. Fixed some b+ tree bugs.
This commit is contained in:
7
src/CMakeLists.txt
Normal file
7
src/CMakeLists.txt
Normal 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)
|
||||
110
src/bplus_tree.c
110
src/bplus_tree.c
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user