New: prepared statements, UPDATE and DELETE, and key lookups that seek — 0.143 ms through the gateway.Read the update

Platform · Row storage

Rows that are durable before they are acknowledged.

A log-structured engine with snapshot-isolation transactions, idempotent writes and a garbage-collection horizon that is itself durable. Key lookups read one row. Every number here is from a dated report on a shared development host.

412,447Point reads per secondYCSB C, one client; RocksDB 274,508 in the same run
0.143 msPrimary-key SELECT through psql10,608 lookups/s at 8 clients; was 5.52 ms before key seeks
23 msWorst write latencyWas 371 ms before incremental compaction
19,243Durable writes per second32 clients, 17 writes per fdatasync on average
Guarantees

What a write means

These are the properties the engine's tests hold it to. Each one has a test or a campaign behind it; none is a configuration option.

Snapshot isolation

A transaction reads from one snapshot and commits only if no other transaction committed a write to the same keys after that snapshot: first committer wins. Write skew is allowed under snapshot isolation; serializable isolation comes with the distributed phase.

Built

Idempotent writes

A write can carry a client key. Retrying the same key returns the original outcome instead of writing twice; retrying it with a different batch is an error, not a silent second write.

Built

Durable GC horizon

Every write gets a commit timestamp and old versions are kept until a durable horizon passes them. Reading at a snapshot older than the horizon is an explicit error, never a partial answer.

Built

Acknowledged means on disk

A batch is a checksummed, chained record in the write-ahead log and is acknowledged only after it is durable. If a sync fails, the log refuses further writes rather than guess what reached the disk.

Built

Recovery that does not guess

On start the log is replayed from the last flushed point. A torn record at the end is cut off; damage in the middle is reported as corruption, never skipped. One million simulated crash points, no acknowledged write lost.

Built

Tenant as a key range

A tenant's rows live in that tenant's key range, so isolation is a bound on the scan, not a predicate someone must remember. SQL tables carry a tenant key you can neither read nor write.

Built
SQL writes

What UPDATE and DELETE guarantee

The SQL subset is small on purpose. What it does run, it runs completely or not at all. Details in SQL and psql.

Each statement is one atomic step

An UPDATE … SET … WHERE or DELETE … WHERE is bound to a verified plan that yields the affected rows, and the node writes the result in one batch. There is no half-applied statement. An INSERT of an existing primary key fails the whole statement with 23505.

Only your tenant, never the key

An update or delete changes only the requester's tenant's rows. A primary key cannot be changed by UPDATE. Two tenants can both hold an order 1; neither statement can reach the other's.

Masked columns are protected

An UPDATE of a table with columns above your clearance is refused with 42501 rather than risk writing over values you cannot see. This case was found while building the feature and is now refused at bind time and again at the node.

Not yet

BEGIN/COMMIT/ROLLBACK over SQL, RETURNING and ON CONFLICT are the next SQL phase. Until then, several statements in one query string are refused when one of them writes, because there is no transaction to undo a half-applied string. Planned

Key seeks

A key lookup reads one row

Before 23 October a primary-key SELECT read the tenant's whole key range and filtered. Now a lookup or a range on the primary key reads only the matching rows, and the result is checked to be identical either way.

SQL through the gateway, pgbench, prepared statements

Loopback TCP → gateway → node, 10 s per run, 0 failed transactions (23 Oct 2026, commit 4362b9d). "Before" is the same run one day earlier, without key seeks.

StatementClientsAvg msBeforeStmts/s
Primary-key SELECT10.1435.526,984
Primary-key SELECT80.76741.710,608
GROUP BY with count and sum15.385.64189
Single-row INSERT10.9221.061,149
Single-row INSERT86.176.81,296

What a seek never does

The rule, and the test that holds it

  • A seek never changes an answer: 20 000 generated primary-key predicates are run with seeks and without, and must agree.
  • Bounds are taken only from equality, IN, ranges and BETWEEN on primary-key columns of the exact type. A masked column, a cast, an OR or a columnar collection falls back to the full tenant range.
  • Every security operator and the filter still run on every row read, so a source that ignores the hint stays correct.
  • Aggregates and inserts did not change: a GROUP BY still reads every row on one engine thread, and inserts wait on the log sync. Parallel reads and group commit for collection inserts are the next levers.
Measured

Engine numbers, with the host named

All runs on a shared development host, 3 CPUs / 6 GB; indicative, not a production promise. One client, fsync on every write, 100-byte values, no compression in either engine. RocksDB is the project's differential oracle and runs in the same harness.

Key-value engine, YCSB-style

Operations per second, 19 Oct 2026, same run for both engines

UltraFabric RocksDB
0227k454kUltraFabric C: point reads: 412447 ops/sRocksDB C: point reads: 274508 ops/sC: point readsUltraFabric E: short scans: 22655 ops/sRocksDB E: short scans: 21927 ops/sE: short scans

Group commit through the node

Durable single-key writes over the Unix socket; writes that queue while one fdatasync is in flight go out together in the next one

ClientsWrites/sp99Writes per fdatasync
11,2331.2 ms1.0
85,1482.1 ms4.0
3219,2432.3 ms17.0

Honest reading

Where RocksDB is still ahead

  • RocksDB keeps a lower p99 on point reads: 7.6 µs against 11.5 µs in the same run.
  • Write-heavy memory is 32 MB against RocksDB's 26 MB.
  • Worst-case write latency is within about 25% of RocksDB's after incremental compaction; it was 15× worse before.
  • The dataset (about 35 MB) fits the page cache and there is one client. Nothing here is a production promise; see the RocksDB comparison.
Inside

How the engine is built

Enough to judge the design; the storage docs have the rest.

  • Write-ahead log, memtable, sorted table filesEach batch is a record with a length, a CRC-32C and a chained hash. Table files are sorted blocks with restart points, a Bloom filter, an index and a checksummed footer; every block is verified when read.
  • Atomic manifestA flush or compaction becomes visible in one manifest record, written after the new files are complete and verified.
  • Incremental compactionMerging runs in bounded steps alongside writes, with a stop trigger for backpressure, so a large merge never stalls a single write. Finished blocks stream to the output file in 1 MiB chunks instead of buffering whole tables.
  • Byte-bounded block cacheRaw blocks are cached and decoded one entry at a time from the nearest restart point. Reads check the memtable, then table files newest first, skipping files by Bloom filter.

Engine seam. Storage is reached through one trait with three implementations: this engine, a RocksDB binding used as the differential oracle and documented fallback, and an in-memory reference model. Every storage test runs against all of them.

Read the storage docs, then the bench reports.

Every figure above names its commit and its raw result file in the repository.