DVR recording¶
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.
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) — a foreign archive read from another server settles on them. 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
max_bytes: 500000000000
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.
Cleanup and retention¶
Cleanup runs once an hour (5 minutes after the hour boundary):
max_depthis hour-granular: only fully elapsed hours are deleted;max_bytesis counted from newest blobs to oldest: everything older than the first blob exceeding the limit is deleted;- when both limits are set, the tighter one wins;
- blobs with protected episodes are never deleted by retention;
- the blob of the current (actively written) hour is never deleted.
Disk-overflow protection works separately: when free space drops below min_free_bytes (default 1% of disk capacity), Sapsan deletes the oldest blobs regardless of retention until enough space is freed.
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.