rhiza

package module
v0.8.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: MIT Imports: 10 Imported by: 0

README

rhiza

Rhiza is an embedded, leaderless Go database with SQL, Graph, and KV. Any healthy peer can accept a write; QuePaxa records a certified decision on a quorum before the API acknowledges it. An HTTP server is an optional adapter over the same Go API.

Runtime

  • Go 1.27.0; GOTOOLCHAIN=auto is expected.
  • Green Tea GC is the Go 1.27 default.
  • The container enables GOEXPERIMENT=arenas for QLog read scratch buffers.
  • SQLite uses cgo-free ncruces/go-sqlite3.
  • Graph uses the pure-Go latticedb-go engine.
go test ./...
go vet ./...
GOEXPERIMENT=arenas go test ./...
go build ./cmd/rhiza
docker build -t rhiza:dev .

Embedded Go API

db, err := rhiza.Open(ctx, rhiza.Config{
    NodeID: "node-1",
    DataDir: "./rhiza-data",
})
if err != nil { return err }
defer db.Close()

_, err = db.Execute(ctx, rhiza.ExecuteRequest{
    RequestID: "schema-1",
    SQL: "CREATE TABLE tea (id INTEGER PRIMARY KEY, name TEXT)",
})
rows, err := db.Query(ctx, rhiza.QueryRequest{
    SQL: "SELECT id, name FROM tea",
    Consistency: rhiza.ConsistencyLocal,
})

Open starts the embedded engine and its private peer endpoint, but no public HTTP listener. Use db.Handler() or db itself as an http.Handler when a server endpoint is wanted. SQL, KV, Graph, and Notify methods are available directly on DB.

Optional HTTP API

All mutations require a unique request_id and are idempotent. The optional HTTP adapter accepts JSON bodies up to 1 MiB, while every canonically encoded consensus mutation must fit within 128 KiB. An HTTP request below 1 MiB can therefore still be rejected by the consensus limit. Embedded SQL callers can preflight the exact mutation contract with rhiza.ValidateExecuteRequest and inspect rhiza.MaxReplicatedMutationBytes; neither limit should be raised without evaluating consensus latency and memory. SQL text is limited to 256 KiB, with at most 999 arguments and 64 statements per transaction. Queries return at most 10,000 rows.

  • POST /sql/execute: one mutation statement and arguments.
  • POST /sql/transaction: an atomic statements array.
  • POST /sql/query: arguments plus local or linearizable consistency.
  • POST /graph/execute: one idempotent Cypher mutation with named arguments.
  • POST /graph/query: read-only Cypher with local or linearizable consistency.
  • POST /kv/put, /get, /delete, /cas: binary values, TTL, and CAS.
  • POST /notify/publish: replicated notification publication.
  • GET /notify/subscribe?topic=...: bounded, live, at-most-once SSE stream.

Replicated SQL rejects explicit transaction control, attachment, and known nondeterministic functions. Multi-statement client transactions use the transaction endpoint.

The SQL surface is SQLite's: DDL, views, triggers, generated and STRICT tables, partial and expression indexes, CTEs and recursive CTEs, joins, subqueries, UPSERT, RETURNING, window functions, JSON functions, and FTS5 are supported. Replicated Execute and transaction calls never expose statement rows: want_rows is rejected and their idempotent response is one bounded aggregate MutationReceipt. Use Query for read-only SQL and observe committed state with linearizable consistency. Raw unprepared SQL batches are omitted because the prepared statements array covers the same database features.

Peer transport

Peer consensus and catch-up traffic uses raw QUIC over UDP 9090 with a private rhiza-peer ALPN and FlatBuffers messages. Each RPC uses an independent bidirectional QUIC stream on a reused connection. Frames are capped at 1 MiB; connections use TLS 1.3, keepalive, bounded stream counts, five-second RPC deadlines, and reconnect after transport failure.

Replay-safe Record, certified Learned, and read-only Decisions operations may use QUIC 0-RTT after session resumption. Propose waits for the handshake because replay before a decision could consume duplicate consensus slots. Peer tokens are checked against fixed membership when configured. This is server authentication and membership-token authorization, not peer mTLS. Deploy peer UDP and the optional HTTP adapter only on a private network, limit them with firewall or Kubernetes NetworkPolicy, keep membership tokens secret, and do not expose the unauthenticated HTTP adapter publicly. Add peer mTLS at a deployment boundary where private-network and token trust are insufficient. The public HTTP API remains TCP 8080 and contains no registered internal consensus routes.

Reads and failures

Local reads use the peer's applied state and remain available without a quorum. Linearizable reads decide a unique read barrier and return HTTP 503 if a quorum is unavailable; they never fall back to a stale read. With three peers, one failed peer preserves reads and writes. Two failed peers preserve only local reads and reject writes and linearizable reads with HTTP 503.

For embedded health checks, DB.Ready() means local recovery and startup catch-up completed; it is not a live quorum signal, so an isolated peer may remain locally ready. Use an inexpensive linearizable query when current quorum readiness is required. Mutations and linearizable reads always enforce quorum at operation time and fail closed.

SQLite and LatticeDB are derived from the certified QLog. Startup replays missing decisions; unreadable local state is quarantined and rebuilt from the log. Checkpoints capture both engines at the same applied slot and restore the fixed SQLite and Graph files atomically.

Docker quick start

docker build -t rhiza:dev -t rhiza-e2e:dev .
docker run --rm --name rhiza -p 8080:8080 \
  -e RHIZA_BIND_ADDR=0.0.0.0:8080 \
  -v rhiza-data:/data \
  rhiza:dev

For Kubernetes qualification, preload rhiza-e2e:dev into every node or replace the manifest image references with published registry images. Then apply deploy/k8s/sql-server-3peer-e2e.yaml or deploy/k8s/graph-server-3peer-e2e.yaml with standard kubectl. The Chaos Mesh manifests under e2e/chaos work with any compatible Kubernetes environment.

On a local Kubernetes cluster on 2026-08-24, the QUIC/FlatBuffers Chaos Mesh scenario passed: one failed peer kept quorum writes available (31.2 ms sample), the rebuilt peer converged, two failed peers rejected writes with 503, and writes resumed after quorum recovery. Normal three-peer SQL benchmark medians were 0.207 ms local read, 2.67 ms linearizable read, and 1.24 ms write. With one failed peer they were 0.245 ms, 1.98 ms, and 9.10 ms respectively. These include local port-forward overhead and showed substantial tail variance.

For Graph qualification, preload rhiza-e2e:dev, then apply deploy/k8s/graph-server-3peer-e2e.yaml. Set RHIZA_GRAPH_E2E_URL to a forwarded peer and run go test ./e2e -run TestGraphServer. The same local Kubernetes qualification passed with a 15.2 ms one-peer-failure write, HTTP 503 with two failed peers, convergence, and a successful write after quorum recovery. Three-peer samples were 0.29–0.35 ms local read, 4.7–21.6 ms linearizable read, and 8.1–11.6 ms graph write, including port-forward overhead.

Every binary and node includes SQL, Graph, and KV. Graph mutations, request receipts, and the applied slot commit atomically in LatticeDB before the SQLite sidecar tip, so a crash replays without applying a graph mutation twice. LatticeDB is rebuilt from the QLog when local state is missing; checkpoints always bundle the SQLite and LatticeDB materializations.

License

MIT

Documentation

Overview

Package rhiza provides the primary in-process Go API. HTTP is an optional adapter.

Index

Constants

View Source
const (
	ConsistencyLocal               = "local"
	ConsistencyLinearizable        = "linearizable"
	ObjectStoreDurabilityAsync     = types.ObjectStoreDurabilityAsync
	ObjectStoreDurabilityBeforeAck = types.ObjectStoreDurabilityBeforeAck
	DefaultHedgeDelay              = 5 * time.Millisecond
	// MaxReplicatedMutationBytes is the encoded consensus-value limit.
	MaxReplicatedMutationBytes = quepaxa.MaxReplicatedValueBytes
	// MaxHTTPBodyBytes is the optional HTTP adapter's larger JSON envelope limit.
	MaxHTTPBodyBytes = network.MaxRequestBodyBytes
)

