Skip to content

Resonious/filedict

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Filedict

This is a single-header C library that provides very simple file-backed key-value store.

Filedict does not allocate memory using malloc or similar; it only uses open and mmap. All values are const char * and live inside the file-backed memory.

I built this specifically for very fast data sharing between a running Ruby program and language server process.

Key features

  • Simple file-backed key-value store. (hashmap style. not a btree)
  • Great for when you need to save data but redis or sqlite is too much.
  • Doesn't allocate memory.
  • No dependencies other than the C standard library.
  • All in a single header - no need to mess with your linker or package manager.

What data does this store, exactly?

String keys, each associated with one or more string values.

All keys and all values are null-terminated C strings. Works fine with UTF-8 because it doesn't actually parse anything.

There is a size limit! By default, keys and values share a single 512-byte buffer. You can change this with #define FILEDICT_BUCKET_ENTRY_BYTES 1024 if you'd like. But do note that this will make your data files much larger and more spacious unless you actually use most of the bytes.

Despite the size limit on individual keys and values, there is actually no limit on how many values you can have under one key, or how many keys you can have. The store can grow indefinitely without any re-hashing. Also, storing many small values under the same key will stuff all of the values into the same entry until that entry runs out of space.

How to use

#include "../path/to/filedict.h"

int main() {
    /* Init a new filedict */
    filedict_t filedict;
    filedict_init(&filedict);

    /* You need to open a file before using it! */
    filedict_open_new(&filedict, "my-data-store.filedict");

    /* Instead of error return-values, most functions will set filedict.error
     * when something goes wrong.
     */
    if (filedict.error) {
        printf("Something went wrong: %s\n", filedict.error);
        return 1;
    }

    filedict_insert(&filedict, "my key", "my value");

    filedict_read_t read = filedict_get(&filedict, "my key");
    assert(strcmp(read.value, "my key") == 0);

    /* Because filedict lets you store multiple values under the same key, you
     * can use this "filedict_read_t" to get the rest of the values by calling
     * `filedict_get_next(&read)` until it returns 0.
     */

    /* This will unmap the memory and close the file. */
    filedict_deinit(&filedict);

    return 0;
}