db_stress: constrain batched prefix scans#14512
db_stress: constrain batched prefix scans#14512xingbowang wants to merge 6 commits intofacebook:mainfrom
Conversation
Batched snapshot mode does not verify the full DB state against the expected-state oracle. Instead, it relies on local invariants over the 10-key family written atomically by BatchedOpsStressTest::TestPut(). For a base key K and value body V, TestPut() writes: "0" + K -> V + "0" ... "9" + K -> V + "9" in one write batch. TestPrefixScan() then picks one base key, derives 10 seek prefixes 0+P .. 9+P where P is the first FLAGS_prefix_size - 1 bytes of K, and opens 10 iterators on the same snapshot. The verifier advances those iterators in lockstep and checks that: * each iterator stays in its own seek prefix; * no iterator exhausts its prefix before the others; * at position n, all values match after stripping the trailing digit; * the trailing digit still matches the corresponding prefix stream; and * value() and columns() remain mutually consistent for wide-column / entity reads. That lockstep oracle assumes every iterator is explicitly bounded to the seek prefix before we assert same-length, same-index progress across all 10 streams. Before this change, the batched test only installed an iterate_upper_bound to the next prefix half of the time. In the other half, Seek(prefix) could legitimately continue into the next prefix, while the verifier still assumed the iterator would stop at the prefix boundary. That made the verifier depend on behavior it had not actually requested from RocksDB. Set ReadOptions::prefix_same_as_start = true for every iterator used by this batched prefix verifier. This matches the semantics the verifier needs: RocksDB records the seek prefix and invalidates the iterator once Next() / Prev() leave that prefix, and the memtable path also switches to dynamic prefix iteration under the same condition. Relevant option interactions for this verifier: * test_batches_snapshots requires prefix_size > 0. * db_stress installs NewFixedPrefixTransform(prefix_size) whenever prefix_size >= 0, so the semantic precondition here is the configured prefix_extractor, not specifically memtablerep=prefix_hash. * prefixpercent only controls how often this verifier runs. * auto_refresh_iterator_with_snapshot is irrelevant here because the batched verifier pins one explicit snapshot for all 10 iterators. * When a next-prefix upper bound is installed, the test still exercises iterate_upper_bound and SQFC range-query filtering. * allow_unprepared_value is still handled via PrepareValue(). * use_put_entity_one_in, use_attribute_group, use_timed_put_one_in, and use_merge only change how the values/entities are encoded; the verifier still checks trailing-digit agreement and value()/columns() consistency. * memtablerep=prefix_hash, memtable_prefix_bloom_size_ratio, memtable_whole_key_filtering, and enable_memtable_insert_with_hint_prefix_extractor affect prefix-aware filtering/performance paths but do not change the verifier's lockstep invariant. * user_timestamp_size is out of scope because batched snapshot mode does not support timestamps. This intentionally makes the batched prefix-scan oracle validate explicitly prefix-bounded iteration every time, while the non-batched stress path continues to provide separate randomized coverage of iterate_upper_bound-only behavior.
|
| Check | Count |
|---|---|
performance-unnecessary-copy-initialization |
2 |
| Total | 2 |
Details
db/blob/db_blob_basic_test.cc (2 warning(s))
db/blob/db_blob_basic_test.cc:2612:17: warning: local copy 'r1_end' of the variable 'mid' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization]
db/blob/db_blob_basic_test.cc:2613:17: warning: local copy 'r2_start' of the variable 'mid' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization]
✅ Claude Code ReviewAuto-triggered after CI passed — reviewing commit 5514e9d I now have a thorough understanding of the change. Let me write the review. SummaryCorrect, minimal fix for a real assertion failure in Issues FoundNo critical or significant issues. 🟢 Nitpick: The while-loop at line 606 already manually checks 🟢 Nitpick: The comment (lines 588-590 in the post-change file) is good and explains the "why." No issues there. Cross-Component Analysis
Positive Observations
ℹ️ About this responseGenerated by Claude Code. Limitations:
Commands:
|
|
@xingbowang has imported this pull request. If you are a Meta employee, you can view this in D98302018. |
|
@xingbowang has imported this pull request. If you are a Meta employee, you can view this in D98302018. |
Summary
BatchedOpsStressTest::TestPrefixScanopens 10 iterators with different prefixes and compares their results in lockstep. About half of the iterators randomly receive aniterate_upper_bound, while the other half had no range constraint at all. Withoutprefix_same_as_start, unconstrained iterators could return keys beyond their seek prefix, producing more entries than bounded iterators and triggering assertion failures in the verification loop.Fix
Set
prefix_same_as_start = trueon all 10ReadOptionsso every iterator stops at the seek prefix boundary, making the lockstep comparison valid regardless of whether an upper bound is also set.