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:
@@ -161,10 +161,15 @@ bool ReaSamplerSession::saveToActiveProject() {
|
||||
SetProjExtState(static_cast<ReaProject*>(proj), projExtNamespace(),
|
||||
kProjExtTailKey, tailJson.c_str());
|
||||
|
||||
// Written on every save so the manifest and the bank stay in lockstep on disk.
|
||||
const std::string ownedJson = owned_.serialize();
|
||||
SetProjExtState(static_cast<ReaProject*>(proj), projExtNamespace(),
|
||||
kProjExtOwnedKey, ownedJson.c_str());
|
||||
// Written on every save so the ledger and the bank stay in lockstep on disk —
|
||||
// EXCEPT over a blob we could not read: replacing it would destroy the only
|
||||
// record of every file created before the corruption, silently turning them
|
||||
// into permanently unreclaimable foreign files.
|
||||
if (trackingStatus_ != tracking::LedgerStatus::Unreadable) {
|
||||
const std::string ledgerJson = tracking_.serialize();
|
||||
SetProjExtState(static_cast<ReaProject*>(proj), projExtNamespace(),
|
||||
kProjExtOwnedKey, ledgerJson.c_str());
|
||||
}
|
||||
|
||||
// stampVersion() (not appVersion()) is the numeric triple only, no "-beta"
|
||||
// suffix, so the stamp is byte-identical to stable regardless of channel
|
||||
@@ -229,21 +234,20 @@ capture::TailSetting loadTailSetting(ReaProject* proj) {
|
||||
return *loaded;
|
||||
}
|
||||
|
||||
// Absent/empty key -> empty manifest. Malformed JSON warns and falls back to
|
||||
// empty; prune then attributes nothing until the next capture rebuilds it —
|
||||
// degrades safety, never correctness.
|
||||
model::OwnedFileManifest loadOwnedManifest(ReaProject* proj) {
|
||||
if (!proj) return model::OwnedFileManifest{};
|
||||
const std::string ownedJson =
|
||||
getProjExtStateString(proj, projExtNamespace(), kProjExtOwnedKey);
|
||||
if (ownedJson.empty()) return model::OwnedFileManifest{}; // no stored manifest -> empty
|
||||
std::optional<model::OwnedFileManifest> loaded =
|
||||
model::OwnedFileManifest::deserialize(ownedJson);
|
||||
if (!loaded) {
|
||||
ShowConsoleMsg("ReaSampler: stored owned-file manifest is malformed -- ignoring.\n");
|
||||
return model::OwnedFileManifest{};
|
||||
// Absent/empty key -> Fresh (a new project, or a bank predating the ledger).
|
||||
// Malformed -> Unreadable, which halts the prune and suppresses the next write
|
||||
// rather than degrading to an empty ledger that looks like "nothing was ever
|
||||
// created".
|
||||
tracking::LedgerLoad loadOriginLedger(ReaProject* proj) {
|
||||
if (!proj) return tracking::LedgerLoad{};
|
||||
tracking::LedgerLoad load = tracking::loadLedger(
|
||||
getProjExtStateString(proj, projExtNamespace(), kProjExtOwnedKey));
|
||||
if (load.status == tracking::LedgerStatus::Unreadable) {
|
||||
ShowConsoleMsg("ReaSampler: the stored file-tracking ledger is malformed. Prune "
|
||||
"is halted for this project and the stored value is left intact "
|
||||
"for recovery.\n");
|
||||
}
|
||||
return std::move(*loaded);
|
||||
return load;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -255,13 +259,15 @@ void ReaSamplerSession::loadFromProject(void* proj, const std::string& projectDi
|
||||
// consumeLoadSignal() on the same tick.
|
||||
loadPending_ = true;
|
||||
|
||||
// view_/tail_/owned_ are all restored on EVERY load path: switching to a
|
||||
// view_/tail_/tracking_ are all restored on EVERY load path: switching to a
|
||||
// project with no stored state must reset to default, never inherit the
|
||||
// previous project's. An undo/redo reload must re-read the restored
|
||||
// values so they match the rolled-back state.
|
||||
view_ = loadViewModel(static_cast<ReaProject*>(proj));
|
||||
tail_ = loadTailSetting(static_cast<ReaProject*>(proj));
|
||||
owned_ = loadOwnedManifest(static_cast<ReaProject*>(proj));
|
||||
tracking::LedgerLoad ledger = loadOriginLedger(static_cast<ReaProject*>(proj));
|
||||
trackingStatus_ = ledger.status;
|
||||
tracking_ = std::move(ledger.ledger);
|
||||
|
||||
// An absent stamp classifies as PreVersioning, a malformed one as Unknown
|
||||
// — both silent. proj == nullptr -> "" -> default.
|
||||
|
||||
Reference in New Issue
Block a user