Skip to content

测试意向锁 - #4

Merged
yy782 merged 7 commits into
mainfrom
测试意向锁
Jul 29, 2026

Hidden character warning

The head ref may contain hidden characters: "\u6d4b\u8bd5\u610f\u5411\u9501"
Merged

测试意向锁#4
yy782 merged 7 commits into
mainfrom
测试意向锁

Conversation

@yy782

@yy782 yy782 commented Jul 27, 2026

Copy link
Copy Markdown
Owner

No description provided.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Fix IntentLock rollback leak and add multi-fingerprint lock tests

🐞 Bug fix 🧪 Tests ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Fix DbSlice intent-lock rollback to avoid leaking lock counts on partial failure.
• Add comprehensive IntentLock unit tests for multi-fp conflicts and all-or-nothing semantics.
• Simplify test build by removing embedded Redis dict sources and unifying tests under gtest.
Diagram

graph TD
  A["unit_tests (gtest)"] --> B["intent_lock_test.cpp"] --> C["DbSlice::Acquire"] --> D["IntentLock table"]
  B --> E["KeyLockArgs (fps)"] --> C
  C --> F{Acquire fails?} --> G["Rollback: Release [0..i]"] --> D
  H["CMake test wiring"] --> A
  subgraph Legend
    direction LR
    _t["Test"] ~~~ _m["Module"] ~~~ _d{"Decision"}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. RAII rollback guard for partial Acquire
  • ➕ Eliminates manual index bookkeeping and off-by-one risks
  • ➕ Ensures rollback happens even if future code adds early returns/exceptions
  • ➕ Centralizes acquire/release pairing for multi-fp operations
  • ➖ Slightly more abstraction and code to maintain
  • ➖ May require careful integration if Acquire is performance-sensitive
2. Change IntentLock::Acquire to not increment before success
  • ➕ Avoids needing to release the failing fingerprint at all
  • ➕ Simplifies rollback logic to 'release only successfully acquired'
  • ➖ More invasive semantic change; affects all call sites and assumptions
  • ➖ Harder to validate without broader concurrency/behavior testing

Recommendation: Current fix is appropriate and low-impact for correctness: it compensates for IntentLock::Acquire's pre-increment behavior and matches the intended all-or-nothing semantics. If this area evolves further, consider introducing an RAII rollback guard to make partial-acquire failure paths structurally safe.

Files changed (8) +271 / -127

Bug fix (1) +4 / -2
db_slice.cppFix intent-lock rollback to release the failing fingerprint too +4/-2

Fix intent-lock rollback to release the failing fingerprint too

• Corrects rollback when multi-fp intent lock acquisition fails by releasing the full range [0..i] inclusive. Prevents leaked lock counts because the underlying acquire path increments the counter before detecting failure.

src/sharding/db_slice.cpp

Refactor (2) +6 / -0
namespaces.cppWhitespace-only formatting change +3/-0

Whitespace-only formatting change

• Adds blank lines with no functional changes. Runtime behavior is unchanged.

src/sharding/namespaces.cpp

namespaces.hppWhitespace-only formatting change +3/-0

Whitespace-only formatting change

• Adds blank lines with no functional changes. Public API remains unchanged.

src/sharding/namespaces.hpp

Tests (4) +261 / -124
CMakeLists.txtRegister intent_lock_test.cpp in unified unit_tests target +1/-0

Register intent_lock_test.cpp in unified unit_tests target

• Adds the new IntentLock test file to the unit_tests executable. This ensures it runs under the standard gtest runner.

test/CMakeLists.txt

db_table_perf.cppConvert perf benchmark into gtest and drop Redis dict comparison +25/-116

Convert perf benchmark into gtest and drop Redis dict comparison

• Refactors the benchmark to run as a gtest TEST case instead of a standalone main. Removes the embedded Redis dict dependency and limits the comparison to DashTable vs std::unordered_map.

test/db_table_perf.cpp

db_table_test.cppIntegrate DbTable tests into unified gtest runner +1/-8

Integrate DbTable tests into unified gtest runner

• Removes the custom main() and namespace wrapper so tests are discovered by the shared unit_tests entry point. Keeps the existing test logic intact.

