Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Peer server and thin clients

A peer server is a peer hosted as a standalone process. It exposes query, pull, transact, datom scans, and transaction ranges over gRPC.

Use it for a language that has no peer library. For a language with a peer library, embed the peer instead. An embedded peer queries in-process.

Start a peer server

corium peer-server --db people --listen 0.0.0.0:4336 \
  --transactor http://127.0.0.1:4334

One process hosts one database. Run one process per database.

FlagDefaultEffect
--db <name>None. Required.Database to host.
--listen <addr>127.0.0.1:4336gRPC listen address.
--max-fuel <n>10000000Ceiling on datoms touched per query.
--metrics-listen <addr>NonePrometheus endpoint at /metrics.

The peer server takes the same connection flags as the other client commands, and the same serving flags as the transactor.

Query fuel

Fuel bounds a runaway query. A client can request less fuel. fuel = 0 requests the server default. The server clamps every request to --max-fuel.

An exhausted budget returns INVALID_ARGUMENT.

Storage bootstrap

By default the peer server replays the log from basis 0 at startup. On a large database that is slow.

corium peer-server --db people --peer-bootstrap \
  --storage-key file:/etc/corium/storage.key

--peer-bootstrap reads the published snapshot from storage and subscribes from the index basis. The peer needs network reach to the storage backend, and a build with the matching storage feature.

The transactor supplies the connection details through its GetStorageInfo call, using the read-only credential that you configured. See storage backends.

Segment cache

A peer server can keep a local SSD cache of segments.

FlagDefaultEffect
--segment-cache-dir <path>NoneDedicated directory for the cache.
--segment-cache-capacity <size>None. Required with the directory.Disk capacity, for example 256GiB.
--segment-cache-memory <size>64MiB, or the capacity when smallerMemory front tier.

A size accepts the suffixes B, KiB, MiB, GiB, TiB, kB, MB, GB, and TB.

The cache requires --peer-bootstrap. Without it, the process fails at startup with a clear message.

Give the cache a dedicated directory. Corium manages the contents.

Failover

Pass every transactor endpoint, active first:

corium peer-server --db people \
  --transactor http://txor-a:4334,http://txor-b:4334

The peer rotates the list on failure. A standby rejects subscriptions with a standby status, which the peer treats as a reason to try the next endpoint. See high availability.

The thin-client contract

The wire contract is documented in thin-client-protocol.md. The canonical schema is crates/corium-protocol/proto/corium.proto.

Six rules matter to an operator.

  • Every transact and subscribe request sends a protocol_version. This build speaks version 3 and accepts version 1 and later. An unsupported version is FAILED_PRECONDITION, never a silent downgrade.
  • Malformed input is INVALID_ARGUMENT. An unknown database or entity is NOT_FOUND. Upstream loss is UNAVAILABLE.
  • Query results stream in chunks. A client concatenates them and stops at last = true.
  • Subscribe.from_basis_t is exclusive. The server backfills every later transaction without gaps, then continues live.
  • The subscription handshake advertises the heartbeat interval. A client treats silence for a few multiples of it as a dead upstream.
  • Transact gives read-your-writes on the serving peer before it responds.

A client is conformant when it reproduces the behavioral corpus in tests/conformance.

Version 3 adds the sealed value tag. A client older than version 3 never receives a sealed value. An unopened value reaches it as the tagged EDN element #corium/redacted, which every EDN reader parses.

Serving many principals

A peer server serves every client from one process and one database value. Which facts a client sees is a policy question, not a process question.

A principal whose view hides attributes cannot Transact, and it cannot Subscribe. Transaction data is opaque bytes by the time authorization runs. A subscription proxies the stream of the transactor. Neither call can honor a filter, so the server refuses rather than serve unfiltered data.

Language clients

ClientLocation
Rustcorium-peer, corium-client
Pythonclients/python
Javaclients/java
Clojurecorium-cljrs, the corium.api namespace

The Python and Java clients each offer two peers behind one interface.

PeerWhere it runs
LocalPeerEmbeds a full peer in the process. It indexes and queries in process, and it talks to a transactor directly.
RemotePeerConnects to a peer server over gRPC.

Both produce the same database values, and every time view works the same way on both. Only a remote peer can join across databases in one query.

An embedded peer can also read published segments straight from storage, and it can hold its own class keys. Use it where the keys must stay in the application process.