Resolve the forensic key map once per disc, not once per playlist

resolve_content_key_map loops every title into resolve_mux_key_map, which called
resolve_fmts_key_map FIRST — before the CpsUnitCache — and on an FMTS disc
returned immediately. So every playlist re-derived facts that belong to the DISC:
a full UDF walk plus /AACS/IndividualSegment.tbl, and on an FMTS disc the anchor
probe, the 32-index phase probe, and a fetch.fmts_indexes round trip.

On a 60-playlist disc, measured on a synthetic fixture: 840 -> 14 metadata reads,
2,400 -> 40 probe reads, and 60 -> 1 key-service calls. Worst case before was up
to 256 probe reads and 32 key-service calls per title. The 60 redundant
key-service round trips are a strong candidate for the keyserver storm seen in
the field.

Two memos behind a pub(crate) DiscKeyCache. The table memo (UDF walk + tbl parse)
is disc-invariant outright — nothing in that path mentions the title — and runs on
EVERY disc, so a plain BD benefits too. Only the deterministic negatives are
memoised as "not FMTS"; a DiscRead fault propagates uncached so a later title
retries.

A blind once-per-disc hoist of the PROBES was rejected as unsafe, and this is the
load-bearing reasoning: the title enters through clip_byte_to_lba, which decides
which segments are addressable and which LBA every probed clip byte reads from, so
two titles with different extent lists probe different physical bytes. A hoist
would serve title B an answer derived from title A's media and could silently turn
a per-title FmtsKeyMissing into a success. The extent list is the ONLY per-title
input, so keying on it is exactly sufficient — matching the ForcedProbeCache
precedent.

Result-identity was proved, not assumed: NEITHER probe reads the key pool.
Verified here independently — probe_fmts_index_keys takes no keys parameter at
all; index keys come from `fetch`, and the anchor's reply feeds the phase probe.
So the pool's growth across titles, the one thing that does change between calls,
cannot move a memoised value, and the result is order-independent. A test resolves
three titles through a shared memo and through fresh memos and asserts both the
per-title ranges and the final key pool (keys, slots, order) are identical.

Not memoised, deliberately: fail-loud FmtsKeyMissing, and any run where an index
hit a read fault — that is a property of a transient drive fault, not of the
extents, and caching it would spread one bad read across 59 playlists.

A fully-memoised title now does zero I/O, which made the old in-loop halt polls
unreachable for it, so a check_halt on entry was added with a test that cancels
after warming the memos.

Also corrects my own overstatement from last round: the CpsUnitCache doc now says
plainly that on an FMTS disc it removes NO reads, because this function returns
before the extent loop ever runs.

Five mutations, all verified red. Pre-existing bug flagged but not fixed:
filter_addressable_segments only checks that a segment's START byte maps to some
LBA in the title, so a play-all playlist can pass the filter while mapping segment
bytes into the wrong clip, whose anchor then returns empty and aborts the sweep.
This commit is contained in:
Matthew Jackson
2026-07-29 20:27:50 -07:00
parent b4bf0daa82
commit 13897e14f0
3 changed files with 1003 additions and 114 deletions
+14
View File
@@ -41,6 +41,20 @@
### Fixed
- **The FMTS (AACS 2.1) forensic key resolution now runs once per disc, not once
per title.** `Disc::resolve_content_key_map` resolves every title, and the FMTS
branch ran ahead of everything else — so each playlist re-walked the UDF
filesystem to re-read `/AACS/IndividualSegment.tbl`, re-ran the forensic anchor
probe and the per-index phase probe, and **re-asked the key service for the
disc's index-key set**. On a 60-playlist AACS 2.1 disc that was 60 identical
key-service round trips (a key-server storm) and tens of thousands of random
6144-byte reads for one disc-wide answer. The UDF walk is now memoised for the
whole disc and the index keys + phases per distinct extent list — the only
per-title input to the probes. A read-faulted phase probe is deliberately never
memoised, so one bad read is not spread across the remaining playlists. The
per-title UDF walk was paid on **every** disc, FMTS or not, so a plain BD sweep
loses ~59 full-stroke seeks too. The multi-CPS extent memo added in 1.6.0 is
also reachable on an FMTS disc for the first time.
- **Mux correctness pass** (the `v1.4.0..HEAD` 10-phase audit): DTS core-header
false-drops that dropped good DTS frames; the TrueHD channel-correction probe
now runs correctly on AACS discs (7.1/Atmos no longer understated as 5.1);