Repository navigation
Conversation
…bic#453) flushIO()/flushIOMaxPriorityItem() ran the real save()/load() but discarded the result, and the blocking paths (asyncBlockingSave, blocking asyncLoad) always returned totalSize, so a write/read failure looked like success to the caller. The existing checks in virtual_memory (sz != pageSize) and the ant-colony export (saved != totalBytes) were therefore dead code. - Record the real save()/load() result on the FileItem (mResult) in both flush paths, and log failed reads/writes with the file name (always-on, not debug). - Return mResult from the blocking paths instead of totalSize, so callers see the real outcome; a stop during the wait now returns kStop rather than a false success. This is additive: no change to the queue/threading, and no caller changes needed for virtual-memory paging and the ant-colony export — their existing result checks simply start working. save()/load() already return <0 on failure. Remaining from qubic#453, to do next on this branch: unit tests for a failed load/save and for a stop during a wait (modeled on the TestAsyncFileIO harness), and the end-of-epoch/revenue saves can gain an explicit check now that the result is meaningful. The testnet failure-simulation (missing / read-only directory) needs the node environment — happy to coordinate on that.
Add two regression tests under TestAsyncFileIO that drive a blocking asyncLoad()/asyncSave() which is guaranteed to fail (a missing file and an unopenable path) and assert the returned result is now negative. Before qubic#1027 the blocking paths returned the request size even when the underlying save()/load() failed, so a failed read/write was indistinguishable from success. These tests return 64 (totalSize) on the pre-fix code and -1 afterwards, so they lock in the propagation fix.
|
Tests added and verified locally (built Regression proof — the two new tests fail on the pre-#1027 code and pass after: Against ( With this PR they pass, and you can see the new failure logging fire: Full |
|
Looks in general good to me. To additions would be nice:
I also think the end-of-epoch/revenue checks would be nice. And a test on BM is needed before we could merge it. We definitely could help to run it by our test team but would be nice to have a test strategy to also force some of the failure cases. @cyber-pc do you have any additions? |
…c#453) Review follow-ups for the error-propagation change: - file_io.h: the asyncBlockingSave()/asyncLoad() main-thread (synchronous flush) path now reads mResult, frees the slot (kFree) and returns, instead of returning without freeing. flushWrite()/flushRead() run markAsDone(), which leaves a kBlockingWait slot in kProcessed, so without this each main-thread call permanently consumed one of the fixed blocking slots. - virtual_memory.h: loadPageToCache() invalidates the cache slot (cachePageId[cache_page_id] = (unsigned long long)-1, the same empty-slot sentinel reset() fills via setMem(..., 0xff)) before returning -1 on a failed/partial page load, so a later findCachePage() cannot return this slot and serve corrupt data under a page id that was valid before the load.
…ubic#453) Drive more than a full blocking-queue depth (ASYNC_FILE_IO_BLOCKING_MAX_QUEUE_ITEMS * 2) of guaranteed-failing blocking load/save ops and assert that each one propagates a real (<0) failure and that the fixed queue is never exhausted, i.e. the slot is recycled on the failure path rather than leaked. These exercise the NO_UEFI-reachable (non-main-thread) blocking path. The main-thread flush path fixed in this PR is only reachable on bare metal; see the PR test strategy for how that path is forced and asserted there.
|
Thanks for the review — pushed
One caveat worth flagging for the test team: under |
Implements the error-propagation part of #453.
Problem
flushIO()/flushIOMaxPriorityItem()run the realsave()/load()but discard the result, and the blocking paths (asyncBlockingSave, blockingasyncLoad) alwaysreturn (long long)totalSize. So a failed write/read looks like success to the caller — and the existing checks invirtual_memory.h(if (sz != pageSize) …) and the ant-colony export (if (saved != totalBytes) return false) are effectively dead code.This PR (additive, no threading/queue changes)
save()/load()result on theFileItem(mResult) in both flush paths, and log failed reads/writes with the file name (always-on, vialogToConsole).mResultfrom the blocking paths instead oftotalSize, so callers see the real outcome; a stop during the wait now returnskStoprather than a false success.No caller changes are needed for virtual-memory paging or the ant-colony export — their existing result checks simply start working (
save()/load()already return<0on failure).Mapping to the #453 checklist
save()/load()result back to callers.test/file_io.cpp:AsyncBlockingLoadMissingFilePropagatesFailure(blocking load of a missing file) andAsyncBlockingSaveFailurePropagatesFailure(blocking save to an unopenable path). Both assert the blocking result is now< 0. The stop-during-wait →kStopcase is noted in a comment as not deterministically reachable through the public API (mIsStopis private and only set bydeInit(), which also flushes and freesgAsyncFileIO), so it's left to inspection rather than a racy test.@cyber-pc — this is the approach from above (result on the item + return it from the blocking paths + log on failure), now with the tests in. Happy to adjust if you'd prefer anything different.