The latest reading of any series in one read: Semurg as a time-series database
12 October 2026 · Semurg · 3 min read · Markdown
Verified: every command below ran on a fresh node of r11.78.20261012.bc0d94f (how)
Much of what a monitoring screen or a trading desk asks a time-series store is one question, many times: what is the latest reading of this series, now? Semurg keeps, for every series, a small record that always points at its newest reading, so that question is one read whatever the history behind it.
It answers that question, and not yet the others: there is no query over a range of time, no downsampling and no per-series aggregate, so it is a store for current readings, not yet a replacement for a full time-series query engine.
Write readings
Each reading is a row of three or four whole numbers after the series name: the time in milliseconds, the value, and optionally a size or count. Values are integers, so keep a price in cents or a percentage in hundredths. One call can carry readings for many series:
export SEMURG_API_TOKEN=<your token>
curl -sS http://localhost:4000/v1/query \
-H "Authorization: Bearer $SEMURG_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"op": "ts_ingest",
"rows": [["cpu.host1.usage", 1760259600000, 4210],
["cpu.host1.usage", 1760259660000, 4385],
["cpu.host2.usage", 1760259600000, 1970]]}'Expected: three readings for two series are written
The reply counts the rows you sent and the series they touched, and how many of those series it had not seen before. If two rows in one call name the same series and the same time, the last one wins.
Read the latest reading of each series
export SEMURG_API_TOKEN=<your token>
curl -sS http://localhost:4000/v1/query \
-H "Authorization: Bearer $SEMURG_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"op": "ts_latest", "series": ["cpu.host1.usage", "cpu.host2.usage", "cpu.host9.usage"]}'Expected: host1's newest reading, host2's only reading, and host9 marked absent
The answers come back in the order you asked, each with its time, value and size, or absent for a series with no readings. The latest reading only moves forward in time: a reading older than the newest one is stored, but does not replace it.
What a reading becomes on disk
Every reading is one 64-byte record of its own. Each series also keeps one record per hour of readings and one record that points at its newest reading, and its name is stored once. The time, value and size are also laid out as dense columns of 8-byte numbers, which the node builds in the background, for scans over a whole column.
Where it stands
We have taken our published benchmark rows down while every domain is re-measured on new hardware, with a dataset in RAM and one bigger than RAM running at the same time, as a stress test of Semurg itself. The re-measured time-series results will be on the benchmark page, wins and losses alike, with the release and the machine they ran on. Until then this post states no comparison.
What it does not do yet
- Query a range of time, downsample, or aggregate one series: the door answers the latest reading, and older readings are stored but not read back by time.
- Store decimal values or tags beyond the series name.
- Delete readings, or expire them after a retention period.
- Load from QuestDB, InfluxDB or TimescaleDB directly: there is no connector for them yet.
Next
- Ticks and research notes on one engine: a quant desk's blueprint built on this door.
- Talk to a Semurg node over plain HTTP: the token and every route.
How these commands were checked
Our test farm ran each of the 2 command blocks marked runnable, exactly as written, with the answer checked against the expectation printed under it, against a fresh node of the published release r11.78.20261012.bc0d94f. A post is published only when every one of them passed there.