Hello Elixir and Nerves community,
I have been working for a while on an open-source embedded key-value database for Elixir, that I called CubDB
. I use it for several IoT projects I run using Nerves, where I need to store large-ish amount of data locally to the device.
I am already using it in production, but before I release version 1.0.0 I would love some feedback from the Nerves (and Elixir) community.
You can find the CubDB repository here
And here the API documentation
A quick basic usage example:
{:ok, db} = CubDB.start_link("my/data/directory")
CubDB.put(db, :foo, "some value")
#=> :ok
CubDB.get(db, :foo)
#=> "some value"
CubDB.delete(db, :foo)
#=> :ok
CubDB.put(db, {:keys, "can", :be, 'anything'}, ["and", :values, 'too'])
#=> :ok
# Check out docs for advanced usage with select/3 and get_and_update_multi/4
I know that Elixir comes with ETS/DETS and Mnesia, but:
-
ETS is not persistent across reboots
-
DETS does not offer sorted collections, and is thus not ideal when one needs to select arbitrary ranges of keys, iterate in order, etc.
-
Mnesia is great, but on embedded projects I don’t need distribution
-
Sometimes I really just need a “persisted map”, sorted by key
-
It’s nice to be able to backup the whole DB by just copying one file
The use-cases I am primarily targeting is what described in this blog post by the Nerves team: Using Ecto and Sqlite3 with Nerves - Embedded Elixir
CubDB
is somehow similar to SQLite in which it stores the data locally in a single file, but it is written in Elixir, is key-value and schema-less, and both keys and values can be any Elixir (or Erlang) terms, so no serialization/de-serialization is needed.
The data structure it uses is an append-only immutable B-tree, inspired by CouchDB: that guarantees robustness to data corruption (no in-place mutation), and enables features like concurrent read operations that do not block writes, and atomic transactions.
It was already a lot of fun for me to develop it, but I would love to hear your constructive feedback.
What do you think about it? Do you have a use-case where this could be useful? Do you have feedback about the API?
Thanks in advance