Coverage Report

Created: 2026-04-14 05:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/index/index_page.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 <butil/macros.h>
21
#include <gen_cpp/segment_v2.pb.h>
22
#include <glog/logging.h>
23
#include <stdint.h>
24
25
#include <cstddef>
26
#include <vector>
27
28
#include "common/status.h"
29
#include "storage/metadata_adder.h"
30
#include "storage/segment/page_pointer.h"
31
#include "util/faststring.h"
32
#include "util/slice.h"
33
34
namespace doris {
35
namespace segment_v2 {
36
37
// IndexPage is the building block for IndexedColumn's ordinal index and value index.
38
// It is used to guide searching for a particular key to the data page containing it.
39
// We use the same general format for all index pages, regardless of the data type and node type (leaf or internal)
40
//   IndexPageBody := IndexEntry^NumEntry
41
//   IndexEntry := KeyLength(vint), Byte^KeyLength, PageOffset(vlong), PageSize(vint)
42
//
43
// IndexPageFooterPB records NumEntry and type (leaf/internal) of the index page.
44
// For leaf, IndexKey records the first/smallest key of the data page PagePointer points to.
45
// For internal, IndexKey records the first/smallest key of the next-level index page PagePointer points to.
46
//
47
// All keys are treated as binary string and compared with memcpy. Keys of other data type are encoded first by
48
// KeyCoder, e.g., ordinal index's original key type is uint64_t but is encoded to binary string.
49
class IndexPageBuilder {
50
public:
51
    explicit IndexPageBuilder(size_t index_page_size, bool is_leaf)
52
1.74M
            : _index_page_size(index_page_size), _is_leaf(is_leaf) {}
53
54
    void add(const Slice& key, const PagePointer& ptr);
55
56
    bool is_full() const;
57
58
1.84M
    size_t count() const { return _count; }
59
60
    void finish(OwnedSlice* body, PageFooterPB* footer);
61
62
45.4k
    uint64_t size() { return _buffer.size(); }
63
64
    // Return the key of the first entry in this index block.
65
    // The pointed-to data is only valid until the next call to this builder.
66
    Status get_first_key(Slice* key) const;
67
68
0
    void reset() {
69
0
        _finished = false;
70
0
        _buffer.clear();
71
0
        _count = 0;
72
0
    }
73
74
private:
75
    DISALLOW_COPY_AND_ASSIGN(IndexPageBuilder);
76
    const size_t _index_page_size;
77
    const bool _is_leaf;
78
    bool _finished = false;
79
    faststring _buffer;
80
    uint32_t _count = 0;
81
};
82
83
class IndexPageReader : public MetadataAdder<IndexPageReader> {
84
public:
85
2.96M
    IndexPageReader() : _parsed(false) {}
86
87
    Status parse(const Slice& body, const IndexPageFooterPB& footer);
88
89
3.91M
    size_t count() const {
90
3.91M
        DCHECK(_parsed);
91
3.91M
        return _footer.num_entries();
92
3.91M
    }
93
94
0
    bool is_leaf() const {
95
0
        DCHECK(_parsed);
96
0
        return _footer.type() == IndexPageFooterPB::LEAF;
97
0
    }
98
99
20.0M
    const Slice& get_key(int idx) const {
100
20.0M
        DCHECK(_parsed);
101
20.0M
        DCHECK(idx >= 0 && idx < _footer.num_entries());
102
20.0M
        return _keys[idx];
103
20.0M
    }
104
105
6.04M
    const PagePointer& get_value(int idx) const {
106
6.04M
        DCHECK(_parsed);
107
6.04M
        DCHECK(idx >= 0 && idx < _footer.num_entries());
108
6.04M
        return _values[idx];
109
6.04M
    }
110
111
    void reset();
112
113
private:
114
    int64_t get_metadata_size() const override;
115
116
    bool _parsed;
117
118
    IndexPageFooterPB _footer;
119
    std::vector<Slice> _keys;
120
    std::vector<PagePointer> _values;
121
};
122
123
class IndexPageIterator {
124
public:
125
8.62M
    explicit IndexPageIterator(const IndexPageReader* reader) : _reader(reader), _pos(0) {}
126
127
    // Find the largest index entry whose key is <= search_key.
128
    // Return OK status when such entry exists.
129
    // Return ENTRY_NOT_FOUND when no such entry is found (all keys > search_key).
130
    // Return other error status otherwise.
131
    Status seek_at_or_before(const Slice& search_key);
132
133
254
    void seek_to_first() { _pos = 0; }
134
135
    // Move to the next index entry.
136
    // Return true on success, false when no more entries can be read.
137
2.51k
    bool move_next() {
138
2.51k
        _pos++;
139
2.51k
        if (_pos >= _reader->count()) {
140
0
            return false;
141
0
        }
142
2.51k
        return true;
143
2.51k
    }
144
145
    // Return true when has next page.
146
618
    bool has_next() { return (_pos + 1) < _reader->count(); }
147
148
0
    const Slice& current_key() const { return _reader->get_key(cast_set<int>(_pos)); }
149
150
3.87M
    const PagePointer& current_page_pointer() const {
151
3.87M
        return _reader->get_value(cast_set<int>(_pos));
152
3.87M
    }
153
154
private:
155
    const IndexPageReader* _reader = nullptr;
156
157
    size_t _pos;
158
};
159
160
} // namespace segment_v2
161
} // namespace doris