Coverage Report

Created: 2026-07-13 10:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/format/table/iceberg_reader_mixin.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 <cstddef>
21
#include <cstdint>
22
#include <memory>
23
#include <string>
24
#include <unordered_map>
25
#include <vector>
26
27
#include "common/consts.h"
28
#include "common/status.h"
29
#include "core/block/block.h"
30
#include "core/column/column_dictionary.h"
31
#include "core/column/column_nullable.h"
32
#include "core/column/column_string.h"
33
#include "core/column/column_struct.h"
34
#include "core/data_type/data_type_number.h"
35
#include "core/data_type/data_type_string.h"
36
#include "format/generic_reader.h"
37
#include "format/table/equality_delete.h"
38
#include "format/table/iceberg_delete_file_reader_helper.h"
39
#include "format/table/table_schema_change_helper.h"
40
#include "runtime/runtime_profile.h"
41
#include "runtime/runtime_state.h"
42
#include "storage/olap_common.h"
43
44
namespace doris {
45
class TIcebergDeleteFileDesc;
46
} // namespace doris
47
48
namespace doris {
49
50
class ShardedKVCache;
51
52
// CRTP mixin for Iceberg reader functionality.
53
// BaseReader should be ParquetReader or OrcReader.
54
// Inherits BaseReader + TableSchemaChangeHelper, providing shared Iceberg logic
55
// (delete files, deletion vectors, equality delete, $row_id synthesis).
56
//
57
// Inheritance chain:
58
//   IcebergParquetReader -> IcebergReaderMixin<ParquetReader> -> ParquetReader -> GenericReader
59
//   IcebergOrcReader     -> IcebergReaderMixin<OrcReader>     -> OrcReader     -> GenericReader
60
template <typename BaseReader>
61
class IcebergReaderMixin : public BaseReader, public TableSchemaChangeHelper {
62
public:
63
    struct PositionDeleteRange {
64
        std::vector<std::string> data_file_path;
65
        std::vector<std::pair<int, int>> range;
66
    };
67
68
    // Forward BaseReader constructor arguments + Iceberg-specific kv_cache
69
    template <typename... Args>
70
    IcebergReaderMixin(ShardedKVCache* kv_cache, Args&&... args)
71
16
            : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) {
72
16
        static const char* iceberg_profile = "IcebergProfile";
73
16
        ADD_TIMER(this->get_profile(), iceberg_profile);
74
16
        _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles",
75
16
                                                              TUnit::UNIT, iceberg_profile);
76
16
        _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows",
77
16
                                                             TUnit::UNIT, iceberg_profile);
78
16
        _iceberg_profile.delete_files_read_time =
79
16
                ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile);
80
16
        _iceberg_profile.delete_rows_sort_time =
81
16
                ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile);
82
16
        _iceberg_profile.parse_delete_file_time =
83
16
                ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile);
84
16
        _iceberg_profile.decoded_cache_hit_count =
85
16
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount",
86
16
                                  TUnit::UNIT, iceberg_profile);
87
16
        _iceberg_profile.decoded_cache_miss_count =
88
16
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount",
89
16
                                  TUnit::UNIT, iceberg_profile);
90
16
        _iceberg_profile.file_cache_hit_count =
91
16
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount",
92
16
                                  TUnit::UNIT, iceberg_profile);
93
16
        _iceberg_profile.file_cache_miss_count =
94
16
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount",
95
16
                                  TUnit::UNIT, iceberg_profile);
96
16
        _iceberg_profile.file_cache_peer_read_count =
97
16
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount",
98
16
                                  TUnit::UNIT, iceberg_profile);
99
16
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEEC2IJRPNS_14RuntimeProfileERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRPKN4cctz9time_zoneERPNS_2io9IOContextERPNS_12RuntimeStateERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
Line
Count
Source
71
9
            : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) {
72
9
        static const char* iceberg_profile = "IcebergProfile";
73
9
        ADD_TIMER(this->get_profile(), iceberg_profile);
74
9
        _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles",
75
9
                                                              TUnit::UNIT, iceberg_profile);
76
9
        _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows",
77
9
                                                             TUnit::UNIT, iceberg_profile);
78
9
        _iceberg_profile.delete_files_read_time =
79
9
                ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile);
80
9
        _iceberg_profile.delete_rows_sort_time =
81
9
                ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile);
82
9
        _iceberg_profile.parse_delete_file_time =
83
9
                ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile);
84
9
        _iceberg_profile.decoded_cache_hit_count =
85
9
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount",
86
9
                                  TUnit::UNIT, iceberg_profile);
87
9
        _iceberg_profile.decoded_cache_miss_count =
88
9
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount",
89
9
                                  TUnit::UNIT, iceberg_profile);
90
9
        _iceberg_profile.file_cache_hit_count =
91
9
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount",
92
9
                                  TUnit::UNIT, iceberg_profile);
93
9
        _iceberg_profile.file_cache_miss_count =
94
9
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount",
95
9
                                  TUnit::UNIT, iceberg_profile);
96
9
        _iceberg_profile.file_cache_peer_read_count =
97
9
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount",
98
9
                                  TUnit::UNIT, iceberg_profile);
99
9
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEEC2IJRPNS_14RuntimeProfileERPNS_12RuntimeStateERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERPNS_2io9IOContextERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
Line
Count
Source
71
7
            : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) {
72
7
        static const char* iceberg_profile = "IcebergProfile";
73
7
        ADD_TIMER(this->get_profile(), iceberg_profile);
74
7
        _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles",
75
7
                                                              TUnit::UNIT, iceberg_profile);
76
7
        _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows",
77
7
                                                             TUnit::UNIT, iceberg_profile);
78
7
        _iceberg_profile.delete_files_read_time =
79
7
                ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile);
80
7
        _iceberg_profile.delete_rows_sort_time =
81
7
                ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile);
82
7
        _iceberg_profile.parse_delete_file_time =
83
7
                ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile);
84
7
        _iceberg_profile.decoded_cache_hit_count =
85
7
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount",
86
7
                                  TUnit::UNIT, iceberg_profile);
87
7
        _iceberg_profile.decoded_cache_miss_count =
88
7
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount",
89
7
                                  TUnit::UNIT, iceberg_profile);
90
7
        _iceberg_profile.file_cache_hit_count =
91
7
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount",
92
7
                                  TUnit::UNIT, iceberg_profile);
93
7
        _iceberg_profile.file_cache_miss_count =
94
7
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount",
95
7
                                  TUnit::UNIT, iceberg_profile);
96
7
        _iceberg_profile.file_cache_peer_read_count =
97
7
                ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount",
98
7
                                  TUnit::UNIT, iceberg_profile);
99
7
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEEC2IJRPNS_14RuntimeProfileERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRPKN4cctz9time_zoneESt10shared_ptrINS_2io9IOContextEERPNS_12RuntimeStateERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEEC2IJRPNS_14RuntimeProfileERPNS_12RuntimeStateERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10shared_ptrINS_2io9IOContextEERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_
100
101
16
    ~IcebergReaderMixin() override = default;
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEED2Ev
Line
Count
Source
101
9
    ~IcebergReaderMixin() override = default;
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEED2Ev
Line
Count
Source
101
7
    ~IcebergReaderMixin() override = default;
102
103
    void set_current_file_info(const std::string& file_path, int32_t partition_spec_id,
104
0
                               const std::string& partition_data_json) {
105
0
        _current_file_path = file_path;
106
0
        _partition_spec_id = partition_spec_id;
107
0
        _partition_data_json = partition_data_json;
108
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21set_current_file_infoERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiSA_
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21set_current_file_infoERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiSA_
109
110
    enum { DATA, POSITION_DELETE, EQUALITY_DELETE, DELETION_VECTOR };
111
    enum Fileformat { NONE, PARQUET, ORC, AVRO };
112
113
    virtual void set_delete_rows() = 0;
114
    virtual void set_deletion_vector() = 0;
115
116
    // Table-level COUNT(*) is handled by CountReader (created by FileScanner after
117
    // init_reader). If _do_get_next_block is called, COUNT must have been resolved.
118
2
    Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override {
119
2
        DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT);
120
2
        return BaseReader::_do_get_next_block(block, read_rows, eof);
121
2
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE18_do_get_next_blockEPNS_5BlockEPmPb
Line
Count
Source
118
1
    Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override {
119
        DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT);
120
1
        return BaseReader::_do_get_next_block(block, read_rows, eof);
121
1
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE18_do_get_next_blockEPNS_5BlockEPmPb
Line
Count
Source
118
1
    Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override {
119
        DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT);
120
1
        return BaseReader::_do_get_next_block(block, read_rows, eof);
121
1
    }
