Skip to content

Commit a2eba10

Browse files
alvin-phoenix-aiclaude
authored andcommitted
[Refactor] Extract exec join core module (StarRocks#72303)
Signed-off-by: alvin-celerdata <alvin.zhao@celerdata.com>
1 parent 0768768 commit a2eba10

13 files changed

Lines changed: 207 additions & 63 deletions

be/AGENTS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,14 @@ Reusable exec sorting algorithms without pipeline, spill, workgroup, storage, or
205205
- Allowed target deps: `ExprCore`, `RuntimeCore`, `ChunkCore`, `ColumnCore`, `TypesCore`, `Common`, `Base`, `Gutil`, `StarRocksGen`
206206
- Core tests: `exec_sorting_core_test`
207207
- Remediation: Keep ExecSortingCore limited to reusable sorting algorithms; leave merge-path pipeline observer integration, chunk sorters, spill-aware sorting, and exec-node adapters in higher modules.
208+
209+
### ExecJoinCore (`execjoincore`)
210+
Reusable exec join hash table algorithms without join nodes, pipeline, storage, service, or util coupling.
211+
- Targets: `ExecJoinCore`
212+
- Allowed internal include prefixes: `exec/join/`, `exec/sorting/sort_helper.h`, `exprs/`, `serde/`, `runtime/`, `column/`, `types/`, `common/`, `base/`, `gutil/`, `gen_cpp/`
213+
- Allowed target deps: `ExecSortingCore`, `ExprCore`, `SerdeCore`, `RuntimeCore`, `ChunkCore`, `ColumnCore`, `TypesCore`, `Common`, `Base`, `Gutil`, `StarRocksGen`
214+
- Core tests: `exec_join_core_test`
215+
- Remediation: Keep ExecJoinCore limited to reusable join hash table algorithms; leave join nodes, pipeline operators, storage/service integration, and util diagnostics in higher modules.
208216
<!-- END GENERATED: BE MODULE HARNESSES -->
209217

210218
## BE-Specific Sync Rules

be/module_boundary_manifest.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,30 @@
421421
"allowed_test_targets": ["exec_sorting_core_test"],
422422
"allowed_test_link_deps": ["ExecSortingCore", "ExprCore", "RuntimeCore", "ChunkCore", "ColumnCore", "TypesCore", "Common", "Base", "Gutil", "StarRocksGen"],
423423
"remediation": "Keep ExecSortingCore limited to reusable sorting algorithms; leave merge-path pipeline observer integration, chunk sorters, spill-aware sorting, and exec-node adapters in higher modules."
424+
},
425+
{
426+
"id": "execjoincore",
427+
"doc_label": "ExecJoinCore",
428+
"summary": "Reusable exec join hash table algorithms without join nodes, pipeline, storage, service, or util coupling.",
429+
"owned_targets": ["ExecJoinCore"],
430+
"owned_globs": [
431+
"be/src/exec/join/**"
432+
],
433+
"allowed_include_prefixes": ["exec/join/", "exec/sorting/sort_helper.h", "exprs/", "serde/", "runtime/", "column/", "types/", "common/", "base/", "gutil/", "gen_cpp/"],
434+
"forbidden_include_prefixes": ["exec/", "exec/pipeline/", "exec/spill/", "exec/workgroup/", "runtime/batch_write/", "runtime/routine_load/", "runtime/stream_load/", "storage/", "service/", "http/", "cache/", "connector/", "util/"],
435+
"forbidden_includes": [
436+
"exec/cross_join_node.h",
437+
"exec/data_sink.h",
438+
"exec/exec_node.h",
439+
"exec/hash_join_components.h",
440+
"exec/hash_join_node.h",
441+
"exec/hash_joiner.h",
442+
"runtime/exec_env.h"
443+
],
444+
"allowed_target_deps": ["ExecSortingCore", "ExprCore", "SerdeCore", "RuntimeCore", "ChunkCore", "ColumnCore", "TypesCore", "Common", "Base", "Gutil", "StarRocksGen"],
445+
"allowed_test_targets": ["exec_join_core_test"],
446+
"allowed_test_link_deps": ["ExecJoinCore", "ExecSortingCore", "ExprCore", "SerdeCore", "RuntimeCore", "ChunkCore", "ColumnCore", "TypesCore", "Common", "Base", "Gutil", "StarRocksGen"],
447+
"remediation": "Keep ExecJoinCore limited to reusable join hash table algorithms; leave join nodes, pipeline operators, storage/service integration, and util diagnostics in higher modules."
424448
}
425449
]
426450
}

