Skip to content

Cluster Execution Engine

DistributedQueryBytecode VMPerformance
Beta Works · surface still evolving · the full path — SQL → bytecode → worker VM → streamed result — is built, wired into the remote dispatcher and proven end to end over real sockets; cluster mode itself is still gated behind AETHERIUS_CLUSTER_MODE=1 and the topology file
Premium feature Available only with a license key that grants cluster. Flags and environment variables cannot enable it. To license this feature, contact the AetheriusDB team at aetheriusdb.com or aetheriuslabs.com. The orchestrator and every worker need the grant; a worker started without it exits instead of serving. See Licensing → Premium features.

When AETHERIUS_CLUSTER_MODE=1 is set, the daemon becomes an orchestrator: it owns the catalog and the SQL surface but holds no data. Each worker (AETHERIUS_WORKER_MODE=<cluster>) owns a directory of .acf containers and nothing else — no parser, no planner, no catalog. Between them runs a single idea, applied everywhere:

The orchestrator compiles the question into a few dozen 64-bit instructions. The worker runs them over its column stripes in a register VM and sends back only what the question produces: row offsets, projected cells, one aggregate scalar, or one hash-table slot per group.

Nothing is parsed on the worker. Nothing is allocated per row on either side. The worker never sees SQL; the orchestrator never sees a row it did not ask for.

PieceWhereWhat it does
Remote dispatcheraetherius-runtime::dispatch::remoteRoutes a statement to the cluster that owns its table (or the two clusters of a join), or refuses with a message that names the reason.
Bytecode compileraetherius-orchestratorTurns WHERE, projections, aggregates, GROUP BY and join conditions into Tiny VM programs. Zero heap allocations; ~25 ns for a three-predicate WHERE.
Tiny VMaetherius-runtime::vmA 256-register interpreter with four specialised row loops (filter, materialize, aggregate, join). Reads column stripes in place, including packed nullable stripes through a rank dictionary.
Worker nodeaetherius-runtime::workerA raw TCP listener that discovers its containers, runs programs over every block of the target table, and streams chunked results.
Wire protocolaether-cluster-wire64-byte header, fixed record payloads viewed in place on both sides. Version 17 as of this arc.
Shadow HA streameraetherius-runtime::dispatch::shadow_streamerAsynchronous tail replication of a primary’s .acf to its standby, driven by heartbeat PONGs.

Measured on one Apple M-series core with criterion; each number states what was measured and the caveat that applies. “Dense” means a column with no NULLs; “1 M” is one million rows in a real .acf container.

OperationMeasuredCaveat
VM dispatch, mock block0.78–0.98 ns per instructionVaries per build (see codegen note below).
Compile a 3-predicate WHERE25.5 ns, 13 instructions, 0 allocations
WHERE col1 != 5 OR col2 <= 10, 1 M dense rows5.78–5.90 ms → 5.8 ns/row, 170 M rows/sThe standing regression guard for the filter loop.
Nullable LOAD_COL through the rank dictionary, 1 M rows1.12 ns per instruction
WHERE col1 > 60, 3 containers, 330,000 rows, 105,600 matches1.62 ms VM walk; 3.22 ms end to end over loopback TCP, 27 chunksIncludes result materialisation at the orchestrator.
SELECT COUNT(*) … WHERE over 10,000,000 rows80 bytes on the wire, one frameOffsets would have been 160 MB in 2,443 frames.
SELECT SUM(price) WHERE qty > 0, 5,000,000 rows, 5 containers27.7 ms end to end (5.5 ns/row), 80 bytes of worker outputOffsets would have been 72 MB.
Bytecode join, 20,000 probe rows × 3 build keys, 2,880 pairsrows identical to the oracleCorrectness witness, not a timing.
SQL JOIN across two workers, 30,000 × 2,000 rowsrows identical to the oracleThrough the real dispatcher from SQL text.