122
123
    void set_create_row_id_column_iterator_func(
124
0
            std::function<std::shared_ptr<segment_v2::RowIdColumnIteratorV2>()> create_func) {
125
0
        _create_topn_row_id_column_iterator = create_func;
126
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE38set_create_row_id_column_iterator_funcESt8functionIFSt10shared_ptrINS_10segment_v221RowIdColumnIteratorV2EEvEE
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE38set_create_row_id_column_iterator_funcESt8functionIFSt10shared_ptrINS_10segment_v221RowIdColumnIteratorV2EEvEE
127
128
    Status TEST_read_deletion_vector(const std::string& data_file_path,
129
1
                                     const TIcebergDeleteFileDesc& delete_file_desc) {
130
1
        return read_deletion_vector(data_file_path, delete_file_desc);
131
1
    }
132
133
    Status TEST_position_delete_base(const std::string& data_file_path,
134
1
                                     const std::vector<TIcebergDeleteFileDesc>& delete_files) {
135
1
        return _position_delete_base(data_file_path, delete_files);
136
1
    }
137
138
protected:
139
    // ---- Hook implementations ----
140
141
    // Called before reading a block: expand block for equality delete columns + detect row_id
142
2
    Status on_before_read_block(Block* block) override {
143
2
        RETURN_IF_ERROR(_expand_block_if_need(block));
144
2
        return Status::OK();
145
2
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20on_before_read_blockEPNS_5BlockE
Line
Count
Source
142
1
    Status on_before_read_block(Block* block) override {
143
1
        RETURN_IF_ERROR(_expand_block_if_need(block));
144
1
        return Status::OK();
145
1
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20on_before_read_blockEPNS_5BlockE
Line
Count
Source
142
1
    Status on_before_read_block(Block* block) override {
143
1
        RETURN_IF_ERROR(_expand_block_if_need(block));
144
1
        return Status::OK();
145
1
    }
146
147
    /// Fill Iceberg $row_id synthesized column. Registered as handler during init.
148
0
    Status _fill_iceberg_row_id(Block* block, size_t rows) {
149
0
        int row_id_pos = block->get_position_by_name(BeConsts::ICEBERG_ROWID_COL);
150
0
        DORIS_CHECK(row_id_pos >= 0);
151
152
        // Lazy-init file info: only set when $row_id is actually needed.
153
0
        const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
154
0
        std::string file_path = table_desc.original_file_path;
155
0
        int32_t partition_spec_id =
156
0
                table_desc.__isset.partition_spec_id ? table_desc.partition_spec_id : 0;
157
0
        std::string partition_data_json;
158
0
        if (table_desc.__isset.partition_data_json) {
159
0
            partition_data_json = table_desc.partition_data_json;
160
0
        }
161
0
        set_current_file_info(file_path, partition_spec_id, partition_data_json);
162
163
0
        const auto& row_ids = this->current_batch_row_positions();
164
0
        auto& col_with_type = block->get_by_position(static_cast<size_t>(row_id_pos));
165
0
        MutableColumnPtr row_id_column;
166
0
        RETURN_IF_ERROR(_build_iceberg_rowid_column(col_with_type.type, _current_file_path, row_ids,
167
0
                                                    _partition_spec_id, _partition_data_json,
168
0
                                                    &row_id_column));
169
0
        col_with_type.column = std::move(row_id_column);
170
0
        return Status::OK();
171
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20_fill_iceberg_row_idEPNS_5BlockEm
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20_fill_iceberg_row_idEPNS_5BlockEm
172
173
0
    void _init_row_lineage_columns() {
174
0
        const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
175
0
        if (table_desc.__isset.first_row_id) {
176
0
            _row_lineage_columns.first_row_id = table_desc.first_row_id;
177
0
        }
178
0
        if (table_desc.__isset.last_updated_sequence_number) {
179
0
            _row_lineage_columns.last_updated_sequence_number =
180
0
                    table_desc.last_updated_sequence_number;
181
0
        }
182
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE25_init_row_lineage_columnsEv
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE25_init_row_lineage_columnsEv
183
184
0
    Status _fill_row_lineage_row_id(Block* block, size_t rows) {
185
0
        int col_pos = block->get_position_by_name(ROW_LINEAGE_ROW_ID);
186
0
        DORIS_CHECK(col_pos >= 0);
187
188
0
        if (_row_lineage_columns.first_row_id >= 0) {
189
0
            auto column_guard = block->mutate_column_scoped(col_pos);
190
0
            auto* nullable_column =
191
0
                    assert_cast<ColumnNullable*>(column_guard.mutable_column().get());
192
0
            auto& null_map = nullable_column->get_null_map_data();
193
0
            auto& data =
194
0
                    assert_cast<ColumnInt64&>(*nullable_column->get_nested_column_ptr()).get_data();
195
0
            const auto& row_ids = this->current_batch_row_positions();
196
0
            for (size_t i = 0; i < rows; ++i) {
197
0
                if (null_map[i] != 0) {
198
0
                    null_map[i] = 0;
199
0
                    data[i] = _row_lineage_columns.first_row_id + static_cast<int64_t>(row_ids[i]);
200
0
                }
201
0
            }
202
0
        }
203
0
        return Status::OK();
204
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE24_fill_row_lineage_row_idEPNS_5BlockEm
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE24_fill_row_lineage_row_idEPNS_5BlockEm
205
206
0
    Status _fill_row_lineage_last_updated_sequence_number(Block* block, size_t rows) {
207
0
        int col_pos = block->get_position_by_name(ROW_LINEAGE_LAST_UPDATED_SEQ_NUMBER);
208
0
        DORIS_CHECK(col_pos >= 0);
209
210
0
        if (_row_lineage_columns.last_updated_sequence_number >= 0) {
211
0
            auto column_guard = block->mutate_column_scoped(col_pos);
212
0
            auto* nullable_column =
213
0
                    assert_cast<ColumnNullable*>(column_guard.mutable_column().get());
214
0
            auto& null_map = nullable_column->get_null_map_data();
215
0
            auto& data =
216
0
                    assert_cast<ColumnInt64&>(*nullable_column->get_nested_column_ptr()).get_data();
217
0
            for (size_t i = 0; i < rows; ++i) {
218
0
                if (null_map[i] != 0) {
219
0
                    null_map[i] = 0;
220
0
                    data[i] = _row_lineage_columns.last_updated_sequence_number;
221
0
                }
222
0
            }
223
0
        }
224
0
        return Status::OK();
225
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE46_fill_row_lineage_last_updated_sequence_numberEPNS_5BlockEm
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE46_fill_row_lineage_last_updated_sequence_numberEPNS_5BlockEm
226
227
    // Called after reading a block: apply equality delete filter + shrink block
228
2
    Status on_after_read_block(Block* block, size_t* read_rows) override {
229
2
        if (!_equality_delete_impls.empty()) {
230
0
            std::unique_ptr<IColumn::Filter> filter =
231
0
                    std::make_unique<IColumn::Filter>(block->rows(), 1);
232
0
            for (auto& equality_delete_impl : _equality_delete_impls) {
233
0
                RETURN_IF_ERROR(equality_delete_impl->filter_data_block(
234
0
                        block, this->col_name_to_block_idx_ref(), _id_to_block_column_name,
235
0
                        *filter));
236
0
            }
237
0
            Block::filter_block_internal(block, *filter, block->columns());
238
0
            *read_rows = block->rows();
239
0
        }
240
2
        return _shrink_block_if_need(block);
241
2
    }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE19on_after_read_blockEPNS_5BlockEPm
Line
Count
Source
228
1
    Status on_after_read_block(Block* block, size_t* read_rows) override {
229
1
        if (!_equality_delete_impls.empty()) {
230
0
            std::unique_ptr<IColumn::Filter> filter =
231
0
                    std::make_unique<IColumn::Filter>(block->rows(), 1);
232
0
            for (auto& equality_delete_impl : _equality_delete_impls) {
233
0
                RETURN_IF_ERROR(equality_delete_impl->filter_data_block(
234
0
                        block, this->col_name_to_block_idx_ref(), _id_to_block_column_name,
235
0
                        *filter));
236
0
            }
237
0
            Block::filter_block_internal(block, *filter, block->columns());
238
0
            *read_rows = block->rows();
239
0
        }
240
1
        return _shrink_block_if_need(block);
241
1
    }
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE19on_after_read_blockEPNS_5BlockEPm
Line
Count
Source
228
1
    Status on_after_read_block(Block* block, size_t* read_rows) override {
229
1
        if (!_equality_delete_impls.empty()) {
230
0
            std::unique_ptr<IColumn::Filter> filter =
231
0
                    std::make_unique<IColumn::Filter>(block->rows(), 1);
232
0
            for (auto& equality_delete_impl : _equality_delete_impls) {
233
0
                RETURN_IF_ERROR(equality_delete_impl->filter_data_block(
234
0
                        block, this->col_name_to_block_idx_ref(), _id_to_block_column_name,
235
0
                        *filter));
236
0
            }
237
0
            Block::filter_block_internal(block, *filter, block->columns());
238
0
            *read_rows = block->rows();
239
0
        }
240
1
        return _shrink_block_if_need(block);
241
1
    }
242
243
    // ---- Shared Iceberg methods ----
244
245
    Status _init_row_filters();
246
    Status _position_delete_base(const std::string data_file_path,
247
                                 const std::vector<TIcebergDeleteFileDesc>& delete_files);
248
    Status _equality_delete_base(const std::vector<TIcebergDeleteFileDesc>& delete_files);
249
    Status read_deletion_vector(const std::string& data_file_path,
250
                                const TIcebergDeleteFileDesc& delete_file_desc);
251
252
    Status _expand_block_if_need(Block* block);
253
    Status _shrink_block_if_need(Block* block);
254
255
    // Type aliases — must be defined before member function declarations that use them.
256
    using DeleteRows = std::vector<int64_t>;
257
    using DeleteFile = phmap::parallel_flat_hash_map<
258
            std::string, std::unique_ptr<DeleteRows>, std::hash<std::string>, std::equal_to<>,
259
            std::allocator<std::pair<const std::string, std::unique_ptr<DeleteRows>>>, 8,
260
            std::mutex>;
261
262
    PositionDeleteRange _get_range(const ColumnDictI32& file_path_column);
263
    PositionDeleteRange _get_range(const ColumnString& file_path_column);
264
    static void _sort_delete_rows(const std::vector<std::vector<int64_t>*>& delete_rows_array,
265
                                  int64_t num_delete_rows, std::vector<int64_t>& result);
266
    Status _gen_position_delete_file_range(Block& block, DeleteFile* position_delete,
267
                                           size_t read_rows,
268
                                           bool file_path_column_dictionary_coded);
269
    void _generate_equality_delete_block(Block* block,
270
                                         const std::vector<std::string>& equality_delete_col_names,
271
                                         const std::vector<DataTypePtr>& equality_delete_col_types);
272
273
    // Pure virtual: format-specific delete file reading
274
    virtual Status _read_position_delete_file(const TFileRangeDesc*, DeleteFile*) = 0;
275
    virtual std::unique_ptr<GenericReader> _create_equality_reader(
276
            const TFileRangeDesc& delete_desc) = 0;
277
278
1
    static std::string _delet_file_cache_key(const std::string& path) { return "delete_" + path; }
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_delet_file_cache_keyERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Line
Count
Source
278
1
    static std::string _delet_file_cache_key(const std::string& path) { return "delete_" + path; }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_delet_file_cache_keyERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
279
280
    /// Build the Iceberg V2 row-id struct column.
281
    static Status _build_iceberg_rowid_column(const DataTypePtr& type, const std::string& file_path,
282
                                              const std::vector<rowid_t>& row_ids,
283
                                              int32_t partition_spec_id,
284
                                              const std::string& partition_data_json,
285
0
                                              MutableColumnPtr* column_out) {
286
0
        if (type == nullptr || column_out == nullptr) {
287
0
            return Status::InvalidArgument("Invalid iceberg rowid column type or output column");
288
0
        }
289
0
        MutableColumnPtr column = type->create_column();
290
0
        ColumnNullable* nullable_col = check_and_get_column<ColumnNullable>(column.get());
291
0
        ColumnStruct* struct_col = nullptr;
292
0
        if (nullable_col != nullptr) {
293
0
            struct_col =
294
0
                    check_and_get_column<ColumnStruct>(nullable_col->get_nested_column_ptr().get());
295
0
        } else {
296
0
            struct_col = check_and_get_column<ColumnStruct>(column.get());
297
0
        }
298
0
        if (struct_col == nullptr || struct_col->tuple_size() < 4) {
299
0
            return Status::InternalError("Invalid iceberg rowid column structure");
300
0
        }
301
0
        size_t num_rows = row_ids.size();
302
0
        auto& file_path_col = struct_col->get_column(0);
303
0
        auto& row_pos_col = struct_col->get_column(1);
304
0
        auto& spec_id_col = struct_col->get_column(2);
305
0
        auto& partition_data_col = struct_col->get_column(3);
306
0
        file_path_col.reserve(num_rows);
307
0
        row_pos_col.reserve(num_rows);
308
0
        spec_id_col.reserve(num_rows);
309
0
        partition_data_col.reserve(num_rows);
310
0
        for (size_t i = 0; i < num_rows; ++i) {
311
0
            file_path_col.insert_data(file_path.data(), file_path.size());
312
0
        }
313
0
        for (size_t i = 0; i < num_rows; ++i) {
314
0
            int64_t row_pos = static_cast<int64_t>(row_ids[i]);
315
0
            row_pos_col.insert_data(reinterpret_cast<const char*>(&row_pos), sizeof(row_pos));
316
0
        }
317
0
        for (size_t i = 0; i < num_rows; ++i) {
318
0
            int32_t spec_id = partition_spec_id;
319
0
            spec_id_col.insert_data(reinterpret_cast<const char*>(&spec_id), sizeof(spec_id));
320
0
        }
321
0
        for (size_t i = 0; i < num_rows; ++i) {
322
0
            partition_data_col.insert_data(partition_data_json.data(), partition_data_json.size());
323
0
        }
324
0
        if (nullable_col != nullptr) {
325
0
            nullable_col->get_null_map_data().resize_fill(num_rows, 0);
326
0
        }
327
0
        *column_out = std::move(column);
328
0
        return Status::OK();
329
0
    }
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE27_build_iceberg_rowid_columnERKSt10shared_ptrIKNS_9IDataTypeEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIjSaIjEEiSG_PNS_3COWINS_7IColumnEE11mutable_ptrISN_EE
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE27_build_iceberg_rowid_columnERKSt10shared_ptrIKNS_9IDataTypeEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIjSaIjEEiSG_PNS_3COWINS_7IColumnEE11mutable_ptrISN_EE
330
331
    struct IcebergProfile {
332
        RuntimeProfile::Counter* num_delete_files;
333
        RuntimeProfile::Counter* num_delete_rows;
334
        RuntimeProfile::Counter* delete_files_read_time;
335
        RuntimeProfile::Counter* delete_rows_sort_time;
336
        RuntimeProfile::Counter* parse_delete_file_time;
337
        RuntimeProfile::Counter* decoded_cache_hit_count;
338
        RuntimeProfile::Counter* decoded_cache_miss_count;
339
        RuntimeProfile::Counter* file_cache_hit_count;
340
        RuntimeProfile::Counter* file_cache_miss_count;
341
        RuntimeProfile::Counter* file_cache_peer_read_count;
342
    };
343
344
    bool _need_row_id_column = false;
345
    std::string _current_file_path;
346
    int32_t _partition_spec_id = 0;
347
    std::string _partition_data_json;
348
349
    ShardedKVCache* _kv_cache;
350
    IcebergProfile _iceberg_profile;
351
    const std::vector<int64_t>* _iceberg_delete_rows = nullptr;
352
    const DeletionVector* _iceberg_deletion_vector = nullptr;
353
    std::vector<std::string> _expand_col_names;
354
    std::vector<ColumnWithTypeAndName> _expand_columns;
355
    std::vector<std::string> _all_required_col_names;
356
    Fileformat _file_format = Fileformat::NONE;
357
358
    const int64_t MIN_SUPPORT_DELETE_FILES_VERSION = 2;
359
    const std::string ICEBERG_FILE_PATH = "file_path";
360
    const std::string ICEBERG_ROW_POS = "pos";
361
    const std::vector<std::string> delete_file_col_names {ICEBERG_FILE_PATH, ICEBERG_ROW_POS};
362
    const std::unordered_map<std::string, uint32_t> DELETE_COL_NAME_TO_BLOCK_IDX = {
363
            {ICEBERG_FILE_PATH, 0}, {ICEBERG_ROW_POS, 1}};
364
    const int ICEBERG_FILE_PATH_INDEX = 0;
365
    const int ICEBERG_FILE_POS_INDEX = 1;
366
    const int READ_DELETE_FILE_BATCH_SIZE = 102400;
367
368
    // all ids that need read for eq delete (from all eq delete files)
369
    std::set<int> _equality_delete_col_ids;
370
    // eq delete column ids -> location of _equality_delete_blocks / _equality_delete_impls
371
    std::map<std::vector<int>, int> _equality_delete_block_map;
372
    // EqualityDeleteBase stores raw pointers to these blocks, so do not modify this vector after
373
    // creating entries in _equality_delete_impls.
374
    std::vector<Block> _equality_delete_blocks;
375
    std::vector<std::unique_ptr<EqualityDeleteBase>> _equality_delete_impls;
376
377
    // id -> block column name
378
    std::unordered_map<int, std::string> _id_to_block_column_name;
379
380
    std::function<std::shared_ptr<segment_v2::RowIdColumnIteratorV2>()>
381
            _create_topn_row_id_column_iterator;
382
383
    static constexpr const char* ROW_LINEAGE_ROW_ID = "_row_id";
384
    static constexpr const char* ROW_LINEAGE_LAST_UPDATED_SEQ_NUMBER =
385
            "_last_updated_sequence_number";
386
    struct RowLineageColumns {
387
        int64_t first_row_id = -1;
388
        int64_t last_updated_sequence_number = -1;
389
    };
390
    RowLineageColumns _row_lineage_columns;
391
};
392
393
// ============================================================================
394
// Template method implementations (must be in header for templates)
395
// ============================================================================
396
397
template <typename BaseReader>
398
2
Status IcebergReaderMixin<BaseReader>::_init_row_filters() {
399
    // COUNT(*) short-circuit. A table-level row count of 0 (e.g. an all-deleted table read with
400
    // ignore_iceberg_dangling_delete, where total-records == total-position-deletes) is still a
401
    // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE
402
    // sends -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the
403
    // delete-applying path below and never produce the intended CountReader(0).
404
2
    if (this->_push_down_agg_type == TPushAggOp::type::COUNT &&
405
2
        this->get_scan_range().table_format_params.__isset.table_level_row_count &&
406
2
        this->get_scan_range().table_format_params.table_level_row_count >= 0) {
407
0
        return Status::OK();
408
0
    }
409
410
2
    const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
411
2
    const auto& version = table_desc.format_version;
412
2
    if (version < MIN_SUPPORT_DELETE_FILES_VERSION) {
413
2
        return Status::OK();
414
2
    }
415
416
0
    std::vector<TIcebergDeleteFileDesc> position_delete_files;
417
0
    std::vector<TIcebergDeleteFileDesc> equality_delete_files;
418
0
    std::vector<TIcebergDeleteFileDesc> deletion_vector_files;
419
0
    for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) {
420
0
        if (desc.content == POSITION_DELETE) {
421
0
            position_delete_files.emplace_back(desc);
422
0
        } else if (desc.content == EQUALITY_DELETE) {
423
0
            equality_delete_files.emplace_back(desc);
424
0
        } else if (desc.content == DELETION_VECTOR) {
425
0
            deletion_vector_files.emplace_back(desc);
426
0
        }
427
0
    }
428
429
0
    if (!equality_delete_files.empty()) {
430
0
        RETURN_IF_ERROR(_equality_delete_base(equality_delete_files));
431
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
432
0
    }
433
434
0
    if (!deletion_vector_files.empty()) {
435
0
        if (deletion_vector_files.size() != 1) [[unlikely]] {
436
            /*
437
             * Deletion vectors are a binary representation of deletes for a single data file that is more efficient
438
             * at execution time than position delete files. Unlike equality or position delete files, there can be
439
             * at most one deletion vector for a given data file in a snapshot.
440
             */
441
0
            return Status::DataQualityError("This iceberg data file has multiple DVs.");
442
0
        }
443
0
        RETURN_IF_ERROR(
444
0
                read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0]));
445
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
446
0
    } else if (!position_delete_files.empty()) {
447
0
        RETURN_IF_ERROR(
448
0
                _position_delete_base(table_desc.original_file_path, position_delete_files));
449
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
450
0
    }
451
452
0
    COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size());
453
0
    return Status::OK();
454
0
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE17_init_row_filtersEv
Line
Count
Source
398
1
Status IcebergReaderMixin<BaseReader>::_init_row_filters() {
399
    // COUNT(*) short-circuit. A table-level row count of 0 (e.g. an all-deleted table read with
400
    // ignore_iceberg_dangling_delete, where total-records == total-position-deletes) is still a
401
    // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE
402
    // sends -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the
403
    // delete-applying path below and never produce the intended CountReader(0).
404
1
    if (this->_push_down_agg_type == TPushAggOp::type::COUNT &&
405
1
        this->get_scan_range().table_format_params.__isset.table_level_row_count &&
406
1
        this->get_scan_range().table_format_params.table_level_row_count >= 0) {
407
0
        return Status::OK();
408
0
    }
409
410
1
    const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
411
1
    const auto& version = table_desc.format_version;
412
1
    if (version < MIN_SUPPORT_DELETE_FILES_VERSION) {
413
1
        return Status::OK();
414
1
    }
415
416
0
    std::vector<TIcebergDeleteFileDesc> position_delete_files;
417
0
    std::vector<TIcebergDeleteFileDesc> equality_delete_files;
418
0
    std::vector<TIcebergDeleteFileDesc> deletion_vector_files;
419
0
    for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) {
420
0
        if (desc.content == POSITION_DELETE) {
421
0
            position_delete_files.emplace_back(desc);
422
0
        } else if (desc.content == EQUALITY_DELETE) {
423
0
            equality_delete_files.emplace_back(desc);
424
0
        } else if (desc.content == DELETION_VECTOR) {
425
0
            deletion_vector_files.emplace_back(desc);
426
0
        }
427
0
    }
428
429
0
    if (!equality_delete_files.empty()) {
430
0
        RETURN_IF_ERROR(_equality_delete_base(equality_delete_files));
431
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
432
0
    }
433
434
0
    if (!deletion_vector_files.empty()) {
435
0
        if (deletion_vector_files.size() != 1) [[unlikely]] {
436
            /*
437
             * Deletion vectors are a binary representation of deletes for a single data file that is more efficient
438
             * at execution time than position delete files. Unlike equality or position delete files, there can be
439
             * at most one deletion vector for a given data file in a snapshot.
440
             */
441
0
            return Status::DataQualityError("This iceberg data file has multiple DVs.");
442
0
        }
443
0
        RETURN_IF_ERROR(
444
0
                read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0]));
445
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
446
0
    } else if (!position_delete_files.empty()) {
447
0
        RETURN_IF_ERROR(
448
0
                _position_delete_base(table_desc.original_file_path, position_delete_files));
449
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
450
0
    }
451
452
0
    COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size());
