fix(review): embed asymmetry comment, single-lock assign-marker, dedup-collapse test
This commit is contained in:
@@ -113,6 +113,10 @@ void ReaSamplerEmbed::maybeRefresh() {
|
||||
} else if (lastSeenBankGeneration_ < 0) {
|
||||
currentGen = 0; // unprimed + no stamp (pre-S9): treat as generation 0 for the first read
|
||||
}
|
||||
// Intentional asymmetry: a TRANSIENT bridge failure (readReasamplerExtState returned
|
||||
// nullopt after we were already primed) leaves currentGen == lastSeenBankGeneration_,
|
||||
// so the bank-blob read is skipped and the editor keeps its last-known sample list.
|
||||
// A stale-but-intact list is better than clearing samples_ on every transient hiccup.
|
||||
|
||||
if (lastSeenBankGeneration_ < 0 || currentGen != lastSeenBankGeneration_) {
|
||||
auto banks =
|
||||
|
||||
@@ -430,22 +430,24 @@ ReaSamplerProcessor::pollBankSync(bool isFocusedTarget) {
|
||||
}
|
||||
}
|
||||
|
||||
// Read lastConsumed and conditionally write it back under a single lock scope so there
|
||||
// is no interleave window between the read and the write (a concurrent getState could
|
||||
// otherwise observe a stale marker between the two separate lock acquisitions).
|
||||
std::int64_t lastConsumed = 0;
|
||||
{
|
||||
const AssignConsumeDecision decision = [&] {
|
||||
std::lock_guard<std::mutex> lock(assignMarkerMutex_);
|
||||
lastConsumed = lastConsumedAssignGeneration_;
|
||||
}
|
||||
const AssignConsumeDecision decision =
|
||||
consumeDecision(request, lastConsumed, resolves, isFocusedTarget);
|
||||
|
||||
// Advance the persisted consumed marker whenever the decision consumed the request
|
||||
// (applied OR dropped-as-seen). getState will persist it on the next project save so a
|
||||
// re-open does not re-apply. A non-target instance leaves the marker (decision returns it
|
||||
// unchanged) so it stays eligible if focus later lands here.
|
||||
if (decision.consumedGeneration != lastConsumed) {
|
||||
std::lock_guard<std::mutex> lock(assignMarkerMutex_);
|
||||
lastConsumedAssignGeneration_ = decision.consumedGeneration;
|
||||
}
|
||||
const AssignConsumeDecision d =
|
||||
consumeDecision(request, lastConsumed, resolves, isFocusedTarget);
|
||||
// Advance the persisted consumed marker whenever the decision consumed the request
|
||||
// (applied OR dropped-as-seen). getState will persist it on the next project save so
|
||||
// a re-open does not re-apply. A non-target instance leaves the marker (decision
|
||||
// returns it unchanged) so it stays eligible if focus later lands here.
|
||||
if (d.consumedGeneration != lastConsumed) {
|
||||
lastConsumedAssignGeneration_ = d.consumedGeneration;
|
||||
}
|
||||
return d;
|
||||
}();
|
||||
|
||||
if (decision.apply) {
|
||||
// Apply the assignment as this instance's own selection (the same path a user card-pick
|
||||
|
||||
Reference in New Issue
Block a user