Coverage Report

Created: 2026-07-12 00:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/format/table/paimon_reader.cpp
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
#include "format/table/paimon_reader.h"
19
20
#include <fmt/format.h>
21
22
#include <cstring>
23
#include <memory>
24
#include <utility>
25
#include <vector>
26
27
#include "common/status.h"
28
#include "exec/common/endian.h"
29
#include "format/table/deletion_vector_reader.h"
30
#include "runtime/runtime_state.h"
31
32
namespace doris {
33
34
namespace {
35
36
constexpr static char PAIMON_BITMAP_MAGIC[] = {'\x5E', '\x43', '\xF2', '\xD0'};
37
38
} // namespace
39
40
21.6k
std::string build_paimon_deletion_vector_cache_key(const TPaimonDeletionFileDesc& deletion_file) {
41
21.6k
    return fmt::format("paimon_dv_{}#{}#{}", deletion_file.path, deletion_file.offset,
42
21.6k
                       deletion_file.length);
43
21.6k
}
44
45
Status decode_paimon_deletion_vector_buffer(const char* buf, size_t buffer_size,
46
239
                                            DeletionVector* deletion_vector) {
47
239
    if (deletion_vector == nullptr) {
48
0
        return Status::InvalidArgument("deletion_vector must not be null");
49
0
    }
50
239
    if (buffer_size < 8) [[unlikely]] {
51
2
        return Status::DataQualityError("Deletion vector file size too small: {}", buffer_size);
52
2
    }
53
54
237
    const uint32_t actual_length = BigEndian::Load32(buf);
55
237
    if (actual_length + 4 != buffer_size) [[unlikely]] {
56
2
        return Status::RuntimeError(
57
2
                "DeletionVector deserialize error: length not match, "
58
2
                "actual length: {}, expect length: {}",
59
2
                actual_length, buffer_size - 4);
60
2
    }
61
62
235
    if (memcmp(buf + sizeof(actual_length), PAIMON_BITMAP_MAGIC, 4) != 0) [[unlikely]] {
63
2
        return Status::RuntimeError("DeletionVector deserialize error: invalid magic number {}",
64
2
                                    BigEndian::Load32(buf + sizeof(actual_length)));
65
2
    }
66
67
233
    roaring::Roaring roaring_bitmap;
68
233
    try {
69
233
        roaring_bitmap = roaring::Roaring::readSafe(buf + 8, buffer_size - 8);
70
233
    } catch (const std::runtime_error& e) {
71
2
        return Status::RuntimeError(
72
2
                "DeletionVector deserialize error: failed to deserialize roaring bitmap, {}",
73
2
                e.what());
74
2
    }
75
76
231
    *deletion_vector |= DeletionVector(std::move(roaring_bitmap));
77
231
    return Status::OK();
78
233
}
79
80
namespace {
81
82
template <typename Profile>
83
void init_deletion_vector_cache_profile(RuntimeProfile* profile, const char* parent,
84
2
                                        Profile* counters) {
85
2
    counters->decoded_cache_hit_count =
86
2
            ADD_CHILD_COUNTER(profile, "DeletionVectorDecodedCacheHitCount", TUnit::UNIT, parent);
87
2
    counters->decoded_cache_miss_count =
88
2
            ADD_CHILD_COUNTER(profile, "DeletionVectorDecodedCacheMissCount", TUnit::UNIT, parent);
89
2
    counters->file_cache_hit_count =
90
2
            ADD_CHILD_COUNTER(profile, "DeletionVectorFileCacheHitCount", TUnit::UNIT, parent);
91
2
    counters->file_cache_miss_count =
92
2
            ADD_CHILD_COUNTER(profile, "DeletionVectorFileCacheMissCount", TUnit::UNIT, parent);
93
2
    counters->file_cache_peer_read_count =
94
2
            ADD_CHILD_COUNTER(profile, "DeletionVectorFileCachePeerReadCount", TUnit::UNIT, parent);
95
2
}
paimon_reader.cpp:_ZN5doris12_GLOBAL__N_134init_deletion_vector_cache_profileINS_15PaimonOrcReader13PaimonProfileEEEvPNS_14RuntimeProfileEPKcPT_
Line
Count
Source
84
1
                                        Profile* counters) {
85
1
    counters->decoded_cache_hit_count =
86
1
            ADD_CHILD_COUNTER(profile, "DeletionVectorDecodedCacheHitCount", TUnit::UNIT, parent);
87
1
    counters->decoded_cache_miss_count =
88
1
            ADD_CHILD_COUNTER(profile, "DeletionVectorDecodedCacheMissCount", TUnit::UNIT, parent);
89
1
    counters->file_cache_hit_count =
90
1
            ADD_CHILD_COUNTER(profile, "DeletionVectorFileCacheHitCount", TUnit::UNIT, parent);
91
1
    counters->file_cache_miss_count =
92
1
            ADD_CHILD_COUNTER(profile, "DeletionVectorFileCacheMissCount", TUnit::UNIT, parent);
93
1
    counters->file_cache_peer_read_count =
94
1
            ADD_CHILD_COUNTER(profile, "DeletionVectorFileCachePeerReadCount", TUnit::UNIT, parent);
95
1
}
paimon_reader.cpp:_ZN5doris12_GLOBAL__N_134init_deletion_vector_cache_profileINS_19PaimonParquetReader13PaimonProfileEEEvPNS_14RuntimeProfileEPKcPT_
Line
Count
Source
84
1
                                        Profile* counters) {
85
1
    counters->decoded_cache_hit_count =
86
1
            ADD_CHILD_COUNTER(profile, "DeletionVectorDecodedCacheHitCount", TUnit::UNIT, parent);
87
1
    counters->decoded_cache_miss_count =
88
1
            ADD_CHILD_COUNTER(profile, "DeletionVectorDecodedCacheMissCount", TUnit::UNIT, parent);
89
1
    counters->file_cache_hit_count =
90
1
            ADD_CHILD_COUNTER(profile, "DeletionVectorFileCacheHitCount", TUnit::UNIT, parent);
91
1
    counters->file_cache_miss_count =
92
1
            ADD_CHILD_COUNTER(profile, "DeletionVectorFileCacheMissCount", TUnit::UNIT, parent);
93
1
    counters->file_cache_peer_read_count =
94
1
            ADD_CHILD_COUNTER(profile, "DeletionVectorFileCachePeerReadCount", TUnit::UNIT, parent);
95
1
}
96
97
template <typename Profile>
98
void update_deletion_vector_file_cache_profile(const DeletionVectorReader& reader,
99
0
                                               Profile* counters) {
100
0
    const auto& stats = reader.file_cache_statistics();
101
0
    COUNTER_UPDATE(counters->file_cache_hit_count, stats.num_local_io_total);
102
0
    COUNTER_UPDATE(counters->file_cache_miss_count, stats.num_remote_io_total);
103
0
    COUNTER_UPDATE(counters->file_cache_peer_read_count, stats.num_peer_io_total);
104
0
}
Unexecuted instantiation: paimon_reader.cpp:_ZN5doris12_GLOBAL__N_141update_deletion_vector_file_cache_profileINS_15PaimonOrcReader13PaimonProfileEEEvRKNS_20DeletionVectorReaderEPT_
Unexecuted instantiation: paimon_reader.cpp:_ZN5doris12_GLOBAL__N_141update_deletion_vector_file_cache_profileINS_19PaimonParquetReader13PaimonProfileEEEvRKNS_20DeletionVectorReaderEPT_
105
106
} // namespace
107
108
// ============================================================================
109
// PaimonOrcReader
110
// ============================================================================
111
1
void PaimonOrcReader::_init_paimon_profile() {
112
1
    static const char* paimon_profile = "PaimonProfile";
113
1
    ADD_TIMER(get_profile(), paimon_profile);
114
1
    _paimon_profile.num_delete_rows =
115
1
            ADD_CHILD_COUNTER(get_profile(), "NumDeleteRows", TUnit::UNIT, paimon_profile);
116
1
    _paimon_profile.delete_files_read_time =
117
1
            ADD_CHILD_TIMER(get_profile(), "DeleteFileReadTime", paimon_profile);
118
1
    _paimon_profile.parse_deletion_vector_time =
119
1
            ADD_CHILD_TIMER(get_profile(), "ParseDeletionVectorTime", paimon_profile);
120
1
    init_deletion_vector_cache_profile(get_profile(), paimon_profile, &_paimon_profile);
121
1
}
122
123
0
Status PaimonOrcReader::on_before_init_reader(ReaderInitContext* ctx) {
124
0
    _column_descs = ctx->column_descs;
125
0
    _fill_col_name_to_block_idx = ctx->col_name_to_block_idx;
126
0
    RETURN_IF_ERROR(_extract_partition_values(*ctx->range, ctx->tuple_descriptor,
127
0
                                              _fill_partition_values,
128
0
                                              &_fill_partition_value_is_null));
129
0
    const orc::Type* orc_type_ptr = nullptr;
130
0
    RETURN_IF_ERROR(get_file_type(&orc_type_ptr));
131
132
0
    RETURN_IF_ERROR(gen_table_info_node_by_field_id(
133
0
            get_scan_params(), get_scan_range().table_format_params.paimon_params.schema_id,
134
0
            get_tuple_descriptor(), orc_type_ptr));
135
0
    ctx->table_info_node = table_info_node_ptr;
136
137
0
    for (const auto& desc : *ctx->column_descs) {
138
0
        if (desc.category == ColumnCategory::REGULAR ||
139
0
            desc.category == ColumnCategory::GENERATED) {
140
0
            ctx->column_names.push_back(desc.name);
141
0
        }
142
0
    }
143
0
    return Status::OK();
144
0
}
145
146
0
Status PaimonOrcReader::on_after_init_reader(ReaderInitContext* /*ctx*/) {
147
0
    return _init_deletion_vector();
148
0
}
149
150
1
Status PaimonOrcReader::_init_deletion_vector() {
151
1
    const auto& table_desc = get_scan_range().table_format_params.paimon_params;
152
1
    if (!table_desc.__isset.deletion_file) {
153
0
        return Status::OK();
154
0
    }
155
156
    // Cannot do count push down if there are delete files
157
1
    if (!get_scan_range().table_format_params.paimon_params.__isset.row_count) {
158
1
        set_push_down_agg_type(TPushAggOp::NONE);
159
1
    }
160
1
    const auto& deletion_file = table_desc.deletion_file;
161
162
1
    Status create_status = Status::OK();
163
164
1
    SCOPED_TIMER(_paimon_profile.delete_files_read_time);
165
1
    bool decoded_cache_hit = false;
166
1
    _deletion_vector = _kv_cache->get<DeletionVector>(
167
1
            build_paimon_deletion_vector_cache_key(deletion_file),
168
1
            [&]() -> DeletionVector* {
169
1
                auto deletion_vector = std::make_unique<DeletionVector>();
170
171
1
                TFileRangeDesc delete_range;
172
1
                delete_range.__set_fs_name(get_scan_range().fs_name);
173
1
                delete_range.path = deletion_file.path;
174
1
                delete_range.start_offset = deletion_file.offset;
175
1
                delete_range.size = deletion_file.length + 4;
176
1
                delete_range.file_size = -1;
177
178
1
                DeletionVectorReader dv_reader(get_state(), get_profile(), get_scan_params(),
179
1
                                               delete_range, get_io_ctx());
180
1
                create_status = dv_reader.open();
181
1
                if (!create_status.ok()) [[unlikely]] {
182
1
                    return nullptr;
183
1
                }
184
185
0
                size_t bytes_read = deletion_file.length + 4;
186
0
                std::vector<char> buffer(bytes_read);
187
0
                create_status =
188
0
                        dv_reader.read_at(deletion_file.offset, {buffer.data(), bytes_read});
189
0
                update_deletion_vector_file_cache_profile(dv_reader, &_paimon_profile);
190
0
                if (!create_status.ok()) [[unlikely]] {
191
0
                    return nullptr;
192
0
                }
193
194
0
                SCOPED_TIMER(_paimon_profile.parse_deletion_vector_time);
195
0
                create_status = decode_paimon_deletion_vector_buffer(buffer.data(), bytes_read,
196
0
                                                                     deletion_vector.get());
197
0
                if (!create_status.ok()) [[unlikely]] {
198
0
                    return nullptr;
199
0
                }
200
0
                COUNTER_UPDATE(_paimon_profile.num_delete_rows, deletion_vector->cardinality());
201
0
                return deletion_vector.release();
202
0
            },
203
1
            &decoded_cache_hit);
204
1
    RETURN_IF_ERROR(create_status);
205
0
    COUNTER_UPDATE(decoded_cache_hit ? _paimon_profile.decoded_cache_hit_count
206
0
                                     : _paimon_profile.decoded_cache_miss_count,
207
0
                   1);
208
0
    if (!_deletion_vector->isEmpty()) [[likely]] {
209
0
        set_deletion_vector(_deletion_vector);
210
0
    }
211
0
    return Status::OK();
212
1
}
213
214
// ============================================================================
215
// PaimonParquetReader
216
// ============================================================================
217
1
void PaimonParquetReader::_init_paimon_profile() {
218
1
    static const char* paimon_profile = "PaimonProfile";
219
1
    ADD_TIMER(get_profile(), paimon_profile);
220
1
    _paimon_profile.num_delete_rows =
221
1
            ADD_CHILD_COUNTER(get_profile(), "NumDeleteRows", TUnit::UNIT, paimon_profile);
222
1
    _paimon_profile.delete_files_read_time =
223
1
            ADD_CHILD_TIMER(get_profile(), "DeleteFileReadTime", paimon_profile);
224
1
    _paimon_profile.parse_deletion_vector_time =
225
1
            ADD_CHILD_TIMER(get_profile(), "ParseDeletionVectorTime", paimon_profile);
226
1
    init_deletion_vector_cache_profile(get_profile(), paimon_profile, &_paimon_profile);
227
1
}
228
229
0
Status PaimonParquetReader::on_before_init_reader(ReaderInitContext* ctx) {
230
0
    _column_descs = ctx->column_descs;
231
0
    _fill_col_name_to_block_idx = ctx->col_name_to_block_idx;
232
0
    RETURN_IF_ERROR(_extract_partition_values(*ctx->range, ctx->tuple_descriptor,
233
0
                                              _fill_partition_values,
234
0
                                              &_fill_partition_value_is_null));
235
0
    const FieldDescriptor* field_desc = nullptr;
236
0
    RETURN_IF_ERROR(get_file_metadata_schema(&field_desc));
237
0
    DCHECK(field_desc != nullptr);
238
239
0
    RETURN_IF_ERROR(gen_table_info_node_by_field_id(
240
0
            get_scan_params(), get_scan_range().table_format_params.paimon_params.schema_id,
241
0
            get_tuple_descriptor(), *field_desc));
242
0
    ctx->table_info_node = table_info_node_ptr;
243
244
0
    for (const auto& desc : *ctx->column_descs) {
245
0
        if (desc.category == ColumnCategory::REGULAR ||
246
0
            desc.category == ColumnCategory::GENERATED) {
247
0
            ctx->column_names.push_back(desc.name);
248
0
        }
249
0
    }
250
0
    return Status::OK();
251
0
}
252
253
0
Status PaimonParquetReader::on_after_init_reader(ReaderInitContext* /*ctx*/) {
254
0
    return _init_deletion_vector();
255
0
}
256
257
1
Status PaimonParquetReader::_init_deletion_vector() {
258
1
    const auto& table_desc = get_scan_range().table_format_params.paimon_params;
259
1
    if (!table_desc.__isset.deletion_file) {
260
0
        return Status::OK();
261
0
    }
262
263
1
    if (!get_scan_range().table_format_params.paimon_params.__isset.row_count) {
264
1
        set_push_down_agg_type(TPushAggOp::NONE);
265
1
    }
266
1
    const auto& deletion_file = table_desc.deletion_file;
267
268
1
    Status create_status = Status::OK();
269
270
1
    SCOPED_TIMER(_paimon_profile.delete_files_read_time);
271
1
    bool decoded_cache_hit = false;
272
1
    _deletion_vector = _kv_cache->get<DeletionVector>(
273
1
            build_paimon_deletion_vector_cache_key(deletion_file),
274
1
            [&]() -> DeletionVector* {
275
1
                auto deletion_vector = std::make_unique<DeletionVector>();
276
277
1
                TFileRangeDesc delete_range;
278
1
                delete_range.__set_fs_name(get_scan_range().fs_name);
279
1
                delete_range.path = deletion_file.path;
280
1
                delete_range.start_offset = deletion_file.offset;
281
1
                delete_range.size = deletion_file.length + 4;
282
1
                delete_range.file_size = -1;
283
284
1
                DeletionVectorReader dv_reader(get_state(), get_profile(), get_scan_params(),
285
1
                                               delete_range, get_io_ctx());
286
1
                create_status = dv_reader.open();
287
1
                if (!create_status.ok()) [[unlikely]] {
288
1
                    return nullptr;
289
1
                }
290
291
0
                size_t bytes_read = deletion_file.length + 4;
292
0
                std::vector<char> buffer(bytes_read);
293
0
                create_status =
294
0
                        dv_reader.read_at(deletion_file.offset, {buffer.data(), bytes_read});
295
0
                update_deletion_vector_file_cache_profile(dv_reader, &_paimon_profile);
296
0
                if (!create_status.ok()) [[unlikely]] {
297
0
                    return nullptr;
298
0
                }
299
300
0
                SCOPED_TIMER(_paimon_profile.parse_deletion_vector_time);
301
0
                create_status = decode_paimon_deletion_vector_buffer(buffer.data(), bytes_read,
302
0
                                                                     deletion_vector.get());
303
0
                if (!create_status.ok()) [[unlikely]] {
304
0
                    return nullptr;
305
0
                }
306
0
                COUNTER_UPDATE(_paimon_profile.num_delete_rows, deletion_vector->cardinality());
307
0
                return deletion_vector.release();
308
0
            },
309
1
            &decoded_cache_hit);
310
1
    RETURN_IF_ERROR(create_status);
311
0
    COUNTER_UPDATE(decoded_cache_hit ? _paimon_profile.decoded_cache_hit_count
312
0
                                     : _paimon_profile.decoded_cache_miss_count,
313
0
                   1);
314
0
    if (!_deletion_vector->isEmpty()) [[likely]] {
315
0
        ParquetReader::set_deletion_vector(_deletion_vector);
316
0
    }
317
0
    return Status::OK();
318
1
}
319
320
} // namespace doris