Skip to content

Commit

Permalink
feat(db): add hash table saving to file
Browse files Browse the repository at this point in the history
refactor(hashtable): remove null terminator from field names
perf(db): add precalculating content length when saving to file
  • Loading branch information
aloima committed Dec 14, 2024
1 parent 918d4dc commit 72fda30
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 36 deletions.
142 changes: 115 additions & 27 deletions src/database/file.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "../../headers/database.h"
#include "../../headers/server.h"
#include "../../headers/hashtable.h"
#include "../../headers/utils.h"

#include <stdio.h>
Expand Down Expand Up @@ -63,27 +64,66 @@ void close_database_fd() {
close(fd);
}

static void generate_name_key(char **data, off64_t *len, const string_t key) {
const uint8_t bit_count = log2(key.len) + 1;
const uint8_t byte_count = ceil((float) (bit_count - 6) / 8);
const uint8_t first = (byte_count << 6) | (key.len & 0b111111);
const uint32_t length_in_bytes = key.len >> 6;
static off64_t get_value_size(const enum TellyTypes type, void *value) {
switch (type) {
case TELLY_NULL:
return 0;

*data = realloc(*data, (*len + key.len + byte_count + 1));
case TELLY_NUM: {
const uint32_t bit_count = log2(*((long *) value)) + 1;
return ((bit_count / 8) + 1);
}

(*data)[*len] = first;
memcpy(*data + (*len += 1), &length_in_bytes, byte_count);
memcpy(*data + (*len += byte_count), key.value, key.len);
*len += key.len;
case TELLY_STR: {
const string_t *string = value;
const uint8_t bit_count = log2(string->len) + 1;
const uint8_t byte_count = ceil(((float) bit_count) / 8);

return (byte_count + string->len);
}

case TELLY_BOOL:
return 1;

case TELLY_HASHTABLE: {
const struct HashTable *table = value;
off64_t length = 5;

for (uint32_t i = 0; i < table->size.allocated; ++i) {
struct FVPair *fv = table->fvs[i];

while (fv) {
length += (1 + get_value_size(TELLY_STR, &fv->name) + get_value_size(fv->type, value));
fv = fv->next;
}
}

return length;
}

case TELLY_LIST: {
const struct List *list = value;
struct ListNode *node = list->begin;
off64_t length = 4;

while (node) {
length += (1 + get_value_size(node->type, node->value));
node = node->next;
}

return length;
}

default:
return 0;
}
}

static void generate_number_value(char **data, off64_t *len, const long *number) {
const uint32_t bit_count = log2(*number) + 1;
const uint32_t byte_count = (bit_count / 8) + 1;

*data = realloc(*data, (*len + byte_count + 2));
(*data)[*len] = TELLY_NUM;
(*data)[*len += 1] = byte_count;
(*data)[*len] = byte_count;
memcpy(*data + (*len += 1), number, byte_count);
*len += byte_count;
}
Expand All @@ -94,32 +134,28 @@ static void generate_string_value(char **data, off64_t *len, const string_t *str
const uint8_t first = (byte_count << 6) | (string->len & 0b111111);
const uint32_t length_in_bytes = string->len >> 6;

*data = realloc(*data, (*len + string->len + byte_count + 2));
(*data)[*len] = TELLY_STR;
(*data)[*len += 1] = first;
(*data)[*len] = first;
memcpy(*data + (*len += 1), &length_in_bytes, byte_count);
memcpy(*data + (*len += byte_count), string->value, string->len);
*len += string->len;
}

static void generate_boolean_value(char **data, off64_t *len, const bool *boolean) {
*data = realloc(*data, (*len + 2));
(*data)[*len] = TELLY_BOOL;
(*data)[*len += 1] = *boolean;

(*data)[*len] = *boolean;
*len += 1;
}

static void generate_null_value(char **data, off64_t *len) {
*data = realloc(*data, (*len + 1));
(*data)[*len] = TELLY_NULL;
*len += 1;
}

static off64_t generate_value(char **data, struct KVPair *kv) {
off64_t len = 0;

generate_name_key(data, &len, kv->key);
generate_string_value(data, &len, &kv->key);
(*data)[len] = kv->type;
len += 1;

switch (kv->type) {
case TELLY_NULL:
Expand All @@ -138,17 +174,62 @@ static off64_t generate_value(char **data, struct KVPair *kv) {
generate_boolean_value(data, &len, kv->value);
break;

case TELLY_HASHTABLE: {
struct HashTable *table = kv->value;
memcpy(*data + len, &table->size.allocated, 4);
len += 4;

for (uint32_t i = 0; i < table->size.allocated; ++i) {
struct FVPair *fv = table->fvs[i];

while (fv) {
(*data)[len] = fv->type;
len += 1;

generate_string_value(data, &len, &fv->name);

switch (fv->type) {
case TELLY_NULL:
generate_null_value(data, &len);
break;

case TELLY_NUM:
generate_number_value(data, &len, fv->value);
break;

case TELLY_STR:
generate_string_value(data, &len, fv->value);
break;

case TELLY_BOOL:
generate_boolean_value(data, &len, fv->value);
break;

default:
break;
}

fv = fv->next;
}
}

(*data)[len] = 0x17;
len += 1;

break;
}

case TELLY_LIST: {
struct List *list = kv->value;

*data = realloc(*data, (len + 5));
(*data)[len] = TELLY_LIST;
memcpy(*data + (len += 1), &list->size, 4);
memcpy(*data + len, &list->size, 4);
len += 4;

struct ListNode *node = list->begin;

while (node) {
(*data)[len] = node->type;
len += 1;

switch (node->type) {
case TELLY_NULL:
generate_null_value(data, &len);
Expand Down Expand Up @@ -240,7 +321,14 @@ void save_data(const uint64_t server_age) {
struct BTree *cache = get_cache();
struct BTreeValue **values = get_values_from_btree(cache, &size);

char *data = malloc(1);
off64_t memory_block_length = 0;

for (uint32_t i = 0; i < size; ++i) {
struct KVPair *kv = values[i]->data;
memory_block_length += (1 + get_value_size(TELLY_STR, &kv->key) + get_value_size(kv->type, kv->value));
}

char *data = malloc(memory_block_length);

for (uint32_t i = 0; i < size; ++i) {
struct KVPair *kv = values[i]->data;
Expand Down
2 changes: 1 addition & 1 deletion src/hashtable/hashtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct FVPair *get_fv_from_hashtable(struct HashTable *table, const string_t nam
const uint32_t index = hash(name.value, name.len) % table->size.allocated;
struct FVPair *fv = table->fvs[index];

while (fv && !streq(fv->name.value, name.value)) fv = fv->next;
while (fv && ((name.len != fv->name.len) || (memcmp(fv->name.value, name.value, name.len) != 0))) fv = fv->next;
return fv;
}

Expand Down
14 changes: 6 additions & 8 deletions src/hashtable/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void add_fv_to_hashtable(struct HashTable *table, const string_t name, void *val

if ((fv = table->fvs[index])) {
do {
if (streq(fv->name.value, name.value)) {
if ((name.len == fv->name.len) && (memcmp(fv->name.value, name.value, name.len) == 0)) {
found = true;
break;
} else if (fv->next) fv = fv->next;
Expand Down Expand Up @@ -54,10 +54,9 @@ void add_fv_to_hashtable(struct HashTable *table, const string_t name, void *val
fv->hash = hashed;
fv->next = NULL;

const uint32_t size = name.len + 1;
fv->name.len = name.len;
fv->name.value = malloc(size);
memcpy(fv->name.value, name.value, size);
fv->name.value = malloc(name.len);
memcpy(fv->name.value, name.value, name.len);
}
} else {
table->size.all += 1;
Expand All @@ -68,10 +67,9 @@ void add_fv_to_hashtable(struct HashTable *table, const string_t name, void *val
fv->hash = hashed;
fv->next = NULL;

const uint32_t size = name.len + 1;
fv->name.len = name.len;
fv->name.value = malloc(size);
memcpy(fv->name.value, name.value, size);
fv->name.value = malloc(name.len);
memcpy(fv->name.value, name.value, name.len);

table->fvs[index] = fv;
}
Expand All @@ -86,7 +84,7 @@ bool del_fv_to_hashtable(struct HashTable *table, const string_t name) {

if ((fv = table->fvs[index])) {
do {
if (streq(fv->name.value, name.value)) {
if ((name.len == fv->name.len) && (memcmp(fv->name.value, name.value, name.len) == 0)) {
// b is element will be deleted
if (prev) { // a b a or a a b
prev->next = fv->next;
Expand Down

0 comments on commit 72fda30

Please sign in to comment.