be/src/storage/partial_update_info.h
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | #pragma once |
19 | | #include <gen_cpp/olap_file.pb.h> |
20 | | |
21 | | #include <cstdint> |
22 | | #include <functional> |
23 | | #include <map> |
24 | | #include <memory> |
25 | | #include <set> |
26 | | #include <string> |
27 | | #include <vector> |
28 | | |
29 | | #include "common/status.h" |
30 | | #include "core/column/column.h" |
31 | | #include "core/data_type/primitive_type.h" |
32 | | #include "storage/rowset/rowset_fwd.h" |
33 | | #include "storage/tablet/tablet_fwd.h" |
34 | | |
35 | | namespace doris { |
36 | | class TabletSchema; |
37 | | class PartialUpdateInfoPB; |
38 | | class PUniqueId; |
39 | | class BitmapValue; |
40 | | struct RowLocation; |
41 | | class Block; |
42 | | class MutableBlock; |
43 | | class IOlapColumnDataAccessor; |
44 | | namespace segment_v2 { |
45 | | struct HistoricalRowRetrieverContext; |
46 | | } |
47 | | |
48 | | struct RowsetWriterContext; |
49 | | struct RowsetId; |
50 | | class BitmapValue; |
51 | | class HistoricalRowFetcher; |
52 | | class OlapBlockDataConvertor; |
53 | | class RowKeyEncoder; |
54 | | struct MowContext; |
55 | | namespace segment_v2 { |
56 | | class MowKeyProbe; |
57 | | } |
58 | | |
59 | | class SegmentCacheHandle; |
60 | | |
61 | | struct PartialUpdateInfo { |
62 | | Status init(int64_t tablet_id, int64_t txn_id, const TabletSchema& tablet_schema, |
63 | | UniqueKeyUpdateModePB unique_key_update_mode, PartialUpdateNewRowPolicyPB policy, |
64 | | const std::set<std::string>& partial_update_cols, bool is_strict_mode, |
65 | | int64_t timestamp_ms, int32_t nano_seconds, const std::string& timezone, |
66 | | const std::string& auto_increment_column, int32_t sequence_map_col_uid = -1, |
67 | | int64_t cur_max_version = -1, const PUniqueId* load_id = nullptr); |
68 | | void to_pb(PartialUpdateInfoPB* partial_update_info) const; |
69 | | void from_pb(PartialUpdateInfoPB* partial_update_info); |
70 | | Status handle_new_key(const TabletSchema& tablet_schema, |
71 | | const std::function<std::string()>& line, |
72 | | BitmapValue* skip_bitmap = nullptr); |
73 | | std::string summary() const; |
74 | | |
75 | 0 | std::string partial_update_mode_str() const { |
76 | 0 | switch (partial_update_mode) { |
77 | 0 | case UniqueKeyUpdateModePB::UPSERT: |
78 | 0 | return "upsert"; |
79 | 0 | case UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS: |
80 | 0 | return "partial update"; |
81 | 0 | case UniqueKeyUpdateModePB::UPDATE_FLEXIBLE_COLUMNS: |
82 | 0 | return "flexible partial update"; |
83 | 0 | } |
84 | 0 | return ""; |
85 | 0 | } |
86 | 329 | bool is_partial_update() const { return partial_update_mode != UniqueKeyUpdateModePB::UPSERT; } |
87 | 217 | bool is_fixed_partial_update() const { |
88 | 217 | return partial_update_mode == UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS; |
89 | 217 | } |
90 | 73 | bool is_flexible_partial_update() const { |
91 | 73 | return partial_update_mode == UniqueKeyUpdateModePB::UPDATE_FLEXIBLE_COLUMNS; |
92 | 73 | } |
93 | 16 | UniqueKeyUpdateModePB update_mode() const { return partial_update_mode; } |
94 | 0 | int32_t sequence_map_col_uid() const { return sequence_map_col_unqiue_id; } |
95 | | |
96 | | private: |
97 | | void _generate_default_values_for_missing_cids(const TabletSchema& tablet_schema); |
98 | | |
99 | | public: |
100 | | UniqueKeyUpdateModePB partial_update_mode {UniqueKeyUpdateModePB::UPSERT}; |
101 | | PartialUpdateNewRowPolicyPB partial_update_new_key_policy {PartialUpdateNewRowPolicyPB::APPEND}; |
102 | | int64_t max_version_in_flush_phase {-1}; |
103 | | std::set<std::string> partial_update_input_columns; |
104 | | std::vector<uint32_t> missing_cids; |
105 | | std::vector<uint32_t> update_cids; |
106 | | // if key not exist in old rowset, use default value or null value for the unmentioned cols |
107 | | // to generate a new row, only available in non-strict mode |
108 | | bool can_insert_new_rows_in_partial_update {true}; |
109 | | bool is_strict_mode {false}; |
110 | | // Shared by all replicas and persisted for publish/recovery. Never use process-local RNGs |
111 | | // when filling a missing cell after the input rows have been fanned out. |
112 | | bool has_load_id {false}; |
113 | | uint64_t load_id_hi {0}; |
114 | | uint64_t load_id_lo {0}; |
115 | | int64_t timestamp_ms {0}; |
116 | | int32_t nano_seconds {0}; |
117 | | std::string timezone; |
118 | | bool is_input_columns_contains_auto_inc_column = false; |
119 | | bool is_schema_contains_auto_inc_column = false; |
120 | | |
121 | | // default values for missing cids |
122 | | std::vector<std::string> default_values; |
123 | | |
124 | | int32_t sequence_map_col_unqiue_id {-1}; |
125 | | }; |
126 | | |
127 | | // used in mow partial update |
128 | | struct RidAndPos { |
129 | | uint32_t rid; |
130 | | // pos in block |
131 | | size_t pos; |
132 | | }; |
133 | | |
134 | | class FixedReadPlan { |
135 | | public: |
136 | | bool empty() const; |
137 | 0 | void clear() { plan.clear(); } |
138 | | void prepare_to_read(const RowLocation& row_location, size_t pos); |
139 | | Status read_columns_by_plan(const TabletSchema& tablet_schema, |
140 | | std::vector<uint32_t> cids_to_read, |
141 | | const std::map<RowsetId, RowsetSharedPtr>& rsid_to_rowset, |
142 | | Block& block, std::map<uint32_t, uint32_t>* read_index, |
143 | | bool force_read_old_delete_signs, |
144 | | const signed char* __restrict cur_delete_signs = nullptr) const; |
145 | | Status fill_missing_columns(const segment_v2::HistoricalRowRetrieverContext& historical_context, |
146 | | const std::map<RowsetId, RowsetSharedPtr>& rsid_to_rowset, |
147 | | const TabletSchema& tablet_schema, Block& full_block, |
148 | | const std::vector<bool>& use_default_or_null_flag, |
149 | | bool has_default_or_nullable, uint32_t segment_start_pos, |
150 | | const Block* block, |
151 | | std::vector<signed char>* old_delete_signs = nullptr) const; |
152 | | Status fill_old_delete_signs(const Block& old_value_block, |
153 | | const std::map<uint32_t, uint32_t>& read_index, size_t num_rows, |
154 | | std::vector<signed char>* old_delete_signs) const; |
155 | | |
156 | | private: |
157 | | std::map<RowsetId, std::map<uint32_t /* segment_id */, std::vector<RidAndPos>>> plan; |
158 | | }; |
159 | | |
160 | | class FlexibleReadPlan { |
161 | | public: |
162 | 105 | FlexibleReadPlan(bool has_row_store_for_column) : use_row_store(has_row_store_for_column) {} |
163 | | void prepare_to_read(const RowLocation& row_location, size_t pos, |
164 | | const BitmapValue& skip_bitmap); |
165 | | // for column store |
166 | | Status read_columns_by_plan(const TabletSchema& tablet_schema, |
167 | | const std::map<RowsetId, RowsetSharedPtr>& rsid_to_rowset, |
168 | | Block& old_value_block, |
169 | | std::map<uint32_t, std::map<uint32_t, uint32_t>>* read_index) const; |
170 | | |
171 | | // for row_store |
172 | | Status read_columns_by_plan(const TabletSchema& tablet_schema, |
173 | | const std::vector<uint32_t>& cids_to_read, |
174 | | const std::map<RowsetId, RowsetSharedPtr>& rsid_to_rowset, |
175 | | Block& old_value_block, |
176 | | std::map<uint32_t, uint32_t>* read_index) const; |
177 | | Status fill_non_primary_key_columns( |
178 | | const segment_v2::HistoricalRowRetrieverContext& historical_context, |
179 | | const std::map<RowsetId, RowsetSharedPtr>& rsid_to_rowset, |
180 | | const TabletSchema& tablet_schema, Block& full_block, |
181 | | const std::vector<bool>& use_default_or_null_flag, bool has_default_or_nullable, |
182 | | uint32_t segment_start_pos, uint32_t block_start_pos, const Block* block, |
183 | | std::vector<BitmapValue>* skip_bitmaps) const; |
184 | | |
185 | | Status fill_non_primary_key_columns_for_column_store( |
186 | | const segment_v2::HistoricalRowRetrieverContext& historical_context, |
187 | | const std::map<RowsetId, RowsetSharedPtr>& rsid_to_rowset, |
188 | | const TabletSchema& tablet_schema, const std::vector<uint32_t>& non_sort_key_cids, |
189 | | Block& old_value_block, MutableColumns& mutable_full_columns, |
190 | | const std::vector<bool>& use_default_or_null_flag, bool has_default_or_nullable, |
191 | | uint32_t segment_start_pos, uint32_t block_start_pos, const Block* block, |
192 | | std::vector<BitmapValue>* skip_bitmaps) const; |
193 | | Status fill_non_primary_key_columns_for_row_store( |
194 | | const segment_v2::HistoricalRowRetrieverContext& historical_context, |
195 | | const std::map<RowsetId, RowsetSharedPtr>& rsid_to_rowset, |
196 | | const TabletSchema& tablet_schema, const std::vector<uint32_t>& non_sort_key_cids, |
197 | | Block& old_value_block, MutableColumns& mutable_full_columns, |
198 | | const std::vector<bool>& use_default_or_null_flag, bool has_default_or_nullable, |
199 | | uint32_t segment_start_pos, uint32_t block_start_pos, const Block* block, |
200 | | std::vector<BitmapValue>* skip_bitmaps) const; |
201 | | |
202 | | private: |
203 | | bool use_row_store {false}; |
204 | | // rowset_id -> segment_id -> column unique id -> mappings |
205 | | std::map<RowsetId, std::map<uint32_t, std::map<uint32_t, std::vector<RidAndPos>>>> plan; |
206 | | std::map<RowsetId, std::map<uint32_t /* segment_id */, std::vector<RidAndPos>>> row_store_plan; |
207 | | }; |
208 | | |
209 | | ColumnBitmap* get_mutable_skip_bitmap_column(Block* block, size_t skip_bitmap_col_idx); |
210 | | |
211 | | class BlockAggregator { |
212 | | public: |
213 | | ~BlockAggregator(); |
214 | | // All references must live longer than the aggregator; the flexible fill |
215 | | // stage builds everything as locals in one apply() scope. The aggregator |
216 | | // owns its block convertor (key + sequence column slots). |
217 | | BlockAggregator(TabletSchema& tablet_schema, BaseTabletSPtr tablet, |
218 | | std::shared_ptr<MowContext> mow_context, |
219 | | const PartialUpdateInfo& partial_update_info, const RowKeyEncoder& key_encoder, |
220 | | const segment_v2::MowKeyProbe& probe, HistoricalRowFetcher& fetcher); |
221 | | |
222 | | Status convert_pk_columns(Block* block, size_t row_pos, size_t num_rows, |
223 | | std::vector<IOlapColumnDataAccessor*>& key_columns); |
224 | | Status convert_seq_column(Block* block, size_t row_pos, size_t num_rows, |
225 | | IOlapColumnDataAccessor*& seq_column); |
226 | | // Optional sidecars are aggregated and filtered with `block`; on return each element is |
227 | | // aligned with the corresponding row in the final block. A non-zero |
228 | | // `insert_after_delete_flags` entry marks the surviving INSERT of a same-batch |
229 | | // DELETE-then-INSERT pair. |
230 | | Status aggregate_for_flexible_partial_update( |
231 | | Block* block, size_t num_rows, const std::vector<RowsetSharedPtr>& specified_rowsets, |
232 | | std::vector<std::unique_ptr<SegmentCacheHandle>>& segment_caches, |
233 | | std::vector<int64_t>* row_lsns = nullptr, |
234 | | std::vector<uint8_t>* insert_after_delete_flags = nullptr); |
235 | | |
236 | | private: |
237 | | Status aggregate_for_sequence_column( |
238 | | Block* block, int num_rows, const std::vector<IOlapColumnDataAccessor*>& key_columns, |
239 | | IOlapColumnDataAccessor* seq_column, |
240 | | const std::vector<RowsetSharedPtr>& specified_rowsets, |
241 | | std::vector<std::unique_ptr<SegmentCacheHandle>>& segment_caches, |
242 | | std::vector<int64_t>* row_lsns); |
243 | | Status aggregate_for_insert_after_delete( |
244 | | Block* block, size_t num_rows, const std::vector<IOlapColumnDataAccessor*>& key_columns, |
245 | | const std::vector<RowsetSharedPtr>& specified_rowsets, |
246 | | std::vector<std::unique_ptr<SegmentCacheHandle>>& segment_caches, |
247 | | std::vector<int64_t>* row_lsns, std::vector<uint8_t>* insert_after_delete_flags); |
248 | | Status filter_block(Block* block, size_t num_rows, MutableColumnPtr filter_column, |
249 | | int duplicate_rows, std::string col_name); |
250 | | |
251 | | Status fill_sequence_column(Block* block, size_t num_rows, const FixedReadPlan& read_plan, |
252 | | std::vector<BitmapValue>& skip_bitmaps); |
253 | | |
254 | | void append_or_merge_row(MutableBlock& dst_block, Block* src_block, int rid, |
255 | | BitmapValue& skip_bitmap, bool have_delete_sign); |
256 | | void merge_one_row(MutableBlock& dst_block, Block* src_block, int rid, |
257 | | BitmapValue& skip_bitmap); |
258 | | void append_one_row(MutableBlock& dst_block, Block* src_block, int rid); |
259 | | void remove_last_n_rows(MutableBlock& dst_block, int n); |
260 | | |
261 | | void append_row_lsn(int rid); |
262 | | void merge_row_lsn(int rid); |
263 | | void remove_last_row_lsns(int n); |
264 | | |
265 | | // aggregate rows with same keys in range [start, end) from block to output_block |
266 | | Status aggregate_rows(MutableBlock& output_block, Block* block, int start, int end, |
267 | | std::string key, std::vector<BitmapValue>* skip_bitmaps, |
268 | | const signed char* delete_signs, IOlapColumnDataAccessor* seq_column, |
269 | | const std::vector<RowsetSharedPtr>& specified_rowsets, |
270 | | std::vector<std::unique_ptr<SegmentCacheHandle>>& segment_caches); |
271 | | |
272 | | Status _generate_encoded_default_seq_value(std::string* encoded_value); |
273 | | |
274 | | TabletSchema& _tablet_schema; |
275 | | BaseTabletSPtr _tablet; |
276 | | std::shared_ptr<MowContext> _mow_context; |
277 | | const PartialUpdateInfo& _partial_update_info; |
278 | | const RowKeyEncoder& _key_encoder; |
279 | | std::unique_ptr<OlapBlockDataConvertor> _convertor; |
280 | | const segment_v2::MowKeyProbe& _probe; |
281 | | HistoricalRowFetcher& _fetcher; |
282 | | |
283 | | // Optional sidecar used by Row Binlog. Flexible aggregation can remove or merge input rows; |
284 | | // keep the persisted LSN aligned with the surviving row and retain the largest LSN of all |
285 | | // merged changes. |
286 | | const std::vector<int64_t>* _input_row_lsns = nullptr; |
287 | | std::vector<int64_t>* _output_row_lsns = nullptr; |
288 | | |
289 | | // used to store state when aggregating rows in block |
290 | | struct AggregateState { |
291 | | int rows {0}; |
292 | | bool has_row_with_delete_sign {false}; |
293 | | |
294 | 27 | bool should_merge() const { |
295 | 27 | return ((rows == 1 && !has_row_with_delete_sign) || rows == 2); |
296 | 27 | } |
297 | | |
298 | 20 | void reset() { |
299 | 20 | rows = 0; |
300 | 20 | has_row_with_delete_sign = false; |
301 | 20 | } |
302 | | |
303 | 0 | std::string to_string() const { |
304 | 0 | return fmt::format("rows={}, have_delete_row={}", rows, has_row_with_delete_sign); |
305 | 0 | } |
306 | | } _state {}; |
307 | | }; |
308 | | |
309 | | struct PartialUpdateStats { |
310 | | int64_t num_rows_updated {0}; |
311 | | int64_t num_rows_new_added {0}; |
312 | | int64_t num_rows_deleted {0}; |
313 | | int64_t num_rows_filtered {0}; |
314 | | }; |
315 | | } // namespace doris |