Skip to content

Fix range lock manager assertion crash on reverse-comparator CF point locks#14880

Closed
jaykorean wants to merge 1 commit into
facebook:mainfrom
jaykorean:export-D109591908
Closed

Fix range lock manager assertion crash on reverse-comparator CF point locks#14880
jaykorean wants to merge 1 commit into
facebook:mainfrom
jaykorean:export-D109591908

Conversation

@jaykorean

@jaykorean jaykorean commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary:
The RocksDB 11.5.0 reverse-comparator range-lock fix (#14831) made RangeTreeLockManager::CompareDbtEndpoints reverse-aware by wrapping the endpoint-suffix tie-break results in an is_reverse flip. The length-disparity (different user key) branches need that flip, but the equal-length / equal-user-key branch was flipped too, and that is incorrect.

Range-lock endpoints are encoded as [suffix_byte][user_key] where the suffix is SUFFIX_INFIMUM (0x0) or SUFFIX_SUPREMUM (0x1). When two endpoints share the same user key and differ only in the suffix byte, the suffix is a positional boundary marker for that key, not key content, so the infimum endpoint must sort before the supremum endpoint in any total order, regardless of the column family sort direction. Flipping it for a reverse comparator makes m_cmp(infimum(K), supremum(K)) > 0.

MyRocks issues an equality lock (e.g. UPDATE t1 SET a=123 WHERE a=35) as the range [infimum(K), supremum(K)] over the same user key K. On a reverse (rev:) column family — which uses the stock ReverseBytewiseComparator(), so is_reverse is true — the flipped comparator reports left > right, tripping paranoid_invariant(m_cmp(left_key, right_key) <= 0) in toku::locktree::try_acquire_lock and aborting the server with SIGABRT. This broke many MyRocks ---range_locking MTR tests (partial_index*, bypass_select_range_sk*, alter_table_online_debug, allow_no_primary_key_with_sk) after RocksDB was bumped to 11.5.0.

Fix: in the equal-length / equal-user-key branch of CompareDbtEndpoints, compare the suffix bytes without the is_reverse flip so infimum always precedes supremum. The length-disparity branches keep the reverse-aware flip (still covered by RangeLockWithReverseComparator).

Differential Revision: D109591908

… locks

Summary:
The RocksDB 11.5.0 reverse-comparator range-lock fix (the HISTORY.md entry "Fixed a bug where the range lock manager would crash with an assertion failure when using a reverse comparator column family") made `RangeTreeLockManager::CompareDbtEndpoints` reverse-aware by wrapping the endpoint-suffix tie-break results in an `is_reverse` flip. The length-disparity (different user key) branches need that flip, but the equal-length / equal-user-key branch was flipped too, and that is incorrect.

Range-lock endpoints are encoded as `[suffix_byte][user_key]` where the suffix is `SUFFIX_INFIMUM` (0x0) or `SUFFIX_SUPREMUM` (0x1). When two endpoints share the same user key and differ only in the suffix byte, the suffix is a positional boundary marker for that key, not key content, so the infimum endpoint must sort before the supremum endpoint in any total order, regardless of the column family sort direction. Flipping it for a reverse comparator makes `m_cmp(infimum(K), supremum(K)) > 0`.

MyRocks issues an equality lock (e.g. `UPDATE t1 SET a=123 WHERE a=35`) as the range `[infimum(K), supremum(K)]` over the same user key K. On a reverse (`rev:`) column family — which uses the stock `ReverseBytewiseComparator()`, so `is_reverse` is true — the flipped comparator reports `left > right`, tripping `paranoid_invariant(m_cmp(left_key, right_key) <= 0)` in `toku::locktree::try_acquire_lock` and aborting the server with SIGABRT. This broke many MyRocks `---range_locking` MTR tests (partial_index*, bypass_select_range_sk*, alter_table_online_debug, allow_no_primary_key_with_sk) after RocksDB was bumped to 11.5.0 in D108936924.

Fix: in the equal-length / equal-user-key branch of `CompareDbtEndpoints`, compare the suffix bytes without the `is_reverse` flip so infimum always precedes supremum. The length-disparity branches keep the reverse-aware flip (still covered by `RangeLockWithReverseComparator`).

Note: this lands in `internal_repo_rocksdb/repo`, the RocksDB development tree; it reaches `fbcode/rocksdb/src` (what MyRocks/ZippyDB link) through the RocksDB release sync. Tracked in T276980728.

Differential Revision: D109591908
@meta-cla meta-cla Bot added the CLA Signed label Jun 24, 2026
@meta-codesync

meta-codesync Bot commented Jun 24, 2026

Copy link
Copy Markdown

@jaykorean has exported this pull request. If you are a Meta employee, you can view the originating Diff in D109591908.

@github-actions

Copy link
Copy Markdown

✅ clang-tidy: No findings on changed lines

Completed in 45.6s.

@github-actions

Copy link
Copy Markdown

🟡 Codex Code Review

Auto-triggered after CI passed — reviewing commit 5cdb2bb


Codex review failed before producing findings.

WARNING: proceeding, even though we could not create PATH aliases: Refusing to create helper binaries under temporary dir "/tmp" (codex_home: AbsolutePathBuf("/tmp/codex-home"))
error: the argument '--base <BRANCH>' cannot be used with '[PROMPT]'

Usage: codex exec review --commit <SHA> --base <BRANCH> --title <TITLE> --model <MODEL> --config <key=value> --dangerously-bypass-approvals-and-sandbox --output-last-message <FILE> [PROMPT]

For more information, try '--help'.

ℹ️ About this response

Generated by Codex CLI.
Review methodology: claude_md/code_review.md

Limitations:

  • Codex may miss context from files not in the diff
  • Large PRs may be truncated
  • Always apply human judgment to AI suggestions

Commands:

  • /codex-review [context] — Request a code review
  • /codex-query <question> — Ask about the PR or codebase
@github-actions

Copy link
Copy Markdown

✅ Claude Code Review

Auto-triggered after CI passed — reviewing commit 5cdb2bb


Summary

This is a well-targeted, correct bug fix for a regression introduced by the 11.5.0 reverse-comparator range-lock fix. The change correctly removes the is_reverse flip from the equal-user-key / suffix-only branch of CompareDbtEndpoints, preserving the locktree's left <= right invariant for point range locks on reverse-comparator column families. The regression test is appropriate and follows existing patterns.

High-severity findings (0):
No high-severity findings.

Full review (click to expand)

Findings

🟡 MEDIUM

M1. Custom reverse comparators are not detected by IsReverseComparator() -- range_tree_lock_manager.cc:48
  • Issue: IsReverseComparator() only checks for ReverseBytewiseComparator() and ReverseBytewiseComparatorWithU64Ts() by pointer identity. A user-defined comparator that implements reverse ordering would have is_reverse = false, meaning the length-disparity branches (1 and 2) would produce incorrect results. This is a pre-existing issue, not introduced by this PR.
  • Suggested fix: Out of scope for this PR. Could be addressed by adding a virtual IsReverse() method to Comparator or checking the comparator's Name().
M2. Missing unreleased_history entry
  • Issue: HISTORY.md 11.5.0 already has "Fixed a bug where the range lock manager would crash with an assertion failure when using a reverse comparator column family." This PR fixes a regression in that fix. If this lands after 11.5.0, it should have its own unreleased_history/bug_fixes/ entry.
  • Suggested fix: Add an entry clarifying this fixes point-equality locks specifically (regression from the 11.5.0 fix).

🟢 LOW / NIT

L1. Test could also cover ReverseBytewiseComparatorWithU64Ts -- range_locking_test.cc
  • Issue: Only ReverseBytewiseComparator() is tested. Optional improvement for completeness.
L2. Test could verify conflict detection on reverse CF -- range_locking_test.cc
  • Issue: Test only verifies the lock succeeds (doesn't crash). Could additionally verify a conflicting lock is rejected.

Cross-Component Analysis

The comparator is used by the locktree for try_acquire_lock invariant checks, keyrange::compare (overlap detection), keyrange::extend (escalation merging), and BST operations. All usages rely on a consistent total order, which the fix preserves. The three branches in CompareDbtEndpoints are correctly partitioned: branches 1-2 (different user keys) keep the is_reverse flip for key ordering; branch 3 (same user key, suffix-only) correctly removes the flip since the suffix is a positional marker.

All alternative execution contexts (WritePreparedTxnDB, UDT, lock escalation, ReverseBytewiseComparatorWithU64Ts) were verified safe.

Positive Observations

  • Minimal, surgical fix -- only the exact incorrect branch is changed
  • Thorough commit message explaining the bug, root cause, and impact
  • Good regression test following existing patterns
  • Clear code comments explaining the rationale
  • Slight performance improvement from removing a branch

ℹ️ About this response

Generated by Claude Code.
Review methodology: claude_md/code_review.md

Limitations:

  • Claude may miss context from files not in the diff
  • Large PRs may be truncated
  • Always apply human judgment to AI suggestions

Commands:

  • /claude-review [context] — Request a code review
  • /claude-query <question> — Ask about the PR or codebase
@meta-codesync meta-codesync Bot closed this in b0ecf86 Jun 24, 2026
@meta-codesync meta-codesync Bot added the Merged label Jun 24, 2026
@meta-codesync

meta-codesync Bot commented Jun 24, 2026

Copy link
Copy Markdown

This pull request has been merged in b0ecf86.

@jaykorean jaykorean deleted the export-D109591908 branch June 24, 2026 22:57
jaykorean added a commit that referenced this pull request Jun 24, 2026
… locks (#14880)

Summary:
Pull Request resolved: #14880

The RocksDB 11.5.0 reverse-comparator range-lock fix (the HISTORY.md entry "Fixed a bug where the range lock manager would crash with an assertion failure when using a reverse comparator column family") made `RangeTreeLockManager::CompareDbtEndpoints` reverse-aware by wrapping the endpoint-suffix tie-break results in an `is_reverse` flip. The length-disparity (different user key) branches need that flip, but the equal-length / equal-user-key branch was flipped too, and that is incorrect.

Range-lock endpoints are encoded as `[suffix_byte][user_key]` where the suffix is `SUFFIX_INFIMUM` (0x0) or `SUFFIX_SUPREMUM` (0x1). When two endpoints share the same user key and differ only in the suffix byte, the suffix is a positional boundary marker for that key, not key content, so the infimum endpoint must sort before the supremum endpoint in any total order, regardless of the column family sort direction. Flipping it for a reverse comparator makes `m_cmp(infimum(K), supremum(K)) > 0`.

MyRocks issues an equality lock (e.g. `UPDATE t1 SET a=123 WHERE a=35`) as the range `[infimum(K), supremum(K)]` over the same user key K. On a reverse (`rev:`) column family — which uses the stock `ReverseBytewiseComparator()`, so `is_reverse` is true — the flipped comparator reports `left > right`, tripping `paranoid_invariant(m_cmp(left_key, right_key) <= 0)` in `toku::locktree::try_acquire_lock` and aborting the server with SIGABRT. This broke many MyRocks `---range_locking` MTR tests (partial_index*, bypass_select_range_sk*, alter_table_online_debug, allow_no_primary_key_with_sk) after RocksDB was bumped to 11.5.0 in D108936924.

Fix: in the equal-length / equal-user-key branch of `CompareDbtEndpoints`, compare the suffix bytes without the `is_reverse` flip so infimum always precedes supremum. The length-disparity branches keep the reverse-aware flip (still covered by `RangeLockWithReverseComparator`).

Note: this lands in `internal_repo_rocksdb/repo`, the RocksDB development tree; it reaches `fbcode/rocksdb/src` (what MyRocks/ZippyDB link) through the RocksDB release sync. Tracked in T276980728.

Reviewed By: xingbowang

Differential Revision: D109591908

fbshipit-source-id: 078b16e6e51f4f365b4a8d539ac5b968a7461729
jaykorean added a commit to jaykorean/rocksdb that referenced this pull request Jun 25, 2026
…ok#14887)

Summary:

This reverts two changes to the range-lock endpoint comparator and restores the prior, direction-agnostic behavior:
- facebook#14831 ("Fix range lock manager crash with reverse comparator"), which made RangeTreeLockManager::CompareDbtEndpoints reverse-aware, and
- facebook#14880 (a follow-up that only corrected the equal-length / point-range branch).

Why: facebook#14831 taught the endpoint comparator about reverse-ordered column families by flipping the suffix tie-break based on comparator direction. However, callers that use range locking on a reverse-ordered CF already flip the start/end endpoints themselves before calling lock_range() -- for example, MyRocks does this in ha_rocksdb::set_range_lock() (see its "RangeFlagsShouldBeFlippedForRevCF" comment). The two corrections stack and produce left > right again, which:
(a) trips paranoid_invariant(compare(left, right) <= 0) in toku::locktree::try_acquire_lock() and aborts on equality/point locks, and
(b) for range scans, mis-orders the endpoints and produces an incorrect lock range, leading to silent correctness issues under concurrency.
facebook#14880 only addressed (a) (the equal-length / point-range branch), not (b), so it was an incomplete fix at the wrong layer.

Decision: keep CompareDbtEndpoints direction-agnostic and make it an explicit caller requirement to pass a flipped (swapped start/end, with negated infimum/supremum flags) range for range locking to work on a reverse-ordered column family. A function-level comment documenting this contract is added so reverse-awareness is not reintroduced here.

Removes the RangeLockWithReverseComparator unit test added by facebook#14831 (it asserts the reverted direction-flipped ordering). Keeps a regression test that a point range lock [infimum(K), supremum(K)] works on a reverse-comparator column family.

Differential Revision: D109713989
meta-codesync Bot pushed a commit that referenced this pull request Jun 25, 2026
Summary:
Pull Request resolved: #14887

This reverts two changes to the range-lock endpoint comparator and restores the prior, direction-agnostic behavior:
- #14831 ("Fix range lock manager crash with reverse comparator"), which made RangeTreeLockManager::CompareDbtEndpoints reverse-aware, and
- #14880 (a follow-up that only corrected the equal-length / point-range branch).

Why: #14831 taught the endpoint comparator about reverse-ordered column families by flipping the suffix tie-break based on comparator direction. However, callers that use range locking on a reverse-ordered CF already flip the start/end endpoints themselves before calling lock_range() -- for example, MyRocks does this in ha_rocksdb::set_range_lock() (see its "RangeFlagsShouldBeFlippedForRevCF" comment). The two corrections stack and produce left > right again, which:
(a) trips paranoid_invariant(compare(left, right) <= 0) in toku::locktree::try_acquire_lock() and aborts on equality/point locks, and
(b) for range scans, mis-orders the endpoints and produces an incorrect lock range, leading to silent correctness issues under concurrency.
#14880 only addressed (a) (the equal-length / point-range branch), not (b), so it was an incomplete fix at the wrong layer.

Decision: keep CompareDbtEndpoints direction-agnostic and make it an explicit caller requirement to pass a flipped (swapped start/end, with negated infimum/supremum flags) range for range locking to work on a reverse-ordered column family. A function-level comment documenting this contract is added so reverse-awareness is not reintroduced here.

Removes the RangeLockWithReverseComparator unit test added by #14831 (it asserts the reverted direction-flipped ordering). Keeps a regression test that a point range lock [infimum(K), supremum(K)] works on a reverse-comparator column family.

Reviewed By: xingbowang

Differential Revision: D109713989

fbshipit-source-id: 4ea0999c92645e1adc9cd1114d924cad142f2001
jaykorean added a commit that referenced this pull request Jun 25, 2026
Summary:
Pull Request resolved: #14887

This reverts two changes to the range-lock endpoint comparator and restores the prior, direction-agnostic behavior:
- #14831 ("Fix range lock manager crash with reverse comparator"), which made RangeTreeLockManager::CompareDbtEndpoints reverse-aware, and
- #14880 (a follow-up that only corrected the equal-length / point-range branch).

Why: #14831 taught the endpoint comparator about reverse-ordered column families by flipping the suffix tie-break based on comparator direction. However, callers that use range locking on a reverse-ordered CF already flip the start/end endpoints themselves before calling lock_range() -- for example, MyRocks does this in ha_rocksdb::set_range_lock() (see its "RangeFlagsShouldBeFlippedForRevCF" comment). The two corrections stack and produce left > right again, which:
(a) trips paranoid_invariant(compare(left, right) <= 0) in toku::locktree::try_acquire_lock() and aborts on equality/point locks, and
(b) for range scans, mis-orders the endpoints and produces an incorrect lock range, leading to silent correctness issues under concurrency.
#14880 only addressed (a) (the equal-length / point-range branch), not (b), so it was an incomplete fix at the wrong layer.

Decision: keep CompareDbtEndpoints direction-agnostic and make it an explicit caller requirement to pass a flipped (swapped start/end, with negated infimum/supremum flags) range for range locking to work on a reverse-ordered column family. A function-level comment documenting this contract is added so reverse-awareness is not reintroduced here.

Removes the RangeLockWithReverseComparator unit test added by #14831 (it asserts the reverted direction-flipped ordering). Keeps a regression test that a point range lock [infimum(K), supremum(K)] works on a reverse-comparator column family.

Reviewed By: xingbowang

Differential Revision: D109713989

fbshipit-source-id: 4ea0999c92645e1adc9cd1114d924cad142f2001
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment