@@ -932,6 +932,62 @@ SegmentSnapshotPtr Segment::createSnapshot(const DMContext & dm_context, bool fo
932932 Logger::get (dm_context.tracing_id ));
933933}
934934
935+ std::vector<DMFilePackFilter> Segment::loadDMFilePackFilters (
936+ const DMFiles & dmfiles,
937+ const MinMaxIndexCachePtr & index_cache,
938+ const RowKeyRanges & rowkey_ranges,
939+ const RSOperatorPtr & rs_filter,
940+ const FileProviderPtr & file_provider,
941+ const ReadLimiterPtr & read_limiter,
942+ const ScanContextPtr & scan_context,
943+ const String & tracing_id,
944+ const ReadTag & read_tag)
945+ {
946+ std::vector<DMFilePackFilter> pack_filters;
947+ pack_filters.reserve (dmfiles.size ());
948+ for (const auto & dmfile : dmfiles)
949+ {
950+ auto pack_filter = DMFilePackFilter::loadFrom (
951+ dmfile,
952+ index_cache,
953+ /* set_cache_if_miss*/ true ,
954+ rowkey_ranges,
955+ rs_filter,
956+ /* read_packs*/ {},
957+ file_provider,
958+ read_limiter,
959+ scan_context,
960+ tracing_id,
961+ read_tag);
962+ pack_filters.emplace_back (std::move (pack_filter));
963+ }
964+ return pack_filters;
965+ }
966+
967+ UInt64 Segment::estimatedBytesOfInternalColumns (
968+ const SegmentSnapshotPtr & read_snap,
969+ std::vector<DMFilePackFilter> & pack_filters,
970+ UInt64 start_ts)
971+ {
972+ // stable->getDMFiles() at least return one DMFile.
973+ const auto & dmfiles = read_snap->stable ->getDMFiles ();
974+ RUNTIME_CHECK (!dmfiles.empty ());
975+ auto handle_size = dmfiles.front ()->getColumnStat (EXTRA_HANDLE_COLUMN_ID ).avg_size ;
976+ if (handle_size == 0 )
977+ handle_size = sizeof (UInt64);
978+ constexpr auto version_size = sizeof (UInt64);
979+ constexpr auto delmark_size = sizeof (UInt8);
980+
981+ // For delta, rs_filter does not filter rows, so we need to read all rows.
982+ const auto delta_read_rows = read_snap->delta ->getRows ();
983+ // For Stable, rs_filter may filter rows.
984+ const auto stable_read_rows = read_snap->stable ->estimatedReadRows (
985+ pack_filters,
986+ start_ts,
987+ /* use_delta_index*/ delta_read_rows != 0 );
988+ return (handle_size + version_size + delmark_size) * (delta_read_rows + stable_read_rows);
989+ }
990+
935991BlockInputStreamPtr Segment::getInputStream (
936992 const ReadMode & read_mode,
937993 const DMContext & dm_context,
@@ -949,6 +1005,33 @@ BlockInputStreamPtr Segment::getInputStream(
9491005 expected_block_size,
9501006 columns_to_read,
9511007 segment_snap->stable ->stable );
1008+
1009+ // Building MVCC bitmap can be a resource-intensive operation that cannot be paused midway.
1010+ // To prevent scenarios where multiple segments concurrently build MVCC bitmaps but exhaust
1011+ // RU during execution and causing RU consumption to exceed limitations, we need to first
1012+ // estimate the cost of building the MVCC bitmap, pre-consume the corresponding RU,
1013+ // and then proceed with the building task.
1014+ const auto & res_group_name = dm_context.scan_context ->resource_group_name ;
1015+ if (likely (read_mode == ReadMode::Bitmap && !res_group_name.empty ()))
1016+ {
1017+ auto real_ranges = shrinkRowKeyRanges (read_ranges);
1018+ if (!real_ranges.empty ())
1019+ {
1020+ auto pack_filters = loadDMFilePackFilters (
1021+ segment_snap->stable ->getDMFiles (),
1022+ dm_context.global_context .getMinMaxIndexCache (),
1023+ real_ranges,
1024+ filter ? filter->rs_operator : EMPTY_RS_OPERATOR ,
1025+ dm_context.global_context .getFileProvider (),
1026+ dm_context.global_context .getReadLimiter (),
1027+ dm_context.scan_context ,
1028+ dm_context.tracing_id ,
1029+ ReadTag::MVCC );
1030+ auto bytes = estimatedBytesOfInternalColumns (segment_snap, pack_filters, start_ts);
1031+ LocalAdmissionController::global_instance->consumeBytesResource (res_group_name, bytesToRU (bytes));
1032+ }
1033+ }
1034+
9521035 switch (read_mode)
9531036 {
9541037 case ReadMode::Normal:
0 commit comments