Implexus provides a flexible storage layer through the Dbm interface, allowing applications to choose the most appropriate backend for their use case.
The Dbm interface defines a low-level key-value storage abstraction with support for:
get, set, delete, has_key)keys propertybegin_transaction, commit_transaction, rollback_transaction)The storage layer is used by BasicStorage to provide high-level entity persistence operations, and by IndexManager for index storage.
Location: src/Storage/FilesystemDbm.vala
A simple file-based storage implementation where each key-value pair is stored in a separate file within a directory.
| Property | Value |
|---|---|
| Transaction Support | Software-based (in-memory buffering) |
| Performance | Good for small datasets, degrades with size |
| Dependencies | None (pure GLib) |
| File Format | One file per key, hex-encoded filenames |
var dbm = new FilesystemDbm("/path/to/data/directory");
var storage = new BasicStorage(dbm);
Location: src/Storage/Gdbm/GdbmDbm.vala
A production-ready backend using the GNU DBM library for persistent key-value storage.
| Property | Value |
|---|---|
| Transaction Support | Software-based (in-memory buffering) |
| Performance | Good for medium datasets |
| Dependencies | libgdbm |
| File Format | Single database file with hash table structure |
var dbm = new GdbmDbm();
dbm.open("/path/to/database.gdbm", false); // false = read-write mode
var storage = new BasicStorage(dbm);
Location: src/Storage/Lmdb/LmdbDbm.vala
A high-performance backend using the Lightning Memory-Mapped Database (LMDB).
| Property | Value |
|---|---|
| Transaction Support | Native ACID transactions |
| Performance | Excellent for read-heavy workloads |
| Dependencies | liblmdb |
| File Format | Memory-mapped B+tree |
| Map Size | Default 1GB (configurable) |
var dbm = new LmdbDbm();
dbm.open("/path/to/lmdb/directory", false); // false = read-write mode
var storage = new BasicStorage(dbm);
| Backend | Transaction Type | Read Performance | Write Performance | Concurrent Reads | Concurrent Writes | Dependencies | Recommended Use Case |
|---|---|---|---|---|---|---|---|
| FilesystemDbm | Software | Poor | Poor | No | No | None | Development, testing |
| GdbmDbm | Software | Good | Good | Limited | No | libgdbm | Single-threaded apps |
| LmdbDbm | Native ACID | Excellent | Good | Yes | Single writer | liblmdb | Production, high-performance |
When using EngineConfiguration for embedded mode, the storage backend is selected based on the application's needs:
// Create embedded configuration with storage path
var config = EngineConfiguration.embedded("/path/to/database");
// The EngineFactory creates the appropriate backend
var engine = EngineFactory.create(config);
For direct control over the storage backend:
// Using LMDB for high performance
var lmdb = new LmdbDbm();
lmdb.open("/data/implexus-lmdb", false);
var storage = new BasicStorage(lmdb);
var index_manager = new IndexManager(lmdb);
// Using GDBM for medium workloads
var gdbm = new GdbmDbm();
gdbm.open("/data/implexus.gdbm", false);
var storage = new BasicStorage(gdbm);
// Using FilesystemDbm for testing
var fsdbm = new FilesystemDbm("/data/test-storage");
var storage = new BasicStorage(fsdbm);
All backends implement the same transaction interface, but with different guarantees:
dbm.begin_transaction();
try {
dbm.set("key1", value1);
dbm.set("key2", value2);
dbm.delete("key3");
dbm.commit_transaction();
} catch (StorageError e) {
dbm.rollback_transaction();
}
Operations are buffered in memory and applied atomically on commit. Rollback discards the buffer without modifying persistent storage.
LMDB provides true ACID transactions with crash recovery and durability guarantees. The same API is used:
dbm.begin_transaction();
try {
dbm.set("key1", value1);
dbm.set("key2", value2);
dbm.commit_transaction();
} catch (StorageError e) {
dbm.rollback_transaction();
}
For applications with high read-to-write ratios, LmdbDbm is recommended due to:
For write-intensive applications:
For development or small embedded applications:
To migrate data between backends:
// Open source backend
var source = new GdbmDbm();
source.open("/old/database.gdbm", true); // read-only
// Open target backend
var target = new LmdbDbm();
target.open("/new/lmdb/dir", false); // read-write
// Copy all keys
foreach (var key in source.keys) {
var value = source.get(key);
if (value != null) {
target.set(key, (!) value);
}
}