Coverage Report

Created: 2026-08-18 10:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exec/partitioner/partitioner.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <algorithm>
21
22
#include "core/block/block.h"
23
#include "exprs/vexpr.h"
24
#include "exprs/vexpr_context.h"
25
26
namespace doris {
27
28
class PartitionerBase {
29
public:
30
    using HashValType = uint32_t;
31
32
322k
    PartitionerBase(HashValType partition_count) : _partition_count(partition_count) {}
33
325k
    virtual ~PartitionerBase() = default;
34
35
    virtual Status init(const std::vector<TExpr>& texprs) = 0;
36
37
    virtual Status prepare(RuntimeState* state, const RowDescriptor& row_desc) = 0;
38
39
    virtual Status open(RuntimeState* state) = 0;
40
41
    virtual Status close(RuntimeState* state) = 0;
42
43
    virtual Status do_partitioning(RuntimeState* state, Block* block) const = 0;
44
45
    virtual const std::vector<HashValType>& get_channel_ids() const = 0;
46
47
    virtual Status clone(RuntimeState* state, std::unique_ptr<PartitionerBase>& partitioner) = 0;
48
49
    // use _partition_count as invalid sentinel value. since modulo operation result is [0, partition_count-1]
50
6
    HashValType partition_count() const { return _partition_count; }
51
    // use a individual function to highlight its special meaning
52
4
    HashValType invalid_sentinel() const { return partition_count(); }
53
54
protected:
55
    const HashValType _partition_count;
56
};
57
58
class PartitionFunction {
59
public:
60
    using HashValType = PartitionerBase::HashValType;
61
62
5
    virtual ~PartitionFunction() = default;
63
64
    virtual Status init(const std::vector<TExpr>& texprs) = 0;
65
66
    virtual Status prepare(RuntimeState* state, const RowDescriptor& row_desc) = 0;
67
68
    virtual Status open(RuntimeState* state) = 0;
69
70
    virtual Status close(RuntimeState* state) = 0;
71
72
    virtual Status get_partitions(RuntimeState* state, Block* block, size_t partition_count,
73
                                  std::vector<HashValType>& partitions) const = 0;
74
75
    virtual HashValType partition_count() const = 0;
76
77
    virtual Status clone(RuntimeState* state,
78
                         std::unique_ptr<PartitionFunction>& function) const = 0;
79
};
80
81
enum class ShuffleHashMethod {
82
    CRC32,
83
    CRC32C,
84
};
85
86
template <typename ChannelIds>
87
class Crc32HashPartitioner : public PartitionerBase {
88
public:
89
322k
    Crc32HashPartitioner(int partition_count) : PartitionerBase(partition_count) {}
_ZN5doris20Crc32HashPartitionerINS_15ShiftChannelIdsEEC2Ei
Line
Count
Source
89
315k
    Crc32HashPartitioner(int partition_count) : PartitionerBase(partition_count) {}
_ZN5doris20Crc32HashPartitionerINS_17ShuffleChannelIdsEEC2Ei
Line
Count
Source
89
7.21k
    Crc32HashPartitioner(int partition_count) : PartitionerBase(partition_count) {}
_ZN5doris20Crc32HashPartitionerINS_24SpillPartitionChannelIdsEEC2Ei
Line
Count
Source
89
23
    Crc32HashPartitioner(int partition_count) : PartitionerBase(partition_count) {}
_ZN5doris20Crc32HashPartitionerINS_26SpillRePartitionChannelIdsEEC2Ei
Line
Count
Source
89
10
    Crc32HashPartitioner(int partition_count) : PartitionerBase(partition_count) {}
90
325k
    ~Crc32HashPartitioner() override = default;
_ZN5doris20Crc32HashPartitionerINS_15ShiftChannelIdsEED2Ev
Line
Count
Source
90
317k
    ~Crc32HashPartitioner() override = default;
_ZN5doris20Crc32HashPartitionerINS_17ShuffleChannelIdsEED2Ev
Line
Count
Source
90
7.34k
    ~Crc32HashPartitioner() override = default;
_ZN5doris20Crc32HashPartitionerINS_24SpillPartitionChannelIdsEED2Ev
Line
Count
Source
90
23
    ~Crc32HashPartitioner() override = default;
_ZN5doris20Crc32HashPartitionerINS_26SpillRePartitionChannelIdsEED2Ev
Line
Count
Source
90
10
    ~Crc32HashPartitioner() override = default;
91
92
210k
    Status init(const std::vector<TExpr>& texprs) override {
93
210k
        return VExpr::create_expr_trees(texprs, _partition_expr_ctxs);
94
210k
    }
_ZN5doris20Crc32HashPartitionerINS_15ShiftChannelIdsEE4initERKSt6vectorINS_5TExprESaIS4_EE
Line
Count
Source
92
203k
    Status init(const std::vector<TExpr>& texprs) override {
93
203k
        return VExpr::create_expr_trees(texprs, _partition_expr_ctxs);
94
203k
    }
_ZN5doris20Crc32HashPartitionerINS_17ShuffleChannelIdsEE4initERKSt6vectorINS_5TExprESaIS4_EE
Line
Count
Source
92
6.78k
    Status init(const std::vector<TExpr>& texprs) override {
93
6.78k
        return VExpr::create_expr_trees(texprs, _partition_expr_ctxs);
94
6.78k
    }
_ZN5doris20Crc32HashPartitionerINS_24SpillPartitionChannelIdsEE4initERKSt6vectorINS_5TExprESaIS4_EE
Line
Count
Source
92
18
    Status init(const std::vector<TExpr>& texprs) override {
93
18
        return VExpr::create_expr_trees(texprs, _partition_expr_ctxs);
94
18
    }
_ZN5doris20Crc32HashPartitionerINS_26SpillRePartitionChannelIdsEE4initERKSt6vectorINS_5TExprESaIS4_EE
Line
Count
Source
92
6
    Status init(const std::vector<TExpr>& texprs) override {
93
6
        return VExpr::create_expr_trees(texprs, _partition_expr_ctxs);
94
6
    }
95
96
210k
    Status prepare(RuntimeState* state, const RowDescriptor& row_desc) override {
97
210k
        return VExpr::prepare(_partition_expr_ctxs, state, row_desc);
98
210k
    }
_ZN5doris20Crc32HashPartitionerINS_15ShiftChannelIdsEE7prepareEPNS_12RuntimeStateERKNS_13RowDescriptorE
Line
Count
Source
96
203k
    Status prepare(RuntimeState* state, const RowDescriptor& row_desc) override {
97
203k
        return VExpr::prepare(_partition_expr_ctxs, state, row_desc);
98
203k
    }
_ZN5doris20Crc32HashPartitionerINS_17ShuffleChannelIdsEE7prepareEPNS_12RuntimeStateERKNS_13RowDescriptorE
Line
Count
Source
96
6.77k
    Status prepare(RuntimeState* state, const RowDescriptor& row_desc) override {
97
6.77k
        return VExpr::prepare(_partition_expr_ctxs, state, row_desc);
98
6.77k
    }
_ZN5doris20Crc32HashPartitionerINS_24SpillPartitionChannelIdsEE7prepareEPNS_12RuntimeStateERKNS_13RowDescriptorE
Line
Count
Source
96
15
    Status prepare(RuntimeState* state, const RowDescriptor& row_desc) override {
97
15
        return VExpr::prepare(_partition_expr_ctxs, state, row_desc);
98
15
    }
_ZN5doris20Crc32HashPartitionerINS_26SpillRePartitionChannelIdsEE7prepareEPNS_12RuntimeStateERKNS_13RowDescriptorE
Line
Count
Source
96
6
    Status prepare(RuntimeState* state, const RowDescriptor& row_desc) override {
97
6
        return VExpr::prepare(_partition_expr_ctxs, state, row_desc);
98
6
    }
99
100
212k
    Status open(RuntimeState* state) override { return VExpr::open(_partition_expr_ctxs, state); }
_ZN5doris20Crc32HashPartitionerINS_15ShiftChannelIdsEE4openEPNS_12RuntimeStateE
Line
Count
Source
100
205k
    Status open(RuntimeState* state) override { return VExpr::open(_partition_expr_ctxs, state); }
_ZN5doris20Crc32HashPartitionerINS_17ShuffleChannelIdsEE4openEPNS_12RuntimeStateE
Line
Count
Source
100
6.91k
    Status open(RuntimeState* state) override { return VExpr::open(_partition_expr_ctxs, state); }
_ZN5doris20Crc32HashPartitionerINS_24SpillPartitionChannelIdsEE4openEPNS_12RuntimeStateE
Line
Count
Source
100
6
    Status open(RuntimeState* state) override { return VExpr::open(_partition_expr_ctxs, state); }
_ZN5doris20Crc32HashPartitionerINS_26SpillRePartitionChannelIdsEE4openEPNS_12RuntimeStateE
Line
Count
Source
100
6
    Status open(RuntimeState* state) override { return VExpr::open(_partition_expr_ctxs, state); }
101
102
196k
    Status close(RuntimeState* state) override { return Status::OK(); }
_ZN5doris20Crc32HashPartitionerINS_15ShiftChannelIdsEE5closeEPNS_12RuntimeStateE
Line
Count
Source
102
189k
    Status close(RuntimeState* state) override { return Status::OK(); }
_ZN5doris20Crc32HashPartitionerINS_17ShuffleChannelIdsEE5closeEPNS_12RuntimeStateE
Line
Count
Source
102
6.83k
    Status close(RuntimeState* state) override { return Status::OK(); }
Unexecuted instantiation: _ZN5doris20Crc32HashPartitionerINS_24SpillPartitionChannelIdsEE5closeEPNS_12RuntimeStateE
Unexecuted instantiation: _ZN5doris20Crc32HashPartitionerINS_26SpillRePartitionChannelIdsEE5closeEPNS_12RuntimeStateE
103
104
    Status do_partitioning(RuntimeState* state, Block* block) const override;
105
106
224k
    const std::vector<HashValType>& get_channel_ids() const override { return _hash_vals; }
_ZNK5doris20Crc32HashPartitionerINS_15ShiftChannelIdsEE15get_channel_idsEv
Line
Count
Source
106
215k
    const std::vector<HashValType>& get_channel_ids() const override { return _hash_vals; }
_ZNK5doris20Crc32HashPartitionerINS_17ShuffleChannelIdsEE15get_channel_idsEv
Line
Count
Source
106
9.43k
    const std::vector<HashValType>& get_channel_ids() const override { return _hash_vals; }
_ZNK5doris20Crc32HashPartitionerINS_24SpillPartitionChannelIdsEE15get_channel_idsEv
Line
Count
Source
106
8
    const std::vector<HashValType>& get_channel_ids() const override { return _hash_vals; }
_ZNK5doris20Crc32HashPartitionerINS_26SpillRePartitionChannelIdsEE15get_channel_idsEv
Line
Count
Source
106
8
    const std::vector<HashValType>& get_channel_ids() const override { return _hash_vals; }
107
108
    Status clone(RuntimeState* state, std::unique_ptr<PartitionerBase>& partitioner) override;
109
110
protected:
111
46.6k
    Status _get_partition_column_result(Block* block, std::vector<int>& result) const {
112
46.6k
        int counter = 0;
113
67.0k
        for (auto ctx : _partition_expr_ctxs) {
114
67.0k
            RETURN_IF_ERROR(ctx->execute(block, &result[counter++]));
115
67.0k
        }
116
46.6k
        return Status::OK();
117
46.6k
    }
_ZNK5doris20Crc32HashPartitionerINS_17ShuffleChannelIdsEE28_get_partition_column_resultEPNS_5BlockERSt6vectorIiSaIiEE
Line
Count
Source
111
4.27k
    Status _get_partition_column_result(Block* block, std::vector<int>& result) const {
112
4.27k
        int counter = 0;
113
4.27k
        for (auto ctx : _partition_expr_ctxs) {
114
4.27k
            RETURN_IF_ERROR(ctx->execute(block, &result[counter++]));
115
4.27k
        }
116
4.27k
        return Status::OK();
117
4.27k
    }
_ZNK5doris20Crc32HashPartitionerINS_24SpillPartitionChannelIdsEE28_get_partition_column_resultEPNS_5BlockERSt6vectorIiSaIiEE
Line
Count
Source
111
8
    Status _get_partition_column_result(Block* block, std::vector<int>& result) const {
112
8
        int counter = 0;
113
8
        for (auto ctx : _partition_expr_ctxs) {
114
8
            RETURN_IF_ERROR(ctx->execute(block, &result[counter++]));
115
8
        }
116
8
        return Status::OK();
117
8
    }
_ZNK5doris20Crc32HashPartitionerINS_26SpillRePartitionChannelIdsEE28_get_partition_column_resultEPNS_5BlockERSt6vectorIiSaIiEE
Line
Count
Source
111
8
    Status _get_partition_column_result(Block* block, std::vector<int>& result) const {
112
8
        int counter = 0;
113
8
        for (auto ctx : _partition_expr_ctxs) {
114
8
            RETURN_IF_ERROR(ctx->execute(block, &result[counter++]));
115
8
        }
116
8
        return Status::OK();
117
8
    }
_ZNK5doris20Crc32HashPartitionerINS_15ShiftChannelIdsEE28_get_partition_column_resultEPNS_5BlockERSt6vectorIiSaIiEE
Line
Count
Source
111
42.3k
    Status _get_partition_column_result(Block* block, std::vector<int>& result) const {
112
42.3k
        int counter = 0;
113
62.7k
        for (auto ctx : _partition_expr_ctxs) {
114
62.7k
            RETURN_IF_ERROR(ctx->execute(block, &result[counter++]));
115
62.7k
        }
116
42.3k
        return Status::OK();
117
42.3k
    }
118
119
111k
    Status _clone_expr_ctxs(RuntimeState* state, VExprContextSPtrs& new_partition_expr_ctxs) const {
120
111k
        new_partition_expr_ctxs.resize(_partition_expr_ctxs.size());
121
236k
        for (size_t i = 0; i < _partition_expr_ctxs.size(); i++) {
122
125k
            RETURN_IF_ERROR(_partition_expr_ctxs[i]->clone(state, new_partition_expr_ctxs[i]));
123
125k
        }
124
111k
        return Status::OK();
125
111k
    }
_ZNK5doris20Crc32HashPartitionerINS_17ShuffleChannelIdsEE16_clone_expr_ctxsEPNS_12RuntimeStateERSt6vectorISt10shared_ptrINS_12VExprContextEESaIS8_EE
Line
Count
Source
119
407
    Status _clone_expr_ctxs(RuntimeState* state, VExprContextSPtrs& new_partition_expr_ctxs) const {
120
407
        new_partition_expr_ctxs.resize(_partition_expr_ctxs.size());
121
815
        for (size_t i = 0; i < _partition_expr_ctxs.size(); i++) {
122
408
            RETURN_IF_ERROR(_partition_expr_ctxs[i]->clone(state, new_partition_expr_ctxs[i]));
123
408
        }
124
407
        return Status::OK();
125
407
    }
_ZNK5doris20Crc32HashPartitionerINS_24SpillPartitionChannelIdsEE16_clone_expr_ctxsEPNS_12RuntimeStateERSt6vectorISt10shared_ptrINS_12VExprContextEESaIS8_EE
Line
Count
Source
119
5
    Status _clone_expr_ctxs(RuntimeState* state, VExprContextSPtrs& new_partition_expr_ctxs) const {
120
5
        new_partition_expr_ctxs.resize(_partition_expr_ctxs.size());
121
10
        for (size_t i = 0; i < _partition_expr_ctxs.size(); i++) {
122
5
            RETURN_IF_ERROR(_partition_expr_ctxs[i]->clone(state, new_partition_expr_ctxs[i]));
123
5
        }
124
5
        return Status::OK();
125
5
    }
_ZNK5doris20Crc32HashPartitionerINS_26SpillRePartitionChannelIdsEE16_clone_expr_ctxsEPNS_12RuntimeStateERSt6vectorISt10shared_ptrINS_12VExprContextEESaIS8_EE
Line
Count
Source
119
4
    Status _clone_expr_ctxs(RuntimeState* state, VExprContextSPtrs& new_partition_expr_ctxs) const {
120
4
        new_partition_expr_ctxs.resize(_partition_expr_ctxs.size());
121
8
        for (size_t i = 0; i < _partition_expr_ctxs.size(); i++) {
122
4
            RETURN_IF_ERROR(_partition_expr_ctxs[i]->clone(state, new_partition_expr_ctxs[i]));
123
4
        }
124
4
        return Status::OK();
125
4
    }
_ZNK5doris20Crc32HashPartitionerINS_15ShiftChannelIdsEE16_clone_expr_ctxsEPNS_12RuntimeStateERSt6vectorISt10shared_ptrINS_12VExprContextEESaIS8_EE
Line
Count
Source
119
111k
    Status _clone_expr_ctxs(RuntimeState* state, VExprContextSPtrs& new_partition_expr_ctxs) const {
120
111k
        new_partition_expr_ctxs.resize(_partition_expr_ctxs.size());
121
235k
        for (size_t i = 0; i < _partition_expr_ctxs.size(); i++) {
122
124k
            RETURN_IF_ERROR(_partition_expr_ctxs[i]->clone(state, new_partition_expr_ctxs[i]));
123
124k
        }
124
111k
        return Status::OK();
125
111k
    }
126
127
    virtual void _do_hash(const ColumnPtr& column, HashValType* __restrict result, int idx) const;
128
4.29k
    virtual void _initialize_hash_vals(size_t rows) const {
129
4.29k
        _hash_vals.resize(rows);
130
4.29k
        std::ranges::fill(_hash_vals, 0);
131
4.29k
    }
Unexecuted instantiation: _ZNK5doris20Crc32HashPartitionerINS_15ShiftChannelIdsEE21_initialize_hash_valsEm
_ZNK5doris20Crc32HashPartitionerINS_17ShuffleChannelIdsEE21_initialize_hash_valsEm
Line
Count
Source
128
4.27k
    virtual void _initialize_hash_vals(size_t rows) const {
129
4.27k
        _hash_vals.resize(rows);
130
4.27k
        std::ranges::fill(_hash_vals, 0);
131
4.27k
    }
_ZNK5doris20Crc32HashPartitionerINS_24SpillPartitionChannelIdsEE21_initialize_hash_valsEm
Line
Count
Source
128
8
    virtual void _initialize_hash_vals(size_t rows) const {
129
8
        _hash_vals.resize(rows);
130
8
        std::ranges::fill(_hash_vals, 0);
131
8
    }
_ZNK5doris20Crc32HashPartitionerINS_26SpillRePartitionChannelIdsEE21_initialize_hash_valsEm
Line
Count
Source
128
8
    virtual void _initialize_hash_vals(size_t rows) const {
129
8
        _hash_vals.resize(rows);
130
8
        std::ranges::fill(_hash_vals, 0);
131
8
    }
132
133
    VExprContextSPtrs _partition_expr_ctxs;
134
    mutable std::vector<HashValType> _hash_vals;
135
};
136
137
struct ShuffleChannelIds {
138
    using HashValType = PartitionerBase::HashValType;
139
4.71M
    HashValType operator()(HashValType l, size_t r) { return l % r; }
140
};
141
142
struct SpillPartitionChannelIds {
143
    using HashValType = PartitionerBase::HashValType;
144
    // Default spill partition mapping used by level-0 partitioning:
145
    // rotate hash bits and apply modulo to get a channel id directly.
146
3.14M
    HashValType operator()(HashValType l, size_t r) { return ((l >> 16) | (l << 16)) % r; }
147
};
148
149
struct SpillRePartitionChannelIds {
150
    using HashValType = PartitionerBase::HashValType;
151
152
    // Repartition mode: return the raw hash value without modulo.
153
    // The caller (SpillRepartitioner) will apply level-aware hash mixing and
154
    // final channel mapping, so repartition behavior can vary by level.
155
20
    HashValType operator()(HashValType l, size_t /*r*/) { return l; }
156
};
157
158
27.9M
static inline PartitionerBase::HashValType crc32c_shuffle_mix(PartitionerBase::HashValType h) {
159
    // Step 1: fold high entropy into low bits
160
27.9M
    h ^= h >> 16;
161
    // Step 2: odd multiplicative scramble (cheap avalanche)
162
27.9M
    h *= 0xA5B35705U;
163
    // Step 3: final fold to break remaining linearity
164
27.9M
    h ^= h >> 13;
165
27.9M
    return h;
166
27.9M
}
Unexecuted instantiation: unity_0_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
unity_13_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
Line
Count
Source
158
650
static inline PartitionerBase::HashValType crc32c_shuffle_mix(PartitionerBase::HashValType h) {
159
    // Step 1: fold high entropy into low bits
160
650
    h ^= h >> 16;
161
    // Step 2: odd multiplicative scramble (cheap avalanche)
162
650
    h *= 0xA5B35705U;
163
    // Step 3: final fold to break remaining linearity
164
650
    h ^= h >> 13;
165
650
    return h;
166
650
}
Unexecuted instantiation: unity_1_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
unity_7_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
Line
Count
Source
158
27.9M
static inline PartitionerBase::HashValType crc32c_shuffle_mix(PartitionerBase::HashValType h) {
159
    // Step 1: fold high entropy into low bits
160
27.9M
    h ^= h >> 16;
161
    // Step 2: odd multiplicative scramble (cheap avalanche)
162
27.9M
    h *= 0xA5B35705U;
163
    // Step 3: final fold to break remaining linearity
164
27.9M
    h ^= h >> 13;
165
27.9M
    return h;
166
27.9M
}
Unexecuted instantiation: unity_6_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: unity_10_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: unity_2_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: unity_9_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: unity_5_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: unity_8_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: unity_4_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: unity_3_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: hashjoin_build_sink.cpp:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: join_build_sink_operator.cpp:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: operator.cpp:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: partitioned_aggregation_sink_operator.cpp:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: scan_operator.cpp:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: vfile_result_writer.cpp:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: unity_29_cxx.cxx:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: vorc_reader.cpp:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: vparquet_reader.cpp:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: merge_partitioner.cpp:_ZN5dorisL18crc32c_shuffle_mixEj
Unexecuted instantiation: iceberg_partition_function.cpp:_ZN5dorisL18crc32c_shuffle_mixEj
167
168
// use high 16 bits as channel id to avoid conflict with crc32c hash table
169
// shuffle hash function same with crc32c hash table(eg join hash table) will lead bad performance
170
// hash table offten use low 16 bits as bucket index, so we shift 16 bits to high bits to avoid conflict
171
struct ShiftChannelIds {
172
    using HashValType = PartitionerBase::HashValType;
173
27.9M
    HashValType operator()(HashValType l, size_t r) { return crc32c_shuffle_mix(l) % r; }
174
};
175
176
class Crc32CHashPartitioner : public Crc32HashPartitioner<ShiftChannelIds> {
177
public:
178
    Crc32CHashPartitioner(int partition_count)
179
314k
            : Crc32HashPartitioner<ShiftChannelIds>(partition_count) {}
180
181
    Status clone(RuntimeState* state, std::unique_ptr<PartitionerBase>& partitioner) override;
182
183
private:
184
    void _do_hash(const ColumnPtr& column, HashValType* __restrict result, int idx) const override;
185
186
42.3k
    void _initialize_hash_vals(size_t rows) const override {
187
42.3k
        _hash_vals.resize(rows);
188
        // use golden ratio to initialize hash values to avoid collision with hash table's hash function
189
42.3k
        constexpr HashValType CRC32C_SHUFFLE_SEED = 0x9E3779B9U;
190
42.3k
        std::ranges::fill(_hash_vals, CRC32C_SHUFFLE_SEED);
191
42.3k
    }
192
};
193
194
/// Instantiated once in partitioner.cpp; suppresses per-TU implicit instantiation.
195
extern template class Crc32HashPartitioner<ShuffleChannelIds>;
196
extern template class Crc32HashPartitioner<SpillPartitionChannelIds>;
197
extern template class Crc32HashPartitioner<SpillRePartitionChannelIds>;
198
199
} // namespace doris