[trading-native][storage-core] Commit applier + JMT pipeline + AptosDB wiring#19919
Conversation
387c1f9 to
d9994e0
Compare
77c3346 to
d38edd8
Compare
35d7ac3 to
1399952
Compare
1399952 to
f9d9a0e
Compare
d9994e0 to
65cd867
Compare
10f7a2f to
7268704
Compare
65cd867 to
c6e532b
Compare
7268704 to
3f1372c
Compare
3f1372c to
808aecf
Compare
f50f56b to
9cdfed0
Compare
| } | ||
| chain_state = Some(new_latest); | ||
| } | ||
| version += 1; |
There was a problem hiding this comment.
Per-version DB commit writes all 16 shards unnecessarily
Medium Severity
NativeStateCommitter::apply is called once per transaction output inside the chunk loop, and each call invokes PositionDb::commit, which spawns 16 rayon tasks to write progress markers to ALL shards—even the 15+ shards that received no data for that version. For a chunk of N transactions, this produces N × 18 DB writes (16 shards + metadata + progress). Main-state batches the entire chunk into a single commit. The per-version commit IS required for find_prior_version correctness, but writing progress to all 16 empty shards each time is wasteful and could cause significant I/O amplification on the commit path.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit f50f56b. Configure here.
| batch.delete::<StalePositionValueIndexSchema>(&index)?; | ||
| } | ||
| Ok(()) | ||
| } |
There was a problem hiding this comment.
Truncation scans entire shard instead of seeking efficiently
Low Severity
delete_position_value_and_index calls iter.seek_to_first() and scans every PositionValueSchema row in the shard, only deleting entries with version >= start_version. Because the key uses bit-inverted version (!version), rows aren't physically sorted by version across key hashes, making a targeted seek impossible with this schema. However, this full-table scan could be very slow for large position DBs on crash-recovery startup. The stale-index iteration below it is efficient, but the value scan is not.
Reviewed by Cursor Bugbot for commit f50f56b. Configure here.
9cdfed0 to
9b465c2
Compare
c6e532b to
8297de8
Compare
12b5c63 to
57290e6
Compare
ae1ef62 to
90a8639
Compare
255ccb6 to
60f285d
Compare
…B wiring Adds the durable-commit applier, the two-stage JMT commit pipeline, and the AptosDB integration for native positions. Builds on the durable storage tier in `[storage-core-db]` and the shared primitives in `[shared] LeafEntry trait + StateSummary Option` / `[shared] Lift async-commit pipeline`. The in-memory scanner mirror (the `NativeStateStore` DashMap and its readers) is layered on top in a later `[in-memory-store]` commit; the durable + JMT side here stands on its own. Commit applier: - `NativeStateCommitter::apply`: per-shard `SchemaBatch` fan-out against `position_db` for every Position write, returning `NativeMerkleLeafUpdates` (`MerkleLeafUpdate` per write) for the JMT pipeline. Stale-index entries for prior versions are written into the same batch so the pruner can drop them later. Commit pipeline: - `PositionBufferedState` — alias of the shared `BufferedState<L, S, P, X>` generic with position's pipeline parameters and a no-op `PositionExtras`. Constructed via `spawn_commit_pipeline`. - `PositionSnapshotCommitter` driver (`merklize_position`): pulls `PositionSnapshotToCommit` payloads, runs the snapshot through `ShardedJmtMerkleDb::merklize_snapshot`, forwards the resulting `PositionMerkleCommit` downstream. - `PositionMerkleBatchCommitter`: pulls `PositionMerkleCommit`s and persists per-shard JMT batches + top-levels batch to `position_merkle_db`. State-shape primitives in `storage-interface`: `storage/storage-interface/src/state_store/sharded_jmt_state.rs` with the JMT-sharded pipeline primitives that aren't main-state shared: `LeafSlot<V>` + `impl LeafEntry for LeafSlot<V>`, `ShardedJmtState<Slot>` (16 `MapLayer` chains + `extend` / `make_delta` / `is_descendant_of`), the inherent impl on `StateAndSummary<ShardedJmtState<Slot: LeafEntry>>` (`new_empty`, `extend`, `make_delta`, etc.), and `pre_shard_jmt_updates`. Adds two `StateSummary` constructors that only JMT-sharded pipelines without a hot companion need: `new_global_only(version, smt)` and `new_empty_global_only()`. In-aptosdb crate: - `PositionSlot` — type alias of `LeafSlot<()>` (value not carried in-slot; lives in `position_db` durably). - `PositionStateStore` — owner / coordinator, type alias of the shared `PipelineStateStore<L, BS>` (also added in this commit, in `crate::common`). Wraps the shared `current_state` mutex (readable by outside consumers) and the `PositionBufferedState` mutex (commit-path serialization). - `PositionDb` gains the `commit` / `commit_single_shard` / `write_progress` / `find_prior_version` methods that the committer uses. AptosDB wiring: - `AptosDB` gains optional handles for `PositionDb` + `PositionMerkleDb` + `PositionStateStore`. Accessed by the rest of the codebase via `native_position_handles` / `native_state_committer`. - `init_native_position`: opens 16 sharded position DBs + unsharded merkle DB with production CF tuning. Spawns the async commit pipeline seeded with the empty-tree placeholder root. Idempotent (rejects second call). Logs the open. - `commit_native_position` (in `aptosdb_writer.rs`): rayon-spawned alongside main-state commit; drains `output.write_set().native_position_iter()` (the WriteSet sibling bucket from [types]) through `NativeStateCommitter`, feeding the resulting `MerkleLeafUpdate`s into the position JMT pipeline. Cargo.toml deps + lib.rs mod exports for the new files. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
60f285d to
7f3172c
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7f3172c. Configure here.
| }); | ||
| }); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Write amplification: every shard written on every commit
Medium Severity
PositionDb::commit calls commit_single_shard for all 16 shards on every chunk commit, even when batch_opt is None. Each call writes a PositionShardCommitProgress marker via unwrap_or_default(). This means 16 RocksDB writes per chunk purely for progress markers on shards with no actual position data, causing unnecessary write amplification on every block.
Reviewed by Cursor Bugbot for commit 7f3172c. Configure here.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
✅ Forge suite
|
✅ Forge suite
|
✅ Forge suite
|
| // The native-position DB isn't open here; it attaches later | ||
| // via `AptosDB::init_native_position`, which re-binds the | ||
| // pruner via `LedgerPrunerManager::attach_native_pruners`. |
There was a problem hiding this comment.
Why isn't it open here? The comment should say the reason instead of the fact.


Adds the durable-commit applier, the two-stage JMT commit pipeline, and the AptosDB integration for native positions. Builds on the durable storage tier in PR #19883 and the shared primitives in PRs #19894 + #19908.
The in-memory scanner mirror (the
NativeStateStoreDashMap and its readers) is layered on top in a later commit; the durable + JMT side here stands on its own.Commit applier
NativeStateCommitter::apply: per-shardSchemaBatchfan-out againstposition_dbfor every Position write, returningNativeMerkleLeafUpdates(MerkleLeafUpdateper write) for the JMT pipeline. Stale-index entries for prior versions are written into the same batch so the pruner can drop them later.Commit pipeline
PositionBufferedState— alias of the sharedBufferedState<L, S, P, X>generic with position's pipeline parameters and a no-opPositionExtras. Constructed viaspawn_commit_pipeline.PositionSnapshotCommitterdriver (merklize_position): pullsPositionSnapshotToCommitpayloads, runs the snapshot throughShardedJmtMerkleDb::merklize_snapshot, forwards the resultingPositionMerkleCommitdownstream.PositionMerkleBatchCommitter: pullsPositionMerkleCommits and persists per-shard JMT batches + top-levels batch toposition_merkle_db.State-shape primitives
Adds
storage/storage-interface/src/state_store/sharded_jmt_state.rswith the JMT-sharded pipeline primitives that aren't main-state shared:LeafSlot<V>+impl LeafEntry for LeafSlot<V>,ShardedJmtState<Slot>(16MapLayerchains +extend/make_delta/is_descendant_of), the inherent impl onStateAndSummary<ShardedJmtState<Slot: LeafEntry>>(new_empty,extend,make_delta, etc.), andpre_shard_jmt_updates.Also adds two
StateSummaryconstructors that only JMT-sharded pipelines without a hot companion need:new_global_only(version, smt)andnew_empty_global_only().In the
aptos-dbcrate:PositionSlot— type alias ofLeafSlot<()>(value not carried in-slot; lives inposition_dbdurably).PositionStateStore— owner / coordinator, type alias of the sharedPipelineStateStore<L, BS>(also added in this commit, incrate::common). Wraps the sharedcurrent_statemutex (readable by outside consumers) and thePositionBufferedStatemutex (commit-path serialization).PositionDbgains thecommit/commit_single_shard/write_progress/find_prior_versionmethods that the committer uses.AptosDB wiring
AptosDBgains optional handles forPositionDb+PositionMerkleDb+PositionStateStore. Accessed vianative_position_handles/native_state_committer.init_native_position: opens 16 sharded position DBs + unsharded merkle DB with production CF tuning. Spawns the async commit pipeline seeded with the empty-tree placeholder root. Idempotent (rejects second call). Logs the open.commit_native_position(inaptosdb_writer.rs): rayon-spawned alongside main-state commit; drainsoutput.write_set().native_position_iter()(the WriteSet sibling bucket from [types]) throughNativeStateCommitter, feeding the resultingMerkleLeafUpdates into the position JMT pipeline.Note
High Risk
Introduces a new ledger commit sub-path and dual-DB crash/truncation/replay logic for trading positions; mitigated while
ENABLE_TRADING_NATIVEremains false.Overview
Adds native trading position persistence and commit integration in
aptos-db, wired like main state but on a separateposition_db/position_merkle_dbpair andWriteSet::native_position_iter().Durable KV path:
NativeStateCommitter::applybatches per-shardPositionValuewrites and stale-index rows (with in-chunk prior-version chaining), thenPositionDb::commitonce per ledger chunk.PositionDbgainsfind_prior_version, progress metadata, and truncation helpers aligned with chainOverallCommitProgress.In-memory + JMT path: New
ShardedJmtState/LeafSlottypes andStateSummary::new_global_onlysupport a position-specificBufferedStatepipeline (merklize_position→ asyncPositionMerkleBatchCommitter).PipelineStateStorecoordinates sharedcurrent_statevs commit-pathbuffered_state.AptosDB: Optional
PositionBundleon open whenENABLE_TRADING_NATIVEis true (currentlyfalse).init_native_positionopens DBs, truncates ahead-of-chain data on restart, replays gap write sets, and seeds the pipeline.commit_native_positionruns in parallel during pre-commit: applies native writes, extends SMT at checkpoints, commits KV, updates buffered state. Checkpoints now include position DBs.Unit tests cover stale-index semantics, tombstones, truncation, and in-chunk overwrite chaining.
Reviewed by Cursor Bugbot for commit 7f3172c. Bugbot is set up for automated code reviews on this repo. Configure here.