The VM’s row loop is sensitive to how many arms it carries. Adding the aggregate and projection arms to one monolithic loop moved the dense 1 M filter bench from 5.90 to 7.3 ms; four structurally equivalent variants measured between 5.8 and 8.2 ms with run-to-run spread under 1 percent. An aligned-loops build reproduced the numbers to 0.1 ms, so alignment was ruled out: the cause is LLVM register allocation across one large match function spilling to the stack. The fix that held was one loop per program kind, each holding only the arms it can execute. The dense bench is back to 5.8 ms and is re-run after every change to the loop.

Every branch that can fire exposes a counter, and the tests assert the counter moved rather than that wall time improved. The system.execution_mode view reports the dispatcher’s mode and its counters:

ColumnMeaning
filters_compiledPrograms compiled at the seam.
frames_shippedEXEC_BYTECODE_REQ frames sent to workers.
chunks_receivedResult frames consumed (offsets, cells, aggregates, groups).
remote_rowsRows materialised from worker replies.

Worker-side counters (worker_exec, worker_table, worker_segment) count rows yielded, chunks sent, blocks walked, refusals, bytes sent, probe frames run, tables loaded, segments served and appended.

VariableRoleEffect
AETHERIUS_CLUSTER_MODE=1OrchestratorSelects the remote dispatcher at boot. Decided once, cached for the process.
AETHERIUS_TOPOLOGY_JSON / AETHERIUS_TOPOLOGY_FILEOrchestratorThe cluster topology: clusters, their addresses, the tables they own, an optional standby.
AETHERIUS_WORKER_MODE=<cluster>WorkerBoots as a worker for the named cluster. No SQL surface is bound.
AETHERIUS_WORKER_PORTWorkerListening port. Default 5434.
AETHERIUS_WORKER_DATA_DIRWorkerThe containers/ directory to discover blocks from. Unset: the worker serves no data and answers every frame EXEC_SUCCESS.
AETHERIUS_ENABLE_MULTI_TENANCY=1BothAccept tenants other than the system tenant. Off by default; see Multi-Tenancy.
AETHERIUS_MAX_CONCURRENT_QUERIES_PER_TENANTOrchestratorStatements one tenant may have in flight. Default 50.
AETHERIUS_TX_TIMEOUTOrchestratorMilliseconds before a stalled transaction is aborted. Default 5000.
AETHERIUS_VACUUM_INTERVALWorkerSeconds between vacuum sweeps. Default 60.
  • Filters: =, !=, <, <=, >, >=, AND, OR, NOT, +, -, *, / over integer columns and literals. Division by zero yields NULL.
  • Projections: any list of columns or *, streamed as columnar chunks with validity bitmaps.
  • Aggregates: COUNT, SUM, MIN, MAX, AVG (as SUM and COUNT, divided at the orchestrator), with or without WHERE.
  • GROUP BY one column with up to four accumulators per group (AVG uses two).
  • Joins: INNER and LEFT equi-joins on one or more columns, with build-side columns projected from the broadcast table and cross-side WHERE conjuncts evaluated after the probe.
  • Text: VARCHAR columns — =, <>, <, <=, >, >= and LIKE 'prefix%', selected back as text. See VARCHAR in Cluster Tables.
  • Writes: INSERT … VALUES, DELETE … WHERE, UPDATE … SET … WHERE, inside or outside a transaction. See Deletes, Updates & the Vacuum and Cluster Transactions.
  • Indexes: point lookups, ranges and prefix searches through a secondary index. See Secondary Indexes on Cluster Tables.

Recorded in the plan documents, not hidden:

  • RIGHT and FULL joins; joins of more than two tables.
  • Floats and timestamps in the VM (they route to the single-node executor); text takes no part in joins.
  • GROUP BY on more than one column; more than four accumulators per group; group tables above 4,096 slots are refused rather than spilled.
  • Cluster mode refuses DDL, and the catalog must exist before the daemon boots as an orchestrator. SET, SHOW, BEGIN/COMMIT/ROLLBACK, EXPLAIN, SELECT without a FROM and the system.* views run on the orchestrator locally and are counted.
  • CREATE INDEX, per-tenant schema changes, tenant snapshots and restores are orchestrator API calls, not SQL statements.

The arc landed in thirteen phases over one working day, each a set of small commits behind a file-length gate and a benchmark. The phase log is in Engine Hardening Log.