Coverage Report

Created: 2026-08-21 22:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/schema.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <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 <vector>
29
30
#include "common/consts.h"
31
#include "common/status.h"
32
#include "core/column/column.h"
33
#include "exprs/aggregate/aggregate_function.h"
34
#include "io/io_common.h"
35
#include "runtime/thread_context.h"
36
#include "storage/olap_common.h"
37
#include "storage/tablet/tablet_schema.h"
38
#include "storage/utils.h"
39
40
namespace doris {
41
42
class ReadSchema;
43
class Block;
44
using ReadSchemaSPtr = std::shared_ptr<ReadSchema>;
45
46
// Select columns by their ordinal in `columns`, preserving the requested order and duplicates.
47
// Keeping this source-layout operation outside ReadSchema prevents those ordinals from being
48
// confused with the dense ordinals of the resulting ReadSchema.
49
std::vector<TabletColumnPtr> project_columns_by_ordinal(
50
        const std::vector<TabletColumnPtr>& columns,
51
        const std::vector<ColumnId>& source_column_ordinals);
52
53
// The dense, ordered column layout consumed by one storage reader. For example, if the caller's
54
// Block is [k1, v1] and a historical delete predicate needs dropped_v2, the layout is
55
// [k1, v1, dropped_v2]: num_block_columns() is 2, num_read_columns() is 3, and every reader-side
56
// ColumnId is an ordinal in this list. TabletColumn keeps physical storage metadata, while
57
// data_type() records the expected materialized type, such as a pruned STRUCT type.
58
class ReadSchema {
59
public:
60
    using SequenceMap = std::unordered_map<ColumnId, std::vector<ColumnId>>;
61
62
    explicit ReadSchema(std::vector<TabletColumnPtr> columns);
63
64
    // Every column is initially caller-visible. Historical delete-predicate columns may be
65
    // appended later without changing num_block_columns().
66
    explicit ReadSchema(std::vector<TabletColumnPtr> columns, std::vector<DataTypePtr> read_types);
67
68
    static IColumn::MutablePtr get_predicate_column_ptr(const DataTypePtr& data_type,
69
                                                        const ReaderType reader_type);
70
71
10.6k
    const std::vector<TabletColumnPtr>& columns() const { return _read_columns; }
72
73
85.8k
    DataTypePtr data_type(size_t ordinal) const {
74
85.8k
        DCHECK_LT(ordinal, _read_types.size());
75
85.8k
        return _read_types[ordinal];
76
85.8k
    }
77
78
    // Append private historical delete-predicate columns without extending the Block prefix.
79
    void append_dropped_columns(std::vector<TabletColumn> columns);
80
81
    // Create caller-visible Blocks from the FE-slot prefix.
82
    Block create_read_block() const;
83
84
    std::string read_columns_to_string() const;
85
86
    Status init_sequence_map(const TabletSchema& tablet_schema);
87
88
0
    const SequenceMap& sequence_map() const { return _sequence_map; }
89
90
    // Return the matching before-image ordinal for a Row Binlog value column. For example, in
91
    // [v1, v2, __BEFORE__v1__, __BEFORE__v2__], 0 maps to 2 and 1 maps to 3. Columns without a
92
    // before image, including TSO/LSN/OP, map to themselves.
93
43
    ColumnId before_column_ordinal(ColumnId ordinal) const {
94
43
        DCHECK_LT(ordinal, _before_column_ordinals.size());
95
43
        return _before_column_ordinals[ordinal];
96
43
    }
97
98
1.23M
    const TabletColumn* column(size_t ordinal) const { return _read_columns[ordinal].get(); }
99
100
    // Total columns used inside storage, including appended storage-only columns.
101
    // Use this for per-column state and iteration over the complete ReadSchema.
102
161k
    size_t num_read_columns() const { return _read_columns.size(); }
103
104
    // Columns materialized in caller Blocks. They are the ReadSchema prefix before
105
    // appended storage-only columns; use this for Block layout and position bounds.
106
1.05M
    size_t num_block_columns() const { return _num_block_columns; }
107
108
    // Number of key columns present in the caller-visible ReadSchema. This is deliberately not the
109
    // full TabletSchema key count. Merge readers additionally require these columns to be the full,
110
    // leading storage-key prefix; direct/projected readers may contain fewer key columns.
111
1.06M
    size_t num_key_columns() const { return _num_key_columns; }
112
113
    // All special-column ordinals below address the caller-visible Block prefix and are -1 when
114
    // absent. A Row Binlog layout may be [k1, v1, __BEFORE__v1__, TSO, LSN, OP]; a snapshot layout
115
    // may instead contain COMMIT_TSO.
116
    // Logical-delete marker used by unique-key reads.
117
2.96k
    int32_t delete_sign_ordinal() const { return _delete_sign_ordinal; }
118
    // Sequence column used to choose the winning row during merge.
119
461
    int32_t sequence_ordinal() const { return _sequence_ordinal; }
120
    // Synthetic row identifier returned by rowid-producing scans.
121
7
    int32_t rowid_ordinal() const { return _rowid_ordinal; }
122
    // Rowset version synthesized for single-version reads.
123
12.9k
    int32_t version_ordinal() const { return _version_ordinal; }
124
    // Row Binlog transaction timestamp.
125
1.60k
    int32_t tso_ordinal() const { return _tso_ordinal; }
126
    // Row Binlog log-sequence number.
127
8
    int32_t lsn_ordinal() const { return _lsn_ordinal; }
128
    // Row Binlog operation kind, such as INSERT, UPDATE, or DELETE.
129
26
    int32_t op_ordinal() const { return _op_ordinal; }
130
    // Snapshot commit timestamp.
131
69
    int32_t commit_tso_ordinal() const { return _commit_tso_ordinal; }
132
133
    // -1 if no column with this unique id is present.
134
280
    int32_t ordinal_by_uid(int32_t unique_id) const {
135
280
        auto it = _uid_to_ordinal.find(unique_id);
136
280
        return it == _uid_to_ordinal.end() ? -1 : it->second;
137
280
    }
138
139
private:
140
    void _init_read_types();
141
    void _init_before_column_ordinals();
142
143
944
    void _init_descriptors() {
144
944
        DORIS_CHECK_LE(_num_block_columns, _read_columns.size());
145
944
        DORIS_CHECK_EQ(_read_columns.size(), _read_types.size());
146
944
        _num_key_columns = 0;
147
944
        _delete_sign_ordinal = -1;
148
944
        _sequence_ordinal = -1;
149
944
        _rowid_ordinal = -1;
150
944
        _version_ordinal = -1;
151
944
        _tso_ordinal = -1;
152
944
        _lsn_ordinal = -1;
153
944
        _op_ordinal = -1;
154
944
        _commit_tso_ordinal = -1;
155
944
        _before_column_ordinals.clear();
156
944
        _uid_to_ordinal.clear();
157
6.62k
        for (uint32_t i = 0; i < _read_columns.size(); ++i) {
158
5.67k
            const auto& col = *_read_columns[i];
159
5.67k
            if (col.unique_id() >= 0) {
160
5.41k
                _uid_to_ordinal.emplace(col.unique_id(), i);
161
5.41k
            }
162
5.67k
        }
163
6.62k
        for (uint32_t i = 0; i < _num_block_columns; ++i) {
164
5.67k
            const auto& col = *_read_columns[i];
165
5.67k
            if (col.is_key()) {
166
1.65k
                ++_num_key_columns;
167
1.65k
            }
168
5.67k
            if (col.name() == DELETE_SIGN) {
169
129
                _delete_sign_ordinal = i;
170
129
            }
171
5.67k
            if (col.name() == SEQUENCE_COL) {
172
64
                _sequence_ordinal = i;
173
64
            }
174
5.67k
            if (col.name().starts_with(BeConsts::GLOBAL_ROWID_COL)) {
175
0
                _rowid_ordinal = i;
176
0
            }
177
5.67k
            if (col.name() == VERSION_COL) {
178
40
                _version_ordinal = i;
179
40
            }
180
5.67k
            if (col.name() == BINLOG_TSO_COL) {
181
32
                _tso_ordinal = i;
182
32
            }
183
5.67k
            if (col.name() == BINLOG_LSN_COL) {
184
30
                _lsn_ordinal = i;
185
30
            }
186
5.67k
            if (col.name() == BINLOG_OP_COL) {
187
32
                _op_ordinal = i;
188
32
            }
189
5.67k
            if (col.name() == COMMIT_TSO_COL) {
190
4
                _commit_tso_ordinal = i;
191
4
            }
192
5.67k
        }
193
944
        if (_op_ordinal >= 0) {
194
32
            _init_before_column_ordinals();
195
32
        }
196
944
    }
197
198
    // Example: storage has k(uid=1, INT) and
199
    // s(uid=2, STRUCT<a:INT,b:STRING,c:BIGINT>). The scan needs k and only s.a/s.c, while
200
    // a historical delete predicate `old_v = 0` needs the dropped column old_v(uid=3, INT):
201
    //   [0] _read_columns: k:INT (uid=1)
202
    //       _read_types:   INT
203
    //   [1] _read_columns: s:STRUCT<a:INT,b:STRING,c:BIGINT> (uid=2)
204
    //       _read_types:   STRUCT<a:INT,c:BIGINT>
205
    //   [2] _read_columns: old_v:INT (uid=3, dropped)
206
    //       _read_types:   INT
207
    // `_num_block_columns` is 2, so create_read_block() materializes ordinals [0, 2). Ordinal 2
208
    // is read only for delete filtering and never appears in the caller Block.
209
    std::vector<TabletColumnPtr> _read_columns;
210
    // Types aligned by ordinal with `_read_columns`.
211
    std::vector<DataTypePtr> _read_types;
212
    // Boundary between the columns materialized in Blocks and the appended dropped columns.
213
    size_t _num_block_columns = 0;
214
215
    size_t _num_key_columns = 0;
216
    int32_t _delete_sign_ordinal = -1;
217
    int32_t _sequence_ordinal = -1;
218
    int32_t _rowid_ordinal = -1;
219
    int32_t _version_ordinal = -1;
220
    int32_t _tso_ordinal = -1;
221
    int32_t _lsn_ordinal = -1;
222
    int32_t _op_ordinal = -1;
223
    int32_t _commit_tso_ordinal = -1;
224
    std::unordered_map<int32_t, int32_t> _uid_to_ordinal;
225
    SequenceMap _sequence_map;
226
    std::vector<ColumnId> _before_column_ordinals;
227
};
228
229
} // namespace doris