Working on B+ tree implementation.
This commit is contained in:
@@ -3,4 +3,5 @@ project(SDB C)
|
|||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
|
||||||
add_executable(SDB src/main.c src/InputBuffer.c src/InputBuffer.h src/SQL.c src/SQL.h src/scanner.c src/scanner.h src/parser.c src/parser.h)
|
include_directories(${CMAKE_SOURCE_DIR}/lib)
|
||||||
|
add_executable(SDB src/main.c src/InputBuffer.c src/InputBuffer.h src/SQL.c src/SQL.h src/scanner.c src/scanner.h src/parser.c src/parser.h src/bplus_tree.c src/bplus_tree.h)
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ void print_column_spec_list(ColumnSpecList *list) {
|
|||||||
for (size_t i = 0; i < list->length; i++) {
|
for (size_t i = 0; i < list->length; i++) {
|
||||||
ColumnSpec *spec = list->columns[i];
|
ColumnSpec *spec = list->columns[i];
|
||||||
if (spec->type == COLTYPE_STRING) {
|
if (spec->type == COLTYPE_STRING) {
|
||||||
printf("%s STRING(%d)", spec->identifier, spec->size);
|
printf("%s STRING(%ld)", spec->identifier, spec->size);
|
||||||
} else if (spec->type == COLTYPE_INT) {
|
} else if (spec->type == COLTYPE_INT) {
|
||||||
printf("%s INTEGER", spec->identifier);
|
printf("%s INTEGER", spec->identifier);
|
||||||
}
|
}
|
||||||
@@ -470,6 +470,6 @@ void print_value(Value *value) {
|
|||||||
}
|
}
|
||||||
printf("'");
|
printf("'");
|
||||||
} else if (value->type == VALUE_NUMBER) {
|
} else if (value->type == VALUE_NUMBER) {
|
||||||
printf("%lld", value->number);
|
printf("%ld", value->number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
251
src/bplus_tree.c
Normal file
251
src/bplus_tree.c
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
//
|
||||||
|
// Created by sam on 14/06/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "bplus_tree.h"
|
||||||
|
|
||||||
|
BPlusKV *new_bplus_kv(uint64_t key, void *value, BPlusNode *leftPointer) {
|
||||||
|
BPlusKV *kv = malloc(sizeof(BPlusKV));
|
||||||
|
kv->key = key;
|
||||||
|
kv->value = value;
|
||||||
|
kv->rightPointer = leftPointer;
|
||||||
|
return kv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_bplus_kv(BPlusKV *kv) {
|
||||||
|
if (kv->rightPointer != NULL) {
|
||||||
|
free_bplus_node(kv->rightPointer);
|
||||||
|
}
|
||||||
|
if (kv->value != NULL) {
|
||||||
|
free(kv->value);
|
||||||
|
}
|
||||||
|
free(kv);
|
||||||
|
}
|
||||||
|
|
||||||
|
BPlusNode *new_bplus_node(uint64_t id, bool isInternal, size_t order) {
|
||||||
|
BPlusNode *node = malloc(sizeof(BPlusNode));
|
||||||
|
node->id = id;
|
||||||
|
node->isInternal = isInternal;
|
||||||
|
node->order = order;
|
||||||
|
node->parent = NULL;
|
||||||
|
node->keys = calloc(order, sizeof(BPlusKV *));
|
||||||
|
node->keyCount = 0;
|
||||||
|
node->leftPointer = NULL;
|
||||||
|
node->leftLeaf = NULL;
|
||||||
|
node->rightLeaf = NULL;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_bplus_node(BPlusNode *node) {
|
||||||
|
for (size_t i = 0; i < node->keyCount; i++) {
|
||||||
|
free_bplus_kv(node->keys[i]);
|
||||||
|
}
|
||||||
|
free(node->keys);
|
||||||
|
if (node->leftPointer != NULL) {
|
||||||
|
free_bplus_node(node->leftPointer);
|
||||||
|
}
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bplus_node_insert_kv(BPlusNode *node, BPlusKV *kv) {
|
||||||
|
if (node->keyCount == node->order) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//Insert if empty
|
||||||
|
if (node->keyCount == 0) {
|
||||||
|
node->keys[0] = kv;
|
||||||
|
node->keyCount = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//Check if can add to end
|
||||||
|
if (kv->key > node->keys[node->keyCount - 1]->key) {
|
||||||
|
node->keys[node->keyCount++] = kv;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Find an index where we should insert
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < node->keyCount; i++) {
|
||||||
|
if (kv->key < node->keys[i]->key) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Make hole for new value
|
||||||
|
for (size_t k = node->order - 1; k > i; k--) {
|
||||||
|
node->keys[k] = node->keys[k - 1];
|
||||||
|
}
|
||||||
|
node->keys[i] = kv;
|
||||||
|
node->keyCount++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_bplus_node(BPlusNode *node, size_t indent) {
|
||||||
|
char *indentStr = calloc(indent + 1, sizeof(char));
|
||||||
|
memset(indentStr, ' ', sizeof(char) * indent);
|
||||||
|
|
||||||
|
if (node->parent == NULL) {
|
||||||
|
printf("%sROOT #%ld (%ld/%ld)\n", indentStr, node->id, node->keyCount, node->order);
|
||||||
|
} else if (node->isInternal) {
|
||||||
|
printf("%sINTERNAL #%ld (%ld/%ld)\n", indentStr, node->id, node->keyCount, node->order);
|
||||||
|
} else {
|
||||||
|
printf("%sLEAF #%ld (%ld/%ld)\n", indentStr, node->id, node->keyCount, node->order);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->leftPointer != NULL) {
|
||||||
|
print_bplus_node(node->leftPointer, indent + 4);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < node->keyCount; i++) {
|
||||||
|
printf("%s Key: %ld\t", indentStr, node->keys[i]->key);
|
||||||
|
if (!node->isInternal) {
|
||||||
|
if (node->keys[i]->value != NULL) {
|
||||||
|
printf("Value: %p", node->keys[i]->value);
|
||||||
|
} else {
|
||||||
|
printf("Value: NULL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
if (node->keys[i]->rightPointer != NULL) {
|
||||||
|
print_bplus_node(node->keys[i]->rightPointer, indent + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(indentStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
BPlusTree *new_bplus_tree(size_t order) {
|
||||||
|
BPlusTree *tree = malloc(sizeof(BPlusTree));
|
||||||
|
tree->order = order;
|
||||||
|
tree->minFill = order / 2;
|
||||||
|
tree->nextID = 0;
|
||||||
|
tree->root = new_bplus_node(tree->nextID++, false, order);
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_bplus_tree(BPlusTree *tree) {
|
||||||
|
if (tree->root != NULL) {
|
||||||
|
free_bplus_node(tree->root);
|
||||||
|
}
|
||||||
|
free(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_bplus_tree(BPlusTree *tree) {
|
||||||
|
printf("B+ Tree\n");
|
||||||
|
printf("- Order: %ld\n", tree->order);
|
||||||
|
printf("- Min Fill: %ld\n", tree->minFill);
|
||||||
|
|
||||||
|
if (tree->root != NULL) {
|
||||||
|
print_bplus_node(tree->root, 2);
|
||||||
|
} else {
|
||||||
|
printf(" EMPTY TREE\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BPlusNode *bplus_tree_find_leaf(BPlusTree *tree, uint64_t key) {
|
||||||
|
BPlusNode *node = tree->root;
|
||||||
|
|
||||||
|
//Descend to correct leaf node
|
||||||
|
while (node != NULL) {
|
||||||
|
//Found our way to a leaf node
|
||||||
|
if (!node->isInternal) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//We are assuming at least one key
|
||||||
|
if (key < node->keys[0]->key) {
|
||||||
|
//Follow left pointer if less than first key
|
||||||
|
node = node->leftPointer;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
size_t i;
|
||||||
|
for (i = 1; i < node->keyCount; i++) {
|
||||||
|
if (key < node->keys[i]->key) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = node->keys[i - 1]->rightPointer;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bplus_tree_insert(BPlusTree *tree, uint64_t newKey, void *newValue) {
|
||||||
|
BPlusNode *node = bplus_tree_find_leaf(tree, newKey);
|
||||||
|
assert(node != NULL);
|
||||||
|
|
||||||
|
if (node->keyCount < node->order - 1) {
|
||||||
|
//Can insert at this node
|
||||||
|
BPlusKV *kv = new_bplus_kv(newKey, newValue, NULL);
|
||||||
|
bool insertKV = bplus_node_insert_kv(node, kv);
|
||||||
|
assert(insertKV == true);
|
||||||
|
} else {
|
||||||
|
//Note: as this is a leaf node, we are not updating/maintaining any pointers
|
||||||
|
//Insert and split
|
||||||
|
BPlusKV *kv = new_bplus_kv(newKey, newValue, NULL);
|
||||||
|
bool insertKV = bplus_node_insert_kv(node, kv);
|
||||||
|
assert(insertKV == true);
|
||||||
|
|
||||||
|
//Decide on new midpoint
|
||||||
|
size_t midpointIndex = node->order / 2;
|
||||||
|
|
||||||
|
//Create new node and update leaf links
|
||||||
|
BPlusNode *newNode = new_bplus_node(tree->nextID++, false, node->order);
|
||||||
|
newNode->parent = node->parent;
|
||||||
|
newNode->rightLeaf = node->rightLeaf;
|
||||||
|
newNode->leftLeaf = node;
|
||||||
|
node->rightLeaf = newNode;
|
||||||
|
|
||||||
|
//Move keys >= midpoint to a new node
|
||||||
|
size_t k = 0;
|
||||||
|
for (size_t i = midpointIndex; i < node->order; i++) {
|
||||||
|
newNode->keys[k++] = node->keys[i];
|
||||||
|
node->keys[i] = NULL;
|
||||||
|
newNode->keyCount++;
|
||||||
|
node->keyCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send midpoint key to parent
|
||||||
|
BPlusKV *ascendingKV = new_bplus_kv(newNode->keys[0]->key, NULL, NULL);
|
||||||
|
ascendingKV->rightPointer = newNode;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (node->parent == NULL) {
|
||||||
|
//Split root, create a new node with the ascending kv and replace it
|
||||||
|
BPlusNode *newRoot = new_bplus_node(tree->nextID++, true, tree->order);
|
||||||
|
newRoot->leftPointer = node;
|
||||||
|
bplus_node_insert_kv(newRoot, ascendingKV);
|
||||||
|
tree->root = newRoot;
|
||||||
|
newNode->parent = tree->root;
|
||||||
|
node->parent = tree->root;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
node = node->parent;
|
||||||
|
bplus_node_insert_kv(node, ascendingKV);
|
||||||
|
if (node->keyCount < node->order) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
//Parent needs splitting
|
||||||
|
midpointIndex = node->order / 2;
|
||||||
|
//Create new node
|
||||||
|
newNode = new_bplus_node(tree->nextID++, true, node->order);
|
||||||
|
newNode->parent = node->parent;
|
||||||
|
//Move midpoint up and move keys > midpoint to new node
|
||||||
|
k = 0;
|
||||||
|
for (size_t i = midpointIndex + 1; i < node->order; i++) {
|
||||||
|
newNode->keys[k++] = node->keys[i];
|
||||||
|
node->keys[i] = NULL;
|
||||||
|
newNode->keyCount++;
|
||||||
|
node->keyCount--;
|
||||||
|
}
|
||||||
|
ascendingKV = node->keys[midpointIndex];
|
||||||
|
node->keys[midpointIndex] = NULL;
|
||||||
|
node->keyCount--;
|
||||||
|
newNode->leftPointer = ascendingKV->rightPointer;
|
||||||
|
ascendingKV->rightPointer = newNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (node != NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
65
src/bplus_tree.h
Normal file
65
src/bplus_tree.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
//
|
||||||
|
// Created by sam on 14/06/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SDB_BPLUS_TREE_H
|
||||||
|
#define SDB_BPLUS_TREE_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct BPlusNode_t;
|
||||||
|
typedef struct BPlusNode_t BPlusNode;
|
||||||
|
|
||||||
|
struct BPlusKV_t {
|
||||||
|
uint64_t key;
|
||||||
|
void *value;
|
||||||
|
BPlusNode *rightPointer;
|
||||||
|
};
|
||||||
|
typedef struct BPlusKV_t BPlusKV;
|
||||||
|
|
||||||
|
BPlusKV *new_bplus_kv(uint64_t key, void *value, BPlusNode *leftPointer);
|
||||||
|
|
||||||
|
void free_bplus_kv(BPlusKV *kv);
|
||||||
|
|
||||||
|
struct BPlusNode_t {
|
||||||
|
uint64_t id;
|
||||||
|
bool isInternal;
|
||||||
|
size_t order;
|
||||||
|
BPlusNode *parent;
|
||||||
|
BPlusKV **keys;
|
||||||
|
size_t keyCount;
|
||||||
|
BPlusNode *leftPointer;
|
||||||
|
BPlusNode *leftLeaf;
|
||||||
|
BPlusNode *rightLeaf;
|
||||||
|
};
|
||||||
|
|
||||||
|
BPlusNode *new_bplus_node(uint64_t id, bool isInternal, size_t order);
|
||||||
|
|
||||||
|
void free_bplus_node(BPlusNode *node);
|
||||||
|
|
||||||
|
bool bplus_node_insert_kv(BPlusNode *node, BPlusKV *kv);
|
||||||
|
|
||||||
|
void print_bplus_node(BPlusNode *node, size_t indent);
|
||||||
|
|
||||||
|
struct BPlusTree_t {
|
||||||
|
size_t order;
|
||||||
|
size_t minFill;
|
||||||
|
BPlusNode *root;
|
||||||
|
uint64_t nextID;
|
||||||
|
};
|
||||||
|
typedef struct BPlusTree_t BPlusTree;
|
||||||
|
|
||||||
|
BPlusTree *new_bplus_tree(size_t order);
|
||||||
|
|
||||||
|
void free_bplus_tree(BPlusTree *tree);
|
||||||
|
|
||||||
|
void print_bplus_tree(BPlusTree *tree);
|
||||||
|
|
||||||
|
BPlusNode * bplus_tree_find_leaf(BPlusTree *tree, uint64_t key);
|
||||||
|
|
||||||
|
bool bplus_tree_insert(BPlusTree *tree, uint64_t key, void *value);
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SDB_BPLUS_TREE_H
|
||||||
Reference in New Issue
Block a user