tracking: one ledger, one authority — prune protection and replace-vs-add answered from the same records, fail-safe on unreadable state

This commit is contained in:
2026-07-30 19:44:11 -04:00
parent 7bd911d58b
commit 7f70d94228
40 changed files with 1546 additions and 633 deletions
+9 -18
View File
@@ -178,9 +178,9 @@ std::optional<std::string> readExtStateValue(ReaProject* proj, const char* key)
} // namespace
UsageScanResult liveInstanceHeldPaths(void* projOpaque) {
UsageFoldResult scanInstanceUsage(void* projOpaque) {
ReaProject* proj = static_cast<ReaProject*>(projOpaque);
UsageScanResult result;
UsageFoldResult result;
// Enumerate rsusage_* keys, then read+decode via the growing reader
// (EnumProjExtState's fixed val buffer could truncate a large record).
@@ -199,19 +199,14 @@ UsageScanResult liveInstanceHeldPaths(void* projOpaque) {
}
if (usageKeys.empty()) return result; // no instance ever published — skip the scan
std::vector<std::optional<UsageRecord>> decoded;
std::vector<DecodedUsage> decoded;
decoded.reserve(usageKeys.size());
for (std::size_t ki = 0; ki < usageKeys.size(); ++ki) {
const std::string& key = usageKeys[ki];
for (const std::string& key : usageKeys) {
const std::optional<std::string> value = readExtStateValue(proj, key.c_str());
if (!value) {
decoded.push_back(std::nullopt); // unreadable -> abort (pure fold)
result.offendingKeys.push_back(key);
continue;
}
const std::optional<UsageRecord> rec = decodeUsageRecord(*value);
if (!rec) result.offendingKeys.push_back(key);
decoded.push_back(rec); // undecodable nullopt -> abort
// Unreadable or undecodable both land as a nullopt record; the pure fold
// turns either into the abort and names the key.
decoded.push_back(DecodedUsage{
key, value ? decodeUsageRecord(*value) : std::nullopt});
}
// Enumerate live ReaSampler 9000 hosts; a track needs only one instance to
@@ -254,11 +249,7 @@ UsageScanResult liveInstanceHeldPaths(void* projOpaque) {
// The pure fold decides: abort on any unreadable record; protect-all when
// zero instances were identified; otherwise the per-record liveness rule.
const UsageFoldResult fold = foldUsageRecords(decoded, liveTrackGuids, anyLive);
result.abortPrune = fold.abortPrune;
result.heldPaths = fold.heldPaths;
if (!result.abortPrune) result.offendingKeys.clear(); // only meaningful on abort
return result;
return foldUsageRecords(decoded, liveTrackGuids, anyLive);
}
} // namespace reasampler