-
Notifications
You must be signed in to change notification settings - Fork 9
shard flush buffer to multi core #387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| +3 −8 | .github/workflows/ci.yml | |
| +7 −0 | CMakeLists.txt | |
| +5 −158 | scripts/install_dependency_ubuntu2404.sh | |
| +3 −0 | src/storage/object_store.cpp | |
| +4 −0 | tests/common.cpp | |
| +159 −37 | tests/common.h | |
| +2 −2 | tests/test_unit_coverage.sh |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1017,6 +1017,7 @@ class LocalCcShards | |
| range_entry->UpdateRangeEntry(version, std::move(range_slices)); | ||
| } | ||
|
|
||
| mi_heap_set_default(prev_heap); | ||
| if (is_override_thd) | ||
| { | ||
| mi_override_thread(prev_thd); | ||
|
|
@@ -1025,7 +1026,6 @@ class LocalCcShards | |
| { | ||
| mi_restore_default_thread_id(); | ||
| } | ||
| mi_heap_set_default(prev_heap); | ||
|
|
||
| #if defined(WITH_JEMALLOC) | ||
| JemallocArenaSwitcher::SwitchToArena(prev_arena_id); | ||
|
|
@@ -2452,6 +2452,13 @@ class LocalCcShards | |
| uint32_t range_cnt, | ||
| int32_t &out_next_partition_id); | ||
|
|
||
| /** | ||
| * @brief Map a data_sync_worker index to the fixed flush_data_worker index. | ||
| * Used when data_sync_worker count != flush_data_worker count so that each | ||
| * data_sync_worker consistently targets one flush_data_worker. | ||
| */ | ||
| size_t DataSyncWorkerToFlushDataWorker(size_t data_sync_worker_id) const; | ||
|
|
||
|
Comment on lines
+2455
to
+2461
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # Find the .cpp file and locate the implementation of DataSyncWorkerToFlushDataWorker
fd -e cpp -path "*/tx_service/*" local_cc_shards | head -20Repository: eloqdata/tx_service Length of output: 231 🏁 Script executed: # Search for DataSyncWorkerToFlushDataWorker implementation
rg -n "DataSyncWorkerToFlushDataWorker" --type cpp -A 10Repository: eloqdata/tx_service Length of output: 3867 🏁 Script executed: # Search for flush_data_worker_ctx_ initialization and worker_num_
rg -n "flush_data_worker_ctx_" --type cpp -A 3 -B 1Repository: eloqdata/tx_service Length of output: 8710 🏁 Script executed: # Search for worker_num_ validation/checks
rg -n "worker_num_" --type cpp --type h -A 2 -B 1Repository: eloqdata/tx_service Length of output: 9840 Validate The modulo operation in 🤖 Prompt for AI Agents |
||
| /** | ||
| * @brief Add a flush task entry to the flush task. If the there's no | ||
| * pending flush task, create a new flush task and add the entry to it. | ||
|
|
@@ -2463,16 +2470,21 @@ class LocalCcShards | |
|
|
||
| WorkerThreadContext flush_data_worker_ctx_; | ||
|
|
||
| // The flush task that has not reached the max pending flush size. | ||
| // New flush task entry will be added to this buffer. This task will | ||
| // be appended to pending_flush_work_ when it reaches the max pending flush | ||
| // size, which will then be processed by flush data worker. | ||
| FlushDataTask cur_flush_buffer_; | ||
| // Flush task queue for flush data worker to process. | ||
| std::deque<std::unique_ptr<FlushDataTask>> pending_flush_work_; | ||
|
|
||
| void FlushDataWorker(); | ||
| void FlushData(std::unique_lock<std::mutex> &flush_worker_lk); | ||
| // Per-worker flush buffers. Each DataSyncWorker has its own buffer. | ||
| // New flush task entry will be added to the corresponding buffer. This task | ||
| // will be appended to pending_flush_work_[worker_idx] when it reaches the | ||
| // max pending flush size, which will then be processed by the corresponding | ||
| // flush data worker. Store as pointers because FlushDataTask contains a | ||
| // bthread::Mutex and is non-movable/non-copyable, which cannot be stored | ||
| // directly in a vector that may reallocate. | ||
| std::vector<std::unique_ptr<FlushDataTask>> cur_flush_buffers_; | ||
| // Per-worker flush task queues. Each FlushDataWorker processes its | ||
| // corresponding queue. | ||
| std::vector<std::deque<std::unique_ptr<FlushDataTask>>> pending_flush_work_; | ||
|
|
||
| void FlushDataWorker(size_t worker_idx); | ||
| void FlushData(std::unique_lock<std::mutex> &flush_worker_lk, | ||
| size_t worker_idx); | ||
|
|
||
| // Memory controller for data sync. | ||
| DataSyncMemoryController data_sync_mem_controller_; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard
UpdatedMemory()against counter drift and arithmetic overflow.Line 9112 can overflow in
dirty_key_count_ * memory_usage_, and ifdirty_key_count_temporarily exceedsdata_key_count_, the estimate can exceed total memory and distort flush decisions. Clamp dirty count to total count and compute with overflow-safe arithmetic.🔧 Suggested fix
size_t UpdatedMemory() const { if (data_key_count_ == 0) return 0; - // Use cc map's data_key_count_ and dirty_key_count_ for estimation. - // integer math with rounding up to avoid systematic underestimation - return static_cast<size_t>( - (dirty_key_count_ * memory_usage_ + data_key_count_ - 1) / - data_key_count_); + // Use cc map's data_key_count_ and dirty_key_count_ for estimation. + // Clamp to avoid over-estimation when counters are temporarily inconsistent. + const size_t effective_dirty_key_count = + std::min(dirty_key_count_, data_key_count_); + // Integer math with rounding up; split multiply/divide to reduce overflow risk. + const uint64_t base = memory_usage_ / data_key_count_; + const uint64_t rem = memory_usage_ % data_key_count_; + return static_cast<size_t>( + base * effective_dirty_key_count + + (rem * effective_dirty_key_count + data_key_count_ - 1) / data_key_count_); }🤖 Prompt for AI Agents