Skip to content

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_depth is hour-granular: only fully elapsed hours are deleted;
  • max_bytes is 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.

Next steps