feat(lsm): possibly implemented trie insert
This commit is contained in:
parent
0548efda97
commit
622d644f25
8 changed files with 340 additions and 3 deletions
|
|
@ -1 +1,128 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "lsm.h"
|
||||
#include "lsm/trie_internal.h"
|
||||
|
||||
lsm_error lsm_trie_node_init(lsm_trie_node **ptr) {
|
||||
lsm_trie_node *node = calloc(1, sizeof(lsm_trie_node));
|
||||
|
||||
if (node == NULL) {
|
||||
return lsm_error_failed_alloc;
|
||||
}
|
||||
|
||||
*ptr = node;
|
||||
|
||||
return lsm_error_ok;
|
||||
}
|
||||
|
||||
lsm_error lsm_trie_init(lsm_trie **ptr) {
|
||||
lsm_trie *trie = calloc(1, sizeof(lsm_trie));
|
||||
|
||||
if (trie == NULL) {
|
||||
return lsm_error_failed_alloc;
|
||||
}
|
||||
|
||||
lsm_trie_node *root;
|
||||
lsm_error res = lsm_trie_node_init(&root);
|
||||
|
||||
if (res != lsm_error_ok) {
|
||||
return res;
|
||||
}
|
||||
|
||||
trie->root = root;
|
||||
*ptr = trie;
|
||||
|
||||
return lsm_error_ok;
|
||||
}
|
||||
|
||||
lsm_error lsm_trie_insert(lsm_trie *trie, lsm_str *key, void *data) {
|
||||
// NULL is not allowed as a data value, as it's used to indicate a lack of
|
||||
// data
|
||||
if (data == NULL) {
|
||||
return lsm_error_null_value;
|
||||
}
|
||||
|
||||
uint64_t key_len = lsm_str_len(key);
|
||||
|
||||
// Empty string is represented by the root
|
||||
if (key_len == 0) {
|
||||
if (trie->root->data == NULL) {
|
||||
trie->root->data = data;
|
||||
|
||||
return lsm_error_ok;
|
||||
} else {
|
||||
return lsm_error_already_present;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t index = 0;
|
||||
lsm_trie_node *node = trie->root;
|
||||
lsm_trie_node *next_node;
|
||||
lsm_error res;
|
||||
|
||||
while (index < key_len) {
|
||||
char c = lsm_str_char(key, index);
|
||||
res = lsm_bt_search((void **)&next_node, &node->bt, c);
|
||||
|
||||
// No child is present yet for this character, so we can insert the string
|
||||
// here
|
||||
if (res == lsm_error_not_found) {
|
||||
lsm_trie_node *new_node;
|
||||
res = lsm_trie_node_init(&new_node);
|
||||
|
||||
if (res != lsm_error_ok) {
|
||||
return res;
|
||||
}
|
||||
|
||||
new_node->data = data;
|
||||
lsm_str_substr(&new_node->skip, key, index + 1, key_len);
|
||||
|
||||
return lsm_bt_insert(&node->bt, c, new_node);
|
||||
}
|
||||
|
||||
index++;
|
||||
|
||||
// We compare the remaining part of the key with the node's skip. If cmp is
|
||||
// less than the length of the skip, we know they differ and the edge should
|
||||
// be split.
|
||||
uint64_t cmp = lsm_str_cmp(key, index, &next_node->skip, 0);
|
||||
|
||||
if (cmp < lsm_str_len(&next_node->skip)) {
|
||||
lsm_trie_node *split_node;
|
||||
res = lsm_trie_node_init(&split_node);
|
||||
|
||||
if (res != lsm_error_ok) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// split_node replaces the original node as the new child node
|
||||
lsm_trie_node *bottom_node;
|
||||
lsm_bt_replace((void **)&bottom_node, &node->bt, c, split_node);
|
||||
|
||||
// The old child node now becomes the child of split_node
|
||||
lsm_bt_insert(&split_node->bt, lsm_str_char(key, index + cmp),
|
||||
bottom_node);
|
||||
|
||||
// The new node splits the edge into two parts, so the new node will have
|
||||
// the remaining part of the skip (minus the one character) as its skip
|
||||
lsm_str_substr(&split_node->skip, &next_node->skip, cmp + 1,
|
||||
lsm_str_len(&next_node->skip));
|
||||
|
||||
// The old node keeps the first part of the skip
|
||||
lsm_str_truncate(&next_node->skip, cmp);
|
||||
|
||||
next_node = split_node;
|
||||
}
|
||||
|
||||
node = next_node;
|
||||
index += cmp;
|
||||
}
|
||||
|
||||
if (node->data != NULL) {
|
||||
return lsm_error_already_present;
|
||||
}
|
||||
|
||||
node->data = data;
|
||||
|
||||
return lsm_error_ok;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue