Coverage Report

Created: 2026-08-17 23:49

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