mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-10-06 17:31:58 -04:00
writeM3U8 truncated and rewrote the whole playlist every time a fragment
completed. That is O(fragments) of writing per fragment, so an event pays
O(fragments squared) overall. For the ten minute events a section length
produces the manifest is about 55KB and the cost is invisible. It stops being
invisible when an event does not close.
On a box here, four monitors stopped closing their events after a reboot and
ran for 51 hours. Their manifests reached 17MB and 470,000 lines, and strace
showed where the writes were going: in one window the mp4 took 3 writes while
index.m3u8 took 195, opened O_WRONLY|O_CREAT|O_TRUNC. The cameras produced
0.4MB/s of video between them and the disk was absorbing 24MB/s at 100%
utilisation, 106ms average write latency.
That is a loop rather than just waste. One rewrite took 3.48s of wall clock
against a fragment arriving every 1.2s, so the event thread could never catch
up, the packet queue stayed full ("Analysis is not keeping up" every three
seconds), and the analysis thread is where the section length check that would
have closed the event lives. The growth starved the only thing that could stop
it.
An EVENT playlist is append only: a fragment's three lines never change once
written, and only the header depends on anything global. So write the new
fragments to the end, and fall back to a full rewrite when something above
them would differ -- a changed target duration or init segment end, the
different url the close path passes, a different path, or the closing
ENDLIST. The remembered byte count is checked against the file before
appending, so a manifest that something else has truncated, replaced or
removed is rebuilt rather than appended to; any failure zeroes the state,
which makes a rewrite the answer to anything unexpected.
The header and fragment text are split into m3u8Header, m3u8Fragment and
m3u8TargetDuration so the property that matters can be tested without
standing up a VideoStore: appending one fragment at a time produces a byte
identical manifest to writing the whole thing at once.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>