Coverage Report

Created: 2026-07-29 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exec/sink/viceberg_delete_sink.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/DataSinks_types.h>
21
#include <gen_cpp/PlanNodes_types.h>
22
23
#include <cstddef>
24
#include <cstdint>
25
#include <map>
26
#include <memory>
27
#include <string>
28
#include <vector>
29
30
#include "common/status.h"
31
#include "core/block/block.h"
32
#include "exec/sink/writer/async_result_writer.h"
33
#include "exec/sink/writer/iceberg/viceberg_delete_file_writer.h"
34
#include "exprs/vexpr_fwd.h"
35
#include "roaring/roaring64map.hh"
36
#include "runtime/runtime_profile.h"
37
38
namespace doris {
39
40
class ObjectPool;
41
class RuntimeState;
42
class Dependency;
43
44
class VIcebergDeleteFileWriter;
45
46
Status calculate_iceberg_deletion_vector_content_size(size_t bitmap_size, int64_t* content_size);
47
48
struct IcebergFileDeletion {
49
    IcebergFileDeletion() = default;
50
    IcebergFileDeletion(int32_t spec_id, std::string data_json)
51
371
            : partition_spec_id(spec_id), partition_data_json(std::move(data_json)) {}
52
53
    int32_t partition_spec_id = 0;
54
    std::string partition_data_json;
55
    roaring::Roaring64Map rows_to_delete;
56
};
57
58
/**
59
 * Sink for writing Iceberg position delete files.
60
 *
61
 * This sink receives blocks containing a $row_id column with
62
 * (file_path, row_position, partition_spec_id, partition_data).
63
 * It groups delete records by file_path and writes position delete files.
64
 */
65
class VIcebergDeleteSink final : public AsyncResultWriter {
66
public:
67
    VIcebergDeleteSink(const TDataSink& t_sink, const VExprContextSPtrs& output_exprs,
68
                       std::shared_ptr<Dependency> dep, std::shared_ptr<Dependency> fin_dep);
69
70
2.44k
    ~VIcebergDeleteSink() override = default;
71
72
    Status init_properties(ObjectPool* pool);
73
74
    Status open(RuntimeState* state, RuntimeProfile* profile) override;
75
76
    Status write(RuntimeState* state, Block& block) override;
77
78
    Status close(Status) override;
79
80
1.73k
    void defer_file_cleanup_until_outer_close() { _defer_file_cleanup_until_outer_close = true; }
81
82
    void finish_deferred_file_cleanup(Status outer_status);
83
84
private:
85
    /**
86
     * Extract $row_id column from block and group by file_path.
87
     */
88
    Status _collect_position_deletes(const Block& block,
89
                                     std::map<std::string, IcebergFileDeletion>& file_deletions);
90
91
    /**
92
     * Write grouped position deletes to delete files
93
     */
94
    Status _write_position_delete_files(
95
            const std::map<std::string, IcebergFileDeletion>& file_deletions);
96
97
    Status _write_deletion_vector_files(
98
            const std::map<std::string, IcebergFileDeletion>& file_deletions);
99
100
    struct DeletionVectorBlob {
101
        std::string referenced_data_file;
102
        int32_t partition_spec_id = 0;
103
        std::string partition_data_json;
104
        int64_t delete_count = 0; // The number of rows deleted in this delete operation.
105
        int64_t merged_count =
106
                0; // The number of rows after merging the old deletion vector and position delete.
107
        int64_t content_offset = 0;
108
        int64_t content_size_in_bytes = 0;
109
        std::vector<char> blob_data;
110
    };
111
112
    Status _write_puffin_file(const std::string& puffin_path,
113
                              std::vector<DeletionVectorBlob>* blobs, int64_t* out_file_size);
114
115
    std::string _build_puffin_footer_json(const std::vector<DeletionVectorBlob>& blobs);
116
117
    std::string _generate_puffin_file_path();
118
119
    /**
120
     * Generate unique delete file path
121
     */
122
    std::string _generate_delete_file_path(const std::string& referenced_data_file = "");
123
124
    /**
125
     * Get $row_id column index from block
126
     */
127
    int _get_row_id_column_index(const Block& block);
128
129
    /**
130
     * Build a block for position delete (file_path, pos)
131
     */
132
    Status _build_position_delete_block(const std::string& file_path,
133
                                        const std::vector<int64_t>& positions, Block& output_block);
134
    Status _init_position_delete_output_exprs();
135
    std::string _get_file_extension() const;
136
    void _cleanup_created_files();
137
138
    TDataSink _t_sink;
139
    RuntimeState* _state = nullptr;
140
141
    int32_t _format_version = 2;
142
    TFileContent::type _delete_type = TFileContent::POSITION_DELETES;
143
144
    // Writers for delete files
145
    std::vector<std::unique_ptr<VIcebergDeleteFileWriter>> _writers;
146
147
    // Collected commit data from all writers
148
    std::vector<TIcebergCommitData> _commit_data_list;
149
    // MERGE owns both data and delete objects until both inner sinks close successfully.
150
    std::vector<std::pair<std::shared_ptr<io::FileSystem>, std::string>> _created_files;
151
    bool _defer_file_cleanup_until_outer_close = false;
152
    // TODO: All deletions are held in memory until close(). Consider flushing
153
    //  per-file when the upstream guarantees file_path ordering, or flushing
154
    //  when estimated memory exceeds a threshold, to reduce peak memory usage.
155
    std::map<std::string, IcebergFileDeletion> _file_deletions;
156
    std::map<std::string, std::vector<TIcebergDeleteFileDesc>> _rewritable_delete_files;
157
158
    // Hadoop configuration
159
    std::map<std::string, std::string> _hadoop_conf;
160
161
    // File format settings
162
    TFileFormatType::type _file_format_type = TFileFormatType::FORMAT_PARQUET;
163
    TFileCompressType::type _compress_type = TFileCompressType::SNAPPYBLOCK;
164
165
    // Output directory for delete files
166
    std::string _output_path;
167
    std::string _table_location;
168
169
    TFileType::type _file_type = TFileType::FILE_HDFS;
170
    std::vector<TNetworkAddress> _broker_addresses;
171
172
    // Partition information
173
    int32_t _partition_spec_id = 0;
174
    std::string _partition_data_json;
175
176
    // Counters
177
    size_t _row_count = 0;
178
    size_t _delete_file_count = 0;
179
180
    // Profile counters
181
    RuntimeProfile::Counter* _written_rows_counter = nullptr;
182
    RuntimeProfile::Counter* _send_data_timer = nullptr;
183
    RuntimeProfile::Counter* _write_delete_files_timer = nullptr;
184
    RuntimeProfile::Counter* _delete_file_count_counter = nullptr;
185
    RuntimeProfile::Counter* _open_timer = nullptr;
186
    RuntimeProfile::Counter* _close_timer = nullptr;
187
188
    VExprContextSPtrs _position_delete_output_expr_ctxs;
189
};
190
191
} // namespace doris