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 <concurrentqueue.h> |
21 | | |
22 | | #include "exec/operator/operator.h" |
23 | | #include "exec/pipeline/dependency.h" |
24 | | |
25 | | namespace doris { |
26 | | template <typename T> |
27 | | void clear_blocks(moodycamel::ConcurrentQueue<T>& blocks, |
28 | | RuntimeProfile::Counter* memory_used_counter = nullptr); |
29 | | |
30 | | class PartitionerBase; |
31 | | class LocalExchangeSourceLocalState; |
32 | | class LocalExchangeSinkLocalState; |
33 | | |
34 | | struct Profile { |
35 | | RuntimeProfile::Counter* compute_hash_value_timer = nullptr; |
36 | | RuntimeProfile::Counter* distribute_timer = nullptr; |
37 | | RuntimeProfile::Counter* copy_data_timer = nullptr; |
38 | | }; |
39 | | |
40 | | struct SinkInfo { |
41 | | int* channel_id; |
42 | | PartitionerBase* partitioner; |
43 | | LocalExchangeSinkLocalState* local_state; |
44 | | std::map<int, int>* shuffle_idx_to_instance_idx; |
45 | | int ins_idx; |
46 | | }; |
47 | | |
48 | | struct SourceInfo { |
49 | | int channel_id; |
50 | | LocalExchangeSourceLocalState* local_state; |
51 | | }; |
52 | | /** |
53 | | * One exchanger is hold by one `LocalExchangeSharedState`. And one `LocalExchangeSharedState` is |
54 | | * shared by all local exchange sink operators and source operators with the same id. |
55 | | * |
56 | | * In exchanger, two block queues is maintained, one is data block queue and another is free block queue. |
57 | | * |
58 | | * In details, data block queue has queues as many as source operators. Each source operator will get |
59 | | * data block from the corresponding queue. Data blocks is push into the queue by sink operators. One |
60 | | * sink operator will push blocks into one or more queues. |
61 | | * |
62 | | * Free block is used to reuse the allocated memory. To reduce the memory limit, we also use a conf |
63 | | * to limit the size of free block queue. |
64 | | */ |
65 | | class ExchangerBase { |
66 | | public: |
67 | | /** |
68 | | * `BlockWrapper` is used to wrap a data block with a reference count. |
69 | | * |
70 | | * In function `unref()`, if `ref_count` decremented to 0, which means this block is not needed by |
71 | | * operators, so we put it into `_free_blocks` to reuse its memory if needed and refresh memory usage |
72 | | * in current queue. |
73 | | * |
74 | | * Note: `ref_count` will be larger than 1 only if this block is shared between multiple queues in |
75 | | * shuffle exchanger. |
76 | | */ |
77 | | class BlockWrapper { |
78 | | public: |
79 | | ENABLE_FACTORY_CREATOR(BlockWrapper); |
80 | | BlockWrapper(Block&& data_block, LocalExchangeSharedState* shared_state, int channel_id) |
81 | 103 | : _data_block(std::move(data_block)), |
82 | 103 | _shared_state(shared_state), |
83 | 103 | _allocated_bytes(_data_block.allocated_bytes()) { |
84 | 103 | if (_shared_state) { |
85 | 103 | _shared_state->add_total_mem_usage(_allocated_bytes); |
86 | 103 | } |
87 | 103 | } |
88 | 103 | ~BlockWrapper() { |
89 | 103 | if (_shared_state != nullptr) { |
90 | 103 | DCHECK_GT(_allocated_bytes, 0); |
91 | | // `_channel_ids` may be empty if exchanger is shuffled exchanger and channel id is |
92 | | // not used by `sub_total_mem_usage`. So we just pass -1 here. |
93 | 103 | _shared_state->sub_total_mem_usage(_allocated_bytes); |
94 | 103 | if (_shared_state->exchanger->_free_block_limit == 0 || |
95 | 103 | _shared_state->exchanger->_free_blocks.size_approx() < |
96 | 28 | _shared_state->exchanger->_free_block_limit * |
97 | 87 | _shared_state->exchanger->_num_sources) { |
98 | 87 | _data_block.clear_column_data(); |
99 | | // Free blocks is used to improve memory efficiency. Failure during pushing back |
100 | | // free block will not incur any bad result so just ignore the return value. |
101 | 87 | _shared_state->exchanger->_free_blocks.enqueue(std::move(_data_block)); |
102 | 87 | } |
103 | 103 | }; |
104 | 103 | } |
105 | 162 | void record_channel_id(int channel_id) { |
106 | 162 | _channel_ids.push_back(channel_id); |
107 | 162 | if (_shared_state) { |
108 | 162 | _shared_state->add_mem_usage(channel_id, _allocated_bytes); |
109 | 162 | } |
110 | 162 | } |
111 | | |
112 | | private: |
113 | | friend class ShuffleExchanger; |
114 | | friend class BucketShuffleExchanger; |
115 | | friend class PassthroughExchanger; |
116 | | friend class BroadcastExchanger; |
117 | | friend class PassToOneExchanger; |
118 | | friend class AdaptivePassthroughExchanger; |
119 | | template <typename BlockType> |
120 | | friend class Exchanger; |
121 | | |
122 | | Block _data_block; |
123 | | LocalExchangeSharedState* _shared_state; |
124 | | std::vector<int> _channel_ids; |
125 | | const size_t _allocated_bytes; |
126 | | }; |
127 | | ExchangerBase(int running_sink_operators, int num_partitions, int free_block_limit) |
128 | 4 | : _running_sink_operators(running_sink_operators), |
129 | 4 | _running_source_operators(num_partitions), |
130 | 4 | _num_partitions(num_partitions), |
131 | 4 | _num_senders(running_sink_operators), |
132 | 4 | _num_sources(num_partitions), |
133 | 4 | _free_block_limit(free_block_limit) {} |
134 | | ExchangerBase(int running_sink_operators, int num_sources, int num_partitions, |
135 | | int free_block_limit) |
136 | 3 | : _running_sink_operators(running_sink_operators), |
137 | 3 | _running_source_operators(num_sources), |
138 | 3 | _num_partitions(num_partitions), |
139 | 3 | _num_senders(running_sink_operators), |
140 | 3 | _num_sources(num_sources), |
141 | 3 | _free_block_limit(free_block_limit) {} |
142 | 7 | virtual ~ExchangerBase() = default; |
143 | | virtual Status get_block(RuntimeState* state, Block* block, bool* eos, Profile&& profile, |
144 | | SourceInfo&& source_info) = 0; |
145 | | virtual Status sink(RuntimeState* state, Block* in_block, bool eos, Profile&& profile, |
146 | | SinkInfo& sink_info) = 0; |
147 | | virtual TLocalPartitionType::type get_type() const = 0; |
148 | | // Called if a local exchanger source operator are closed. Free the unused data block in data_queue. |
149 | | virtual void close(SourceInfo&& source_info) = 0; |
150 | | // Called if all local exchanger source operators are closed. We free the memory in |
151 | | // `_free_blocks` here. |
152 | | virtual void finalize(); |
153 | | |
154 | | virtual std::string data_queue_debug_string(int i) = 0; |
155 | | |
156 | 0 | void set_low_memory_mode() { |
157 | 0 | _free_block_limit = 0; |
158 | 0 | clear_blocks(_free_blocks); |
159 | 0 | } |
160 | | |
161 | | protected: |
162 | | friend struct LocalExchangeSharedState; |
163 | | friend class LocalExchangeSourceLocalState; |
164 | | friend class LocalExchangeSinkOperatorX; |
165 | | friend class LocalExchangeSinkLocalState; |
166 | | std::atomic<int> _running_sink_operators = 0; |
167 | | std::atomic<int> _running_source_operators = 0; |
168 | | const int _num_partitions; |
169 | | const int _num_senders; |
170 | | const int _num_sources; |
171 | | std::atomic_int _free_block_limit = 0; |
172 | | moodycamel::ConcurrentQueue<Block> _free_blocks; |
173 | | }; |
174 | | |
175 | | struct PartitionedRowIdxs { |
176 | | std::shared_ptr<PODArray<uint32_t>> row_idxs; |
177 | | uint32_t offset_start; |
178 | | uint32_t length; |
179 | | }; |
180 | | |
181 | | using PartitionedBlock = |
182 | | std::pair<std::shared_ptr<ExchangerBase::BlockWrapper>, PartitionedRowIdxs>; |
183 | | |
184 | | struct BroadcastRowRange { |
185 | | uint32_t offset_start; |
186 | | size_t length; |
187 | | }; |
188 | | using BroadcastBlock = std::pair<std::shared_ptr<ExchangerBase::BlockWrapper>, BroadcastRowRange>; |
189 | | |
190 | | template <typename BlockType> |
191 | | struct BlockQueue { |
192 | | std::atomic<bool> eos = false; |
193 | | moodycamel::ConcurrentQueue<BlockType> data_queue; |
194 | | moodycamel::ProducerToken ptok {data_queue}; |
195 | 25 | BlockQueue() : eos(false), data_queue(moodycamel::ConcurrentQueue<BlockType>()) {}_ZN5doris10BlockQueueISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_18PartitionedRowIdxsEEEC2Ev Line | Count | Source | 195 | 13 | BlockQueue() : eos(false), data_queue(moodycamel::ConcurrentQueue<BlockType>()) {} |
_ZN5doris10BlockQueueISt10shared_ptrINS_13ExchangerBase12BlockWrapperEEEC2Ev Line | Count | Source | 195 | 8 | BlockQueue() : eos(false), data_queue(moodycamel::ConcurrentQueue<BlockType>()) {} |
_ZN5doris10BlockQueueISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_17BroadcastRowRangeEEEC2Ev Line | Count | Source | 195 | 4 | BlockQueue() : eos(false), data_queue(moodycamel::ConcurrentQueue<BlockType>()) {} |
|
196 | | BlockQueue(BlockQueue<BlockType>&& other) |
197 | 0 | : eos(other.eos.load()), data_queue(std::move(other.data_queue)) {}Unexecuted instantiation: _ZN5doris10BlockQueueISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_18PartitionedRowIdxsEEEC2EOS8_ Unexecuted instantiation: _ZN5doris10BlockQueueISt10shared_ptrINS_13ExchangerBase12BlockWrapperEEEC2EOS5_ Unexecuted instantiation: _ZN5doris10BlockQueueISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_17BroadcastRowRangeEEEC2EOS8_ |
198 | | inline bool enqueue(BlockType const& item) { |
199 | | if (!eos) { |
200 | | if (!data_queue.enqueue(ptok, item)) [[unlikely]] { |
201 | | throw Exception(ErrorCode::INTERNAL_ERROR, |
202 | | "Exception occurs in data queue [size = {}] of local exchange.", |
203 | | data_queue.size_approx()); |
204 | | } |
205 | | return true; |
206 | | } |
207 | | return false; |
208 | | } |
209 | | |
210 | 162 | inline bool enqueue(BlockType&& item) { |
211 | 162 | if (!eos) { |
212 | 130 | if (!data_queue.enqueue(ptok, std::move(item))) [[unlikely]] { |
213 | 0 | throw Exception(ErrorCode::INTERNAL_ERROR, |
214 | 0 | "Exception occurs in data queue [size = {}] of local exchange.", |
215 | 0 | data_queue.size_approx()); |
216 | 0 | } |
217 | 130 | return true; |
218 | 130 | } |
219 | 32 | return false; |
220 | 162 | } _ZN5doris10BlockQueueISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_18PartitionedRowIdxsEEE7enqueueEOS7_ Line | Count | Source | 210 | 57 | inline bool enqueue(BlockType&& item) { | 211 | 57 | if (!eos) { | 212 | 49 | if (!data_queue.enqueue(ptok, std::move(item))) [[unlikely]] { | 213 | 0 | throw Exception(ErrorCode::INTERNAL_ERROR, | 214 | 0 | "Exception occurs in data queue [size = {}] of local exchange.", | 215 | 0 | data_queue.size_approx()); | 216 | 0 | } | 217 | 49 | return true; | 218 | 49 | } | 219 | 8 | return false; | 220 | 57 | } |
_ZN5doris10BlockQueueISt10shared_ptrINS_13ExchangerBase12BlockWrapperEEE7enqueueEOS4_ Line | Count | Source | 210 | 41 | inline bool enqueue(BlockType&& item) { | 211 | 41 | if (!eos) { | 212 | 33 | if (!data_queue.enqueue(ptok, std::move(item))) [[unlikely]] { | 213 | 0 | throw Exception(ErrorCode::INTERNAL_ERROR, | 214 | 0 | "Exception occurs in data queue [size = {}] of local exchange.", | 215 | 0 | data_queue.size_approx()); | 216 | 0 | } | 217 | 33 | return true; | 218 | 33 | } | 219 | 8 | return false; | 220 | 41 | } |
_ZN5doris10BlockQueueISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_17BroadcastRowRangeEEE7enqueueEOS7_ Line | Count | Source | 210 | 64 | inline bool enqueue(BlockType&& item) { | 211 | 64 | if (!eos) { | 212 | 48 | if (!data_queue.enqueue(ptok, std::move(item))) [[unlikely]] { | 213 | 0 | throw Exception(ErrorCode::INTERNAL_ERROR, | 214 | 0 | "Exception occurs in data queue [size = {}] of local exchange.", | 215 | 0 | data_queue.size_approx()); | 216 | 0 | } | 217 | 48 | return true; | 218 | 48 | } | 219 | 16 | return false; | 220 | 64 | } |
|
221 | | |
222 | 255 | bool try_dequeue(BlockType& item) { return data_queue.try_dequeue(item); }_ZN5doris10BlockQueueISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_18PartitionedRowIdxsEEE11try_dequeueERS7_ Line | Count | Source | 222 | 117 | bool try_dequeue(BlockType& item) { return data_queue.try_dequeue(item); } |
_ZN5doris10BlockQueueISt10shared_ptrINS_13ExchangerBase12BlockWrapperEEE11try_dequeueERS4_ Line | Count | Source | 222 | 66 | bool try_dequeue(BlockType& item) { return data_queue.try_dequeue(item); } |
_ZN5doris10BlockQueueISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_17BroadcastRowRangeEEE11try_dequeueERS7_ Line | Count | Source | 222 | 72 | bool try_dequeue(BlockType& item) { return data_queue.try_dequeue(item); } |
|
223 | | |
224 | 20 | void set_eos() { eos = true; }_ZN5doris10BlockQueueISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_18PartitionedRowIdxsEEE7set_eosEv Line | Count | Source | 224 | 8 | void set_eos() { eos = true; } |
_ZN5doris10BlockQueueISt10shared_ptrINS_13ExchangerBase12BlockWrapperEEE7set_eosEv Line | Count | Source | 224 | 8 | void set_eos() { eos = true; } |
_ZN5doris10BlockQueueISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_17BroadcastRowRangeEEE7set_eosEv Line | Count | Source | 224 | 4 | void set_eos() { eos = true; } |
|
225 | | }; |
226 | | |
227 | | using BlockWrapperSPtr = std::shared_ptr<ExchangerBase::BlockWrapper>; |
228 | | |
229 | | template <typename BlockType> |
230 | | class Exchanger : public ExchangerBase { |
231 | | public: |
232 | | Exchanger(int running_sink_operators, int num_partitions, int free_block_limit, |
233 | | TLocalPartitionType::type type) |
234 | 4 | : ExchangerBase(running_sink_operators, num_partitions, free_block_limit), _type(type) { |
235 | 4 | _data_queue.resize(num_partitions); |
236 | 4 | _m.resize(num_partitions); |
237 | 20 | for (size_t i = 0; i < num_partitions; i++) { |
238 | 16 | _m[i] = std::make_unique<std::mutex>(); |
239 | 16 | } |
240 | 4 | } _ZN5doris9ExchangerISt10shared_ptrINS_13ExchangerBase12BlockWrapperEEEC2EiiiNS_19TLocalPartitionType4typeE Line | Count | Source | 234 | 2 | : ExchangerBase(running_sink_operators, num_partitions, free_block_limit), _type(type) { | 235 | 2 | _data_queue.resize(num_partitions); | 236 | 2 | _m.resize(num_partitions); | 237 | 10 | for (size_t i = 0; i < num_partitions; i++) { | 238 | 8 | _m[i] = std::make_unique<std::mutex>(); | 239 | 8 | } | 240 | 2 | } |
_ZN5doris9ExchangerISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_17BroadcastRowRangeEEEC2EiiiNS_19TLocalPartitionType4typeE Line | Count | Source | 234 | 1 | : ExchangerBase(running_sink_operators, num_partitions, free_block_limit), _type(type) { | 235 | 1 | _data_queue.resize(num_partitions); | 236 | 1 | _m.resize(num_partitions); | 237 | 5 | for (size_t i = 0; i < num_partitions; i++) { | 238 | 4 | _m[i] = std::make_unique<std::mutex>(); | 239 | 4 | } | 240 | 1 | } |
_ZN5doris9ExchangerISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_18PartitionedRowIdxsEEEC2EiiiNS_19TLocalPartitionType4typeE Line | Count | Source | 234 | 1 | : ExchangerBase(running_sink_operators, num_partitions, free_block_limit), _type(type) { | 235 | 1 | _data_queue.resize(num_partitions); | 236 | 1 | _m.resize(num_partitions); | 237 | 5 | for (size_t i = 0; i < num_partitions; i++) { | 238 | 4 | _m[i] = std::make_unique<std::mutex>(); | 239 | 4 | } | 240 | 1 | } |
|
241 | | Exchanger(int running_sink_operators, int num_sources, int num_partitions, int free_block_limit, |
242 | | TLocalPartitionType::type type) |
243 | 3 | : ExchangerBase(running_sink_operators, num_sources, num_partitions, free_block_limit), |
244 | 3 | _type(type) { |
245 | 3 | _data_queue.resize(num_sources); |
246 | 3 | _m.resize(num_sources); |
247 | 12 | for (size_t i = 0; i < num_sources; i++) { |
248 | 9 | _m[i] = std::make_unique<std::mutex>(); |
249 | 9 | } |
250 | 3 | } |
251 | 7 | ~Exchanger() override = default; _ZN5doris9ExchangerISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_18PartitionedRowIdxsEEED2Ev Line | Count | Source | 251 | 4 | ~Exchanger() override = default; |
_ZN5doris9ExchangerISt10shared_ptrINS_13ExchangerBase12BlockWrapperEEED2Ev Line | Count | Source | 251 | 2 | ~Exchanger() override = default; |
_ZN5doris9ExchangerISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_17BroadcastRowRangeEEED2Ev Line | Count | Source | 251 | 1 | ~Exchanger() override = default; |
|
252 | 1 | TLocalPartitionType::type get_type() const override { return _type; }_ZNK5doris9ExchangerISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_18PartitionedRowIdxsEEE8get_typeEv Line | Count | Source | 252 | 1 | TLocalPartitionType::type get_type() const override { return _type; } |
Unexecuted instantiation: _ZNK5doris9ExchangerISt10shared_ptrINS_13ExchangerBase12BlockWrapperEEE8get_typeEv Unexecuted instantiation: _ZNK5doris9ExchangerISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_17BroadcastRowRangeEEE8get_typeEv |
253 | 0 | std::string data_queue_debug_string(int i) override { |
254 | 0 | return fmt::format("Data Queue {}: [size approx = {}, eos = {}]", i, |
255 | 0 | _data_queue[i].data_queue.size_approx(), _data_queue[i].eos); |
256 | 0 | } Unexecuted instantiation: _ZN5doris9ExchangerISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_18PartitionedRowIdxsEEE23data_queue_debug_stringB5cxx11Ei Unexecuted instantiation: _ZN5doris9ExchangerISt10shared_ptrINS_13ExchangerBase12BlockWrapperEEE23data_queue_debug_stringB5cxx11Ei Unexecuted instantiation: _ZN5doris9ExchangerISt4pairISt10shared_ptrINS_13ExchangerBase12BlockWrapperEENS_17BroadcastRowRangeEEE23data_queue_debug_stringB5cxx11Ei |
257 | | |
258 | | protected: |
259 | | // Enqueue data block and set downstream source operator to read. |
260 | | void _enqueue_data_and_set_ready(int channel_id, LocalExchangeSinkLocalState* local_state, |
261 | | BlockType&& block); |
262 | | bool _dequeue_data(LocalExchangeSourceLocalState* local_state, BlockType& block, bool* eos, |
263 | | Block* data_block, int channel_id); |
264 | | |
265 | | void _enqueue_data_and_set_ready(int channel_id, BlockType&& block); |
266 | | bool _dequeue_data(BlockType& block, bool* eos, Block* data_block, int channel_id); |
267 | | std::vector<BlockQueue<BlockType>> _data_queue; |
268 | | std::vector<std::unique_ptr<std::mutex>> _m; |
269 | | const TLocalPartitionType::type _type; |
270 | | }; |
271 | | |
272 | | class LocalExchangeSourceLocalState; |
273 | | class LocalExchangeSinkLocalState; |
274 | | |
275 | | class ShuffleExchanger : public Exchanger<PartitionedBlock> { |
276 | | public: |
277 | | ENABLE_FACTORY_CREATOR(ShuffleExchanger); |
278 | | ShuffleExchanger(int running_sink_operators, int num_sources, int num_partitions, |
279 | | int free_block_limit, TLocalPartitionType::type type) |
280 | 3 | : Exchanger<PartitionedBlock>(running_sink_operators, num_sources, num_partitions, |
281 | 3 | free_block_limit, type) { |
282 | 3 | DCHECK_GT(num_partitions, 0); |
283 | 3 | DCHECK_GT(num_sources, 0); |
284 | 3 | _partition_rows_histogram.resize(running_sink_operators); |
285 | 3 | } |
286 | 3 | ~ShuffleExchanger() override = default; |
287 | | Status sink(RuntimeState* state, Block* in_block, bool eos, Profile&& profile, |
288 | | SinkInfo& sink_info) override; |
289 | | |
290 | | Status get_block(RuntimeState* state, Block* block, bool* eos, Profile&& profile, |
291 | | SourceInfo&& source_info) override; |
292 | | void close(SourceInfo&& source_info) override; |
293 | | |
294 | | protected: |
295 | | Status _split_rows(RuntimeState* state, const std::vector<uint32_t>& channel_ids, Block* block, |
296 | | int channel_id, LocalExchangeSinkLocalState* local_state, |
297 | | std::map<int, int>* shuffle_idx_to_instance_idx); |
298 | | Status _split_rows(RuntimeState* state, const std::vector<uint32_t>& channel_ids, Block* block, |
299 | | int channel_id); |
300 | | std::vector<std::vector<uint32_t>> _partition_rows_histogram; |
301 | | }; |
302 | | |
303 | | class BucketShuffleExchanger final : public ShuffleExchanger { |
304 | | ENABLE_FACTORY_CREATOR(BucketShuffleExchanger); |
305 | | BucketShuffleExchanger(int running_sink_operators, int num_sources, int num_partitions, |
306 | | int free_block_limit) |
307 | 0 | : ShuffleExchanger(running_sink_operators, num_sources, num_partitions, |
308 | 0 | free_block_limit, TLocalPartitionType::BUCKET_HASH_SHUFFLE) {} |
309 | 0 | ~BucketShuffleExchanger() override = default; |
310 | | }; |
311 | | |
312 | | class PassthroughExchanger final : public Exchanger<BlockWrapperSPtr> { |
313 | | public: |
314 | | ENABLE_FACTORY_CREATOR(PassthroughExchanger); |
315 | | PassthroughExchanger(int running_sink_operators, int num_partitions, int free_block_limit) |
316 | 1 | : Exchanger<BlockWrapperSPtr>(running_sink_operators, num_partitions, free_block_limit, |
317 | 1 | TLocalPartitionType::PASSTHROUGH) {} |
318 | 1 | ~PassthroughExchanger() override = default; |
319 | | Status sink(RuntimeState* state, Block* in_block, bool eos, Profile&& profile, |
320 | | SinkInfo& sink_info) override; |
321 | | |
322 | | Status get_block(RuntimeState* state, Block* block, bool* eos, Profile&& profile, |
323 | | SourceInfo&& source_info) override; |
324 | | void close(SourceInfo&& source_info) override; |
325 | | }; |
326 | | |
327 | | class PassToOneExchanger final : public Exchanger<BlockWrapperSPtr> { |
328 | | public: |
329 | | ENABLE_FACTORY_CREATOR(PassToOneExchanger); |
330 | | PassToOneExchanger(int running_sink_operators, int num_partitions, int free_block_limit) |
331 | 1 | : Exchanger<BlockWrapperSPtr>(running_sink_operators, num_partitions, free_block_limit, |
332 | 1 | TLocalPartitionType::PASS_TO_ONE) {} |
333 | 1 | ~PassToOneExchanger() override = default; |
334 | | Status sink(RuntimeState* state, Block* in_block, bool eos, Profile&& profile, |
335 | | SinkInfo& sink_info) override; |
336 | | |
337 | | Status get_block(RuntimeState* state, Block* block, bool* eos, Profile&& profile, |
338 | | SourceInfo&& source_info) override; |
339 | | void close(SourceInfo&& source_info) override; |
340 | | }; |
341 | | class BroadcastExchanger final : public Exchanger<BroadcastBlock> { |
342 | | public: |
343 | | ENABLE_FACTORY_CREATOR(BroadcastExchanger); |
344 | | BroadcastExchanger(int running_sink_operators, int num_partitions, int free_block_limit) |
345 | 1 | : Exchanger<BroadcastBlock>(running_sink_operators, num_partitions, free_block_limit, |
346 | 1 | TLocalPartitionType::BROADCAST) {} |
347 | 1 | ~BroadcastExchanger() override = default; |
348 | | Status sink(RuntimeState* state, Block* in_block, bool eos, Profile&& profile, |
349 | | SinkInfo& sink_info) override; |
350 | | |
351 | | Status get_block(RuntimeState* state, Block* block, bool* eos, Profile&& profile, |
352 | | SourceInfo&& source_info) override; |
353 | | void close(SourceInfo&& source_info) override; |
354 | | }; |
355 | | |
356 | | //The code in AdaptivePassthroughExchanger is essentially |
357 | | // a copy of ShuffleExchanger and PassthroughExchanger. |
358 | | class AdaptivePassthroughExchanger : public Exchanger<PartitionedBlock> { |
359 | | public: |
360 | | ENABLE_FACTORY_CREATOR(AdaptivePassthroughExchanger); |
361 | | AdaptivePassthroughExchanger(int running_sink_operators, int num_partitions, |
362 | | int free_block_limit) |
363 | 1 | : Exchanger<PartitionedBlock>(running_sink_operators, num_partitions, free_block_limit, |
364 | 1 | TLocalPartitionType::ADAPTIVE_PASSTHROUGH) { |
365 | 1 | _partition_rows_histogram.resize(running_sink_operators); |
366 | 1 | _tmp_eos.resize(num_partitions); |
367 | 1 | _tmp_block.resize(num_partitions); |
368 | 1 | } |
369 | | Status sink(RuntimeState* state, Block* in_block, bool eos, Profile&& profile, |
370 | | SinkInfo& sink_info) override; |
371 | | |
372 | | Status get_block(RuntimeState* state, Block* block, bool* eos, Profile&& profile, |
373 | | SourceInfo&& source_info) override; |
374 | | |
375 | | void close(SourceInfo&& source_info) override; |
376 | | |
377 | | private: |
378 | | Status _passthrough_sink(RuntimeState* state, Block* in_block, SinkInfo& sink_info); |
379 | | Status _shuffle_sink(RuntimeState* state, Block* in_block, SinkInfo& sink_info); |
380 | | Status _split_rows(RuntimeState* state, const std::vector<uint32_t>& channel_ids, Block* block, |
381 | | SinkInfo& sink_info); |
382 | | |
383 | | std::atomic_bool _is_pass_through = false; |
384 | | std::atomic_int32_t _total_block = 0; |
385 | | std::vector<std::vector<uint32_t>> _partition_rows_histogram; |
386 | | |
387 | | std::vector<Block> _tmp_block; |
388 | | std::vector<bool> _tmp_eos; |
389 | | }; |
390 | | } // namespace doris |