test/db_table_test.cpp

intent_lock_test.cppAdd multi-fp intent lock correctness test suite +234/-0

Add multi-fp intent lock correctness test suite

• Adds coverage for acquire/release/reacquire, shared/exclusive mutual exclusion, partial-conflict all-or-nothing behavior, and isolation across different fp sets. Specifically validates that failed multi-fp Acquire attempts do not leak locks or inflate counts.

test/intent_lock_test.cpp

Other (1) +0 / -1
CMakeLists.txtStop building embedded Redis test subdirectory +0/-1

Stop building embedded Redis test subdirectory

• Removes the test/redis subdirectory from the BUILD_TESTS build. This aligns with the removal of embedded Redis dict sources from the test suite.

CMakeLists.txt

@qodo-code-review

qodo-code-review Bot commented Jul 27, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Shard destroyed too early 🐞 Bug ☼ Reliability ⭐ New
Description
IntentLockTest::TearDown destroys EngineShard thread-local state while the fixture still owns a live
DbSlice (slice_), so DbSlice/DbTable destructors may later deallocate via an already-freed
EngineShard::memory_resource(). This can cause teardown-time crashes or ASAN/LSAN failures.
Code

test/intent_lock_test.cpp[15]

+  void TearDown() override { EngineShard::DestroyThreadLocal(); }
Evidence
The test fixture destroys the thread-local EngineShard but keeps slice_ alive (not reset). DbSlice
allocates DbTable using owner_->memory_resource() from EngineShard, and EngineShard teardown frees
the underlying heap, so later destruction of DbSlice/DbTable may use an invalid memory_resource.

test/intent_lock_test.cpp[10-16]
test/intent_lock_test.cpp[25-27]
src/sharding/engine_shard.cpp[13-37]
src/sharding/db_slice.cpp[180-184]
src/sharding/db_table.cpp[8-10]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`IntentLockTest::TearDown()` calls `EngineShard::DestroyThreadLocal()` while `slice_` (a `std::unique_ptr<DbSlice>`) is still alive. Because `DbSlice` creates `DbTable` with `owner_->memory_resource()` (owned by `EngineShard`), destroying the shard first makes the allocator/resource lifetime invalid; when the fixture later destroys `slice_`, it may deallocate via a freed memory resource.

### Issue Context
- `EngineShard::DestroyThreadLocal()` destroys the shard object and deletes its mimalloc heap.
- `DbSlice::CreateDb()` constructs `DbTable` with `owner_->memory_resource()`.
- `DbTable`/`DashTable` store that memory_resource and may use it during destruction.

### Fix Focus Areas
- test/intent_lock_test.cpp[10-16]

