Time-Series Engine

A standalone InfluxDB-style time-series engine, mounted like the SQL engine in the same process. Each series (measurement × tag-set × field) is a Gorilla-compressed columnar stream — about 0.3 bytes per point on regular data. Off by default; zero cost when unused.

Enable it

OXIDB_TSDB=1 ./oxidb-server
# data under <OXIDB_DATA>/tsdb (override with OXIDB_TSDB_DATA)

Write points

TSDB requests carry "engine": "tsdb", "cmd": "tsdb", and an "op". Fields are typed (float / integer / boolean / string).

{ "engine": "tsdb", "cmd": "tsdb", "op": "write",
  "measurement": "cpu", "tags": {"host": "a", "region": "eu"},
  "fields": {"usage": 0.63}, "ts": 1700000000000 }

InfluxDB line protocol

Ingest the InfluxDB line protocol verbatim — ms timestamps, now() when absent.

{ "engine": "tsdb", "cmd": "tsdb", "op": "write_lp",
  "lp": "cpu,host=a,region=eu usage=0.63 1700000000000\ncpu,host=b usage=0.41" }

Query & downsample

Filter by measurement, field, tags, and a [start, end) window; optionally downsample with GROUP BY time(interval) and group by tags.

{ "engine": "tsdb", "cmd": "tsdb", "op": "query",
  "measurement": "cpu", "field": "usage",
  "tag_filters": [{"key": "host", "value": "a"}],
  "start": 1700000000000, "end": 1700003600000,
  "interval": 600000, "group_by": ["region"],
  "agg": "mean" }

Aggregations

AggMeaning
mean sum min max count first last distinctStandard numeric aggregations
ratePer-second change (for counters)
percentile (+ p), or p95 shorthandLinear-interpolated percentile

Text (string) fields support first / last / count / distinct.

Continuous-aggregate rollups

Materialize completed time buckets of every numeric series into a derived measurement (<m>@<label>). Incremental via a crash-safe per-series watermark — no double-count on restart.

{ "engine": "tsdb", "cmd": "tsdb", "op": "rollup_add",
  "measurement": "cpu", "interval": 60000, "aggs": ["mean", "max"] }
{ "engine": "tsdb", "cmd": "tsdb", "op": "rollup_refresh", "now": 1700003600000 }
// query the rollup as measurement "cpu@1m", field "usage_mean"

Retention & checkpoints

Retention drops whole expired blocks — durable for free. A checkpoint seals buffers, writes a fresh snapshot, and rotates the WAL (auto past 8 MiB).

{ "engine": "tsdb", "cmd": "tsdb", "op": "retention", "cutoff": 1699000000000 }
{ "engine": "tsdb", "cmd": "tsdb", "op": "checkpoint" }
{ "engine": "tsdb", "cmd": "tsdb", "op": "stats" }

Backup & restore

Like the SQL engine, the TSDB has a consistent low-lock online backup — it pins a committed generation and compresses with the write lock released, so ingestion keeps flowing. Admin-only.

{ "engine": "tsdb", "cmd": "backup",  "path": "/backups/tsdb.tar.gz" }
{ "engine": "tsdb", "cmd": "restore", "archive": "/backups/tsdb.tar.gz", "target": "/data/restored" }

Persistence

A versioned block snapshot + per-generation WAL, with a MANIFEST as the atomic commit point. Every point is WAL-appended; a checkpoint writes a fresh snapshot, atomically replaces the MANIFEST, then rotates the WAL — a crash on either side never double-counts. Node-local. A Go client ships in the repo.

Report Issue