Opsmas 2025 Day 7: (kv)(idx)(kit) & (m)
TOC:
kvidxkit
I like writing specific interfaces on top of more general systems. Encapsulation is king. Especially when it involves things like pre-validating or pre-restricting data input/output formats, setting up interfaces or libarires to work “the right way” transparently throughout user interfaces, and even guarding against experienced failure cases by baking in proper edge case handling behind the scenes.
Here we have kvidxkit which is a pluggable storage and access abstraction wrapper on top of sqlite, lmdb, or even rocksdb.
What good is a pluggable wrapper here?
Using the sqlite3 backend as an example, kvidxkit bakes in pre-compiled queries for the common operations with optimal usage behind the scenes. Sure, these are simple queries, but it’s easier to use repeated patterns through an encapsulated and isolated programmatic interface instead of spraying sql and error checking in three dozen places all over your app:
static const char *stmtBegin = "BEGIN;";
static const char *stmtCommit = "COMMIT;";
static const char *stmtGet = "SELECT term, cmd, data FROM log WHERE id = ?;";
static const char *stmtGetPrev = "SELECT id, term, cmd, data FROM log WHERE "
"id < ? ORDER BY id DESC LIMIT 1;";
static const char *stmtGetNext = "SELECT id, term, cmd, data FROM log WHERE "
"id > ? ORDER BY id ASC LIMIT 1;";
static const char *stmtExists = "SELECT EXISTS(SELECT 1 FROM log WHERE id=?);";
static const char *stmtExistsDual =
"SELECT EXISTS(SELECT 1 FROM log WHERE id=? AND term=?);";
static const char *stmtInsert = "INSERT INTO log VALUES(?, ?, ?, ?, ?);";
static const char *stmtRemove = "DELETE FROM log WHERE id = ?;";
static const char *stmtMaxId = "SELECT MAX(id) FROM log;";
static const char *stmtRemoveAfterNInclusive = "DELETE FROM log WHERE id >= ?";
static const char *stmtRemoveBeforeNInclusive = "DELETE FROM log WHERE id <= ?";Then you just use a consistent interface regardless of the backend (could actually be lmdb or anything else with adapters for the interface protocol spec):
/* Open / Close / Management */
bool kvidxOpen(kvidxInstance *i, const char *filename, const char **err);
bool kvidxClose(kvidxInstance *i);
bool kvidxFsync(kvidxInstance *i);
/* Transactional Management */
bool kvidxBegin(struct kvidxInstance *i);
bool kvidxCommit(struct kvidxInstance *i);
bool kvidxAbort(struct kvidxInstance *i);
/* Reading */
bool kvidxGet(kvidxInstance *i, uint64_t key, uint64_t *term, uint64_t *cmd,
const uint8_t **data, size_t *len);
bool kvidxGetPrev(kvidxInstance *i, uint64_t nextKey, uint64_t *prevKey,
uint64_t *prevTerm, uint64_t *cmd, const uint8_t **data,
size_t *len);
bool kvidxGetNext(kvidxInstance *i, uint64_t previousKey, uint64_t *nextKey,
uint64_t *nextTerm, uint64_t *cmd, const uint8_t **data,
size_t *len);
bool kvidxExists(kvidxInstance *i, uint64_t key);
bool kvidxExistsDual(kvidxInstance *i, uint64_t key, uint64_t term);
bool kvidxMaxKey(kvidxInstance *i, uint64_t *key);
bool kvidxInsert(kvidxInstance *i, uint64_t key, uint64_t term, uint64_t cmd,
const void *data, size_t dataLen);
/* Deleting */
bool kvidxRemove(kvidxInstance *i, uint64_t key);
bool kvidxRemoveAfterNInclusive(kvidxInstance *i, uint64_t key);
bool kvidxRemoveBeforeNInclusive(kvidxInstance *i, uint64_t key);it’s not rocket surgery, but it’s simple and well-encapsulated and covers up edge cases, performance optimizations, consistent error checking and error reporting all behind the scenes automatically (instead of trying to remember to do each of those consistently every place you use the underlying DB apis in your apps directly).
kvidxkit also includes my weird take on a sql-generator for C including structured table definitions with auto-generated SQL and even auto-genearted queries where you define your table structure logically then it can be created automatically at runtime:
rando exampos:
User Management System
/* Users table */
static const kvidxColDef userCols[] = {
COL("id", KVIDX_COL_PK_AUTO),
COL("username", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL | KVIDX_COL_UNIQUE),
COL("email", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL | KVIDX_COL_UNIQUE),
COL("password_hash", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL),
COL_DEFAULT_INT("status", KVIDX_COL_INTEGER | KVIDX_COL_NOT_NULL, 1),
COL_DEFAULT_INT("login_count", KVIDX_COL_INTEGER, 0),
COL_DEFAULT_EXPR("created_at", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL, "CURRENT_TIMESTAMP"),
COL_DEFAULT_EXPR("updated_at", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL, "CURRENT_TIMESTAMP"),
COL_DEFAULT_NULL("last_login_at", KVIDX_COL_TEXT),
COL_DEFAULT_NULL("deleted_at", KVIDX_COL_TEXT),
};
static const kvidxIndexDef userIndexes[] = {
INDEX_UNIQUE("username"),
INDEX_UNIQUE("email"),
INDEX("status"),
INDEX("created_at"),
};
static const kvidxTableDef usersTable = {
.name = "users",
.columns = userCols,
.colCount = sizeof(userCols) / sizeof(*userCols),
.indexes = userIndexes,
.indexCount = sizeof(userIndexes) / sizeof(*userIndexes),
};Generated SQL:
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
email TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
status INTEGER NOT NULL DEFAULT 1,
login_count INTEGER DEFAULT 0,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_login_at TEXT DEFAULT NULL,
deleted_at TEXT DEFAULT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS users_username_idx ON users (username);
CREATE UNIQUE INDEX IF NOT EXISTS users_email_idx ON users (email);
CREATE INDEX IF NOT EXISTS users_status_idx ON users (status);
CREATE INDEX IF NOT EXISTS users_created_at_idx ON users (created_at);E-Commerce Order System
/* Products table */
static const kvidxColDef productCols[] = {
COL("id", KVIDX_COL_PK_AUTO),
COL("sku", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL | KVIDX_COL_UNIQUE),
COL("name", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL),
COL("description", KVIDX_COL_TEXT),
COL("price", KVIDX_COL_REAL | KVIDX_COL_NOT_NULL),
COL_DEFAULT_INT("stock", KVIDX_COL_INTEGER | KVIDX_COL_NOT_NULL, 0),
COL_DEFAULT_INT("active", KVIDX_COL_INTEGER | KVIDX_COL_NOT_NULL, 1),
};
/* Orders table */
static const kvidxColDef orderCols[] = {
COL("id", KVIDX_COL_PK_AUTO),
COL_FK("user_id", KVIDX_COL_FK | KVIDX_COL_NOT_NULL, "users"),
COL_DEFAULT_TEXT("status", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL, "pending"),
COL("total", KVIDX_COL_REAL | KVIDX_COL_NOT_NULL),
COL_DEFAULT_EXPR("ordered_at", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL, "CURRENT_TIMESTAMP"),
COL_DEFAULT_NULL("shipped_at", KVIDX_COL_TEXT),
COL_DEFAULT_NULL("delivered_at", KVIDX_COL_TEXT),
};
static const kvidxIndexDef orderIndexes[] = {
INDEX("user_id"),
INDEX("status"),
INDEX("ordered_at"),
INDEX("user_id", "status"),
};
/* Order items (line items) */
static const kvidxColDef orderItemCols[] = {
COL("id", KVIDX_COL_PK_AUTO),
COL_FK("order_id", KVIDX_COL_FK_CASCADE | KVIDX_COL_NOT_NULL, "orders"),
COL_FK("product_id", KVIDX_COL_FK | KVIDX_COL_NOT_NULL, "products"),
COL("quantity", KVIDX_COL_INTEGER | KVIDX_COL_NOT_NULL),
COL("unit_price", KVIDX_COL_REAL | KVIDX_COL_NOT_NULL),
};
static const kvidxIndexDef orderItemIndexes[] = {
INDEX("order_id"),
INDEX("product_id"),
INDEX_UNIQUE("order_id", "product_id"), /* One line item per product per order */
};Multi-Tenant SaaS Application
/* Tenants */
static const kvidxColDef tenantCols[] = {
COL("id", KVIDX_COL_PK_AUTO),
COL("name", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL),
COL("slug", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL | KVIDX_COL_UNIQUE),
COL_DEFAULT_TEXT("plan", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL, "free"),
COL_DEFAULT_INT("active", KVIDX_COL_INTEGER | KVIDX_COL_NOT_NULL, 1),
COL_DEFAULT_EXPR("created_at", KVIDX_COL_TEXT, "CURRENT_TIMESTAMP"),
};
/* Tenant users (with deferred FK for circular references) */
static const kvidxColDef tenantUserCols[] = {
COL("id", KVIDX_COL_PK_AUTO),
COL_FK("tenant_id", KVIDX_COL_FK_CASCADE | KVIDX_COL_NOT_NULL, "tenants"),
COL("email", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL),
COL_DEFAULT_TEXT("role", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL, "member"),
COL_DEFAULT_INT("active", KVIDX_COL_INTEGER | KVIDX_COL_NOT_NULL, 1),
};
static const kvidxIndexDef tenantUserIndexes[] = {
INDEX("tenant_id"),
INDEX_UNIQUE("tenant_id", "email"), /* Email unique per tenant */
INDEX("tenant_id", "role"),
};
/* Tenant resources */
static const kvidxColDef resourceCols[] = {
COL("id", KVIDX_COL_PK_AUTO),
COL_FK("tenant_id", KVIDX_COL_FK_CASCADE | KVIDX_COL_NOT_NULL, "tenants"),
COL("type", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL),
COL("name", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL),
COL("data", KVIDX_COL_BLOB),
COL_DEFAULT_EXPR("created_at", KVIDX_COL_TEXT, "CURRENT_TIMESTAMP"),
COL_DEFAULT_EXPR("updated_at", KVIDX_COL_TEXT, "CURRENT_TIMESTAMP"),
};
static const kvidxIndexDef resourceIndexes[] = {
INDEX("tenant_id"),
INDEX("tenant_id", "type"),
INDEX_UNIQUE("tenant_id", "type", "name"), /* Unique name per type per tenant */
};More Code Example
#include "kvidxkitTableDesc.h"
#include "kvidxkitSchema.h"
#include <sqlite3.h>
#include <stdio.h>
/* Define all columns */
static const kvidxColDef userCols[] = {
COL("id", KVIDX_COL_PK_AUTO),
COL("username", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL | KVIDX_COL_UNIQUE),
COL("email", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL | KVIDX_COL_UNIQUE),
COL_DEFAULT_INT("active", KVIDX_COL_INTEGER | KVIDX_COL_NOT_NULL, 1),
COL_DEFAULT_EXPR("created_at", KVIDX_COL_TEXT, "CURRENT_TIMESTAMP"),
};
static const kvidxColDef postCols[] = {
COL("id", KVIDX_COL_PK_AUTO),
COL_FK("user_id", KVIDX_COL_FK_CASCADE | KVIDX_COL_NOT_NULL, "users"),
COL("title", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL),
COL("body", KVIDX_COL_TEXT),
COL_DEFAULT_INT("published", KVIDX_COL_INTEGER | KVIDX_COL_NOT_NULL, 0),
COL_DEFAULT_EXPR("created_at", KVIDX_COL_TEXT, "CURRENT_TIMESTAMP"),
};
/* Define all indexes */
static const kvidxIndexDef userIndexes[] = {
INDEX_UNIQUE("username"),
INDEX_UNIQUE("email"),
INDEX("active"),
};
static const kvidxIndexDef postIndexes[] = {
INDEX("user_id"),
INDEX("published"),
INDEX("user_id", "published"),
INDEX("created_at"),
};
/* Define all tables */
static const kvidxTableDef tables[] = {
{
.name = "users",
.columns = userCols,
.colCount = sizeof(userCols) / sizeof(*userCols),
.indexes = userIndexes,
.indexCount = sizeof(userIndexes) / sizeof(*userIndexes),
},
{
.name = "posts",
.columns = postCols,
.colCount = sizeof(postCols) / sizeof(*postCols),
.indexes = postIndexes,
.indexCount = sizeof(postIndexes) / sizeof(*postIndexes),
},
};
int main(void) {
sqlite3 *db;
/* Open database */
if (sqlite3_open("blog.db", &db) != SQLITE_OK) {
fprintf(stderr, "Failed to open database\n");
return 1;
}
/* Enable foreign keys */
sqlite3_exec(db, "PRAGMA foreign_keys = ON;", NULL, NULL, NULL);
/* Create all tables */
kvidxError err = kvidxSchemaCreateTables(db, tables,
sizeof(tables) / sizeof(*tables));
if (err != KVIDX_OK) {
fprintf(stderr, "Failed to create tables\n");
sqlite3_close(db);
return 1;
}
/* Generate and print INSERT statement for users */
char buf[1024];
kvidxGenInsert(&tables[0], buf, sizeof(buf));
printf("Users INSERT: %s\n", buf);
/* Generate UPDATE statement */
kvidxGenUpdateById(&tables[0], buf, sizeof(buf));
printf("Users UPDATE: %s\n", buf);
/* Use the generated statements with sqlite3_prepare_v2... */
sqlite3_close(db);
return 0;
}WITHOUT ROWID Table
For key-value stores or tables where you don’t need SQLite’s implicit rowid.
static const kvidxColDef cols[] = {
COL("key", KVIDX_COL_TEXT | KVIDX_COL_PRIMARY_KEY),
COL("value", KVIDX_COL_BLOB),
};
static const kvidxTableDef kvTable = {
.name = "keyvalue",
.columns = cols,
.colCount = 2,
.withoutRowid = true, /* Creates WITHOUT ROWID table */
};Basic Table
static const kvidxColDef cols[] = {
COL("id", KVIDX_COL_PK_AUTO),
COL("name", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL),
};
static const kvidxTableDef table = {
.name = "items",
.columns = cols,
.colCount = sizeof(cols) / sizeof(*cols),
};Table with Indexes
static const kvidxColDef cols[] = {
COL("id", KVIDX_COL_PK_AUTO),
COL("email", KVIDX_COL_TEXT | KVIDX_COL_NOT_NULL),
COL("status", KVIDX_COL_INTEGER),
COL_DEFAULT_EXPR("created", KVIDX_COL_TEXT, "CURRENT_TIMESTAMP"),
};
static const kvidxIndexDef indexes[] = {
INDEX_UNIQUE("email"),
INDEX("status"),
INDEX("status", "created"),
};
static const kvidxTableDef table = {
.name = "users",
.columns = cols,
.colCount = sizeof(cols) / sizeof(*cols),
.indexes = indexes,
.indexCount = sizeof(indexes) / sizeof(*indexes),
};tests n stuff
Start 1: kvidxkit-basic-tests
Start 2: kvidxkit-comprehensive-tests
Start 3: kvidxkit-error-handling-tests
Start 4: kvidxkit-batch-operation-tests
Start 5: kvidxkit-iterator-tests
Start 6: kvidxkit-statistics-tests
Start 7: kvidxkit-configuration-tests
Start 8: kvidxkit-range-operation-tests
1/14 Test #3: kvidxkit-error-handling-tests .... Passed 0.56 sec
Start 9: kvidxkit-export-import-tests
2/14 Test #4: kvidxkit-batch-operation-tests ... Passed 1.19 sec
Start 10: kvidxkit-tabledesc-tests
3/14 Test #2: kvidxkit-comprehensive-tests ..... Passed 1.66 sec
Start 11: kvidxkit-primitives-tests
4/14 Test #1: kvidxkit-basic-tests ............. Passed 2.13 sec
Start 12: kvidxkit-lmdb-adapter-tests
5/14 Test #5: kvidxkit-iterator-tests .......... Passed 2.67 sec
Start 13: kvidxkit-rocksdb-adapter-tests
6/14 Test #6: kvidxkit-statistics-tests ........ Passed 3.38 sec
Start 14: kvidxkit-fuzzer-tests
7/14 Test #7: kvidxkit-configuration-tests ..... Passed 3.76 sec
8/14 Test #8: kvidxkit-range-operation-tests ... Passed 4.42 sec
9/14 Test #9: kvidxkit-export-import-tests ..... Passed 4.28 sec
10/14 Test #10: kvidxkit-tabledesc-tests ......... Passed 3.81 sec
11/14 Test #12: kvidxkit-lmdb-adapter-tests ...... Passed 4.28 sec
12/14 Test #11: kvidxkit-primitives-tests ........ Passed 5.94 sec
13/14 Test #13: kvidxkit-rocksdb-adapter-tests ... Passed 5.23 sec
14/14 Test #14: kvidxkit-fuzzer-tests ............ Passed 296.72 sec
100% tests passed, 0 tests failed out of 14
Total Test time (real) = 300.11 secbenchy and stuff
╔══════════════════════════════════════════════════════════════════════════════╗
║ kvidxkit Performance Benchmark Framework v1.0 ║
╠══════════════════════════════════════════════════════════════════════════════╣
║ Operations: 100000 | Adapters: 3 | Data size: 64 bytes ║
╚══════════════════════════════════════════════════════════════════════════════╝
════════════════════════════════════════════════════════════════════════════════
Benchmarking: SQLite3
════════════════════════════════════════════════════════════════════════════════
[1/10] Sequential Insert...
[2/10] Sequential Read...
[3/10] Random Insert...
[4/10] Random Read...
[5/10] Mixed Workload (80/20)...
[6/10] Batch Insert...
[7/10] Range Count Query...
[8/10] Iterator Scan...
[9/10] Large Data (4KB blobs)...
[10/10] Delete...
Done.
════════════════════════════════════════════════════════════════════════════════
Benchmarking: LMDB
════════════════════════════════════════════════════════════════════════════════
[1/10] Sequential Insert...
[2/10] Sequential Read...
[3/10] Random Insert...
[4/10] Random Read...
[5/10] Mixed Workload (80/20)...
[6/10] Batch Insert...
[7/10] Range Count Query...
[8/10] Iterator Scan...
[9/10] Large Data (4KB blobs)...
[10/10] Delete...
Done.
════════════════════════════════════════════════════════════════════════════════
Benchmarking: RocksDB
════════════════════════════════════════════════════════════════════════════════
[1/10] Sequential Insert...
[2/10] Sequential Read...
[3/10] Random Insert...
[4/10] Random Read...
[5/10] Mixed Workload (80/20)...
[6/10] Batch Insert...
[7/10] Range Count Query...
[8/10] Iterator Scan...
[9/10] Large Data (4KB blobs)...
[10/10] Delete...
Done.
╔══════════════════════════════════════════════════════════════════════════════╗
║ BENCHMARK RESULTS (ops/sec) ║
╚══════════════════════════════════════════════════════════════════════════════╝
Benchmark │ SQLite3 │ LMDB │ RocksDB
─────────────────────┼───────────────────────┼───────────────────────┼───────────────────────
Sequential Insert │ 980.16K │ 803.71K │ 90.30K
Sequential Read │ 907.19K │ 994.53K │ 180.38K
Random Insert │ 433.16K │ 550.39K │ 47.32K
Random Read │ 697.19K │ 747.10K │ 172.45K
Mixed 80/20 R/W │ 807.41K │ 166.52K │ 81.01K
Batch Insert │ 869.35K │ 179.78K │ 64.78K
Range Count Query │ 311 │ 1.38K │ 149.45K
Iterator Scan │ 867.49K │ 939.16K │ 119.46K
Large Data (4KB) │ 49.31K │ 85.62K │ 46.48K
Delete │ 1.18M │ 745.06K │ 114.94K
╔══════════════════════════════════════════════════════════════════════════════╗
║ THROUGHPUT RESULTS (MB/s) ║
╚══════════════════════════════════════════════════════════════════════════════╝
Benchmark │ SQLite3 │ LMDB │ RocksDB
─────────────────────┼───────────────────────┼───────────────────────┼───────────────────────
Sequential Insert │ 59.82 │ 49.05 │ 5.51
Sequential Read │ 55.37 │ 60.70 │ 11.01
Random Insert │ 26.44 │ 33.59 │ 2.89
Random Read │ 42.55 │ 45.60 │ 10.53
Mixed 80/20 R/W │ 49.28 │ 10.16 │ 4.94
Batch Insert │ 53.06 │ 10.97 │ 3.95
Iterator Scan │ 52.95 │ 57.32 │ 7.29
Large Data (4KB) │ 192.64 │ 334.47 │ 181.58
╔══════════════════════════════════════════════════════════════════════════════╗
║ LATENCY RESULTS (microseconds) ║
╚══════════════════════════════════════════════════════════════════════════════╝
Benchmark │ SQLite3 │ LMDB │ RocksDB
─────────────────────┼───────────────────────┼───────────────────────┼───────────────────────
Sequential Insert │ 1.02 │ 1.24 │ 11.07
Sequential Read │ 1.10 │ 1.01 │ 5.54
Random Insert │ 2.31 │ 1.82 │ 21.13
Random Read │ 1.43 │ 1.34 │ 5.80
Mixed 80/20 R/W │ 1.24 │ 6.01 │ 12.34
Batch Insert │ 1.15 │ 5.56 │ 15.44
Range Count Query │ 3212.83 │ 724.78 │ 6.69
Iterator Scan │ 1.15 │ 1.06 │ 8.37
Large Data (4KB) │ 20.28 │ 11.68 │ 21.51
Delete │ 0.85 │ 1.34 │ 8.70
╔══════════════════════════════════════════════════════════════════════════════╗
║ WINNER REPORT - Best Adapter by Operation ║
╠══════════════════════════════════════════════════════════════════════════════╣
║ (~) = within 10% of leader, considered statistical tie ║
╚══════════════════════════════════════════════════════════════════════════════╝
Operation │ Winner │ Performance │ Ranking (slowdown factor)
─────────────────────┼──────────────┼──────────────┼──────────────────────────────────────
Sequential Insert │ SQLite3 │ 980.16K/s │ SQLite3 > LMDB(1.2x) > RocksDB(10.9x)
Sequential Read │ ~TIE~ │ 994.53K/s │ LMDB ~ SQLite3 > RocksDB(5.5x)
Random Insert │ LMDB │ 550.39K/s │ LMDB > SQLite3(1.3x) > RocksDB(11.6x)
Random Read │ ~TIE~ │ 747.10K/s │ LMDB ~ SQLite3 > RocksDB(4.3x)
Mixed 80/20 R/W │ SQLite3 │ 807.41K/s │ SQLite3 > LMDB(4.8x) > RocksDB(10.0x)
Batch Insert │ SQLite3 │ 869.35K/s │ SQLite3 > LMDB(4.8x) > RocksDB(13.4x)
Range Count Query │ RocksDB │ 149.45K/s │ RocksDB > LMDB(108.3x) > SQLite3(480.2x)
Iterator Scan │ ~TIE~ │ 939.16K/s │ LMDB ~ SQLite3 > RocksDB(7.9x)
Large Data (4KB) │ LMDB │ 85.62K/s │ LMDB > SQLite3(1.7x) > RocksDB(1.8x)
Delete │ SQLite3 │ 1.18M/s │ SQLite3 > LMDB(1.6x) > RocksDB(10.3x)
╔══════════════════════════════════════════════════════════════════════════════╗
║ OVERALL SCORE BY ADAPTER ║
╠══════════════════════════════════════════════════════════════════════════════╣
║ Clear wins = 1 point, Tied wins = 0.5 points each ║
╚══════════════════════════════════════════════════════════════════════════════╝
SQLite3 █████▌░░░░ 5.5 pts (4 clear + 3 tied) <- OVERALL WINNER
LMDB ███▌░░░░░░ 3.5 pts (2 clear + 3 tied)
RocksDB █░░░░░░░░░ 1.0 pts (1 clear)
╔══════════════════════════════════════════════════════════════════════════════╗
║ BENCHMARK COMPLETE ║
╚══════════════════════════════════════════════════════════════════════════════╝stats
===============================================================================
Language Files Lines Code Comments Blanks
===============================================================================
C 28 23296 17761 2610 2925
C Header 14 2085 925 876 284
CMake 1 233 154 35 44
-------------------------------------------------------------------------------
Markdown 13 4520 0 2879 1641
|- BASH 8 221 137 56 28
|- C 12 3660 2731 430 499
|- CMake 2 10 8 1 1
|- Dockerfile 1 24 13 5 6
|- Markdown 1 13 0 7 6
|- SQL 2 35 33 0 2
|- YAML 1 72 70 0 2
(Total) 8555 2992 3378 2185
===============================================================================
Total 56 30134 18840 6400 4894
===============================================================================of course, this key-term-value index compliance safe-committed storage system was designed to be useful in real world scenarios where you need guaranteed trustworthy term-key-value logging which we will get to… probably tomorrow.
m
mixtures of experts are so hot right now.
so anyway, i started blasting, bang bang and i banged out a mixture of expert mixing system earlier this year
it just takes numbers from the past and tries to predict numbers from the future. no big deal. there’s pictures and stuff in the repo of it predicting/completing geometric shapes with various perturberances applied in various dimensional spaces.
i can’t imagine why anybody would care about high dimensional number predicting or anything.
stats
===============================================================================
Language Files Lines Code Comments Blanks
===============================================================================
Python 28 14481 10913 1124 2444
YAML 10 791 637 38 116
-------------------------------------------------------------------------------
Markdown 5 1741 0 1135 606
|- BASH 2 131 63 44 24
|- Python 5 1114 785 166 163
|- YAML 3 81 67 6 8
(Total) 3067 915 1351 801
===============================================================================
Total 43 17013 11550 2297 3166
===============================================================================