HoloDb built on pleroma

HoloDb is built with Pleroma

HoloDb is built with Pleroma, the exact count-and-sum structure in the Phasor package. Three parts of HoloDb are Pleroma parts. This page says what each gives you and what it costs. The first two are optional and off until you ask for them.

Engine results and plane results

The headline results on the evidence page are the engine's, not the plane's. The 10,000,000-invoice billing comparison against SQLite, DuckDB and SQL Server, and the single-row write tables against SQLite, were run on the HoloDb engine alone, with no plane attached. The plane is a separate, opt-in feature, measured in its own runs, where its costs sit beside its wins.

The aggregate plane: exact answers from a derived summary

You name a few small-domain columns (dimensions, INT or TEXT) and the INT columns to sum (measures). HoloDb keeps a Pleroma summary of them, updated by every write, and answers filters, multi-column GROUP BY, COUNT(DISTINCT), MIN and MAX of a dimension, and equi-join COUNT and SUM from it, without scanning the table.

Exact and derived
The columns stay the source of truth, and the plane is rebuilt from them. PleromaVerify rebuilds it and compares, and returns nothing when they agree. Sums are held exactly past 64 bits: the plane raises an error rather than wrap, and PleromaSumExact returns the exact 128-bit total.
It declines safely
Anything the plane does not hold (AVG, a column that is not a dimension or measure, a dimension over its cap of distinct values, a join over 4,095 keys) goes to the engine, so a query returns the same rows with the plane on or off. The default routing, PleromaMode.Auto, also leaves to the engine the shapes where it already reads a maintained total (whole-table counts and sums, single-column GROUP BY) and GROUP BY with a WHERE below 140,000 rows, because the engine is faster there.
What it costs
On a 1,000,000-row table the plane is slower than the engine alone on whole-table COUNT, whole-table SUM, single-column GROUP BY and MIN and MAX, because the engine reads a maintained total in microseconds there. It adds to single-row INSERT and UPDATE, and to bulk load a little. Every cost is in the evidence record beside the wins.
Limits
Memory-resident tables only: a paged table refuses a plane. A plane attached with EnablePleroma is not persisted, so call it again after Open. A plane created with SQL is replayed from the log and survives Checkpoint. It is opt-in per table.

Index SQL and EXPLAIN: build it and see why

The plane has a SQL form, so a remote client can build it through the server like any statement. SHOW INDEXES reports its size and how many queries it served and declined, and EXPLAIN reports why a query was served or declined, without running it.

EXPLAIN runs the engine's own routing code in a mode that stops before the heavy work, so what it reports is the decision the real statement takes. It does not run an IN (SELECT ...) subquery, which it shows unresolved. A binary older than the release that added this SQL cannot open a log or snapshot that contains it.

C#
using HoloDb;

var db = Database.Open();
db.Execute("CREATE TABLE sales (id INT PRIMARY KEY, region TEXT, tier INT, qty INT)");
db.Execute("INSERT INTO sales (id, region, tier, qty) VALUES (1,'north',1,10),(2,'north',2,-4),(3,'south',1,7),(4,'east',3,5),(5,'south',2,9)");

// build the plane from SQL: key columns are dimensions, INCLUDE columns are measures
db.Execute("CREATE INDEX by_region ON sales (region, tier) INCLUDE (qty) USING SUMMARY");
db.PleromaMode = PleromaMode.Always;

Console.WriteLine(db.Execute("SELECT SUM(qty) FROM sales WHERE region = 'north' OR tier = 3").Rows[0]["sum(qty)"]);

// why was it served, or declined?
foreach (var r in db.Execute("EXPLAIN SELECT region, SUM(qty) FROM sales WHERE region = 'north' GROUP BY region").Rows)
    Console.WriteLine($"{r["kind"]}: {r["route"]}");
foreach (var r in db.Execute("EXPLAIN SELECT COUNT(*) FROM sales WHERE qty > 5").Rows)
    Console.WriteLine($"{r["kind"]}: {r["route"]}");

Console.WriteLine(db.PleromaVerify("sales") ?? "plane equals a rebuild from the columns");
Console.WriteLine(db.PleromaSumExact("SELECT SUM(qty) FROM sales"));
Output
11
route: Pleroma plane (exact aggregate from the derived plane)
decline: WHERE uses a column that is not a plane dimension, a dimension over its cap, a column-to-column comparison or a subquery
access: block-wise mask scan
route: predicate count (block-wise byte-mask, no position list)
plane equals a rebuild from the columns
27

The Pleroma page store: durable, checksummed pages

PleromaPageStore holds many exact Pleroma pages as the data itself, durably and larger than memory, with no columns behind them. PleromaSparsePageStore does the same for sparse pages over a large vocabulary.

Checksummed pages
Every page carries a check prime, a mirror of its cells in a second prime, and a header hash. Verify proves every record and parity group intact. VerifyOnLoad does the same on every load and is off by default (about 100 microseconds for a 110-key page).
Parity repair
Records are grouped (8 by default) with one exact-sum parity record per group, and the members of a group sit on different 8 KB pager pages. Any one lost pager page, or any one damaged record per group, is rebuilt by Repair. A rebuilt page must pass its own check before it is written, and a page whose group parity is also damaged is reported as unrecoverable, never rebuilt wrong.
Restore points
Checkpoint returns a restore point, and RestoreTo returns the store to exactly that state with no recount. It is copy-on-write, so a restore point costs one before-image per page changed since, not a copy of the data. Eight are kept by default.
Exactly-once replay
Every AddBatch is journaled (fsynced by default) before it is applied, and each page remembers the last batch applied to it, so crash recovery applies a logged add exactly once, even over pages already flushed. A torn journal tail is discarded, so a batch survives whole or not at all.

Limits: one shape per store, and it must be CompleteKeys and admissible for a check prime. Shapes with a continuous component or a relation face cannot be saved. One process opens a store at a time and one writer works at a time. A batch is applied page by page, so a reader sees every page whole but may see a batch on some pages and not on others. The sparse store has no parity groups, restore points or event journal. Page-store throughput is not reported.

C#
using HoloDb;
using Phasor;

var shape = new HologramShape { KeyCapacity = 2, KeyCycle = 110, CompleteKeys = true };
var dir = Path.Combine(Path.GetTempPath(), "plrstore-restore");
if (Directory.Exists(dir)) Directory.Delete(dir, true);

using (var store = PleromaPageStore.Open(dir, shape))
{
    store.AddBatch(new[] { new PageAdd(42, 5, 3) });
    var point = store.Checkpoint();                       // a restore point: id and journal position
    store.AddBatch(new[] { new PageAdd(42, 5, 10), new PageAdd(9, 1, 1) });
    Console.WriteLine($"{store.Counts(42)[5]} {store.Contains(9)}");

    store.RestoreTo(point.Id);                            // back to the point, no recount
    Console.WriteLine($"{store.Counts(42)[5]} {store.Contains(9)}");

    Console.WriteLine(store.Verify().Clean);
    Console.WriteLine(store.Repair().Unrecoverable.Count);
}
Directory.Delete(dir, true);
Output
13 True
3 False
True
0

Exactness

The plane returns row-for-row the same answers as the engine and SQLite across its parity suite, including a random insert, update, delete, rollback and reopen log, and sums past 64 bits, and the page store passes its fault suite. The checks, and the deliberate mutations that turned them red, are listed with the figures.