453
0
    return Status::OK();
454
0
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE17_init_row_filtersEv
Line
Count
Source
398
1
Status IcebergReaderMixin<BaseReader>::_init_row_filters() {
399
    // COUNT(*) short-circuit. A table-level row count of 0 (e.g. an all-deleted table read with
400
    // ignore_iceberg_dangling_delete, where total-records == total-position-deletes) is still a
401
    // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE
402
    // sends -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the
403
    // delete-applying path below and never produce the intended CountReader(0).
404
1
    if (this->_push_down_agg_type == TPushAggOp::type::COUNT &&
405
1
        this->get_scan_range().table_format_params.__isset.table_level_row_count &&
406
1
        this->get_scan_range().table_format_params.table_level_row_count >= 0) {
407
0
        return Status::OK();
408
0
    }
409
410
1
    const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params;
411
1
    const auto& version = table_desc.format_version;
412
1
    if (version < MIN_SUPPORT_DELETE_FILES_VERSION) {
413
1
        return Status::OK();
414
1
    }
415
416
0
    std::vector<TIcebergDeleteFileDesc> position_delete_files;
417
0
    std::vector<TIcebergDeleteFileDesc> equality_delete_files;
418
0
    std::vector<TIcebergDeleteFileDesc> deletion_vector_files;
419
0
    for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) {
420
0
        if (desc.content == POSITION_DELETE) {
421
0
            position_delete_files.emplace_back(desc);
422
0
        } else if (desc.content == EQUALITY_DELETE) {
423
0
            equality_delete_files.emplace_back(desc);
424
0
        } else if (desc.content == DELETION_VECTOR) {
425
0
            deletion_vector_files.emplace_back(desc);
426
0
        }
427
0
    }
428
429
0
    if (!equality_delete_files.empty()) {
430
0
        RETURN_IF_ERROR(_equality_delete_base(equality_delete_files));
431
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
432
0
    }
433
434
0
    if (!deletion_vector_files.empty()) {
435
0
        if (deletion_vector_files.size() != 1) [[unlikely]] {
436
            /*
437
             * Deletion vectors are a binary representation of deletes for a single data file that is more efficient
438
             * at execution time than position delete files. Unlike equality or position delete files, there can be
439
             * at most one deletion vector for a given data file in a snapshot.
440
             */
441
0
            return Status::DataQualityError("This iceberg data file has multiple DVs.");
442
0
        }
443
0
        RETURN_IF_ERROR(
444
0
                read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0]));
445
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
446
0
    } else if (!position_delete_files.empty()) {
447
0
        RETURN_IF_ERROR(
448
0
                _position_delete_base(table_desc.original_file_path, position_delete_files));
449
0
        this->set_push_down_agg_type(TPushAggOp::NONE);
450
0
    }
451
452
0
    COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size());
453
0
    return Status::OK();
454
0
}
455
456
template <typename BaseReader>
457
Status IcebergReaderMixin<BaseReader>::_equality_delete_base(
458
0
        const std::vector<TIcebergDeleteFileDesc>& delete_files) {
459
0
    std::unordered_map<std::string, std::tuple<std::string, const SlotDescriptor*>>
460
0
            partition_columns;
461
0
    std::unordered_map<std::string, VExprContextSPtr> missing_columns;
462
463
0
    for (const auto& delete_file : delete_files) {
464
0
        TFileRangeDesc delete_desc;
465
0
        delete_desc.__set_fs_name(this->get_scan_range().fs_name);
466
0
        delete_desc.path = delete_file.path;
467
0
        delete_desc.start_offset = 0;
468
0
        delete_desc.size = -1;
469
0
        delete_desc.file_size = -1;
470
471
0
        if (!delete_file.__isset.field_ids) [[unlikely]] {
472
0
            return Status::InternalError(
473
0
                    "missing delete field ids when reading equality delete file");
474
0
        }
475
0
        auto& read_column_field_ids = delete_file.field_ids;
476
0
        std::set<int> read_column_field_ids_set;
477
0
        for (const auto& field_id : read_column_field_ids) {
478
0
            read_column_field_ids_set.insert(field_id);
479
0
            _equality_delete_col_ids.insert(field_id);
480
0
        }
481
482
0
        std::unique_ptr<GenericReader> delete_reader = _create_equality_reader(delete_desc);
483
0
        RETURN_IF_ERROR(delete_reader->init_schema_reader());
484
485
0
        std::vector<std::string> equality_delete_col_names;
486
0
        std::vector<DataTypePtr> equality_delete_col_types;
487
488
        // Build delete col names/types/ids by matching field_ids from delete file schema.
489
        // Master iterates delete file's FieldDescriptor and uses field_id to match,
490
        // NOT idx-based pairing (get_parsed_schema order != field_ids order).
491
0
        std::vector<std::string> delete_col_names;
492
0
        std::vector<DataTypePtr> delete_col_types;
493
0
        std::vector<int> delete_col_ids;
494
0
        std::unordered_map<std::string, uint32_t> delete_col_name_to_block_idx;
495
496
0
        if (auto* parquet_reader = typeid_cast<ParquetReader*>(delete_reader.get())) {
497
0
            const FieldDescriptor* delete_field_desc = nullptr;
498
0
            RETURN_IF_ERROR(parquet_reader->get_file_metadata_schema(&delete_field_desc));
499
0
            DCHECK(delete_field_desc != nullptr);
500
501
0
            for (const auto& delete_file_field : delete_field_desc->get_fields_schema()) {
502
0
                if (delete_file_field.field_id == -1) [[unlikely]] {
503
0
                    return Status::DataQualityError(
504
0
                            "missing field id when reading equality delete file");
505
0
                }
506
0
                if (!read_column_field_ids_set.contains(delete_file_field.field_id)) {
507
0
                    continue;
508
0
                }
509
0
                if (delete_file_field.children.size() > 0) [[unlikely]] {
510
0
                    return Status::InternalError(
511
0
                            "can not support read complex column in equality delete file");
512
0
                }
513
514
0
                delete_col_ids.emplace_back(delete_file_field.field_id);
515
0
                delete_col_names.emplace_back(delete_file_field.name);
516
0
                delete_col_types.emplace_back(make_nullable(delete_file_field.data_type));
517
518
0
                int field_id = delete_file_field.field_id;
519
0
                if (!_id_to_block_column_name.contains(field_id)) {
520
0
                    _id_to_block_column_name.emplace(field_id, delete_file_field.name);
521
0
                    _expand_col_names.emplace_back(delete_file_field.name);
522
0
                    _expand_columns.emplace_back(
523
0
                            make_nullable(delete_file_field.data_type)->create_column(),
524
0
                            make_nullable(delete_file_field.data_type), delete_file_field.name);
525
0
                }
526
0
            }
527
0
            for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) {
528
0
                delete_col_name_to_block_idx[delete_col_names[idx]] = idx;
529
0
            }
530
            // Delete files have TFileRangeDesc.size=-1, which would cause
531
            // set_fill_columns to return EndOfFile("No row group to read")
532
            // when _filter_groups is true. Master passes filter_groups=false.
533
0
            ParquetInitContext eq_delete_ctx;
534
0
            eq_delete_ctx.filter_groups = false;
535
0
            eq_delete_ctx.column_names = delete_col_names;
536
0
            eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx;
537
0
            auto st2 = parquet_reader->init_reader(&eq_delete_ctx);
538
0
            if (!st2.ok()) {
539
0
                return st2;
540
0
            }
541
0
        } else if (auto* orc_reader = typeid_cast<OrcReader*>(delete_reader.get())) {
542
            // For ORC: use get_parsed_schema with field_ids from delete_file
543
            // ORC field_ids come from the Thrift descriptor, not from ORC metadata
544
0
            RETURN_IF_ERROR(delete_reader->get_parsed_schema(&equality_delete_col_names,
545
0
                                                             &equality_delete_col_types));
546
0
            for (uint32_t idx = 0; idx < equality_delete_col_names.size(); ++idx) {
547
0
                if (idx < read_column_field_ids.size()) {
548
0
                    int field_id = read_column_field_ids[idx];
549
0
                    if (!read_column_field_ids_set.contains(field_id)) continue;
550
0
                    delete_col_ids.emplace_back(field_id);
551
0
                    delete_col_names.emplace_back(equality_delete_col_names[idx]);
552
0
                    delete_col_types.emplace_back(make_nullable(equality_delete_col_types[idx]));
553
0
                    if (!_id_to_block_column_name.contains(field_id)) {
554
0
                        _id_to_block_column_name.emplace(field_id, equality_delete_col_names[idx]);
555
0
                        _expand_col_names.emplace_back(equality_delete_col_names[idx]);
556
0
                        _expand_columns.emplace_back(
557
0
                                make_nullable(equality_delete_col_types[idx])->create_column(),
558
0
                                make_nullable(equality_delete_col_types[idx]),
559
0
                                equality_delete_col_names[idx]);
560
0
                    }
561
0
                }
562
0
            }
563
0
            for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) {
564
0
                delete_col_name_to_block_idx[delete_col_names[idx]] = idx;
565
0
            }
566
0
            OrcInitContext eq_delete_ctx;
567
0
            eq_delete_ctx.column_names = delete_col_names;
568
0
            eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx;
569
0
            RETURN_IF_ERROR(orc_reader->init_reader(&eq_delete_ctx));
570
0
        } else {
571
0
            return Status::InternalError("Unsupported format of delete file");
572
0
        }
