Coverage Report

Created: 2026-08-13 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/segment/column_writer.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/AgentService_types.h>
21
#include <gen_cpp/olap_file.pb.h>
22
#include <gen_cpp/segment_v2.pb.h>
23
#include <stddef.h>
24
#include <stdint.h>
25
26
#include <algorithm>
27
#include <memory> // for unique_ptr
28
#include <ostream>
29
#include <span>
30
#include <string>
31
#include <unordered_map>
32
#include <utility>
33
#include <vector>
34
35
#include "common/status.h" // for Status
36
#include "core/column/column_variant.h"
37
#include "storage/index/ann/ann_index_writer.h"
38
#include "storage/index/bloom_filter/bloom_filter.h"
39
#include "storage/index/inverted/inverted_index_writer.h"
40
#include "storage/segment/common.h"
41
#include "storage/segment/options.h"
42
#include "storage/segment/variant/nested_group_provider.h"
43
#include "storage/segment/variant/variant_statistics.h"
44
#include "storage/tablet/tablet_schema.h" // for TabletColumnPtr
45
#include "storage/types.h"                // for field_type_size
46
#include "util/bitmap.h"                  // for BitmapChange
47
#include "util/slice.h"                   // for OwnedSlice
48
49
namespace doris {
50
51
class BlockCompressionCodec;
52
class TabletColumn;
53
class TabletIndex;
54
struct RowsetWriterContext;
55
struct VariantColumnData;
56
57
namespace io {
58
class FileWriter;
59
}
60
61
namespace segment_v2 {
62
63
enum class VariantWriterInputFormat : uint8_t {
64
    UNSET,
65
    V1,
66
    V2,
67
};
68
69
struct ColumnWriterOptions {
70
    // input and output parameter:
71
    // - input: column_id/unique_id/type/length/encoding/compression/is_nullable members
72
    // - output: encoding/indexes/dict_page members
73
    ColumnMetaPB* meta = nullptr;
74
    size_t data_page_size = STORAGE_PAGE_SIZE_DEFAULT_VALUE;
75
    size_t dict_page_size = STORAGE_DICT_PAGE_SIZE_DEFAULT_VALUE;
76
    // store compressed page only when space saving is above the threshold.
77
    // space saving = 1 - compressed_size / uncompressed_size
78
    double compression_min_space_saving = 0.1;
79
    bool need_zone_map = false;
80
    bool need_bloom_filter = false;
81
    bool is_ngram_bf_index = false;
82
    bool need_inverted_index = false;
83
    bool need_ann_index = false;
84
    uint8_t gram_size;
85
    uint16_t gram_bf_size;
86
    BloomFilterOptions bf_options;
87
    std::vector<const TabletIndex*> inverted_indexes;
88
    IndexFileWriter* index_file_writer = nullptr;
89
90
    SegmentFooterPB* footer = nullptr;
91
    io::FileWriter* file_writer = nullptr;
92
    CompressionTypePB compression_type = UNKNOWN_COMPRESSION;
93
    RowsetWriterContext* rowset_ctx = nullptr;
94
    // For collect segment statistics for compaction
95
    std::vector<RowsetReaderSharedPtr> input_rs_readers;
96
    const TabletIndex* ann_index = nullptr;
97
98
    // Storage format of the owning tablet (V2 or V3). Set once by the segment writer
99
    // (from TabletMeta::storage_format()) and propagated down to aux child writers
100
    // (null / array-length / map-length), struct subcolumn writers and variant subcolumn
101
    // writers. All encoding-default decisions consult this via resolve_default_encoding().
102
    // Also forwarded to BinaryDictPageBuilder via PageBuilderOptions::binary_plain_encoding.
103
    TabletStorageFormatPB storage_format = TabletStorageFormatPB::TABLET_STORAGE_FORMAT_V2;
104
105
0
    std::string to_string() const {
106
0
        std::stringstream ss;
107
0
        ss << std::boolalpha << "meta=" << meta->DebugString()
108
0
           << ", data_page_size=" << data_page_size << ", dict_page_size=" << dict_page_size
109
0
           << ", compression_min_space_saving = " << compression_min_space_saving
110
0
           << ", need_zone_map=" << need_zone_map << ", need_bloom_filter" << need_bloom_filter;
111
0
        return ss.str();
112
0
    }
113
};
114
115
class EncodingInfo;
116
class NullBitmapBuilder;
117
class OrdinalIndexWriter;
118
class PageBuilder;
119
class BloomFilterIndexWriter;
120
class ZoneMapIndexWriter;
121
class VariantColumnWriterImpl;
122
class VariantShredder;
123
class VariantPathBuilder;
124
class ColumnWriter;
125
126
class ColumnWriter {
127
public:
128
    static Status create(const ColumnWriterOptions& opts, const TabletColumn* column,
129
                         io::FileWriter* file_writer, std::unique_ptr<ColumnWriter>* writer);
130
    static Status create_struct_writer(const ColumnWriterOptions& opts, const TabletColumn* column,
131
                                       io::FileWriter* file_writer,
132
                                       std::unique_ptr<ColumnWriter>* writer);
133
    static Status create_array_writer(const ColumnWriterOptions& opts, const TabletColumn* column,
134
                                      io::FileWriter* file_writer,
135
                                      std::unique_ptr<ColumnWriter>* writer);
136
    static Status create_map_writer(const ColumnWriterOptions& opts, const TabletColumn* column,
137
                                    io::FileWriter* file_writer,
138
                                    std::unique_ptr<ColumnWriter>* writer);
139
140
    static Status create_variant_writer(const ColumnWriterOptions& opts, const TabletColumn* column,
141
                                        io::FileWriter* file_writer,
142
                                        std::unique_ptr<ColumnWriter>* writer);
143
144
    static Status create_agg_state_writer(const ColumnWriterOptions& opts,
145
                                          const TabletColumn* column, io::FileWriter* file_writer,
146
                                          std::unique_ptr<ColumnWriter>* writer);
147
148
    explicit ColumnWriter(TabletColumnPtr column, bool is_nullable, ColumnMetaPB* meta);
149
150
1.12M
    virtual ~ColumnWriter() = default;
151
152
    virtual Status init() = 0;
153
154
    template <typename CellType>
155
    Status append(const CellType& cell) {
156
        if (_is_nullable) {
157
            uint8_t nullmap = 0;
158
            BitmapChange(&nullmap, 0, cell.is_null());
159
            return append_nullable(&nullmap, cell.cell_ptr(), 1);
160
        } else {
161
            auto* cel_ptr = cell.cell_ptr();
162
            return append_data((const uint8_t**)&cel_ptr, 1);
163
        }
164
    }
165
166
    // Now we only support append one by one, we should support append
167
    // multi rows in one call
168
    Status append(bool is_null, void* data) {
169
        uint8_t nullmap = 0;
170
        BitmapChange(&nullmap, 0, is_null);
171
        return append_nullable(&nullmap, data, 1);
172
    }
173
174
    Status append(const uint8_t* nullmap, const void* data, size_t num_rows);
175
176
    Status append_nullable(const uint8_t* nullmap, const void* data, size_t num_rows);
177
178
    // use only in vectorized load
179
    virtual Status append_nullable(const uint8_t* null_map, const uint8_t** data, size_t num_rows);
180
181
    virtual Status append_nulls(size_t num_rows) = 0;
182
183
    virtual Status finish_current_page() = 0;
184
185
    virtual uint64_t estimate_buffer_size() = 0;
186
187
    // finish append data
188
    virtual Status finish() = 0;
189
190
    // write all data into file
191
    virtual Status write_data() = 0;
192
193
    virtual Status write_ordinal_index() = 0;
194
195
    virtual Status write_zone_map() = 0;
196
197
    virtual Status write_inverted_index() = 0;
198
199
787k
    virtual Status write_ann_index() { return Status::OK(); }
200
201
    virtual Status write_bloom_filter_index() = 0;
202
203
    virtual ordinal_t get_next_rowid() const = 0;
204
205
    virtual uint64_t get_raw_data_bytes() const = 0;
206
    virtual uint64_t get_total_uncompressed_data_pages_bytes() const = 0;
207
    virtual uint64_t get_total_compressed_data_pages_bytes() const = 0;
208
209
    // used for append not null data.
210
    virtual Status append_data(const uint8_t** ptr, size_t num_rows) = 0;
211
212
6.72M
    bool is_nullable() const { return _is_nullable; }
213
214
3.36M
    const TabletColumn* get_column() const { return _column.get(); }
215
216
    // Per-row in-memory cell footprint of this writer's column, used to step
217
    // the input pointer across rows in append_*/null-run loops.
218
4.85M
    size_t cell_size() const { return field_type_size(_column->type()); }
219
220
830k
    ColumnMetaPB* get_column_meta() const { return _column_meta; }
221
222
protected:
223
    DataTypePtr _data_type;
224
225
private:
226
    TabletColumnPtr _column;
227
    bool _is_nullable;
228
    ColumnMetaPB* _column_meta;
229
    std::vector<uint8_t> _null_bitmap;
230
};
231
232
class FlushPageCallback {
233
public:
234
68.3k
    virtual ~FlushPageCallback() = default;
235
0
    virtual void put_extra_info_in_page(DataPageFooterPB* footer) {}
236
};
237
238
// Encode one column's data into some memory slice.
239
// Because some columns would be stored in a file, we should wait
240
// until all columns has been finished, and then data can be written
241
// to file
242
class ScalarColumnWriter : public ColumnWriter {
243
public:
244
    ScalarColumnWriter(const ColumnWriterOptions& opts, TabletColumnPtr column,
245
                       io::FileWriter* file_writer);
246
247
    ~ScalarColumnWriter() override;
248
249
    Status init() override;
250
251
    Status append_nulls(size_t num_rows) override;
252
253
    Status finish_current_page() override;
254
255
    uint64_t estimate_buffer_size() override;
256
257
    // finish append data
258
    Status finish() override;
259
260
    Status write_data() override;
261
    Status write_ordinal_index() override;
262
    Status write_zone_map() override;
263
    Status write_inverted_index() override;
264
    Status write_bloom_filter_index() override;
265
176k
    ordinal_t get_next_rowid() const override { return _next_rowid; }
266
267
949k
    uint64_t get_raw_data_bytes() const override { return _raw_data_bytes; }
268
269
949k
    uint64_t get_total_uncompressed_data_pages_bytes() const override {
270
949k
        return _total_uncompressed_data_pages_size;
271
949k
    }
272
273
949k
    uint64_t get_total_compressed_data_pages_bytes() const override {
274
949k
        return _total_compressed_data_pages_size;
275
949k
    }
276
277
68.3k
    void register_flush_page_callback(FlushPageCallback* flush_page_callback) {
278
68.3k
        _new_page_callback = flush_page_callback;
279
68.3k
    }
280
    Status append_data(const uint8_t** ptr, size_t num_rows) override;
281
    Status append_nullable(const uint8_t* null_map, const uint8_t** ptr, size_t num_rows) override;
282
283
    // used for append not null data. When page is full, will append data not reach num_rows.
284
    Status append_data_in_current_page(const uint8_t** ptr, size_t* num_written);
285
286
4.41M
    Status append_data_in_current_page(const uint8_t* ptr, size_t* num_written) {
287
4.41M
        RETURN_IF_CATCH_EXCEPTION(
288
4.41M
                { return _internal_append_data_in_current_page(ptr, num_written); });
289
4.41M
    }
290
    friend class ArrayColumnWriter;
291
    friend class OffsetColumnWriter;
292
293
private:
294
    Status _internal_append_data_in_current_page(const uint8_t* ptr, size_t* num_written);
295
296
private:
297
    struct NullRun {
298
        bool is_null;
299
        uint32_t len;
300
    };
301
302
    std::vector<NullRun> _null_run_buffer;
303
    std::unique_ptr<PageBuilder> _page_builder;
304
305
    std::unique_ptr<NullBitmapBuilder> _null_bitmap_builder;
306
307
    ColumnWriterOptions _opts;
308
309
    const EncodingInfo* _encoding_info = nullptr;
310
311
    ordinal_t _next_rowid = 0;
312
313
    // All Pages will be organized into a linked list
314
    struct Page {
315
        // the data vector may contain:
316
        //     1. one OwnedSlice if the page body is compressed
317
        //     2. one OwnedSlice if the page body is not compressed and doesn't have nullmap
318
        //     3. two OwnedSlice if the page body is not compressed and has nullmap
319
        // use vector for easier management for lifetime of OwnedSlice
320
        std::vector<OwnedSlice> data;
321
        PageFooterPB footer;
322
    };
323
324
1.08M
    void _push_back_page(std::unique_ptr<Page> page) {
325
2.07M
        for (auto& data_slice : page->data) {
326
2.07M
            _data_size += data_slice.slice().size;
327
2.07M
        }
328
        // estimate (page footer + footer size + checksum) took 20 bytes
329
1.08M
        _data_size += 20;
330
        // add page to pages' tail
331
1.08M
        _pages.emplace_back(std::move(page));
332
1.08M
    }
333
334
    Status _write_data_page(Page* page);
335
336
private:
337
    io::FileWriter* _file_writer = nullptr;
338
    // total size of data page list
339
    uint64_t _data_size;
340
341
    uint64_t _raw_data_bytes {0};
342
    uint64_t _total_uncompressed_data_pages_size {0};
343
    uint64_t _total_compressed_data_pages_size {0};
344
345
    // cached generated pages,
346
    std::vector<std::unique_ptr<Page>> _pages;
347
    ordinal_t _first_rowid = 0;
348
349
    BlockCompressionCodec* _compress_codec;
350
351
    std::unique_ptr<OrdinalIndexWriter> _ordinal_index_builder;
352
    std::unique_ptr<ZoneMapIndexWriter> _zone_map_index_builder;
353
    std::vector<std::unique_ptr<IndexColumnWriter>> _inverted_index_builders;
354
    std::unique_ptr<BloomFilterIndexWriter> _bloom_filter_index_builder;
355
356
    // call before flush data page.
357
    FlushPageCallback* _new_page_callback = nullptr;
358
};
359
360
// offsetColumnWriter is used column which has offset column, like array, map.
361
//  column type is only uint64 and should response for whole column value [start, end], end will set
362
//  in footer.next_array_item_ordinal which in finish_cur_page() callback put_extra_info_in_page()
363
class OffsetColumnWriter final : public ScalarColumnWriter, FlushPageCallback {
364
public:
365
    OffsetColumnWriter(const ColumnWriterOptions& opts, TabletColumnPtr column,
366
                       io::FileWriter* file_writer);
367
368
    ~OffsetColumnWriter() override;
369
370
    Status init() override;
371
372
    Status append_data(const uint8_t** ptr, size_t num_rows) override;
373
374
private:
375
    void put_extra_info_in_page(DataPageFooterPB* footer) override;
376
377
    uint64_t _next_offset;
378
};
379
380
class StructColumnWriter final : public ColumnWriter {
381
public:
382
    explicit StructColumnWriter(const ColumnWriterOptions& opts, TabletColumnPtr column,
383
                                ScalarColumnWriter* null_writer,
384
                                std::vector<std::unique_ptr<ColumnWriter>>& sub_column_writers);
385
3.11k
    ~StructColumnWriter() override = default;
386
387
    Status init() override;
388
389
    Status append_nullable(const uint8_t* null_map, const uint8_t** data, size_t num_rows) override;
390
    Status append_data(const uint8_t** ptr, size_t num_rows) override;
391
392
    uint64_t estimate_buffer_size() override;
393
394
    Status finish() override;
395
    Status write_data() override;
396
    Status write_ordinal_index() override;
397
    Status append_nulls(size_t num_rows) override;
398
399
    Status finish_current_page() override;
400
401
2.41k
    Status write_zone_map() override {
402
2.41k
        if (_opts.need_zone_map) {
403
0
            return Status::NotSupported("struct not support zone map");
404
0
        }
405
2.41k
        return Status::OK();
406
2.41k
    }
407
408
    Status write_inverted_index() override;
409
2.41k
    Status write_bloom_filter_index() override {
410
2.41k
        if (_opts.need_bloom_filter) {
411
0
            return Status::NotSupported("struct not support bloom filter index");
412
0
        }
413
2.41k
        return Status::OK();
414
2.41k
    }
415
416
3.51k
    ordinal_t get_next_rowid() const override { return _sub_column_writers[0]->get_next_rowid(); }
417
418
3.11k
    uint64_t get_raw_data_bytes() const override {
419
3.11k
        return _get_total_data_pages_bytes(&ColumnWriter::get_raw_data_bytes);
420
3.11k
    }
421
422
3.11k
    uint64_t get_total_uncompressed_data_pages_bytes() const override {
423
3.11k
        return _get_total_data_pages_bytes(&ColumnWriter::get_total_uncompressed_data_pages_bytes);
424
3.11k
    }
425
426
3.11k
    uint64_t get_total_compressed_data_pages_bytes() const override {
427
3.11k
        return _get_total_data_pages_bytes(&ColumnWriter::get_total_compressed_data_pages_bytes);
428
3.11k
    }
429
430
private:
431
    template <typename Func>
432
9.33k
    uint64_t _get_total_data_pages_bytes(Func func) const {
433
9.33k
        uint64_t size = is_nullable() ? std::invoke(func, _null_writer.get()) : 0;
434
59.4k
        for (const auto& writer : _sub_column_writers) {
435
59.4k
            size += std::invoke(func, writer.get());
436
59.4k
        }
437
9.33k
        return size;
438
9.33k
    }
439
440
private:
441
    size_t _num_sub_column_writers;
442
    std::unique_ptr<ScalarColumnWriter> _null_writer;
443
    std::vector<std::unique_ptr<ColumnWriter>> _sub_column_writers;
444
    ColumnWriterOptions _opts;
445
};
446
447
class ArrayColumnWriter final : public ColumnWriter {
448
public:
449
    explicit ArrayColumnWriter(const ColumnWriterOptions& opts, TabletColumnPtr column,
450
                               OffsetColumnWriter* offset_writer, ScalarColumnWriter* null_writer,
451
                               std::unique_ptr<ColumnWriter> item_writer);
452
44.7k
    ~ArrayColumnWriter() override = default;
453
454
    Status init() override;
455
456
    Status append_data(const uint8_t** ptr, size_t num_rows) override;
457
458
    uint64_t estimate_buffer_size() override;
459
460
    Status finish() override;
461
    Status write_data() override;
462
    Status write_ordinal_index() override;
463
    Status append_nulls(size_t num_rows) override;
464
    Status append_nullable(const uint8_t* null_map, const uint8_t** ptr, size_t num_rows) override;
465
466
    Status finish_current_page() override;
467
468
41.8k
    Status write_zone_map() override {
469
41.8k
        if (_opts.need_zone_map) {
470
0
            return Status::NotSupported("array not support zone map");
471
0
        }
472
41.8k
        return Status::OK();
473
41.8k
    }
474
475
    Status write_inverted_index() override;
476
    Status write_ann_index() override;
477
41.8k
    Status write_bloom_filter_index() override {
478
41.8k
        if (_opts.need_bloom_filter) {
479
0
            return Status::NotSupported("array not support bloom filter index");
480
0
        }
481
41.8k
        return Status::OK();
482
41.8k
    }
483
48.4k
    ordinal_t get_next_rowid() const override { return _offset_writer->get_next_rowid(); }
484
485
43.9k
    uint64_t get_raw_data_bytes() const override {
486
43.9k
        return _get_total_data_pages_bytes(&ColumnWriter::get_raw_data_bytes);
487
43.9k
    }
488
489
43.9k
    uint64_t get_total_uncompressed_data_pages_bytes() const override {
490
43.9k
        return _get_total_data_pages_bytes(&ColumnWriter::get_total_uncompressed_data_pages_bytes);
491
43.9k
    }
492
493
43.9k
    uint64_t get_total_compressed_data_pages_bytes() const override {
494
43.9k
        return _get_total_data_pages_bytes(&ColumnWriter::get_total_compressed_data_pages_bytes);
495
43.9k
    }
496
497
private:
498
    template <typename Func>
499
131k
    uint64_t _get_total_data_pages_bytes(Func func) const {
500
131k
        uint64_t size = std::invoke(func, _offset_writer.get());
501
131k
        if (is_nullable()) {
502
82.9k
            size += std::invoke(func, _null_writer.get());
503
82.9k
        }
504
131k
        size += std::invoke(func, _item_writer.get());
505
131k
        return size;
506
131k
    }
507
508
private:
509
    Status write_null_column(size_t num_rows, bool is_null); // 写入num_rows个null标记
510
44.2k
    bool has_empty_items() const { return _item_writer->get_next_rowid() == 0; }
511
512
private:
513
    std::unique_ptr<OffsetColumnWriter> _offset_writer;
514
    std::unique_ptr<ScalarColumnWriter> _null_writer;
515
    std::unique_ptr<ColumnWriter> _item_writer;
516
    std::unique_ptr<IndexColumnWriter> _inverted_index_writer;
517
    std::unique_ptr<AnnIndexColumnWriter> _ann_index_writer;
518
    ColumnWriterOptions _opts;
519
};
520
521
class MapColumnWriter final : public ColumnWriter {
522
public:
523
    explicit MapColumnWriter(const ColumnWriterOptions& opts, TabletColumnPtr column,
524
                             ScalarColumnWriter* null_writer, OffsetColumnWriter* offsets_writer,
525
                             std::vector<std::unique_ptr<ColumnWriter>>& _kv_writers);
526
527
23.5k
    ~MapColumnWriter() override = default;
528
529
    Status init() override;
530
531
    Status append_data(const uint8_t** ptr, size_t num_rows) override;
532
    Status append_nullable(const uint8_t* null_map, const uint8_t** ptr, size_t num_rows) override;
533
    uint64_t estimate_buffer_size() override;
534
535
    Status finish() override;
536
    Status write_data() override;
537
    Status write_ordinal_index() override;
538
    Status write_inverted_index() override;
539
    Status append_nulls(size_t num_rows) override;
540
541
    Status finish_current_page() override;
542
543
11.3k
    Status write_zone_map() override {
544
11.3k
        if (_opts.need_zone_map) {
545
0
            return Status::NotSupported("map not support zone map");
546
0
        }
547
11.3k
        return Status::OK();
548
11.3k
    }
549
550
11.3k
    Status write_bloom_filter_index() override {
551
11.3k
        if (_opts.need_bloom_filter) {
552
0
            return Status::NotSupported("map not support bloom filter index");
553
0
        }
554
11.3k
        return Status::OK();
555
11.3k
    }
556
557
    // according key writer to get next rowid
558
24.6k
    ordinal_t get_next_rowid() const override { return _offsets_writer->get_next_rowid(); }
559
560
11.9k
    uint64_t get_raw_data_bytes() const override {
561
11.9k
        return _get_total_data_pages_bytes(&ColumnWriter::get_raw_data_bytes);
562
11.9k
    }
563
564
11.9k
    uint64_t get_total_uncompressed_data_pages_bytes() const override {
565
11.9k
        return _get_total_data_pages_bytes(&ColumnWriter::get_total_uncompressed_data_pages_bytes);
566
11.9k
    }
567
568
11.9k
    uint64_t get_total_compressed_data_pages_bytes() const override {
569
11.9k
        return _get_total_data_pages_bytes(&ColumnWriter::get_total_compressed_data_pages_bytes);
570
11.9k
    }
571
572
private:
573
    template <typename Func>
574
35.7k
    uint64_t _get_total_data_pages_bytes(Func func) const {
575
35.7k
        uint64_t size = std::invoke(func, _offsets_writer.get());
576
35.7k
        if (is_nullable()) {
577
29.9k
            size += std::invoke(func, _null_writer.get());
578
29.9k
        }
579
71.5k
        for (const auto& writer : _kv_writers) {
580
71.5k
            size += std::invoke(func, writer.get());
581
71.5k
        }
582
35.7k
        return size;
583
35.7k
    }
584
585
private:
586
    std::vector<std::unique_ptr<ColumnWriter>> _kv_writers;
587
    // we need null writer to make sure a row is null or not
588
    std::unique_ptr<ScalarColumnWriter> _null_writer;
589
    std::unique_ptr<OffsetColumnWriter> _offsets_writer;
590
    std::unique_ptr<IndexColumnWriter> _index_builder;
591
    ColumnWriterOptions _opts;
592
};
593
594
// used for compaction to write sub variant column
595
class VariantSubcolumnWriter : public ColumnWriter {
596
public:
597
    explicit VariantSubcolumnWriter(const ColumnWriterOptions& opts, TabletColumnPtr column);
598
599
    ~VariantSubcolumnWriter() override;
600
601
    Status init() override;
602
603
    Status append_data(const uint8_t** ptr, size_t num_rows) override;
604
605
    uint64_t estimate_buffer_size() override;
606
607
    Status finish() override;
608
    Status write_data() override;
609
    Status write_ordinal_index() override;
610
611
    Status write_zone_map() override;
612
613
    Status write_inverted_index() override;
614
    Status write_bloom_filter_index() override;
615
6
    ordinal_t get_next_rowid() const override { return _next_rowid; }
616
617
21
    uint64_t get_raw_data_bytes() const override {
618
21
        return 0; // TODO
619
21
    }
620
621
21
    uint64_t get_total_uncompressed_data_pages_bytes() const override {
622
21
        return 0; // TODO
623
21
    }
624
625
21
    uint64_t get_total_compressed_data_pages_bytes() const override {
626
21
        return 0; // TODO
627
21
    }
628
629
0
    Status append_nulls(size_t num_rows) override {
630
0
        return Status::NotSupported("variant writer can not append_nulls");
631
0
    }
632
    Status append_nullable(const uint8_t* null_map, const uint8_t** ptr, size_t num_rows) override;
633
634
0
    Status finish_current_page() override {
635
0
        return Status::NotSupported("variant writer has no data, can not finish_current_page");
636
0
    }
637
638
0
    size_t get_non_null_size() const { return none_null_size; }
639
640
    Status finalize();
641
642
private:
643
    Status _append(const uint8_t* null_map, const uint8_t** ptr, size_t num_rows);
644
    Status _append_v2(const VariantColumnData& column, size_t num_rows,
645
                      std::span<const uint8_t> outer_nulls);
646
    Status _ensure_input_format(const VariantColumnData& column);
647
    Status _initialize_v2_builder();
648
    bool is_finalized() const;
649
    bool _is_finalized = false;
650
    ordinal_t _next_rowid = 0;
651
    size_t none_null_size = 0;
652
    VariantWriterInputFormat _input_format = VariantWriterInputFormat::UNSET;
653
    ColumnVariant::MutablePtr _v1_column;
654
    std::unique_ptr<VariantPathBuilder> _v2_builder;
655
    size_t _num_rows = 0;
656
    ColumnWriterOptions _opts;
657
    std::unique_ptr<ColumnWriter> _writer;
658
    TabletIndexes _indexes;
659
660
    std::unique_ptr<NestedGroupWriteProvider> _nested_group_provider;
661
    VariantStatistics _statistics;
662
};
663
664
class VariantColumnWriter : public ColumnWriter {
665
public:
666
    explicit VariantColumnWriter(const ColumnWriterOptions& opts, TabletColumnPtr column);
667
668
5.28k
    ~VariantColumnWriter() override = default;
669
670
    Status init() override;
671
672
    Status append_data(const uint8_t** ptr, size_t num_rows) override;
673
674
    uint64_t estimate_buffer_size() override;
675
676
    Status finish() override;
677
    Status write_data() override;
678
    Status write_ordinal_index() override;
679
680
    Status write_zone_map() override;
681
682
    Status write_inverted_index() override;
683
    Status write_bloom_filter_index() override;
684
26
    ordinal_t get_next_rowid() const override { return _next_rowid; }
685
686
5.23k
    uint64_t get_raw_data_bytes() const override {
687
5.23k
        return 0; // TODO
688
5.23k
    }
689
690
5.23k
    uint64_t get_total_uncompressed_data_pages_bytes() const override {
691
5.23k
        return 0; // TODO
692
5.23k
    }
693
694
5.23k
    uint64_t get_total_compressed_data_pages_bytes() const override {
695
5.23k
        return 0; // TODO
696
5.23k
    }
697
698
0
    Status append_nulls(size_t num_rows) override {
699
0
        return Status::NotSupported("variant writer can not append_nulls");
700
0
    }
701
    Status append_nullable(const uint8_t* null_map, const uint8_t** ptr, size_t num_rows) override;
702
703
0
    Status finish_current_page() override {
704
0
        return Status::NotSupported("variant writer has no data, can not finish_current_page");
705
0
    }
706
707
    VariantColumnWriterImpl* impl_for_test() const { return _impl.get(); }
708
709
private:
710
    std::unique_ptr<VariantColumnWriterImpl> _impl;
711
    ordinal_t _next_rowid = 0;
712
};
713
714
} // namespace segment_v2
715
} // namespace doris