### Suggested fix
In `TearDown()`, explicitly destroy/reset `slice_` before destroying the thread-local shard:
```cpp
void TearDown() override {
 slice_.reset();
 EngineShard::DestroyThreadLocal();
}
```
(Optionally also reset/clean any other objects that might indirectly reference `EngineShard::tlocal()` before calling `DestroyThreadLocal()`.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Thread-local shard leak ✓ Resolved 🐞 Bug ☼ Reliability
Description
IntentLockTest::SetUp calls EngineShard::InitThreadLocal() for every test but TearDown never calls
EngineShard::DestroyThreadLocal(), leaking the EngineShard instance and its mi_heap allocations per
test. This can cause unit test processes (especially ASAN/LSAN runs) to fail due to accumulated
leaks.
Code

test/intent_lock_test.cpp[R9-15]

+  void SetUp() override {
+    EngineShard::InitThreadLocal(&loop_);
+    slice_ = std::make_unique<DbSlice>(0, false, EngineShard::tlocal());
+  }
+
+  void TearDown() override { slice_.reset(); }
+
Evidence
The fixture initializes thread-local EngineShard but never calls the provided DestroyThreadLocal
cleanup; InitThreadLocal allocates heap/shard and overwrites the thread_local pointer, so repeated
tests leak memory unless DestroyThreadLocal is called.

test/intent_lock_test.cpp[9-15]
src/sharding/engine_shard.hpp[26-33]
src/sharding/engine_shard.cpp[13-37]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`IntentLockTest` initializes EngineShard thread-local state in `SetUp()` but never tears it down, causing per-test leaks.

### Issue Context
`EngineShard::InitThreadLocal()` allocates a new mi_heap and placement-news an `EngineShard` into it. The only cleanup path is `EngineShard::DestroyThreadLocal()`.

### Fix Focus Areas
- test/intent_lock_test.cpp[9-15]
- src/sharding/engine_shard.cpp[13-37]

### Suggested fix
- In `IntentLockTest::TearDown()`, after `slice_.reset()`, call `EngineShard::DestroyThreadLocal()`.
- Optionally, to avoid repeated init/destroy costs and reduce noise, move init/cleanup to `SetUpTestSuite()` / `TearDownTestSuite()` (or guard `InitThreadLocal()` with `if (EngineShard::tlocal() == nullptr)`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Rollback tests miss mid-failure ✓ Resolved 🐞 Bug ≡ Correctness
Description
The new PartialLockConflict cases intend to validate DbSlice::Acquire “all-or-nothing” rollback, but
all conflicting B_args lists start with a conflicting fingerprint so acquisition fails at index 0
and never exercises rollback of previously acquired locks. This means the tests would not catch
regressions for failures occurring at i>0 (the scenario the DbSlice rollback fix targets).
Code

test/intent_lock_test.cpp[R95-123]

+  // --- 场景1: A:{a,b}排他, B:{b,c}排他 → B失败, c 不能被泄漏 ---
+  {
+    // A 的 key 集合: {1, 2, 3, 4}   取了 a,b
+    // B 的 key 集合: {3, 4, 5, 6} 和 A 有重叠 3,4
+    KeyLockArgs A_args = {0, {1, 2, 3, 4}};
+    KeyLockArgs B_args = {0, {3, 4, 5, 6}};
+
+    EXPECT_TRUE(slice_->Acquire(IntentLock::EXCLUSIVE, A_args));
+    EXPECT_FALSE(slice_->Acquire(IntentLock::EXCLUSIVE, B_args));
+
+    // B 失败后, fp=5,6 不能残留锁: A 可以直接获取它们
+    KeyLockArgs test_5 = {0, {5}};
+    KeyLockArgs test_6 = {0, {6}};
+    EXPECT_TRUE(slice_->Acquire(IntentLock::EXCLUSIVE, test_5));
+    EXPECT_TRUE(slice_->Acquire(IntentLock::EXCLUSIVE, test_6));
+    slice_->Release(IntentLock::EXCLUSIVE, test_5);
+    slice_->Release(IntentLock::EXCLUSIVE, test_6);
+
+    slice_->Release(IntentLock::EXCLUSIVE, A_args);
+  }
+
+  // --- 场景2: A:{a,b,c}共享, B:{c,d}排他 → B失败, d 不能被泄漏 ---
+  {
+    KeyLockArgs A_args = {0, {10, 20, 30}};
+    KeyLockArgs B_args = {0, {30, 40}};
+
+    EXPECT_TRUE(slice_->Acquire(IntentLock::SHARED, A_args));
+    EXPECT_FALSE(slice_->Acquire(IntentLock::EXCLUSIVE, B_args));
+
Evidence
DbSlice rollback behavior depends on the failure index i; the current test inputs make contention
happen on the first element, so the code path that rolls back previously acquired elements is never
exercised.

src/sharding/db_slice.cpp[303-323]
test/intent_lock_test.cpp[95-123]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`PartialLockConflict` does not cover the case where some fingerprints are successfully acquired before a later fingerprint fails, so it doesn't validate rollback of earlier-acquired locks.

### Issue Context
`DbSlice::Acquire()` now explicitly rolls back `[0..i]` (including the failed index) because `IntentLock::Acquire()` increments counters before checking contention. To test that rollback works when `i > 0`, the conflicting fp must appear after at least one non-conflicting fp.

### Fix Focus Areas
- test/intent_lock_test.cpp[92-198]
- src/sharding/db_slice.cpp[303-323]

### Suggested fix
Add at least one scenario like:
- A holds EXCLUSIVE on `{3}`
- B tries EXCLUSIVE on `{5, 3, 6}` (so it acquires `5` then fails on `3`)
- Verify `{5}` and `{6}` are acquirable after the failed call (proving no leak), and that A's `{3}` lock is still intact.
Repeat similarly for SHARED/EXCLUSIVE combinations if needed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Perf benchmark not built 🐞 Bug ⚙ Maintainability
Description
db_table_perf.cpp was converted into a gtest TEST, but it is not included in the unit_tests target
sources, so it won’t compile or run in CI. The CMake comment claiming all *_perf.cpp are included is
now misleading.
Code

test/CMakeLists.txt[R3-7]

# 单元测试可执行文件(统一入口,包含所有 *_test.cpp 和 *_perf.cpp)
add_executable(unit_tests
    db_table_test.cpp
+    intent_lock_test.cpp
)
Evidence
The build file explicitly lists test sources and excludes db_table_perf.cpp, while db_table_perf.cpp
now only provides a gtest TEST entrypoint (no standalone main), making it effectively unused unless
added to a target.

test/CMakeLists.txt[3-7]
test/db_table_perf.cpp[205-214]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`db_table_perf.cpp` defines a gtest `TEST(...)` but is not compiled into any shown test target.

### Issue Context
`test/CMakeLists.txt` only lists `db_table_test.cpp` and `intent_lock_test.cpp` for `unit_tests`.

### Fix Focus Areas
- test/CMakeLists.txt[3-7]
- test/db_table_perf.cpp[205-214]

### Suggested fix
Choose one:
1) Add `db_table_perf.cpp` to `unit_tests` sources (if it’s acceptable for CI runtime), or
2) Create a separate `db_table_perf`/`benchmarks` target and keep it out of unit tests, and update the comment in `test/CMakeLists.txt` accordingly.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Previous review results

Review updated until commit 6b16f89

Results up to commit 78a73a5 ⚖️ Balanced


🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. Thread-local shard leak ✓ Resolved 🐞 Bug ☼ Reliability
Description
IntentLockTest::SetUp calls EngineShard::InitThreadLocal() for every test but TearDown never calls
EngineShard::DestroyThreadLocal(), leaking the EngineShard instance and its mi_heap allocations per
test. This can cause unit test processes (especially ASAN/LSAN runs) to fail due to accumulated
leaks.
Code

test/intent_lock_test.cpp[R9-15]

+  void SetUp() override {
+    EngineShard::InitThreadLocal(&loop_);
+    slice_ = std::make_unique<DbSlice>(0, false, EngineShard::tlocal());
+  }
+
+  void TearDown() override { slice_.reset(); }
+
Evidence
The fixture initializes thread-local EngineShard but never calls the provided DestroyThreadLocal
cleanup; InitThreadLocal allocates heap/shard and overwrites the thread_local pointer, so repeated
tests leak memory unless DestroyThreadLocal is called.

test/intent_lock_test.cpp[9-15]
src/sharding/engine_shard.hpp[26-33]
src/sharding/engine_shard.cpp[13-37]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`IntentLockTest` initializes EngineShard thread-local state in `SetUp()` but never tears it down, causing per-test leaks.

### Issue Context
`EngineShard::InitThreadLocal()` allocates a new mi_heap and placement-news an `EngineShard` into it. The only cleanup path is `EngineShard::DestroyThreadLocal()`.

### Fix Focus Areas
- test/intent_lock_test.cpp[9-15]
- src/sharding/engine_shard.cpp[13-37]

### Suggested fix
- In `IntentLockTest::TearDown()`, after `slice_.reset()`, call `EngineShard::DestroyThreadLocal()`.
- Optionally, to avoid repeated init/destroy costs and reduce noise, move init/cleanup to `SetUpTestSuite()` / `TearDownTestSuite()` (or guard `InitThreadLocal()` with `if (EngineShard::tlocal() == nullptr)`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
2. Rollback tests miss mid-failure ✓ Resolved 🐞 Bug ≡ Correctness
Description
The new PartialLockConflict cases intend to validate DbSlice::Acquire “all-or-nothing” rollback, but
all conflicting B_args lists start with a conflicting fingerprint so acquisition fails at index 0
and never exercises rollback of previously acquired locks. This means the tests would not catch
regressions for failures occurring at i>0 (the scenario the DbSlice rollback fix targets).
Code

test/intent_lock_test.cpp[R95-123]

+  // --- 场景1: A:{a,b}排他, B:{b,c}排他 → B失败, c 不能被泄漏 ---
+  {
+    // A 的 key 集合: {1, 2, 3, 4}   取了 a,b
+    // B 的 key 集合: {3, 4, 5, 6} 和 A 有重叠 3,4
+    KeyLockArgs A_args = {0, {1, 2, 3, 4}};
+    KeyLockArgs B_args = {0, {3, 4, 5, 6}};
+
+    EXPECT_TRUE(slice_->Acquire(IntentLock::EXCLUSIVE, A_args));
+    EXPECT_FALSE(slice_->Acquire(IntentLock::EXCLUSIVE, B_args));
+
+    // B 失败后, fp=5,6 不能残留锁: A 可以直接获取它们
+    KeyLockArgs test_5 = {0, {5}};
+    KeyLockArgs test_6 = {0, {6}};
+    EXPECT_TRUE(slice_->Acquire(IntentLock::EXCLUSIVE, test_5));
+    EXPECT_TRUE(slice_->Acquire(IntentLock::EXCLUSIVE, test_6));
+    slice_->Release(IntentLock::EXCLUSIVE, test_5);
+    slice_->Release(IntentLock::EXCLUSIVE, test_6);
+
+    slice_->Release(IntentLock::EXCLUSIVE, A_args);
+  }
+
+  // --- 场景2: A:{a,b,c}共享, B:{c,d}排他 → B失败, d 不能被泄漏 ---
+  {
+    KeyLockArgs A_args = {0, {10, 20, 30}};
+    KeyLockArgs B_args = {0, {30, 40}};
+
+    EXPECT_TRUE(slice_->Acquire(IntentLock::SHARED, A_args));
+    EXPECT_FALSE(slice_->Acquire(IntentLock::EXCLUSIVE, B_args));
+
Evidence
DbSlice rollback behavior depends on the failure index i; the current test inputs make contention
happen on the first element, so the code path that rolls back previously acquired elements is never
exercised.

src/sharding/db_slice.cpp[303-323]
test/intent_lock_test.cpp[95-123]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`PartialLockConflict` does not cover the case where some fingerprints are successfully acquired before a later fingerprint fails, so it doesn't validate rollback of earlier-acquired locks.

### Issue Context
`DbSlice::Acquire()` now explicitly rolls back `[0..i]` (including the failed index) because `IntentLock::Acquire()` increments counters before checking contention. To test that rollback works when `i > 0`, the conflicting fp must appear after at least one non-conflicting fp.

### Fix Focus Areas
- test/intent_lock_test.cpp[92-198]
- src/sharding/db_slice.cpp[303-323]

### Suggested fix
Add at least one scenario like:
- A holds EXCLUSIVE on `{3}`
- B tries EXCLUSIVE on `{5, 3, 6}` (so it acquires `5` then fails on `3`)
- Verify `{5}` and `{6}` are acquirable after the failed call (proving no leak), and that A's `{3}` lock is still intact.
Repeat similarly for SHARED/EXCLUSIVE combinations if needed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational
3. Perf benchmark not built 🐞 Bug ⚙ Maintainability
Description
db_table_perf.cpp was converted into a gtest TEST, but it is not included in the unit_tests target
sources, so it won’t compile or run in CI. The CMake comment claiming all *_perf.cpp are included is
now misleading.
Code

test/CMakeLists.txt[R3-7]

# 单元测试可执行文件(统一入口,包含所有 *_test.cpp 和 *_perf.cpp)
add_executable(unit_tests
    db_table_test.cpp
+    intent_lock_test.cpp
)
Evidence
The build file explicitly lists test sources and excludes db_table_perf.cpp, while db_table_perf.cpp
now only provides a gtest TEST entrypoint (no standalone main), making it effectively unused unless
added to a target.

test/CMakeLists.txt[3-7]
test/db_table_perf.cpp[205-214]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`db_table_perf.cpp` defines a gtest `TEST(...)` but is not compiled into any shown test target.

### Issue Context
`test/CMakeLists.txt` only lists `db_table_test.cpp` and `intent_lock_test.cpp` for `unit_tests`.

### Fix Focus Areas
- test/CMakeLists.txt[3-7]
- test/db_table_perf.cpp[205-214]

### Suggested fix
Choose one:
1) Add `db_table_perf.cpp` to `unit_tests` sources (if it’s acceptable for CI runtime), or
2) Create a separate `db_table_perf`/`benchmarks` target and keep it out of unit tests, and update the comment in `test/CMakeLists.txt` accordingly.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

Comment thread test/intent_lock_test.cpp Outdated
Comment thread test/intent_lock_test.cpp Outdated
Comment thread test/CMakeLists.txt
Comment on lines 3 to 7
# 单元测试可执行文件(统一入口,包含所有 *_test.cpp 和 *_perf.cpp)
add_executable(unit_tests
db_table_test.cpp
intent_lock_test.cpp
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Informational

3. Perf benchmark not built 🐞 Bug ⚙ Maintainability

db_table_perf.cpp was converted into a gtest TEST, but it is not included in the unit_tests target
sources, so it won’t compile or run in CI. The CMake comment claiming all *_perf.cpp are included is
now misleading.
Agent Prompt
### Issue description
`db_table_perf.cpp` defines a gtest `TEST(...)` but is not compiled into any shown test target.

### Issue Context
`test/CMakeLists.txt` only lists `db_table_test.cpp` and `intent_lock_test.cpp` for `unit_tests`.

### Fix Focus Areas
- test/CMakeLists.txt[3-7]
- test/db_table_perf.cpp[205-214]

### Suggested fix
Choose one:
1) Add `db_table_perf.cpp` to `unit_tests` sources (if it’s acceptable for CI runtime), or
2) Create a separate `db_table_perf`/`benchmarks` target and keep it out of unit tests, and update the comment in `test/CMakeLists.txt` accordingly.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@yy782

