Coverage Report

Created: 2026-08-18 04:57

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