573
574
0
        if (!_equality_delete_block_map.contains(delete_col_ids)) {
575
0
            _equality_delete_block_map.emplace(delete_col_ids, _equality_delete_blocks.size());
576
0
            Block block;
577
0
            _generate_equality_delete_block(&block, delete_col_names, delete_col_types);
578
0
            _equality_delete_blocks.emplace_back(block);
579
0
        }
580
0
        Block& eq_file_block = _equality_delete_blocks[_equality_delete_block_map[delete_col_ids]];
581
582
0
        bool eof = false;
583
0
        while (!eof) {
584
0
            Block tmp_block;
585
0
            _generate_equality_delete_block(&tmp_block, delete_col_names, delete_col_types);
586
0
            size_t read_rows = 0;
587
0
            auto st = delete_reader->get_next_block(&tmp_block, &read_rows, &eof);
588
0
            if (!st.ok()) {
589
0
                return st;
590
0
            }
591
0
            if (read_rows > 0) {
592
0
                ScopedMutableBlock scoped_mutable_block(&eq_file_block);
593
0
                auto& mutable_block = scoped_mutable_block.mutable_block();
594
0
                RETURN_IF_ERROR(mutable_block.merge(tmp_block));
595
0
            }
596
0
        }
597
0
    }
598
599
0
    for (const auto& [delete_col_ids, block_idx] : _equality_delete_block_map) {
600
0
        auto& eq_file_block = _equality_delete_blocks[block_idx];
601
0
        auto equality_delete_impl =
602
0
                EqualityDeleteBase::get_delete_impl(&eq_file_block, delete_col_ids);
603
0
        RETURN_IF_ERROR(equality_delete_impl->init(this->get_profile()));
604
0
        _equality_delete_impls.emplace_back(std::move(equality_delete_impl));
605
0
    }