Variables

View Source
var (
	ErrNotReady              = network.ErrNotReady
	ErrRequestConflict       = network.ErrRequestConflict
	ErrInvalidRequest        = network.ErrInvalidRequest
	ErrQuorumUnavailable     = quepaxa.ErrQuorumUnavailable
	ErrDurabilityUnavailable = network.ErrDurabilityUnavailable
	ErrCommitUnknown         = network.ErrCommitUnknown
)

Functions

func ValidateExecuteRequest added in v0.8.1

func ValidateExecuteRequest(req ExecuteRequest) error

ValidateExecuteRequest applies the replicated SQL contract and encoded-size limit without submitting the mutation.

Types

type Config

type Config struct {
	ClusterID             string
	NodeID                string
	DataDir               string
	BindAddr              string
	PeerAddr              string
	AdminToken            string
	Members               []Member
	ObjStoreEndpoint      string
	ObjStoreBucket        string
	ObjStoreProvider      string
	ObjStoreDir           string
	ObjStorePrefix        string
	ObjStoreRegion        string
	ObjStoreInsecure      bool
	ObjStoreRetries       int
	ObjStoreAccessKey     string
	ObjStoreSecretKey     string
	ObjStoreSessionToken  string
	ObjStoreDurability    ObjectStoreDurability
	ObjStoreSyncInterval  time.Duration
	ObjStoreBatchDelay    time.Duration
	ObjStoreGCInterval    time.Duration
	ObjStoreGCGracePeriod time.Duration
	CheckpointInterval    time.Duration
	CheckpointTailBytes   int64
	MaxWALBytes           int64
	// HedgeDelay delays each lower-priority proposer. Nil uses
	// DefaultHedgeDelay; a pointer to zero explicitly enables eager hedging.
	HedgeDelay *time.Duration
}

Config contains the durable local path, fixed membership, and peer endpoint.

type DB

type DB struct {
	// contains filtered or unexported fields
}

DB owns one embedded Rhiza node and its private QUIC peer endpoint.

func Open

func Open(ctx context.Context, config Config) (*DB, error)

Open starts the embedded engine. It does not start a public HTTP listener.

func (*DB) Close

func (db *DB) Close() error

func (*DB) Execute

func (db *DB) Execute(ctx context.Context, req ExecuteRequest) (ExecuteResponse, error)

func (*DB) GraphChanges

func (db *DB) GraphChanges(ctx context.Context, req GraphStreamReadRequest) (GraphStreamReadResponse, error)

GraphChanges reads the node-local LatticeDB semantic graph changefeed.

func (*DB) GraphExecute

func (db *DB) GraphExecute(ctx context.Context, req GraphCommand) (GraphExecuteResponse, error)

func (*DB) GraphQuery

func (db *DB) GraphQuery(ctx context.Context, req GraphQueryRequest) (GraphResult, error)

func (*DB) GraphStreamOffset

func (db *DB) GraphStreamOffset(ctx context.Context, req GraphStreamOffsetRequest) (GraphStreamOffsetResponse, error)

GraphStreamOffset returns a replicated durable consumer offset.

func (*DB) GraphStreamRead

func (db *DB) GraphStreamRead(ctx context.Context, req GraphStreamReadRequest) (GraphStreamReadResponse, error)

GraphStreamRead reads a replicated named stream after its per-stream cursor.

func (*DB) Handler

func (db *DB) Handler() http.Handler

Handler exposes the optional HTTP server API without opening a listener.

func (*DB) KVCAS

func (*DB) KVDelete

func (db *DB) KVDelete(ctx context.Context, req KVMutationRequest) (KVMutationResponse, error)

func (*DB) KVGet

func (db *DB) KVGet(ctx context.Context, req KVGetRequest) (KVGetResponse, error)

func (*DB) KVPut

func (*DB) NotificationDrops

