Skip to content

Commit f050924

Browse files
disagg: Fix unexpected object storage usage caused by pre-lock residue (#10760) (#10767)
close #10763 disagg: eliminate pre-lock key residue that lead to unexpected OSS usage Signed-off-by: ti-chi-bot <ti-community-prow-bot@tidb.io> Co-authored-by: JaySon <tshent@qq.com>
1 parent 9e1f968 commit f050924

13 files changed

+746
-55
lines changed

AGENTS.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# TiFlash Agent Guide
2+
3+
This document provides essential information for agentic coding tools operating in the TiFlash repository.
4+
It focuses on the fastest safe path to build, test, and navigate the codebase.
5+
6+
## 🚀 Quick Start
7+
- **Configure (preset):** `cmake --preset dev`
8+
- **Build:**
9+
* tiflash binary: `cmake --build --preset dev`
10+
* unit test binary: `cmake --build --preset unit-tests`
11+
- **Run one test:** `cmake-build-debug/dbms/gtests_dbms --gtest_filter=TestName.*`
12+
13+
## 🛠 Build & Development
14+
15+
TiFlash uses CMake with presets for configuration and building.
16+
17+
### Build Presets
18+
Common presets defined in `CMakePresets.json`:
19+
- `dev`: DEBUG build with tests enabled. (Recommended for development)
20+
- `release`: RELWITHDEBINFO build without tests.
21+
- `asan`: AddressSanitizer build.
22+
- `tsan`: ThreadSanitizer build.
23+
- `benchmarks`: RELEASE build with benchmarks.
24+
25+
### Dependencies & Versions
26+
- **CMake/Ninja/Clang/LLVM/Python/Rust**: Use versions supported by your platform toolchain.
27+
- **Linux vs macOS**: Toolchains live under `release-linux-llvm/` and `release-darwin/` respectively.
28+
- **Submodules/third-party**: Ensure any required submodules are initialized before building.
29+
30+
### Common Commands
31+
- **Configure & Build (Dev):** `cmake --workflow --preset dev`
32+
- **Preset-only (recommended):**
33+
- Configure: `cmake --preset dev`
34+
- Build: `cmake --build --preset dev`
35+
- **Manual Build:**
36+
```bash
37+
mkdir cmake-build-debug && cd cmake-build-debug
38+
cmake .. -GNinja -DCMAKE_BUILD_TYPE=DEBUG -DENABLE_TESTS=ON
39+
ninja tiflash
40+
```
41+
- **Linting & Formatting:**
42+
- Format diff: `python3 format-diff.py --diff_from $(git merge-base upstream/master HEAD)`
43+
(Use `origin/master` or another base if `upstream` is not configured.)
44+
- Clang-Tidy: `python3 release-linux-llvm/scripts/run-clang-tidy.py -p cmake-build-debug`
45+
46+
## 🧪 Testing
47+
48+
### Unit Tests (Google Test)
49+
Build targets: `gtests_dbms`, `gtests_libdaemon`, `gtests_libcommon`.
50+
51+
- **Run all:** `cmake-build-debug/dbms/gtests_dbms`
52+
- **Run single test:** `cmake-build-debug/dbms/gtests_dbms --gtest_filter=TestName.*`
53+
- **List tests:** `cmake-build-debug/dbms/gtests_dbms --gtest_list_tests`
54+
- **Parallel runner:**
55+
```bash
56+
python3 tests/gtest_10x.py cmake-build-debug/dbms/gtests_dbms
57+
```
58+
- **Other targets:**
59+
- `cmake-build-debug/dbms/gtests_libdaemon`
60+
- `cmake-build-debug/dbms/gtests_libcommon`
61+
62+
### Integration Tests
63+
See `tests/AGENTS.md` for prerequisites and usage.
64+
65+
### Sanitizers
66+
When running with ASAN/TSAN, use suppression files:
67+
```bash
68+
LSAN_OPTIONS="suppressions=tests/sanitize/asan.suppression" ./dbms/gtests_dbms
69+
TSAN_OPTIONS="suppressions=tests/sanitize/tsan.suppression" ./dbms/gtests_dbms
70+
```
71+
72+
## 🎨 Code Style (C++)
73+
74+
TiFlash follows a style based on Google, enforced by `clang-format` 17.0.0+.
75+
76+
### General
77+
- **Naming:**
78+
- Classes/Structs: `PascalCase` (e.g., `StorageDeltaMerge`)
79+
- Methods/Variables: `camelCase` (e.g., `readBlock`, `totalBytes`)
80+
- Files: `PascalCase` matching class name (e.g., `StorageDeltaMerge.cpp`)
81+
- **Namespaces:** Primary code resides in `namespace DB`.
82+
- **Headers:** Use `#pragma once`. Use relative paths from `dbms/src` (e.g., `#include <Core/Types.h>`).
83+
84+
### Types & Error Handling
85+
- **Types:** Use explicit width types from `dbms/src/Core/Types.h`: `UInt8`, `UInt32`, `Int64`, `Float64`, `String`.
86+
- **Smart Pointers:** Prefer `std::shared_ptr` and `std::unique_ptr`. Use `std::make_shared` and `std::make_unique`.
87+
- **Error Handling:**
88+
- Use `DB::Exception`.
89+
- Prefer the fmt-style constructor with error code first: `throw Exception(ErrorCodes::SOME_CODE, "Message with {}", arg);`
90+
- For fixed strings without formatting, `throw Exception("Message", ErrorCodes::SOME_CODE);` is still acceptable.
91+
- Error codes are defined in `dbms/src/Common/ErrorCodes.cpp` and `errors.toml`.
92+
- In broad `catch (...)` paths, prefer `tryLogCurrentException(log, "context")` to avoid duplicated exception-formatting code.
93+
- **Logging:** Use macros like `LOG_INFO(log, "message {}", arg)`. `log` is usually a `DB::LoggerPtr`.
94+
- When only log level differs by runtime condition, prefer `LOG_IMPL(log, level, ...)` (with `Poco::Message::Priority`) instead of duplicated `if/else` log blocks.
95+
96+
### Modern C++ Practices
97+
- Prefer `auto` for complex iterators/templates.
98+
- Use `std::string_view` for read-only string parameters.
99+
- Use `fmt::format` for string construction.
100+
- Prefer `FmtBuffer` for complex string building in performance-critical paths.
101+
102+
## 🦀 Rust Code
103+
Rust is used in:
104+
- `contrib/tiflash-proxy`: The proxy layer between TiFlash and TiKV.
105+
- `contrib/tiflash-proxy-next-gen`: Disaggregated architecture components.
106+
107+
Follow standard Rust idioms and `cargo fmt`. Use `cargo clippy` for linting.
108+
109+
## 📚 Module-Specific Guides
110+
For more detailed information on specific subsystems, refer to:
111+
- **Storage Engine**: `dbms/src/Storages/AGENTS.md` (DeltaMerge, KVStore, PageStorage)
112+
- **Computation Engine**: `dbms/src/Flash/AGENTS.md` (Planner, MPP, Pipeline)
113+
- **TiDB Integration**: `dbms/src/TiDB/AGENTS.md` (Schema Sync, Decoding, Collation)
114+
- **Testing Utilities**: `dbms/src/TestUtils/AGENTS.md` (Base classes, Mocking, Data generation)
115+
116+
## 📂 Directory Structure
117+
- `dbms/src`: Main TiFlash C++ source code.
118+
- `libs/`: Shared libraries used by TiFlash.
119+
- `tests/`: Integration and unit test utilities.
120+
- `docs/`: Design and development documentation.
121+
- `release-linux-llvm/`: Build scripts and environment configurations for Linux.
122+
123+
## 💡 Debugging Tips
124+
- **LLDB:** Use to debug crashes or hangs.
125+
- **Coredumps:** Ensure coredumps are enabled in your environment.
126+
- **Failpoints:** TiFlash uses failpoints and syncpoints for testing error paths.
127+
- Search for `FAIL_POINT_TRIGGER_EXCEPTION` or `FAIL_POINT_PAUSE` for failpoints in the code.
128+
- Search for `SyncPointCtl` or `SYNC_FOR` for syncpoints in the code.
129+
- **Build artifacts:** If `compile_commands.json` is missing, ensure you configured with a preset.
130+
131+
## 📖 References
132+
- `docs/DEVELOPMENT.md`: General engineering practices.
133+
- `docs/design/`: Design documents for major features.
134+
- [TiDB Developer Guide](https://pingcap.github.io/tidb-dev-guide/): General TiDB ecosystem information.

dbms/src/Common/TiFlashMetrics.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,15 @@ static_assert(RAFT_REGION_BIG_WRITE_THRES * 4 < RAFT_REGION_BIG_WRITE_MAX, "Inva
845845
F(type_to_finished, {"type", "to_finished"}), \
846846
F(type_to_error, {"type", "to_error"}), \
847847
F(type_to_cancelled, {"type", "to_cancelled"})) \
848+
M(tiflash_storage_s3_lock_mgr_status, "S3 Lock Manager", Gauge, F(type_prelock_keys, {{"type", "prelock_keys"}})) \
849+
M(tiflash_storage_s3_lock_mgr_counter, \
850+
"S3 Lock Manager Counter", \
851+
Counter, \
852+
F(type_create_lock_local, {{"type", "create_lock_local"}}), \
853+
F(type_create_lock_ingest, {{"type", "create_lock_ingest"}}), \
854+
F(type_clean_lock, {{"type", "clean_lock"}}), \
855+
F(type_clean_lock_erase_hit, {{"type", "clean_lock_erase_hit"}}), \
856+
F(type_clean_lock_erase_miss, {{"type", "clean_lock_erase_miss"}})) \
848857
M(tiflash_storage_s3_gc_status, \
849858
"S3 GC status", \
850859
Gauge, \

dbms/src/Storages/DeltaMerge/DeltaMergeStore_InternalSegment.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,9 +1283,9 @@ SegmentPtr DeltaMergeStore::segmentMergeDelta(
12831283

12841284
if (!isSegmentValid(lock, segment))
12851285
{
1286-
LOG_DEBUG(
1286+
LOG_INFO(
12871287
log,
1288-
"MergeDelta - Give up segmentMergeDelta because segment not valid, segment={}",
1288+
"MergeDelta - Give up segmentMergeDelta because segment not valid, reason=concurrent_update segment={}",
12891289
segment->simpleInfo());
12901290
wbs.setRollback();
12911291
return {};

dbms/src/Storages/Page/V3/PageDirectory.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <shared_mutex>
3939
#include <type_traits>
4040
#include <utility>
41+
#include <vector>
4142

4243

4344
#ifdef FIU_ENABLE
@@ -1612,6 +1613,13 @@ std::unordered_set<String> PageDirectory<Trait>::apply(PageEntriesEdit && edit,
16121613
CurrentMetrics::Increment pending_writer_size{CurrentMetrics::PSPendingWriterNum};
16131614
Writer w;
16141615
w.edit = &edit;
1616+
// Capture this writer's checkpoint data_file_ids before write-group merge.
1617+
// Followers' edit objects are cleared by the owner during merge.
1618+
for (const auto & r : edit.getRecords())
1619+
{
1620+
if (r.entry.checkpoint_info.has_value())
1621+
w.applied_data_files.emplace(*r.entry.checkpoint_info.data_location.data_file_id);
1622+
}
16151623

16161624
Stopwatch watch;
16171625
std::unique_lock apply_lock(apply_mutex);
@@ -1639,9 +1647,9 @@ std::unordered_set<String> PageDirectory<Trait>::apply(PageEntriesEdit && edit,
16391647
throw Exception(ErrorCodes::LOGICAL_ERROR, "Unknown exception");
16401648
}
16411649
}
1642-
// the `applied_data_files` will be returned by the write
1643-
// group owner, others just return an empty set.
1644-
return {};
1650+
// Return per-writer ids instead of merged-group ids, so upper-layer
1651+
// lock cleanup can always clean locks created by this writer.
1652+
return std::move(w.applied_data_files);
16451653
}
16461654

16471655
/// This thread now is the write group owner, build the group. It will merge the
@@ -1703,7 +1711,6 @@ std::unordered_set<String> PageDirectory<Trait>::apply(PageEntriesEdit && edit,
17031711
});
17041712

17051713
SYNC_FOR("before_PageDirectory::apply_to_memory");
1706-
std::unordered_set<String> applied_data_files;
17071714
{
17081715
std::unique_lock table_lock(table_rw_mutex);
17091716

@@ -1775,12 +1782,6 @@ std::unordered_set<String> PageDirectory<Trait>::apply(PageEntriesEdit && edit,
17751782
"should not handle edit with invalid type, type={}",
17761783
magic_enum::enum_name(r.type));
17771784
}
1778-
1779-
// collect the applied remote data_file_ids
1780-
if (r.entry.checkpoint_info.has_value())
1781-
{
1782-
applied_data_files.emplace(*r.entry.checkpoint_info.data_location.data_file_id);
1783-
}
17841785
}
17851786
catch (DB::Exception & e)
17861787
{
@@ -1800,7 +1801,9 @@ std::unordered_set<String> PageDirectory<Trait>::apply(PageEntriesEdit && edit,
18001801
}
18011802

18021803
success = true;
1803-
return applied_data_files;
1804+
// Even for write-group owner, return only this writer's pre-captured ids.
1805+
// Other writers return their own ids in the `w.done` branch above.
1806+
return std::move(w.applied_data_files);
18041807
}
18051808

18061809
template <typename Trait>

dbms/src/Storages/Page/V3/PageDirectory.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,9 @@ class PageDirectory
628628
struct Writer
629629
{
630630
PageEntriesEdit * edit;
631+
// Keep per-writer checkpoint lock keys before write-group merge so
632+
// followers can still return their own applied ids for lock cleanup.
633+
std::unordered_set<String> applied_data_files;
631634
bool done = false; // The work has been performed by other thread
632635
bool success = false; // The work complete successfully
633636
std::unique_ptr<DB::Exception> exception;

0 commit comments

Comments
 (0)