be/src/column/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,4 @@ ADD_BE_LIB(Column
6767
)
6868

6969
target_link_libraries(ChunkCore PUBLIC ColumnCore)
70-
target_link_libraries(Column PUBLIC ColumnCore ChunkCore)
70+
target_link_libraries(Column PUBLIC ColumnCore ChunkCore SerdeCore)

be/src/exec/AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ Local guide for work under `be/src/exec`.
1313
## Current Direction
1414

1515
- Keep `Exec` as the temporary compatibility umbrella while extracted modules move out of it.
16-
- Treat existing targets such as `ExecCore`, `ExecSinkCore`, `SpillCore`, `ExecSchemaScannerCore`, `ExecSchemaScanners`, and `ExecSortingCore` as the model for future extractions.
17-
- Follow `handbook/plans/active/2026-04-28-exec-layering-rollout.md` for the active exec module roadmap.
16+
- Treat existing targets such as `ExecCore`, `ExecSinkCore`, `SpillCore`, `ExecSchemaScannerCore`, `ExecSchemaScanners`, `ExecSortingCore`, and `ExecJoinCore` as the model for future extractions.
17+
- Keep local or checkout-specific roadmap notes outside the committed guide unless they become shared repository policy.
1818

1919
## Validation
2020

be/src/exec/CMakeLists.txt

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,44 @@ target_link_libraries(ExecSortingCore PUBLIC
135135
StarRocksGen
136136
)
137137