606
0
    return Status::OK();
607
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_equality_delete_baseERKSt6vectorINS_22TIcebergDeleteFileDescESaIS4_EE
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_equality_delete_baseERKSt6vectorINS_22TIcebergDeleteFileDescESaIS4_EE
608
609
template <typename BaseReader>
610
void IcebergReaderMixin<BaseReader>::_generate_equality_delete_block(
611
        Block* block, const std::vector<std::string>& equality_delete_col_names,
612
0
        const std::vector<DataTypePtr>& equality_delete_col_types) {
613
0
    for (int i = 0; i < equality_delete_col_names.size(); ++i) {
614
0
        DataTypePtr data_type = make_nullable(equality_delete_col_types[i]);
615
0
        MutableColumnPtr data_column = data_type->create_column();
616
0
        block->insert(ColumnWithTypeAndName(std::move(data_column), data_type,
617
0
                                            equality_delete_col_names[i]));
618
0
    }
619
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE31_generate_equality_delete_blockEPNS_5BlockERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EERKS5_ISt10shared_ptrIKNS_9IDataTypeEESaISJ_EE
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE31_generate_equality_delete_blockEPNS_5BlockERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EERKS5_ISt10shared_ptrIKNS_9IDataTypeEESaISJ_EE
620
621
template <typename BaseReader>
622
2
Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) {
623
2
    std::set<std::string> names;
624
2
    auto block_names = block->get_names();
625
2
    names.insert(block_names.begin(), block_names.end());
626
2
    for (auto& col : _expand_columns) {
627
0
        if (names.contains(col.name)) {
628
0
            return Status::InternalError("Wrong expand column '{}'", col.name);
629
0
        }
630
0
        names.insert(col.name);
631
0
        (*this->col_name_to_block_idx_ref())[col.name] = block->columns();
632
0
        block->insert({col.type->create_column(), col.type, col.name});
633
0
    }
634
2
    return Status::OK();
635
2
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_expand_block_if_needEPNS_5BlockE
Line
Count
Source
622
1
Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) {
623
1
    std::set<std::string> names;
624
1
    auto block_names = block->get_names();
625
1
    names.insert(block_names.begin(), block_names.end());
626
1
    for (auto& col : _expand_columns) {
627
0
        if (names.contains(col.name)) {
628
0
            return Status::InternalError("Wrong expand column '{}'", col.name);
629
0
        }
630
0
        names.insert(col.name);
631
0
        (*this->col_name_to_block_idx_ref())[col.name] = block->columns();
632
0
        block->insert({col.type->create_column(), col.type, col.name});
633
0
    }
634
1
    return Status::OK();
635
1
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_expand_block_if_needEPNS_5BlockE
Line
Count
Source
622
1
Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) {
623
1
    std::set<std::string> names;
624
1
    auto block_names = block->get_names();
625
1
    names.insert(block_names.begin(), block_names.end());
626
1
    for (auto& col : _expand_columns) {
627
0
        if (names.contains(col.name)) {
628
0
            return Status::InternalError("Wrong expand column '{}'", col.name);
629
0
        }
630
0
        names.insert(col.name);
631
0
        (*this->col_name_to_block_idx_ref())[col.name] = block->columns();
632
0
        block->insert({col.type->create_column(), col.type, col.name});
633
0
    }
634
1
    return Status::OK();
635
1
}
636
637
template <typename BaseReader>
638
2
Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) {
639
2
    std::set<size_t> positions_to_erase;
640
2
    for (const std::string& expand_col : _expand_col_names) {
641
0
        if (!this->col_name_to_block_idx_ref()->contains(expand_col)) {
642
0
            return Status::InternalError("Wrong erase column '{}', block: {}", expand_col,
643
0
                                         block->dump_names());
644
0
        }
645
0
        positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]);
646
0
    }
647
2
    block->erase(positions_to_erase);
648
2
    for (const std::string& expand_col : _expand_col_names) {
649
0
        this->col_name_to_block_idx_ref()->erase(expand_col);
650
0
    }
651
2
    return Status::OK();
652
2
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_shrink_block_if_needEPNS_5BlockE
Line
Count
Source
638
1
Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) {
639
1
    std::set<size_t> positions_to_erase;
640
1
    for (const std::string& expand_col : _expand_col_names) {
641
0
        if (!this->col_name_to_block_idx_ref()->contains(expand_col)) {
642
0
            return Status::InternalError("Wrong erase column '{}', block: {}", expand_col,
643
0
                                         block->dump_names());
644
0
        }
645
0
        positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]);
646
0
    }
647
1
    block->erase(positions_to_erase);
648
1
    for (const std::string& expand_col : _expand_col_names) {
649
0
        this->col_name_to_block_idx_ref()->erase(expand_col);
650
0
    }
651
1
    return Status::OK();
652
1
}
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_shrink_block_if_needEPNS_5BlockE
Line
Count
Source
638
1
Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) {
639
1
    std::set<size_t> positions_to_erase;
640
1
    for (const std::string& expand_col : _expand_col_names) {
641
0
        if (!this->col_name_to_block_idx_ref()->contains(expand_col)) {
642
0
            return Status::InternalError("Wrong erase column '{}', block: {}", expand_col,
643
0
                                         block->dump_names());
644
0
        }
645
0
        positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]);
646
0
    }
647
1
    block->erase(positions_to_erase);
648
1
    for (const std::string& expand_col : _expand_col_names) {
649
0
        this->col_name_to_block_idx_ref()->erase(expand_col);
650
0
    }
651
1
    return Status::OK();
652
1
}
653
654
template <typename BaseReader>
655
Status IcebergReaderMixin<BaseReader>::_position_delete_base(
656
1
        const std::string data_file_path, const std::vector<TIcebergDeleteFileDesc>& delete_files) {
657
1
    std::vector<DeleteRows*> delete_rows_array;
658
1
    int64_t num_delete_rows = 0;
659
1
    for (const auto& delete_file : delete_files) {
660
1
        SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
661
1
        Status create_status = Status::OK();
662
1
        auto* delete_file_cache = _kv_cache->template get<DeleteFile>(
663
1
                _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* {
664
1
                    auto position_delete = std::make_unique<DeleteFile>();
665
1
                    TFileRangeDesc delete_file_range;
666
1
                    delete_file_range.__set_fs_name(this->get_scan_range().fs_name);
667
1
                    delete_file_range.path = delete_file.path;
668
1
                    delete_file_range.start_offset = 0;
669
1
                    delete_file_range.size = -1;
670
1
                    delete_file_range.file_size = -1;
671
1
                    create_status =
672
1
                            _read_position_delete_file(&delete_file_range, position_delete.get());
673
1
                    if (!create_status) {
674
1
                        return nullptr;
675
1
                    }
676
0
                    return position_delete.release();
677
1
                });
_ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE_clB5cxx11Ev
Line
Count
Source
663
1
                _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* {
664
1
                    auto position_delete = std::make_unique<DeleteFile>();
665
1
                    TFileRangeDesc delete_file_range;
666
1
                    delete_file_range.__set_fs_name(this->get_scan_range().fs_name);
667
1
                    delete_file_range.path = delete_file.path;
668
1
                    delete_file_range.start_offset = 0;
669
1
                    delete_file_range.size = -1;
670
1
                    delete_file_range.file_size = -1;
671
1
                    create_status =
672
1
                            _read_position_delete_file(&delete_file_range, position_delete.get());
673
1
                    if (!create_status) {
674
1
                        return nullptr;
675
1
                    }
676
0
                    return position_delete.release();
677
1
                });
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE_clB5cxx11Ev
678
1
        if (create_status.is<ErrorCode::END_OF_FILE>()) {
679
0
            continue;
680
1
        } else if (!create_status.ok()) {
681
1
            return create_status;
682
1
        }
683
684
0
        DeleteFile& delete_file_map = *((DeleteFile*)delete_file_cache);
685
0
        auto get_value = [&](const auto& v) {
686
0
            DeleteRows* row_ids = v.second.get();
687
0
            if (!row_ids->empty()) {
688
0
                delete_rows_array.emplace_back(row_ids);
689
0
                num_delete_rows += row_ids->size();
690
0
            }
691
0
        };
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlRKT_E_clISt4pairIKS8_St10unique_ptrIS9_IlSaIlEESt14default_deleteISO_EEEEEDaSH_
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlRKT_E_clISt4pairIKS8_St10unique_ptrIS9_IlSaIlEESt14default_deleteISO_EEEEEDaSH_
692
0
        delete_file_map.if_contains(data_file_path, get_value);
693
0
    }
694
0
    if (num_delete_rows > 0) {
695
0
        SCOPED_TIMER(_iceberg_profile.delete_rows_sort_time);
696
0
        _iceberg_delete_rows =
697
0
                _kv_cache->template get<DeleteRows>(data_file_path, [&]() -> DeleteRows* {
698
0
                    auto data_file_position_delete = std::make_unique<DeleteRows>();
699
0
                    _sort_delete_rows(delete_rows_array, num_delete_rows,
700
0
                                      *data_file_position_delete);
701
0
                    return data_file_position_delete.release();
702
0
                });
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE0_clEv
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE0_clEv
703
0
        set_delete_rows();
704
0
        COUNTER_UPDATE(_iceberg_profile.num_delete_rows, num_delete_rows);
705
0
    }
706
0
    return Status::OK();
707
1
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EE
Line
Count
Source
656
1
        const std::string data_file_path, const std::vector<TIcebergDeleteFileDesc>& delete_files) {
657
1
    std::vector<DeleteRows*> delete_rows_array;
658
1
    int64_t num_delete_rows = 0;
659
1
    for (const auto& delete_file : delete_files) {
660
1
        SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
661
1
        Status create_status = Status::OK();
662
1
        auto* delete_file_cache = _kv_cache->template get<DeleteFile>(
663
1
                _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* {
664
1
                    auto position_delete = std::make_unique<DeleteFile>();
665
1
                    TFileRangeDesc delete_file_range;
666
1
                    delete_file_range.__set_fs_name(this->get_scan_range().fs_name);
667
1
                    delete_file_range.path = delete_file.path;
668
1
                    delete_file_range.start_offset = 0;
669
1
                    delete_file_range.size = -1;
670
1
                    delete_file_range.file_size = -1;
671
1
                    create_status =
672
1
                            _read_position_delete_file(&delete_file_range, position_delete.get());
673
1
                    if (!create_status) {
674
1
                        return nullptr;
675
1
                    }
676
1
                    return position_delete.release();
677
1
                });
678
1
        if (create_status.is<ErrorCode::END_OF_FILE>()) {
679
0
            continue;
680
1
        } else if (!create_status.ok()) {
681
1
            return create_status;
682
1
        }
683
684
0
        DeleteFile& delete_file_map = *((DeleteFile*)delete_file_cache);
685
0
        auto get_value = [&](const auto& v) {
686
0
            DeleteRows* row_ids = v.second.get();
687
0
            if (!row_ids->empty()) {
688
0
                delete_rows_array.emplace_back(row_ids);
689
0
                num_delete_rows += row_ids->size();
690
0
            }
691
0
        };
692
0
        delete_file_map.if_contains(data_file_path, get_value);
693
0
    }
694
0
    if (num_delete_rows > 0) {
695
0
        SCOPED_TIMER(_iceberg_profile.delete_rows_sort_time);
696
0
        _iceberg_delete_rows =
697
0
                _kv_cache->template get<DeleteRows>(data_file_path, [&]() -> DeleteRows* {
698
0
                    auto data_file_position_delete = std::make_unique<DeleteRows>();
699
0
                    _sort_delete_rows(delete_rows_array, num_delete_rows,
700
0
                                      *data_file_position_delete);
701
0
                    return data_file_position_delete.release();
702
0
                });
703
0
        set_delete_rows();
704
0
        COUNTER_UPDATE(_iceberg_profile.num_delete_rows, num_delete_rows);
705
0
    }
706
0
    return Status::OK();
707
1
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EE
708
709
template <typename BaseReader>
710
typename IcebergReaderMixin<BaseReader>::PositionDeleteRange
711
0
IcebergReaderMixin<BaseReader>::_get_range(const ColumnDictI32& file_path_column) {
712
0
    PositionDeleteRange range;
713
0
    size_t read_rows = file_path_column.get_data().size();
714
0
    const int* code_path = file_path_column.get_data().data();
715
0
    const int* code_path_start = code_path;
716
0
    const int* code_path_end = code_path + read_rows;
717
0
    while (code_path < code_path_end) {
718
0
        int code = code_path[0];
719
0
        const int* code_end = std::upper_bound(code_path, code_path_end, code);
720
0
        range.data_file_path.emplace_back(file_path_column.get_value(code).to_string());
721
0
        range.range.emplace_back(code_path - code_path_start, code_end - code_path_start);
722
0
        code_path = code_end;
723
0
    }
724
0
    return range;
725
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE10_get_rangeERKNS_13ColumnDictI32E
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE10_get_rangeERKNS_13ColumnDictI32E
726
727
template <typename BaseReader>
728
typename IcebergReaderMixin<BaseReader>::PositionDeleteRange
729
0
IcebergReaderMixin<BaseReader>::_get_range(const ColumnString& file_path_column) {
730
0
    PositionDeleteRange range;
731
0
    size_t read_rows = file_path_column.size();
732
0
    size_t index = 0;
733
0
    while (index < read_rows) {
734
0
        StringRef data_path = file_path_column.get_data_at(index);
735
0
        size_t left = index - 1;
736
0
        size_t right = read_rows;
737
0
        while (left + 1 != right) {
738
0
            size_t mid = left + (right - left) / 2;
739
0
            if (file_path_column.get_data_at(mid) > data_path) {
740
0
                right = mid;
741
0
            } else {
742
0
                left = mid;
743
0
            }
744
0
        }
745
0
        range.data_file_path.emplace_back(data_path.to_string());
746
0
        range.range.emplace_back(index, left + 1);
747
0
        index = left + 1;
748
0
    }
749
0
    return range;
750
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE10_get_rangeERKNS_9ColumnStrIjEE
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE10_get_rangeERKNS_9ColumnStrIjEE
751
752
template <typename BaseReader>
753
void IcebergReaderMixin<BaseReader>::_sort_delete_rows(
754
        const std::vector<std::vector<int64_t>*>& delete_rows_array, int64_t num_delete_rows,
755
0
        std::vector<int64_t>& result) {
756
0
    if (delete_rows_array.empty()) {
757
0
        return;
758
0
    }
759
0
    if (delete_rows_array.size() == 1) {
760
0
        result.resize(num_delete_rows);
761
0
        memcpy(result.data(), delete_rows_array.front()->data(), sizeof(int64_t) * num_delete_rows);
762
0
        return;
763
0
    }
764
0
    if (delete_rows_array.size() == 2) {
765
0
        result.resize(num_delete_rows);
766
0
        std::merge(delete_rows_array.front()->begin(), delete_rows_array.front()->end(),
767
0
                   delete_rows_array.back()->begin(), delete_rows_array.back()->end(),
768
0
                   result.begin());
769
0
        return;
770
0
    }
771
772
0
    using vec_pair = std::pair<std::vector<int64_t>::iterator, std::vector<int64_t>::iterator>;
773
0
    result.resize(num_delete_rows);
774
0
    auto row_id_iter = result.begin();
775
0
    auto iter_end = result.end();
776
0
    std::vector<vec_pair> rows_array;
777
0
    for (auto* rows : delete_rows_array) {
778
0
        if (!rows->empty()) {
779
0
            rows_array.emplace_back(rows->begin(), rows->end());
780
0
        }
781
0
    }
782
0
    size_t array_size = rows_array.size();
783
0
    while (row_id_iter != iter_end) {
784
0
        int64_t min_index = 0;
785
0
        int64_t min = *rows_array[0].first;
786
0
        for (size_t i = 0; i < array_size; ++i) {
787
0
            if (*rows_array[i].first < min) {
788
0
                min_index = i;
789
0
                min = *rows_array[i].first;
790
0
            }
791
0
        }
792
0
        *row_id_iter++ = min;
793
0
        rows_array[min_index].first++;
794
0
        if (UNLIKELY(rows_array[min_index].first == rows_array[min_index].second)) {
795
0
            rows_array.erase(rows_array.begin() + min_index);
796
0
            array_size--;
797
0
        }
798
0
    }
799
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE17_sort_delete_rowsERKSt6vectorIPS3_IlSaIlEESaIS6_EElRS5_
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE17_sort_delete_rowsERKSt6vectorIPS3_IlSaIlEESaIS6_EElRS5_
800
801
template <typename BaseReader>
802
Status IcebergReaderMixin<BaseReader>::_gen_position_delete_file_range(
803
        Block& block, DeleteFile* position_delete, size_t read_rows,
804
0
        bool file_path_column_dictionary_coded) {
805
0
    SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
806
0
    auto name_to_pos_map = block.get_name_to_pos_map();
807
0
    ColumnPtr path_column = block.get_by_position(name_to_pos_map[ICEBERG_FILE_PATH]).column;
808
0
    DCHECK_EQ(path_column->size(), read_rows);
809
0
    ColumnPtr pos_column = block.get_by_position(name_to_pos_map[ICEBERG_ROW_POS]).column;
810
0
    if (const auto* nullable_col = check_and_get_column<ColumnNullable>(*path_column);
811
0
        nullable_col != nullptr) {
812
0
        if (nullable_col->has_null(0, read_rows)) {
813
0
            return Status::Corruption(
814
0
                    "Iceberg position delete column file_path contains null values");
815
0
        }
816
0
        path_column = remove_nullable(path_column);
817
0
    }
818
0
    if (const auto* nullable_col = check_and_get_column<ColumnNullable>(*pos_column);
819
0
        nullable_col != nullptr) {
820
0
        if (nullable_col->has_null(0, read_rows)) {
821
0
            return Status::Corruption("Iceberg position delete column pos contains null values");
822
0
        }
823
0
        pos_column = remove_nullable(pos_column);
824
0
    }
825
0
    using ColumnType = typename PrimitiveTypeTraits<TYPE_BIGINT>::ColumnType;
826
0
    const int64_t* src_data = assert_cast<const ColumnType&>(*pos_column).get_data().data();
827
0
    PositionDeleteRange range;
828
0
    if (file_path_column_dictionary_coded) {
829
0
        range = _get_range(assert_cast<const ColumnDictI32&>(*path_column));
830
0
    } else {
831
0
        range = _get_range(assert_cast<const ColumnString&>(*path_column));
832
0
    }
833
0
    for (int i = 0; i < range.range.size(); ++i) {
834
0
        std::string key = range.data_file_path[i];
835
0
        auto iter = position_delete->find(key);
836
0
        DeleteRows* delete_rows;
837
0
        if (iter == position_delete->end()) {
838
0
            delete_rows = new DeleteRows;
839
0
            std::unique_ptr<DeleteRows> delete_rows_ptr(delete_rows);
840
0
            (*position_delete)[key] = std::move(delete_rows_ptr);
841
0
        } else {
842
0
            delete_rows = iter->second.get();
843
0
        }
844
0
        const int64_t* cpy_start = src_data + range.range[i].first;
845
0
        const int64_t cpy_count = range.range[i].second - range.range[i].first;
846
0
        int64_t origin_size = delete_rows->size();
847
0
        delete_rows->resize(origin_size + cpy_count);
848
0
        int64_t* dest_position = &(*delete_rows)[origin_size];
849
0
        memcpy(dest_position, cpy_start, cpy_count * sizeof(int64_t));
850
0
    }
851
0
    return Status::OK();
852
0
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE31_gen_position_delete_file_rangeERNS_5BlockEPN5phmap22parallel_flat_hash_mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10unique_ptrISt6vectorIlSaIlEESt14default_deleteISG_EESt4hashISC_ESt8equal_toIvESaISt4pairIKSC_SJ_EELm8ESt5mutexEEmb
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE31_gen_position_delete_file_rangeERNS_5BlockEPN5phmap22parallel_flat_hash_mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10unique_ptrISt6vectorIlSaIlEESt14default_deleteISG_EESt4hashISC_ESt8equal_toIvESaISt4pairIKSC_SJ_EELm8ESt5mutexEEmb
853
854
template <typename BaseReader>
855
Status IcebergReaderMixin<BaseReader>::read_deletion_vector(
856
1
        const std::string& data_file_path, const TIcebergDeleteFileDesc& delete_file_desc) {
857
1
    Status create_status = Status::OK();
858
1
    SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
859
1
    bool decoded_cache_hit = false;
860
1
    _iceberg_deletion_vector = _kv_cache->template get<DeletionVector>(
861
1
            build_iceberg_deletion_vector_cache_key(data_file_path, delete_file_desc),
862
1
            [&]() -> DeletionVector* {
863
1
                auto deletion_vector = std::make_unique<DeletionVector>();
864
865
1
                io::FileCacheStatistics file_cache_stats;
866
1
                IcebergDeleteFileReaderOptions options;
867
1
                options.state = this->get_state();
868
1
                options.profile = this->get_profile();
869
1
                options.scan_params = &this->get_scan_params();
870
1
                options.io_ctx = this->get_io_ctx();
871
1
                options.fs_name = &this->get_scan_range().fs_name;
872
1
                options.deletion_vector_file_cache_stats = &file_cache_stats;
873
1
                create_status = read_iceberg_deletion_vector(delete_file_desc, options,
874
1
                                                             deletion_vector.get());
875
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count,
876
1
                               file_cache_stats.num_local_io_total);
877
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count,
878
1
                               file_cache_stats.num_remote_io_total);
879
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count,
880
1
                               file_cache_stats.num_peer_io_total);
881
1
                if (!create_status.ok()) [[unlikely]] {
882
1
                    return nullptr;
883
1
                }
884
885
0
                SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
886
0
                COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality());
887
0
                return deletion_vector.release();
888
1
            },
_ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescEENKUlvE_clEv
Line
Count
Source
862
1
            [&]() -> DeletionVector* {
863
1
                auto deletion_vector = std::make_unique<DeletionVector>();
864
865
1
                io::FileCacheStatistics file_cache_stats;
866
1
                IcebergDeleteFileReaderOptions options;
867
1
                options.state = this->get_state();
868
1
                options.profile = this->get_profile();
869
1
                options.scan_params = &this->get_scan_params();
870
1
                options.io_ctx = this->get_io_ctx();
871
1
                options.fs_name = &this->get_scan_range().fs_name;
872
1
                options.deletion_vector_file_cache_stats = &file_cache_stats;
873
1
                create_status = read_iceberg_deletion_vector(delete_file_desc, options,
874
1
                                                             deletion_vector.get());
875
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count,
876
1
                               file_cache_stats.num_local_io_total);
877
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count,
878
1
                               file_cache_stats.num_remote_io_total);
879
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count,
880
1
                               file_cache_stats.num_peer_io_total);
881
1
                if (!create_status.ok()) [[unlikely]] {
882
1
                    return nullptr;
883
1
                }
884
885
0
                SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
886
0
                COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality());
887
0
                return deletion_vector.release();
888
1
            },
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescEENKUlvE_clEv
889
1
            &decoded_cache_hit);
890
891
1
    RETURN_IF_ERROR(create_status);
892
0
    COUNTER_UPDATE(decoded_cache_hit ? _iceberg_profile.decoded_cache_hit_count
893
0
                                     : _iceberg_profile.decoded_cache_miss_count,
894
0
                   1);
895
0
    if (!_iceberg_deletion_vector->isEmpty()) [[likely]] {
896
0
        set_deletion_vector();
897
0
    }
898
0
    return Status::OK();
899
1
}
_ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescE
Line
Count
Source
856
1
        const std::string& data_file_path, const TIcebergDeleteFileDesc& delete_file_desc) {
857
1
    Status create_status = Status::OK();
858
1
    SCOPED_TIMER(_iceberg_profile.delete_files_read_time);
859
1
    bool decoded_cache_hit = false;
860
1
    _iceberg_deletion_vector = _kv_cache->template get<DeletionVector>(
861
1
            build_iceberg_deletion_vector_cache_key(data_file_path, delete_file_desc),
862
1
            [&]() -> DeletionVector* {
863
1
                auto deletion_vector = std::make_unique<DeletionVector>();
864
865
1
                io::FileCacheStatistics file_cache_stats;
866
1
                IcebergDeleteFileReaderOptions options;
867
1
                options.state = this->get_state();
868
1
                options.profile = this->get_profile();
869
1
                options.scan_params = &this->get_scan_params();
870
1
                options.io_ctx = this->get_io_ctx();
871
1
                options.fs_name = &this->get_scan_range().fs_name;
872
1
                options.deletion_vector_file_cache_stats = &file_cache_stats;
873
1
                create_status = read_iceberg_deletion_vector(delete_file_desc, options,
874
1
                                                             deletion_vector.get());
875
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count,
876
1
                               file_cache_stats.num_local_io_total);
877
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count,
878
1
                               file_cache_stats.num_remote_io_total);
879
1
                COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count,
880
1
                               file_cache_stats.num_peer_io_total);
881
1
                if (!create_status.ok()) [[unlikely]] {
882
1
                    return nullptr;
883
1
                }
884
885
1
                SCOPED_TIMER(_iceberg_profile.parse_delete_file_time);
886
1
                COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality());
887
1
                return deletion_vector.release();
888
1
            },
889
1
            &decoded_cache_hit);
890
891
1
    RETURN_IF_ERROR(create_status);
892
0
    COUNTER_UPDATE(decoded_cache_hit ? _iceberg_profile.decoded_cache_hit_count
893
0
                                     : _iceberg_profile.decoded_cache_miss_count,
894
0
                   1);
895
0
    if (!_iceberg_deletion_vector->isEmpty()) [[likely]] {
896
0
        set_deletion_vector();
897
0
    }
898
0
    return Status::OK();
899
1
}
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescE
900
901
} // namespace doris