Add monad-mpt --rescan-devices - #2532
Open
maxkozlovsky wants to merge 1 commit into
Open
maxkozlovsky wants to merge 1 commit into
maxkozlovsky wants to merge 1 commit into
Conversation
maxkozlovsky
force-pushed
the
max/test-pool-disk-usage
branch
from
September 1, 2026 22:26
e0d4bc1 to
d13ac80
Compare
Contributor
There was a problem hiding this comment.
Reviewed per REVIEW.md: traits (n/a — no category/execution or category/vm changes), FFI boundary (untouched — no extern "C" header, RLP, or monad-bft-facing changes), C++ correctness, crash safety, testing, style, PR hygiene, and security.
What I verified in depth:
- Hash compatibility.
compute_unique_hash_andcompute_config_hash_reproduce the pre-existing FNV1a fold order and truncations exactly (including the low-32-bits-of-size fold and the two-pass unique-hash/chunks+capacity ordering infill_chunks_), so existing pools keep their identities. The golden-value test (config_hash_formula_is_pinned) pins this. - Crash-ordering discipline. The commit protocol is sound at every interruption point I traced: members are stamped with the target hash before the grown device's relocated footer commits; the relocated bytes-used array is written and synced before the footer that validates it;
fill_chunks_flushes device footers beforeDbMetadataContextgrowschunk_info[]; and the metadata growth itself is guarded byPENDING_OP_ADD_DEVICESwith idempotent replay. The stranded footer is never rewritten, so re-running an interrupted operation re-validates against a fixed point. Each of these has a dedicated interruption test. extend_chunk_info_initializes all sevenchunk_info_tfields, continues insertion counts from the free-list tail exactly as the existingappend_does, and runs under one dirty scope. Thetotal_seq_chunks <= chunk_offset_t::max_idbound correctly keeps the top id free for theINVALID_CHUNK_IDsentinel.db_metadatalayout.device_sizesis carved fromfuture_variables_unusedwith the total size pinned at 4480 bystatic_assert, and its placement inside the window the MONAD007 migration zeroes is statically asserted, so the zero sentinel holds on every existing pool.- Healing sizing. Both
db_copyhealing sites that now usedb_map_size_of_are guarded by a current-MAGIC check on the source copy beforechunk_info_countis trusted, and the result is bounds-asserted againstmetadata_mmap_size_. metadata_mapping_()reconstructs themmapbase/length inmake_device_exactly (and incidentally fixes a potential one-pagemunmapshortfall in the old destructor arithmetic).- CLI flag interactions.
--rescan-devicessits in therequire_option(0, 1)exclusive group, and the out-of-group--restore/--archivecombinations have an explicit guard placed before--restoresetstruncate_database— both covered byrescan_devices_argument_cross_checks. - Coherency. All footer/metadata I/O on this path is buffered (no
O_DIRECT) withfdatasync/msync(MS_SYNC)barriers, so the pre-pass reads, relocation writes, and later mappings observe consistent data.
Test coverage is exemplary — every refusal message and crash window has a test, including the death test for a grown pool opened without mode::add_devices.
One P3 posted inline (recorded_device_size reads only metadata copy 0, creating a narrow unrecoverable-without-restore corner when copy 0 is corrupt and a device was already extended). Nothing blocking.
Verdict: CORRECT
🤖 Generated with Claude Code
maxkozlovsky
force-pushed
the
max/device-resize-v2
branch
2 times, most recently
from
September 1, 2026 23:15
3b4b643 to
8f9a6e4
Compare
Growing a node's database meant --archive then --restore into a freshly created larger pool: scratch space, plus a full dump and restore. Extending a device the pool already owned was worse than unsupported -- the metadata saying a device belongs to a pool lives at its very end, so lvextend left it unopenable, with no resize2fs step to follow. --rescan-devices reconciles a database with whatever storage it is now given: --storage lists every device it should contain, and one offline run joins any blank suffix and takes up the space of an extended last device, under one confirmation and one metadata growth. Taking up an extend needs the previous size of the device, which the extend itself strands mid-device, so db_metadata now records every device's size on each writable open, in padding it already reserves -- no magic bump, no migration. That recording is the only source, and is acted on only where the stranded footer's config_hash confirms it, so an extend must be preceded by a writable open under a release carrying this code. Refusing two sources that name one device is needed here, but the hole is not new: creating a pool with a device listed twice was silently accepted, and no later open could detect it. That check goes in the constructor, for every mode. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
maxkozlovsky
force-pushed
the
max/device-resize-v2
branch
from
September 8, 2026 19:54
8f9a6e4 to
72f6d9e
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.
Growing a node's database meant --archive then --restore into a freshly created larger pool: scratch space, plus a full dump and restore. Extending a device the pool already owned was worse than unsupported -- the metadata saying a device belongs to a pool lives at its very end, so lvextend left it unopenable, with no resize2fs step to follow.
--rescan-devices reconciles a database with whatever storage it is now given: --storage lists every device it should contain, and one offline run joins any blank suffix and takes up the space of an extended last device, under one confirmation and one metadata growth.
Taking up an extend needs the previous size of the device, which the extend itself strands mid-device, so db_metadata now records every device's size on each writable open, in padding it already reserves -- no magic bump, no migration. That recording is the only source, and is acted on only where the stranded footer's config_hash confirms it, so an extend must be preceded by a writable open under a release carrying this code.
Refusing two sources that name one device is needed here, but the hole is not new: creating a pool with a device listed twice was silently accepted, and no later open could detect it. That check goes in the constructor, for every mode.