Files
tuliprox/backend/repository/src/lib.rs
T
DarkBreakpoint 154112de52 feat(dvr)!: persist the recording queue in a recoverable B+Tree
The queue was a single JSON document rewritten in full on every mutation.
That cannot survive a torn write, and a change to the record shape had no
upgrade path other than refusing to load — load_from_disk fails closed on
an unknown schema_version, which would have stranded every operator on a
version bump.

Replace it with RecordingRepository: one record per task in a B+Tree, with
every write routed through BPlusTreeRecoveryJournal. A deleted or corrupt
database is now rebuilt from the recovery history instead of being lost,
and a future record-shape change becomes a migration step rather than a
refusal to start.

- backend/repository/src/recording_repository.rs owns the persisted shape
  and RecordingRecoverySchema V1. It knows nothing about execution: the DVR
  decides what a task means and hands over a set to commit atomically.
- commit() diffs the candidate against what is stored, so the recovery
  journal stays proportional to what actually changed rather than to the
  size of the queue.
- The partition (queued/scheduled/active/finished) is stored explicitly.
  Deriving it from the state would be wrong: `active` is a distinct slot
  and two tasks in the same state can sit in different partitions.
- Repository calls run on spawn_blocking; it fsyncs both the journal and
  the B+Tree, so it must not run on a runtime worker thread.

RecordingTaskState moves to shared, along with the label() helper and the
TransferStatusDto conversion that were inherent impls in the DVR. The
repository crate cannot depend on the DVR, and the state is part of the
persisted contract either way.

Recovery generations are written under backup_dir, so they survive the loss
of the storage volume.

There is no migration from recordings_state.json: an existing queue is
discarded on upgrade.
2026-09-01 07:52:22 -05:00

72 lines
2.2 KiB
Rust

mod storage;
mod target_id_mapping;
// A B+Tree-backed IPv4 lookup and a CLI dumper for the repository's databases.
// Both read repository storage directly, so they belong here rather than in
// `utils`, which must not depend on this layer.
mod alias_repository;
mod db_viewer;
mod epg_repository;
mod geoip;
pub mod identity_registry;
mod library_repository;
mod live_stream_metadata_repository;
mod m3u_playlist_iterator;
mod m3u_repository;
mod metadata_retry_record;
mod network_access;
pub mod playlist_cache_loader;
pub mod playlist_mem_cache;
mod playlist_repository;
mod playlist_scratch;
mod playlist_source;
mod playlist_stream;
mod provider_dns_repository;
mod qos_snapshot_repository;
pub mod recording_repository;
pub mod recording_rule_repository;
pub mod stalker_generation_repository;
pub mod stalker_repository;
mod startup_migration;
pub mod storage_const;
mod stream_history;
mod strm_repository;
mod user_repository;
mod xtream_playlist_iterator;
mod xtream_repository;
pub use alias_repository::*;
pub use db_viewer::*;
pub use epg_repository::*;
pub use geoip::*;
pub use library_repository::*;
pub use live_stream_metadata_repository::{
load_input_live_bitrate_bps, persist_input_live_bitrate_bps, LiveBitratePersistenceOutcome,
};
pub use m3u_playlist_iterator::*;
pub use m3u_repository::*;
pub use metadata_retry_record::*;
pub use network_access::*;
pub use playlist_mem_cache::*;
pub use playlist_repository::*;
pub use playlist_source::*;
pub use playlist_stream::*;
pub use provider_dns_repository::*;
pub use qos_snapshot_repository::*;
pub use recording_repository::{
PersistedRecordingTask, RecordingPartition, RecordingRepository, RecordingRepositorySnapshot,
};
pub use stalker_repository::*;
pub use startup_migration::*;
pub use storage::*;
pub use storage_const::*;
pub use stream_history::*;
pub use strm_repository::*;
pub use target_id_mapping::*;
// The B+Tree storage engine is its own package. Aliased under its historical
// module name so every `crate::bplustree::X` path keeps resolving.
pub use tuliprox_btree as bplustree;
pub use tuliprox_btree::*;
pub use user_repository::*;
pub use xtream_playlist_iterator::*;
pub use xtream_repository::*;