mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-10-24 06:42:30 +00:00
fix(nomadnet): bound cache transient-stall so a failing SD seam cannot freeze the UI
The SD page cache (16af3b5) made the SD card a soft dependency of
NomadNet page loads, but its step machine retries a transient storage
result (BUSY = SPI-mutex timeout, UNAVAILABLE = card not mounted)
forever with no budget. On a persistently unhealthy seam the boot-time
recovery pins operation_ != NONE, the flow stays LOOKUP, and the UI
freezes at 'Checking SD page cache...' (the CACHE state has no
deadline, unlike every other NomadNet state).
NomadNetCache::service() now compares each call's entry state to the
previous call's. Any advance (op, offset, scan/cleanup index, scan
count, open-flags) resets a stall counter, so slow-but-progressing
steps (chunked 64 KB transfers, up to 96-record directory scans) never
false-trip; a no-progress tick is a transient stall. Past 500
consecutive no-progress ticks (far beyond any real SPI contention or
SD mount window) the cache bails: mark the namespace non-authoritative
for the session (lookups/commits bypass) and clear the op, so the flow
falls through to a live fetch -- the pre-cache page-load behavior.
Regression tests: cache-level (persistent UNAVAILABLE recovery bails;
lookup bypasses after bail) and flow-level (a permanently BUSY
beginList no longer parks the flow in LOOKUP; it reaches NEED_LIVE in
bounded ticks). Both fail on the pre-fix code and pass with it.
Verified: tdeck firmware build SUCCESS; tests/native 121 passed (3
pre-existing env failures, fail identically on origin/main baseline);
tests/build_scripts 184 passed.
This commit is contained in:
1 parent
a5f85f6756
commit
feb7f0574b
4 files changed
+124
-2
No files matched your search
@@ -929,6 +929,38 @@ CacheResult NomadNetCache::invalidate(const CacheKey& key) {
|
||||
}
|
||||
|
||||
void NomadNetCache::service() {
|
||||
// Transient-stall guard (cross-call): compare this call's entry state to
|
||||
// the previous call's. A transient (BUSY/UNAVAILABLE) retry changes none
|
||||
// of the tracked bits, so an unchanged entry across consecutive service()
|
||||
// calls is a stall; any advance resets the counter. Past the bounded
|
||||
// budget, bail so a persistently unhealthy SD seam can never pin the cache
|
||||
// (and the NomadNet UI at "Checking SD page cache..."). The baseline is
|
||||
// refreshed before the switch so every path — including early returns —
|
||||
// leaves a correct entry for the next call.
|
||||
if (operation_ != Operation::NONE &&
|
||||
operation_ == transient_prev_op_ &&
|
||||
offset_ == transient_prev_offset_ &&
|
||||
scan_index_ == transient_prev_scan_index_ &&
|
||||
cleanup_index_ == transient_prev_cleanup_index_ &&
|
||||
scan_seen_ == transient_prev_scan_seen_ &&
|
||||
read_open_ == transient_prev_read_open_ &&
|
||||
write_open_ == transient_prev_write_open_) {
|
||||
if (transient_stall_count_ < MAX_TRANSIENT_STALL_TICKS) {
|
||||
++transient_stall_count_;
|
||||
} else {
|
||||
transient_stall_count_ = 0;
|
||||
transient_bail();
|
||||
}
|
||||
} else if (operation_ != Operation::NONE) {
|
||||
transient_stall_count_ = 0;
|
||||
}
|
||||
transient_prev_op_ = operation_;
|
||||
transient_prev_offset_ = offset_;
|
||||
transient_prev_scan_index_ = scan_index_;
|
||||
transient_prev_cleanup_index_ = cleanup_index_;
|
||||
transient_prev_scan_seen_ = scan_seen_;
|
||||
transient_prev_read_open_ = read_open_;
|
||||
transient_prev_write_open_ = write_open_;
|
||||
switch (operation_) {
|
||||
case Operation::NONE:
|
||||
return;
|
||||
@@ -1428,6 +1460,30 @@ void NomadNetCache::service() {
|
||||
}
|
||||
}
|
||||
|
||||
void NomadNetCache::transient_bail() {
|
||||
// The storage seam has been stalled for far longer than any real SPI
|
||||
// contention or SD mount window. Stop retrying: drop all namespace
|
||||
// authority (lookups and commits now bypass), and clear the in-flight op
|
||||
// so the caller's flow falls through to a live fetch, restoring the
|
||||
// pre-cache page-load behavior instead of a frozen UI.
|
||||
transient_stall_count_ = 0;
|
||||
namespace_authoritative_ = false;
|
||||
read_open_ = false;
|
||||
write_open_ = false;
|
||||
commit_job_ = false;
|
||||
cleanup_stages_after_failure_ = false;
|
||||
eviction_pending_ = false;
|
||||
eviction_generation_ = -1;
|
||||
quota_recovery_ = false;
|
||||
recovery_complete_ = false;
|
||||
offset_ = 0;
|
||||
io_.clear();
|
||||
metadata_bytes_.clear();
|
||||
ExternalVector<std::uint8_t>().swap(body_);
|
||||
operation_ = Operation::NONE;
|
||||
result_ = CacheResult::BYPASS;
|
||||
}
|
||||
|
||||
void NomadNetCache::cancel() {
|
||||
if (!busy() || eviction_pending_ || quota_recovery_) {
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user