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 <gen_cpp/ExternalTableSchema_types.h> |
21 | | |
22 | | #include <cstddef> |
23 | | #include <cstdint> |
24 | | #include <memory> |
25 | | #include <ranges> |
26 | | #include <string> |
27 | | #include <unordered_map> |
28 | | #include <vector> |
29 | | |
30 | | #include "common/consts.h" |
31 | | #include "common/status.h" |
32 | | #include "core/block/block.h" |
33 | | #include "core/column/column_dictionary.h" |
34 | | #include "core/column/column_nullable.h" |
35 | | #include "core/column/column_string.h" |
36 | | #include "core/column/column_struct.h" |
37 | | #include "core/data_type/data_type_number.h" |
38 | | #include "core/data_type/data_type_string.h" |
39 | | #include "core/data_type/primitive_type.h" |
40 | | #include "format/generic_reader.h" |
41 | | #include "format/table/equality_delete.h" |
42 | | #include "format/table/iceberg_delete_file_reader_helper.h" |
43 | | #include "format/table/iceberg_scan_semantics.h" |
44 | | #include "format/table/table_schema_change_helper.h" |
45 | | #include "runtime/runtime_profile.h" |
46 | | #include "runtime/runtime_state.h" |
47 | | #include "storage/olap_common.h" |
48 | | #include "util/url_coding.h" |
49 | | |
50 | | namespace doris { |
51 | | class TIcebergDeleteFileDesc; |
52 | | } // namespace doris |
53 | | |
54 | | namespace doris { |
55 | | |
56 | | class ShardedKVCache; |
57 | | |
58 | | // CRTP mixin for Iceberg reader functionality. |
59 | | // BaseReader should be ParquetReader or OrcReader. |
60 | | // Inherits BaseReader + TableSchemaChangeHelper, providing shared Iceberg logic |
61 | | // (delete files, deletion vectors, equality delete, $row_id synthesis). |
62 | | // |
63 | | // Inheritance chain: |
64 | | // IcebergParquetReader -> IcebergReaderMixin<ParquetReader> -> ParquetReader -> GenericReader |
65 | | // IcebergOrcReader -> IcebergReaderMixin<OrcReader> -> OrcReader -> GenericReader |
66 | | template <typename BaseReader> |
67 | | class IcebergReaderMixin : public BaseReader, public TableSchemaChangeHelper { |
68 | | public: |
69 | | struct PositionDeleteRange { |
70 | | std::vector<std::string> data_file_path; |
71 | | std::vector<std::pair<int, int>> range; |
72 | | }; |
73 | | |
74 | | // Forward BaseReader constructor arguments + Iceberg-specific kv_cache |
75 | | template <typename... Args> |
76 | | IcebergReaderMixin(ShardedKVCache* kv_cache, Args&&... args) |
77 | 28 | : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) { |
78 | 28 | static const char* iceberg_profile = "IcebergProfile"; |
79 | 28 | ADD_TIMER(this->get_profile(), iceberg_profile); |
80 | 28 | _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles", |
81 | 28 | TUnit::UNIT, iceberg_profile); |
82 | 28 | _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows", |
83 | 28 | TUnit::UNIT, iceberg_profile); |
84 | 28 | _iceberg_profile.delete_files_read_time = |
85 | 28 | ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile); |
86 | 28 | _iceberg_profile.delete_rows_sort_time = |
87 | 28 | ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile); |
88 | 28 | _iceberg_profile.parse_delete_file_time = |
89 | 28 | ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile); |
90 | 28 | _iceberg_profile.decoded_cache_hit_count = |
91 | 28 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount", |
92 | 28 | TUnit::UNIT, iceberg_profile); |
93 | 28 | _iceberg_profile.decoded_cache_miss_count = |
94 | 28 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount", |
95 | 28 | TUnit::UNIT, iceberg_profile); |
96 | 28 | _iceberg_profile.file_cache_hit_count = |
97 | 28 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount", |
98 | 28 | TUnit::UNIT, iceberg_profile); |
99 | 28 | _iceberg_profile.file_cache_miss_count = |
100 | 28 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount", |
101 | 28 | TUnit::UNIT, iceberg_profile); |
102 | 28 | _iceberg_profile.file_cache_peer_read_count = |
103 | 28 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount", |
104 | 28 | TUnit::UNIT, iceberg_profile); |
105 | 28 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEEC2IJRPNS_14RuntimeProfileERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRPKN4cctz9time_zoneERPNS_2io9IOContextERPNS_12RuntimeStateERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_ Line | Count | Source | 77 | 18 | : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) { | 78 | 18 | static const char* iceberg_profile = "IcebergProfile"; | 79 | 18 | ADD_TIMER(this->get_profile(), iceberg_profile); | 80 | 18 | _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles", | 81 | 18 | TUnit::UNIT, iceberg_profile); | 82 | 18 | _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows", | 83 | 18 | TUnit::UNIT, iceberg_profile); | 84 | 18 | _iceberg_profile.delete_files_read_time = | 85 | 18 | ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile); | 86 | 18 | _iceberg_profile.delete_rows_sort_time = | 87 | 18 | ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile); | 88 | 18 | _iceberg_profile.parse_delete_file_time = | 89 | 18 | ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile); | 90 | 18 | _iceberg_profile.decoded_cache_hit_count = | 91 | 18 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount", | 92 | 18 | TUnit::UNIT, iceberg_profile); | 93 | 18 | _iceberg_profile.decoded_cache_miss_count = | 94 | 18 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount", | 95 | 18 | TUnit::UNIT, iceberg_profile); | 96 | 18 | _iceberg_profile.file_cache_hit_count = | 97 | 18 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount", | 98 | 18 | TUnit::UNIT, iceberg_profile); | 99 | 18 | _iceberg_profile.file_cache_miss_count = | 100 | 18 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount", | 101 | 18 | TUnit::UNIT, iceberg_profile); | 102 | 18 | _iceberg_profile.file_cache_peer_read_count = | 103 | 18 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount", | 104 | 18 | TUnit::UNIT, iceberg_profile); | 105 | 18 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEEC2IJRPNS_14RuntimeProfileERPNS_12RuntimeStateERKNS_20TFileScanRangeParamsERKNS_14TFileRangeDescERmRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERPNS_2io9IOContextERPNS_13FileMetaCacheEEEEPNS_14ShardedKVCacheEDpOT_ Line | Count | Source | 77 | 10 | : BaseReader(std::forward<Args>(args)...), _kv_cache(kv_cache) { | 78 | 10 | static const char* iceberg_profile = "IcebergProfile"; | 79 | 10 | ADD_TIMER(this->get_profile(), iceberg_profile); | 80 | 10 | _iceberg_profile.num_delete_files = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteFiles", | 81 | 10 | TUnit::UNIT, iceberg_profile); | 82 | 10 | _iceberg_profile.num_delete_rows = ADD_CHILD_COUNTER(this->get_profile(), "NumDeleteRows", | 83 | 10 | TUnit::UNIT, iceberg_profile); | 84 | 10 | _iceberg_profile.delete_files_read_time = | 85 | 10 | ADD_CHILD_TIMER(this->get_profile(), "DeleteFileReadTime", iceberg_profile); | 86 | 10 | _iceberg_profile.delete_rows_sort_time = | 87 | 10 | ADD_CHILD_TIMER(this->get_profile(), "DeleteRowsSortTime", iceberg_profile); | 88 | 10 | _iceberg_profile.parse_delete_file_time = | 89 | 10 | ADD_CHILD_TIMER(this->get_profile(), "ParseDeleteFileTime", iceberg_profile); | 90 | 10 | _iceberg_profile.decoded_cache_hit_count = | 91 | 10 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheHitCount", | 92 | 10 | TUnit::UNIT, iceberg_profile); | 93 | 10 | _iceberg_profile.decoded_cache_miss_count = | 94 | 10 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorDecodedCacheMissCount", | 95 | 10 | TUnit::UNIT, iceberg_profile); | 96 | 10 | _iceberg_profile.file_cache_hit_count = | 97 | 10 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheHitCount", | 98 | 10 | TUnit::UNIT, iceberg_profile); | 99 | 10 | _iceberg_profile.file_cache_miss_count = | 100 | 10 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCacheMissCount", | 101 | 10 | TUnit::UNIT, iceberg_profile); | 102 | 10 | _iceberg_profile.file_cache_peer_read_count = | 103 | 10 | ADD_CHILD_COUNTER(this->get_profile(), "DeletionVectorFileCachePeerReadCount", | 104 | 10 | TUnit::UNIT, iceberg_profile); | 105 | 10 | } |
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_ |
106 | | |
107 | 28 | ~IcebergReaderMixin() override = default; _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEED2Ev Line | Count | Source | 107 | 18 | ~IcebergReaderMixin() override = default; |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEED2Ev Line | Count | Source | 107 | 10 | ~IcebergReaderMixin() override = default; |
|
108 | | |
109 | | void set_current_file_info(const std::string& file_path, int32_t partition_spec_id, |
110 | 0 | const std::string& partition_data_json) { |
111 | 0 | _current_file_path = file_path; |
112 | 0 | _partition_spec_id = partition_spec_id; |
113 | 0 | _partition_data_json = partition_data_json; |
114 | 0 | } Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21set_current_file_infoERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiSA_ Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21set_current_file_infoERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiSA_ |
115 | | |
116 | | enum { DATA, POSITION_DELETE, EQUALITY_DELETE, DELETION_VECTOR }; |
117 | | enum Fileformat { NONE, PARQUET, ORC, AVRO }; |
118 | | |
119 | | virtual void set_delete_rows() = 0; |
120 | | virtual void set_deletion_vector() = 0; |
121 | | |
122 | | // Table-level COUNT(*) is handled by CountReader (created by FileScanner after |
123 | | // init_reader). If _do_get_next_block is called, COUNT must have been resolved. |
124 | 9 | Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override { |
125 | 9 | DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT); |
126 | 9 | return BaseReader::_do_get_next_block(block, read_rows, eof); |
127 | 9 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE18_do_get_next_blockEPNS_5BlockEPmPb Line | Count | Source | 124 | 5 | Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override { | 125 | | DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT); | 126 | 5 | return BaseReader::_do_get_next_block(block, read_rows, eof); | 127 | 5 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE18_do_get_next_blockEPNS_5BlockEPmPb Line | Count | Source | 124 | 4 | Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override { | 125 | | DCHECK(this->_push_down_agg_type != TPushAggOp::type::COUNT); | 126 | 4 | return BaseReader::_do_get_next_block(block, read_rows, eof); | 127 | 4 | } |
|
128 | | |
129 | | void set_create_row_id_column_iterator_func( |
130 | 0 | std::function<std::shared_ptr<segment_v2::RowIdColumnIteratorV2>()> create_func) { |
131 | 0 | _create_topn_row_id_column_iterator = create_func; |
132 | 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 |
133 | | |
134 | | Status TEST_read_deletion_vector(const std::string& data_file_path, |
135 | 1 | const TIcebergDeleteFileDesc& delete_file_desc) { |
136 | 1 | return read_deletion_vector(data_file_path, delete_file_desc); |
137 | 1 | } |
138 | | |
139 | | Status TEST_position_delete_base(const std::string& data_file_path, |
140 | 1 | const std::vector<TIcebergDeleteFileDesc>& delete_files) { |
141 | 1 | return _position_delete_base(data_file_path, delete_files); |
142 | 1 | } |
143 | | |
144 | | void TEST_set_column_name_to_block_index( |
145 | 4 | std::unordered_map<std::string, uint32_t>* column_name_to_block_index) { |
146 | 4 | this->col_name_to_block_idx_ref() = column_name_to_block_index; |
147 | 4 | } |
148 | | |
149 | | Status TEST_register_missing_equality_delete_column(int32_t field_id, const std::string& name, |
150 | 5 | const DataTypePtr& delete_key_type) { |
151 | 5 | return _register_missing_equality_delete_column(field_id, name, delete_key_type); |
152 | 5 | } |
153 | | |
154 | 2 | Status TEST_materialize_missing_equality_delete_columns(Block* block, size_t rows) { |
155 | 2 | return _materialize_missing_equality_delete_columns(block, rows); |
156 | 2 | } |
157 | | |
158 | | protected: |
159 | | // ---- Hook implementations ---- |
160 | | |
161 | | Status on_fill_missing_columns(Block* block, size_t rows, |
162 | 11 | const std::vector<std::string>& cols) override { |
163 | 11 | if (!supports_iceberg_scan_semantics_v1(&this->get_scan_params())) { |
164 | 4 | return BaseReader::on_fill_missing_columns(block, rows, cols); |
165 | 4 | } |
166 | 7 | std::vector<std::string> generic_columns; |
167 | 7 | for (const auto& name : cols) { |
168 | 1 | const auto* field = _find_current_schema_field(name); |
169 | 1 | if (field == nullptr || !field->__isset.initial_default_value) { |
170 | 0 | generic_columns.push_back(name); |
171 | 0 | continue; |
172 | 0 | } |
173 | 1 | if (!this->col_name_to_block_idx_ref()->contains(name)) { |
174 | 0 | return Status::InternalError("Missing column: {} not found in block {}", name, |
175 | 0 | block->dump_structure()); |
176 | 0 | } |
177 | 1 | const auto position = this->col_name_to_block_idx_ref()->at(name); |
178 | 1 | ColumnPtr value; |
179 | 1 | RETURN_IF_ERROR(_build_owned_initial_default_column( |
180 | 1 | *field, block->get_by_position(position).type, rows, &value)); |
181 | | // Iceberg metadata is authoritative for pre-add rows; a generic FE expression may be |
182 | | // the Base64 carrier rather than the logical BINARY/FIXED/UUID value. |
183 | 1 | block->get_by_position(position).column = value->convert_to_full_column_if_const(); |
184 | 1 | } |
185 | 7 | return BaseReader::on_fill_missing_columns(block, rows, generic_columns); |
186 | 7 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE23on_fill_missing_columnsEPNS_5BlockEmRKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EE Line | Count | Source | 162 | 7 | const std::vector<std::string>& cols) override { | 163 | 7 | if (!supports_iceberg_scan_semantics_v1(&this->get_scan_params())) { | 164 | 3 | return BaseReader::on_fill_missing_columns(block, rows, cols); | 165 | 3 | } | 166 | 4 | std::vector<std::string> generic_columns; | 167 | 4 | for (const auto& name : cols) { | 168 | 1 | const auto* field = _find_current_schema_field(name); | 169 | 1 | if (field == nullptr || !field->__isset.initial_default_value) { | 170 | 0 | generic_columns.push_back(name); | 171 | 0 | continue; | 172 | 0 | } | 173 | 1 | if (!this->col_name_to_block_idx_ref()->contains(name)) { | 174 | 0 | return Status::InternalError("Missing column: {} not found in block {}", name, | 175 | 0 | block->dump_structure()); | 176 | 0 | } | 177 | 1 | const auto position = this->col_name_to_block_idx_ref()->at(name); | 178 | 1 | ColumnPtr value; | 179 | 1 | RETURN_IF_ERROR(_build_owned_initial_default_column( | 180 | 1 | *field, block->get_by_position(position).type, rows, &value)); | 181 | | // Iceberg metadata is authoritative for pre-add rows; a generic FE expression may be | 182 | | // the Base64 carrier rather than the logical BINARY/FIXED/UUID value. | 183 | 1 | block->get_by_position(position).column = value->convert_to_full_column_if_const(); | 184 | 1 | } | 185 | 4 | return BaseReader::on_fill_missing_columns(block, rows, generic_columns); | 186 | 4 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE23on_fill_missing_columnsEPNS_5BlockEmRKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EE Line | Count | Source | 162 | 4 | const std::vector<std::string>& cols) override { | 163 | 4 | if (!supports_iceberg_scan_semantics_v1(&this->get_scan_params())) { | 164 | 1 | return BaseReader::on_fill_missing_columns(block, rows, cols); | 165 | 1 | } | 166 | 3 | std::vector<std::string> generic_columns; | 167 | 3 | for (const auto& name : cols) { | 168 | 0 | const auto* field = _find_current_schema_field(name); | 169 | 0 | if (field == nullptr || !field->__isset.initial_default_value) { | 170 | 0 | generic_columns.push_back(name); | 171 | 0 | continue; | 172 | 0 | } | 173 | 0 | if (!this->col_name_to_block_idx_ref()->contains(name)) { | 174 | 0 | return Status::InternalError("Missing column: {} not found in block {}", name, | 175 | 0 | block->dump_structure()); | 176 | 0 | } | 177 | 0 | const auto position = this->col_name_to_block_idx_ref()->at(name); | 178 | 0 | ColumnPtr value; | 179 | 0 | RETURN_IF_ERROR(_build_owned_initial_default_column( | 180 | 0 | *field, block->get_by_position(position).type, rows, &value)); | 181 | | // Iceberg metadata is authoritative for pre-add rows; a generic FE expression may be | 182 | | // the Base64 carrier rather than the logical BINARY/FIXED/UUID value. | 183 | 0 | block->get_by_position(position).column = value->convert_to_full_column_if_const(); | 184 | 0 | } | 185 | 3 | return BaseReader::on_fill_missing_columns(block, rows, generic_columns); | 186 | 3 | } |
|
187 | | |
188 | | // Called before reading a block: expand block for equality delete columns + detect row_id |
189 | 9 | Status on_before_read_block(Block* block) override { |
190 | 9 | RETURN_IF_ERROR(_expand_block_if_need(block)); |
191 | 9 | return Status::OK(); |
192 | 9 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20on_before_read_blockEPNS_5BlockE Line | Count | Source | 189 | 5 | Status on_before_read_block(Block* block) override { | 190 | 5 | RETURN_IF_ERROR(_expand_block_if_need(block)); | 191 | 5 | return Status::OK(); | 192 | 5 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20on_before_read_blockEPNS_5BlockE Line | Count | Source | 189 | 4 | Status on_before_read_block(Block* block) override { | 190 | 4 | RETURN_IF_ERROR(_expand_block_if_need(block)); | 191 | 4 | return Status::OK(); | 192 | 4 | } |
|
193 | | |
194 | | /// Fill Iceberg $row_id synthesized column. Registered as handler during init. |
195 | 0 | Status _fill_iceberg_row_id(Block* block, size_t rows) { |
196 | 0 | int row_id_pos = block->get_position_by_name(BeConsts::ICEBERG_ROWID_COL); |
197 | 0 | DORIS_CHECK(row_id_pos >= 0); |
198 | | |
199 | | // Lazy-init file info: only set when $row_id is actually needed. |
200 | 0 | const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params; |
201 | 0 | std::string file_path = table_desc.original_file_path; |
202 | 0 | int32_t partition_spec_id = |
203 | 0 | table_desc.__isset.partition_spec_id ? table_desc.partition_spec_id : 0; |
204 | 0 | std::string partition_data_json; |
205 | 0 | if (table_desc.__isset.partition_data_json) { |
206 | 0 | partition_data_json = table_desc.partition_data_json; |
207 | 0 | } |
208 | 0 | set_current_file_info(file_path, partition_spec_id, partition_data_json); |
209 | |
|
210 | 0 | const auto& row_ids = this->current_batch_row_positions(); |
211 | 0 | auto& col_with_type = block->get_by_position(static_cast<size_t>(row_id_pos)); |
212 | 0 | MutableColumnPtr row_id_column; |
213 | 0 | RETURN_IF_ERROR(_build_iceberg_rowid_column(col_with_type.type, _current_file_path, row_ids, |
214 | 0 | _partition_spec_id, _partition_data_json, |
215 | 0 | &row_id_column)); |
216 | 0 | col_with_type.column = std::move(row_id_column); |
217 | 0 | return Status::OK(); |
218 | 0 | } Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20_fill_iceberg_row_idEPNS_5BlockEm Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20_fill_iceberg_row_idEPNS_5BlockEm |
219 | | |
220 | 0 | void _init_row_lineage_columns() { |
221 | 0 | const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params; |
222 | 0 | if (table_desc.__isset.first_row_id) { |
223 | 0 | _row_lineage_columns.first_row_id = table_desc.first_row_id; |
224 | 0 | } |
225 | 0 | if (table_desc.__isset.last_updated_sequence_number) { |
226 | 0 | _row_lineage_columns.last_updated_sequence_number = |
227 | 0 | table_desc.last_updated_sequence_number; |
228 | 0 | } |
229 | 0 | } Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE25_init_row_lineage_columnsEv Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE25_init_row_lineage_columnsEv |
230 | | |
231 | 0 | Status _fill_row_lineage_row_id(Block* block, size_t rows) { |
232 | 0 | int col_pos = block->get_position_by_name(ROW_LINEAGE_ROW_ID); |
233 | 0 | DORIS_CHECK(col_pos >= 0); |
234 | |
|
235 | 0 | if (_row_lineage_columns.first_row_id >= 0) { |
236 | 0 | auto column_guard = block->mutate_column_scoped(col_pos); |
237 | 0 | auto* nullable_column = |
238 | 0 | assert_cast<ColumnNullable*>(column_guard.mutable_column().get()); |
239 | 0 | auto& null_map = nullable_column->get_null_map_data(); |
240 | 0 | auto& data = |
241 | 0 | assert_cast<ColumnInt64&>(*nullable_column->get_nested_column_ptr()).get_data(); |
242 | 0 | const auto& row_ids = this->current_batch_row_positions(); |
243 | 0 | for (size_t i = 0; i < rows; ++i) { |
244 | 0 | if (null_map[i] != 0) { |
245 | 0 | null_map[i] = 0; |
246 | 0 | data[i] = _row_lineage_columns.first_row_id + static_cast<int64_t>(row_ids[i]); |
247 | 0 | } |
248 | 0 | } |
249 | 0 | } |
250 | 0 | return Status::OK(); |
251 | 0 | } Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE24_fill_row_lineage_row_idEPNS_5BlockEm Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE24_fill_row_lineage_row_idEPNS_5BlockEm |
252 | | |
253 | 0 | Status _fill_row_lineage_last_updated_sequence_number(Block* block, size_t rows) { |
254 | 0 | int col_pos = block->get_position_by_name(ROW_LINEAGE_LAST_UPDATED_SEQ_NUMBER); |
255 | 0 | DORIS_CHECK(col_pos >= 0); |
256 | |
|
257 | 0 | if (_row_lineage_columns.last_updated_sequence_number >= 0) { |
258 | 0 | auto column_guard = block->mutate_column_scoped(col_pos); |
259 | 0 | auto* nullable_column = |
260 | 0 | assert_cast<ColumnNullable*>(column_guard.mutable_column().get()); |
261 | 0 | auto& null_map = nullable_column->get_null_map_data(); |
262 | 0 | auto& data = |
263 | 0 | assert_cast<ColumnInt64&>(*nullable_column->get_nested_column_ptr()).get_data(); |
264 | 0 | for (size_t i = 0; i < rows; ++i) { |
265 | 0 | if (null_map[i] != 0) { |
266 | 0 | null_map[i] = 0; |
267 | 0 | data[i] = _row_lineage_columns.last_updated_sequence_number; |
268 | 0 | } |
269 | 0 | } |
270 | 0 | } |
271 | 0 | return Status::OK(); |
272 | 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 |
273 | | |
274 | | // Called after reading a block: apply equality delete filter + shrink block |
275 | 9 | Status on_after_read_block(Block* block, size_t* read_rows) override { |
276 | 9 | if (!_equality_delete_impls.empty()) { |
277 | 4 | std::unique_ptr<IColumn::Filter> filter = |
278 | 4 | std::make_unique<IColumn::Filter>(block->rows(), 1); |
279 | 4 | for (auto& equality_delete_impl : _equality_delete_impls) { |
280 | 4 | RETURN_IF_ERROR(equality_delete_impl->filter_data_block( |
281 | 4 | block, this->col_name_to_block_idx_ref(), _id_to_block_column_name, |
282 | 4 | *filter)); |
283 | 4 | } |
284 | 4 | Block::filter_block_internal(block, *filter, block->columns()); |
285 | 4 | *read_rows = block->rows(); |
286 | 4 | } |
287 | 9 | return _shrink_block_if_need(block); |
288 | 9 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE19on_after_read_blockEPNS_5BlockEPm Line | Count | Source | 275 | 5 | Status on_after_read_block(Block* block, size_t* read_rows) override { | 276 | 5 | if (!_equality_delete_impls.empty()) { | 277 | 2 | std::unique_ptr<IColumn::Filter> filter = | 278 | 2 | std::make_unique<IColumn::Filter>(block->rows(), 1); | 279 | 2 | for (auto& equality_delete_impl : _equality_delete_impls) { | 280 | 2 | RETURN_IF_ERROR(equality_delete_impl->filter_data_block( | 281 | 2 | block, this->col_name_to_block_idx_ref(), _id_to_block_column_name, | 282 | 2 | *filter)); | 283 | 2 | } | 284 | 2 | Block::filter_block_internal(block, *filter, block->columns()); | 285 | 2 | *read_rows = block->rows(); | 286 | 2 | } | 287 | 5 | return _shrink_block_if_need(block); | 288 | 5 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE19on_after_read_blockEPNS_5BlockEPm Line | Count | Source | 275 | 4 | Status on_after_read_block(Block* block, size_t* read_rows) override { | 276 | 4 | if (!_equality_delete_impls.empty()) { | 277 | 2 | std::unique_ptr<IColumn::Filter> filter = | 278 | 2 | std::make_unique<IColumn::Filter>(block->rows(), 1); | 279 | 2 | for (auto& equality_delete_impl : _equality_delete_impls) { | 280 | 2 | RETURN_IF_ERROR(equality_delete_impl->filter_data_block( | 281 | 2 | block, this->col_name_to_block_idx_ref(), _id_to_block_column_name, | 282 | 2 | *filter)); | 283 | 2 | } | 284 | 2 | Block::filter_block_internal(block, *filter, block->columns()); | 285 | 2 | *read_rows = block->rows(); | 286 | 2 | } | 287 | 4 | return _shrink_block_if_need(block); | 288 | 4 | } |
|
289 | | |
290 | | // ---- Shared Iceberg methods ---- |
291 | | |
292 | | Status _init_row_filters(); |
293 | | Status _position_delete_base(const std::string data_file_path, |
294 | | const std::vector<TIcebergDeleteFileDesc>& delete_files); |
295 | | Status _equality_delete_base(const std::vector<TIcebergDeleteFileDesc>& delete_files); |
296 | | Status read_deletion_vector(const std::string& data_file_path, |
297 | | const TIcebergDeleteFileDesc& delete_file_desc); |
298 | | |
299 | | Status _expand_block_if_need(Block* block); |
300 | | Status _shrink_block_if_need(Block* block); |
301 | | const schema::external::TStructField* _current_schema_root() const; |
302 | | const schema::external::TField* _find_current_schema_field(const std::string& name) const; |
303 | | const schema::external::TField* _find_current_schema_field(int32_t field_id) const; |
304 | | Status _build_owned_initial_default_column(const schema::external::TField& field, |
305 | | const DataTypePtr& type, size_t rows, |
306 | | ColumnPtr* column) const; |
307 | | Status _register_missing_equality_delete_column(int32_t field_id, const std::string& name, |
308 | | const DataTypePtr& delete_key_type); |
309 | | Status _materialize_missing_equality_delete_column(Block* block, const std::string& name, |
310 | | const ColumnPtr& value, size_t rows); |
311 | | Status _materialize_missing_equality_delete_columns(Block* block, size_t rows); |
312 | | |
313 | | // Type aliases — must be defined before member function declarations that use them. |
314 | | using DeleteRows = std::vector<int64_t>; |
315 | | using DeleteFile = phmap::parallel_flat_hash_map< |
316 | | std::string, std::unique_ptr<DeleteRows>, std::hash<std::string>, std::equal_to<>, |
317 | | std::allocator<std::pair<const std::string, std::unique_ptr<DeleteRows>>>, 8, |
318 | | std::mutex>; |
319 | | |
320 | | PositionDeleteRange _get_range(const ColumnDictI32& file_path_column); |
321 | | PositionDeleteRange _get_range(const ColumnString& file_path_column); |
322 | | static void _sort_delete_rows(const std::vector<std::vector<int64_t>*>& delete_rows_array, |
323 | | int64_t num_delete_rows, std::vector<int64_t>& result); |
324 | | Status _gen_position_delete_file_range(Block& block, DeleteFile* position_delete, |
325 | | size_t read_rows, |
326 | | bool file_path_column_dictionary_coded); |
327 | | void _generate_equality_delete_block(Block* block, |
328 | | const std::vector<std::string>& equality_delete_col_names, |
329 | | const std::vector<DataTypePtr>& equality_delete_col_types); |
330 | | |
331 | | // Pure virtual: format-specific delete file reading |
332 | | virtual Status _read_position_delete_file(const TFileRangeDesc*, DeleteFile*) = 0; |
333 | | virtual std::unique_ptr<GenericReader> _create_equality_reader( |
334 | | const TFileRangeDesc& delete_desc) = 0; |
335 | | |
336 | 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 | 336 | 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 |
337 | | |
338 | | /// Build the Iceberg V2 row-id struct column. |
339 | | static Status _build_iceberg_rowid_column(const DataTypePtr& type, const std::string& file_path, |
340 | | const std::vector<rowid_t>& row_ids, |
341 | | int32_t partition_spec_id, |
342 | | const std::string& partition_data_json, |
343 | 0 | MutableColumnPtr* column_out) { |
344 | 0 | if (type == nullptr || column_out == nullptr) { |
345 | 0 | return Status::InvalidArgument("Invalid iceberg rowid column type or output column"); |
346 | 0 | } |
347 | 0 | MutableColumnPtr column = type->create_column(); |
348 | 0 | ColumnNullable* nullable_col = check_and_get_column<ColumnNullable>(column.get()); |
349 | 0 | ColumnStruct* struct_col = nullptr; |
350 | 0 | if (nullable_col != nullptr) { |
351 | 0 | struct_col = |
352 | 0 | check_and_get_column<ColumnStruct>(nullable_col->get_nested_column_ptr().get()); |
353 | 0 | } else { |
354 | 0 | struct_col = check_and_get_column<ColumnStruct>(column.get()); |
355 | 0 | } |
356 | 0 | if (struct_col == nullptr || struct_col->tuple_size() < 4) { |
357 | 0 | return Status::InternalError("Invalid iceberg rowid column structure"); |
358 | 0 | } |
359 | 0 | size_t num_rows = row_ids.size(); |
360 | 0 | auto& file_path_col = struct_col->get_column(0); |
361 | 0 | auto& row_pos_col = struct_col->get_column(1); |
362 | 0 | auto& spec_id_col = struct_col->get_column(2); |
363 | 0 | auto& partition_data_col = struct_col->get_column(3); |
364 | 0 | file_path_col.reserve(num_rows); |
365 | 0 | row_pos_col.reserve(num_rows); |
366 | 0 | spec_id_col.reserve(num_rows); |
367 | 0 | partition_data_col.reserve(num_rows); |
368 | 0 | for (size_t i = 0; i < num_rows; ++i) { |
369 | 0 | file_path_col.insert_data(file_path.data(), file_path.size()); |
370 | 0 | } |
371 | 0 | for (size_t i = 0; i < num_rows; ++i) { |
372 | 0 | int64_t row_pos = static_cast<int64_t>(row_ids[i]); |
373 | 0 | row_pos_col.insert_data(reinterpret_cast<const char*>(&row_pos), sizeof(row_pos)); |
374 | 0 | } |
375 | 0 | for (size_t i = 0; i < num_rows; ++i) { |
376 | 0 | int32_t spec_id = partition_spec_id; |
377 | 0 | spec_id_col.insert_data(reinterpret_cast<const char*>(&spec_id), sizeof(spec_id)); |
378 | 0 | } |
379 | 0 | for (size_t i = 0; i < num_rows; ++i) { |
380 | 0 | partition_data_col.insert_data(partition_data_json.data(), partition_data_json.size()); |
381 | 0 | } |
382 | 0 | if (nullable_col != nullptr) { |
383 | 0 | nullable_col->get_null_map_data().resize_fill(num_rows, 0); |
384 | 0 | } |
385 | 0 | *column_out = std::move(column); |
386 | 0 | return Status::OK(); |
387 | 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 |
388 | | |
389 | | struct IcebergProfile { |
390 | | RuntimeProfile::Counter* num_delete_files; |
391 | | RuntimeProfile::Counter* num_delete_rows; |
392 | | RuntimeProfile::Counter* delete_files_read_time; |
393 | | RuntimeProfile::Counter* delete_rows_sort_time; |
394 | | RuntimeProfile::Counter* parse_delete_file_time; |
395 | | RuntimeProfile::Counter* decoded_cache_hit_count; |
396 | | RuntimeProfile::Counter* decoded_cache_miss_count; |
397 | | RuntimeProfile::Counter* file_cache_hit_count; |
398 | | RuntimeProfile::Counter* file_cache_miss_count; |
399 | | RuntimeProfile::Counter* file_cache_peer_read_count; |
400 | | }; |
401 | | |
402 | | bool _need_row_id_column = false; |
403 | | std::string _current_file_path; |
404 | | int32_t _partition_spec_id = 0; |
405 | | std::string _partition_data_json; |
406 | | |
407 | | ShardedKVCache* _kv_cache; |
408 | | IcebergProfile _iceberg_profile; |
409 | | const std::vector<int64_t>* _iceberg_delete_rows = nullptr; |
410 | | const DeletionVector* _iceberg_deletion_vector = nullptr; |
411 | | std::vector<std::string> _expand_col_names; |
412 | | std::vector<ColumnWithTypeAndName> _expand_columns; |
413 | | std::unordered_map<std::string, ColumnPtr> _missing_equality_delete_values; |
414 | | std::vector<std::string> _all_required_col_names; |
415 | | Fileformat _file_format = Fileformat::NONE; |
416 | | |
417 | | const int64_t MIN_SUPPORT_DELETE_FILES_VERSION = 2; |
418 | | const std::string ICEBERG_FILE_PATH = "file_path"; |
419 | | const std::string ICEBERG_ROW_POS = "pos"; |
420 | | const std::vector<std::string> delete_file_col_names {ICEBERG_FILE_PATH, ICEBERG_ROW_POS}; |
421 | | const std::unordered_map<std::string, uint32_t> DELETE_COL_NAME_TO_BLOCK_IDX = { |
422 | | {ICEBERG_FILE_PATH, 0}, {ICEBERG_ROW_POS, 1}}; |
423 | | const int ICEBERG_FILE_PATH_INDEX = 0; |
424 | | const int ICEBERG_FILE_POS_INDEX = 1; |
425 | | const int READ_DELETE_FILE_BATCH_SIZE = 102400; |
426 | | |
427 | | // all ids that need read for eq delete (from all eq delete files) |
428 | | std::set<int> _equality_delete_col_ids; |
429 | | // eq delete column ids -> location of _equality_delete_blocks / _equality_delete_impls |
430 | | std::map<std::vector<int>, int> _equality_delete_block_map; |
431 | | // EqualityDeleteBase stores raw pointers to these blocks, so do not modify this vector after |
432 | | // creating entries in _equality_delete_impls. |
433 | | std::vector<Block> _equality_delete_blocks; |
434 | | std::vector<std::unique_ptr<EqualityDeleteBase>> _equality_delete_impls; |
435 | | |
436 | | // id -> block column name |
437 | | std::unordered_map<int, std::string> _id_to_block_column_name; |
438 | | |
439 | | std::function<std::shared_ptr<segment_v2::RowIdColumnIteratorV2>()> |
440 | | _create_topn_row_id_column_iterator; |
441 | | |
442 | | static constexpr const char* ROW_LINEAGE_ROW_ID = "_row_id"; |
443 | | static constexpr const char* ROW_LINEAGE_LAST_UPDATED_SEQ_NUMBER = |
444 | | "_last_updated_sequence_number"; |
445 | | struct RowLineageColumns { |
446 | | int64_t first_row_id = -1; |
447 | | int64_t last_updated_sequence_number = -1; |
448 | | }; |
449 | | RowLineageColumns _row_lineage_columns; |
450 | | }; |
451 | | |
452 | | // ============================================================================ |
453 | | // Template method implementations (must be in header for templates) |
454 | | // ============================================================================ |
455 | | |
456 | | template <typename BaseReader> |
457 | 9 | Status IcebergReaderMixin<BaseReader>::_init_row_filters() { |
458 | | // COUNT(*) short-circuit. A table-level row count of 0 (e.g. an all-deleted table read with |
459 | | // ignore_iceberg_dangling_delete, where total-records == total-position-deletes) is still a |
460 | | // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE |
461 | | // sends -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the |
462 | | // delete-applying path below and never produce the intended CountReader(0). |
463 | 9 | if (this->_push_down_agg_type == TPushAggOp::type::COUNT && |
464 | 9 | this->get_scan_range().table_format_params.__isset.table_level_row_count && |
465 | 9 | this->get_scan_range().table_format_params.table_level_row_count >= 0) { |
466 | 0 | return Status::OK(); |
467 | 0 | } |
468 | | |
469 | 9 | const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params; |
470 | 9 | const auto& version = table_desc.format_version; |
471 | 9 | if (version < MIN_SUPPORT_DELETE_FILES_VERSION) { |
472 | 5 | return Status::OK(); |
473 | 5 | } |
474 | | |
475 | 4 | std::vector<TIcebergDeleteFileDesc> position_delete_files; |
476 | 4 | std::vector<TIcebergDeleteFileDesc> equality_delete_files; |
477 | 4 | std::vector<TIcebergDeleteFileDesc> deletion_vector_files; |
478 | 4 | for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) { |
479 | 4 | if (desc.content == POSITION_DELETE) { |
480 | 0 | position_delete_files.emplace_back(desc); |
481 | 4 | } else if (desc.content == EQUALITY_DELETE) { |
482 | 4 | equality_delete_files.emplace_back(desc); |
483 | 4 | } else if (desc.content == DELETION_VECTOR) { |
484 | 0 | deletion_vector_files.emplace_back(desc); |
485 | 0 | } |
486 | 4 | } |
487 | | |
488 | 4 | if (!equality_delete_files.empty()) { |
489 | 4 | RETURN_IF_ERROR(_equality_delete_base(equality_delete_files)); |
490 | 4 | this->set_push_down_agg_type(TPushAggOp::NONE); |
491 | 4 | } |
492 | | |
493 | 4 | if (!deletion_vector_files.empty()) { |
494 | 0 | if (deletion_vector_files.size() != 1) [[unlikely]] { |
495 | | /* |
496 | | * Deletion vectors are a binary representation of deletes for a single data file that is more efficient |
497 | | * at execution time than position delete files. Unlike equality or position delete files, there can be |
498 | | * at most one deletion vector for a given data file in a snapshot. |
499 | | */ |
500 | 0 | return Status::DataQualityError("This iceberg data file has multiple DVs."); |
501 | 0 | } |
502 | 0 | RETURN_IF_ERROR( |
503 | 0 | read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0])); |
504 | 0 | this->set_push_down_agg_type(TPushAggOp::NONE); |
505 | 4 | } else if (!position_delete_files.empty()) { |
506 | 0 | RETURN_IF_ERROR( |
507 | 0 | _position_delete_base(table_desc.original_file_path, position_delete_files)); |
508 | 0 | this->set_push_down_agg_type(TPushAggOp::NONE); |
509 | 0 | } |
510 | | |
511 | 4 | COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size()); |
512 | 4 | return Status::OK(); |
513 | 4 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE17_init_row_filtersEv Line | Count | Source | 457 | 5 | Status IcebergReaderMixin<BaseReader>::_init_row_filters() { | 458 | | // COUNT(*) short-circuit. A table-level row count of 0 (e.g. an all-deleted table read with | 459 | | // ignore_iceberg_dangling_delete, where total-records == total-position-deletes) is still a | 460 | | // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE | 461 | | // sends -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the | 462 | | // delete-applying path below and never produce the intended CountReader(0). | 463 | 5 | if (this->_push_down_agg_type == TPushAggOp::type::COUNT && | 464 | 5 | this->get_scan_range().table_format_params.__isset.table_level_row_count && | 465 | 5 | this->get_scan_range().table_format_params.table_level_row_count >= 0) { | 466 | 0 | return Status::OK(); | 467 | 0 | } | 468 | | | 469 | 5 | const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params; | 470 | 5 | const auto& version = table_desc.format_version; | 471 | 5 | if (version < MIN_SUPPORT_DELETE_FILES_VERSION) { | 472 | 3 | return Status::OK(); | 473 | 3 | } | 474 | | | 475 | 2 | std::vector<TIcebergDeleteFileDesc> position_delete_files; | 476 | 2 | std::vector<TIcebergDeleteFileDesc> equality_delete_files; | 477 | 2 | std::vector<TIcebergDeleteFileDesc> deletion_vector_files; | 478 | 2 | for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) { | 479 | 2 | if (desc.content == POSITION_DELETE) { | 480 | 0 | position_delete_files.emplace_back(desc); | 481 | 2 | } else if (desc.content == EQUALITY_DELETE) { | 482 | 2 | equality_delete_files.emplace_back(desc); | 483 | 2 | } else if (desc.content == DELETION_VECTOR) { | 484 | 0 | deletion_vector_files.emplace_back(desc); | 485 | 0 | } | 486 | 2 | } | 487 | | | 488 | 2 | if (!equality_delete_files.empty()) { | 489 | 2 | RETURN_IF_ERROR(_equality_delete_base(equality_delete_files)); | 490 | 2 | this->set_push_down_agg_type(TPushAggOp::NONE); | 491 | 2 | } | 492 | | | 493 | 2 | if (!deletion_vector_files.empty()) { | 494 | 0 | if (deletion_vector_files.size() != 1) [[unlikely]] { | 495 | | /* | 496 | | * Deletion vectors are a binary representation of deletes for a single data file that is more efficient | 497 | | * at execution time than position delete files. Unlike equality or position delete files, there can be | 498 | | * at most one deletion vector for a given data file in a snapshot. | 499 | | */ | 500 | 0 | return Status::DataQualityError("This iceberg data file has multiple DVs."); | 501 | 0 | } | 502 | 0 | RETURN_IF_ERROR( | 503 | 0 | read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0])); | 504 | 0 | this->set_push_down_agg_type(TPushAggOp::NONE); | 505 | 2 | } else if (!position_delete_files.empty()) { | 506 | 0 | RETURN_IF_ERROR( | 507 | 0 | _position_delete_base(table_desc.original_file_path, position_delete_files)); | 508 | 0 | this->set_push_down_agg_type(TPushAggOp::NONE); | 509 | 0 | } | 510 | | | 511 | 2 | COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size()); | 512 | 2 | return Status::OK(); | 513 | 2 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE17_init_row_filtersEv Line | Count | Source | 457 | 4 | Status IcebergReaderMixin<BaseReader>::_init_row_filters() { | 458 | | // COUNT(*) short-circuit. A table-level row count of 0 (e.g. an all-deleted table read with | 459 | | // ignore_iceberg_dangling_delete, where total-records == total-position-deletes) is still a | 460 | | // valid pushed-down count, so accept >= 0 -- matching FileScanner and the Paimon readers. FE | 461 | | // sends -1 when there is no table-level count; using > 0 here would drop a genuine 0 into the | 462 | | // delete-applying path below and never produce the intended CountReader(0). | 463 | 4 | if (this->_push_down_agg_type == TPushAggOp::type::COUNT && | 464 | 4 | this->get_scan_range().table_format_params.__isset.table_level_row_count && | 465 | 4 | this->get_scan_range().table_format_params.table_level_row_count >= 0) { | 466 | 0 | return Status::OK(); | 467 | 0 | } | 468 | | | 469 | 4 | const auto& table_desc = this->get_scan_range().table_format_params.iceberg_params; | 470 | 4 | const auto& version = table_desc.format_version; | 471 | 4 | if (version < MIN_SUPPORT_DELETE_FILES_VERSION) { | 472 | 2 | return Status::OK(); | 473 | 2 | } | 474 | | | 475 | 2 | std::vector<TIcebergDeleteFileDesc> position_delete_files; | 476 | 2 | std::vector<TIcebergDeleteFileDesc> equality_delete_files; | 477 | 2 | std::vector<TIcebergDeleteFileDesc> deletion_vector_files; | 478 | 2 | for (const TIcebergDeleteFileDesc& desc : table_desc.delete_files) { | 479 | 2 | if (desc.content == POSITION_DELETE) { | 480 | 0 | position_delete_files.emplace_back(desc); | 481 | 2 | } else if (desc.content == EQUALITY_DELETE) { | 482 | 2 | equality_delete_files.emplace_back(desc); | 483 | 2 | } else if (desc.content == DELETION_VECTOR) { | 484 | 0 | deletion_vector_files.emplace_back(desc); | 485 | 0 | } | 486 | 2 | } | 487 | | | 488 | 2 | if (!equality_delete_files.empty()) { | 489 | 2 | RETURN_IF_ERROR(_equality_delete_base(equality_delete_files)); | 490 | 2 | this->set_push_down_agg_type(TPushAggOp::NONE); | 491 | 2 | } | 492 | | | 493 | 2 | if (!deletion_vector_files.empty()) { | 494 | 0 | if (deletion_vector_files.size() != 1) [[unlikely]] { | 495 | | /* | 496 | | * Deletion vectors are a binary representation of deletes for a single data file that is more efficient | 497 | | * at execution time than position delete files. Unlike equality or position delete files, there can be | 498 | | * at most one deletion vector for a given data file in a snapshot. | 499 | | */ | 500 | 0 | return Status::DataQualityError("This iceberg data file has multiple DVs."); | 501 | 0 | } | 502 | 0 | RETURN_IF_ERROR( | 503 | 0 | read_deletion_vector(table_desc.original_file_path, deletion_vector_files[0])); | 504 | 0 | this->set_push_down_agg_type(TPushAggOp::NONE); | 505 | 2 | } else if (!position_delete_files.empty()) { | 506 | 0 | RETURN_IF_ERROR( | 507 | 0 | _position_delete_base(table_desc.original_file_path, position_delete_files)); | 508 | 0 | this->set_push_down_agg_type(TPushAggOp::NONE); | 509 | 0 | } | 510 | | | 511 | 2 | COUNTER_UPDATE(_iceberg_profile.num_delete_files, table_desc.delete_files.size()); | 512 | 2 | return Status::OK(); | 513 | 2 | } |
|
514 | | |
515 | | template <typename BaseReader> |
516 | | Status IcebergReaderMixin<BaseReader>::_equality_delete_base( |
517 | 4 | const std::vector<TIcebergDeleteFileDesc>& delete_files) { |
518 | 4 | std::unordered_map<std::string, std::tuple<std::string, const SlotDescriptor*>> |
519 | 4 | partition_columns; |
520 | 4 | std::unordered_map<std::string, VExprContextSPtr> missing_columns; |
521 | | |
522 | 4 | for (const auto& delete_file : delete_files) { |
523 | 4 | TFileRangeDesc delete_desc; |
524 | 4 | delete_desc.__set_fs_name(this->get_scan_range().fs_name); |
525 | 4 | delete_desc.path = delete_file.path; |
526 | 4 | delete_desc.start_offset = 0; |
527 | 4 | delete_desc.size = -1; |
528 | 4 | delete_desc.file_size = -1; |
529 | | |
530 | 4 | if (!delete_file.__isset.field_ids) [[unlikely]] { |
531 | 0 | return Status::InternalError( |
532 | 0 | "missing delete field ids when reading equality delete file"); |
533 | 0 | } |
534 | 4 | auto& read_column_field_ids = delete_file.field_ids; |
535 | 4 | std::set<int> read_column_field_ids_set; |
536 | 4 | for (const auto& field_id : read_column_field_ids) { |
537 | 4 | read_column_field_ids_set.insert(field_id); |
538 | 4 | _equality_delete_col_ids.insert(field_id); |
539 | 4 | } |
540 | | |
541 | 4 | std::unique_ptr<GenericReader> delete_reader = _create_equality_reader(delete_desc); |
542 | 4 | RETURN_IF_ERROR(delete_reader->init_schema_reader()); |
543 | | |
544 | 4 | std::vector<std::string> equality_delete_col_names; |
545 | 4 | std::vector<DataTypePtr> equality_delete_col_types; |
546 | | |
547 | | // Build delete col names/types/ids by matching field_ids from delete file schema. |
548 | | // Master iterates delete file's FieldDescriptor and uses field_id to match, |
549 | | // NOT idx-based pairing (get_parsed_schema order != field_ids order). |
550 | 4 | std::vector<std::string> delete_col_names; |
551 | 4 | std::vector<DataTypePtr> delete_col_types; |
552 | 4 | std::vector<int> delete_col_ids; |
553 | 4 | std::unordered_map<std::string, uint32_t> delete_col_name_to_block_idx; |
554 | | |
555 | 4 | if (auto* parquet_reader = typeid_cast<ParquetReader*>(delete_reader.get())) { |
556 | 2 | const FieldDescriptor* delete_field_desc = nullptr; |
557 | 2 | RETURN_IF_ERROR(parquet_reader->get_file_metadata_schema(&delete_field_desc)); |
558 | 2 | DCHECK(delete_field_desc != nullptr); |
559 | | |
560 | 2 | for (const auto& delete_file_field : delete_field_desc->get_fields_schema()) { |
561 | 2 | if (delete_file_field.field_id == -1) [[unlikely]] { |
562 | 0 | return Status::DataQualityError( |
563 | 0 | "missing field id when reading equality delete file"); |
564 | 0 | } |
565 | 2 | if (!read_column_field_ids_set.contains(delete_file_field.field_id)) { |
566 | 0 | continue; |
567 | 0 | } |
568 | 2 | if (delete_file_field.children.size() > 0) [[unlikely]] { |
569 | 0 | return Status::InternalError( |
570 | 0 | "can not support read complex column in equality delete file"); |
571 | 0 | } |
572 | | |
573 | 2 | delete_col_ids.emplace_back(delete_file_field.field_id); |
574 | 2 | delete_col_names.emplace_back(delete_file_field.name); |
575 | 2 | delete_col_types.emplace_back(make_nullable(delete_file_field.data_type)); |
576 | | |
577 | 2 | int field_id = delete_file_field.field_id; |
578 | 2 | if (!_id_to_block_column_name.contains(field_id)) { |
579 | 2 | _id_to_block_column_name.emplace(field_id, delete_file_field.name); |
580 | 2 | _expand_col_names.emplace_back(delete_file_field.name); |
581 | 2 | _expand_columns.emplace_back( |
582 | 2 | make_nullable(delete_file_field.data_type)->create_column(), |
583 | 2 | make_nullable(delete_file_field.data_type), delete_file_field.name); |
584 | 2 | } |
585 | 2 | } |
586 | 4 | for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) { |
587 | 2 | delete_col_name_to_block_idx[delete_col_names[idx]] = idx; |
588 | 2 | } |
589 | | // Delete files have TFileRangeDesc.size=-1, which would cause |
590 | | // set_fill_columns to return EndOfFile("No row group to read") |
591 | | // when _filter_groups is true. Master passes filter_groups=false. |
592 | 2 | ParquetInitContext eq_delete_ctx; |
593 | 2 | eq_delete_ctx.filter_groups = false; |
594 | 2 | eq_delete_ctx.column_names = delete_col_names; |
595 | 2 | eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx; |
596 | 2 | auto st2 = parquet_reader->init_reader(&eq_delete_ctx); |
597 | 2 | if (!st2.ok()) { |
598 | 0 | return st2; |
599 | 0 | } |
600 | 2 | } else if (auto* orc_reader = typeid_cast<OrcReader*>(delete_reader.get())) { |
601 | | // For ORC: use get_parsed_schema with field_ids from delete_file |
602 | | // ORC field_ids come from the Thrift descriptor, not from ORC metadata |
603 | 2 | RETURN_IF_ERROR(delete_reader->get_parsed_schema(&equality_delete_col_names, |
604 | 2 | &equality_delete_col_types)); |
605 | 4 | for (uint32_t idx = 0; idx < equality_delete_col_names.size(); ++idx) { |
606 | 2 | if (idx < read_column_field_ids.size()) { |
607 | 2 | int field_id = read_column_field_ids[idx]; |
608 | 2 | if (!read_column_field_ids_set.contains(field_id)) continue; |
609 | 2 | delete_col_ids.emplace_back(field_id); |
610 | 2 | delete_col_names.emplace_back(equality_delete_col_names[idx]); |
611 | 2 | delete_col_types.emplace_back(make_nullable(equality_delete_col_types[idx])); |
612 | 2 | if (!_id_to_block_column_name.contains(field_id)) { |
613 | 2 | _id_to_block_column_name.emplace(field_id, equality_delete_col_names[idx]); |
614 | 2 | _expand_col_names.emplace_back(equality_delete_col_names[idx]); |
615 | 2 | _expand_columns.emplace_back( |
616 | 2 | make_nullable(equality_delete_col_types[idx])->create_column(), |
617 | 2 | make_nullable(equality_delete_col_types[idx]), |
618 | 2 | equality_delete_col_names[idx]); |
619 | 2 | } |
620 | 2 | } |
621 | 2 | } |
622 | 4 | for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) { |
623 | 2 | delete_col_name_to_block_idx[delete_col_names[idx]] = idx; |
624 | 2 | } |
625 | 2 | OrcInitContext eq_delete_ctx; |
626 | 2 | eq_delete_ctx.column_names = delete_col_names; |
627 | 2 | eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx; |
628 | 2 | RETURN_IF_ERROR(orc_reader->init_reader(&eq_delete_ctx)); |
629 | 2 | } else { |
630 | 0 | return Status::InternalError("Unsupported format of delete file"); |
631 | 0 | } |
632 | | |
633 | 4 | if (!_equality_delete_block_map.contains(delete_col_ids)) { |
634 | 4 | _equality_delete_block_map.emplace(delete_col_ids, _equality_delete_blocks.size()); |
635 | 4 | Block block; |
636 | 4 | _generate_equality_delete_block(&block, delete_col_names, delete_col_types); |
637 | 4 | _equality_delete_blocks.emplace_back(block); |
638 | 4 | } |
639 | 4 | Block& eq_file_block = _equality_delete_blocks[_equality_delete_block_map[delete_col_ids]]; |
640 | | |
641 | 4 | bool eof = false; |
642 | 10 | while (!eof) { |
643 | 6 | Block tmp_block; |
644 | 6 | _generate_equality_delete_block(&tmp_block, delete_col_names, delete_col_types); |
645 | 6 | size_t read_rows = 0; |
646 | 6 | auto st = delete_reader->get_next_block(&tmp_block, &read_rows, &eof); |
647 | 6 | if (!st.ok()) { |
648 | 0 | return st; |
649 | 0 | } |
650 | 6 | if (read_rows > 0) { |
651 | 4 | ScopedMutableBlock scoped_mutable_block(&eq_file_block); |
652 | 4 | auto& mutable_block = scoped_mutable_block.mutable_block(); |
653 | 4 | RETURN_IF_ERROR(mutable_block.merge(tmp_block)); |
654 | 4 | } |
655 | 6 | } |
656 | 4 | } |
657 | | |
658 | 4 | for (const auto& [delete_col_ids, block_idx] : _equality_delete_block_map) { |
659 | 4 | auto& eq_file_block = _equality_delete_blocks[block_idx]; |
660 | 4 | auto equality_delete_impl = |
661 | 4 | EqualityDeleteBase::get_delete_impl(&eq_file_block, delete_col_ids); |
662 | 4 | RETURN_IF_ERROR(equality_delete_impl->init(this->get_profile())); |
663 | 4 | _equality_delete_impls.emplace_back(std::move(equality_delete_impl)); |
664 | 4 | } |
665 | 4 | return Status::OK(); |
666 | 4 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_equality_delete_baseERKSt6vectorINS_22TIcebergDeleteFileDescESaIS4_EE Line | Count | Source | 517 | 2 | const std::vector<TIcebergDeleteFileDesc>& delete_files) { | 518 | 2 | std::unordered_map<std::string, std::tuple<std::string, const SlotDescriptor*>> | 519 | 2 | partition_columns; | 520 | 2 | std::unordered_map<std::string, VExprContextSPtr> missing_columns; | 521 | | | 522 | 2 | for (const auto& delete_file : delete_files) { | 523 | 2 | TFileRangeDesc delete_desc; | 524 | 2 | delete_desc.__set_fs_name(this->get_scan_range().fs_name); | 525 | 2 | delete_desc.path = delete_file.path; | 526 | 2 | delete_desc.start_offset = 0; | 527 | 2 | delete_desc.size = -1; | 528 | 2 | delete_desc.file_size = -1; | 529 | | | 530 | 2 | if (!delete_file.__isset.field_ids) [[unlikely]] { | 531 | 0 | return Status::InternalError( | 532 | 0 | "missing delete field ids when reading equality delete file"); | 533 | 0 | } | 534 | 2 | auto& read_column_field_ids = delete_file.field_ids; | 535 | 2 | std::set<int> read_column_field_ids_set; | 536 | 2 | for (const auto& field_id : read_column_field_ids) { | 537 | 2 | read_column_field_ids_set.insert(field_id); | 538 | 2 | _equality_delete_col_ids.insert(field_id); | 539 | 2 | } | 540 | | | 541 | 2 | std::unique_ptr<GenericReader> delete_reader = _create_equality_reader(delete_desc); | 542 | 2 | RETURN_IF_ERROR(delete_reader->init_schema_reader()); | 543 | | | 544 | 2 | std::vector<std::string> equality_delete_col_names; | 545 | 2 | std::vector<DataTypePtr> equality_delete_col_types; | 546 | | | 547 | | // Build delete col names/types/ids by matching field_ids from delete file schema. | 548 | | // Master iterates delete file's FieldDescriptor and uses field_id to match, | 549 | | // NOT idx-based pairing (get_parsed_schema order != field_ids order). | 550 | 2 | std::vector<std::string> delete_col_names; | 551 | 2 | std::vector<DataTypePtr> delete_col_types; | 552 | 2 | std::vector<int> delete_col_ids; | 553 | 2 | std::unordered_map<std::string, uint32_t> delete_col_name_to_block_idx; | 554 | | | 555 | 2 | if (auto* parquet_reader = typeid_cast<ParquetReader*>(delete_reader.get())) { | 556 | 2 | const FieldDescriptor* delete_field_desc = nullptr; | 557 | 2 | RETURN_IF_ERROR(parquet_reader->get_file_metadata_schema(&delete_field_desc)); | 558 | 2 | DCHECK(delete_field_desc != nullptr); | 559 | | | 560 | 2 | for (const auto& delete_file_field : delete_field_desc->get_fields_schema()) { | 561 | 2 | if (delete_file_field.field_id == -1) [[unlikely]] { | 562 | 0 | return Status::DataQualityError( | 563 | 0 | "missing field id when reading equality delete file"); | 564 | 0 | } | 565 | 2 | if (!read_column_field_ids_set.contains(delete_file_field.field_id)) { | 566 | 0 | continue; | 567 | 0 | } | 568 | 2 | if (delete_file_field.children.size() > 0) [[unlikely]] { | 569 | 0 | return Status::InternalError( | 570 | 0 | "can not support read complex column in equality delete file"); | 571 | 0 | } | 572 | | | 573 | 2 | delete_col_ids.emplace_back(delete_file_field.field_id); | 574 | 2 | delete_col_names.emplace_back(delete_file_field.name); | 575 | 2 | delete_col_types.emplace_back(make_nullable(delete_file_field.data_type)); | 576 | | | 577 | 2 | int field_id = delete_file_field.field_id; | 578 | 2 | if (!_id_to_block_column_name.contains(field_id)) { | 579 | 2 | _id_to_block_column_name.emplace(field_id, delete_file_field.name); | 580 | 2 | _expand_col_names.emplace_back(delete_file_field.name); | 581 | 2 | _expand_columns.emplace_back( | 582 | 2 | make_nullable(delete_file_field.data_type)->create_column(), | 583 | 2 | make_nullable(delete_file_field.data_type), delete_file_field.name); | 584 | 2 | } | 585 | 2 | } | 586 | 4 | for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) { | 587 | 2 | delete_col_name_to_block_idx[delete_col_names[idx]] = idx; | 588 | 2 | } | 589 | | // Delete files have TFileRangeDesc.size=-1, which would cause | 590 | | // set_fill_columns to return EndOfFile("No row group to read") | 591 | | // when _filter_groups is true. Master passes filter_groups=false. | 592 | 2 | ParquetInitContext eq_delete_ctx; | 593 | 2 | eq_delete_ctx.filter_groups = false; | 594 | 2 | eq_delete_ctx.column_names = delete_col_names; | 595 | 2 | eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx; | 596 | 2 | auto st2 = parquet_reader->init_reader(&eq_delete_ctx); | 597 | 2 | if (!st2.ok()) { | 598 | 0 | return st2; | 599 | 0 | } | 600 | 2 | } else if (auto* orc_reader = typeid_cast<OrcReader*>(delete_reader.get())) { | 601 | | // For ORC: use get_parsed_schema with field_ids from delete_file | 602 | | // ORC field_ids come from the Thrift descriptor, not from ORC metadata | 603 | 0 | RETURN_IF_ERROR(delete_reader->get_parsed_schema(&equality_delete_col_names, | 604 | 0 | &equality_delete_col_types)); | 605 | 0 | for (uint32_t idx = 0; idx < equality_delete_col_names.size(); ++idx) { | 606 | 0 | if (idx < read_column_field_ids.size()) { | 607 | 0 | int field_id = read_column_field_ids[idx]; | 608 | 0 | if (!read_column_field_ids_set.contains(field_id)) continue; | 609 | 0 | delete_col_ids.emplace_back(field_id); | 610 | 0 | delete_col_names.emplace_back(equality_delete_col_names[idx]); | 611 | 0 | delete_col_types.emplace_back(make_nullable(equality_delete_col_types[idx])); | 612 | 0 | if (!_id_to_block_column_name.contains(field_id)) { | 613 | 0 | _id_to_block_column_name.emplace(field_id, equality_delete_col_names[idx]); | 614 | 0 | _expand_col_names.emplace_back(equality_delete_col_names[idx]); | 615 | 0 | _expand_columns.emplace_back( | 616 | 0 | make_nullable(equality_delete_col_types[idx])->create_column(), | 617 | 0 | make_nullable(equality_delete_col_types[idx]), | 618 | 0 | equality_delete_col_names[idx]); | 619 | 0 | } | 620 | 0 | } | 621 | 0 | } | 622 | 0 | for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) { | 623 | 0 | delete_col_name_to_block_idx[delete_col_names[idx]] = idx; | 624 | 0 | } | 625 | 0 | OrcInitContext eq_delete_ctx; | 626 | 0 | eq_delete_ctx.column_names = delete_col_names; | 627 | 0 | eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx; | 628 | 0 | RETURN_IF_ERROR(orc_reader->init_reader(&eq_delete_ctx)); | 629 | 0 | } else { | 630 | 0 | return Status::InternalError("Unsupported format of delete file"); | 631 | 0 | } | 632 | | | 633 | 2 | if (!_equality_delete_block_map.contains(delete_col_ids)) { | 634 | 2 | _equality_delete_block_map.emplace(delete_col_ids, _equality_delete_blocks.size()); | 635 | 2 | Block block; | 636 | 2 | _generate_equality_delete_block(&block, delete_col_names, delete_col_types); | 637 | 2 | _equality_delete_blocks.emplace_back(block); | 638 | 2 | } | 639 | 2 | Block& eq_file_block = _equality_delete_blocks[_equality_delete_block_map[delete_col_ids]]; | 640 | | | 641 | 2 | bool eof = false; | 642 | 4 | while (!eof) { | 643 | 2 | Block tmp_block; | 644 | 2 | _generate_equality_delete_block(&tmp_block, delete_col_names, delete_col_types); | 645 | 2 | size_t read_rows = 0; | 646 | 2 | auto st = delete_reader->get_next_block(&tmp_block, &read_rows, &eof); | 647 | 2 | if (!st.ok()) { | 648 | 0 | return st; | 649 | 0 | } | 650 | 2 | if (read_rows > 0) { | 651 | 2 | ScopedMutableBlock scoped_mutable_block(&eq_file_block); | 652 | 2 | auto& mutable_block = scoped_mutable_block.mutable_block(); | 653 | 2 | RETURN_IF_ERROR(mutable_block.merge(tmp_block)); | 654 | 2 | } | 655 | 2 | } | 656 | 2 | } | 657 | | | 658 | 2 | for (const auto& [delete_col_ids, block_idx] : _equality_delete_block_map) { | 659 | 2 | auto& eq_file_block = _equality_delete_blocks[block_idx]; | 660 | 2 | auto equality_delete_impl = | 661 | 2 | EqualityDeleteBase::get_delete_impl(&eq_file_block, delete_col_ids); | 662 | 2 | RETURN_IF_ERROR(equality_delete_impl->init(this->get_profile())); | 663 | 2 | _equality_delete_impls.emplace_back(std::move(equality_delete_impl)); | 664 | 2 | } | 665 | 2 | return Status::OK(); | 666 | 2 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_equality_delete_baseERKSt6vectorINS_22TIcebergDeleteFileDescESaIS4_EE Line | Count | Source | 517 | 2 | const std::vector<TIcebergDeleteFileDesc>& delete_files) { | 518 | 2 | std::unordered_map<std::string, std::tuple<std::string, const SlotDescriptor*>> | 519 | 2 | partition_columns; | 520 | 2 | std::unordered_map<std::string, VExprContextSPtr> missing_columns; | 521 | | | 522 | 2 | for (const auto& delete_file : delete_files) { | 523 | 2 | TFileRangeDesc delete_desc; | 524 | 2 | delete_desc.__set_fs_name(this->get_scan_range().fs_name); | 525 | 2 | delete_desc.path = delete_file.path; | 526 | 2 | delete_desc.start_offset = 0; | 527 | 2 | delete_desc.size = -1; | 528 | 2 | delete_desc.file_size = -1; | 529 | | | 530 | 2 | if (!delete_file.__isset.field_ids) [[unlikely]] { | 531 | 0 | return Status::InternalError( | 532 | 0 | "missing delete field ids when reading equality delete file"); | 533 | 0 | } | 534 | 2 | auto& read_column_field_ids = delete_file.field_ids; | 535 | 2 | std::set<int> read_column_field_ids_set; | 536 | 2 | for (const auto& field_id : read_column_field_ids) { | 537 | 2 | read_column_field_ids_set.insert(field_id); | 538 | 2 | _equality_delete_col_ids.insert(field_id); | 539 | 2 | } | 540 | | | 541 | 2 | std::unique_ptr<GenericReader> delete_reader = _create_equality_reader(delete_desc); | 542 | 2 | RETURN_IF_ERROR(delete_reader->init_schema_reader()); | 543 | | | 544 | 2 | std::vector<std::string> equality_delete_col_names; | 545 | 2 | std::vector<DataTypePtr> equality_delete_col_types; | 546 | | | 547 | | // Build delete col names/types/ids by matching field_ids from delete file schema. | 548 | | // Master iterates delete file's FieldDescriptor and uses field_id to match, | 549 | | // NOT idx-based pairing (get_parsed_schema order != field_ids order). | 550 | 2 | std::vector<std::string> delete_col_names; | 551 | 2 | std::vector<DataTypePtr> delete_col_types; | 552 | 2 | std::vector<int> delete_col_ids; | 553 | 2 | std::unordered_map<std::string, uint32_t> delete_col_name_to_block_idx; | 554 | | | 555 | 2 | if (auto* parquet_reader = typeid_cast<ParquetReader*>(delete_reader.get())) { | 556 | 0 | const FieldDescriptor* delete_field_desc = nullptr; | 557 | 0 | RETURN_IF_ERROR(parquet_reader->get_file_metadata_schema(&delete_field_desc)); | 558 | 0 | DCHECK(delete_field_desc != nullptr); | 559 | |
| 560 | 0 | for (const auto& delete_file_field : delete_field_desc->get_fields_schema()) { | 561 | 0 | if (delete_file_field.field_id == -1) [[unlikely]] { | 562 | 0 | return Status::DataQualityError( | 563 | 0 | "missing field id when reading equality delete file"); | 564 | 0 | } | 565 | 0 | if (!read_column_field_ids_set.contains(delete_file_field.field_id)) { | 566 | 0 | continue; | 567 | 0 | } | 568 | 0 | if (delete_file_field.children.size() > 0) [[unlikely]] { | 569 | 0 | return Status::InternalError( | 570 | 0 | "can not support read complex column in equality delete file"); | 571 | 0 | } | 572 | | | 573 | 0 | delete_col_ids.emplace_back(delete_file_field.field_id); | 574 | 0 | delete_col_names.emplace_back(delete_file_field.name); | 575 | 0 | delete_col_types.emplace_back(make_nullable(delete_file_field.data_type)); | 576 | |
| 577 | 0 | int field_id = delete_file_field.field_id; | 578 | 0 | if (!_id_to_block_column_name.contains(field_id)) { | 579 | 0 | _id_to_block_column_name.emplace(field_id, delete_file_field.name); | 580 | 0 | _expand_col_names.emplace_back(delete_file_field.name); | 581 | 0 | _expand_columns.emplace_back( | 582 | 0 | make_nullable(delete_file_field.data_type)->create_column(), | 583 | 0 | make_nullable(delete_file_field.data_type), delete_file_field.name); | 584 | 0 | } | 585 | 0 | } | 586 | 0 | for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) { | 587 | 0 | delete_col_name_to_block_idx[delete_col_names[idx]] = idx; | 588 | 0 | } | 589 | | // Delete files have TFileRangeDesc.size=-1, which would cause | 590 | | // set_fill_columns to return EndOfFile("No row group to read") | 591 | | // when _filter_groups is true. Master passes filter_groups=false. | 592 | 0 | ParquetInitContext eq_delete_ctx; | 593 | 0 | eq_delete_ctx.filter_groups = false; | 594 | 0 | eq_delete_ctx.column_names = delete_col_names; | 595 | 0 | eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx; | 596 | 0 | auto st2 = parquet_reader->init_reader(&eq_delete_ctx); | 597 | 0 | if (!st2.ok()) { | 598 | 0 | return st2; | 599 | 0 | } | 600 | 2 | } else if (auto* orc_reader = typeid_cast<OrcReader*>(delete_reader.get())) { | 601 | | // For ORC: use get_parsed_schema with field_ids from delete_file | 602 | | // ORC field_ids come from the Thrift descriptor, not from ORC metadata | 603 | 2 | RETURN_IF_ERROR(delete_reader->get_parsed_schema(&equality_delete_col_names, | 604 | 2 | &equality_delete_col_types)); | 605 | 4 | for (uint32_t idx = 0; idx < equality_delete_col_names.size(); ++idx) { | 606 | 2 | if (idx < read_column_field_ids.size()) { | 607 | 2 | int field_id = read_column_field_ids[idx]; | 608 | 2 | if (!read_column_field_ids_set.contains(field_id)) continue; | 609 | 2 | delete_col_ids.emplace_back(field_id); | 610 | 2 | delete_col_names.emplace_back(equality_delete_col_names[idx]); | 611 | 2 | delete_col_types.emplace_back(make_nullable(equality_delete_col_types[idx])); | 612 | 2 | if (!_id_to_block_column_name.contains(field_id)) { | 613 | 2 | _id_to_block_column_name.emplace(field_id, equality_delete_col_names[idx]); | 614 | 2 | _expand_col_names.emplace_back(equality_delete_col_names[idx]); | 615 | 2 | _expand_columns.emplace_back( | 616 | 2 | make_nullable(equality_delete_col_types[idx])->create_column(), | 617 | 2 | make_nullable(equality_delete_col_types[idx]), | 618 | 2 | equality_delete_col_names[idx]); | 619 | 2 | } | 620 | 2 | } | 621 | 2 | } | 622 | 4 | for (uint32_t idx = 0; idx < delete_col_names.size(); ++idx) { | 623 | 2 | delete_col_name_to_block_idx[delete_col_names[idx]] = idx; | 624 | 2 | } | 625 | 2 | OrcInitContext eq_delete_ctx; | 626 | 2 | eq_delete_ctx.column_names = delete_col_names; | 627 | 2 | eq_delete_ctx.col_name_to_block_idx = &delete_col_name_to_block_idx; | 628 | 2 | RETURN_IF_ERROR(orc_reader->init_reader(&eq_delete_ctx)); | 629 | 2 | } else { | 630 | 0 | return Status::InternalError("Unsupported format of delete file"); | 631 | 0 | } | 632 | | | 633 | 2 | if (!_equality_delete_block_map.contains(delete_col_ids)) { | 634 | 2 | _equality_delete_block_map.emplace(delete_col_ids, _equality_delete_blocks.size()); | 635 | 2 | Block block; | 636 | 2 | _generate_equality_delete_block(&block, delete_col_names, delete_col_types); | 637 | 2 | _equality_delete_blocks.emplace_back(block); | 638 | 2 | } | 639 | 2 | Block& eq_file_block = _equality_delete_blocks[_equality_delete_block_map[delete_col_ids]]; | 640 | | | 641 | 2 | bool eof = false; | 642 | 6 | while (!eof) { | 643 | 4 | Block tmp_block; | 644 | 4 | _generate_equality_delete_block(&tmp_block, delete_col_names, delete_col_types); | 645 | 4 | size_t read_rows = 0; | 646 | 4 | auto st = delete_reader->get_next_block(&tmp_block, &read_rows, &eof); | 647 | 4 | if (!st.ok()) { | 648 | 0 | return st; | 649 | 0 | } | 650 | 4 | if (read_rows > 0) { | 651 | 2 | ScopedMutableBlock scoped_mutable_block(&eq_file_block); | 652 | 2 | auto& mutable_block = scoped_mutable_block.mutable_block(); | 653 | 2 | RETURN_IF_ERROR(mutable_block.merge(tmp_block)); | 654 | 2 | } | 655 | 4 | } | 656 | 2 | } | 657 | | | 658 | 2 | for (const auto& [delete_col_ids, block_idx] : _equality_delete_block_map) { | 659 | 2 | auto& eq_file_block = _equality_delete_blocks[block_idx]; | 660 | 2 | auto equality_delete_impl = | 661 | 2 | EqualityDeleteBase::get_delete_impl(&eq_file_block, delete_col_ids); | 662 | 2 | RETURN_IF_ERROR(equality_delete_impl->init(this->get_profile())); | 663 | 2 | _equality_delete_impls.emplace_back(std::move(equality_delete_impl)); | 664 | 2 | } | 665 | 2 | return Status::OK(); | 666 | 2 | } |
|
667 | | |
668 | | template <typename BaseReader> |
669 | | void IcebergReaderMixin<BaseReader>::_generate_equality_delete_block( |
670 | | Block* block, const std::vector<std::string>& equality_delete_col_names, |
671 | 10 | const std::vector<DataTypePtr>& equality_delete_col_types) { |
672 | 20 | for (int i = 0; i < equality_delete_col_names.size(); ++i) { |
673 | 10 | DataTypePtr data_type = make_nullable(equality_delete_col_types[i]); |
674 | 10 | MutableColumnPtr data_column = data_type->create_column(); |
675 | 10 | block->insert(ColumnWithTypeAndName(std::move(data_column), data_type, |
676 | 10 | equality_delete_col_names[i])); |
677 | 10 | } |
678 | 10 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE31_generate_equality_delete_blockEPNS_5BlockERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EERKS5_ISt10shared_ptrIKNS_9IDataTypeEESaISJ_EE Line | Count | Source | 671 | 4 | const std::vector<DataTypePtr>& equality_delete_col_types) { | 672 | 8 | for (int i = 0; i < equality_delete_col_names.size(); ++i) { | 673 | 4 | DataTypePtr data_type = make_nullable(equality_delete_col_types[i]); | 674 | 4 | MutableColumnPtr data_column = data_type->create_column(); | 675 | 4 | block->insert(ColumnWithTypeAndName(std::move(data_column), data_type, | 676 | 4 | equality_delete_col_names[i])); | 677 | 4 | } | 678 | 4 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE31_generate_equality_delete_blockEPNS_5BlockERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISB_EERKS5_ISt10shared_ptrIKNS_9IDataTypeEESaISJ_EE Line | Count | Source | 671 | 6 | const std::vector<DataTypePtr>& equality_delete_col_types) { | 672 | 12 | for (int i = 0; i < equality_delete_col_names.size(); ++i) { | 673 | 6 | DataTypePtr data_type = make_nullable(equality_delete_col_types[i]); | 674 | 6 | MutableColumnPtr data_column = data_type->create_column(); | 675 | 6 | block->insert(ColumnWithTypeAndName(std::move(data_column), data_type, | 676 | 6 | equality_delete_col_names[i])); | 677 | 6 | } | 678 | 6 | } |
|
679 | | |
680 | | template <typename BaseReader> |
681 | 9 | Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) { |
682 | 9 | std::set<std::string> names; |
683 | 9 | auto block_names = block->get_names(); |
684 | 9 | names.insert(block_names.begin(), block_names.end()); |
685 | 9 | for (auto& col : _expand_columns) { |
686 | 4 | if (_missing_equality_delete_values.contains(col.name)) { |
687 | | // Missing equality keys are logical columns, not physical file columns. Add them only |
688 | | // after the base reader has established the batch row count. |
689 | 1 | continue; |
690 | 1 | } |
691 | 3 | if (names.contains(col.name)) { |
692 | 0 | return Status::InternalError("Wrong expand column '{}'", col.name); |
693 | 0 | } |
694 | 3 | names.insert(col.name); |
695 | 3 | (*this->col_name_to_block_idx_ref())[col.name] = block->columns(); |
696 | 3 | block->insert({col.type->create_column(), col.type, col.name}); |
697 | 3 | } |
698 | 9 | return Status::OK(); |
699 | 9 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_expand_block_if_needEPNS_5BlockE Line | Count | Source | 681 | 5 | Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) { | 682 | 5 | std::set<std::string> names; | 683 | 5 | auto block_names = block->get_names(); | 684 | 5 | names.insert(block_names.begin(), block_names.end()); | 685 | 5 | for (auto& col : _expand_columns) { | 686 | 2 | if (_missing_equality_delete_values.contains(col.name)) { | 687 | | // Missing equality keys are logical columns, not physical file columns. Add them only | 688 | | // after the base reader has established the batch row count. | 689 | 0 | continue; | 690 | 0 | } | 691 | 2 | if (names.contains(col.name)) { | 692 | 0 | return Status::InternalError("Wrong expand column '{}'", col.name); | 693 | 0 | } | 694 | 2 | names.insert(col.name); | 695 | 2 | (*this->col_name_to_block_idx_ref())[col.name] = block->columns(); | 696 | 2 | block->insert({col.type->create_column(), col.type, col.name}); | 697 | 2 | } | 698 | 5 | return Status::OK(); | 699 | 5 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_expand_block_if_needEPNS_5BlockE Line | Count | Source | 681 | 4 | Status IcebergReaderMixin<BaseReader>::_expand_block_if_need(Block* block) { | 682 | 4 | std::set<std::string> names; | 683 | 4 | auto block_names = block->get_names(); | 684 | 4 | names.insert(block_names.begin(), block_names.end()); | 685 | 4 | for (auto& col : _expand_columns) { | 686 | 2 | if (_missing_equality_delete_values.contains(col.name)) { | 687 | | // Missing equality keys are logical columns, not physical file columns. Add them only | 688 | | // after the base reader has established the batch row count. | 689 | 1 | continue; | 690 | 1 | } | 691 | 1 | if (names.contains(col.name)) { | 692 | 0 | return Status::InternalError("Wrong expand column '{}'", col.name); | 693 | 0 | } | 694 | 1 | names.insert(col.name); | 695 | 1 | (*this->col_name_to_block_idx_ref())[col.name] = block->columns(); | 696 | 1 | block->insert({col.type->create_column(), col.type, col.name}); | 697 | 1 | } | 698 | 4 | return Status::OK(); | 699 | 4 | } |
|
700 | | |
701 | | template <typename BaseReader> |
702 | 2 | const schema::external::TStructField* IcebergReaderMixin<BaseReader>::_current_schema_root() const { |
703 | 2 | const auto& scan_params = this->get_scan_params(); |
704 | 2 | if (!scan_params.__isset.history_schema_info || scan_params.history_schema_info.empty()) { |
705 | 0 | return nullptr; |
706 | 0 | } |
707 | 2 | const schema::external::TSchema* current_schema = &scan_params.history_schema_info.front(); |
708 | 2 | if (scan_params.__isset.current_schema_id) { |
709 | 2 | const auto schema_it = std::ranges::find_if( |
710 | 2 | scan_params.history_schema_info, [&](const schema::external::TSchema& schema) { |
711 | 2 | return schema.__isset.schema_id && |
712 | 2 | schema.schema_id == scan_params.current_schema_id; |
713 | 2 | }); _ZZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE20_current_schema_rootEvENKUlRKNS_6schema8external7TSchemaEE_clES7_ Line | Count | Source | 710 | 2 | scan_params.history_schema_info, [&](const schema::external::TSchema& schema) { | 711 | 2 | return schema.__isset.schema_id && | 712 | 2 | schema.schema_id == scan_params.current_schema_id; | 713 | 2 | }); |
Unexecuted instantiation: _ZZNK5doris18IcebergReaderMixinINS_9OrcReaderEE20_current_schema_rootEvENKUlRKNS_6schema8external7TSchemaEE_clES7_ |
714 | 2 | if (schema_it == scan_params.history_schema_info.end()) { |
715 | 0 | return nullptr; |
716 | 0 | } |
717 | 2 | current_schema = &*schema_it; |
718 | 2 | } |
719 | 2 | return current_schema->__isset.root_field ? ¤t_schema->root_field : nullptr; |
720 | 2 | } _ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE20_current_schema_rootEv Line | Count | Source | 702 | 2 | const schema::external::TStructField* IcebergReaderMixin<BaseReader>::_current_schema_root() const { | 703 | 2 | const auto& scan_params = this->get_scan_params(); | 704 | 2 | if (!scan_params.__isset.history_schema_info || scan_params.history_schema_info.empty()) { | 705 | 0 | return nullptr; | 706 | 0 | } | 707 | 2 | const schema::external::TSchema* current_schema = &scan_params.history_schema_info.front(); | 708 | 2 | if (scan_params.__isset.current_schema_id) { | 709 | 2 | const auto schema_it = std::ranges::find_if( | 710 | 2 | scan_params.history_schema_info, [&](const schema::external::TSchema& schema) { | 711 | 2 | return schema.__isset.schema_id && | 712 | 2 | schema.schema_id == scan_params.current_schema_id; | 713 | 2 | }); | 714 | 2 | if (schema_it == scan_params.history_schema_info.end()) { | 715 | 0 | return nullptr; | 716 | 0 | } | 717 | 2 | current_schema = &*schema_it; | 718 | 2 | } | 719 | 2 | return current_schema->__isset.root_field ? ¤t_schema->root_field : nullptr; | 720 | 2 | } |
Unexecuted instantiation: _ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE20_current_schema_rootEv |
721 | | |
722 | | template <typename BaseReader> |
723 | | const schema::external::TField* IcebergReaderMixin<BaseReader>::_find_current_schema_field( |
724 | 1 | const std::string& name) const { |
725 | 1 | const auto* root = _current_schema_root(); |
726 | 1 | if (root == nullptr) { |
727 | 0 | return nullptr; |
728 | 0 | } |
729 | 1 | const auto field = std::ranges::find_if(root->fields, [&](const auto& field_ptr) { |
730 | 1 | return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr && |
731 | 1 | field_ptr.field_ptr->__isset.name && field_ptr.field_ptr->name == name; |
732 | 1 | }); _ZZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE26_find_current_schema_fieldERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENKUlRKT_E_clINS_6schema8external9TFieldPtrEEEDaSD_ Line | Count | Source | 729 | 1 | const auto field = std::ranges::find_if(root->fields, [&](const auto& field_ptr) { | 730 | 1 | return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr && | 731 | 1 | field_ptr.field_ptr->__isset.name && field_ptr.field_ptr->name == name; | 732 | 1 | }); |
Unexecuted instantiation: _ZZNK5doris18IcebergReaderMixinINS_9OrcReaderEE26_find_current_schema_fieldERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENKUlRKT_E_clINS_6schema8external9TFieldPtrEEEDaSD_ |
733 | 1 | return field == root->fields.end() ? nullptr : field->field_ptr.get(); |
734 | 1 | } _ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE26_find_current_schema_fieldERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE Line | Count | Source | 724 | 1 | const std::string& name) const { | 725 | 1 | const auto* root = _current_schema_root(); | 726 | 1 | if (root == nullptr) { | 727 | 0 | return nullptr; | 728 | 0 | } | 729 | 1 | const auto field = std::ranges::find_if(root->fields, [&](const auto& field_ptr) { | 730 | 1 | return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr && | 731 | 1 | field_ptr.field_ptr->__isset.name && field_ptr.field_ptr->name == name; | 732 | 1 | }); | 733 | 1 | return field == root->fields.end() ? nullptr : field->field_ptr.get(); | 734 | 1 | } |
Unexecuted instantiation: _ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE26_find_current_schema_fieldERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE |
735 | | |
736 | | template <typename BaseReader> |
737 | | const schema::external::TField* IcebergReaderMixin<BaseReader>::_find_current_schema_field( |
738 | 1 | int32_t field_id) const { |
739 | 1 | const auto* root = _current_schema_root(); |
740 | 1 | if (root == nullptr) { |
741 | 0 | return nullptr; |
742 | 0 | } |
743 | 2 | const auto field = std::ranges::find_if(root->fields, [&](const auto& field_ptr) { |
744 | 2 | return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr && |
745 | 2 | field_ptr.field_ptr->__isset.id && field_ptr.field_ptr->id == field_id; |
746 | 2 | }); _ZZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE26_find_current_schema_fieldEiENKUlRKT_E_clINS_6schema8external9TFieldPtrEEEDaS5_ Line | Count | Source | 743 | 2 | const auto field = std::ranges::find_if(root->fields, [&](const auto& field_ptr) { | 744 | 2 | return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr && | 745 | 2 | field_ptr.field_ptr->__isset.id && field_ptr.field_ptr->id == field_id; | 746 | 2 | }); |
Unexecuted instantiation: _ZZNK5doris18IcebergReaderMixinINS_9OrcReaderEE26_find_current_schema_fieldEiENKUlRKT_E_clINS_6schema8external9TFieldPtrEEEDaS5_ |
747 | 1 | return field == root->fields.end() ? nullptr : field->field_ptr.get(); |
748 | 1 | } _ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE26_find_current_schema_fieldEi Line | Count | Source | 738 | 1 | int32_t field_id) const { | 739 | 1 | const auto* root = _current_schema_root(); | 740 | 1 | if (root == nullptr) { | 741 | 0 | return nullptr; | 742 | 0 | } | 743 | 1 | const auto field = std::ranges::find_if(root->fields, [&](const auto& field_ptr) { | 744 | 1 | return field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr && | 745 | 1 | field_ptr.field_ptr->__isset.id && field_ptr.field_ptr->id == field_id; | 746 | 1 | }); | 747 | 1 | return field == root->fields.end() ? nullptr : field->field_ptr.get(); | 748 | 1 | } |
Unexecuted instantiation: _ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE26_find_current_schema_fieldEi |
749 | | |
750 | | template <typename BaseReader> |
751 | | Status IcebergReaderMixin<BaseReader>::_build_owned_initial_default_column( |
752 | | const schema::external::TField& field, const DataTypePtr& type, size_t rows, |
753 | 6 | ColumnPtr* column) const { |
754 | 6 | DORIS_CHECK(type != nullptr); |
755 | 6 | DORIS_CHECK(column != nullptr); |
756 | 6 | DORIS_CHECK(field.__isset.initial_default_value); |
757 | 6 | const auto nested_type = remove_nullable(type); |
758 | 6 | const bool is_base64 = |
759 | 6 | (field.__isset.initial_default_value_is_base64 && |
760 | 6 | field.initial_default_value_is_base64) || |
761 | 6 | (field.__isset.type && thrift_to_type(field.type.type) == TYPE_VARBINARY); |
762 | 6 | Field value; |
763 | 6 | if (is_base64) { |
764 | 3 | std::string decoded; |
765 | 3 | if (!base64_decode(field.initial_default_value, &decoded)) { |
766 | 0 | return Status::InvalidArgument("Invalid Base64 Iceberg initial default for field {}", |
767 | 0 | field.name); |
768 | 0 | } |
769 | 3 | if (nested_type->get_primitive_type() == TYPE_VARBINARY) { |
770 | 2 | value = Field::create_field<TYPE_VARBINARY>(StringView(decoded)); |
771 | 2 | } else { |
772 | 1 | DORIS_CHECK(is_string_type(nested_type->get_primitive_type())); |
773 | 1 | value = Field::create_field<TYPE_STRING>(decoded); |
774 | 1 | } |
775 | | // Variable-width Fields borrow decoded. Materialize before it leaves scope so every V1 |
776 | | // missing-column and equality-delete boundary keeps UUID/FIXED payloads alive. |
777 | 3 | *column = type->create_column_const(rows, value); |
778 | 3 | return Status::OK(); |
779 | 3 | } |
780 | 3 | RETURN_IF_ERROR(nested_type->get_serde()->from_fe_string(field.initial_default_value, value)); |
781 | 3 | *column = type->create_column_const(rows, value); |
782 | 3 | return Status::OK(); |
783 | 3 | } _ZNK5doris18IcebergReaderMixinINS_13ParquetReaderEE35_build_owned_initial_default_columnERKNS_6schema8external6TFieldERKSt10shared_ptrIKNS_9IDataTypeEEmPNS_3COWINS_7IColumnEE13immutable_ptrISF_EE Line | Count | Source | 753 | 5 | ColumnPtr* column) const { | 754 | 5 | DORIS_CHECK(type != nullptr); | 755 | 5 | DORIS_CHECK(column != nullptr); | 756 | 5 | DORIS_CHECK(field.__isset.initial_default_value); | 757 | 5 | const auto nested_type = remove_nullable(type); | 758 | 5 | const bool is_base64 = | 759 | 5 | (field.__isset.initial_default_value_is_base64 && | 760 | 5 | field.initial_default_value_is_base64) || | 761 | 5 | (field.__isset.type && thrift_to_type(field.type.type) == TYPE_VARBINARY); | 762 | 5 | Field value; | 763 | 5 | if (is_base64) { | 764 | 3 | std::string decoded; | 765 | 3 | if (!base64_decode(field.initial_default_value, &decoded)) { | 766 | 0 | return Status::InvalidArgument("Invalid Base64 Iceberg initial default for field {}", | 767 | 0 | field.name); | 768 | 0 | } | 769 | 3 | if (nested_type->get_primitive_type() == TYPE_VARBINARY) { | 770 | 2 | value = Field::create_field<TYPE_VARBINARY>(StringView(decoded)); | 771 | 2 | } else { | 772 | 1 | DORIS_CHECK(is_string_type(nested_type->get_primitive_type())); | 773 | 1 | value = Field::create_field<TYPE_STRING>(decoded); | 774 | 1 | } | 775 | | // Variable-width Fields borrow decoded. Materialize before it leaves scope so every V1 | 776 | | // missing-column and equality-delete boundary keeps UUID/FIXED payloads alive. | 777 | 3 | *column = type->create_column_const(rows, value); | 778 | 3 | return Status::OK(); | 779 | 3 | } | 780 | 2 | RETURN_IF_ERROR(nested_type->get_serde()->from_fe_string(field.initial_default_value, value)); | 781 | 2 | *column = type->create_column_const(rows, value); | 782 | 2 | return Status::OK(); | 783 | 2 | } |
_ZNK5doris18IcebergReaderMixinINS_9OrcReaderEE35_build_owned_initial_default_columnERKNS_6schema8external6TFieldERKSt10shared_ptrIKNS_9IDataTypeEEmPNS_3COWINS_7IColumnEE13immutable_ptrISF_EE Line | Count | Source | 753 | 1 | ColumnPtr* column) const { | 754 | 1 | DORIS_CHECK(type != nullptr); | 755 | 1 | DORIS_CHECK(column != nullptr); | 756 | 1 | DORIS_CHECK(field.__isset.initial_default_value); | 757 | 1 | const auto nested_type = remove_nullable(type); | 758 | 1 | const bool is_base64 = | 759 | 1 | (field.__isset.initial_default_value_is_base64 && | 760 | 1 | field.initial_default_value_is_base64) || | 761 | 1 | (field.__isset.type && thrift_to_type(field.type.type) == TYPE_VARBINARY); | 762 | 1 | Field value; | 763 | 1 | if (is_base64) { | 764 | 0 | std::string decoded; | 765 | 0 | if (!base64_decode(field.initial_default_value, &decoded)) { | 766 | 0 | return Status::InvalidArgument("Invalid Base64 Iceberg initial default for field {}", | 767 | 0 | field.name); | 768 | 0 | } | 769 | 0 | if (nested_type->get_primitive_type() == TYPE_VARBINARY) { | 770 | 0 | value = Field::create_field<TYPE_VARBINARY>(StringView(decoded)); | 771 | 0 | } else { | 772 | 0 | DORIS_CHECK(is_string_type(nested_type->get_primitive_type())); | 773 | 0 | value = Field::create_field<TYPE_STRING>(decoded); | 774 | 0 | } | 775 | | // Variable-width Fields borrow decoded. Materialize before it leaves scope so every V1 | 776 | | // missing-column and equality-delete boundary keeps UUID/FIXED payloads alive. | 777 | 0 | *column = type->create_column_const(rows, value); | 778 | 0 | return Status::OK(); | 779 | 0 | } | 780 | 1 | RETURN_IF_ERROR(nested_type->get_serde()->from_fe_string(field.initial_default_value, value)); | 781 | 1 | *column = type->create_column_const(rows, value); | 782 | 1 | return Status::OK(); | 783 | 1 | } |
|
784 | | |
785 | | template <typename BaseReader> |
786 | | Status IcebergReaderMixin<BaseReader>::_register_missing_equality_delete_column( |
787 | 6 | int32_t field_id, const std::string& name, const DataTypePtr& delete_key_type) { |
788 | 6 | DORIS_CHECK(delete_key_type != nullptr); |
789 | 6 | const schema::external::TField* table_field = nullptr; |
790 | 6 | const auto& scan_params = this->get_scan_params(); |
791 | 6 | const schema::external::TSchema* current_schema = nullptr; |
792 | 6 | if (scan_params.__isset.history_schema_info && !scan_params.history_schema_info.empty()) { |
793 | 6 | current_schema = &scan_params.history_schema_info.front(); |
794 | 6 | } |
795 | 6 | if (current_schema != nullptr && scan_params.__isset.current_schema_id) { |
796 | 6 | const auto schema_it = std::ranges::find_if( |
797 | 6 | scan_params.history_schema_info, [&](const schema::external::TSchema& schema) { |
798 | 6 | return schema.__isset.schema_id && |
799 | 6 | schema.schema_id == scan_params.current_schema_id; |
800 | 6 | }); _ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEEENKUlRKNS_6schema8external7TSchemaEE_clESL_ Line | Count | Source | 797 | 5 | scan_params.history_schema_info, [&](const schema::external::TSchema& schema) { | 798 | 5 | return schema.__isset.schema_id && | 799 | 5 | schema.schema_id == scan_params.current_schema_id; | 800 | 5 | }); |
_ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEEENKUlRKNS_6schema8external7TSchemaEE_clESL_ Line | Count | Source | 797 | 1 | scan_params.history_schema_info, [&](const schema::external::TSchema& schema) { | 798 | 1 | return schema.__isset.schema_id && | 799 | 1 | schema.schema_id == scan_params.current_schema_id; | 800 | 1 | }); |
|
801 | 6 | if (schema_it != scan_params.history_schema_info.end()) { |
802 | 6 | current_schema = &*schema_it; |
803 | 6 | } else { |
804 | 0 | current_schema = nullptr; |
805 | 0 | } |
806 | 6 | } |
807 | 6 | if (current_schema != nullptr && current_schema->__isset.root_field) { |
808 | 11 | for (const auto& field_ptr : current_schema->root_field.fields) { |
809 | 11 | if (field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr && |
810 | 11 | field_ptr.field_ptr->__isset.id && field_ptr.field_ptr->id == field_id) { |
811 | 5 | table_field = field_ptr.field_ptr.get(); |
812 | 5 | break; |
813 | 5 | } |
814 | 11 | } |
815 | 6 | } |
816 | 6 | if (table_field == nullptr) { |
817 | | // A projected descriptor from an older FE may omit a hidden equality key. Without the |
818 | | // current Iceberg field metadata BE cannot distinguish a true NULL initial default from a |
819 | | // non-NULL default, so continuing would risk silently keeping or deleting wrong rows. |
820 | 1 | return Status::InternalError( |
821 | 1 | "Missing Iceberg schema metadata for equality-delete field id {}", field_id); |
822 | 1 | } |
823 | | |
824 | 5 | ColumnPtr value_column; |
825 | 5 | if (table_field->__isset.initial_default_value) { |
826 | 5 | RETURN_IF_ERROR(_build_owned_initial_default_column(*table_field, delete_key_type, 1, |
827 | 5 | &value_column)); |
828 | 5 | } else { |
829 | 0 | value_column = delete_key_type->create_column_const(1, Field()); |
830 | 0 | } |
831 | 5 | const bool inserted = |
832 | 5 | _missing_equality_delete_values.emplace(name, std::move(value_column)).second; |
833 | 5 | DORIS_CHECK(inserted); |
834 | 5 | this->register_synthesized_column_handler( |
835 | 5 | name, [this, name](Block* block, size_t rows) -> Status { |
836 | 1 | DORIS_CHECK(_missing_equality_delete_values.contains(name)); |
837 | 1 | return _materialize_missing_equality_delete_column( |
838 | 1 | block, name, _missing_equality_delete_values.at(name), rows); |
839 | 1 | }); Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEEENKUlPNS_5BlockEmE_clESI_m _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEEENKUlPNS_5BlockEmE_clESI_m Line | Count | Source | 835 | 1 | name, [this, name](Block* block, size_t rows) -> Status { | 836 | 1 | DORIS_CHECK(_missing_equality_delete_values.contains(name)); | 837 | 1 | return _materialize_missing_equality_delete_column( | 838 | 1 | block, name, _missing_equality_delete_values.at(name), rows); | 839 | 1 | }); |
|
840 | 5 | return Status::OK(); |
841 | 5 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEE Line | Count | Source | 787 | 5 | int32_t field_id, const std::string& name, const DataTypePtr& delete_key_type) { | 788 | 5 | DORIS_CHECK(delete_key_type != nullptr); | 789 | 5 | const schema::external::TField* table_field = nullptr; | 790 | 5 | const auto& scan_params = this->get_scan_params(); | 791 | 5 | const schema::external::TSchema* current_schema = nullptr; | 792 | 5 | if (scan_params.__isset.history_schema_info && !scan_params.history_schema_info.empty()) { | 793 | 5 | current_schema = &scan_params.history_schema_info.front(); | 794 | 5 | } | 795 | 5 | if (current_schema != nullptr && scan_params.__isset.current_schema_id) { | 796 | 5 | const auto schema_it = std::ranges::find_if( | 797 | 5 | scan_params.history_schema_info, [&](const schema::external::TSchema& schema) { | 798 | 5 | return schema.__isset.schema_id && | 799 | 5 | schema.schema_id == scan_params.current_schema_id; | 800 | 5 | }); | 801 | 5 | if (schema_it != scan_params.history_schema_info.end()) { | 802 | 5 | current_schema = &*schema_it; | 803 | 5 | } else { | 804 | 0 | current_schema = nullptr; | 805 | 0 | } | 806 | 5 | } | 807 | 5 | if (current_schema != nullptr && current_schema->__isset.root_field) { | 808 | 9 | for (const auto& field_ptr : current_schema->root_field.fields) { | 809 | 9 | if (field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr && | 810 | 9 | field_ptr.field_ptr->__isset.id && field_ptr.field_ptr->id == field_id) { | 811 | 4 | table_field = field_ptr.field_ptr.get(); | 812 | 4 | break; | 813 | 4 | } | 814 | 9 | } | 815 | 5 | } | 816 | 5 | if (table_field == nullptr) { | 817 | | // A projected descriptor from an older FE may omit a hidden equality key. Without the | 818 | | // current Iceberg field metadata BE cannot distinguish a true NULL initial default from a | 819 | | // non-NULL default, so continuing would risk silently keeping or deleting wrong rows. | 820 | 1 | return Status::InternalError( | 821 | 1 | "Missing Iceberg schema metadata for equality-delete field id {}", field_id); | 822 | 1 | } | 823 | | | 824 | 4 | ColumnPtr value_column; | 825 | 4 | if (table_field->__isset.initial_default_value) { | 826 | 4 | RETURN_IF_ERROR(_build_owned_initial_default_column(*table_field, delete_key_type, 1, | 827 | 4 | &value_column)); | 828 | 4 | } else { | 829 | 0 | value_column = delete_key_type->create_column_const(1, Field()); | 830 | 0 | } | 831 | 4 | const bool inserted = | 832 | 4 | _missing_equality_delete_values.emplace(name, std::move(value_column)).second; | 833 | 4 | DORIS_CHECK(inserted); | 834 | 4 | this->register_synthesized_column_handler( | 835 | 4 | name, [this, name](Block* block, size_t rows) -> Status { | 836 | 4 | DORIS_CHECK(_missing_equality_delete_values.contains(name)); | 837 | 4 | return _materialize_missing_equality_delete_column( | 838 | 4 | block, name, _missing_equality_delete_values.at(name), rows); | 839 | 4 | }); | 840 | 4 | return Status::OK(); | 841 | 4 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE40_register_missing_equality_delete_columnEiRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt10shared_ptrIKNS_9IDataTypeEE Line | Count | Source | 787 | 1 | int32_t field_id, const std::string& name, const DataTypePtr& delete_key_type) { | 788 | 1 | DORIS_CHECK(delete_key_type != nullptr); | 789 | 1 | const schema::external::TField* table_field = nullptr; | 790 | 1 | const auto& scan_params = this->get_scan_params(); | 791 | 1 | const schema::external::TSchema* current_schema = nullptr; | 792 | 1 | if (scan_params.__isset.history_schema_info && !scan_params.history_schema_info.empty()) { | 793 | 1 | current_schema = &scan_params.history_schema_info.front(); | 794 | 1 | } | 795 | 1 | if (current_schema != nullptr && scan_params.__isset.current_schema_id) { | 796 | 1 | const auto schema_it = std::ranges::find_if( | 797 | 1 | scan_params.history_schema_info, [&](const schema::external::TSchema& schema) { | 798 | 1 | return schema.__isset.schema_id && | 799 | 1 | schema.schema_id == scan_params.current_schema_id; | 800 | 1 | }); | 801 | 1 | if (schema_it != scan_params.history_schema_info.end()) { | 802 | 1 | current_schema = &*schema_it; | 803 | 1 | } else { | 804 | 0 | current_schema = nullptr; | 805 | 0 | } | 806 | 1 | } | 807 | 1 | if (current_schema != nullptr && current_schema->__isset.root_field) { | 808 | 2 | for (const auto& field_ptr : current_schema->root_field.fields) { | 809 | 2 | if (field_ptr.__isset.field_ptr && field_ptr.field_ptr != nullptr && | 810 | 2 | field_ptr.field_ptr->__isset.id && field_ptr.field_ptr->id == field_id) { | 811 | 1 | table_field = field_ptr.field_ptr.get(); | 812 | 1 | break; | 813 | 1 | } | 814 | 2 | } | 815 | 1 | } | 816 | 1 | if (table_field == nullptr) { | 817 | | // A projected descriptor from an older FE may omit a hidden equality key. Without the | 818 | | // current Iceberg field metadata BE cannot distinguish a true NULL initial default from a | 819 | | // non-NULL default, so continuing would risk silently keeping or deleting wrong rows. | 820 | 0 | return Status::InternalError( | 821 | 0 | "Missing Iceberg schema metadata for equality-delete field id {}", field_id); | 822 | 0 | } | 823 | | | 824 | 1 | ColumnPtr value_column; | 825 | 1 | if (table_field->__isset.initial_default_value) { | 826 | 1 | RETURN_IF_ERROR(_build_owned_initial_default_column(*table_field, delete_key_type, 1, | 827 | 1 | &value_column)); | 828 | 1 | } else { | 829 | 0 | value_column = delete_key_type->create_column_const(1, Field()); | 830 | 0 | } | 831 | 1 | const bool inserted = | 832 | 1 | _missing_equality_delete_values.emplace(name, std::move(value_column)).second; | 833 | 1 | DORIS_CHECK(inserted); | 834 | 1 | this->register_synthesized_column_handler( | 835 | 1 | name, [this, name](Block* block, size_t rows) -> Status { | 836 | 1 | DORIS_CHECK(_missing_equality_delete_values.contains(name)); | 837 | 1 | return _materialize_missing_equality_delete_column( | 838 | 1 | block, name, _missing_equality_delete_values.at(name), rows); | 839 | 1 | }); | 840 | 1 | return Status::OK(); | 841 | 1 | } |
|
842 | | |
843 | | template <typename BaseReader> |
844 | | Status IcebergReaderMixin<BaseReader>::_materialize_missing_equality_delete_column( |
845 | 5 | Block* block, const std::string& name, const ColumnPtr& value, size_t rows) { |
846 | 5 | if (!this->col_name_to_block_idx_ref()->contains(name)) { |
847 | | // ORC must not register a key that is absent from the file as a physical child. In that |
848 | | // case the reader block has no slot for the synthesized key, so append one here before |
849 | | // equality-delete filtering. MultiEqualityDelete requires a full, batch-sized column. |
850 | 1 | const auto expand_col = std::ranges::find_if( |
851 | 1 | _expand_columns, |
852 | 1 | [&](const ColumnWithTypeAndName& col) { return col.name == name; });Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEmENKUlRKNS_21ColumnWithTypeAndNameEE_clESM_ _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEmENKUlRKNS_21ColumnWithTypeAndNameEE_clESM_ Line | Count | Source | 852 | 1 | [&](const ColumnWithTypeAndName& col) { return col.name == name; }); |
|
853 | 1 | DORIS_CHECK(expand_col != _expand_columns.end()); |
854 | 1 | (*this->col_name_to_block_idx_ref())[name] = block->columns(); |
855 | 1 | block->insert({value->clone_resized(rows)->convert_to_full_column_if_const(), |
856 | 1 | expand_col->type, name}); |
857 | 1 | return Status::OK(); |
858 | 1 | } |
859 | 4 | const auto position = this->col_name_to_block_idx_ref()->at(name); |
860 | 4 | DORIS_CHECK(position < block->columns()); |
861 | 4 | DORIS_CHECK(block->get_by_position(position).column->empty()); |
862 | | // MultiEqualityDelete hashes each key column directly. Materialize the repeated default so |
863 | | // every key has the batch row count; a ColumnConst keeps only one nested value and therefore |
864 | | // cannot participate in the row-wise multi-column hash contract. |
865 | 4 | block->get_by_position(position).column = |
866 | 4 | value->clone_resized(rows)->convert_to_full_column_if_const(); |
867 | 4 | return Status::OK(); |
868 | 5 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEm Line | Count | Source | 845 | 4 | Block* block, const std::string& name, const ColumnPtr& value, size_t rows) { | 846 | 4 | if (!this->col_name_to_block_idx_ref()->contains(name)) { | 847 | | // ORC must not register a key that is absent from the file as a physical child. In that | 848 | | // case the reader block has no slot for the synthesized key, so append one here before | 849 | | // equality-delete filtering. MultiEqualityDelete requires a full, batch-sized column. | 850 | 0 | const auto expand_col = std::ranges::find_if( | 851 | 0 | _expand_columns, | 852 | 0 | [&](const ColumnWithTypeAndName& col) { return col.name == name; }); | 853 | 0 | DORIS_CHECK(expand_col != _expand_columns.end()); | 854 | 0 | (*this->col_name_to_block_idx_ref())[name] = block->columns(); | 855 | 0 | block->insert({value->clone_resized(rows)->convert_to_full_column_if_const(), | 856 | 0 | expand_col->type, name}); | 857 | 0 | return Status::OK(); | 858 | 0 | } | 859 | 4 | const auto position = this->col_name_to_block_idx_ref()->at(name); | 860 | 4 | DORIS_CHECK(position < block->columns()); | 861 | 4 | DORIS_CHECK(block->get_by_position(position).column->empty()); | 862 | | // MultiEqualityDelete hashes each key column directly. Materialize the repeated default so | 863 | | // every key has the batch row count; a ColumnConst keeps only one nested value and therefore | 864 | | // cannot participate in the row-wise multi-column hash contract. | 865 | 4 | block->get_by_position(position).column = | 866 | 4 | value->clone_resized(rows)->convert_to_full_column_if_const(); | 867 | 4 | return Status::OK(); | 868 | 4 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE43_materialize_missing_equality_delete_columnEPNS_5BlockERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_3COWINS_7IColumnEE13immutable_ptrISE_EEm Line | Count | Source | 845 | 1 | Block* block, const std::string& name, const ColumnPtr& value, size_t rows) { | 846 | 1 | if (!this->col_name_to_block_idx_ref()->contains(name)) { | 847 | | // ORC must not register a key that is absent from the file as a physical child. In that | 848 | | // case the reader block has no slot for the synthesized key, so append one here before | 849 | | // equality-delete filtering. MultiEqualityDelete requires a full, batch-sized column. | 850 | 1 | const auto expand_col = std::ranges::find_if( | 851 | 1 | _expand_columns, | 852 | 1 | [&](const ColumnWithTypeAndName& col) { return col.name == name; }); | 853 | 1 | DORIS_CHECK(expand_col != _expand_columns.end()); | 854 | 1 | (*this->col_name_to_block_idx_ref())[name] = block->columns(); | 855 | 1 | block->insert({value->clone_resized(rows)->convert_to_full_column_if_const(), | 856 | 1 | expand_col->type, name}); | 857 | 1 | return Status::OK(); | 858 | 1 | } | 859 | 0 | const auto position = this->col_name_to_block_idx_ref()->at(name); | 860 | 0 | DORIS_CHECK(position < block->columns()); | 861 | 0 | DORIS_CHECK(block->get_by_position(position).column->empty()); | 862 | | // MultiEqualityDelete hashes each key column directly. Materialize the repeated default so | 863 | | // every key has the batch row count; a ColumnConst keeps only one nested value and therefore | 864 | | // cannot participate in the row-wise multi-column hash contract. | 865 | 0 | block->get_by_position(position).column = | 866 | 0 | value->clone_resized(rows)->convert_to_full_column_if_const(); | 867 | 0 | return Status::OK(); | 868 | 1 | } |
|
869 | | |
870 | | template <typename BaseReader> |
871 | | Status IcebergReaderMixin<BaseReader>::_materialize_missing_equality_delete_columns(Block* block, |
872 | 2 | size_t rows) { |
873 | 4 | for (const auto& [name, value] : _missing_equality_delete_values) { |
874 | 4 | RETURN_IF_ERROR(_materialize_missing_equality_delete_column(block, name, value, rows)); |
875 | 4 | } |
876 | 2 | return Status::OK(); |
877 | 2 | } |
878 | | |
879 | | template <typename BaseReader> |
880 | 9 | Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) { |
881 | 9 | std::set<size_t> positions_to_erase; |
882 | 9 | for (const std::string& expand_col : _expand_col_names) { |
883 | 4 | if (!this->col_name_to_block_idx_ref()->contains(expand_col)) { |
884 | 0 | return Status::InternalError("Wrong erase column '{}', block: {}", expand_col, |
885 | 0 | block->dump_names()); |
886 | 0 | } |
887 | 4 | positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]); |
888 | 4 | } |
889 | 9 | block->erase(positions_to_erase); |
890 | 9 | for (const std::string& expand_col : _expand_col_names) { |
891 | 4 | this->col_name_to_block_idx_ref()->erase(expand_col); |
892 | 4 | } |
893 | 9 | return Status::OK(); |
894 | 9 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_shrink_block_if_needEPNS_5BlockE Line | Count | Source | 880 | 5 | Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) { | 881 | 5 | std::set<size_t> positions_to_erase; | 882 | 5 | for (const std::string& expand_col : _expand_col_names) { | 883 | 2 | if (!this->col_name_to_block_idx_ref()->contains(expand_col)) { | 884 | 0 | return Status::InternalError("Wrong erase column '{}', block: {}", expand_col, | 885 | 0 | block->dump_names()); | 886 | 0 | } | 887 | 2 | positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]); | 888 | 2 | } | 889 | 5 | block->erase(positions_to_erase); | 890 | 5 | for (const std::string& expand_col : _expand_col_names) { | 891 | 2 | this->col_name_to_block_idx_ref()->erase(expand_col); | 892 | 2 | } | 893 | 5 | return Status::OK(); | 894 | 5 | } |
_ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_shrink_block_if_needEPNS_5BlockE Line | Count | Source | 880 | 4 | Status IcebergReaderMixin<BaseReader>::_shrink_block_if_need(Block* block) { | 881 | 4 | std::set<size_t> positions_to_erase; | 882 | 4 | for (const std::string& expand_col : _expand_col_names) { | 883 | 2 | if (!this->col_name_to_block_idx_ref()->contains(expand_col)) { | 884 | 0 | return Status::InternalError("Wrong erase column '{}', block: {}", expand_col, | 885 | 0 | block->dump_names()); | 886 | 0 | } | 887 | 2 | positions_to_erase.emplace((*this->col_name_to_block_idx_ref())[expand_col]); | 888 | 2 | } | 889 | 4 | block->erase(positions_to_erase); | 890 | 4 | for (const std::string& expand_col : _expand_col_names) { | 891 | 2 | this->col_name_to_block_idx_ref()->erase(expand_col); | 892 | 2 | } | 893 | 4 | return Status::OK(); | 894 | 4 | } |
|
895 | | |
896 | | template <typename BaseReader> |
897 | | Status IcebergReaderMixin<BaseReader>::_position_delete_base( |
898 | 1 | const std::string data_file_path, const std::vector<TIcebergDeleteFileDesc>& delete_files) { |
899 | 1 | std::vector<DeleteRows*> delete_rows_array; |
900 | 1 | int64_t num_delete_rows = 0; |
901 | 1 | for (const auto& delete_file : delete_files) { |
902 | 1 | SCOPED_TIMER(_iceberg_profile.delete_files_read_time); |
903 | 1 | Status create_status = Status::OK(); |
904 | 1 | auto* delete_file_cache = _kv_cache->template get<DeleteFile>( |
905 | 1 | _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* { |
906 | 1 | auto position_delete = std::make_unique<DeleteFile>(); |
907 | 1 | TFileRangeDesc delete_file_range; |
908 | 1 | delete_file_range.__set_fs_name(this->get_scan_range().fs_name); |
909 | 1 | delete_file_range.path = delete_file.path; |
910 | 1 | delete_file_range.start_offset = 0; |
911 | 1 | delete_file_range.size = -1; |
912 | 1 | delete_file_range.file_size = -1; |
913 | 1 | create_status = |
914 | 1 | _read_position_delete_file(&delete_file_range, position_delete.get()); |
915 | 1 | if (!create_status) { |
916 | 1 | return nullptr; |
917 | 1 | } |
918 | 0 | return position_delete.release(); |
919 | 1 | }); _ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE_clB5cxx11Ev Line | Count | Source | 905 | 1 | _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* { | 906 | 1 | auto position_delete = std::make_unique<DeleteFile>(); | 907 | 1 | TFileRangeDesc delete_file_range; | 908 | 1 | delete_file_range.__set_fs_name(this->get_scan_range().fs_name); | 909 | 1 | delete_file_range.path = delete_file.path; | 910 | 1 | delete_file_range.start_offset = 0; | 911 | 1 | delete_file_range.size = -1; | 912 | 1 | delete_file_range.file_size = -1; | 913 | 1 | create_status = | 914 | 1 | _read_position_delete_file(&delete_file_range, position_delete.get()); | 915 | 1 | if (!create_status) { | 916 | 1 | return nullptr; | 917 | 1 | } | 918 | 0 | return position_delete.release(); | 919 | 1 | }); |
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EEENKUlvE_clB5cxx11Ev |
920 | 1 | if (create_status.is<ErrorCode::END_OF_FILE>()) { |
921 | 0 | continue; |
922 | 1 | } else if (!create_status.ok()) { |
923 | 1 | return create_status; |
924 | 1 | } |
925 | | |
926 | 0 | DeleteFile& delete_file_map = *((DeleteFile*)delete_file_cache); |
927 | 0 | auto get_value = [&](const auto& v) { |
928 | 0 | DeleteRows* row_ids = v.second.get(); |
929 | 0 | if (!row_ids->empty()) { |
930 | 0 | delete_rows_array.emplace_back(row_ids); |
931 | 0 | num_delete_rows += row_ids->size(); |
932 | 0 | } |
933 | 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_ |
934 | 0 | delete_file_map.if_contains(data_file_path, get_value); |
935 | 0 | } |
936 | 0 | if (num_delete_rows > 0) { |
937 | 0 | SCOPED_TIMER(_iceberg_profile.delete_rows_sort_time); |
938 | 0 | _iceberg_delete_rows = |
939 | 0 | _kv_cache->template get<DeleteRows>(data_file_path, [&]() -> DeleteRows* { |
940 | 0 | auto data_file_position_delete = std::make_unique<DeleteRows>(); |
941 | 0 | _sort_delete_rows(delete_rows_array, num_delete_rows, |
942 | 0 | *data_file_position_delete); |
943 | 0 | return data_file_position_delete.release(); |
944 | 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 |
945 | 0 | set_delete_rows(); |
946 | 0 | COUNTER_UPDATE(_iceberg_profile.num_delete_rows, num_delete_rows); |
947 | 0 | } |
948 | 0 | return Status::OK(); |
949 | 1 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EE Line | Count | Source | 898 | 1 | const std::string data_file_path, const std::vector<TIcebergDeleteFileDesc>& delete_files) { | 899 | 1 | std::vector<DeleteRows*> delete_rows_array; | 900 | 1 | int64_t num_delete_rows = 0; | 901 | 1 | for (const auto& delete_file : delete_files) { | 902 | 1 | SCOPED_TIMER(_iceberg_profile.delete_files_read_time); | 903 | 1 | Status create_status = Status::OK(); | 904 | 1 | auto* delete_file_cache = _kv_cache->template get<DeleteFile>( | 905 | 1 | _delet_file_cache_key(delete_file.path), [&]() -> DeleteFile* { | 906 | 1 | auto position_delete = std::make_unique<DeleteFile>(); | 907 | 1 | TFileRangeDesc delete_file_range; | 908 | 1 | delete_file_range.__set_fs_name(this->get_scan_range().fs_name); | 909 | 1 | delete_file_range.path = delete_file.path; | 910 | 1 | delete_file_range.start_offset = 0; | 911 | 1 | delete_file_range.size = -1; | 912 | 1 | delete_file_range.file_size = -1; | 913 | 1 | create_status = | 914 | 1 | _read_position_delete_file(&delete_file_range, position_delete.get()); | 915 | 1 | if (!create_status) { | 916 | 1 | return nullptr; | 917 | 1 | } | 918 | 1 | return position_delete.release(); | 919 | 1 | }); | 920 | 1 | if (create_status.is<ErrorCode::END_OF_FILE>()) { | 921 | 0 | continue; | 922 | 1 | } else if (!create_status.ok()) { | 923 | 1 | return create_status; | 924 | 1 | } | 925 | | | 926 | 0 | DeleteFile& delete_file_map = *((DeleteFile*)delete_file_cache); | 927 | 0 | auto get_value = [&](const auto& v) { | 928 | 0 | DeleteRows* row_ids = v.second.get(); | 929 | 0 | if (!row_ids->empty()) { | 930 | 0 | delete_rows_array.emplace_back(row_ids); | 931 | 0 | num_delete_rows += row_ids->size(); | 932 | 0 | } | 933 | 0 | }; | 934 | 0 | delete_file_map.if_contains(data_file_path, get_value); | 935 | 0 | } | 936 | 0 | if (num_delete_rows > 0) { | 937 | 0 | SCOPED_TIMER(_iceberg_profile.delete_rows_sort_time); | 938 | 0 | _iceberg_delete_rows = | 939 | 0 | _kv_cache->template get<DeleteRows>(data_file_path, [&]() -> DeleteRows* { | 940 | 0 | auto data_file_position_delete = std::make_unique<DeleteRows>(); | 941 | 0 | _sort_delete_rows(delete_rows_array, num_delete_rows, | 942 | 0 | *data_file_position_delete); | 943 | 0 | return data_file_position_delete.release(); | 944 | 0 | }); | 945 | 0 | set_delete_rows(); | 946 | 0 | COUNTER_UPDATE(_iceberg_profile.num_delete_rows, num_delete_rows); | 947 | 0 | } | 948 | 0 | return Status::OK(); | 949 | 1 | } |
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE21_position_delete_baseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorINS_22TIcebergDeleteFileDescESaISA_EE |
950 | | |
951 | | template <typename BaseReader> |
952 | | typename IcebergReaderMixin<BaseReader>::PositionDeleteRange |
953 | 0 | IcebergReaderMixin<BaseReader>::_get_range(const ColumnDictI32& file_path_column) { |
954 | 0 | PositionDeleteRange range; |
955 | 0 | size_t read_rows = file_path_column.get_data().size(); |
956 | 0 | const int* code_path = file_path_column.get_data().data(); |
957 | 0 | const int* code_path_start = code_path; |
958 | 0 | const int* code_path_end = code_path + read_rows; |
959 | 0 | while (code_path < code_path_end) { |
960 | 0 | int code = code_path[0]; |
961 | 0 | const int* code_end = std::upper_bound(code_path, code_path_end, code); |
962 | 0 | range.data_file_path.emplace_back(file_path_column.get_value(code).to_string()); |
963 | 0 | range.range.emplace_back(code_path - code_path_start, code_end - code_path_start); |
964 | 0 | code_path = code_end; |
965 | 0 | } |
966 | 0 | return range; |
967 | 0 | } Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE10_get_rangeERKNS_13ColumnDictI32E Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE10_get_rangeERKNS_13ColumnDictI32E |
968 | | |
969 | | template <typename BaseReader> |
970 | | typename IcebergReaderMixin<BaseReader>::PositionDeleteRange |
971 | 0 | IcebergReaderMixin<BaseReader>::_get_range(const ColumnString& file_path_column) { |
972 | 0 | PositionDeleteRange range; |
973 | 0 | size_t read_rows = file_path_column.size(); |
974 | 0 | size_t index = 0; |
975 | 0 | while (index < read_rows) { |
976 | 0 | StringRef data_path = file_path_column.get_data_at(index); |
977 | 0 | size_t left = index - 1; |
978 | 0 | size_t right = read_rows; |
979 | 0 | while (left + 1 != right) { |
980 | 0 | size_t mid = left + (right - left) / 2; |
981 | 0 | if (file_path_column.get_data_at(mid) > data_path) { |
982 | 0 | right = mid; |
983 | 0 | } else { |
984 | 0 | left = mid; |
985 | 0 | } |
986 | 0 | } |
987 | 0 | range.data_file_path.emplace_back(data_path.to_string()); |
988 | 0 | range.range.emplace_back(index, left + 1); |
989 | 0 | index = left + 1; |
990 | 0 | } |
991 | 0 | return range; |
992 | 0 | } Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE10_get_rangeERKNS_9ColumnStrIjEE Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE10_get_rangeERKNS_9ColumnStrIjEE |
993 | | |
994 | | template <typename BaseReader> |
995 | | void IcebergReaderMixin<BaseReader>::_sort_delete_rows( |
996 | | const std::vector<std::vector<int64_t>*>& delete_rows_array, int64_t num_delete_rows, |
997 | 0 | std::vector<int64_t>& result) { |
998 | 0 | if (delete_rows_array.empty()) { |
999 | 0 | return; |
1000 | 0 | } |
1001 | 0 | if (delete_rows_array.size() == 1) { |
1002 | 0 | result.resize(num_delete_rows); |
1003 | 0 | memcpy(result.data(), delete_rows_array.front()->data(), sizeof(int64_t) * num_delete_rows); |
1004 | 0 | return; |
1005 | 0 | } |
1006 | 0 | if (delete_rows_array.size() == 2) { |
1007 | 0 | result.resize(num_delete_rows); |
1008 | 0 | std::merge(delete_rows_array.front()->begin(), delete_rows_array.front()->end(), |
1009 | 0 | delete_rows_array.back()->begin(), delete_rows_array.back()->end(), |
1010 | 0 | result.begin()); |
1011 | 0 | return; |
1012 | 0 | } |
1013 | | |
1014 | 0 | using vec_pair = std::pair<std::vector<int64_t>::iterator, std::vector<int64_t>::iterator>; |
1015 | 0 | result.resize(num_delete_rows); |
1016 | 0 | auto row_id_iter = result.begin(); |
1017 | 0 | auto iter_end = result.end(); |
1018 | 0 | std::vector<vec_pair> rows_array; |
1019 | 0 | for (auto* rows : delete_rows_array) { |
1020 | 0 | if (!rows->empty()) { |
1021 | 0 | rows_array.emplace_back(rows->begin(), rows->end()); |
1022 | 0 | } |
1023 | 0 | } |
1024 | 0 | size_t array_size = rows_array.size(); |
1025 | 0 | while (row_id_iter != iter_end) { |
1026 | 0 | int64_t min_index = 0; |
1027 | 0 | int64_t min = *rows_array[0].first; |
1028 | 0 | for (size_t i = 0; i < array_size; ++i) { |
1029 | 0 | if (*rows_array[i].first < min) { |
1030 | 0 | min_index = i; |
1031 | 0 | min = *rows_array[i].first; |
1032 | 0 | } |
1033 | 0 | } |
1034 | 0 | *row_id_iter++ = min; |
1035 | 0 | rows_array[min_index].first++; |
1036 | 0 | if (UNLIKELY(rows_array[min_index].first == rows_array[min_index].second)) { |
1037 | 0 | rows_array.erase(rows_array.begin() + min_index); |
1038 | 0 | array_size--; |
1039 | 0 | } |
1040 | 0 | } |
1041 | 0 | } Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE17_sort_delete_rowsERKSt6vectorIPS3_IlSaIlEESaIS6_EElRS5_ Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE17_sort_delete_rowsERKSt6vectorIPS3_IlSaIlEESaIS6_EElRS5_ |
1042 | | |
1043 | | template <typename BaseReader> |
1044 | | Status IcebergReaderMixin<BaseReader>::_gen_position_delete_file_range( |
1045 | | Block& block, DeleteFile* position_delete, size_t read_rows, |
1046 | 0 | bool file_path_column_dictionary_coded) { |
1047 | 0 | SCOPED_TIMER(_iceberg_profile.parse_delete_file_time); |
1048 | 0 | auto name_to_pos_map = block.get_name_to_pos_map(); |
1049 | 0 | ColumnPtr path_column = block.get_by_position(name_to_pos_map[ICEBERG_FILE_PATH]).column; |
1050 | 0 | DCHECK_EQ(path_column->size(), read_rows); |
1051 | 0 | ColumnPtr pos_column = block.get_by_position(name_to_pos_map[ICEBERG_ROW_POS]).column; |
1052 | 0 | if (const auto* nullable_col = check_and_get_column<ColumnNullable>(*path_column); |
1053 | 0 | nullable_col != nullptr) { |
1054 | 0 | if (nullable_col->has_null(0, read_rows)) { |
1055 | 0 | return Status::Corruption( |
1056 | 0 | "Iceberg position delete column file_path contains null values"); |
1057 | 0 | } |
1058 | 0 | path_column = remove_nullable(path_column); |
1059 | 0 | } |
1060 | 0 | if (const auto* nullable_col = check_and_get_column<ColumnNullable>(*pos_column); |
1061 | 0 | nullable_col != nullptr) { |
1062 | 0 | if (nullable_col->has_null(0, read_rows)) { |
1063 | 0 | return Status::Corruption("Iceberg position delete column pos contains null values"); |
1064 | 0 | } |
1065 | 0 | pos_column = remove_nullable(pos_column); |
1066 | 0 | } |
1067 | 0 | using ColumnType = typename PrimitiveTypeTraits<TYPE_BIGINT>::ColumnType; |
1068 | 0 | const int64_t* src_data = assert_cast<const ColumnType&>(*pos_column).get_data().data(); |
1069 | 0 | PositionDeleteRange range; |
1070 | 0 | if (file_path_column_dictionary_coded) { |
1071 | 0 | range = _get_range(assert_cast<const ColumnDictI32&>(*path_column)); |
1072 | 0 | } else { |
1073 | 0 | range = _get_range(assert_cast<const ColumnString&>(*path_column)); |
1074 | 0 | } |
1075 | 0 | for (int i = 0; i < range.range.size(); ++i) { |
1076 | 0 | std::string key = range.data_file_path[i]; |
1077 | 0 | auto iter = position_delete->find(key); |
1078 | 0 | DeleteRows* delete_rows; |
1079 | 0 | if (iter == position_delete->end()) { |
1080 | 0 | delete_rows = new DeleteRows; |
1081 | 0 | std::unique_ptr<DeleteRows> delete_rows_ptr(delete_rows); |
1082 | 0 | (*position_delete)[key] = std::move(delete_rows_ptr); |
1083 | 0 | } else { |
1084 | 0 | delete_rows = iter->second.get(); |
1085 | 0 | } |
1086 | 0 | const int64_t* cpy_start = src_data + range.range[i].first; |
1087 | 0 | const int64_t cpy_count = range.range[i].second - range.range[i].first; |
1088 | 0 | int64_t origin_size = delete_rows->size(); |
1089 | 0 | delete_rows->resize(origin_size + cpy_count); |
1090 | 0 | int64_t* dest_position = &(*delete_rows)[origin_size]; |
1091 | 0 | memcpy(dest_position, cpy_start, cpy_count * sizeof(int64_t)); |
1092 | 0 | } |
1093 | 0 | return Status::OK(); |
1094 | 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 |
1095 | | |
1096 | | template <typename BaseReader> |
1097 | | Status IcebergReaderMixin<BaseReader>::read_deletion_vector( |
1098 | 1 | const std::string& data_file_path, const TIcebergDeleteFileDesc& delete_file_desc) { |
1099 | 1 | size_t bytes_read = 0; |
1100 | 1 | RETURN_IF_ERROR(validate_iceberg_deletion_vector_descriptor(delete_file_desc, bytes_read)); |
1101 | | |
1102 | 1 | Status create_status = Status::OK(); |
1103 | 1 | SCOPED_TIMER(_iceberg_profile.delete_files_read_time); |
1104 | 1 | bool decoded_cache_hit = false; |
1105 | 1 | _iceberg_deletion_vector = _kv_cache->template get<DeletionVector>( |
1106 | 1 | build_iceberg_deletion_vector_cache_key(data_file_path, delete_file_desc), |
1107 | 1 | [&]() -> DeletionVector* { |
1108 | 1 | auto deletion_vector = std::make_unique<DeletionVector>(); |
1109 | | |
1110 | 1 | io::FileCacheStatistics file_cache_stats; |
1111 | 1 | IcebergDeleteFileReaderOptions options; |
1112 | 1 | options.state = this->get_state(); |
1113 | 1 | options.profile = this->get_profile(); |
1114 | 1 | options.scan_params = &this->get_scan_params(); |
1115 | 1 | options.io_ctx = this->get_io_ctx(); |
1116 | 1 | options.fs_name = &this->get_scan_range().fs_name; |
1117 | 1 | options.deletion_vector_file_cache_stats = &file_cache_stats; |
1118 | 1 | create_status = read_iceberg_deletion_vector(delete_file_desc, options, |
1119 | 1 | deletion_vector.get()); |
1120 | 1 | COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count, |
1121 | 1 | file_cache_stats.num_local_io_total); |
1122 | 1 | COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count, |
1123 | 1 | file_cache_stats.num_remote_io_total); |
1124 | 1 | COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count, |
1125 | 1 | file_cache_stats.num_peer_io_total); |
1126 | 1 | if (!create_status.ok()) [[unlikely]] { |
1127 | 1 | return nullptr; |
1128 | 1 | } |
1129 | | |
1130 | 0 | SCOPED_TIMER(_iceberg_profile.parse_delete_file_time); |
1131 | 0 | COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality()); |
1132 | 0 | return deletion_vector.release(); |
1133 | 1 | }, _ZZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescEENKUlvE_clEv Line | Count | Source | 1107 | 1 | [&]() -> DeletionVector* { | 1108 | 1 | auto deletion_vector = std::make_unique<DeletionVector>(); | 1109 | | | 1110 | 1 | io::FileCacheStatistics file_cache_stats; | 1111 | 1 | IcebergDeleteFileReaderOptions options; | 1112 | 1 | options.state = this->get_state(); | 1113 | 1 | options.profile = this->get_profile(); | 1114 | 1 | options.scan_params = &this->get_scan_params(); | 1115 | 1 | options.io_ctx = this->get_io_ctx(); | 1116 | 1 | options.fs_name = &this->get_scan_range().fs_name; | 1117 | 1 | options.deletion_vector_file_cache_stats = &file_cache_stats; | 1118 | 1 | create_status = read_iceberg_deletion_vector(delete_file_desc, options, | 1119 | 1 | deletion_vector.get()); | 1120 | 1 | COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count, | 1121 | 1 | file_cache_stats.num_local_io_total); | 1122 | 1 | COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count, | 1123 | 1 | file_cache_stats.num_remote_io_total); | 1124 | 1 | COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count, | 1125 | 1 | file_cache_stats.num_peer_io_total); | 1126 | 1 | if (!create_status.ok()) [[unlikely]] { | 1127 | 1 | return nullptr; | 1128 | 1 | } | 1129 | | | 1130 | 0 | SCOPED_TIMER(_iceberg_profile.parse_delete_file_time); | 1131 | 0 | COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality()); | 1132 | 0 | return deletion_vector.release(); | 1133 | 1 | }, |
Unexecuted instantiation: _ZZN5doris18IcebergReaderMixinINS_9OrcReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescEENKUlvE_clEv |
1134 | 1 | &decoded_cache_hit); |
1135 | | |
1136 | 1 | RETURN_IF_ERROR(create_status); |
1137 | 0 | COUNTER_UPDATE(decoded_cache_hit ? _iceberg_profile.decoded_cache_hit_count |
1138 | 0 | : _iceberg_profile.decoded_cache_miss_count, |
1139 | 0 | 1); |
1140 | 0 | if (!_iceberg_deletion_vector->isEmpty()) [[likely]] { |
1141 | 0 | set_deletion_vector(); |
1142 | 0 | } |
1143 | 0 | return Status::OK(); |
1144 | 1 | } _ZN5doris18IcebergReaderMixinINS_13ParquetReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescE Line | Count | Source | 1098 | 1 | const std::string& data_file_path, const TIcebergDeleteFileDesc& delete_file_desc) { | 1099 | 1 | size_t bytes_read = 0; | 1100 | 1 | RETURN_IF_ERROR(validate_iceberg_deletion_vector_descriptor(delete_file_desc, bytes_read)); | 1101 | | | 1102 | 1 | Status create_status = Status::OK(); | 1103 | 1 | SCOPED_TIMER(_iceberg_profile.delete_files_read_time); | 1104 | 1 | bool decoded_cache_hit = false; | 1105 | 1 | _iceberg_deletion_vector = _kv_cache->template get<DeletionVector>( | 1106 | 1 | build_iceberg_deletion_vector_cache_key(data_file_path, delete_file_desc), | 1107 | 1 | [&]() -> DeletionVector* { | 1108 | 1 | auto deletion_vector = std::make_unique<DeletionVector>(); | 1109 | | | 1110 | 1 | io::FileCacheStatistics file_cache_stats; | 1111 | 1 | IcebergDeleteFileReaderOptions options; | 1112 | 1 | options.state = this->get_state(); | 1113 | 1 | options.profile = this->get_profile(); | 1114 | 1 | options.scan_params = &this->get_scan_params(); | 1115 | 1 | options.io_ctx = this->get_io_ctx(); | 1116 | 1 | options.fs_name = &this->get_scan_range().fs_name; | 1117 | 1 | options.deletion_vector_file_cache_stats = &file_cache_stats; | 1118 | 1 | create_status = read_iceberg_deletion_vector(delete_file_desc, options, | 1119 | 1 | deletion_vector.get()); | 1120 | 1 | COUNTER_UPDATE(_iceberg_profile.file_cache_hit_count, | 1121 | 1 | file_cache_stats.num_local_io_total); | 1122 | 1 | COUNTER_UPDATE(_iceberg_profile.file_cache_miss_count, | 1123 | 1 | file_cache_stats.num_remote_io_total); | 1124 | 1 | COUNTER_UPDATE(_iceberg_profile.file_cache_peer_read_count, | 1125 | 1 | file_cache_stats.num_peer_io_total); | 1126 | 1 | if (!create_status.ok()) [[unlikely]] { | 1127 | 1 | return nullptr; | 1128 | 1 | } | 1129 | | | 1130 | 1 | SCOPED_TIMER(_iceberg_profile.parse_delete_file_time); | 1131 | 1 | COUNTER_UPDATE(_iceberg_profile.num_delete_rows, deletion_vector->cardinality()); | 1132 | 1 | return deletion_vector.release(); | 1133 | 1 | }, | 1134 | 1 | &decoded_cache_hit); | 1135 | | | 1136 | 1 | RETURN_IF_ERROR(create_status); | 1137 | 0 | COUNTER_UPDATE(decoded_cache_hit ? _iceberg_profile.decoded_cache_hit_count | 1138 | 0 | : _iceberg_profile.decoded_cache_miss_count, | 1139 | 0 | 1); | 1140 | 0 | if (!_iceberg_deletion_vector->isEmpty()) [[likely]] { | 1141 | 0 | set_deletion_vector(); | 1142 | 0 | } | 1143 | 0 | return Status::OK(); | 1144 | 1 | } |
Unexecuted instantiation: _ZN5doris18IcebergReaderMixinINS_9OrcReaderEE20read_deletion_vectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_22TIcebergDeleteFileDescE |
1145 | | |
1146 | | } // namespace doris |