@@ -169,6 +169,11 @@ BlockInputStreamPtr SegmentReadTaskPool::buildInputStream(SegmentReadTaskPtr & t
169169 auto block_size = std::max (
170170 expected_block_size,
171171 static_cast <size_t >(dm_context->db_context .getSettingsRef ().dt_segment_stable_pack_rows ));
172+ if (likely (read_mode == ReadMode::Bitmap && !res_group_name.empty ()))
173+ {
174+ auto bytes = t->read_snapshot ->estimatedBytesOfInternalColumns ();
175+ LocalAdmissionController::global_instance->consumeResource (res_group_name, bytesToRU (bytes), 0 );
176+ }
172177 stream = t->segment ->getInputStream (
173178 read_mode,
174179 *dm_context,
@@ -201,7 +206,8 @@ SegmentReadTaskPool::SegmentReadTaskPool(
201206 AfterSegmentRead after_segment_read_,
202207 const String & tracing_id,
203208 bool enable_read_thread_,
204- Int64 num_streams_)
209+ Int64 num_streams_,
210+ const String & res_group_name_)
205211 : pool_id(nextPoolId())
206212 , physical_table_id(physical_table_id_)
207213 , mem_tracker(current_memory_tracker == nullptr ? nullptr : current_memory_tracker->shared_from_this ())
@@ -224,6 +230,7 @@ SegmentReadTaskPool::SegmentReadTaskPool(
224230 // Limiting the minimum number of reading segments to 2 is to avoid, as much as possible,
225231 // situations where the computation may be faster and the storage layer may not be able to keep up.
226232 , active_segment_limit(std::max(num_streams_, 2 ))
233+ , res_group_name(res_group_name_)
227234{
228235 if (tasks_wrapper.empty ())
229236 {
@@ -355,6 +362,7 @@ void SegmentReadTaskPool::pushBlock(Block && block)
355362{
356363 blk_stat.push (block);
357364 global_blk_stat.push (block);
365+ read_bytes_after_last_check += block.bytes ();
358366 q.push (std::move (block), nullptr );
359367}
360368
@@ -383,6 +391,12 @@ Int64 SegmentReadTaskPool::getFreeActiveSegmentsUnlock() const
383391 return active_segment_limit - static_cast <Int64>(active_segment_ids.size ());
384392}
385393
394+ Int64 SegmentReadTaskPool::getPendingSegmentCount () const
395+ {
396+ std::lock_guard lock (mutex);
397+ return tasks_wrapper.getTasks ().size ();
398+ }
399+
386400bool SegmentReadTaskPool::exceptionHappened () const
387401{
388402 return exception_happened.load (std::memory_order_relaxed);
@@ -403,4 +417,63 @@ void SegmentReadTaskPool::setException(const DB::Exception & e)
403417 }
404418}
405419
420+ static Int64 currentMS ()
421+ {
422+ return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now ().time_since_epoch ())
423+ .count ();
424+ }
425+
426+ static bool checkIsRUExhausted (const String & res_group_name)
427+ {
428+ auto priority = LocalAdmissionController::global_instance->getPriority (res_group_name);
429+ if (unlikely (!priority.has_value ()))
430+ {
431+ return false ;
432+ }
433+ return LocalAdmissionController::isRUExhausted (*priority);
434+ }
435+
436+ bool SegmentReadTaskPool::isRUExhausted ()
437+ {
438+ auto res = isRUExhaustedImpl ();
439+ if (res)
440+ {
441+ GET_METRIC (tiflash_storage_read_thread_counter, type_ru_exhausted).Increment ();
442+ }
443+ return res;
444+ }
445+
446+ bool SegmentReadTaskPool::isRUExhaustedImpl ()
447+ {
448+ if (unlikely (res_group_name.empty () || LocalAdmissionController::global_instance == nullptr ))
449+ {
450+ return false ;
451+ }
452+
453+ // To reduce lock contention in resource control,
454+ // check if RU is exhuasted every `bytes_of_one_hundred_ru` or every `100ms`.
455+
456+ // Fast path.
457+ Int64 ms = currentMS ();
458+ if (read_bytes_after_last_check < bytes_of_one_hundred_ru && ms - last_time_check_ru < check_ru_interval_ms)
459+ {
460+ return ru_is_exhausted; // Return result of last time.
461+ }
462+
463+ std::lock_guard lock (ru_mu);
464+ // If last thread has check is ru exhausted, use the result of last thread.
465+ // Attention: `read_bytes_after_last_check` can be written concurrently in `pushBlock`.
466+ ms = currentMS ();
467+ if (read_bytes_after_last_check < bytes_of_one_hundred_ru && ms - last_time_check_ru < check_ru_interval_ms)
468+ {
469+ return ru_is_exhausted; // Return result of last time.
470+ }
471+
472+ // Check and reset everything.
473+ read_bytes_after_last_check = 0 ;
474+ ru_is_exhausted = checkIsRUExhausted (res_group_name);
475+ last_time_check_ru = ms;
476+ return ru_is_exhausted;
477+ }
478+
406479} // namespace DB::DM
0 commit comments