fluxen 1.1.1
Single-header embedded key-value store for C++20
Loading...
Searching...
No Matches
fluxen

Single-header embedded key-value store for C++20.

Drop this file into any project and get a persistent key-value database with zero dependencies, no build system changes, and no linking required.

Quick start
#include "fluxen.hpp"
fluxen::DB db("myapp.db");
db.put("username", "rick");
if (auto name = db.get("username")) {
std::cout << *name << std::endl; // "rick"
}
A persistent key-value database backed by a single file.
Definition fluxen.hpp:665
How does it work?
The database is an append-only log on disk backed by a memory-mapped file. An in-memory hash index maps each key to the offset and length of its value in the file. Iteration via each() and prefix() is zero-copy. Callbacks receive a Bytes span pointing directly into the mapped region. get() copies into the return type. Writes append a 6-byte header + key + value to the file. Deletes append a tombstone. The index is rebuilt by scanning the log once on open (last write wins). transaction() stages any number of operations and flushes them as a single write + fsync.
File & data layout
[magic: 8 bytes "FLUXEN01"]
[entry] [entry] ...
entry layout:
flags : 1 byte — 0x00 is live and 0x01 is tombstone
key_len : 1 byte — length of key in bytes (max 255)
val_len : 4 bytes — length of value in bytes (little-endian)
key : key_len bytes
value : val_len bytes (omitted in tombstone entries)
Thread safety
All public methods are thread-safe. Concurrent reads are permitted via a shared mutex: multiple threads may call get(), has(), each(), prefix(), key_count(), and file_size() simultaneously. Write operations (put(), remove(), transaction(), compact()) acquire an exclusive lock and block until all active readers have finished.

The memory-mapped file is remapped lazily: writes leave the mapping stale and the first reader to observe a dirty mapping performs the remap under a secondary sync_mutex_ before proceeding. Subsequent concurrent readers that also observed the dirty flag wait for the remap to complete and then proceed without remapping again.

Important limitations
  • Maximum key length: 255 bytes.
  • Maximum value length: ~4 GB (uint32_t).
  • No range queries (keys are stored in hash order).
  • The full key set lives in RAM (std::unordered_map).
  • Windows-specific: The database file is locked while a DB object exists. You must destroy the DB object before attempting to delete or move the file.
Compiler requirements
C++20. Tested with GCC 12+, Clang 15+, MSVC 19.34+. Runs on Linux, macOS, and Windows.
Version
1.1.1
License
MIT License