Prove every ext-state write by reading the key back, so no guard is constant-true
SetProjExtState's return describes the whole extname. The persist and the instrument's publish now re-read their key; both refusals can finally fire.
This commit is contained in:
@@ -130,9 +130,11 @@ private:
|
||||
// One entry's write-back, and the proof of whether it took. Guarded whole: it encodes into
|
||||
// a fresh string and readKey grows a buffer toward 16 MB, and a throw escaping here would
|
||||
// skip the ShowConsoleMsg for EVERY key — the silent console this action exists to make
|
||||
// impossible. A throw is `Unknown` rather than a failure because the write may well have
|
||||
// landed before the check did.
|
||||
// impossible. Which proof a throw yields turns on whether SetProjExtState had run: before
|
||||
// it, the write is KNOWN not to have been made (`Rejected`); after it, the write may well
|
||||
// have landed and only the check failed (`Unknown`).
|
||||
wire::BakeWriteProof writeBackOne(ScannedKey& entry, bool persisted) {
|
||||
bool issued = false;
|
||||
try {
|
||||
std::string value; // empty = clear the key
|
||||
if (entry.write == ScannedKey::Write::Answer) {
|
||||
@@ -146,7 +148,8 @@ wire::BakeWriteProof writeBackOne(ScannedKey& entry, bool persisted) {
|
||||
entry.outcome = refuseBake(
|
||||
BakeStatus::Failed,
|
||||
"the bake reached the bank in memory, but this pass's persist did not "
|
||||
"report success, so this answer cannot promise a reload will find it",
|
||||
"confirm its bank write, so this answer cannot promise a reload will "
|
||||
"find it",
|
||||
entry.outcome.generation);
|
||||
// `detail` left empty on purpose: describeLanding's Unpersisted clause is
|
||||
// that sentence's one home on the console side, and the message above is
|
||||
@@ -158,16 +161,16 @@ wire::BakeWriteProof writeBackOne(ScannedKey& entry, bool persisted) {
|
||||
value = wire::encodeBakeOutcome(entry.outcome);
|
||||
}
|
||||
SetProjExtState(entry.proj, kProjExtNamespace(), entry.key.c_str(), value.c_str());
|
||||
// SetProjExtState's own return is the size of the whole extname's state, which
|
||||
// `banks` alone keeps non-zero in every case a bake can reach, so only re-reading
|
||||
// THIS key can speak for it. An oversized read proves nothing either way — folding
|
||||
// it into bakeWriteLanded's absent case would report a clear off unread bytes.
|
||||
issued = true;
|
||||
// Only re-reading THIS key can speak for it (wire::extStateWriteLanded owns why).
|
||||
// An oversized read proves nothing either way — folding it into that predicate's
|
||||
// absent case would report a clear off unread bytes.
|
||||
const KeyRead back = readKey(entry.proj, entry.key);
|
||||
if (back.oversized) return wire::BakeWriteProof::Unknown;
|
||||
return wire::bakeWriteLanded(value, back.value) ? wire::BakeWriteProof::Confirmed
|
||||
: wire::BakeWriteProof::Rejected;
|
||||
return wire::extStateWriteLanded(value, back.value) ? wire::BakeWriteProof::Confirmed
|
||||
: wire::BakeWriteProof::Rejected;
|
||||
} catch (...) {
|
||||
return wire::BakeWriteProof::Unknown;
|
||||
return issued ? wire::BakeWriteProof::Unknown : wire::BakeWriteProof::Rejected;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,8 +196,12 @@ void RunResampleBake(ReaSamplerSession& session) {
|
||||
std::vector<ScannedKey> scanned;
|
||||
wire::BakeScanTally tally; // every verdict below is counted, skips included
|
||||
std::string aborted; // set only when the scan itself threw
|
||||
bool persisted = false; // the pass's ONE persist reported success
|
||||
bool persisted = false; // the pass's ONE persist confirmed its bank write
|
||||
bool bookChanged = false; // some landing added or refreshed an entry
|
||||
// A local, not a tally field: an entry counted here can still be re-answered as a
|
||||
// failure by the write-back loop below, so this is a persist GATE and never a count
|
||||
// anything reports.
|
||||
bool anyLanded = false;
|
||||
// The scan allocates outside attemptLanding's own guards too (readKey grows a buffer
|
||||
// toward 16 MB, every container here allocates), and a throw that escaped would discard
|
||||
// the answers already buffered — the exact no-answer-with-a-silent-console this action
|
||||
@@ -253,7 +260,7 @@ void RunResampleBake(ReaSamplerSession& session) {
|
||||
request->generation);
|
||||
} else {
|
||||
LandingAttempt attempt = attemptLanding(session, open.dir, *request);
|
||||
if (attempt.outcome.status == BakeStatus::Ok) ++tally.landed;
|
||||
if (attempt.outcome.status == BakeStatus::Ok) anyLanded = true;
|
||||
if (attempt.changedBook) bookChanged = true;
|
||||
// Never Banked here, on ANY path: the pass's persist has not run yet,
|
||||
// and bakeLandingAfterPersist is the one place that word is earned. A
|
||||
@@ -273,7 +280,7 @@ void RunResampleBake(ReaSamplerSession& session) {
|
||||
}
|
||||
}
|
||||
|
||||
if (tally.landed > 0) {
|
||||
if (anyLanded) {
|
||||
// A dedup hit rides the persist too, because that is the only observation that
|
||||
// can promote its landing — but it added nothing, so it earns neither the
|
||||
// refresh every open instance pays for nor an undo point named after a bake
|
||||
|
||||
Reference in New Issue
Block a user