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 <stddef.h> |
21 | | #include <stdint.h> |
22 | | |
23 | | #include <algorithm> |
24 | | #include <cstdint> |
25 | | #include <memory> |
26 | | #include <string> |
27 | | #include <unordered_map> |
28 | | #include <utility> |
29 | | #include <vector> |
30 | | |
31 | | #include "common/consts.h" |
32 | | #include "common/status.h" |
33 | | #include "core/column/column.h" |
34 | | #include "exprs/aggregate/aggregate_function.h" |
35 | | #include "io/io_common.h" |
36 | | #include "runtime/thread_context.h" |
37 | | #include "storage/olap_common.h" |
38 | | #include "storage/tablet/tablet_schema.h" |
39 | | #include "storage/utils.h" |
40 | | |
41 | | namespace doris { |
42 | | |
43 | | class ReadSchema; |
44 | | class Block; |
45 | | class SlotDescriptor; |
46 | | using ReadSchemaSPtr = std::shared_ptr<ReadSchema>; |
47 | | |
48 | | // Select columns by their ordinal in `columns`, preserving the requested order and duplicates. |
49 | | // Keeping this source-layout operation outside ReadSchema prevents those ordinals from being |
50 | | // confused with the dense ordinals of the resulting ReadSchema. |
51 | | std::vector<TabletColumnPtr> project_columns_by_ordinal( |
52 | | const std::vector<TabletColumnPtr>& columns, |
53 | | const std::vector<ColumnId>& source_column_ordinals); |
54 | | |
55 | | // The dense, ordered column layout consumed by one storage reader. For example, if the caller's |
56 | | // Block is [k1, v1] and a historical delete predicate needs dropped_v2, the layout is |
57 | | // [k1, v1, dropped_v2]: num_block_columns() is 2, num_read_columns() is 3, and every reader-side |
58 | | // ColumnId is an ordinal in this list. TabletColumn keeps physical storage metadata, while |
59 | | // data_type() records the expected materialized type, such as a pruned STRUCT type. |
60 | | class ReadSchema { |
61 | | public: |
62 | | using SequenceMap = std::unordered_map<ColumnId, std::vector<ColumnId>>; |
63 | | using RowBinlogValueColumnPairs = std::vector<std::pair<ColumnId, ColumnId>>; |
64 | | |
65 | | explicit ReadSchema(std::vector<TabletColumnPtr> columns); |
66 | | |
67 | | // Every column is initially caller-visible. Historical delete-predicate columns may be |
68 | | // appended later without changing num_block_columns(). |
69 | | explicit ReadSchema(std::vector<TabletColumnPtr> columns, std::vector<DataTypePtr> read_types); |
70 | | |
71 | | static IColumn::MutablePtr get_predicate_column_ptr(const DataTypePtr& data_type, |
72 | | const ReaderType reader_type); |
73 | | |
74 | | // Builds the column `slot` reads from the slot's name, unique id, type and default value. |
75 | | // For a column the tablet schema does not have yet, e.g. one a light schema change just added. |
76 | | static TabletColumn tablet_column_from_slot(const SlotDescriptor& slot); |
77 | | |
78 | 20.6M | const std::vector<TabletColumnPtr>& columns() const { return _read_columns; } |
79 | | |
80 | 76.0M | DataTypePtr data_type(size_t ordinal) const { |
81 | 76.0M | DCHECK_LT(ordinal, _read_types.size()); |
82 | 76.0M | return _read_types[ordinal]; |
83 | 76.0M | } |
84 | | |
85 | | // Append private historical delete-predicate columns without extending the Block prefix. |
86 | | void append_dropped_columns(std::vector<TabletColumn> columns); |
87 | | |
88 | | // Create caller-visible Blocks from the FE-slot prefix. |
89 | | Block create_read_block() const; |
90 | | |
91 | | std::string read_columns_to_string() const; |
92 | | |
93 | | // Always sets the two facts below; the flags add the sequence mapping and the row-binlog |
94 | | // before-image mapping. |
95 | | Status init_from_tablet_schema(const TabletSchema& tablet_schema, |
96 | | bool merge_by_sequence_mapping, bool map_row_binlog_columns); |
97 | | |
98 | | // Whether the tablet schema defines a sequence mapping -- not whether this read merges by |
99 | | // one. A MoW query does not merge, yet a value predicate still must not be pushed down. |
100 | 1.96M | bool tablet_has_sequence_map() const { return _tablet_has_sequence_map; } |
101 | | |
102 | | // Whether the tablet schema materializes variant subcolumns as extracted columns. A |
103 | | // compaction read then takes them as flat leaves. |
104 | 2.98M | bool tablet_has_extracted_variant_columns() const { |
105 | 2.98M | return _tablet_has_extracted_variant_columns; |
106 | 2.98M | } |
107 | | |
108 | 86 | const SequenceMap& sequence_map() const { return _sequence_map; } |
109 | | |
110 | | // Return the matching before-image ordinal for a Row Binlog value column. For example, in |
111 | | // [v1, v2, __BEFORE__v1__, __BEFORE__v2__], 0 maps to 2 and 1 maps to 3. Columns without a |
112 | | // before image, including TSO/LSN/OP, map to themselves. |
113 | 1.16k | ColumnId before_column_ordinal(ColumnId ordinal) const { |
114 | 1.16k | DCHECK_LT(ordinal, _before_column_ordinals.size()); |
115 | 1.16k | return _before_column_ordinals[ordinal]; |
116 | 1.16k | } |
117 | | |
118 | 102 | const RowBinlogValueColumnPairs& row_binlog_value_column_pairs() const { |
119 | 102 | return _row_binlog_value_column_pairs; |
120 | 102 | } |
121 | | |
122 | 102 | bool row_binlog_value_pairs_complete() const { return _row_binlog_value_pairs_complete; } |
123 | | |
124 | 196M | const TabletColumn* column(size_t ordinal) const { return _read_columns[ordinal].get(); } |
125 | | |
126 | | // Total columns used inside storage, including appended storage-only columns. |
127 | | // Use this for per-column state and iteration over the complete ReadSchema. |
128 | 168M | size_t num_read_columns() const { return _read_columns.size(); } |
129 | | |
130 | | // Columns materialized in caller Blocks. They are the ReadSchema prefix before |
131 | | // appended storage-only columns; use this for Block layout and position bounds. |
132 | 104M | size_t num_block_columns() const { return _num_block_columns; } |
133 | | |
134 | | // Number of key columns present in the caller-visible ReadSchema. This is deliberately not the |
135 | | // full TabletSchema key count. Merge readers additionally require these columns to be the full, |
136 | | // leading storage-key prefix; direct/projected readers may contain fewer key columns. |
137 | 17.5M | size_t num_key_columns() const { return _num_key_columns; } |
138 | | |
139 | | // All special-column ordinals below address the caller-visible Block prefix and are -1 when |
140 | | // absent. A Row Binlog layout may be [k1, v1, __BEFORE__v1__, TSO, LSN, OP]; a snapshot layout |
141 | | // may instead contain COMMIT_TSO. |
142 | | // Logical-delete marker used by unique-key reads. |
143 | 973k | int32_t delete_sign_ordinal() const { return _delete_sign_ordinal; } |
144 | | // Sequence column used to choose the winning row during merge. |
145 | 702k | int32_t sequence_ordinal() const { return _sequence_ordinal; } |
146 | | // Synthetic row identifier returned by rowid-producing scans. |
147 | 7 | int32_t rowid_ordinal() const { return _rowid_ordinal; } |
148 | | // Rowset version synthesized for single-version reads. |
149 | 0 | int32_t version_ordinal() const { return _version_ordinal; } |
150 | | // Row Binlog transaction timestamp. |
151 | 2.99M | int32_t tso_ordinal() const { return _tso_ordinal; } |
152 | | // Row Binlog log-sequence number. |
153 | 568 | int32_t lsn_ordinal() const { return _lsn_ordinal; } |
154 | | // Row Binlog operation kind, such as INSERT, UPDATE, or DELETE. |
155 | 616 | int32_t op_ordinal() const { return _op_ordinal; } |
156 | | // Snapshot commit timestamp. |
157 | 107 | int32_t commit_tso_ordinal() const { return _commit_tso_ordinal; } |
158 | | |
159 | | // -1 if no column with this unique id is present. |
160 | 5.42M | int32_t ordinal_by_uid(int32_t unique_id) const { |
161 | 5.42M | auto it = _uid_to_ordinal.find(unique_id); |
162 | 5.42M | return it == _uid_to_ordinal.end() ? -1 : it->second; |
163 | 5.42M | } |
164 | | |
165 | | private: |
166 | | void _init_read_types(); |
167 | | void _init_before_column_ordinals(); |
168 | | Status _init_sequence_map(const TabletSchema& tablet_schema); |
169 | | void _init_row_binlog_column_mappings(const TabletSchema& tablet_schema); |
170 | | |
171 | 3.84M | void _init_descriptors() { |
172 | 3.84M | DORIS_CHECK_LE(_num_block_columns, _read_columns.size()); |
173 | 3.84M | DORIS_CHECK_EQ(_read_columns.size(), _read_types.size()); |
174 | 3.84M | _num_key_columns = 0; |
175 | 3.84M | _delete_sign_ordinal = -1; |
176 | 3.84M | _sequence_ordinal = -1; |
177 | 3.84M | _rowid_ordinal = -1; |
178 | 3.84M | _version_ordinal = -1; |
179 | 3.84M | _tso_ordinal = -1; |
180 | 3.84M | _lsn_ordinal = -1; |
181 | 3.84M | _op_ordinal = -1; |
182 | 3.84M | _commit_tso_ordinal = -1; |
183 | 3.84M | _before_column_ordinals.clear(); |
184 | 3.84M | _uid_to_ordinal.clear(); |
185 | 18.1M | for (uint32_t i = 0; i < _read_columns.size(); ++i) { |
186 | 14.3M | const auto& col = *_read_columns[i]; |
187 | 14.3M | if (col.unique_id() >= 0) { |
188 | 14.2M | _uid_to_ordinal.emplace(col.unique_id(), i); |
189 | 14.2M | } |
190 | 14.3M | } |
191 | 18.1M | for (uint32_t i = 0; i < _num_block_columns; ++i) { |
192 | 14.2M | const auto& col = *_read_columns[i]; |
193 | 14.2M | if (col.is_key()) { |
194 | 9.33M | ++_num_key_columns; |
195 | 9.33M | } |
196 | 14.2M | if (col.name() == DELETE_SIGN) { |
197 | 501k | _delete_sign_ordinal = i; |
198 | 501k | } |
199 | 14.2M | if (col.name() == SEQUENCE_COL) { |
200 | 554 | _sequence_ordinal = i; |
201 | 554 | } |
202 | 14.2M | if (col.name().starts_with(BeConsts::GLOBAL_ROWID_COL)) { |
203 | 7.34k | _rowid_ordinal = i; |
204 | 7.34k | } |
205 | 14.2M | if (col.name() == VERSION_COL) { |
206 | 5.63k | _version_ordinal = i; |
207 | 5.63k | } |
208 | 14.2M | if (col.name() == BINLOG_TSO_COL) { |
209 | 995 | _tso_ordinal = i; |
210 | 995 | } |
211 | 14.2M | if (col.name() == BINLOG_LSN_COL) { |
212 | 369 | _lsn_ordinal = i; |
213 | 369 | } |
214 | 14.2M | if (col.name() == BINLOG_OP_COL) { |
215 | 991 | _op_ordinal = i; |
216 | 991 | } |
217 | 14.2M | if (col.name() == COMMIT_TSO_COL) { |
218 | 1.20k | _commit_tso_ordinal = i; |
219 | 1.20k | } |
220 | 14.2M | } |
221 | 3.84M | if (_op_ordinal >= 0) { |
222 | 989 | _init_before_column_ordinals(); |
223 | 989 | } |
224 | 3.84M | } |
225 | | |
226 | | // Example: storage has k(uid=1, INT) and |
227 | | // s(uid=2, STRUCT<a:INT,b:STRING,c:BIGINT>). The scan needs k and only s.a/s.c, while |
228 | | // a historical delete predicate `old_v = 0` needs the dropped column old_v(uid=3, INT): |
229 | | // [0] _read_columns: k:INT (uid=1) |
230 | | // _read_types: INT |
231 | | // [1] _read_columns: s:STRUCT<a:INT,b:STRING,c:BIGINT> (uid=2) |
232 | | // _read_types: STRUCT<a:INT,c:BIGINT> |
233 | | // [2] _read_columns: old_v:INT (uid=3, dropped) |
234 | | // _read_types: INT |
235 | | // `_num_block_columns` is 2, so create_read_block() materializes ordinals [0, 2). Ordinal 2 |
236 | | // is read only for delete filtering and never appears in the caller Block. |
237 | | std::vector<TabletColumnPtr> _read_columns; |
238 | | // Types aligned by ordinal with `_read_columns`. |
239 | | std::vector<DataTypePtr> _read_types; |
240 | | // Boundary between the columns materialized in Blocks and the appended dropped columns. |
241 | | size_t _num_block_columns = 0; |
242 | | |
243 | | size_t _num_key_columns = 0; |
244 | | int32_t _delete_sign_ordinal = -1; |
245 | | int32_t _sequence_ordinal = -1; |
246 | | int32_t _rowid_ordinal = -1; |
247 | | int32_t _version_ordinal = -1; |
248 | | int32_t _tso_ordinal = -1; |
249 | | int32_t _lsn_ordinal = -1; |
250 | | int32_t _op_ordinal = -1; |
251 | | int32_t _commit_tso_ordinal = -1; |
252 | | std::unordered_map<int32_t, int32_t> _uid_to_ordinal; |
253 | | SequenceMap _sequence_map; |
254 | | std::vector<ColumnId> _before_column_ordinals; |
255 | | RowBinlogValueColumnPairs _row_binlog_value_column_pairs; |
256 | | bool _row_binlog_value_pairs_complete = false; |
257 | | bool _tablet_has_sequence_map = false; |
258 | | bool _tablet_has_extracted_variant_columns = false; |
259 | | }; |
260 | | |
261 | | } // namespace doris |