Coverage Report

Created: 2024-11-20 12:30

/root/doris/be/src/olap/schema_change.h
Line
Count
Source (jump to first uncovered line)
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 <butil/macros.h>
21
#include <fmt/format.h>
22
#include <gen_cpp/Descriptors_types.h>
23
#include <glog/logging.h>
24
#include <stddef.h>
25
#include <stdint.h>
26
27
#include <memory>
28
#include <ostream>
29
#include <set>
30
#include <shared_mutex>
31
#include <string>
32
#include <unordered_map>
33
#include <unordered_set>
34
#include <utility>
35
#include <vector>
36
37
#include "common/config.h"
38
#include "common/object_pool.h"
39
#include "common/status.h"
40
#include "olap/column_mapping.h"
41
#include "olap/olap_common.h"
42
#include "olap/rowset/pending_rowset_helper.h"
43
#include "olap/rowset/rowset.h"
44
#include "olap/rowset/rowset_reader.h"
45
#include "olap/rowset/rowset_writer.h"
46
#include "olap/rowset/segment_v2/inverted_index_writer.h"
47
#include "olap/storage_engine.h"
48
#include "olap/tablet.h"
49
#include "olap/tablet_schema.h"
50
#include "runtime/descriptors.h"
51
#include "runtime/memory/mem_tracker.h"
52
#include "vec/data_types/data_type.h"
53
54
namespace doris {
55
class DeleteHandler;
56
class Field;
57
class TAlterInvertedIndexReq;
58
class TAlterTabletReqV2;
59
class TExpr;
60
enum AlterTabletType : int;
61
enum RowsetTypePB : int;
62
enum SegmentsOverlapPB : int;
63
64
namespace vectorized {
65
class Block;
66
class OlapBlockDataConvertor;
67
} // namespace vectorized
68
69
class BlockChanger {
70
public:
71
    BlockChanger(TabletSchemaSPtr tablet_schema, DescriptorTbl desc_tbl);
72
73
    ~BlockChanger();
74
75
    ColumnMapping* get_mutable_column_mapping(size_t column_index);
76
77
    Status change_block(vectorized::Block* ref_block, vectorized::Block* new_block) const;
78
79
0
    void set_where_expr(const std::shared_ptr<TExpr>& where_expr) { _where_expr = where_expr; }
80
81
0
    void set_type(AlterTabletType type) { _type = type; }
82
83
0
    void set_compatible_version(int32_t version) noexcept { _fe_compatible_version = version; }
84
85
0
    bool has_where() const { return _where_expr != nullptr; }
86
87
private:
88
    static Status _check_cast_valid(vectorized::ColumnPtr ref_column,
89
                                    vectorized::ColumnPtr new_column);
90
91
    // @brief column-mapping specification of new schema
92
    SchemaMapping _schema_mapping;
93
94
    DescriptorTbl _desc_tbl;
95
96
    std::shared_ptr<TExpr> _where_expr;
97
98
    AlterTabletType _type;
99
100
    int32_t _fe_compatible_version = -1;
101
};
102
103
class SchemaChange {
104
public:
105
0
    SchemaChange() = default;
106
0
    virtual ~SchemaChange() = default;
107
108
    virtual Status process(RowsetReaderSharedPtr rowset_reader, RowsetWriter* rowset_writer,
109
                           TabletSharedPtr new_tablet, TabletSharedPtr base_tablet,
110
                           TabletSchemaSPtr base_tablet_schema,
111
0
                           TabletSchemaSPtr new_tablet_schema) {
112
0
        if (rowset_reader->rowset()->empty() || rowset_reader->rowset()->num_rows() == 0) {
113
0
            RETURN_IF_ERROR(rowset_writer->flush());
114
0
            return Status::OK();
115
0
        }
116
117
0
        _filtered_rows = 0;
118
0
        _merged_rows = 0;
119
0
        RETURN_IF_ERROR_OR_CATCH_EXCEPTION(_inner_process(rowset_reader, rowset_writer, new_tablet,
120
0
                                                          base_tablet_schema, new_tablet_schema));
121
122
        // Check row num changes
123
0
        if (!_check_row_nums(rowset_reader, *rowset_writer)) {
124
0
            return Status::Error<ErrorCode::ALTER_STATUS_ERR>("SchemaChange check row nums failed");
125
0
        }
126
127
0
        LOG(INFO) << "all row nums. source_rows=" << rowset_reader->rowset()->num_rows()
128
0
                  << ", source_filtered_rows=" << rowset_reader->filtered_rows()
129
0
                  << ", source_merged_rows=" << rowset_reader->merged_rows()
130
0
                  << ", merged_rows=" << merged_rows() << ", filtered_rows=" << filtered_rows()
131
0
                  << ", new_index_rows=" << rowset_writer->num_rows()
132
0
                  << ", writer_filtered_rows=" << rowset_writer->num_rows_filtered();
133
0
        return Status::OK();
134
0
    }
135
136
0
    uint64_t filtered_rows() const { return _filtered_rows; }
137
138
0
    uint64_t merged_rows() const { return _merged_rows; }
139
140
protected:
141
0
    void _add_filtered_rows(uint64_t filtered_rows) { _filtered_rows += filtered_rows; }
142
143
0
    void _add_merged_rows(uint64_t merged_rows) { _merged_rows += merged_rows; }
144
145
    virtual Status _inner_process(RowsetReaderSharedPtr rowset_reader, RowsetWriter* rowset_writer,
146
                                  TabletSharedPtr new_tablet, TabletSchemaSPtr base_tablet_schema,
147
0
                                  TabletSchemaSPtr new_tablet_schema) {
148
0
        return Status::NotSupported("inner process unsupported.");
149
0
    }
150
151
0
    virtual bool _check_row_nums(RowsetReaderSharedPtr reader, const RowsetWriter& writer) const {
152
0
        if (reader->rowset()->num_rows() - reader->filtered_rows() - reader->merged_rows() !=
153
0
            writer.num_rows() + writer.num_rows_filtered() + _merged_rows + _filtered_rows) {
154
0
            LOG(WARNING) << "fail to check row num! "
155
0
                         << "source_rows=" << reader->rowset()->num_rows()
156
0
                         << ", source_filtered_rows=" << reader->filtered_rows()
157
0
                         << ", source_merged_rows=" << reader->merged_rows()
158
0
                         << ", written_rows=" << writer.num_rows()
159
0
                         << ", writer_filtered_rows=" << writer.num_rows_filtered()
160
0
                         << ", merged_rows=" << merged_rows()
161
0
                         << ", filtered_rows=" << filtered_rows();
162
0
            if (!config::ignore_schema_change_check) {
163
0
                return false;
164
0
            }
165
0
        }
166
0
        return true;
167
0
    }
168
169
private:
170
    uint64_t _filtered_rows {};
171
    uint64_t _merged_rows {};
172
};
173
174
class LinkedSchemaChange : public SchemaChange {
175
public:
176
0
    explicit LinkedSchemaChange(const BlockChanger& changer) : _changer(changer) {}
177
0
    ~LinkedSchemaChange() override = default;
178
179
    Status process(RowsetReaderSharedPtr rowset_reader, RowsetWriter* rowset_writer,
180
                   TabletSharedPtr new_tablet, TabletSharedPtr base_tablet,
181
                   TabletSchemaSPtr base_tablet_schema,
182
                   TabletSchemaSPtr new_tablet_schema) override;
183
184
private:
185
    const BlockChanger& _changer;
186
    DISALLOW_COPY_AND_ASSIGN(LinkedSchemaChange);
187
};
188
189
class VSchemaChangeDirectly : public SchemaChange {
190
public:
191
0
    VSchemaChangeDirectly(const BlockChanger& changer) : _changer(changer) {}
192
193
private:
194
    Status _inner_process(RowsetReaderSharedPtr rowset_reader, RowsetWriter* rowset_writer,
195
                          TabletSharedPtr new_tablet, TabletSchemaSPtr base_tablet_schema,
196
                          TabletSchemaSPtr new_tablet_schema) override;
197
198
0
    bool _check_row_nums(RowsetReaderSharedPtr reader, const RowsetWriter& writer) const override {
199
0
        return _changer.has_where() || SchemaChange::_check_row_nums(reader, writer);
200
0
    }
201
202
    const BlockChanger& _changer;
203
};
204
205
// @breif schema change with sorting
206
class VSchemaChangeWithSorting : public SchemaChange {
207
public:
208
    VSchemaChangeWithSorting(const BlockChanger& changer, size_t memory_limitation);
209
0
    ~VSchemaChangeWithSorting() override = default;
210
211
private:
212
    Status _inner_process(RowsetReaderSharedPtr rowset_reader, RowsetWriter* rowset_writer,
213
                          TabletSharedPtr new_tablet, TabletSchemaSPtr base_tablet_schema,
214
                          TabletSchemaSPtr new_tablet_schema) override;
215
216
    Result<std::pair<RowsetSharedPtr, PendingRowsetGuard>> _internal_sorting(
217
            const std::vector<std::unique_ptr<vectorized::Block>>& blocks,
218
            const Version& temp_delta_versions, int64_t newest_write_timestamp,
219
            TabletSharedPtr new_tablet, RowsetTypePB new_rowset_type,
220
            SegmentsOverlapPB segments_overlap, TabletSchemaSPtr new_tablet_schema);
221
222
    Status _external_sorting(std::vector<RowsetSharedPtr>& src_rowsets, RowsetWriter* rowset_writer,
223
                             TabletSharedPtr new_tablet, TabletSchemaSPtr new_tablet_schema);
224
225
0
    bool _check_row_nums(RowsetReaderSharedPtr reader, const RowsetWriter& writer) const override {
226
0
        return _changer.has_where() || SchemaChange::_check_row_nums(reader, writer);
227
0
    }
228
229
    const BlockChanger& _changer;
230
    size_t _memory_limitation;
231
    Version _temp_delta_versions;
232
    std::unique_ptr<MemTracker> _mem_tracker;
233
};
234
235
class SchemaChangeHandler {
236
public:
237
    // schema change v2, it will not set alter task in base tablet
238
    static Status process_alter_tablet_v2(const TAlterTabletReqV2& request);
239
240
    static std::unique_ptr<SchemaChange> get_sc_procedure(const BlockChanger& changer,
241
0
                                                          bool sc_sorting, bool sc_directly) {
242
0
        if (sc_sorting) {
243
0
            return std::make_unique<VSchemaChangeWithSorting>(
244
0
                    changer, ExecEnv::GetInstance()
245
0
                                     ->get_storage_engine()
246
0
                                     ->memory_limitation_bytes_per_thread_for_schema_change());
247
0
        }
248
249
0
        if (sc_directly) {
250
0
            return std::make_unique<VSchemaChangeDirectly>(changer);
251
0
        }
252
253
0
        return std::make_unique<LinkedSchemaChange>(changer);
254
0
    }
255
256
    static bool tablet_in_converting(int64_t tablet_id);
257
258
private:
259
    static Status _get_versions_to_be_changed(TabletSharedPtr base_tablet,
260
                                              std::vector<Version>* versions_to_be_changed,
261
                                              RowsetSharedPtr* max_rowset);
262
263
    struct AlterMaterializedViewParam {
264
        std::string column_name;
265
        std::string origin_column_name;
266
        std::shared_ptr<TExpr> expr;
267
    };
268
269
    struct SchemaChangeParams {
270
        AlterTabletType alter_tablet_type;
271
        TabletSharedPtr base_tablet;
272
        TabletSharedPtr new_tablet;
273
        TabletSchemaSPtr base_tablet_schema = nullptr;
274
        TabletSchemaSPtr new_tablet_schema = nullptr;
275
        std::vector<RowsetReaderSharedPtr> ref_rowset_readers;
276
        DeleteHandler* delete_handler = nullptr;
277
        std::unordered_map<std::string, AlterMaterializedViewParam> materialized_params_map;
278
        DescriptorTbl* desc_tbl = nullptr;
279
        ObjectPool pool;
280
        int32_t be_exec_version;
281
    };
282
283
    static Status _do_process_alter_tablet_v2(const TAlterTabletReqV2& request);
284
285
    static Status _validate_alter_result(TabletSharedPtr new_tablet,
286
                                         const TAlterTabletReqV2& request);
287
288
    static Status _convert_historical_rowsets(const SchemaChangeParams& sc_params,
289
                                              int64_t* real_alter_version);
290
291
    static Status _parse_request(const SchemaChangeParams& sc_params, BlockChanger* changer,
292
                                 bool* sc_sorting, bool* sc_directly);
293
294
    // Initialization Settings for creating a default value
295
    static Status _init_column_mapping(ColumnMapping* column_mapping,
296
                                       const TabletColumn& column_schema, const std::string& value);
297
298
    static Status _calc_delete_bitmap_for_mow_table(TabletSharedPtr new_tablet,
299
                                                    int64_t alter_version);
300
301
    static std::shared_mutex _mutex;
302
    static std::unordered_set<int64_t> _tablet_ids_in_converting;
303
    static std::set<std::string> _supported_functions;
304
};
305
} // namespace doris