Coverage Report

Created: 2026-11-03 16:23

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 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 <optional>
40
#include <shared_mutex>
41
#include <string>
42
#include <unordered_map>
43
#include <utility>
44
#include <vector>
45
46
#include "common/be_mock_util.h"
47
#include "common/config.h"
48
#include "io/fs/file_system.h"
49
#include "storage/index/index_file_writer.h"
50
#include "storage/index/inverted/common/inverted_index_desc.h"
51
#include "storage/index/inverted/snii/reader/logical_index_reader.h"
52
#include "storage/index/inverted/snii/reader/snii_segment_reader.h"
53
#include "storage/index/inverted/snii/snii_bkd_searcher.h"
54
#include "storage/index/inverted/snii/snii_doris_adapter.h"
55
56
namespace doris {
57
class TabletIndex;
58
namespace segment_v2 {
59
class ReaderFileEntry;
60
class DorisCompoundReader;
61
62
// A singleton class responsible for reading index files, managing file entries, and providing interfaces to access index data.
63
// The singleton object is at segment level, and it is shared by all threads that read the same segment (even across different queries).
64
// It is created when the first index reader is initialized, and destroyed when the segment is closed.
65
class IndexFileReader {
66
public:
67
    // Modern C++ using std::unordered_map with smart pointers for automatic memory management
68
    using EntriesType = std::unordered_map<std::string, std::unique_ptr<ReaderFileEntry>>;
69
    // Map to hold the file entries for each index ID.
70
    using IndicesEntriesMap =
71
            std::map<std::pair<int64_t, std::string>, std::unique_ptr<EntriesType>>;
72
73
    IndexFileReader(io::FileSystemSPtr fs, std::string index_path_prefix,
74
                    InvertedIndexStorageFormatPB storage_format,
75
                    InvertedIndexFileInfo idx_file_info = InvertedIndexFileInfo(),
76
                    int64_t tablet_id = -1)
77
3.65k
            : _fs(std::move(fs)),
78
3.65k
              _index_path_prefix(std::move(index_path_prefix)),
79
3.65k
              _storage_format(storage_format),
80
3.65k
              _idx_file_info(std::move(idx_file_info)),
81
3.65k
              _tablet_id(tablet_id) {}
82
3.65k
    virtual ~IndexFileReader() = default;
83
84
    MOCK_FUNCTION Status init(int32_t read_buffer_size = config::inverted_index_read_buffer_size,
85
                              const io::IOContext* io_ctx = nullptr);
86
    MOCK_FUNCTION Result<std::unique_ptr<DorisCompoundReader, DirectoryDeleter>> open(
87
            const TabletIndex* index_meta, const io::IOContext* io_ctx = nullptr) const;
88
    // Opens one BLOB logical index of kind kBkd: resolves its named sub-files
89
    // (bkd_data / bkd_index / bkd_nulls) into extents through the CONTAINER's own
90
    // directory and hands back a reader bound to this IndexFileReader's file.
91
    // The caller must keep this IndexFileReader alive for the reader's lifetime,
92
    // exactly as open_snii_index requires.
93
    Result<std::unique_ptr<doris::snii::bkd::BkdSearcher>> open_snii_bkd_index(
94
            const TabletIndex* index_meta, const io::IOContext* io_ctx) const;
95
    Result<std::unique_ptr<doris::snii::reader::LogicalIndexReader>> open_snii_index(
96
            const TabletIndex* index_meta, const io::IOContext* io_ctx = nullptr,
97
            doris::snii::reader::LogicalIndexOpenMode open_mode =
98
                    doris::snii::reader::LogicalIndexOpenMode::kQuery) const;
99
    // SNII only: opens one text logical index by its directory key.
100
    Result<std::unique_ptr<doris::snii::reader::LogicalIndexReader>> open_snii_logical_index(
101
            uint64_t index_id, std::string_view suffix, const io::IOContext* io_ctx,
102
            doris::snii::reader::LogicalIndexOpenMode open_mode) const;
103
    // SNII only: every entry of the container directory, text and blob kinds alike.
104
    Result<std::vector<doris::snii::format::LogicalIndexMetadataRef>> snii_logical_indexes() const;
105
    // SNII only: the kind of one directory entry, nothing when the directory has no such entry.
106
    // A directory can hold thousands of VARIANT paths, so a lookup does not copy it.
107
    Result<std::optional<doris::snii::format::LogicalIndexKind>> snii_logical_index_kind(
108
            uint64_t index_id, std::string_view suffix) const;
109
    // SNII only: reads the CoreMetadata of one text logical index with the caller's IO context.
110
    Status snii_core_metadata(uint64_t index_id, std::string_view suffix,
111
                              doris::snii::format::CoreMetadata* out,
112
                              const io::IOContext* io_ctx = nullptr) const;
113
    // SNII only: builds the fully validated inheritance view of this container
114
    // for a BUILD INDEX rewrite. `segment_doc_count` is the segment's row count;
115
    // every kept logical index must agree with it.
116
    Status prepare_snii_rewrite_snapshot(
117
            const std::vector<doris::snii::reader::LogicalIndexKey>& keep,
118
            uint64_t segment_doc_count, doris::snii::reader::SniiRewriteSnapshot* out) const;
119
    // SNII only: the raw byte source backing this container, handed to
120
    // SniiCompoundWriter::inherit for the sequential prefix copy.
121
4
    doris::snii::io::FileReader* snii_io_reader() const { return _snii_file_reader.get(); }
122
    // SNII only: true when the opened container holds a blob logical index
123
    // (BKD / ANN). False when this reader opened no SNII container at all.
124
3
    bool snii_has_blob_index() const {
125
3
        std::shared_lock<std::shared_mutex> lock(_mutex);
126
3
        return _snii_segment_reader != nullptr && _snii_segment_reader->has_blob_index();
127
3
    }
128
    void debug_file_entries();
129
    std::string get_index_file_cache_key(const TabletIndex* index_meta) const;
130
    std::string get_index_file_path(const TabletIndex* index_meta) const;
131
    Status index_file_exist(const TabletIndex* index_meta, bool* res) const;
132
    Status has_null(const TabletIndex* index_meta, bool* res) const;
133
    Result<InvertedIndexDirectoryMap> get_all_directories();
134
    // open file v2, init _stream
135
19
    int64_t get_inverted_file_size() const {
136
19
        if (_storage_format == InvertedIndexStorageFormatPB::SNII) {
137
10
            return _snii_file_reader == nullptr ? 0 : _snii_file_reader->size();
138
10
        }
139
9
        return _stream == nullptr ? 0 : _stream->length();
140
19
    }
141
39
    const std::string& get_index_path_prefix() const { return _index_path_prefix; }
142
2.79k
    InvertedIndexStorageFormatPB get_storage_format() const { return _storage_format; }
143
    friend IndexFileWriter;
144
145
protected:
146
    Status _init_from(int32_t read_buffer_size, const io::IOContext* io_ctx);
147
    Status _init_snii(const io::IOContext* io_ctx);
148
    Result<std::unique_ptr<DorisCompoundReader, DirectoryDeleter>> _open(
149
            int64_t index_id, const std::string& index_suffix,
150
            const io::IOContext* io_ctx = nullptr) const;
151
152
private:
153
    IndicesEntriesMap _indices_entries;
154
    std::unique_ptr<CL_NS(store)::IndexInput> _stream = nullptr;
155
    std::shared_ptr<snii_doris::DorisSniiFileReader> _snii_file_reader;
156
    std::unique_ptr<doris::snii::reader::SniiSegmentReader> _snii_segment_reader;
157
    const io::FileSystemSPtr _fs;
158
    std::string _index_path_prefix;
159
    int32_t _read_buffer_size = -1;
160
    InvertedIndexStorageFormatPB _storage_format;
161
    mutable std::shared_mutex _mutex; // Use mutable for const read operations
162
    bool _inited = false;
163
    InvertedIndexFileInfo _idx_file_info;
164
    int64_t _tablet_id = -1;
165
};
166
167
} // namespace segment_v2
168
} // namespace doris