yy782 commented Jul 27, 2026

Copy link
Copy Markdown
Owner Author

/review

Comment thread test/intent_lock_test.cpp
slice_ = std::make_unique<DbSlice>(0, false, EngineShard::tlocal());
}

void TearDown() override { EngineShard::DestroyThreadLocal(); }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Shard destroyed too early 🐞 Bug ☼ Reliability

IntentLockTest::TearDown destroys EngineShard thread-local state while the fixture still owns a live
DbSlice (slice_), so DbSlice/DbTable destructors may later deallocate via an already-freed
EngineShard::memory_resource(). This can cause teardown-time crashes or ASAN/LSAN failures.
Agent Prompt
### Issue description
`IntentLockTest::TearDown()` calls `EngineShard::DestroyThreadLocal()` while `slice_` (a `std::unique_ptr<DbSlice>`) is still alive. Because `DbSlice` creates `DbTable` with `owner_->memory_resource()` (owned by `EngineShard`), destroying the shard first makes the allocator/resource lifetime invalid; when the fixture later destroys `slice_`, it may deallocate via a freed memory resource.

### Issue Context
- `EngineShard::DestroyThreadLocal()` destroys the shard object and deletes its mimalloc heap.
- `DbSlice::CreateDb()` constructs `DbTable` with `owner_->memory_resource()`.
- `DbTable`/`DashTable` store that memory_resource and may use it during destruction.

### Fix Focus Areas
- test/intent_lock_test.cpp[10-16]

### Suggested fix
In `TearDown()`, explicitly destroy/reset `slice_` before destroying the thread-local shard:
```cpp
void TearDown() override {
  slice_.reset();
  EngineShard::DestroyThreadLocal();
}
```
(Optionally also reset/clean any other objects that might indirectly reference `EngineShard::tlocal()` before calling `DestroyThreadLocal()`.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 9f4a4bb

@yy782
yy782 merged commit 8ad7e66 into main Jul 29, 2026
5 checks passed
@yy782
yy782 deleted the 测试意向锁 branch July 29, 2026 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant