Coverage Report

Created: 2026-08-18 14:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/index/index_file_reader.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
// CLucene is third-party code and is not clean under -Wconversion (which
21
// -Wshorten-64-to-32 belongs to). Whether its first expansion lands inside
22
// someone else's suppressed region depends on include order, so suppress it
23
// deliberately here (same pattern as inverted_index_common_impl.h).
24
#ifdef __clang__
25
#pragma clang diagnostic push
26
#pragma clang diagnostic ignored "-Wconversion"
27
#endif
28
#include <CLucene.h> // IWYU pragma: keep
29
#include <CLucene/store/IndexInput.h>
30
#ifdef __clang__
31
#pragma clang diagnostic pop
32
#endif
33
34
#include <gen_cpp/olap_file.pb.h>
35
36
#include <map>
37
#include <memory>
38
#include <mutex>
39
#include <shared_mutex>
40
#include <string>
41
#include <unordered_map>
42
#include <utility>
43
#include <vector>
44
45
#include "common/be_mock_util.h"
46
#include "common/config.h"
47
#include "io/fs/file_system.h"
48
#include "storage/index/index_file_writer.h"
49
#include "storage/index/inverted/inverted_index_desc.h"
50
#include "storage/index/snii/reader/logical_index_reader.h"
51
#include "storage/index/snii/reader/snii_segment_reader.h"
52
#include "storage/index/snii/snii_bkd_searcher.h"
53
#include "storage/index/snii/snii_doris_adapter.h"
54
55
namespace doris {
56
class TabletIndex;
57
namespace segment_v2 {
58
class ReaderFileEntry;
59
class DorisCompoundReader;
60
61
// A singleton class responsible for reading index files, managing file entries, and providing interfaces to access index data.
62
// The singleton object is at segment level, and it is shared by all threads that read the same segment (even across different queries).
63
// It is created when the first index reader is initialized, and destroyed when the segment is closed.
64
class IndexFileReader {
65
public:
66
    // Modern C++ using std::unordered_map with smart pointers for automatic memory management
67
    using EntriesType = std::unordered_map<std::string, std::unique_ptr<ReaderFileEntry>>;
68
    // Map to hold the file entries for each index ID.
69
    using IndicesEntriesMap =
70
            std::map<std::pair<int64_t, std::string>, std::unique_ptr<EntriesType>>;
71
72
    IndexFileReader(io::FileSystemSPtr fs, std::string index_path_prefix,
73
                    InvertedIndexStorageFormatPB storage_format,
74
                    InvertedIndexFileInfo idx_file_info = InvertedIndexFileInfo(),
75
                    int64_t tablet_id = -1)
76
3.36k
            : _fs(std::move(fs)),
77
3.36k
              _index_path_prefix(std::move(index_path_prefix)),
78
3.36k
              _storage_format(storage_format),
79
3.36k
              _idx_file_info(std::move(idx_file_info)),
80
3.36k
              _tablet_id(tablet_id) {}
81
3.36k
    virtual ~IndexFileReader() = default;
82
83
    MOCK_FUNCTION Status init(int32_t read_buffer_size = config::inverted_index_read_buffer_size,
84
                              const io::IOContext* io_ctx = nullptr);
85
    MOCK_FUNCTION Result<std::unique_ptr<DorisCompoundReader, DirectoryDeleter>> open(
86
            const TabletIndex* index_meta, const io::IOContext* io_ctx = nullptr) const;
87
    // Opens one BLOB logical index of kind kBkd: resolves its named sub-files
88
    // (bkd_data / bkd_index / bkd_nulls) into extents through the CONTAINER's own
89
    // directory and hands back a reader bound to this IndexFileReader's file.
90
    // The caller must keep this IndexFileReader alive for the reader's lifetime,
91
    // exactly as open_snii_index requires.
92
    Result<std::unique_ptr<doris::snii::bkd::BkdSearcher>> open_snii_bkd_index(
93
            const TabletIndex* index_meta, const io::IOContext* io_ctx) const;
94
    Result<std::unique_ptr<doris::snii::reader::LogicalIndexReader>> open_snii_index(
95
            const TabletIndex* index_meta, const io::IOContext* io_ctx = nullptr,
96
            doris::snii::reader::LogicalIndexOpenMode open_mode =
97
                    doris::snii::reader::LogicalIndexOpenMode::kQuery) const;
98
    // SNII only: builds the fully validated inheritance view of this container
99
    // for a BUILD INDEX rewrite. `segment_doc_count` is the segment's row count;
100
    // every kept logical index must agree with it.
101
    Status prepare_snii_rewrite_snapshot(
102
            const std::vector<doris::snii::reader::LogicalIndexKey>& keep,
103
            uint64_t segment_doc_count, doris::snii::reader::SniiRewriteSnapshot* out) const;
104
    // SNII only: the raw byte source backing this container, handed to
105
    // SniiCompoundWriter::inherit for the sequential prefix copy.
106
3
    doris::snii::io::FileReader* snii_io_reader() const { return _snii_file_reader.get(); }
107
    // SNII only: true when the opened container holds a blob logical index
108
    // (BKD / ANN). False when this reader opened no SNII container at all.
109
3
    bool snii_has_blob_index() const {
110
3
        std::shared_lock<std::shared_mutex> lock(_mutex);
111
3
        return _snii_segment_reader != nullptr && _snii_segment_reader->has_blob_index();
112
3
    }
113
    void debug_file_entries();
114
    std::string get_index_file_cache_key(const TabletIndex* index_meta) const;
115
    std::string get_index_file_path(const TabletIndex* index_meta) const;
116
    Status index_file_exist(const TabletIndex* index_meta, bool* res) const;
117
    Status has_null(const TabletIndex* index_meta, bool* res) const;
118
    Result<InvertedIndexDirectoryMap> get_all_directories();
119
    // open file v2, init _stream
120
2
    int64_t get_inverted_file_size() const {
121
2
        if (_storage_format == InvertedIndexStorageFormatPB::SNII) {
122
2
            return _snii_file_reader == nullptr ? 0 : _snii_file_reader->size();
123
2
        }
124
0
        return _stream == nullptr ? 0 : _stream->length();
125
2
    }
126
4
    const std::string& get_index_path_prefix() const { return _index_path_prefix; }
127
2.75k
    InvertedIndexStorageFormatPB get_storage_format() const { return _storage_format; }
128
    friend IndexFileWriter;
129
130
protected:
131
    Status _init_from(int32_t read_buffer_size, const io::IOContext* io_ctx);
132
    Status _init_snii(const io::IOContext* io_ctx);
133
    Result<std::unique_ptr<DorisCompoundReader, DirectoryDeleter>> _open(
134
            int64_t index_id, const std::string& index_suffix,
135
            const io::IOContext* io_ctx = nullptr) const;
136
137
private:
138
    IndicesEntriesMap _indices_entries;
139
    std::unique_ptr<CL_NS(store)::IndexInput> _stream = nullptr;
140
    std::shared_ptr<snii_doris::DorisSniiFileReader> _snii_file_reader;
141
    std::unique_ptr<doris::snii::reader::SniiSegmentReader> _snii_segment_reader;
142
    const io::FileSystemSPtr _fs;
143
    std::string _index_path_prefix;
144
    int32_t _read_buffer_size = -1;
145
    InvertedIndexStorageFormatPB _storage_format;
146
    mutable std::shared_mutex _mutex; // Use mutable for const read operations
147
    bool _inited = false;
148
    InvertedIndexFileInfo _idx_file_info;
149
    int64_t _tablet_id = -1;
150
};
151
152
} // namespace segment_v2
153
} // namespace doris