|
| | DB (const std::string &path) |
| | Opens or creates a database at the given path.
|
| | ~DB ()=default |
| | Closes the database and releases all file locks.
|
| void | put (std::string_view key, std::string_view value) |
| | Stores a string value under the given key.
|
template<typename T>
requires (std::is_trivially_copyable_v<T> && !std::is_convertible_v<T, std::string_view>) |
| void | put (std::string_view key, const T &value) |
| | Stores a trivially copyable value under the given key.
|
| template<typename T = std::string> |
| auto | get (std::string_view key) const -> std::optional< T > |
| | Retrieves the value stored under the given key.
|
| void | remove (std::string_view key) |
| | Deletes the value stored under the given key.
|
| auto | has (std::string_view key) const -> bool |
| | Returns true if the given key exists in the database.
|
| void | each (const std::function< void(std::string_view, Bytes)> &fn) const |
| | Iterates over all live key-value pairs.
|
| void | prefix (std::string_view pfx, const std::function< void(std::string_view, Bytes)> &fn) const |
| | Iterates over all keys that begin with the given prefix.
|
| void | transaction (const std::function< TxResult(Tx &)> &fn) |
| | Executes a batch of operations atomically.
|
| auto | compact () -> bool |
| | Rewrites the database file retaining only live entries.
|
| auto | key_count () const -> size_t |
| | Returns the number of live keys currently stored.
|
| auto | file_size () const -> size_t |
| | Returns the current size of the database file in bytes.
|
A persistent key-value database backed by a single file.
Keys are UTF-8 strings up to 255 bytes. Values can be std::string, string literals, or any trivially copyable type (int, float, struct, ...).
The database is safe to use from multiple threads concurrently. Reads proceed in parallel, and writes acquire an exclusive lock and are given priority over waiting readers to prevent starvation. See the Thread safety section in the main page for full details.
- Poisoned state
- If a write operation fails at the OS level and the subsequent attempt to truncate the partial write also fails, the DB enters a permanent poisoned state. Every subsequent call to any public method will throw fluxen::poisoned_error.
throw fluxen::poisoned_error. The only recovery is to destroy the DB object. Normal I/O errors that are successfully rolled back do not poison the database.
- Note
DB is non-copyable. Create one instance per file.
- Example
db.put("hits", int64_t{0});
if (auto val = db.get<int64_t>("hits")) {
std::cout << *val << std::endl;
}
A persistent key-value database backed by a single file.
Definition fluxen.hpp:701
template<typename T>
requires (std::is_trivially_copyable_v<T> && !std::is_convertible_v<T, std::string_view>)
| void fluxen::DB::put |
( |
std::string_view | key, |
|
|
const T & | value ) |
|
inline |
Stores a trivially copyable value under the given key.
The value is stored as its raw bytes via memcpy. Overwriting a key with a value of a different size is valid. A subsequent get<T>() call will return nullopt if the stored size does not match sizeof(T).
Acquires an exclusive lock, blocking until all active readers have finished.
- Template Parameters
-
| T | Any trivially copyable type: int, float, bool, struct, etc. Must not be implicitly convertible to std::string_view. |
- Parameters
-
| key | Key to write. Must be between 1 and 255 bytes. |
| value | Value to store. |
- Exceptions
-
- Example
struct Config { int port; bool debug; };
db.put("cfg", Config{8080, false});
db.put("score", int32_t{100});
template<typename T = std::string>
| auto fluxen::DB::get |
( |
std::string_view | key | ) |
const->std::optional< T > |
|
inline |
Retrieves the value stored under the given key.
Returns std::nullopt in two cases:
- The key does not exist.
- For non-string
T: the stored byte size differs from sizeof(T).
The default template parameter is std::string, so db.get("key") and db.get<std::string>("key") are equivalent.
Acquires a shared lock, allowing concurrent calls from other readers. If the memory-mapped file is stale from a recent write, this thread will remap it before reading (see ensure_mapped()).
- Template Parameters
-
| T | The type to deserialise into. Defaults to std::string. Must be std::string or a trivially copyable type. |
- Parameters
-
- Returns
- std::optional<T> containing the value, or std::nullopt.
- Exceptions
-
- Example
auto name = db.get("username");
auto score = db.get<int32_t>("score");
auto cfg = db.get<Config>("cfg");
if (auto v = db.get<int32_t>("score")) {
process(*v);
}
| void fluxen::DB::prefix |
( |
std::string_view | pfx, |
|
|
const std::function< void(std::string_view, Bytes)> & | fn ) const |
|
inline |
Iterates over all keys that begin with the given prefix.
A convenient way to implement namespaced key sets. For example, all keys stored as "user:1001", "user:1002", etc. can be iterated with db.prefix("user:", fn).
The callback and locking behaviour are identical to each(). The same warnings about write methods and Bytes span lifetime apply.
- Parameters
-
| pfx | The prefix string to filter by. |
| fn | Callback of the form void(std::string_view key, Bytes val). |
- Note
- Iteration is O(total keys), not O(matching keys), because the underlying index is a hash map with no sorted order.
- Exceptions
-
| std::runtime_error | If the database is poisoned. |
| fluxen::io_error | If remap fails after flushing deferred write. |
- Example
db.put("user:james", "admin");
db.put("user:bryce", "viewer");
db.put("config:x", "value");
});
| auto fluxen::DB::compact |
( |
| ) |
->bool |
|
inlinenodiscard |
Rewrites the database file retaining only live entries.
The append-only log accumulates dead entries over time as keys are overwritten or deleted. compact() rewrites the file with only the current live values, reclaiming that space.
The rewrite is crash-safe. Compacted data is first written to a temporary file ( <path>.tmp), fsynced, and then atomically renamed over the original. A crash at any point leaves either the original or the fully written new file intact.
Acquires an exclusive lock, blocking all reads and writes for the duration of the rewrite. The database remains fully consistent. If the process is interrupted mid-compact the old file is still intact.
There is no automatic compaction. Call this periodically if your workload involves many overwrites or deletions.
- Returns
- true if compaction succeeded. false if the atomic rename failed. In that case the database is fully intact and usable, just not compacted. The caller may retry later.
- Exceptions
-
| fluxen::poisoned_error | If the database is poisoned. |
| fluxen::io_error | If compaction failed and the original file could not be reopened. The DB object must be destroyed; any further use is undefined. |
| fluxen::io_error | If the file mapping could not be refreshed before or after the rewrite. The DB object must be destroyed due to any further use being undefined. |
- Warning
- On success, invalidates all previously returned Bytes spans and pointers into the mapped region. Reacquire any needed data after a successful compaction. Spans remain valid if false is returned.