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 | | #include "load/memtable/memtable.h" |
19 | | |
20 | | #include <fmt/format.h> |
21 | | #include <gen_cpp/olap_file.pb.h> |
22 | | #include <pdqsort.h> |
23 | | |
24 | | #include <algorithm> |
25 | | #include <limits> |
26 | | #include <optional> |
27 | | #include <string> |
28 | | #include <vector> |
29 | | |
30 | | #include "bvar/bvar.h" |
31 | | #include "common/config.h" |
32 | | #include "core/column/column.h" |
33 | | #include "exprs/aggregate/aggregate_function_reader.h" |
34 | | #include "exprs/aggregate/aggregate_function_simple_factory.h" |
35 | | #include "load/delta_writer/delta_writer_context.h" |
36 | | #include "load/memtable/memtable_memory_limiter.h" |
37 | | #include "runtime/descriptors.h" |
38 | | #include "runtime/exec_env.h" |
39 | | #include "runtime/runtime_profile.h" |
40 | | #include "runtime/thread_context.h" |
41 | | #include "runtime/workload_management/resource_context.h" |
42 | | #include "storage/olap_define.h" |
43 | | #include "storage/tablet/tablet_schema.h" |
44 | | #include "util/debug_points.h" |
45 | | #include "util/stopwatch.hpp" |
46 | | |
47 | | namespace doris { |
48 | | |
49 | | bvar::Adder<int64_t> g_memtable_cnt("memtable_cnt"); |
50 | | bvar::Adder<uint64_t> g_flush_cuz_memtable_full("flush_cuz_memtable_full"); |
51 | | |
52 | | using namespace ErrorCode; |
53 | | |
54 | | MemTable::MemTable(int64_t tablet_id, std::shared_ptr<TabletSchema> tablet_schema, |
55 | | const std::vector<SlotDescriptor*>* slot_descs, TupleDescriptor* tuple_desc, |
56 | | bool enable_unique_key_mow, PartialUpdateInfo* partial_update_info, |
57 | | const std::shared_ptr<ResourceContext>& resource_ctx, bool need_row_binlog_lsn) |
58 | 88.7k | : _mem_type(MemType::ACTIVE), |
59 | 88.7k | _tablet_id(tablet_id), |
60 | 88.7k | _enable_unique_key_mow(enable_unique_key_mow), |
61 | 88.7k | _keys_type(tablet_schema->keys_type()), |
62 | 88.7k | _tablet_schema(tablet_schema), |
63 | 88.7k | _resource_ctx(resource_ctx), |
64 | 88.7k | _need_row_binlog_lsn(need_row_binlog_lsn), |
65 | 88.7k | _is_first_insertion(true), |
66 | 88.7k | _agg_functions(tablet_schema->num_columns()), |
67 | 88.7k | _offsets_of_aggregate_states(tablet_schema->num_columns()), |
68 | 88.7k | _total_size_of_aggregate_states(0) { |
69 | 88.7k | g_memtable_cnt << 1; |
70 | 88.7k | _mem_tracker = std::make_shared<MemTracker>(); |
71 | 88.7k | SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER( |
72 | 88.7k | _resource_ctx->memory_context()->mem_tracker()->write_tracker()); |
73 | 88.7k | SCOPED_CONSUME_MEM_TRACKER(_mem_tracker); |
74 | 88.7k | _vec_row_comparator = std::make_shared<RowInBlockComparator>(_tablet_schema); |
75 | 88.8k | if (partial_update_info != nullptr) { |
76 | 88.8k | _partial_update_mode = partial_update_info->update_mode(); |
77 | 88.8k | if (_partial_update_mode == UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS) { |
78 | 1.69k | if (partial_update_info->is_schema_contains_auto_inc_column && |
79 | 1.69k | !partial_update_info->is_input_columns_contains_auto_inc_column) { |
80 | 49 | _is_partial_update_and_auto_inc = true; |
81 | 49 | } |
82 | 1.69k | } |
83 | 88.8k | } |
84 | 88.7k | _init_columns_offset_by_slot_descs(slot_descs, tuple_desc); |
85 | | // TODO: Support ZOrderComparator in the future |
86 | 88.7k | _row_in_blocks = std::make_unique<DorisVector<RowInBlock>>(); |
87 | 88.7k | _load_mem_limit = MemInfo::mem_limit() * config::load_process_max_memory_limit_percent / 100; |
88 | 88.7k | } |
89 | | |
90 | | void MemTable::_init_columns_offset_by_slot_descs(const std::vector<SlotDescriptor*>* slot_descs, |
91 | 88.5k | const TupleDescriptor* tuple_desc) { |
92 | 758k | for (auto slot_desc : *slot_descs) { |
93 | 758k | const auto& slots = tuple_desc->slots(); |
94 | 7.56M | for (int j = 0; j < slots.size(); ++j) { |
95 | 7.55M | if (slot_desc->id() == slots[j]->id()) { |
96 | 753k | _column_offset.emplace_back(j); |
97 | 753k | break; |
98 | 753k | } |
99 | 7.55M | } |
100 | 758k | } |
101 | 88.5k | if (_is_partial_update_and_auto_inc) { |
102 | 49 | _column_offset.emplace_back(_column_offset.size()); |
103 | 49 | } |
104 | 88.5k | _num_columns = _column_offset.size(); |
105 | 88.5k | } |
106 | | |
107 | 44.6k | void MemTable::_init_agg_functions(const Block* block) { |
108 | 44.6k | if (_num_columns > _column_offset.size()) [[unlikely]] { |
109 | 0 | throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR, |
110 | 0 | "num_columns {} is greater than block columns {}", _num_columns, |
111 | 0 | _column_offset.size()); |
112 | 0 | } |
113 | 404k | for (auto cid = _tablet_schema->num_key_columns(); cid < _num_columns; ++cid) { |
114 | 360k | AggregateFunctionPtr function; |
115 | 360k | if (_keys_type == KeysType::UNIQUE_KEYS && _enable_unique_key_mow) { |
116 | | // In such table, non-key column's aggregation type is NONE, so we need to construct |
117 | | // the aggregate function manually. |
118 | 308k | if (_skip_bitmap_col_idx != cid) { |
119 | 307k | function = AggregateFunctionSimpleFactory::instance().get( |
120 | 307k | "replace_load", {block->get_data_type(cid)}, block->get_data_type(cid), |
121 | 307k | block->get_data_type(cid)->is_nullable(), |
122 | 307k | BeExecVersionManager::get_newest_version()); |
123 | 307k | } else { |
124 | 259 | function = AggregateFunctionSimpleFactory::instance().get( |
125 | 259 | "bitmap_intersect", {block->get_data_type(cid)}, block->get_data_type(cid), |
126 | 259 | false, BeExecVersionManager::get_newest_version()); |
127 | 259 | } |
128 | 308k | } else { |
129 | 52.1k | function = _tablet_schema->column(cid).get_aggregate_function( |
130 | 52.1k | AGG_LOAD_SUFFIX, _tablet_schema->column(cid).get_be_exec_version()); |
131 | 52.1k | if (function == nullptr) { |
132 | 0 | LOG(WARNING) << "column get aggregate function failed, column=" |
133 | 0 | << _tablet_schema->column(cid).name(); |
134 | 0 | } |
135 | 52.1k | } |
136 | | |
137 | 360k | DCHECK(function != nullptr); |
138 | 360k | const auto* input_column = _input_mutable_block.get_column_by_position(cid).get(); |
139 | 360k | const IColumn* columns[] = {input_column}; |
140 | 360k | function->check_input_columns_type(columns); |
141 | 360k | function->check_result_column_type(*_output_mutable_block.get_column_by_position(cid)); |
142 | 360k | _agg_functions[cid] = function; |
143 | 360k | } |
144 | | |
145 | 404k | for (auto cid = _tablet_schema->num_key_columns(); cid < _num_columns; ++cid) { |
146 | 360k | _offsets_of_aggregate_states[cid] = _total_size_of_aggregate_states; |
147 | 360k | _total_size_of_aggregate_states += _agg_functions[cid]->size_of_data(); |
148 | | |
149 | | // If not the last aggregate_state, we need pad it so that next aggregate_state will be aligned. |
150 | 360k | if (cid + 1 < _num_columns) { |
151 | 315k | size_t alignment_of_next_state = _agg_functions[cid + 1]->align_of_data(); |
152 | | |
153 | | /// Extend total_size to next alignment requirement |
154 | | /// Add padding by rounding up 'total_size_of_aggregate_states' to be a multiplier of alignment_of_next_state. |
155 | 315k | _total_size_of_aggregate_states = |
156 | 315k | (_total_size_of_aggregate_states + alignment_of_next_state - 1) / |
157 | 315k | alignment_of_next_state * alignment_of_next_state; |
158 | 315k | } |
159 | 360k | } |
160 | 44.6k | } |
161 | | |
162 | 88.8k | MemTable::~MemTable() { |
163 | 88.8k | SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER( |
164 | 88.8k | _resource_ctx->memory_context()->mem_tracker()->write_tracker()); |
165 | 88.8k | { |
166 | 88.8k | SCOPED_CONSUME_MEM_TRACKER(_mem_tracker); |
167 | 88.8k | g_memtable_cnt << -1; |
168 | 88.8k | if (_keys_type != KeysType::DUP_KEYS) { |
169 | 7.65M | for (const auto& row : *_row_in_blocks) { |
170 | 7.65M | if (!_has_agg(row)) { |
171 | 7.65M | continue; |
172 | 7.65M | } |
173 | | // We should release agg_places here, because they are not released when a |
174 | | // load is canceled. |
175 | 18.4E | for (size_t i = _tablet_schema->num_key_columns(); i < _num_columns; ++i) { |
176 | 0 | auto function = _agg_functions[i]; |
177 | 0 | DCHECK(function != nullptr); |
178 | 0 | function->destroy(_agg_place(row, i)); |
179 | 0 | } |
180 | 18.4E | } |
181 | 57.0k | } |
182 | | |
183 | 88.8k | _arena.clear(true); |
184 | 88.8k | _vec_row_comparator.reset(); |
185 | 88.8k | _row_in_blocks.reset(); |
186 | 88.8k | _agg_functions.clear(); |
187 | 88.8k | _input_mutable_block.clear(); |
188 | 88.8k | _output_mutable_block.clear(); |
189 | | // Reset the LSN sidecar to release its capacity tracked by the memtable tracker. |
190 | 88.8k | _output_row_binlog_lsns = DorisVector<int64_t>(); |
191 | 88.8k | } |
192 | 88.8k | if (_is_flush_success) { |
193 | | // If the memtable is flush success, then its memtracker's consumption should be 0 |
194 | 76.3k | if (_mem_tracker->consumption() != 0 && config::crash_in_memory_tracker_inaccurate) { |
195 | 0 | LOG(FATAL) << "memtable flush success but cosumption is not 0, it is " |
196 | 0 | << _mem_tracker->consumption(); |
197 | 0 | } |
198 | 76.3k | } |
199 | 88.8k | } |
200 | | |
201 | 389k | int RowInBlockComparator::operator()(const RowInBlock* left, const RowInBlock* right) const { |
202 | 389k | return _pblock->compare_at(left->_row_pos, right->_row_pos, _tablet_schema->num_key_columns(), |
203 | 389k | *_pblock, -1); |
204 | 389k | } |
205 | | |
206 | 136k | Status MemTable::insert(const Block* input_block, const TabletAddRowsPayload& rows) { |
207 | 136k | SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER( |
208 | 136k | _resource_ctx->memory_context()->mem_tracker()->write_tracker()); |
209 | 136k | SCOPED_CONSUME_MEM_TRACKER(_mem_tracker); |
210 | 136k | const auto& row_idxs = rows.row_idxs; |
211 | 136k | const auto& row_binlog_lsns = rows.row_binlog_lsns; |
212 | | |
213 | 136k | if (_need_row_binlog_lsn) { |
214 | 3 | if (row_binlog_lsns.empty()) { |
215 | 0 | return Status::InternalError( |
216 | 0 | "row binlog lsn is missing for memtable insert, " |
217 | 0 | "tablet_id={}", |
218 | 0 | _tablet_id); |
219 | 0 | } |
220 | 3 | DCHECK_EQ(row_binlog_lsns.size(), row_idxs.size()); |
221 | 136k | } else if (!row_binlog_lsns.empty()) { |
222 | 0 | return Status::InternalError( |
223 | 0 | "row binlog lsn is unexpectedly provided for memtable insert, tablet_id={}", |
224 | 0 | _tablet_id); |
225 | 0 | } |
226 | | |
227 | 136k | if (_is_first_insertion) { |
228 | 76.4k | _is_first_insertion = false; |
229 | 76.4k | auto clone_block = input_block->clone_without_columns(&_column_offset); |
230 | 76.4k | _input_mutable_block = MutableBlock::build_mutable_block(std::move(clone_block)); |
231 | 76.4k | _vec_row_comparator->set_block(&_input_mutable_block); |
232 | 76.4k | clone_block = input_block->clone_without_columns(&_column_offset); |
233 | 76.4k | _output_mutable_block = MutableBlock::build_mutable_block(std::move(clone_block)); |
234 | 76.4k | if (_tablet_schema->has_sequence_col()) { |
235 | 1.62k | if (_partial_update_mode == UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS) { |
236 | | // for unique key fixed partial update, sequence column index in block |
237 | | // may be different with the index in `_tablet_schema` |
238 | 869 | for (int32_t i = 0; i < clone_block.columns(); i++) { |
239 | 681 | if (clone_block.get_by_position(i).name == SEQUENCE_COL) { |
240 | 38 | _seq_col_idx_in_block = i; |
241 | 38 | break; |
242 | 38 | } |
243 | 681 | } |
244 | 1.40k | } else { |
245 | 1.40k | _seq_col_idx_in_block = _tablet_schema->sequence_col_idx(); |
246 | 1.40k | } |
247 | 1.62k | } |
248 | 76.4k | if (_partial_update_mode == UniqueKeyUpdateModePB::UPDATE_FLEXIBLE_COLUMNS && |
249 | 76.4k | _tablet_schema->has_skip_bitmap_col()) { |
250 | | // init of _skip_bitmap_col_idx and _delete_sign_col_idx must be before _init_agg_functions() |
251 | 265 | _skip_bitmap_col_idx = _tablet_schema->skip_bitmap_col_idx(); |
252 | 265 | _delete_sign_col_idx = _tablet_schema->delete_sign_idx(); |
253 | 265 | _delete_sign_col_unique_id = _tablet_schema->column(_delete_sign_col_idx).unique_id(); |
254 | 265 | if (_seq_col_idx_in_block != -1) { |
255 | 25 | _seq_col_unique_id = _tablet_schema->column(_seq_col_idx_in_block).unique_id(); |
256 | 25 | } |
257 | 265 | } |
258 | 76.4k | if (_keys_type != KeysType::DUP_KEYS) { |
259 | | // there may be additional intermediate columns in input_block |
260 | | // we only need columns indicated by column offset in the output |
261 | 44.6k | RETURN_IF_CATCH_EXCEPTION(_init_agg_functions(&clone_block)); |
262 | 44.6k | } |
263 | 76.4k | } |
264 | | |
265 | 136k | auto num_rows = row_idxs.size(); |
266 | 136k | size_t cursor_in_mutableblock = _input_mutable_block.rows(); |
267 | 136k | RETURN_IF_ERROR(_input_mutable_block.add_rows(input_block, row_idxs.data(), |
268 | 136k | row_idxs.data() + num_rows, &_column_offset)); |
269 | 36.3M | for (int i = 0; i < num_rows; i++) { |
270 | 36.1M | _row_in_blocks->emplace_back(cursor_in_mutableblock + i, |
271 | 36.1M | _need_row_binlog_lsn ? row_binlog_lsns[i] : 0); |
272 | 36.1M | } |
273 | | |
274 | 136k | _stat.raw_rows += num_rows; |
275 | 136k | return Status::OK(); |
276 | 136k | } |
277 | | |
278 | 78.6k | void MemTable::_merge_row_binlog_lsn(const RowInBlock& src_row, RowInBlock& dst_row) { |
279 | 78.6k | if (_need_row_binlog_lsn) { |
280 | 0 | dst_row._row_binlog_lsn = std::max(dst_row._row_binlog_lsn, src_row._row_binlog_lsn); |
281 | 0 | } |
282 | 78.6k | } |
283 | | |
284 | 36.7M | void MemTable::_append_output_row_binlog_lsn(const RowInBlock& row) { |
285 | 36.7M | if (_need_row_binlog_lsn) { |
286 | 6 | _output_row_binlog_lsns.emplace_back(row._row_binlog_lsn); |
287 | 6 | } |
288 | 36.7M | } |
289 | | |
290 | | void MemTable::_aggregate_two_row_with_sequence_map(MutableBlock& mutable_block, |
291 | | const RowInBlock& src_row, |
292 | 3 | RowInBlock& dst_row) { |
293 | 3 | _merge_row_binlog_lsn(src_row, dst_row); |
294 | | // for each mapping replace value columns according to the sequence column compare result |
295 | | // for example: a b c d s1 s2 (key:a , s1=>[b,c], s2=>[d]) |
296 | | // src row: 1 4 5 6 8 9 |
297 | | // dst row: 1 2 3 4 7 10 |
298 | | // after aggregate |
299 | | // dst row: 1 4 5 4 8 10 (b,c,s1 will be replaced, d,s2) |
300 | 3 | const auto& seq_map = _tablet_schema->seq_col_idx_to_value_cols_idx(); |
301 | 6 | for (const auto& it : seq_map) { |
302 | 6 | auto sequence = it.first; |
303 | 6 | auto* sequence_col_ptr = mutable_block.mutable_columns()[sequence].get(); |
304 | 6 | auto res = sequence_col_ptr->compare_at(dst_row._row_pos, src_row._row_pos, |
305 | 6 | *sequence_col_ptr, -1); |
306 | 6 | if (res > 0) { |
307 | 2 | continue; |
308 | 2 | } |
309 | 5 | for (auto cid : it.second) { |
310 | 5 | if (cid < _num_columns) { |
311 | 5 | auto* col_ptr = mutable_block.mutable_columns()[cid].get(); |
312 | 5 | _agg_functions[cid]->add(_agg_place(dst_row, cid), |
313 | 5 | const_cast<const doris::IColumn**>(&col_ptr), |
314 | 5 | src_row._row_pos, _arena); |
315 | 5 | } |
316 | 5 | } |
317 | 4 | if (sequence < _num_columns) { |
318 | 4 | _agg_functions[sequence]->add(_agg_place(dst_row, sequence), |
319 | 4 | const_cast<const doris::IColumn**>(&sequence_col_ptr), |
320 | 4 | src_row._row_pos, _arena); |
321 | | // must use replace column instead of update row_pos |
322 | | // because one row may have multi sequence column |
323 | | // and agg function add method won't change the real column value |
324 | 4 | sequence_col_ptr->replace_column_data(*sequence_col_ptr, src_row._row_pos, |
325 | 4 | dst_row._row_pos); |
326 | 4 | } |
327 | 4 | } |
328 | 3 | } |
329 | | |
330 | | template <bool has_skip_bitmap_col> |
331 | | void MemTable::_aggregate_two_row_in_block(MutableBlock& mutable_block, const RowInBlock& src_row, |
332 | 78.7k | RowInBlock& dst_row) { |
333 | 78.7k | _merge_row_binlog_lsn(src_row, dst_row); |
334 | | // for flexible partial update, the caller must guarantees that either src_row and dst_row |
335 | | // both specify the sequence column, or src_row and dst_row both don't specify the |
336 | | // sequence column |
337 | 78.7k | if (_tablet_schema->has_sequence_col() && _seq_col_idx_in_block >= 0) { |
338 | 192 | DCHECK_LT(_seq_col_idx_in_block, mutable_block.columns()); |
339 | 192 | auto col_ptr = mutable_block.mutable_columns()[_seq_col_idx_in_block].get(); |
340 | 192 | auto res = col_ptr->compare_at(dst_row._row_pos, src_row._row_pos, *col_ptr, -1); |
341 | | // dst sequence column larger than src, don't need to update |
342 | 192 | if (res > 0) { |
343 | 91 | return; |
344 | 91 | } |
345 | | // need to update the row pos in dst row to the src row pos when has |
346 | | // sequence column |
347 | 101 | dst_row._row_pos = src_row._row_pos; |
348 | 101 | } |
349 | | // dst is non-sequence row, or dst sequence is smaller |
350 | 78.6k | if constexpr (!has_skip_bitmap_col) { |
351 | 74.6k | DCHECK(_skip_bitmap_col_idx == -1); |
352 | 346k | for (size_t cid = _tablet_schema->num_key_columns(); cid < _num_columns; ++cid) { |
353 | 271k | auto* col_ptr = mutable_block.mutable_columns()[cid].get(); |
354 | 271k | _agg_functions[cid]->add(_agg_place(dst_row, cid), |
355 | 271k | const_cast<const doris::IColumn**>(&col_ptr), src_row._row_pos, |
356 | 271k | _arena); |
357 | 271k | } |
358 | 74.6k | } else { |
359 | 3.95k | DCHECK(_skip_bitmap_col_idx != -1); |
360 | 3.95k | DCHECK_LT(_skip_bitmap_col_idx, mutable_block.columns()); |
361 | 3.95k | const BitmapValue& skip_bitmap = |
362 | 3.95k | assert_cast<ColumnBitmap*, TypeCheckOnRelease::DISABLE>( |
363 | 3.95k | mutable_block.mutable_columns()[_skip_bitmap_col_idx].get()) |
364 | 3.95k | ->get_data()[src_row._row_pos]; |
365 | 71.1k | for (size_t cid = _tablet_schema->num_key_columns(); cid < _num_columns; ++cid) { |
366 | 67.1k | const auto& col = _tablet_schema->column(cid); |
367 | 67.1k | if (cid != _skip_bitmap_col_idx && skip_bitmap.contains(col.unique_id())) { |
368 | 33.8k | continue; |
369 | 33.8k | } |
370 | 33.2k | auto* col_ptr = mutable_block.mutable_columns()[cid].get(); |
371 | 33.2k | _agg_functions[cid]->add(_agg_place(dst_row, cid), |
372 | 33.2k | const_cast<const doris::IColumn**>(&col_ptr), src_row._row_pos, |
373 | 33.2k | _arena); |
374 | 33.2k | } |
375 | 3.95k | } |
376 | 78.6k | } _ZN5doris8MemTable27_aggregate_two_row_in_blockILb0EEEvRNS_12MutableBlockERKNS_10RowInBlockERS4_ Line | Count | Source | 332 | 74.7k | RowInBlock& dst_row) { | 333 | 74.7k | _merge_row_binlog_lsn(src_row, dst_row); | 334 | | // for flexible partial update, the caller must guarantees that either src_row and dst_row | 335 | | // both specify the sequence column, or src_row and dst_row both don't specify the | 336 | | // sequence column | 337 | 74.7k | if (_tablet_schema->has_sequence_col() && _seq_col_idx_in_block >= 0) { | 338 | 192 | DCHECK_LT(_seq_col_idx_in_block, mutable_block.columns()); | 339 | 192 | auto col_ptr = mutable_block.mutable_columns()[_seq_col_idx_in_block].get(); | 340 | 192 | auto res = col_ptr->compare_at(dst_row._row_pos, src_row._row_pos, *col_ptr, -1); | 341 | | // dst sequence column larger than src, don't need to update | 342 | 192 | if (res > 0) { | 343 | 91 | return; | 344 | 91 | } | 345 | | // need to update the row pos in dst row to the src row pos when has | 346 | | // sequence column | 347 | 101 | dst_row._row_pos = src_row._row_pos; | 348 | 101 | } | 349 | | // dst is non-sequence row, or dst sequence is smaller | 350 | 74.6k | if constexpr (!has_skip_bitmap_col) { | 351 | 74.6k | DCHECK(_skip_bitmap_col_idx == -1); | 352 | 346k | for (size_t cid = _tablet_schema->num_key_columns(); cid < _num_columns; ++cid) { | 353 | 271k | auto* col_ptr = mutable_block.mutable_columns()[cid].get(); | 354 | 271k | _agg_functions[cid]->add(_agg_place(dst_row, cid), | 355 | 271k | const_cast<const doris::IColumn**>(&col_ptr), src_row._row_pos, | 356 | 271k | _arena); | 357 | 271k | } | 358 | | } else { | 359 | | DCHECK(_skip_bitmap_col_idx != -1); | 360 | | DCHECK_LT(_skip_bitmap_col_idx, mutable_block.columns()); | 361 | | const BitmapValue& skip_bitmap = | 362 | | assert_cast<ColumnBitmap*, TypeCheckOnRelease::DISABLE>( | 363 | | mutable_block.mutable_columns()[_skip_bitmap_col_idx].get()) | 364 | | ->get_data()[src_row._row_pos]; | 365 | | for (size_t cid = _tablet_schema->num_key_columns(); cid < _num_columns; ++cid) { | 366 | | const auto& col = _tablet_schema->column(cid); | 367 | | if (cid != _skip_bitmap_col_idx && skip_bitmap.contains(col.unique_id())) { | 368 | | continue; | 369 | | } | 370 | | auto* col_ptr = mutable_block.mutable_columns()[cid].get(); | 371 | | _agg_functions[cid]->add(_agg_place(dst_row, cid), | 372 | | const_cast<const doris::IColumn**>(&col_ptr), src_row._row_pos, | 373 | | _arena); | 374 | | } | 375 | | } | 376 | 74.6k | } |
_ZN5doris8MemTable27_aggregate_two_row_in_blockILb1EEEvRNS_12MutableBlockERKNS_10RowInBlockERS4_ Line | Count | Source | 332 | 3.95k | RowInBlock& dst_row) { | 333 | 3.95k | _merge_row_binlog_lsn(src_row, dst_row); | 334 | | // for flexible partial update, the caller must guarantees that either src_row and dst_row | 335 | | // both specify the sequence column, or src_row and dst_row both don't specify the | 336 | | // sequence column | 337 | 3.95k | if (_tablet_schema->has_sequence_col() && _seq_col_idx_in_block >= 0) { | 338 | 0 | DCHECK_LT(_seq_col_idx_in_block, mutable_block.columns()); | 339 | 0 | auto col_ptr = mutable_block.mutable_columns()[_seq_col_idx_in_block].get(); | 340 | 0 | auto res = col_ptr->compare_at(dst_row._row_pos, src_row._row_pos, *col_ptr, -1); | 341 | | // dst sequence column larger than src, don't need to update | 342 | 0 | if (res > 0) { | 343 | 0 | return; | 344 | 0 | } | 345 | | // need to update the row pos in dst row to the src row pos when has | 346 | | // sequence column | 347 | 0 | dst_row._row_pos = src_row._row_pos; | 348 | 0 | } | 349 | | // dst is non-sequence row, or dst sequence is smaller | 350 | | if constexpr (!has_skip_bitmap_col) { | 351 | | DCHECK(_skip_bitmap_col_idx == -1); | 352 | | for (size_t cid = _tablet_schema->num_key_columns(); cid < _num_columns; ++cid) { | 353 | | auto* col_ptr = mutable_block.mutable_columns()[cid].get(); | 354 | | _agg_functions[cid]->add(_agg_place(dst_row, cid), | 355 | | const_cast<const doris::IColumn**>(&col_ptr), src_row._row_pos, | 356 | | _arena); | 357 | | } | 358 | 3.95k | } else { | 359 | 3.95k | DCHECK(_skip_bitmap_col_idx != -1); | 360 | 3.95k | DCHECK_LT(_skip_bitmap_col_idx, mutable_block.columns()); | 361 | 3.95k | const BitmapValue& skip_bitmap = | 362 | 3.95k | assert_cast<ColumnBitmap*, TypeCheckOnRelease::DISABLE>( | 363 | 3.95k | mutable_block.mutable_columns()[_skip_bitmap_col_idx].get()) | 364 | 3.95k | ->get_data()[src_row._row_pos]; | 365 | 71.1k | for (size_t cid = _tablet_schema->num_key_columns(); cid < _num_columns; ++cid) { | 366 | 67.1k | const auto& col = _tablet_schema->column(cid); | 367 | 67.1k | if (cid != _skip_bitmap_col_idx && skip_bitmap.contains(col.unique_id())) { | 368 | 33.8k | continue; | 369 | 33.8k | } | 370 | 33.2k | auto* col_ptr = mutable_block.mutable_columns()[cid].get(); | 371 | 33.2k | _agg_functions[cid]->add(_agg_place(dst_row, cid), | 372 | 33.2k | const_cast<const doris::IColumn**>(&col_ptr), src_row._row_pos, | 373 | 33.2k | _arena); | 374 | 33.2k | } | 375 | 3.95k | } | 376 | 3.95k | } |
|
377 | 73.7k | Status MemTable::_put_into_output(Block& in_block) { |
378 | 73.7k | SCOPED_RAW_TIMER(&_stat.put_into_output_ns); |
379 | 73.7k | DorisVector<uint32_t> row_pos_vec; |
380 | 73.7k | DCHECK(in_block.rows() <= std::numeric_limits<int>::max()); |
381 | 73.7k | row_pos_vec.reserve(in_block.rows()); |
382 | 73.7k | if (_need_row_binlog_lsn) { |
383 | 3 | _output_row_binlog_lsns.reserve(_output_row_binlog_lsns.size() + in_block.rows()); |
384 | 3 | } |
385 | 35.6M | for (const auto& row : *_row_in_blocks) { |
386 | 35.6M | row_pos_vec.emplace_back(row._row_pos); |
387 | 35.6M | _append_output_row_binlog_lsn(row); |
388 | 35.6M | } |
389 | 73.7k | return _output_mutable_block.add_rows(&in_block, row_pos_vec.data(), |
390 | 73.7k | row_pos_vec.data() + in_block.rows()); |
391 | 73.7k | } |
392 | | |
393 | | void MemTable::_sort_one_column(DorisVector<RowInBlock>& row_in_blocks, Tie& tie, |
394 | 182k | std::function<int(const RowInBlock&, const RowInBlock&)> cmp) { |
395 | 182k | auto iter = tie.iter(); |
396 | 3.69M | while (iter.next()) { |
397 | 3.51M | pdqsort(std::next(row_in_blocks.begin(), static_cast<int>(iter.left())), |
398 | 3.51M | std::next(row_in_blocks.begin(), static_cast<int>(iter.right())), |
399 | 241M | [&cmp](const RowInBlock& lhs, const RowInBlock& rhs) -> bool { |
400 | 241M | return cmp(lhs, rhs) < 0; |
401 | 241M | }); |
402 | 3.51M | tie[iter.left()] = 0; |
403 | 50.9M | for (auto i = iter.left() + 1; i < iter.right(); i++) { |
404 | 47.4M | tie[i] = (cmp(row_in_blocks[i - 1], row_in_blocks[i]) == 0); |
405 | 47.4M | } |
406 | 3.51M | } |
407 | 182k | } |
408 | | |
409 | 76.2k | size_t MemTable::_sort() { |
410 | 76.2k | SCOPED_RAW_TIMER(&_stat.sort_ns); |
411 | 76.2k | _stat.sort_times++; |
412 | 76.2k | size_t same_keys_num = 0; |
413 | | // sort new rows |
414 | 76.2k | Tie tie = Tie(_last_sorted_pos, _row_in_blocks->size()); |
415 | 255k | for (size_t i = 0; i < _tablet_schema->num_key_columns(); i++) { |
416 | 273M | auto cmp = [&](const RowInBlock& lhs, const RowInBlock& rhs) -> int { |
417 | 273M | return _input_mutable_block.compare_one_column(lhs._row_pos, rhs._row_pos, i, -1); |
418 | 273M | }; |
419 | 178k | _sort_one_column(*_row_in_blocks, tie, cmp); |
420 | 178k | } |
421 | 76.2k | bool is_dup = (_keys_type == KeysType::DUP_KEYS); |
422 | | // sort extra round by _row_pos to make the sort stable |
423 | 76.2k | auto iter = tie.iter(); |
424 | 214k | while (iter.next()) { |
425 | 138k | pdqsort(std::next(_row_in_blocks->begin(), iter.left()), |
426 | 138k | std::next(_row_in_blocks->begin(), iter.right()), |
427 | 65.0M | [&is_dup](const RowInBlock& lhs, const RowInBlock& rhs) -> bool { |
428 | 65.0M | return is_dup ? lhs._row_pos > rhs._row_pos : lhs._row_pos < rhs._row_pos; |
429 | 65.0M | }); |
430 | 138k | same_keys_num += iter.right() - iter.left(); |
431 | 138k | } |
432 | | // merge new rows and old rows |
433 | 76.2k | _vec_row_comparator->set_block(&_input_mutable_block); |
434 | 76.2k | auto cmp_func = [this, is_dup, &same_keys_num](const RowInBlock& l, |
435 | 76.2k | const RowInBlock& r) -> bool { |
436 | 17 | auto value = (*(this->_vec_row_comparator))(&l, &r); |
437 | 17 | if (value == 0) { |
438 | 8 | same_keys_num++; |
439 | 8 | return is_dup ? l._row_pos > r._row_pos : l._row_pos < r._row_pos; |
440 | 9 | } else { |
441 | 9 | return value < 0; |
442 | 9 | } |
443 | 17 | }; |
444 | 76.2k | auto new_row_it = std::next(_row_in_blocks->begin(), _last_sorted_pos); |
445 | 76.2k | std::inplace_merge(_row_in_blocks->begin(), new_row_it, _row_in_blocks->end(), cmp_func); |
446 | 76.2k | _last_sorted_pos = _row_in_blocks->size(); |
447 | 76.2k | return same_keys_num; |
448 | 76.2k | } |
449 | | |
450 | 1.54k | Status MemTable::_sort_by_cluster_keys() { |
451 | 1.54k | SCOPED_RAW_TIMER(&_stat.sort_ns); |
452 | 1.54k | _stat.sort_times++; |
453 | | // sort all rows |
454 | 1.54k | Block in_block = _output_mutable_block.to_block(); |
455 | 1.54k | auto clone_block = in_block.clone_without_columns(); |
456 | 1.54k | MutableBlock mutable_block = MutableBlock::build_mutable_block(std::move(in_block)); |
457 | 1.54k | _output_mutable_block = MutableBlock::build_mutable_block(std::move(clone_block)); |
458 | | |
459 | 1.54k | DorisVector<RowInBlock> row_in_blocks; |
460 | 1.54k | row_in_blocks.reserve(mutable_block.rows()); |
461 | 1.54k | if (_need_row_binlog_lsn) { |
462 | 0 | DCHECK_EQ(_output_row_binlog_lsns.size(), mutable_block.rows()); |
463 | 0 | } |
464 | 699k | for (size_t i = 0; i < mutable_block.rows(); i++) { |
465 | 698k | row_in_blocks.emplace_back(i, _need_row_binlog_lsn ? _output_row_binlog_lsns[i] : 0); |
466 | 698k | } |
467 | 1.54k | if (_need_row_binlog_lsn) { |
468 | 0 | _output_row_binlog_lsns.clear(); |
469 | 0 | _output_row_binlog_lsns.reserve(mutable_block.rows()); |
470 | 0 | } |
471 | 1.54k | Tie tie = Tie(0, mutable_block.rows()); |
472 | | |
473 | 3.69k | for (auto cid : _tablet_schema->cluster_key_uids()) { |
474 | 3.69k | auto index = _tablet_schema->field_index(cid); |
475 | 3.69k | if (index == -1) { |
476 | 0 | return Status::InternalError("could not find cluster key column with unique_id=" + |
477 | 0 | std::to_string(cid) + " in tablet schema"); |
478 | 0 | } |
479 | 7.20M | auto cmp = [&](const RowInBlock& lhs, const RowInBlock& rhs) -> int { |
480 | 7.20M | return mutable_block.compare_one_column(lhs._row_pos, rhs._row_pos, index, -1); |
481 | 7.20M | }; |
482 | 3.69k | _sort_one_column(row_in_blocks, tie, cmp); |
483 | 3.69k | } |
484 | | |
485 | | // sort extra round by _row_pos to make the sort stable |
486 | 1.54k | auto iter = tie.iter(); |
487 | 119k | while (iter.next()) { |
488 | 118k | pdqsort(std::next(row_in_blocks.begin(), iter.left()), |
489 | 118k | std::next(row_in_blocks.begin(), iter.right()), |
490 | 848k | [](const RowInBlock& lhs, const RowInBlock& rhs) -> bool { |
491 | 848k | return lhs._row_pos < rhs._row_pos; |
492 | 848k | }); |
493 | 118k | } |
494 | | |
495 | 1.54k | in_block = mutable_block.to_block(); |
496 | 1.54k | SCOPED_RAW_TIMER(&_stat.put_into_output_ns); |
497 | 1.54k | DorisVector<uint32_t> row_pos_vec; |
498 | 1.54k | DCHECK(in_block.rows() <= std::numeric_limits<int>::max()); |
499 | 1.54k | row_pos_vec.reserve(in_block.rows()); |
500 | 820k | for (const auto& row : row_in_blocks) { |
501 | 820k | row_pos_vec.emplace_back(row._row_pos); |
502 | 820k | _append_output_row_binlog_lsn(row); |
503 | 820k | } |
504 | 1.54k | std::vector<int> column_offset; |
505 | 21.4k | for (int i = 0; i < _column_offset.size(); ++i) { |
506 | 19.8k | column_offset.emplace_back(i); |
507 | 19.8k | } |
508 | 1.54k | return _output_mutable_block.add_rows(&in_block, row_pos_vec.data(), |
509 | 1.54k | row_pos_vec.data() + in_block.rows(), &column_offset); |
510 | 1.54k | } |
511 | | |
512 | | template <bool is_final> |
513 | 313k | void MemTable::_finalize_one_row(RowInBlock& row, MutableBlock& mutable_block, int row_pos) { |
514 | | // move key columns |
515 | 830k | for (size_t i = 0; i < _tablet_schema->num_key_columns(); ++i) { |
516 | 516k | _output_mutable_block.get_column_by_position(i)->insert_from( |
517 | 516k | *mutable_block.get_column_by_position(i), row._row_pos); |
518 | 516k | } |
519 | 313k | if (_has_agg(row)) { |
520 | | // get value columns from agg_places |
521 | 82.3k | for (size_t i = _tablet_schema->num_key_columns(); i < _num_columns; ++i) { |
522 | 73.9k | auto function = _agg_functions[i]; |
523 | 73.9k | auto* agg_place = _agg_place(row, i); |
524 | 73.9k | auto* col_ptr = _output_mutable_block.get_column_by_position(i).get(); |
525 | 73.9k | function->insert_result_into(agg_place, *col_ptr); |
526 | | |
527 | 73.9k | if constexpr (is_final) { |
528 | 73.8k | function->destroy(agg_place); |
529 | 73.8k | } else { |
530 | 8 | function->reset(agg_place); |
531 | 8 | } |
532 | 73.9k | } |
533 | | |
534 | 8.43k | if constexpr (is_final) { |
535 | 8.43k | row._agg_mem = nullptr; |
536 | 8.43k | } else { |
537 | 13 | for (size_t i = _tablet_schema->num_key_columns(); i < _num_columns; ++i) { |
538 | 8 | auto function = _agg_functions[i]; |
539 | 8 | auto* agg_place = _agg_place(row, i); |
540 | 8 | auto* col_ptr = _output_mutable_block.get_column_by_position(i).get(); |
541 | 8 | function->add(agg_place, const_cast<const doris::IColumn**>(&col_ptr), row_pos, |
542 | 8 | _arena); |
543 | 8 | } |
544 | 5 | } |
545 | 305k | } else { |
546 | | // move columns for rows do not need agg |
547 | 5.62M | for (size_t i = _tablet_schema->num_key_columns(); i < _num_columns; ++i) { |
548 | 5.32M | _output_mutable_block.get_column_by_position(i)->insert_from( |
549 | 5.32M | *mutable_block.get_column_by_position(i), row._row_pos); |
550 | 5.32M | } |
551 | 305k | } |
552 | 313k | _append_output_row_binlog_lsn(row); |
553 | 313k | if constexpr (!is_final) { |
554 | 8 | row._row_pos = row_pos; |
555 | 8 | } |
556 | 313k | } _ZN5doris8MemTable17_finalize_one_rowILb0EEEvRNS_10RowInBlockERNS_12MutableBlockEi Line | Count | Source | 513 | 8 | void MemTable::_finalize_one_row(RowInBlock& row, MutableBlock& mutable_block, int row_pos) { | 514 | | // move key columns | 515 | 24 | for (size_t i = 0; i < _tablet_schema->num_key_columns(); ++i) { | 516 | 16 | _output_mutable_block.get_column_by_position(i)->insert_from( | 517 | 16 | *mutable_block.get_column_by_position(i), row._row_pos); | 518 | 16 | } | 519 | 8 | if (_has_agg(row)) { | 520 | | // get value columns from agg_places | 521 | 13 | for (size_t i = _tablet_schema->num_key_columns(); i < _num_columns; ++i) { | 522 | 8 | auto function = _agg_functions[i]; | 523 | 8 | auto* agg_place = _agg_place(row, i); | 524 | 8 | auto* col_ptr = _output_mutable_block.get_column_by_position(i).get(); | 525 | 8 | function->insert_result_into(agg_place, *col_ptr); | 526 | | | 527 | | if constexpr (is_final) { | 528 | | function->destroy(agg_place); | 529 | 8 | } else { | 530 | 8 | function->reset(agg_place); | 531 | 8 | } | 532 | 8 | } | 533 | | | 534 | | if constexpr (is_final) { | 535 | | row._agg_mem = nullptr; | 536 | 5 | } else { | 537 | 13 | for (size_t i = _tablet_schema->num_key_columns(); i < _num_columns; ++i) { | 538 | 8 | auto function = _agg_functions[i]; | 539 | 8 | auto* agg_place = _agg_place(row, i); | 540 | 8 | auto* col_ptr = _output_mutable_block.get_column_by_position(i).get(); | 541 | 8 | function->add(agg_place, const_cast<const doris::IColumn**>(&col_ptr), row_pos, | 542 | 8 | _arena); | 543 | 8 | } | 544 | 5 | } | 545 | 5 | } else { | 546 | | // move columns for rows do not need agg | 547 | 9 | for (size_t i = _tablet_schema->num_key_columns(); i < _num_columns; ++i) { | 548 | 6 | _output_mutable_block.get_column_by_position(i)->insert_from( | 549 | 6 | *mutable_block.get_column_by_position(i), row._row_pos); | 550 | 6 | } | 551 | 3 | } | 552 | 8 | _append_output_row_binlog_lsn(row); | 553 | 8 | if constexpr (!is_final) { | 554 | 8 | row._row_pos = row_pos; | 555 | 8 | } | 556 | 8 | } |
_ZN5doris8MemTable17_finalize_one_rowILb1EEEvRNS_10RowInBlockERNS_12MutableBlockEi Line | Count | Source | 513 | 313k | void MemTable::_finalize_one_row(RowInBlock& row, MutableBlock& mutable_block, int row_pos) { | 514 | | // move key columns | 515 | 830k | for (size_t i = 0; i < _tablet_schema->num_key_columns(); ++i) { | 516 | 516k | _output_mutable_block.get_column_by_position(i)->insert_from( | 517 | 516k | *mutable_block.get_column_by_position(i), row._row_pos); | 518 | 516k | } | 519 | 313k | if (_has_agg(row)) { | 520 | | // get value columns from agg_places | 521 | 82.3k | for (size_t i = _tablet_schema->num_key_columns(); i < _num_columns; ++i) { | 522 | 73.8k | auto function = _agg_functions[i]; | 523 | 73.8k | auto* agg_place = _agg_place(row, i); | 524 | 73.8k | auto* col_ptr = _output_mutable_block.get_column_by_position(i).get(); | 525 | 73.8k | function->insert_result_into(agg_place, *col_ptr); | 526 | | | 527 | 73.8k | if constexpr (is_final) { | 528 | 73.8k | function->destroy(agg_place); | 529 | | } else { | 530 | | function->reset(agg_place); | 531 | | } | 532 | 73.8k | } | 533 | | | 534 | 8.43k | if constexpr (is_final) { | 535 | 8.43k | row._agg_mem = nullptr; | 536 | | } else { | 537 | | for (size_t i = _tablet_schema->num_key_columns(); i < _num_columns; ++i) { | 538 | | auto function = _agg_functions[i]; | 539 | | auto* agg_place = _agg_place(row, i); | 540 | | auto* col_ptr = _output_mutable_block.get_column_by_position(i).get(); | 541 | | function->add(agg_place, const_cast<const doris::IColumn**>(&col_ptr), row_pos, | 542 | | _arena); | 543 | | } | 544 | | } | 545 | 305k | } else { | 546 | | // move columns for rows do not need agg | 547 | 5.62M | for (size_t i = _tablet_schema->num_key_columns(); i < _num_columns; ++i) { | 548 | 5.32M | _output_mutable_block.get_column_by_position(i)->insert_from( | 549 | 5.32M | *mutable_block.get_column_by_position(i), row._row_pos); | 550 | 5.32M | } | 551 | 305k | } | 552 | 313k | _append_output_row_binlog_lsn(row); | 553 | | if constexpr (!is_final) { | 554 | | row._row_pos = row_pos; | 555 | | } | 556 | 313k | } |
|
557 | | |
558 | 8.43k | void MemTable::_init_row_for_agg(RowInBlock& row, MutableBlock& mutable_block) { |
559 | 8.43k | row._agg_mem = _arena.aligned_alloc(_total_size_of_aggregate_states, 16); |
560 | 82.0k | for (auto cid = _tablet_schema->num_key_columns(); cid < _num_columns; cid++) { |
561 | 73.6k | auto* col_ptr = mutable_block.mutable_columns()[cid].get(); |
562 | 73.6k | auto* data = _agg_place(row, cid); |
563 | 73.6k | _agg_functions[cid]->create(data); |
564 | 73.6k | _agg_functions[cid]->add(data, const_cast<const doris::IColumn**>(&col_ptr), row._row_pos, |
565 | 73.6k | _arena); |
566 | 73.6k | } |
567 | 8.43k | } |
568 | 74.4k | void MemTable::_clear_row_agg(RowInBlock& row) { |
569 | 74.4k | if (_has_agg(row)) { |
570 | 54 | for (size_t i = _tablet_schema->num_key_columns(); i < _num_columns; ++i) { |
571 | 48 | auto function = _agg_functions[i]; |
572 | 48 | auto* agg_place = _agg_place(row, i); |
573 | 48 | function->destroy(agg_place); |
574 | 48 | } |
575 | 6 | row._agg_mem = nullptr; |
576 | 6 | } |
577 | 74.4k | } |
578 | | // only in `to_block` the `is_final` flag will be true, in other cases, it will be false |
579 | | template <bool is_final, bool has_skip_bitmap_col> |
580 | 2.18k | void MemTable::_aggregate() { |
581 | 2.18k | SCOPED_RAW_TIMER(&_stat.agg_ns); |
582 | 2.18k | _stat.agg_times++; |
583 | 2.18k | Block in_block = _input_mutable_block.to_block(); |
584 | 2.18k | std::unique_ptr<Block> empty_input_block = in_block.create_same_struct_block(0); |
585 | 2.18k | MutableBlock mutable_block = MutableBlock::build_mutable_block(std::move(in_block)); |
586 | 2.18k | _vec_row_comparator->set_block(&mutable_block); |
587 | 2.18k | DorisVector<RowInBlock> temp_row_in_blocks; |
588 | | // Rows are held by value, so prev_row below points into temp_row_in_blocks. |
589 | | // Reserving the upper bound up front keeps that pointer valid for the whole |
590 | | // loop. |
591 | 2.18k | temp_row_in_blocks.reserve(_row_in_blocks->size()); |
592 | | //only init agg if needed |
593 | | |
594 | 2.18k | if constexpr (!has_skip_bitmap_col) { |
595 | 2.01k | RowInBlock* prev_row = nullptr; |
596 | 2.01k | int row_pos = -1; |
597 | 385k | for (RowInBlock& cur_row : *_row_in_blocks) { |
598 | 385k | if (!temp_row_in_blocks.empty() && (*_vec_row_comparator)(prev_row, &cur_row) == 0) { |
599 | 74.1k | if (!_has_agg(*prev_row)) { |
600 | 6.99k | _init_row_for_agg(*prev_row, mutable_block); |
601 | 6.99k | } |
602 | 74.1k | _stat.merged_rows++; |
603 | 74.1k | if (_tablet_schema->has_seq_map()) { |
604 | 3 | _aggregate_two_row_with_sequence_map(mutable_block, cur_row, *prev_row); |
605 | 74.1k | } else { |
606 | 74.1k | _aggregate_two_row_in_block<has_skip_bitmap_col>(mutable_block, cur_row, |
607 | 74.1k | *prev_row); |
608 | 74.1k | } |
609 | | |
610 | | // Clean up aggregation state of the merged row to avoid memory leak |
611 | 74.1k | _clear_row_agg(cur_row); |
612 | 311k | } else { |
613 | 311k | if (!temp_row_in_blocks.empty()) { |
614 | | // The rows from the previous batch of _row_in_blocks have been merged into temp_row_in_blocks, |
615 | | // now call finalize to write the aggregation results into _output_mutable_block. |
616 | 309k | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, row_pos); |
617 | 309k | } |
618 | | // Aggregation mutates the group representative, and the copy that |
619 | | // _finalize_one_row will read is the one in temp_row_in_blocks, so |
620 | | // prev_row has to point there rather than into _row_in_blocks. |
621 | 311k | temp_row_in_blocks.push_back(cur_row); |
622 | 311k | prev_row = &temp_row_in_blocks.back(); |
623 | 311k | row_pos++; |
624 | 311k | } |
625 | 385k | } |
626 | 2.02k | if (!temp_row_in_blocks.empty()) { |
627 | | // finalize the last low |
628 | 2.02k | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, row_pos); |
629 | 2.02k | } |
630 | 2.01k | } else { |
631 | 175 | DCHECK(_delete_sign_col_idx != -1); |
632 | 175 | if (_seq_col_idx_in_block == -1) { |
633 | 160 | _aggregate_for_flexible_partial_update_without_seq_col<is_final>(mutable_block, |
634 | 160 | temp_row_in_blocks); |
635 | 160 | } else { |
636 | 15 | _aggregate_for_flexible_partial_update_with_seq_col<is_final>(mutable_block, |
637 | 15 | temp_row_in_blocks); |
638 | 15 | } |
639 | 175 | } |
640 | 2.18k | if constexpr (!is_final) { |
641 | | // if is not final, we collect the agg results to input_block and then continue to insert |
642 | 3 | _input_mutable_block.swap(_output_mutable_block); |
643 | | //TODO(weixang):opt here. |
644 | 3 | _output_mutable_block = MutableBlock::build_mutable_block(std::move(*empty_input_block)); |
645 | 3 | _output_mutable_block.clear_column_data(); |
646 | 3 | _output_row_binlog_lsns.clear(); |
647 | 3 | } |
648 | | // Rows are held by value, so the entries left in _row_in_blocks are stale |
649 | | // copies of the ones _finalize_one_row just worked on -- including their |
650 | | // _agg_mem, whose state it may have released. Adopting the finalized rows |
651 | | // unconditionally keeps ~MemTable from destroying a state a second time. |
652 | 2.18k | *_row_in_blocks = std::move(temp_row_in_blocks); |
653 | 2.18k | _last_sorted_pos = _row_in_blocks->size(); |
654 | 2.18k | } _ZN5doris8MemTable10_aggregateILb0ELb0EEEvv Line | Count | Source | 580 | 3 | void MemTable::_aggregate() { | 581 | 3 | SCOPED_RAW_TIMER(&_stat.agg_ns); | 582 | 3 | _stat.agg_times++; | 583 | 3 | Block in_block = _input_mutable_block.to_block(); | 584 | 3 | std::unique_ptr<Block> empty_input_block = in_block.create_same_struct_block(0); | 585 | 3 | MutableBlock mutable_block = MutableBlock::build_mutable_block(std::move(in_block)); | 586 | 3 | _vec_row_comparator->set_block(&mutable_block); | 587 | 3 | DorisVector<RowInBlock> temp_row_in_blocks; | 588 | | // Rows are held by value, so prev_row below points into temp_row_in_blocks. | 589 | | // Reserving the upper bound up front keeps that pointer valid for the whole | 590 | | // loop. | 591 | 3 | temp_row_in_blocks.reserve(_row_in_blocks->size()); | 592 | | //only init agg if needed | 593 | | | 594 | 3 | if constexpr (!has_skip_bitmap_col) { | 595 | 3 | RowInBlock* prev_row = nullptr; | 596 | 3 | int row_pos = -1; | 597 | 13 | for (RowInBlock& cur_row : *_row_in_blocks) { | 598 | 13 | if (!temp_row_in_blocks.empty() && (*_vec_row_comparator)(prev_row, &cur_row) == 0) { | 599 | 5 | if (!_has_agg(*prev_row)) { | 600 | 4 | _init_row_for_agg(*prev_row, mutable_block); | 601 | 4 | } | 602 | 5 | _stat.merged_rows++; | 603 | 5 | if (_tablet_schema->has_seq_map()) { | 604 | 0 | _aggregate_two_row_with_sequence_map(mutable_block, cur_row, *prev_row); | 605 | 5 | } else { | 606 | 5 | _aggregate_two_row_in_block<has_skip_bitmap_col>(mutable_block, cur_row, | 607 | 5 | *prev_row); | 608 | 5 | } | 609 | | | 610 | | // Clean up aggregation state of the merged row to avoid memory leak | 611 | 5 | _clear_row_agg(cur_row); | 612 | 8 | } else { | 613 | 8 | if (!temp_row_in_blocks.empty()) { | 614 | | // The rows from the previous batch of _row_in_blocks have been merged into temp_row_in_blocks, | 615 | | // now call finalize to write the aggregation results into _output_mutable_block. | 616 | 5 | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, row_pos); | 617 | 5 | } | 618 | | // Aggregation mutates the group representative, and the copy that | 619 | | // _finalize_one_row will read is the one in temp_row_in_blocks, so | 620 | | // prev_row has to point there rather than into _row_in_blocks. | 621 | 8 | temp_row_in_blocks.push_back(cur_row); | 622 | 8 | prev_row = &temp_row_in_blocks.back(); | 623 | 8 | row_pos++; | 624 | 8 | } | 625 | 13 | } | 626 | 3 | if (!temp_row_in_blocks.empty()) { | 627 | | // finalize the last low | 628 | 3 | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, row_pos); | 629 | 3 | } | 630 | | } else { | 631 | | DCHECK(_delete_sign_col_idx != -1); | 632 | | if (_seq_col_idx_in_block == -1) { | 633 | | _aggregate_for_flexible_partial_update_without_seq_col<is_final>(mutable_block, | 634 | | temp_row_in_blocks); | 635 | | } else { | 636 | | _aggregate_for_flexible_partial_update_with_seq_col<is_final>(mutable_block, | 637 | | temp_row_in_blocks); | 638 | | } | 639 | | } | 640 | 3 | if constexpr (!is_final) { | 641 | | // if is not final, we collect the agg results to input_block and then continue to insert | 642 | 3 | _input_mutable_block.swap(_output_mutable_block); | 643 | | //TODO(weixang):opt here. | 644 | 3 | _output_mutable_block = MutableBlock::build_mutable_block(std::move(*empty_input_block)); | 645 | 3 | _output_mutable_block.clear_column_data(); | 646 | 3 | _output_row_binlog_lsns.clear(); | 647 | 3 | } | 648 | | // Rows are held by value, so the entries left in _row_in_blocks are stale | 649 | | // copies of the ones _finalize_one_row just worked on -- including their | 650 | | // _agg_mem, whose state it may have released. Adopting the finalized rows | 651 | | // unconditionally keeps ~MemTable from destroying a state a second time. | 652 | 3 | *_row_in_blocks = std::move(temp_row_in_blocks); | 653 | 3 | _last_sorted_pos = _row_in_blocks->size(); | 654 | 3 | } |
Unexecuted instantiation: _ZN5doris8MemTable10_aggregateILb0ELb1EEEvv _ZN5doris8MemTable10_aggregateILb1ELb0EEEvv Line | Count | Source | 580 | 2.01k | void MemTable::_aggregate() { | 581 | 2.01k | SCOPED_RAW_TIMER(&_stat.agg_ns); | 582 | 2.01k | _stat.agg_times++; | 583 | 2.01k | Block in_block = _input_mutable_block.to_block(); | 584 | 2.01k | std::unique_ptr<Block> empty_input_block = in_block.create_same_struct_block(0); | 585 | 2.01k | MutableBlock mutable_block = MutableBlock::build_mutable_block(std::move(in_block)); | 586 | 2.01k | _vec_row_comparator->set_block(&mutable_block); | 587 | 2.01k | DorisVector<RowInBlock> temp_row_in_blocks; | 588 | | // Rows are held by value, so prev_row below points into temp_row_in_blocks. | 589 | | // Reserving the upper bound up front keeps that pointer valid for the whole | 590 | | // loop. | 591 | 2.01k | temp_row_in_blocks.reserve(_row_in_blocks->size()); | 592 | | //only init agg if needed | 593 | | | 594 | 2.01k | if constexpr (!has_skip_bitmap_col) { | 595 | 2.01k | RowInBlock* prev_row = nullptr; | 596 | 2.01k | int row_pos = -1; | 597 | 385k | for (RowInBlock& cur_row : *_row_in_blocks) { | 598 | 385k | if (!temp_row_in_blocks.empty() && (*_vec_row_comparator)(prev_row, &cur_row) == 0) { | 599 | 74.1k | if (!_has_agg(*prev_row)) { | 600 | 6.98k | _init_row_for_agg(*prev_row, mutable_block); | 601 | 6.98k | } | 602 | 74.1k | _stat.merged_rows++; | 603 | 74.1k | if (_tablet_schema->has_seq_map()) { | 604 | 3 | _aggregate_two_row_with_sequence_map(mutable_block, cur_row, *prev_row); | 605 | 74.1k | } else { | 606 | 74.1k | _aggregate_two_row_in_block<has_skip_bitmap_col>(mutable_block, cur_row, | 607 | 74.1k | *prev_row); | 608 | 74.1k | } | 609 | | | 610 | | // Clean up aggregation state of the merged row to avoid memory leak | 611 | 74.1k | _clear_row_agg(cur_row); | 612 | 311k | } else { | 613 | 311k | if (!temp_row_in_blocks.empty()) { | 614 | | // The rows from the previous batch of _row_in_blocks have been merged into temp_row_in_blocks, | 615 | | // now call finalize to write the aggregation results into _output_mutable_block. | 616 | 309k | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, row_pos); | 617 | 309k | } | 618 | | // Aggregation mutates the group representative, and the copy that | 619 | | // _finalize_one_row will read is the one in temp_row_in_blocks, so | 620 | | // prev_row has to point there rather than into _row_in_blocks. | 621 | 311k | temp_row_in_blocks.push_back(cur_row); | 622 | 311k | prev_row = &temp_row_in_blocks.back(); | 623 | 311k | row_pos++; | 624 | 311k | } | 625 | 385k | } | 626 | 2.02k | if (!temp_row_in_blocks.empty()) { | 627 | | // finalize the last low | 628 | 2.02k | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, row_pos); | 629 | 2.02k | } | 630 | | } else { | 631 | | DCHECK(_delete_sign_col_idx != -1); | 632 | | if (_seq_col_idx_in_block == -1) { | 633 | | _aggregate_for_flexible_partial_update_without_seq_col<is_final>(mutable_block, | 634 | | temp_row_in_blocks); | 635 | | } else { | 636 | | _aggregate_for_flexible_partial_update_with_seq_col<is_final>(mutable_block, | 637 | | temp_row_in_blocks); | 638 | | } | 639 | | } | 640 | | if constexpr (!is_final) { | 641 | | // if is not final, we collect the agg results to input_block and then continue to insert | 642 | | _input_mutable_block.swap(_output_mutable_block); | 643 | | //TODO(weixang):opt here. | 644 | | _output_mutable_block = MutableBlock::build_mutable_block(std::move(*empty_input_block)); | 645 | | _output_mutable_block.clear_column_data(); | 646 | | _output_row_binlog_lsns.clear(); | 647 | | } | 648 | | // Rows are held by value, so the entries left in _row_in_blocks are stale | 649 | | // copies of the ones _finalize_one_row just worked on -- including their | 650 | | // _agg_mem, whose state it may have released. Adopting the finalized rows | 651 | | // unconditionally keeps ~MemTable from destroying a state a second time. | 652 | 2.01k | *_row_in_blocks = std::move(temp_row_in_blocks); | 653 | 2.01k | _last_sorted_pos = _row_in_blocks->size(); | 654 | 2.01k | } |
_ZN5doris8MemTable10_aggregateILb1ELb1EEEvv Line | Count | Source | 580 | 175 | void MemTable::_aggregate() { | 581 | 175 | SCOPED_RAW_TIMER(&_stat.agg_ns); | 582 | 175 | _stat.agg_times++; | 583 | 175 | Block in_block = _input_mutable_block.to_block(); | 584 | 175 | std::unique_ptr<Block> empty_input_block = in_block.create_same_struct_block(0); | 585 | 175 | MutableBlock mutable_block = MutableBlock::build_mutable_block(std::move(in_block)); | 586 | 175 | _vec_row_comparator->set_block(&mutable_block); | 587 | 175 | DorisVector<RowInBlock> temp_row_in_blocks; | 588 | | // Rows are held by value, so prev_row below points into temp_row_in_blocks. | 589 | | // Reserving the upper bound up front keeps that pointer valid for the whole | 590 | | // loop. | 591 | 175 | temp_row_in_blocks.reserve(_row_in_blocks->size()); | 592 | | //only init agg if needed | 593 | | | 594 | | if constexpr (!has_skip_bitmap_col) { | 595 | | RowInBlock* prev_row = nullptr; | 596 | | int row_pos = -1; | 597 | | for (RowInBlock& cur_row : *_row_in_blocks) { | 598 | | if (!temp_row_in_blocks.empty() && (*_vec_row_comparator)(prev_row, &cur_row) == 0) { | 599 | | if (!_has_agg(*prev_row)) { | 600 | | _init_row_for_agg(*prev_row, mutable_block); | 601 | | } | 602 | | _stat.merged_rows++; | 603 | | if (_tablet_schema->has_seq_map()) { | 604 | | _aggregate_two_row_with_sequence_map(mutable_block, cur_row, *prev_row); | 605 | | } else { | 606 | | _aggregate_two_row_in_block<has_skip_bitmap_col>(mutable_block, cur_row, | 607 | | *prev_row); | 608 | | } | 609 | | | 610 | | // Clean up aggregation state of the merged row to avoid memory leak | 611 | | _clear_row_agg(cur_row); | 612 | | } else { | 613 | | if (!temp_row_in_blocks.empty()) { | 614 | | // The rows from the previous batch of _row_in_blocks have been merged into temp_row_in_blocks, | 615 | | // now call finalize to write the aggregation results into _output_mutable_block. | 616 | | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, row_pos); | 617 | | } | 618 | | // Aggregation mutates the group representative, and the copy that | 619 | | // _finalize_one_row will read is the one in temp_row_in_blocks, so | 620 | | // prev_row has to point there rather than into _row_in_blocks. | 621 | | temp_row_in_blocks.push_back(cur_row); | 622 | | prev_row = &temp_row_in_blocks.back(); | 623 | | row_pos++; | 624 | | } | 625 | | } | 626 | | if (!temp_row_in_blocks.empty()) { | 627 | | // finalize the last low | 628 | | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, row_pos); | 629 | | } | 630 | 175 | } else { | 631 | 175 | DCHECK(_delete_sign_col_idx != -1); | 632 | 175 | if (_seq_col_idx_in_block == -1) { | 633 | 160 | _aggregate_for_flexible_partial_update_without_seq_col<is_final>(mutable_block, | 634 | 160 | temp_row_in_blocks); | 635 | 160 | } else { | 636 | 15 | _aggregate_for_flexible_partial_update_with_seq_col<is_final>(mutable_block, | 637 | 15 | temp_row_in_blocks); | 638 | 15 | } | 639 | 175 | } | 640 | | if constexpr (!is_final) { | 641 | | // if is not final, we collect the agg results to input_block and then continue to insert | 642 | | _input_mutable_block.swap(_output_mutable_block); | 643 | | //TODO(weixang):opt here. | 644 | | _output_mutable_block = MutableBlock::build_mutable_block(std::move(*empty_input_block)); | 645 | | _output_mutable_block.clear_column_data(); | 646 | | _output_row_binlog_lsns.clear(); | 647 | | } | 648 | | // Rows are held by value, so the entries left in _row_in_blocks are stale | 649 | | // copies of the ones _finalize_one_row just worked on -- including their | 650 | | // _agg_mem, whose state it may have released. Adopting the finalized rows | 651 | | // unconditionally keeps ~MemTable from destroying a state a second time. | 652 | 175 | *_row_in_blocks = std::move(temp_row_in_blocks); | 653 | 175 | _last_sorted_pos = _row_in_blocks->size(); | 654 | 175 | } |
|
655 | | |
656 | | template <bool is_final> |
657 | | void MemTable::_aggregate_for_flexible_partial_update_without_seq_col( |
658 | 160 | MutableBlock& mutable_block, DorisVector<RowInBlock>& temp_row_in_blocks) { |
659 | 160 | int row_pos = -1; |
660 | 160 | auto& skip_bitmaps = |
661 | 160 | assert_cast<ColumnBitmap*>(mutable_block.mutable_columns()[_skip_bitmap_col_idx].get()) |
662 | 160 | ->get_data(); |
663 | 160 | auto& delete_signs = |
664 | 160 | assert_cast<ColumnInt8*>(mutable_block.mutable_columns()[_delete_sign_col_idx].get()) |
665 | 160 | ->get_data(); |
666 | | // Rows are held by value here: a held row is only appended to |
667 | | // temp_row_in_blocks once its whole key group has been consumed, so it is |
668 | | // aggregated into while it lives in one of these two slots. |
669 | 160 | std::optional<RowInBlock> row_with_delete_sign; |
670 | 160 | std::optional<RowInBlock> row_without_delete_sign; |
671 | | |
672 | 1.91k | auto finalize_rows = [&]() { |
673 | 1.91k | if (row_with_delete_sign.has_value()) { |
674 | 14 | temp_row_in_blocks.push_back(*row_with_delete_sign); |
675 | 14 | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, ++row_pos); |
676 | 14 | row_with_delete_sign.reset(); |
677 | 14 | } |
678 | 1.91k | if (row_without_delete_sign.has_value()) { |
679 | 1.74k | temp_row_in_blocks.push_back(*row_without_delete_sign); |
680 | 1.74k | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, ++row_pos); |
681 | 1.74k | row_without_delete_sign.reset(); |
682 | 1.74k | } |
683 | | // _arena.clear(); |
684 | 1.91k | }; Unexecuted instantiation: _ZZN5doris8MemTable54_aggregate_for_flexible_partial_update_without_seq_colILb0EEEvRNS_12MutableBlockERSt6vectorINS_10RowInBlockENS_18CustomStdAllocatorIS5_NS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEEEEEENKUlvE_clEv _ZZN5doris8MemTable54_aggregate_for_flexible_partial_update_without_seq_colILb1EEEvRNS_12MutableBlockERSt6vectorINS_10RowInBlockENS_18CustomStdAllocatorIS5_NS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEEEEEENKUlvE_clEv Line | Count | Source | 672 | 1.91k | auto finalize_rows = [&]() { | 673 | 1.91k | if (row_with_delete_sign.has_value()) { | 674 | 14 | temp_row_in_blocks.push_back(*row_with_delete_sign); | 675 | 14 | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, ++row_pos); | 676 | 14 | row_with_delete_sign.reset(); | 677 | 14 | } | 678 | 1.91k | if (row_without_delete_sign.has_value()) { | 679 | 1.74k | temp_row_in_blocks.push_back(*row_without_delete_sign); | 680 | 1.74k | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, ++row_pos); | 681 | 1.74k | row_without_delete_sign.reset(); | 682 | 1.74k | } | 683 | | // _arena.clear(); | 684 | 1.91k | }; |
|
685 | | |
686 | 1.77k | auto add_row = [&](const RowInBlock& row, bool with_delete_sign) { |
687 | 1.77k | if (with_delete_sign) { |
688 | 14 | row_with_delete_sign = row; |
689 | 1.75k | } else { |
690 | 1.75k | row_without_delete_sign = row; |
691 | 1.75k | } |
692 | 1.77k | }; Unexecuted instantiation: _ZZN5doris8MemTable54_aggregate_for_flexible_partial_update_without_seq_colILb0EEEvRNS_12MutableBlockERSt6vectorINS_10RowInBlockENS_18CustomStdAllocatorIS5_NS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEEEEEENKUlRKS5_bE_clESE_b _ZZN5doris8MemTable54_aggregate_for_flexible_partial_update_without_seq_colILb1EEEvRNS_12MutableBlockERSt6vectorINS_10RowInBlockENS_18CustomStdAllocatorIS5_NS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEEEEEENKUlRKS5_bE_clESE_b Line | Count | Source | 686 | 1.77k | auto add_row = [&](const RowInBlock& row, bool with_delete_sign) { | 687 | 1.77k | if (with_delete_sign) { | 688 | 14 | row_with_delete_sign = row; | 689 | 1.75k | } else { | 690 | 1.75k | row_without_delete_sign = row; | 691 | 1.75k | } | 692 | 1.77k | }; |
|
693 | 5.72k | for (RowInBlock& cur_row : *_row_in_blocks) { |
694 | 5.72k | const BitmapValue& skip_bitmap = skip_bitmaps[cur_row._row_pos]; |
695 | 5.72k | bool cur_row_has_delete_sign = (!skip_bitmap.contains(_delete_sign_col_unique_id) && |
696 | 5.72k | delete_signs[cur_row._row_pos] != 0); |
697 | | // compare keys, the keys of row_with_delete_sign and row_without_delete_sign is the same, |
698 | | // choose any of them if it's valid |
699 | 5.72k | RowInBlock* prev_row = |
700 | 5.72k | row_with_delete_sign.has_value() |
701 | 5.72k | ? &row_with_delete_sign.value() |
702 | 5.72k | : (row_without_delete_sign.has_value() ? &row_without_delete_sign.value() |
703 | 5.67k | : nullptr); |
704 | 5.72k | if (prev_row != nullptr && (*_vec_row_comparator)(prev_row, &cur_row) == 0) { |
705 | 3.97k | if (cur_row_has_delete_sign) { |
706 | 24 | if (row_without_delete_sign.has_value()) { |
707 | | // if there exits row without delete sign, remove it first |
708 | 13 | _merge_row_binlog_lsn(*row_without_delete_sign, cur_row); |
709 | 13 | _clear_row_agg(*row_without_delete_sign); |
710 | 13 | _stat.merged_rows++; |
711 | 13 | row_without_delete_sign.reset(); |
712 | 13 | } |
713 | | // and then unconditionally replace the previous row |
714 | 24 | prev_row = |
715 | 24 | row_with_delete_sign.has_value() ? &row_with_delete_sign.value() : nullptr; |
716 | 3.95k | } else { |
717 | 3.95k | prev_row = row_without_delete_sign.has_value() ? &row_without_delete_sign.value() |
718 | 3.95k | : nullptr; |
719 | 3.95k | } |
720 | | |
721 | 3.97k | if (prev_row == nullptr) { |
722 | 17 | add_row(cur_row, cur_row_has_delete_sign); |
723 | 3.95k | } else { |
724 | 3.95k | if (!_has_agg(*prev_row)) { |
725 | 1.44k | _init_row_for_agg(*prev_row, mutable_block); |
726 | 1.44k | } |
727 | 3.95k | _stat.merged_rows++; |
728 | 3.95k | _aggregate_two_row_in_block<true>(mutable_block, cur_row, *prev_row); |
729 | 3.95k | } |
730 | 3.97k | } else { |
731 | 1.74k | finalize_rows(); |
732 | 1.74k | add_row(cur_row, cur_row_has_delete_sign); |
733 | 1.74k | } |
734 | 5.72k | } |
735 | | // finalize the last lows |
736 | 160 | finalize_rows(); |
737 | 160 | } Unexecuted instantiation: _ZN5doris8MemTable54_aggregate_for_flexible_partial_update_without_seq_colILb0EEEvRNS_12MutableBlockERSt6vectorINS_10RowInBlockENS_18CustomStdAllocatorIS5_NS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEEEEE _ZN5doris8MemTable54_aggregate_for_flexible_partial_update_without_seq_colILb1EEEvRNS_12MutableBlockERSt6vectorINS_10RowInBlockENS_18CustomStdAllocatorIS5_NS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEEEEE Line | Count | Source | 658 | 160 | MutableBlock& mutable_block, DorisVector<RowInBlock>& temp_row_in_blocks) { | 659 | 160 | int row_pos = -1; | 660 | 160 | auto& skip_bitmaps = | 661 | 160 | assert_cast<ColumnBitmap*>(mutable_block.mutable_columns()[_skip_bitmap_col_idx].get()) | 662 | 160 | ->get_data(); | 663 | 160 | auto& delete_signs = | 664 | 160 | assert_cast<ColumnInt8*>(mutable_block.mutable_columns()[_delete_sign_col_idx].get()) | 665 | 160 | ->get_data(); | 666 | | // Rows are held by value here: a held row is only appended to | 667 | | // temp_row_in_blocks once its whole key group has been consumed, so it is | 668 | | // aggregated into while it lives in one of these two slots. | 669 | 160 | std::optional<RowInBlock> row_with_delete_sign; | 670 | 160 | std::optional<RowInBlock> row_without_delete_sign; | 671 | | | 672 | 160 | auto finalize_rows = [&]() { | 673 | 160 | if (row_with_delete_sign.has_value()) { | 674 | 160 | temp_row_in_blocks.push_back(*row_with_delete_sign); | 675 | 160 | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, ++row_pos); | 676 | 160 | row_with_delete_sign.reset(); | 677 | 160 | } | 678 | 160 | if (row_without_delete_sign.has_value()) { | 679 | 160 | temp_row_in_blocks.push_back(*row_without_delete_sign); | 680 | 160 | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, ++row_pos); | 681 | 160 | row_without_delete_sign.reset(); | 682 | 160 | } | 683 | | // _arena.clear(); | 684 | 160 | }; | 685 | | | 686 | 160 | auto add_row = [&](const RowInBlock& row, bool with_delete_sign) { | 687 | 160 | if (with_delete_sign) { | 688 | 160 | row_with_delete_sign = row; | 689 | 160 | } else { | 690 | 160 | row_without_delete_sign = row; | 691 | 160 | } | 692 | 160 | }; | 693 | 5.72k | for (RowInBlock& cur_row : *_row_in_blocks) { | 694 | 5.72k | const BitmapValue& skip_bitmap = skip_bitmaps[cur_row._row_pos]; | 695 | 5.72k | bool cur_row_has_delete_sign = (!skip_bitmap.contains(_delete_sign_col_unique_id) && | 696 | 5.72k | delete_signs[cur_row._row_pos] != 0); | 697 | | // compare keys, the keys of row_with_delete_sign and row_without_delete_sign is the same, | 698 | | // choose any of them if it's valid | 699 | 5.72k | RowInBlock* prev_row = | 700 | 5.72k | row_with_delete_sign.has_value() | 701 | 5.72k | ? &row_with_delete_sign.value() | 702 | 5.72k | : (row_without_delete_sign.has_value() ? &row_without_delete_sign.value() | 703 | 5.67k | : nullptr); | 704 | 5.72k | if (prev_row != nullptr && (*_vec_row_comparator)(prev_row, &cur_row) == 0) { | 705 | 3.97k | if (cur_row_has_delete_sign) { | 706 | 24 | if (row_without_delete_sign.has_value()) { | 707 | | // if there exits row without delete sign, remove it first | 708 | 13 | _merge_row_binlog_lsn(*row_without_delete_sign, cur_row); | 709 | 13 | _clear_row_agg(*row_without_delete_sign); | 710 | 13 | _stat.merged_rows++; | 711 | 13 | row_without_delete_sign.reset(); | 712 | 13 | } | 713 | | // and then unconditionally replace the previous row | 714 | 24 | prev_row = | 715 | 24 | row_with_delete_sign.has_value() ? &row_with_delete_sign.value() : nullptr; | 716 | 3.95k | } else { | 717 | 3.95k | prev_row = row_without_delete_sign.has_value() ? &row_without_delete_sign.value() | 718 | 3.95k | : nullptr; | 719 | 3.95k | } | 720 | | | 721 | 3.97k | if (prev_row == nullptr) { | 722 | 17 | add_row(cur_row, cur_row_has_delete_sign); | 723 | 3.95k | } else { | 724 | 3.95k | if (!_has_agg(*prev_row)) { | 725 | 1.44k | _init_row_for_agg(*prev_row, mutable_block); | 726 | 1.44k | } | 727 | 3.95k | _stat.merged_rows++; | 728 | 3.95k | _aggregate_two_row_in_block<true>(mutable_block, cur_row, *prev_row); | 729 | 3.95k | } | 730 | 3.97k | } else { | 731 | 1.74k | finalize_rows(); | 732 | 1.74k | add_row(cur_row, cur_row_has_delete_sign); | 733 | 1.74k | } | 734 | 5.72k | } | 735 | | // finalize the last lows | 736 | 160 | finalize_rows(); | 737 | 160 | } |
|
738 | | |
739 | | template <bool is_final> |
740 | | void MemTable::_aggregate_for_flexible_partial_update_with_seq_col( |
741 | 15 | MutableBlock& mutable_block, DorisVector<RowInBlock>& temp_row_in_blocks) { |
742 | | // For flexible partial update, when table has sequence column, we don't do any aggregation |
743 | | // in memtable. These duplicate rows will be aggregated in VerticalSegmentWriter |
744 | 15 | int row_pos = -1; |
745 | 482 | for (const RowInBlock& row : *_row_in_blocks) { |
746 | 482 | temp_row_in_blocks.push_back(row); |
747 | 482 | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, ++row_pos); |
748 | 482 | } |
749 | 15 | } Unexecuted instantiation: _ZN5doris8MemTable51_aggregate_for_flexible_partial_update_with_seq_colILb0EEEvRNS_12MutableBlockERSt6vectorINS_10RowInBlockENS_18CustomStdAllocatorIS5_NS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEEEEE _ZN5doris8MemTable51_aggregate_for_flexible_partial_update_with_seq_colILb1EEEvRNS_12MutableBlockERSt6vectorINS_10RowInBlockENS_18CustomStdAllocatorIS5_NS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEEEEE Line | Count | Source | 741 | 15 | MutableBlock& mutable_block, DorisVector<RowInBlock>& temp_row_in_blocks) { | 742 | | // For flexible partial update, when table has sequence column, we don't do any aggregation | 743 | | // in memtable. These duplicate rows will be aggregated in VerticalSegmentWriter | 744 | 15 | int row_pos = -1; | 745 | 482 | for (const RowInBlock& row : *_row_in_blocks) { | 746 | 482 | temp_row_in_blocks.push_back(row); | 747 | 482 | _finalize_one_row<is_final>(temp_row_in_blocks.back(), mutable_block, ++row_pos); | 748 | 482 | } | 749 | 15 | } |
|
750 | | |
751 | 5 | void MemTable::shrink_memtable_by_agg() { |
752 | 5 | SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER( |
753 | 5 | _resource_ctx->memory_context()->mem_tracker()->write_tracker()); |
754 | 5 | SCOPED_CONSUME_MEM_TRACKER(_mem_tracker); |
755 | 5 | if (_keys_type == KeysType::DUP_KEYS) { |
756 | 0 | return; |
757 | 0 | } |
758 | 5 | size_t same_keys_num = _sort(); |
759 | 5 | if (same_keys_num != 0) { |
760 | 3 | (_skip_bitmap_col_idx == -1) ? _aggregate<false, false>() : _aggregate<false, true>(); |
761 | 3 | } |
762 | 5 | _last_agg_pos = memory_usage(); |
763 | 5 | } |
764 | | |
765 | 136k | bool MemTable::need_flush() const { |
766 | 136k | DBUG_EXECUTE_IF("MemTable.need_flush", { return true; }); |
767 | 136k | auto max_size = _adaptive_write_buffer_size(); |
768 | 136k | if (_partial_update_mode == UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS) { |
769 | 1.49k | auto update_columns_size = _num_columns; |
770 | 1.49k | auto min_buffer_size = config::min_write_buffer_size_for_partial_update; |
771 | 1.49k | max_size = max_size * update_columns_size / _tablet_schema->num_columns(); |
772 | 1.49k | max_size = max_size > min_buffer_size ? max_size : min_buffer_size; |
773 | 1.49k | } |
774 | | |
775 | 136k | if (memory_usage() >= max_size) { |
776 | 0 | g_flush_cuz_memtable_full << 1; |
777 | 0 | return true; |
778 | 0 | } |
779 | 136k | return false; |
780 | 136k | } |
781 | | |
782 | 136k | int64_t MemTable::_adaptive_write_buffer_size() const { |
783 | 136k | if (!config::enable_adaptive_write_buffer_size) [[unlikely]] { |
784 | 0 | return config::write_buffer_size; |
785 | 0 | } |
786 | 136k | auto* memtable_limiter = ExecEnv::GetInstance()->memtable_memory_limiter(); |
787 | 136k | int64_t memtable_mem = |
788 | 136k | (memtable_limiter != nullptr && memtable_limiter->mem_tracker() != nullptr) |
789 | 136k | ? memtable_limiter->mem_tracker()->consumption() |
790 | 136k | : 0; |
791 | 136k | int64_t factor = 4; |
792 | | // Memory usage intervals: |
793 | | // (80 %, 100 %] → 1× buffer |
794 | | // (50 %, 80 %] → 2× buffer |
795 | | // [0 %, 50 %] → 4× buffer |
796 | 136k | if (memtable_mem > (_load_mem_limit * 4) / 5) { // > 80 % |
797 | 0 | factor = 1; |
798 | 136k | } else if (memtable_mem > _load_mem_limit / 2) { // > 50 % |
799 | 0 | factor = 2; |
800 | 0 | } |
801 | 136k | return config::write_buffer_size * factor; |
802 | 136k | } |
803 | | |
804 | 136k | bool MemTable::need_agg() const { |
805 | 136k | if (_keys_type == KeysType::AGG_KEYS) { |
806 | 5.44k | auto max_size = _last_agg_pos + config::write_buffer_size_for_agg; |
807 | 5.44k | return memory_usage() >= max_size; |
808 | 5.44k | } |
809 | 131k | return false; |
810 | 136k | } |
811 | | |
812 | 0 | size_t MemTable::get_flush_reserve_memory_size() const { |
813 | 0 | if (_keys_type == KeysType::DUP_KEYS && _tablet_schema->num_key_columns() == 0) { |
814 | 0 | return 0; // no need to reserve |
815 | 0 | } |
816 | 0 | return static_cast<size_t>(static_cast<double>(_input_mutable_block.allocated_bytes()) * 1.2); |
817 | 0 | } |
818 | | |
819 | 76.3k | Status MemTable::_to_block(std::unique_ptr<Block>* res) { |
820 | 76.3k | _output_row_binlog_lsns.clear(); |
821 | 76.3k | size_t same_keys_num = _sort(); |
822 | 76.3k | if (_keys_type == KeysType::DUP_KEYS || same_keys_num == 0) { |
823 | 74.1k | if (_keys_type == KeysType::DUP_KEYS && _tablet_schema->num_key_columns() == 0) { |
824 | 21 | _output_mutable_block.swap(_input_mutable_block); |
825 | 21 | if (_need_row_binlog_lsn) { |
826 | 0 | _output_row_binlog_lsns.reserve(_row_in_blocks->size()); |
827 | 0 | for (const auto& row : *_row_in_blocks) { |
828 | 0 | _append_output_row_binlog_lsn(row); |
829 | 0 | } |
830 | 0 | } |
831 | 74.1k | } else { |
832 | 74.1k | Block in_block = _input_mutable_block.to_block(); |
833 | 74.1k | RETURN_IF_ERROR(_put_into_output(in_block)); |
834 | 74.1k | } |
835 | 74.1k | } else { |
836 | 2.12k | (_skip_bitmap_col_idx == -1) ? _aggregate<true, false>() : _aggregate<true, true>(); |
837 | 2.12k | } |
838 | 76.3k | if (_keys_type == KeysType::UNIQUE_KEYS && _enable_unique_key_mow && |
839 | 76.3k | !_tablet_schema->cluster_key_uids().empty()) { |
840 | 1.54k | if (_partial_update_mode != UniqueKeyUpdateModePB::UPSERT) { |
841 | 0 | return Status::InternalError( |
842 | 0 | "Partial update for mow with cluster keys is not supported"); |
843 | 0 | } |
844 | 1.54k | RETURN_IF_ERROR(_sort_by_cluster_keys()); |
845 | 1.54k | } |
846 | 76.3k | if (_need_row_binlog_lsn) { |
847 | 3 | DCHECK_EQ(_output_row_binlog_lsns.size(), _output_mutable_block.rows()); |
848 | 3 | } |
849 | 76.3k | _input_mutable_block.clear(); |
850 | 76.3k | *res = Block::create_unique(_output_mutable_block.to_block()); |
851 | 76.3k | return Status::OK(); |
852 | 76.3k | } |
853 | | |
854 | 76.3k | Status MemTable::to_block(std::unique_ptr<Block>* res) { |
855 | 76.3k | RETURN_IF_ERROR_OR_CATCH_EXCEPTION(_to_block(res)); |
856 | 76.2k | return Status::OK(); |
857 | 76.3k | } |
858 | | |
859 | | } // namespace doris |