func (db *DB) NotificationDrops() uint64

func (*DB) NotifyPublish

func (db *DB) NotifyPublish(ctx context.Context, req NotifyCommand) (MutationReceipt, error)

func (*DB) NotifySubscribe

func (db *DB) NotifySubscribe(topic string) (<-chan []byte, func(), error)

func (*DB) ObjectStoreStats

func (db *DB) ObjectStoreStats() (ObjectStoreStats, bool)

func (*DB) Query

func (db *DB) Query(ctx context.Context, req QueryRequest) (QueryResponse, error)

func (*DB) Ready added in v0.8.1

func (db *DB) Ready() bool

Ready reports whether local recovery and catch-up completed. It is not a live quorum probe: an isolated peer may remain locally ready. Mutations and linearizable queries still fail closed when quorum is unavailable.

func (*DB) RequestStatus

func (db *DB) RequestStatus(ctx context.Context, req RequestStatusRequest) (RequestStatusResponse, error)

func (*DB) ServeHTTP

func (db *DB) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*DB) SetGraphStreamOffset

func (db *DB) SetGraphStreamOffset(ctx context.Context, req GraphStreamOffsetRequest) error

SetGraphStreamOffset stores a replicated durable consumer offset.

func (*DB) TrimGraphStream

func (db *DB) TrimGraphStream(ctx context.Context, req GraphStreamTrimRequest) error

TrimGraphStream replicates deletion of records through the supplied sequence.

type ExecuteRequest

type ExecuteRequest = network.ExecuteRequest

type ExecuteResponse

type ExecuteResponse = network.ExecuteResponse

type GraphCommand

type GraphCommand = types.GraphCommand

type GraphExecuteResponse

type GraphExecuteResponse = network.GraphExecuteResponse

type GraphQueryRequest

type GraphQueryRequest = network.GraphQueryRequest

type GraphResult

type GraphResult = types.GraphCommandResult

type GraphStreamEvent

type GraphStreamEvent = types.GraphStreamEvent

type GraphStreamOffsetRequest

type GraphStreamOffsetRequest = network.GraphStreamOffsetRequest

type GraphStreamOffsetResponse

type GraphStreamOffsetResponse = network.GraphStreamOffsetResponse

type GraphStreamReadRequest

type GraphStreamReadRequest = network.GraphStreamReadRequest

type GraphStreamReadResponse

type GraphStreamReadResponse = network.GraphStreamReadResponse

type GraphStreamRecord

type GraphStreamRecord = types.GraphStreamRecord

type GraphStreamTrimRequest

type GraphStreamTrimRequest = network.GraphStreamTrimRequest

type KVGetRequest

type KVGetRequest = network.KVGetRequest

type KVGetResponse

type KVGetResponse = network.KVGetResponse

type KVMutationRequest

type KVMutationRequest = network.KVMutationRequest

type KVMutationResponse

type KVMutationResponse = network.KVMutationResponse

type Member

type Member = quepaxa.Member

type MutationReceipt

type MutationReceipt = types.MutationReceipt

type NotifyCommand

type NotifyCommand = types.NotifyCommand

type ObjectStoreDurability

type ObjectStoreDurability = types.ObjectStoreDurability

type ObjectStoreStats

type ObjectStoreStats = objstore.Stats

type QueryRequest

type QueryRequest = network.QueryRequest

type QueryResponse

type QueryResponse = network.QueryResponse

type RequestStatusRequest

type RequestStatusRequest = network.RequestStatusRequest

type RequestStatusResponse

type RequestStatusResponse = network.RequestStatusResponse

type SQLStatement

type SQLStatement = types.SQLStatement

Directories

Path Synopsis
cmd
rhiza command
rhiza-bench command
internal
pkg
quepaxa
Package quepaxa implements the crash-fault-tolerant QuePaxa Algorithm 3 recorder and Algorithm 4 proposer over a durable QLog.
Package quepaxa implements the crash-fault-tolerant QuePaxa Algorithm 3 recorder and Algorithm 4 proposer over a durable QLog.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL