SDSTOR-20656: clear wbc chunk selector - #177
Closed
nnastonen wants to merge 4 commits into
Closed
Conversation
nnastonen
requested review from
JacksonYao287,
shosseinimotlagh,
szmyd and
xiaoxichen
September 9, 2026 10:12
nnastonen
force-pushed
the
reset_block_allocator
branch
from
September 10, 2026 14:13
5c20f36 to
f617e74
Compare
…22886, SDSTOR-22887) (#176) * SDSTOR-22886 craft: SyncRSCommitLSN RAFT entry apply Implement the apply side of the SyncRSCommitLSN RAFT entry
* craft: S3 commit + read path — advance commit_lsn, serve reads, watchdog Squashed from 11 incremental commits (checksum-array blob format, real read_slot(), VolumeIndexTable::delete_lba_range, index handle + journal-tail overlay, commit() wired into write()/keep_alive(), CraftReplDev::read(), client-liveness watchdog, heavy integration + concurrency test coverage, overlay rebuild on restart, and two rounds of robustness-gap fixes) into one commit for a clean rebase onto the updated dev/v6.x base (PR #176 / S5 landed upstream). Implements S3 (SDSTOR-22733): CraftReplDev::commit() advances commit_lsn by applying journaled entries to the index in strict dLSN order, stalling (not erroring) at the first gap; keep_alive() and write() both piggyback it. CraftReplDev::read() serves [addr, addr+len) as of a client-supplied horizon from the index or the journal-tail overlay (never fetches from a peer), CRC-verifying every LBA and collapsing all-zero content to holes at read time. A per-partition watchdog timer proposes a SyncRSCommitLSN entry when a client goes quiet. rebuild_overlay() repopulates the overlay from the journal on restart. Full unit + HomeStore-integration + concurrency test coverage across test_craft_commit.cpp, test_craft_commit_hs.cpp, test_craft_concurrency.cpp, test_craft_homestore_backend.cpp, and test_craft_watchdog.cpp. * craft: fix 13 review findings from PR #175 (horizon, TOCTOU, block leaks, validation) Addresses sbinmalek/Copilot/szmyd/independent-agent review findings on PR #175, all build-verified (100% tests passing, 12/12 suites). szmyd (blocking) — read()'s piggyback commit can advance commit_lsn past its own read_lsn before read_impl() snapshots it, serving a too-new value with no error. Added volume_error::HORIZON_STALE; read_impl() rejects read_lsn < commit_lsn_snapshot instead of silently serving the too-new value. Residual TOCTOU in read_impl — the horizon check above only guards the snapshot taken BEFORE the unlocked index query; a concurrent commit_impl can still advance commit_lsn while that query runs. Re-snapshot and re-check after the index read closes this second instance of the same class of bug. Copilot — old_blkid == new_blkid frees a live index block on crash-replay of an already-applied slot (index already holds the exact blkid the replay reports as "old"). Skip the free when they match. Copilot — read_slot() never cross-checked the on-disk record's self-describing hdr.lsn against the seq_num actually requested; a corrupt/misplaced record was silently trusted. Now rejected. sbinmalek/Copilot — the all-zero read-time collapse ran before the CRC check, so a bit-flip that zeroed real data was reported as a hole instead of CRC_MISMATCH. CRC is now computed unconditionally before the collapse decision. Copilot — read_slot() derived nlbas from hdr.len without validating alignment/non-zero, letting a corrupt record silently misalign the csum-array and blkid offsets that follow. Validated up front. Copilot — write()'s ack snapshotted state_ BEFORE the piggyback commit() call, so a successful write's own commit progress was never reflected in its own response. Re-snapshot after. Independent-agent finding — hdr.all_committed_lsn (client-controlled) had no validation; a malformed negative value (not the -1 "unset" sentinel) could corrupt this long-lived floor. Now ignored. An unbounded-positive-value poisoning vector remains -- no valid per-call bound exists without breaking the legitimate lagging-replica catch-up signal; documented as a TODO(S8) on the field itself, since only S8's real reclaim implementation has the context to validate it. sbinmalek/Copilot — dest iovec capacity in the read path only checked for emptiness, not whether iov_len actually covered the requested range; an undersized buffer would be written past its end. Copilot — write() allowed a multi-iovec sg_list whose iovs[0] alone happened to satisfy the size/alignment checks, carrying dead trailing iovecs. Rejected as hygiene (the CRC-corruption scenario Copilot originally described was already closed by the pre-existing iov_len check). szmyd (unfiled) — a single contiguous read run could exceed blk_count_t's max (65535 LBAs) at small lba_size/large craft_max_io_len_mb, silently truncating in the run_blkid construction. Capped the run-extension loop at that limit; larger runs now split into multiple read_data batches (invisible to the caller -- adjacent same-type extents still merge). szmyd (unfiled) — commit_impl's is_empty branch skipped overlay retirement entirely, including the case where THIS replica already journaled real data for an lsn the cluster-wide resolution still verdicts Empty ("Empty beats data" reconciliation). Left a live overlay entry that would keep being served on reads, contradicting the verdict. Now attempts a best-effort read_slot() purely to discover the LBA range to retire, even when skipping the index apply. Independent-agent finding (S4 scope, not S3, bundled here per review discussion) — truncate() never freed the data blocks referenced by journal entries it rolled back, permanently leaking them on every login that drops a stale tail. Reads each dropped entry's blkid before the rollback destroys the record, frees it after. Also: two review comments acked but never actually implemented -- explicit is_hole(nlbas, false) initialization (style, sbinmalek) and a shortened TODO-style comment on the logout/watchdog interaction (sbinmalek's "leave a TODO instead of a large comment" request). Deferred to a follow-up PR (design discussion in progress with szmyd): the overlay's single-version-per-LBA limitation, a read_impl/commit_impl atomicity gap distinct from the two fixed above, and asymmetric failure handling for a corrupt journal record hit live vs. at restart. * build: bump version to 6.0.8 * craft: fix build breakage from S5 (PR #176) rebase integration S5 landed independently on dev/v6.x with no visibility into S3's own changes (and vice versa), so several integration points compiled/linked/ran incorrectly even after the rebase's textual conflicts were resolved -- none of these were merge conflicts, they were semantic mismatches between the two branches' independent designs: - HomeStoreCraftJournalBackend::free_slot (S5) computed the blkid offset assuming the pre-S3 [header][blkid] blob layout; S3 inserted a csum array in between ([header][csums][blkid]). Fixed to skip past the csum array via blkid_offset(nlbas), same as read_slot() already does. - apply_sync_rs_commit_lsn's (S5) own write_slot call site never passed csums (added by S3 after S5 branched) -- now passes the fetched slot's own slot.csums. - CraftReplDev moved from a public constructor to a private constructor + create() factory (S5, for shared_from_this()) with S3's lba_size/indx_tbl parameters folded in. Four S3-only test files never conflicted during the rebase (S5 never touched them) but still called the old make_unique<CraftReplDev> pattern directly: test_craft_watchdog.cpp, test_craft_commit.cpp (two call sites), test_craft_concurrency.cpp, test_craft_commit_hs.cpp. All switched to CraftReplDev::create(), with dev_ members changed from unique_ptr to shared_ptr to match create()'s return type. - Three MockCraftJournalBackend mocks (test_craft_commit/concurrency/watchdog) never implemented S5's new free_slot pure virtual, making them abstract classes; added stub overrides. test_craft_raft_entries.cpp's own mock was also missing S3's read_data pure virtual and had a stale 6-arg write_slot override (no csums parameter) -- both fixed. - test_craft_raft_entries's CMakeLists.txt target was missing the generated HB_CONFIG_BINDUMP source and its core-library dependency, causing an undefined reference to home_blks_config_fbs at link time (every other light CRAFT test target already needed this before S5's own tests ever required HB_DYNAMIC_CONFIG). - test_craft_raft_entries.cpp's main() never called SISL_OPTIONS_LOAD -- harmless before S3's watchdog work made CraftReplDev's constructor unconditionally read HB_DYNAMIC_CONFIG(craft_watchdog_timeout_ms), which segfaults against an uninitialized settings registry. Added SISL_OPTIONS_LOAD plus craft_watchdog_timeout_ms=0 (this suite never starts iomgr, so a live recurring timer would crash it regardless). All 13 test suites pass post-fix (100%), including S5's own CraftRaftEntriesTest (28 tests) running for the first time alongside every S3 fix from this review pass. * craft: fix clang-format violation in test_craft_raft_entries.cpp CI's GccAddressSanitize job runs a formatting check against origin/dev/v6.x for PR-modified files and failed on this one line -- pre-existing from the rebase's auto-merge (never touched by any of this session's actual edits to this file, just caught in the same formatting-check scope since the file was modified). Joins the JournalSlot initializer onto one line, matching clang-format -style=file's output. * bump craft client
nnastonen
force-pushed
the
reset_block_allocator
branch
from
September 10, 2026 14:21
b008726 to
2ad2ab7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This change makes chunk release asynchronous and defers returning the chunk to the free pool until cleanup is complete.
New flow: