Archive recording¶
media.dvr.record
Sapsan's DVR is its own on-disk storage: a stream is written append-only into hourly files, per track, across several disks at once. Archive reads do not interfere with writes.
Performance and stable addressing¶
The storage has been successfully tested at 25 Gbit/s of recording to spinning disks while archive cleanup and reading run concurrently. This is a tested storage configuration result; size hardware for the combined recording and reading load.
Each fragment and each frame has a stable address: stream name, track identifier, and integer timestamp. The timeline uses integer ticks and their frequency (timescale), without rounding to fractional seconds. The address is independent of the physical disk or server and remains the same across the cluster, replication, and archive migration.
AI video analytics can store references to detected events, and ERP systems can later access the same individual frames. A frame in a JPEG track uses /streaming/v/<stream>/image/<track>/<utc_ms>.jpg; fragment addresses include a track and a timestamp in the form <ticks>-<timescale>. Data availability at a stable address depends on archive retention and access permissions.
Storage¶
The global dvr section describes the whole storage:
dvr:
root: /storage # archive root
catalog: /storage/catalog # blob catalog (defaults to <root>/catalog)
disks:
- path: d1 # disks relative to root
- path: d2
- path: d3
Disk parameters:
| Parameter | Description |
|---|---|
path |
disk path relative to root |
mode |
Active (default) or Degraded — the disk is read but not written |
min_free_bytes |
minimum free space reserve |
check_mount verifies that the disk path is actually a mount point (protects against writing into an empty directory when a disk drops off).
Warning
Write disks are listed explicitly. root is the catalog's home and the base for relative paths, not a disk: with an empty disks every fragment write fails with an error visible in the statistics, and nothing is written into root.
Besides archive disks, storage may carry cache disks (cache_disks) — archive parts that were read settle on them: a foreign archive fetched from another server, or the local one lifted off the archive disks. Live recording never picks them, and their space is freed not by cleanup but by eviction according to last access. That is the archive cache on an edge node.
Enabling recording for a stream¶
streams:
- name: cam1
inputs:
- rtsp:
url: rtsp://admin:password@10.0.0.5/stream0
dvr:
max_depth: 168 # archive depth, hours
dvr: {} enables recording with default settings.
Write distribution across disks¶
Sapsan balances recording across active disks on its own:
- consecutive hours of one stream alternate between disks;
- neighboring streams are spread evenly across disks;
- tracks of a multibitrate stream are written to different disks in parallel.
A disk in degraded mode keeps serving reads but receives no new data — this is how you decommission a disk without losing the archive.
How storage works¶
The archive is laid out on disks as <disk>/<hash>/<stream>/<Y>/<M>/<D>/<hour>.mp4. Files are only appended, never rewritten; identical init segments are deduplicated within a blob.
A background indexer continuously reconciles the catalog with the disks and heals divergence without administrator involvement:
- blobs that appeared on disk behind the catalog's back (e.g. after moving disks from another server) are added to the catalog;
- records of missing files are removed;
- a corrupt blob sidecar index is rebuilt by scanning the blob itself;
- blob byte sizes and bloom filters are backfilled in the background (blobs younger than one hour are left alone).
Reads are failure-tolerant: if the catalog points at the wrong disk, the fragment is searched on all disks of that hour; orphaned catalog records are skipped without an error.
Observability¶
DVR reports statistics per disk (free/total space, read/write op and byte counters, blob counts, bytes used by the archive) and for the catalog — see the Admin API and monitoring.