Skip to content

Litestore library, a key-value store based on SQLite.

License

Notifications You must be signed in to change notification settings

mlinnosk/liblitestore

Repository files navigation

Litestore library

Buid status

About

What it is and isn't?

Litestore library is a lightweight, embeddable, zero config, key-value style storage system build on SQLite3 database (http://www.sqlite.org/).

Litestore is quite low level. It can be used as is but is intended to be built upon. More about the design in section 'Implementation details'.

It's not a full document database or key-value store server system. Little like comparing SQLite to Mysql or PotgreSQL (actually SQLite compares better than Litestore to CouchDB or MongoDB...).

Why should I use it?

  • If you just want things to work and don't really care about SQL or playing with files.
  • You want to save multiple values in a consistent transactional way that regular files just can't do.
  • Full blown document databases like, CouchDB, MongoDB or Redis are just too huge and have too much dependencies.

License

MIT See LICENSE.txt

SQLite is released in the public domain, see: http://www.sqlite.org/copyright.html This library does not modify SQLite, only links against it.

Please inform me if you use the library ([email protected])!

Building

mkdir build cd build cmake ../ make litestore [make unit_tests && ./tests/unit_tests]

Dependencies

The library:

  • C99 compiler (compile)

    Should be adaptable to older standard.

    Tested with gcc (7.2 64bit, Linux and 6.x 64bit in TravisCI)

  • CMake supported build system or your own build system (compile)

For tests:

  • C++14 compiler

NOTE: sqlite3 and Google test are statically linked and part of this repo. Theres no reason why one couldn't link against shared sqlite3 if one chooses to.

Versioning

Semantic versioning 2.0: http://semver.org/spec/v2.0.0.html See file VERSION, for current version.

Usage example

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "litestore/litestore.h"

/* Callback for raw data, that allocates a new string. */
static
int alloc_str(litestore_blob_t value, void* user_data)
{
    char** res = (char**)user_data;
    *res = strndup((const char*)value.data, value.size);
    return LITESTORE_OK;
}

/* Callback for internal errors. */
static
void err(const int error_code, const char* error_str, void* user_data)
{
    printf("ERR: (%d): %s\n", error_code, error_str);
}

int main(const int argc, const char** argv)
{
    if (argc < 2)
    {
        printf("Must provide DB file name!\n");
        return 0;
    }
    else
    {
        printf("Opening DB to '%s'.\n", argv[1]);
    }

    /* Open the connection */
    litestore* ls = NULL;
    litestore_opts opts = {&err, NULL};
    if (litestore_open(argv[1], opts, &ls) != LITESTORE_OK)
    {
        litestore_close(ls);
        printf("ERROR 1!\n");
        return -1;
    }

    /* Create raw data */
    const char* key = "Hello";
    const char* value = "World!";
    if (litestore_create_raw(ls,
                             litestore_slice_str(key),
                             litestore_make_blob(value, strlen(value)))
        != LITESTORE_OK)
    {
        litestore_close(ls);
        printf("ERROR 2!\n");
        return -1;
    }

    /* Read the created data, note callback usage */
    char* res = NULL;
    if (litestore_read_raw(ls,
                           litestore_slice_str(key),
                           &alloc_str, &res)
        == LITESTORE_OK)
    {
        printf("%s %s\n", key, res);
        free(res);
    }
    else
    {
        printf("ERROR 3!\n");
    }

    /* Clean up, close the connection */
    litestore_close(ls);
    return 0;
}

Basics

Litestore can create objects. Each object has a key and a value. The value can have different types. The key is a user defined UTF-8 encoded string. It can have arbitrary length, though this naturally affects performance since objects are accessed based on the key.

Object values

Value types

Litestore can create two (2) different types of objects. These are:

  • null
  • raw
Null

Simplest is the null type. Basically it can be used as boolean type that either exists or it doesn't. It has no real value and only the key is stored.

Raw

The raw type is just a binary blob and is saved as is. It can be used for any user defined type that can be saved as bytes, either directly or by serializing. Format is totally user dependent.

Implementation details

Design goals

Consistency

The API aims to be concise. All functions return values indicate the success status of the function and possible output parameters are given as the right most function parameters. All API functions and types are prefixed with litestore_. The implementation is not leaked to the user.

Minimum memory allocations

The only memory Litestore library itself allocates, is during open, for the litestore context object. The underlying implementation (SQLite3) does allocations on it's own and these can't be avoided. How ever all the data is passed as directly as possible and possible allocations are left for the user. This enables the usage of custom allocators.

This is also the reasoning behind the callback style API, that admittedly is more cumbersome to use.

On some systems the length of a string is know after constuction (C++ for instance). This is the reason for using the slice_t type for strings. SQLite needs to know the length of the string (or blob) and it is more efficient if explicit strlen() calls can be avoided.

Transactions

Litestore can be used with explicit transactions or implicit transactions. Explicit transactions mean that the user calls the _tx functions explicitely and creates an explicit transaction scope.

If no explicit transaction is created, one will be created on each API call. And commited if the call succeeds.

For better performance, always use explicit transactions to group API calls.

Thread safety

The API is not thread safe. I.E. using the same connection/context in multiple threads is not safe. How ever all the state is stored in the context so it should be safe to create multiple connections, one for each thread, to the same DB. SQLite it self is thread safe, if configured properly. See: http://www.sqlite.org/threadsafe.html

Donate

PayPal

[email protected]

About

Litestore library, a key-value store based on SQLite.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages