snapshots: parallel snapin/wr - #11537
mjain-jump wants to merge 7 commits into
Conversation
┌─ ⚡ PERF · bf2a006 vs main@ce1399b ─────────────────────────────────
│ SUITE BASELINE NEW Δ
│ replay tps, mainnet 29,508 tps 29,476 tps · -0.11%
│ bench tps, localnet 830,810 tps 830,583 tps · -0.03%
│ snapshot load, testnet 15.11 s 15.05 s · -0.39%
!│ mem total, mainnet 158.40 GiB 158.68 GiB ▲ +0.18%
!│ mem total, testnet 89.40 GiB 89.68 GiB ▲ +0.32%
!│ mem total, ag mainnet 189.91 GiB 190.19 GiB ▲ +0.15%
!│ mem total, ag testnet 120.91 GiB 121.19 GiB ▲ +0.23%
│ clean compile, firedancer 2.78 s 2.84 s · +2.34%
│ binary size, firedancer 56.20 MB 56.14 MB · -0.10%
├─────────────────────────────────────────────────────────────────────
@@ 0 REGRESSIONS · 4 WARNINGS · 0 IMPROVED · 5 NOISE @@
└─────────────────────────────────────────────────────────────────────history · 11 pushes ┌─ HISTORY · Δ vs main, per push, newest first ───────────────────────────────────────────
│ HEAD TPS BENCH SNAP MEM·M MEM·T AG·M AG·T COMPILE BINARY
!│ bf2a006 -0.11% -0.03% -0.39% +0.18% +0.32% +0.15% +0.23% +2.34% -0.10%
!│ 4245193 +0.28% +0.22% -30.04% +0.17% +0.30% +0.14% +0.22% +0.40% -0.10%
!│ 01f9314 -0.66% -0.04% -4.91% +0.17% +0.30% +0.14% +0.22% -0.32% -0.10%
!│ feaf379 -2.22% +0.27% -5.97% +0.17% +0.29% +0.14% +0.22% -0.52% -0.10%
!│ 698337d -0.04% +0.14% -31.57% +0.17% +0.29% +0.14% +0.22% +2.11% -0.11%
!│ 14f5f12 +0.22% +0.07% -8.06% +0.17% +0.29% … … +0.27% -0.11%
!│ dd2ae43 +0.23% … … +0.17% +0.29% … … -0.81% -0.11%
!│ a18c325 -0.10% -0.38% -4.34% +0.17% +0.29% … … +2.09% -0.11%
!│ 586c0b1 … … -14.44% +0.17% +0.29% … … +1.13% -0.11%
!│ ddd7767 -0.13% +0.16% -3.67% +0.17% +0.29% … … -0.29% -0.11%
!│ 00a09db +0.13% -1.22% -2.33% +0.17% +0.29% … … -2.98% -0.11%
└───────────────────────────────────────────────────────────────────────────────────────── |
There was a problem hiding this comment.
🟡 Changes recommended
An unresolved critical incremental-load lifecycle issue and moderate correctness and validation issues remain.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
This PR parallelizes snapshot ingestion and account-database writes across snapin workers, replacing the dedicated snapwr writer.
Changes:
- Adds batched pool and accdb snapshot-write APIs.
- Updates parser, topology, configuration, metrics, tooling, tests, and seccomp policies.
- Adds worker coordination and aggregated progress reporting.
File summaries
| File | Reviewed change / final note |
|---|---|
src/util/tmpl/test_pool_para.c |
Batch-pool acquisition and contention tests. |
src/util/tmpl/fd_pool_para.c |
Batch pool acquisition support. |
src/flamenco/accdb/fd_accdb.h |
Snapshot-loading lifecycle and batched-write API contracts. |
src/flamenco/accdb/fd_accdb.c |
Batched writes and concurrent reservations. Moderate (2 votes): reserves cnt entries before determining which accounts need new entries, potentially aborting valid near-capacity loads. |
src/flamenco/accdb/fd_accdb_shmem.c |
Shared-memory compaction coordination. |
src/flamenco/accdb/fd_accdb_private.h |
Internal account-database state. |
src/discof/restore/utils/test_ssparse.c |
Snapshot parser batch tests. |
src/discof/restore/utils/fuzz_snapshot_parser.c |
Parser fuzzer updates. |
src/discof/restore/utils/fd_ssparse.h |
Batched parser API definitions. |
src/discof/restore/utils/fd_ssparse.c |
Batched parsing and appendvec ownership. |
src/discof/restore/utils/fd_ssctrl.h |
Snapshot control definitions. |
src/discof/restore/utils/fd_snapin_shmem.h |
Shared snapin worker coordination. |
src/discof/restore/test_snapwr_tile.c |
Snapwr tile test updates. |
src/discof/restore/test_snapin_accdb.c |
Multi-worker accdb integration tests. |
src/discof/restore/Local.mk |
Restore build integration. |
src/discof/restore/generated/fd_snapwr_tile_seccomp.h |
Generated policy for the removed snapwr tile. |
src/discof/restore/generated/fd_snapin_tile_seccomp.h |
Generated snapin worker seccomp filter. |
src/discof/restore/fd_snapwr_tile.seccomppolicy |
Removed snapwr syscall policy. |
src/discof/restore/fd_snapwr_tile.c |
Removed dedicated snapwr writer tile. |
src/discof/restore/fd_snapin_tile.seccomppolicy |
Snapin worker syscall policy. Critical (2 votes; comment on the corresponding tile implementation): incremental loads do not call fd_accdb_snapshot_load_begin, leaving lifecycle state and compaction handling incorrect. |
src/discof/restore/fd_snapct_tile.c |
Snapshot control tile updates. |
src/disco/topo/fd_topob.c |
Topology builder updates. |
src/disco/topo/fd_topo.h |
Topology declarations. |
src/disco/metrics/metrics.xml |
Snapshot metric definitions. Nit (1 vote): accounts_loaded counts newly inserted accounts only, not duplicates; update the summary or metric behavior. |
src/disco/metrics/generated/fd_metrics_snapwr.h |
Removed snapwr metric identifiers. |
src/disco/metrics/generated/fd_metrics_snapwr.c |
Removed snapwr metric metadata. |
src/disco/metrics/generated/fd_metrics_snapin.h |
Snapin metric identifiers. |
src/disco/metrics/generated/fd_metrics_snapin.c |
Snapin metric metadata. |
src/disco/metrics/generated/fd_metrics_all.h |
Aggregate metric declarations. |
src/disco/metrics/generated/fd_metrics_all.c |
Aggregate metric metadata. |
src/disco/gui/fd_gui.h |
GUI metric interfaces. |
src/disco/gui/fd_gui.c |
Aggregated snapshot progress reporting. |
src/disco/gui/fd_gui_printf.c |
GUI metric formatting. |
src/app/shared/test_config_parse.c |
Configuration parsing tests. |
src/app/shared/fd_config.h |
Worker-count configuration definitions. |
src/app/shared/fd_config.c |
Common configuration validation. Moderate (1 vote): worker counts above FD_TOPO_MAX_TILE_IN_LINKS are not rejected early and can abort during snapin initialization. |
src/app/shared/fd_config_parse.c |
Configuration parsing updates. |
src/app/shared/commands/watch/watch.c |
Aggregated snapshot monitoring metrics. |
src/app/shared/commands/run/run.c |
Run-command integration. |
src/app/firedancer/topology.c |
Production topology wiring. |
src/app/firedancer/main.c |
Tile and object registration. |
src/app/firedancer/config/default.toml |
Default parallel-loader settings. |
src/app/firedancer/callbacks.c |
Shared-memory callbacks. |
src/app/firedancer-dev/main.h |
Development tile and object registration. |
src/app/firedancer-dev/commands/snapshot_load.c |
Standalone snapshot-loader topology and monitoring. |
src/app/firedancer-dev/commands/forktest/forktest.c |
Forktest topology updates. |
src/app/firedancer-dev/commands/backtest.c |
Backtest topology updates. |
book/api/websocket.md |
WebSocket API documentation updates. |
book/api/metrics-generated.md |
Generated metrics documentation. Nit (1 vote): repeats the inaccurate duplicate-account claim; regenerate after correcting metrics.xml. |
Review details
Suppressed comments (3)
book/api/metrics-generated.md:134
- This generated metric table repeats the inaccurate claim that
snapin_account_loadedincludes duplicates, although the implementation increments it only for newly inserted accounts. Regenerate this file after correcting the authoritative summary insrc/disco/metrics/metrics.xml.
| <span class="metrics-name">snapin_​account_​loaded</span> | gauge | Accounts seen during snapshot loading. Includes duplicates. Resets if snapshot load restarts |
src/app/shared/fd_config.c:483
- The shared snapin state and
fd_snapin_tilerejectworker_cnt > FD_TOPO_MAX_TILE_IN_LINKS, but this validation only checks that the configured count is nonzero. A value above 128 passes config validation and topology construction, then aborts during snapin initialization; reject the upper bound during common config validation so all topology entry points fail early and consistently.
CFG_HAS_NON_ZERO( layout.snapin_tile_count );
src/disco/metrics/metrics.xml:1738
accounts_loadedis incremented from the accdbloadedresult, which counts only newly inserted entries; replacements and ignored stale duplicates are reported in separate counters. The current summary therefore incorrectly says this gauge includes duplicates. Describe it as newly inserted accounts (or change the metric update to count every record).
<gauge name="AccountLoaded" summary="Accounts seen during snapshot loading. Includes duplicates. Resets if snapshot load restarts" />
- Files reviewed: 43/52 changed files
- Comments generated: 2
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
Four unresolved findings remain, including two critical snapshot-loading and account-database correctness issues.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (2)
src/discof/restore/fd_snapin_tile.c:1193
fd_accdb_snapshot_write_batchreports only newly inserted entries throughaccounts_loaded; replacements and stale duplicates are returned separately. Adding only this value makes the newSNAPIN ACCOUNT_LOADEDgauge undercount the accounts seen, contrary to its metric definition and the progress/rate displays that consume it. Includeaccounts_replacedandaccounts_ignoredin this gauge (while keepingworker.loadedas the count of new entries).
src/flamenco/accdb/fd_accdb.c:4024- This reserves
cntaccmetaobjects before Phase 2 determines whether any record needs a new pool entry. In an incremental load, a batch can consist entirely of stale records (or in-place replacements) and therefore require zero new objects, but this call still returns NULL and theFD_TESTaborts when fewer thancntpool entries are free. Allocate only when the per-record path takes the new-account branch, or otherwise reserve based on the actual number of new records.
- Files reviewed: 43/52 changed files
- Comments generated: 2
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
🟡 Changes recommended
Two unresolved fd_accdb.c issues remain, including a critical rollback defect.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (1)
src/flamenco/accdb/fd_accdb.c:4024
- This pre-acquires
cntaccount-pool elements before the stripe walk, even though many records in the batch may be replacements or ignored records and therefore need no new element. Near the account-capacity limit (and especially with multiple workers), a batch of eight existing accounts can fail this assertion despite requiring zero free account slots, aborting a valid snapshot load. Acquire slots only for records proven to be new (or otherwise size the reservation to the actual new-record count) and handle genuine exhaustion without asserting.
- Files reviewed: 43/52 changed files
- Comments generated: 1
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
🔵 Needs a closer look
Address the incremental-load coordination issue and avoid reserving pool entries for non-inserted records.
Review details
Suppressed comments (2)
src/discof/restore/fd_snapin_tile.c:1654
- The incremental branch creates the child fork without calling
fd_accdb_snapshot_load_begin, but the sharedsnapshot_loadingflag is what suppresses compaction while snapshot writers update partitions. Sincefd_accdb_snapshot_load_endis still called after the load, incremental writes can be compacted concurrently and the load-end tiering assumptions are not established. Start snapshot-load mode in this branch before the worker writers can begin (before or immediately around the child-fork setup).
src/flamenco/accdb/fd_accdb.c:4024 - This unconditionally reserves
cntaccount-pool entries before the code determines whether each record is an insertion, replacement, or ignored duplicate. A valid incremental batch containing only replacements can therefore abort when fewer thancntpool entries are free, even though it needs no new entries; the same can happen for a mixed batch when the number of inserts is smaller thancnt. Determine the new-entry count under the stripe locks and acquire only that many entries (or otherwise handle pool exhaustion without requiring one slot per input record).
- Files reviewed: 43/52 changed files
- Comments generated: 0 new
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical and moderate findings remain in snapshot lifecycle, stake-cache ordering, concurrent test coverage, and account-pool reservation.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (3)
src/discof/restore/fd_snapin_tile.c:1674
- The incremental INIT creates the fork but never calls
fd_accdb_snapshot_load_begin, while the DONE path still callsfd_accdb_snapshot_load_end. Consequently incremental workers write withsnapshot_loading==0: compaction is not suspended and their layer-0 partitions are not tagged Cold, contrary to the new begin/end contract. Start snapshot-load mode for incremental attempts before any worker can write.
ctx->lead.accdb_incr_fork_id = fd_accdb_attach_child( ctx->accdb, ctx->lead.accdb_root_fork_id );
src/discof/restore/test_snapin_accdb.c:306
- The 9-worker case does not run snapin workers concurrently:
dispatch_snapshotinvokesprocess_account_batchsynchronously for one selected worker at a time. Thus the new shared appendvec claiming, concurrent account writes, and shared stake updates are not exercised under the scheduling that production uses, so races and ordering bugs can pass this test. Add an actual concurrent worker/racesan test or equivalent interleaving that covers the writer path.
src/flamenco/accdb/fd_accdb.c:4024 acc_pool_acquire_batchreservescntentries before this loop determines whether each account is a new insert, replacement, or ignored duplicate. Near the configured account limit, a valid batch containing only replacements/ignored records (or fewer thancntnew records) can have fewer thancntfree pool entries, so this assertion aborts the validator even though no additional entries are required. Classify the records while holding the appropriate stripes and acquire only the entries needed for actual inserts, or otherwise avoid requiringcntfree entries.
- Files reviewed: 41/50 changed files
- Comments generated: 1
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
🔵 Needs a closer look
Three moderate findings and one documentation nit remain unresolved.
Review details
Suppressed comments (4)
src/disco/metrics/metrics.xml:1738
accounts_loadedis incremented from the batch writer'sloadedresult, which counts only newly inserted records; replacements and ignored duplicates are reported separately. The summary claiming this gauge includes duplicates is therefore inaccurate and will mislead users interpreting snapshot progress.
<gauge name="AccountLoaded" summary="Accounts seen during snapshot loading. Includes duplicates. Resets if snapshot load restarts" />
src/discof/restore/fd_snapin_tile.c:1675
- The incremental path creates snapshot writers but never calls
fd_accdb_snapshot_load_begin; only the full path setssnapshot_loading. As a result, compaction remains enabled while incrementalfd_accdb_snapshot_write_batchcalls run, contrary to the lifecycle contract and the protection used for full loads, so compaction can race bulk writes. Begin the load for incremental attempts as well and keep it paired with the existingsnapshot_load_end(including retry cleanup).
ctx->lead.accdb_incr_fork_id = fd_accdb_attach_child( ctx->accdb, ctx->lead.accdb_root_fork_id );
}
src/discof/restore/fd_snapin_tile.c:1200
- This updates the shared stake cache before the account-database commit decides whether the record is accepted. With parallel workers, records for the same stake account at different slots can complete out of order, so an older record that
fd_accdb_snapshot_write_batchlater ignores can overwrite the newer delegation; the final cache then depends on worker scheduling. Apply the update only after the record is known to win, or reconcile it from committed records using slot ordering.
if( FD_UNLIKELY( batch.lamports[ i ] &&
!memcmp( batch.owners[ i ], fd_solana_stake_program_id.uc, 32UL ) ) ) {
snoop_stake_delegation( ctx, (fd_pubkey_t const *)batch.pubkeys[ i ],
batch.lamports[ i ], batch.data_lens[ i ],
batch.datas[ i ], batch.data_lens[ i ] );
}
src/flamenco/accdb/fd_accdb.c:4024
acquiredis reserved for every input before the code determines whether each account is new. In an incremental snapshot, replacements and higher-slot duplicates reuse an existing entry or are ignored, so a batch with (for example) 8 existing accounts can fail when fewer than 8 pool entries are free even though it needs no new entries;FD_TESTthen aborts the loader instead of returning a normal result. Determine the required new entries while holding the relevant stripe locks, or use a reservation/rollback scheme that only consumes entries for new accounts.
- Files reviewed: 41/50 changed files
- Comments generated: 0 new
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
🔵 Needs a closer look
One or more issues must be addressed before approval.
Review details
Suppressed comments (5)
book/api/websocket.md:2057
- The GUI still emits live
snapinrows and classifies them as RW (fd_gui.c:359andfd_gui.c:1100), with rows removed only after shutdown. Omittingsnapinfrom both the tile-name examples and the RW list makes this public schema incomplete for the new parallel loader.
| name | `string` | Tile kind name, e.g. `execle`, `execrp`, `replay`, `tower`, `rpc`, `resolv`, or `accdb` |
| kind_id | `number` | Instance index within this tile kind |
| joiner_type | `string` | `RW` if the tile reads and writes accounts (`execle`, `execrp`, `replay`, `tower`, `accdb`), `RO` if it only reads (`rpc`, `resolv`) |
src/disco/metrics/metrics.xml:1738
AccountLoadedis incremented fromaccounts_loaded, which only counts newly inserted records, so saying duplicates are included is inaccurate. Correct this description and regeneratesrc/disco/metrics/generated/fd_metrics_snapin.handbook/api/metrics-generated.mdso the compiled/API documentation matches the metric.
<gauge name="AccountLoaded" summary="Accounts seen during snapshot loading. Includes duplicates. Resets if snapshot load restarts" />
src/discof/restore/fd_snapin_tile.c:1199
- This updates the shared stake-delegation root for every input record before the account database decides whether that record is the winner. Since snapin workers flush appendvecs independently, an older duplicate can finish after a newer one, and
fd_stake_delegations_root_updateoverwrites unconditionally; the stake cache can then disagree with the account database's highest-slot record. Apply this update only for the committed winner (or preserve/order per-record outcomes before updating the cache).
if( FD_UNLIKELY( batch.lamports[ i ] &&
!memcmp( batch.owners[ i ], fd_solana_stake_program_id.uc, 32UL ) ) ) {
snoop_stake_delegation( ctx, (fd_pubkey_t const *)batch.pubkeys[ i ],
batch.lamports[ i ], batch.data_lens[ i ],
batch.datas[ i ], batch.data_lens[ i ] );
src/discof/restore/fd_snapin_tile.c:1674
fd_accdb_snapshot_load_endruns for both full and incremental loads, butsnapshot_loadingis enabled only in the full branch. Incremental workers therefore leave compaction enabled whilefd_accdb_snapshot_write_batchbulk-updates partitions, defeating the lifecycle's compaction exclusion and allowing the compaction tile to race with the load. Start the load lifecycle for the incremental branch as well, before workers begin writing.
} else {
/* Create a child fork for incremental writes. On failure,
fd_accdb_purge(child) reverts just the incremental changes.
On success, fd_accdb_advance_root(child) promotes them. */
ctx->lead.accdb_incr_fork_id = fd_accdb_attach_child( ctx->accdb, ctx->lead.accdb_root_fork_id );
src/flamenco/accdb/fd_accdb.c:4024
- This reserves
cntaccount-pool entries before the batch determines which records are new. A replacement/ignored-heavy batch can therefore abort when fewer thancntpool slots are free even though it needs no (or fewer) new entries; for example, two same-fork replacements with one free slot fail here. Acquire slots only for the new-entry path (or otherwise reserve the number of actual inserts), while retaining the partial-commit cleanup.
- Files reviewed: 41/50 changed files
- Comments generated: 0 new
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
🔵 Needs a closer look
The critical compaction-coordination issue and two moderate correctness issues remain; concurrent worker coverage is also incomplete.
Review details
Suppressed comments (4)
src/discof/restore/fd_snapin_tile.c:1675
- The incremental path never enters snapshot-loading mode. As a result, partitions created by incremental writers are not tagged Cold and background compaction remains enabled while those writers are active, unlike the full-load path. Call
fd_accdb_snapshot_load_beginfor this branch so it is symmetric with the existingfd_accdb_snapshot_load_endat completion.
ctx->lead.accdb_incr_fork_id = fd_accdb_attach_child( ctx->accdb, ctx->lead.accdb_root_fork_id );
}
src/discof/restore/test_snapin_accdb.c:190
- The nine-worker case still dispatches each appendvec synchronously (
owner = &env->worker[ appendvec_cnt%env->worker_cnt ]), so it never runs workers concurrently. The new shared appendvec claims, concurrent file reservations, and striped account commits are therefore not exercised end-to-end; add a concurrent worker/tile harness that drives the same stream and checks for missing or duplicated accounts.
src/flamenco/accdb/fd_accdb.c:4024 - This pre-acquires
cntaccount-pool elements before the per-key lookup. Near the configured account limit, a batch can contain only stale/replacement entries (or multiple workers can temporarily hold more elements than they will insert), so the pool can have fewer thancntfree elements even though the batch needs no new entries.FD_TESTthen aborts the validator instead of processing the snapshot; acquire pool elements only after determining that an entry is new, or otherwise make acquisition track the actual new-entry count.
src/flamenco/accdb/fd_accdb_private.h:387 - The
snapshot_loadingflag is checked here only to suppress future enqueue operations, but the accdb tile still processes any entries already present on the compaction dlists infd_accdb_background. Such compaction can update account metadata or recycle partitions concurrently withfd_accdb_snapshot_write_batch; the new snapshot stripe locks do not synchronize with that path. The load transition must stop/drain existing compaction work and keep it paused until all snapshot writers finish, rather than only deferring new enqueues.
- Files reviewed: 41/50 changed files
- Comments generated: 0 new
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical and moderate findings affect delegation state, snapshot load lifecycle, compaction, and account-pool reservation safety.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (4)
src/disco/metrics/metrics.xml:1738
AccountLoadedis incremented from the accdbaccounts_loadedresult, while replacements and ignored duplicates are counted separately. The current summary says this gauge includes duplicates, so dashboards will interpret the metric incorrectly; describe it as inserted accounts (excluding duplicates), or useAccountProcessedfor the documented behavior.
<gauge name="AccountLoaded" summary="Accounts seen during snapshot loading. Includes duplicates. Resets if snapshot load restarts" />
src/discof/restore/fd_snapin_tile.c:1645
- This new load flag is not cleared on an aborted attempt:
CTRL_FAILflushes and resets the worker state, butfd_accdb_snapshot_load_endis only called from the successfulDONEpath. A failed full load therefore suppresses compaction until a later full reset (and indefinitely if no retry), while any deferred threshold sweep is skipped. Add an explicit abort/cleanup lifecycle that runs after all writers have stopped and clears the flag without promoting the failed snapshot.
fd_accdb_snapshot_load_begin( ctx->accdb );
src/discof/restore/fd_snapin_tile.c:1645
fd_accdb_snapshot_load_beginis only called in the full-snapshot branch, but incremental workers start writing immediately after theelsebranch. That leavessnapshot_loadingclear during incremental loading, sofd_accdb_shmem_try_enqueue_compactioncan enqueue layer-0 partitions while concurrent batch writes are filling them;fd_accdb_advance_rootis submitted asynchronously beforesnapshot_load_endruns. Start the load lifecycle for both full and incremental attempts after the full reset/child-fork setup, before publishing the attempt.
fd_accdb_snapshot_load_begin( ctx->accdb );
src/flamenco/accdb/fd_accdb.c:4023
- This reserves
cntaccount-pool elements before determining which inputs are new. A valid batch can contain existing/repeated/ignored keys and therefore need fewer thancntnewaccmetaentries; when the pool has fewer thancntfree elements,acc_pool_acquire_batchreturns NULL and thisFD_TESTaborts even though the writes could fit. Acquire pool elements only after the stripe lookup confirms a new entry, or otherwise reserve only the number of genuinely new keys.
- Files reviewed: 41/50 changed files
- Comments generated: 1
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
| fd_accdb_t * accdb; | ||
|
|
||
| /* Shared stake data updated by every tile. */ | ||
| fd_stake_delegations_t * stake_delegations; |
There was a problem hiding this comment.
For later follow up, fold fd_stake_delegations_refresh from replay tile into this snooper
| /* Prevent snapshot workers from updating the same hash chain at once. | ||
| Each lock covers many hash chains to save memory while preserving | ||
| concurrency. */ | ||
| int snapshot_stripe_locks[ FD_ACCDB_SNAPSHOT_STRIPE_CNT ] __attribute__((aligned(64))); |
There was a problem hiding this comment.
Shouldn't exist, just CAS on the acc_map
There was a problem hiding this comment.
For removal, you need to coordinate with the epoch counters to do RCU
There was a problem hiding this comment.
🔵 Needs a closer look
Address the accdb pool-exhaustion failure and add the missing snapin WebSocket entries.
Review details
Suppressed comments (2)
book/api/websocket.md:2057
- The public API table now has
snapinrows, but these examples omitsnapinfrom both the tile-name list and the RW joiner-type list. This contradicts the topology/GUI behavior introduced here, where everysnapintile is registered as an accdb RW consumer; please includesnapinin both descriptions.
| name | `string` | Tile kind name, e.g. `execle`, `execrp`, `replay`, `tower`, `rpc`, `resolv`, or `accdb` |
| kind_id | `number` | Instance index within this tile kind |
| joiner_type | `string` | `RW` if the tile reads and writes accounts (`execle`, `execrp`, `replay`, `tower`, `accdb`), `RO` if it only reads (`rpc`, `resolv`) |
src/flamenco/accdb/fd_accdb.c:4023
- This pre-acquires
cntpool entries before checking whether any inputs are new. A valid snapshot batch can contain replacements or stale duplicates while fewer thancntaccount slots are free (including a full account pool), soacc_pool_acquire_batchreturns NULL andFD_TESTaborts instead of processing the batch. Determine the number of entries that actually need allocation while holding the stripe, or acquire entries on demand and return a normal pool-exhaustion error.
- Files reviewed: 41/48 changed files
- Comments generated: 0 new
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
🔵 Needs a closer look
Two moderate account-database issues remain unresolved.
Review details
Suppressed comments (3)
Previously missed (1) — in code that hasn't changed since the last review.
src/flamenco/accdb/fd_accdb.c:191
- These deferred add/subtract operations can be flushed by different snapshot joins in either order. If one worker inserts an account and another worker replaces that newly inserted entry before the first worker flushes its stats, the replacement flush subtracts from
disk_used_bytesbefore the add is published and the unsigned metric wraps to a huge value. Publish a single ordered/signed delta or otherwise synchronize these updates so the metric cannot underflow during parallel loading.
book/api/websocket.md:2071
- The new topology exposes
snapinrows, but these descriptions no longer listsnapinamong the kinds whose eviction/commit rates are always zero. TheFD_GUI_ACCDB_TILE_KIND_SNAPINcase does not populate either counter, so the API documentation is inaccurate for the new rows.
| evicted_per_sec | `number` | Recent rate at which this tile's commits evicted lines from the cache (always `0` for `RO` tiles) |
| committed_per_sec | `number` | Recent rate of account version commits (new + overwrite) by this tile (always `0` for `RO` tiles and `accdb`) |
src/flamenco/accdb/fd_accdb.c:4023
- This pre-acquires
cntfree account-pool entries before determining which inputs are new. A valid batch containing only replacements/ignored duplicates can therefore fail when fewer thancntpool entries are free (for example, a full snapshot whose unique-account count reachesmax_accounts), andFD_TESTaborts even though no new entry is needed. Classify the entries under the stripe locks and acquire only the number of new records, or otherwise handle this shortage without requiring one free record per input.
- Files reviewed: 41/48 changed files
- Comments generated: 0 new
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
🔵 Needs a closer look
Two moderate findings and three documentation nits remain unresolved.
Review details
Suppressed comments (5)
book/api/websocket.md:2057
- The parallel loader is an RW accdb joiner, but this public schema's RW list omits
snapin, so consumers can misclassify the new per-tile row. Includesnapinin the list.
| joiner_type | `string` | `RW` if the tile reads and writes accounts (`execle`, `execrp`, `replay`, `tower`, `accdb`), `RO` if it only reads (`rpc`, `resolv`) |
book/api/websocket.md:2063
snapindirect writers do not publish writable-acquire metrics, so this zero-value qualifier is incomplete after replacingsnapwrwithsnapin. Includesnapinin the list.
| acquired_writable_per_sec | `number` | Recent writable acquire rate for this tile, in accounts per second (always `0` for `RO` tiles and `accdb`) |
book/api/websocket.md:2071
- The
snapinGUI branch only contributes direct disk bytes and leaves eviction/commit counters at zero, but these updated descriptions no longer mention it. Includesnapinin both qualifiers.
| evicted_per_sec | `number` | Recent rate at which this tile's commits evicted lines from the cache (always `0` for `RO` tiles) |
| committed_per_sec | `number` | Recent rate of account version commits (new + overwrite) by this tile (always `0` for `RO` tiles and `accdb`) |
src/app/shared/fd_config.h:116
- This new effective layout setting is not emitted by
fd_config_to_json: the renderer's layout object insrc/app/shared/fd_config_json.c:351-368has nosnapin_tile_count. The resolved boot-telemetry configuration therefore silently omits the loader parallelism; add the field to that renderer and its JSON coverage.
uint snapin_tile_count;
src/flamenco/accdb/fd_accdb.c:4023
- This pre-acquires
cntpool entries before determining which inputs are inserts. A batch of replacements or ignored duplicates can therefore abort when fewer thancntentries are free, even though it needs no new entries (common for incremental loads nearmax_accounts). Acquire an entry only when the locked lookup proves an insertion is needed, and handle exhaustion at that point.
- Files reviewed: 41/48 changed files
- Comments generated: 0 new
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Batch writes can fail despite sufficient effective capacity and do not reliably detect same-slot duplicates across batches.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
339e1b1 to
bf2a006
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Batch pool preallocation can abort valid writes, and parallel stake updates can publish stale account state.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1


No description provided.