feat: use custom binary file format for data

generic-data-trie
Jef Roosens 2022-12-07 23:55:46 +01:00
parent c99bc83015
commit 4b772d003b
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
4 changed files with 69 additions and 59 deletions

View File

@ -34,13 +34,14 @@ static const std::string index_page = R"(
crow::response add_redirect(std::string base_url, Trie *trie, const char *url, crow::response add_redirect(std::string base_url, Trie *trie, const char *url,
bool secure) { bool secure) {
Entry *new_entry = entry_new(Redirect, url); Entry *new_entry;
uint64_t entry_size = entry_new(&new_entry, Redirect, url);
// The key already gets copied into the trie, so this pointer is safe to use // The key already gets copied into the trie, so this pointer is safe to use
// ever after unlocking the trie // ever after unlocking the trie
trie_wlock(trie); trie_wlock(trie);
char *key; char *key;
TrieExitCode res = trie_add_random(trie, &key, new_entry, secure); TrieExitCode res = trie_add_random(trie, &key, new_entry, entry_size, secure);
trie_unlock(trie); trie_unlock(trie);
if (res != Ok) { if (res != Ok) {
@ -70,11 +71,12 @@ bool store_paste(const char *key, const char *body) {
crow::response add_paste(std::string base_url, Trie *trie, const char *body, crow::response add_paste(std::string base_url, Trie *trie, const char *body,
bool secure) { bool secure) {
Entry *new_entry = entry_new(Paste, ""); Entry *new_entry;
uint64_t entry_size = entry_new(&new_entry, Paste, "");
trie_wlock(trie); trie_wlock(trie);
char *key; char *key;
TrieExitCode res = trie_add_random(trie, &key, new_entry, secure); TrieExitCode res = trie_add_random(trie, &key, new_entry, entry_size, secure);
trie_unlock(trie); trie_unlock(trie);
if (res != Ok) { if (res != Ok) {
@ -169,10 +171,13 @@ int main() {
[api_key, base_url, trie](const crow::request &req, std::string key) { [api_key, base_url, trie](const crow::request &req, std::string key) {
AUTH(); AUTH();
Entry *new_entry = entry_new(Redirect, req.body.c_str()); Entry *new_entry;
uint64_t entry_size =
entry_new(&new_entry, Redirect, req.body.c_str());
trie_wlock(trie); trie_wlock(trie);
TrieExitCode status = trie_add(trie, key.c_str(), new_entry); TrieExitCode status =
trie_add(trie, key.c_str(), new_entry, entry_size);
trie_unlock(trie); trie_unlock(trie);
switch (status) { switch (status) {
@ -209,9 +214,11 @@ int main() {
[api_key, base_url, trie](const crow::request &req, std::string key) { [api_key, base_url, trie](const crow::request &req, std::string key) {
AUTH(); AUTH();
Entry *new_entry = entry_new(Paste, ""); Entry *new_entry;
uint64_t entry_size = entry_new(&new_entry, Paste, "");
trie_wlock(trie); trie_wlock(trie);
TrieExitCode status = trie_add(trie, key.c_str(), new_entry); TrieExitCode status =
trie_add(trie, key.c_str(), new_entry, entry_size);
trie_unlock(trie); trie_unlock(trie);
switch (status) { switch (status) {

View File

@ -42,7 +42,7 @@ typedef enum entry_type { Redirect, Paste, Unknown } EntryType;
typedef struct entry { typedef struct entry {
EntryType type; EntryType type;
char *string; char string[];
} Entry; } Entry;
typedef enum trie_exit_code { typedef enum trie_exit_code {
@ -52,7 +52,7 @@ typedef enum trie_exit_code {
FileError FileError
} TrieExitCode; } TrieExitCode;
Entry *entry_new(EntryType type, const char *string); uint64_t entry_new(Entry **entry_ptr, EntryType type, const char *string);
void entry_free(Entry *entry); void entry_free(Entry *entry);
@ -89,7 +89,8 @@ TrieExitCode trie_search(Trie *trie, void **data_ptr, const char *key);
* @param entry entry to add * @param entry entry to add
* @return 0 if added, 1 if already in trie, something else if other errors * @return 0 if added, 1 if already in trie, something else if other errors
*/ */
TrieExitCode trie_add(Trie *trie, const char *key, void *data); TrieExitCode trie_add(Trie *trie, const char *key, void *data,
uint64_t data_len);
/** /**
* Add an entry by generating a random string as the key. * Add an entry by generating a random string as the key.
@ -101,7 +102,7 @@ TrieExitCode trie_add(Trie *trie, const char *key, void *data);
* unlocking the trie, and should be freed manually. * unlocking the trie, and should be freed manually.
*/ */
TrieExitCode trie_add_random(Trie *trie, char **key_ptr, void *data, TrieExitCode trie_add_random(Trie *trie, char **key_ptr, void *data,
bool secure); uint64_t data_len, bool secure);
/** /**
* Remove an entry from this trie given its key. * Remove an entry from this trie given its key.

View File

@ -43,42 +43,45 @@ TrieExitCode trie_init(Trie **trie_ptr, const char *file_path) {
return FileError; return FileError;
} }
// We read in lines of at most 8192 characters (sounds like enough) uint64_t key_size, data_size;
char buffer[8192]; char *key;
EntryType type; void *data;
Entry *entry;
char *string;
int i, j;
TrieExitCode status; TrieExitCode status;
size_t items_read;
while (fgets(buffer, 8192, fp)) { while (!feof(fp)) {
i = 0; items_read = fread(&key_size, sizeof(uint64_t), 1, fp);
if (items_read < 1) {
// Move index in buffer until we encounter first space character break;
while (buffer[i] != ' ') {
i++;
} }
// Split the buffer into two strings, the key and the payload key = malloc(key_size + 1);
buffer[i] = '\0';
type = entry_type_from_char(buffer[i + 1]); items_read = fread(key, 1, key_size, fp);
if (items_read < key_size) {
// Skip type character & its surrounding spaces break;
j = i + 3;
// Now remove the newline character
while (buffer[j] != '\n') {
j++;
} }
buffer[j] = '\0'; key[key_size] = '\0';
entry = entry_new(type, buffer + i + 3); items_read = fread(&data_size, sizeof(uint64_t), 1, fp);
status = trie_add_no_lock(trie, buffer, entry); if (items_read < 1) {
break;
}
data = malloc(data_size);
items_read = fread(data, 1, data_size, fp);
if (items_read < data_size) {
break;
}
status = trie_add_no_lock(trie, key, data);
if (status != Ok) { if (status != Ok) {
trie_free(trie); trie_free(trie);
free(key);
free(data);
return status; return status;
} }
} }
@ -275,7 +278,8 @@ TrieExitCode trie_add_no_lock(Trie *trie, const char *string, void *data) {
return Ok; return Ok;
} }
TrieExitCode trie_add(Trie *trie, const char *key, void *entry) { TrieExitCode trie_add(Trie *trie, const char *key, void *data,
uint64_t data_len) {
if (trie->file_path != NULL) { if (trie->file_path != NULL) {
// Easiest way to make sure we don't add duplicate entries // Easiest way to make sure we don't add duplicate entries
// We use an internal function that doesn't require a read lock, as we're // We use an internal function that doesn't require a read lock, as we're
@ -290,23 +294,24 @@ TrieExitCode trie_add(Trie *trie, const char *key, void *entry) {
return FileError; return FileError;
} }
/* fputs(key, fp); */ // First we write the key, then the actual data
/* fputs(" ", fp); */ uint64_t key_len = (uint64_t)strlen(key);
/* fputc(entry_type_to_char(entry->type), fp); */ fwrite(&key_len, 1, sizeof(uint64_t), fp);
/* fputs(" ", fp); */ fwrite(key, 1, key_len, fp);
/* fputs(entry->string, fp); */
/* fputs("\n", fp); */ fwrite(&data_len, 1, sizeof(uint64_t), fp);
fwrite(data, 1, data_len, fp);
fclose(fp); fclose(fp);
} }
// This function *should* always return Ok. Otherwise, the function would've // This function *should* always return Ok. Otherwise, the function would've
// exited because the string was found in the trie. // exited because the string was found in the trie.
return trie_add_no_lock(trie, key, entry); return trie_add_no_lock(trie, key, data);
} }
TrieExitCode trie_add_random(Trie *trie, char **key_ptr, void *data, TrieExitCode trie_add_random(Trie *trie, char **key_ptr, void *data,
bool secure) { uint64_t data_len, bool secure) {
// Generate random key // Generate random key
bool ok = false; bool ok = false;
int key_length = secure ? RANDOM_KEY_LENGTH_LONG : RANDOM_KEY_LENGTH_SHORT; int key_length = secure ? RANDOM_KEY_LENGTH_LONG : RANDOM_KEY_LENGTH_SHORT;
@ -324,7 +329,7 @@ TrieExitCode trie_add_random(Trie *trie, char **key_ptr, void *data,
ok = trie_search_node(trie, key).child == NULL; ok = trie_search_node(trie, key).child == NULL;
} }
TrieExitCode return_value = trie_add(trie, key, data); TrieExitCode return_value = trie_add(trie, key, data, data_len);
if (return_value == Ok) { if (return_value == Ok) {
*key_ptr = key; *key_ptr = key;

View File

@ -23,23 +23,20 @@ char entry_type_to_char(EntryType et) {
} }
} }
Entry *entry_new(EntryType type, const char *string) { uint64_t entry_new(Entry **entry_ptr, EntryType type, const char *string) {
Entry *entry = malloc(sizeof(Entry)); size_t str_len = strlen(string);
uint64_t entry_size = sizeof(EntryType) + str_len + 1;
Entry *entry = malloc(entry_size);
entry->type = type; entry->type = type;
if (string != NULL) { if (string != NULL) {
entry->string = strdup(string); memcpy(entry->string, string, str_len + 1);
} else { } else {
entry->string = NULL; entry->string[0] = '\0';
} }
return entry; *entry_ptr = entry;
return entry_size;
} }
void entry_free(Entry *entry) { void entry_free(Entry *entry) { free(entry); }
if (entry->string != NULL) {
free(entry->string);
}
free(entry);
}