138+
set(EXEC_JOIN_CORE_FILES
139+
join/join_hash_table_descriptor.cpp
140+
join/join_key_constructor.cpp
141+
join/join_hash_table.cpp
142+
join/join_hash_map_mapping_inst.cpp
143+
join/join_hash_map_linear_chained_inst.cpp
144+
join/join_hash_map_linear_chained_set_inst.cpp
145+
join/join_hash_map_bucket_chained_inst.cpp
146+
join/join_hash_map_asof_inst.cpp
147+
)
148+
149+
ADD_BE_LIB(ExecJoinCore
150+
${EXEC_JOIN_CORE_FILES}
151+
)
152+
153+
target_link_libraries(ExecJoinCore PUBLIC
154+
ExecSortingCore
155+
ExprCore
156+
SerdeCore
157+
RuntimeCore
158+
ChunkCore
159+
ColumnCore
160+
TypesCore
161+
Common
162+
Base
163+
Gutil
164+
StarRocksGen
165+
)
166+
167+
if (WITH_PCH)
168+
target_precompile_headers(ExecJoinCore
169+
PRIVATE
170+
join/join_hash_map.h
171+
join/join_hash_map.hpp
172+
join/join_hash_map_method.hpp
173+
)
174+
endif()
175+
138176
# Staged pipeline compatibility groups. These source lists are not final clean
139177
# module boundaries yet; keep them named by intended ownership so later
140178
# cycle-cut leaves can promote them into real targets incrementally.
@@ -361,9 +399,6 @@ set(EXEC_NON_PIPELINE_FILES
361399
hash_joiner.cpp
362400
hash_join_node.cpp
363401
hash_join_components.cpp
364-
join/join_hash_table_descriptor.cpp
365-
join/join_key_constructor.cpp
366-
join/join_hash_table.cpp
367402
topn_node.cpp
368403
chunks_sorter.cpp
369404
chunks_sorter_heap_sort.cpp
@@ -494,38 +529,19 @@ add_library(pipeline_extensions_exec_objs OBJECT
494529
${PIPELINE_EXTENSIONS_SRCS}
495530
)
496531

497-
add_library(join_hash_map_inst_objs OBJECT
498-
join/join_hash_map_mapping_inst.cpp
499-
join/join_hash_map_linear_chained_inst.cpp
500-
join/join_hash_map_linear_chained_set_inst.cpp
501-
join/join_hash_map_bucket_chained_inst.cpp
502-
join/join_hash_map_asof_inst.cpp
503-
)
504-
505532
IF(ENABLE_MULTI_DYNAMIC_LIBS)
506533
set_property(TARGET pipeline_primitives_exec_objs PROPERTY POSITION_INDEPENDENT_CODE ON)
507534
set_property(TARGET pipeline_runtime_compat_exec_objs PROPERTY POSITION_INDEPENDENT_CODE ON)
508535
set_property(TARGET pipeline_operators_batch_exec_objs PROPERTY POSITION_INDEPENDENT_CODE ON)
509536
set_property(TARGET pipeline_extensions_exec_objs PROPERTY POSITION_INDEPENDENT_CODE ON)
510-
set_property(TARGET join_hash_map_inst_objs PROPERTY POSITION_INDEPENDENT_CODE ON)
511537
ENDIF()
512538

513-
if (WITH_PCH)
514-
target_precompile_headers(join_hash_map_inst_objs
515-
PRIVATE
516-
join/join_hash_map.h
517-
join/join_hash_map.hpp
518-
join/join_hash_map_method.hpp
519-
)
520-
endif()
521-
522539
ADD_BE_LIB(Exec
523540
${EXEC_NON_PIPELINE_FILES}
524541
$<TARGET_OBJECTS:pipeline_primitives_exec_objs>
525542
$<TARGET_OBJECTS:pipeline_runtime_compat_exec_objs>
526543
$<TARGET_OBJECTS:pipeline_operators_batch_exec_objs>
527544
$<TARGET_OBJECTS:pipeline_extensions_exec_objs>
528-
$<TARGET_OBJECTS:join_hash_map_inst_objs>
529545
)
530546

531-
target_link_libraries(Exec PUBLIC ExecSinkCore ExecCore SpillCore ExecSchemaScannerCore ExecSchemaScanners ExecSortingCore)
547+
target_link_libraries(Exec PUBLIC ExecSinkCore ExecCore SpillCore ExecSchemaScannerCore ExecSchemaScanners ExecSortingCore ExecJoinCore)

be/src/exec/join/join_hash_table.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,14 @@
2222
#include "column/chunk.h"
2323
#include "column/vectorized_fwd.h"
2424
#include "common/runtime_profile.h"
25+
#include "common/stack_util.h"
2526
#include "common/statusor.h"
2627
#include "common/system/cpu_info.h"
27-
#include "exec/hash_join_node.h"
2828
#include "exec/join/join_hash_map_method.h"
2929
#include "exec/join/join_key_constructor.h"
30+
#include "exprs/column_ref.h"
3031
#include "runtime/descriptors.h"
31-
#include "serde/column_array_serde.h"
3232
#include "types/logical_type_infra.h"
33-
#include "util/stack_util.h"
3433

3534
namespace starrocks {
3635

be/src/serde/CMakeLists.txt

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,34 @@ set(LIBRARY_OUTPUT_PATH "${BUILD_DIR}/src/serde")
1717
# where to put generated binaries
1818
set(EXECUTABLE_OUTPUT_PATH "${BUILD_DIR}/src/serde")
1919

20+
ADD_BE_LIB(SerdeCore
21+
column_array_serde.cpp
22+
)
23+
24+
target_link_libraries(SerdeCore PUBLIC
25+
ColumnCore
26+
TypesCore
27+
Common
28+
Base
29+
Gutil
30+
StarRocksGen
31+
)
32+
2033
ADD_BE_LIB(Serde
2134
encode_context.cpp
22-
column_array_serde.cpp
2335
compress_strategy.cpp
2436
protobuf_serde.cpp
2537
)
38+
39+
target_link_libraries(Serde PUBLIC
40+
SerdeCore
41+
Column
42+
RuntimeCore
43+
ChunkCore
44+
ColumnCore
45+
TypesCore
46+
Common
47+
Base
48+
Gutil
49+
StarRocksGen
50+
)

be/src/serde/column_array_serde.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
#include "column/variant_column.h"
4040
#include "column/vectorized_fwd.h"
4141
#include "common/config_diagnostic_fwd.h"
42-
#include "serde/protobuf_serde.h"
42+
#include "serde/encode_level.h"
4343
#include "types/json_value.h"
4444
#include "types/percentile_value.h"
4545

@@ -214,7 +214,7 @@ class FixedLengthColumnSerde {
214214
// NOTE that `serialize` and `deserialize` will store and load the size as uint32_t.
215215
// If you use `serialize` and `deserialize`, please make sure that the size of the column is less than 2^32.
216216
int64_t size = sizeof(T) * column.size();
217-
if (EncodeContext::enable_encode_integer(encode_level) && size >= ENCODE_SIZE_LIMIT) {
217+
if (is_integer_encoding_enabled(encode_level) && size >= ENCODE_SIZE_LIMIT) {
218218
return sizeof(uint32_t) + sizeof(uint64_t) +
219219
std::max((int64_t)size, (int64_t)streamvbyte_max_compressedbytes(upper_int32(size)));
220220
} else {
@@ -225,7 +225,7 @@ class FixedLengthColumnSerde {
225225
static uint8_t* serialize(const FixedLengthColumnBase<T>& column, uint8_t* buff, const int encode_level) {
226226
uint32_t size = sizeof(T) * column.size();
227227
buff = write_little_endian_32(size, buff);
228-
if (EncodeContext::enable_encode_integer(encode_level) && size >= ENCODE_SIZE_LIMIT) {
228+
if (is_integer_encoding_enabled(encode_level) && size >= ENCODE_SIZE_LIMIT) {
229229
// sorted 32-bit integers have a better optimize branch
230230
buff = encode_integers<(sizeof(T) == 4 && sorted)>(column.raw_data(), size, buff, encode_level);
231231
} else {
@@ -240,7 +240,7 @@ class FixedLengthColumnSerde {
240240
ASSIGN_OR_RETURN(buff, read_little_endian_32(buff, end, &size));
241241
auto& data = column->get_data();
242242
raw::make_room(&data, size / sizeof(T));
243-
if (EncodeContext::enable_encode_integer(encode_level) && size >= ENCODE_SIZE_LIMIT) {
243+
if (is_integer_encoding_enabled(encode_level) && size >= ENCODE_SIZE_LIMIT) {
244244
constexpr bool is_sorted_i32 = sizeof(T) == 4 && sorted;
245245
ASSIGN_OR_RETURN(buff, decode_integers<is_sorted_i32>(buff, end, data.data(), size));
246246
} else {
@@ -258,13 +258,13 @@ class BinaryColumnSerde {
258258
const auto& offsets = column.get_offset();
259259
int64_t res = sizeof(T) * 2;
260260
int64_t offsets_size = offsets.size() * sizeof(typename BinaryColumnBase<T>::Offset);
261-
if (EncodeContext::enable_encode_integer(encode_level) && offsets_size >= ENCODE_SIZE_LIMIT) {
261+
if (is_integer_encoding_enabled(encode_level) && offsets_size >= ENCODE_SIZE_LIMIT) {
262262
res += sizeof(uint64_t) +
263263
std::max((int64_t)offsets_size, (int64_t)streamvbyte_max_compressedbytes(upper_int32(offsets_size)));
264264
} else {
265265
res += offsets_size;
266266
}
267-
if (EncodeContext::enable_encode_string(encode_level) && bytes.size() >= ENCODE_SIZE_LIMIT) {
267+
if (is_string_encoding_enabled(encode_level) && bytes.size() >= ENCODE_SIZE_LIMIT) {
268268
res += sizeof(uint64_t) + std::max((int64_t)bytes.size(), (int64_t)LZ4_compressBound(bytes.size()));
269269
} else {
270270
res += bytes.size();
@@ -283,7 +283,7 @@ class BinaryColumnSerde {
283283
} else {
284284
buff = write_little_endian_64(bytes_size, buff);
285285
}
286-
if (EncodeContext::enable_encode_string(encode_level) && bytes_size >= ENCODE_SIZE_LIMIT &&
286+
if (is_string_encoding_enabled(encode_level) && bytes_size >= ENCODE_SIZE_LIMIT &&
287287
bytes_size <= LZ4_MAX_INPUT_SIZE) {
288288
buff = encode_string_lz4(bytes.data(), bytes_size, buff, encode_level);
289289
} else {
@@ -297,7 +297,7 @@ class BinaryColumnSerde {
297297
} else {
298298
buff = write_little_endian_64(offsets_size, buff);
299299
}
300-
if (EncodeContext::enable_encode_integer(encode_level) && offsets_size >= ENCODE_SIZE_LIMIT) {
300+
if (is_integer_encoding_enabled(encode_level) && offsets_size >= ENCODE_SIZE_LIMIT) {
301301
if (sizeof(T) == 4) { // only support sorted 32-bit integers
302302
buff = encode_integers<true>(offsets.data(), offsets_size, buff, encode_level);
303303
} else {
@@ -322,7 +322,7 @@ class BinaryColumnSerde {
322322
column->get_bytes().resize(bytes_size);
323323

324324
auto* bytes_data = column->get_bytes().data();
325-
if (EncodeContext::enable_encode_string(encode_level) && bytes_size >= ENCODE_SIZE_LIMIT &&
325+
if (is_string_encoding_enabled(encode_level) && bytes_size >= ENCODE_SIZE_LIMIT &&
326326
bytes_size <= LZ4_MAX_INPUT_SIZE) {
327327
ASSIGN_OR_RETURN(buff, decode_string_lz4(buff, end, bytes_data, bytes_size));
328328
} else {
@@ -337,7 +337,7 @@ class BinaryColumnSerde {
337337
}
338338
raw::make_room(&column->get_offset(), offset_bytes_size / sizeof(typename BinaryColumnBase<T>::Offset));
339339

340-
if (EncodeContext::enable_encode_integer(encode_level) && offset_bytes_size >= ENCODE_SIZE_LIMIT) {
340+
if (is_integer_encoding_enabled(encode_level) && offset_bytes_size >= ENCODE_SIZE_LIMIT) {
341341
constexpr bool is_i32 = sizeof(T) == 4;
342342
ASSIGN_OR_RETURN(buff, decode_integers<is_i32>(buff, end, column->get_offset().data(), offset_bytes_size));
343343
} else {

be/src/serde/encode_context.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "column/chunk.h"
2323
#include "column/chunk_extra_data.h"
2424
#include "common/statusor.h"
25+
#include "serde/encode_level.h"
2526

2627
namespace starrocks {
2728
class ChunkPB;
@@ -60,14 +61,11 @@ class EncodeContext {
6061

6162
static constexpr uint16_t STREAMVBYTE_PADDING_SIZE = STREAMVBYTE_PADDING;
6263

63-
static bool enable_encode_integer(const int encode_level) { return encode_level & ENCODE_INTEGER; }
64+
static bool enable_encode_integer(const int encode_level) { return is_integer_encoding_enabled(encode_level); }
6465

65-
static bool enable_encode_string(const int encode_level) { return encode_level & ENCODE_STRING; }
66+
static bool enable_encode_string(const int encode_level) { return is_string_encoding_enabled(encode_level); }
6667

6768
private:
68-
static constexpr int ENCODE_INTEGER = 2;
69-
static constexpr int ENCODE_STRING = 4;
70-
7169
// if encode ratio < EncodeRatioLimit, encode it, otherwise not.
7270
void _adjust(const int col_id);
7371
const int _session_encode_level;
@@ -77,4 +75,4 @@ class EncodeContext {
7775
std::vector<uint64_t> _raw_bytes, _encoded_bytes;
7876
std::vector<uint32_t> _column_encode_level;
7977
};
80-
} // namespace starrocks::serde
78+
} // namespace starrocks::serde

be/src/serde/encode_level.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2021-present StarRocks, Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#pragma once
16+
17+
namespace starrocks::serde {
18+
19+
constexpr int ENCODE_INTEGER = 2;
20+
constexpr int ENCODE_STRING = 4;
21+
22+
inline bool is_integer_encoding_enabled(const int encode_level) {
23+
return encode_level & ENCODE_INTEGER;
24+
}
25+
26+
inline bool is_string_encoding_enabled(const int encode_level) {
27+
return encode_level & ENCODE_STRING;
28+
}
29+
30+
} // namespace starrocks::serde

0 commit comments

Comments
 (0)