Skip to content

Commit b05d260

Browse files
[Enhancement] Serve a partitioned Broker Load's pre-split from Parquet/ORC footers (#79509)
Signed-off-by: Yixin Luo <18810541851@163.com> Co-authored-by: Yixin Luo <18810541851@163.com>
1 parent 6cd5cce commit b05d260

13 files changed

Lines changed: 624 additions & 150 deletions

File tree

docs/en/administration/configuration/FE_parameters/stats_storage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ This topic introduces the following types of FE configurations:
814814
- Type: Int
815815
- Unit: -
816816
- Is mutable: Yes
817-
- Description: Number of Parquet/ORC footers the Sample-Based Tablet Pre-Split meta tier reads concurrently from a `FILES()` source. Footer reads are independent per file and the sampler sorts the aggregated statistics, so concurrency only cuts the wall time of the pre-split hook (each footer is a remote round-trip; a many-file source otherwise serializes hundreds of round-trips). Set to `1` to disable concurrency.
817+
- Description: Number of Parquet/ORC footers the Sample-Based Tablet Pre-Split meta tier reads concurrently from a file-backed load source (`FILES()` or Broker Load). Footer reads are independent per file and the sampler sorts the aggregated statistics, so concurrency only cuts the wall time of the pre-split hook (each footer is a remote round-trip; a many-file source otherwise serializes hundreds of round-trips). Set to `1` to disable concurrency.
818818
- Introduced in: v4.1.0
819819

820820
### `tablet_pre_split_max_partitions_per_load`

docs/ja/administration/configuration/FE_parameters/stats_storage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ ADMIN SET FRONTEND CONFIG ("key" = "value");
814814
- タイプ:Int
815815
- 単位:-
816816
- 変更可能:Yes
817-
- 説明:サンプリングベースのタブレット事前分割の meta tier `FILES()` ソースから並行して読み取る Parquet/ORC フッターの数。フッターの読み取りはファイルごとに独立しており、サンプラーは集約した統計情報をソートするため、並行化は事前分割フックの実時間を短縮するだけです(各フッターはリモートへの 1 往復であり、ファイル数の多いソースではこれを直列に数百回繰り返すことになります)。`1` に設定すると並行化を無効化します。
817+
- 説明:サンプリングベースのタブレット事前分割の meta tier がファイルベースのロードソース(`FILES()` または Broker Load)から並行して読み取る Parquet/ORC フッターの数。フッターの読み取りはファイルごとに独立しており、サンプラーは集約した統計情報をソートするため、並行化は事前分割フックの実時間を短縮するだけです(各フッターはリモートへの 1 往復であり、ファイル数の多いソースではこれを直列に数百回繰り返すことになります)。`1` に設定すると並行化を無効化します。
818818
- 導入時期:v4.1.0
819819

820820
### `tablet_pre_split_max_partitions_per_load`

docs/zh/administration/configuration/FE_parameters/stats_storage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ ADMIN SET FRONTEND CONFIG ("key" = "value");
814814
- 类型: Int
815815
- 单位: -
816816
- 是否可变: Yes
817-
- 描述: 基于采样的 Tablet 预分裂 meta tier `FILES()` 数据源并发读取的 Parquet/ORC footer 数量。每个文件的 footer 读取相互独立,且采样器会对汇总后的统计信息排序,因此并发只会缩短预分裂钩子的墙钟耗时(每个 footer 都是一次远程往返;文件众多的数据源否则会串行执行数百次往返)。设为 `1` 可关闭并发。
817+
- 描述: 基于采样的 Tablet 预分裂 meta tier 从文件类导入源(`FILES()` 或 Broker Load)并发读取的 Parquet/ORC footer 数量。每个文件的 footer 读取相互独立,且采样器会对汇总后的统计信息排序,因此并发只会缩短预分裂钩子的墙钟耗时(每个 footer 都是一次远程往返;文件众多的数据源否则会串行执行数百次往返)。设为 `1` 可关闭并发。
818818
- 引入版本: v4.1.0
819819

820820
### `tablet_pre_split_max_partitions_per_load`

fe/fe-core/src/main/java/com/starrocks/alter/reshard/presplit/BrokerLoadRowGroupStatisticsProvider.java

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import com.starrocks.sql.ast.BrokerDesc;
2222
import com.starrocks.thrift.TBrokerFileStatus;
2323
import org.apache.hadoop.conf.Configuration;
24-
import org.apache.hadoop.fs.FileStatus;
2524

2625
import java.util.ArrayList;
2726
import java.util.List;
@@ -50,16 +49,19 @@
5049
* FE-local access cannot reach. Routing footer reads through a
5150
* broker-backed seekable input is a deliberate follow-up.
5251
*
53-
* <p>Non-identity file groups (per-group {@code WHERE}, {@code SET}/explicit
54-
* column list, {@code columns_from_path}, negative-load, or legacy hadoop
55-
* functions) map or filter the sort key, so the raw footer column would diverge
56-
* from the loaded value; they are rejected before any footer read (reusing the
57-
* data tier's {@code rejectNonIdentityFileGroups} guard) and fall back to data
58-
* tier, which skips pre-split for the same shapes.
52+
* <p>A file group whose column mapping would perturb a sampled key column is
53+
* rejected before any footer read, reusing the data tier's
54+
* {@code rejectKeyPerturbingFileGroups} guard so both tiers agree: a per-group
55+
* {@code WHERE}, a negative load, a legacy hadoop function, a {@code SET} /
56+
* derived column, a key column supplied by {@code COLUMNS FROM PATH} (its value
57+
* is in the directory name, not the footer), or a {@code COLUMNS} list that
58+
* omits a key column. An all-identity {@code COLUMNS} list and path columns
59+
* disjoint from the key are accepted — the footer still carries the key columns
60+
* verbatim under the names the load reads them by.
5961
*
6062
* <p>Hadoop-side wiring (configuration build, broker → Hadoop file-status
61-
* conversion) is shared with the INSERT-from-FILES provider via
62-
* {@link PreSplitHadoopAccess}.
63+
* conversion, concurrent footer reads) is shared with the INSERT-from-FILES
64+
* provider via {@link PreSplitHadoopAccess}.
6365
*/
6466
final class BrokerLoadRowGroupStatisticsProvider implements RowGroupStatisticsProvider {
6567

@@ -72,23 +74,25 @@ public List<RowGroupStatistics> fetch(SampleRequest request) throws StarRocksExc
7274
List<List<TBrokerFileStatus>> fileStatusesPerGroup = context.fileStatusesPerGroup();
7375
List<Column> sortKeyColumns = request.getSortKey();
7476

75-
// A non-identity file group (per-group WHERE / SET / columns_from_path / negative-load / hadoop
76-
// functions) maps or filters the sort key, so the raw footer column diverges from the value the
77-
// load actually inserts and footer-derived boundaries would be skewed. Reuse the data tier's
78-
// identity guard as the single source of truth; on rejection defer to the data tier, which
79-
// rejects the same shapes and skips pre-split.
77+
// A file group whose mapping perturbs a sampled key column (per-group WHERE / SET / negative
78+
// load / hadoop function), supplies one from the path, or never names one, makes the raw
79+
// footer column diverge from the value the load actually inserts, so footer-derived
80+
// boundaries would be skewed. Reuse the data tier's guard as the single source of truth;
81+
// on rejection defer to the data tier, which applies the same test.
8082
try {
81-
BrokerLoadSampleSubqueryExecutor.rejectNonIdentityFileGroups(fileGroups);
83+
BrokerLoadSampleSubqueryExecutor.rejectKeyPerturbingFileGroups(
84+
fileGroups, BrokerLoadSampleSubqueryExecutor.sampledKeyColumns(request));
8285
} catch (StarRocksException nonIdentity) {
8386
throw new MetaTierUnavailableException(nonIdentity.getMessage());
8487
}
8588

8689
Configuration hadoopConfig = PreSplitHadoopAccess.buildHadoopConfiguration(brokerDesc.getProperties());
8790

88-
// Read every non-directory file's footer across all file groups. The
89-
// pipeline picks K from total file bytes, so partial enumeration would
90-
// bias the planner's quantile cuts.
91-
List<RowGroupStatistics> aggregated = new ArrayList<>();
91+
// Resolve every non-directory file's reader across all file groups. The pipeline picks K
92+
// from total file bytes, so partial enumeration would bias the planner's quantile cuts.
93+
// Format resolution runs first for every file: it touches no storage, so an unsupported
94+
// format defers to the data tier without having paid for a single footer read.
95+
List<PreSplitHadoopAccess.FooterRead> footerReads = new ArrayList<>();
9296
for (int groupIndex = 0; groupIndex < fileGroups.size(); groupIndex++) {
9397
BrokerFileGroup fileGroup = fileGroups.get(groupIndex);
9498
String declaredFormat = fileGroup.getFileFormat();
@@ -100,11 +104,11 @@ public List<RowGroupStatistics> fetch(SampleRequest request) throws StarRocksExc
100104
// wins; otherwise the file extension), then pick the reader.
101105
MetaTierFormat format = MetaTierFormat.fromBrokerFormatType(
102106
Load.getFormatType(declaredFormat, brokerFileStatus.path), brokerFileStatus.path);
103-
FileStatus hadoopFileStatus = PreSplitHadoopAccess.toHadoopFileStatus(brokerFileStatus);
104-
aggregated.addAll(format.read(hadoopFileStatus, hadoopConfig, sortKeyColumns, context.loadTimeZone()));
107+
footerReads.add(new PreSplitHadoopAccess.FooterRead(
108+
format, PreSplitHadoopAccess.toHadoopFileStatus(brokerFileStatus)));
105109
}
106110
}
107-
return aggregated;
111+
return PreSplitHadoopAccess.readFooters(footerReads, hadoopConfig, sortKeyColumns, context.loadTimeZone());
108112
}
109113

110114
private static BrokerLoadScanContext requireBrokerLoadContext(SampleRequest request)

0 commit comments

Comments
 (0)