Coverage Report

Created: 2026-03-12 17:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/index/index_page.cpp
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
#include "storage/index/index_page.h"
19
20
#include <gen_cpp/segment_v2.pb.h>
21
22
#include <algorithm>
23
#include <ostream>
24
25
#include "util/coding.h"
26
27
namespace doris {
28
namespace segment_v2 {
29
#include "common/compile_check_begin.h"
30
31
1.82M
void IndexPageBuilder::add(const Slice& key, const PagePointer& ptr) {
32
18.4E
    DCHECK(!_finished) << "must reset() after finish() to add new entry";
33
1.82M
    put_length_prefixed_slice(&_buffer, key);
34
1.82M
    ptr.encode_to(&_buffer);
35
1.82M
    _count++;
36
1.82M
}
37
38
0
bool IndexPageBuilder::is_full() const {
39
    // estimate size of IndexPageFooterPB to be 16
40
0
    return _buffer.size() + 16 > _index_page_size;
41
0
}
42
43
13.3k
void IndexPageBuilder::finish(OwnedSlice* body, PageFooterPB* footer) {
44
13.3k
    DCHECK(!_finished) << "already called finish()";
45
13.3k
    *body = _buffer.build();
46
47
13.3k
    footer->set_type(INDEX_PAGE);
48
13.3k
    footer->set_uncompressed_size(cast_set<uint32_t>(body->slice().get_size()));
49
13.3k
    footer->mutable_index_page_footer()->set_num_entries(_count);
50
13.3k
    footer->mutable_index_page_footer()->set_type(_is_leaf ? IndexPageFooterPB::LEAF
51
18.4E
                                                           : IndexPageFooterPB::INTERNAL);
52
13.3k
}
53
54
0
Status IndexPageBuilder::get_first_key(Slice* key) const {
55
0
    if (_count == 0) {
56
0
        return Status::Error<ErrorCode::ENTRY_NOT_FOUND>("index page is empty");
57
0
    }
58
0
    Slice input(_buffer);
59
0
    if (get_length_prefixed_slice(&input, key)) {
60
0
        return Status::OK();
61
0
    } else {
62
0
        return Status::Corruption("can't decode first key");
63
0
    }
64
0
}
65
66
///////////////////////////////////////////////////////////////////////////////
67
68
185k
int64_t IndexPageReader::get_metadata_size() const {
69
185k
    return sizeof(IndexPageReader) + _footer.ByteSizeLong();
70
185k
}
71
72
185k
Status IndexPageReader::parse(const Slice& body, const IndexPageFooterPB& footer) {
73
185k
    _footer = footer;
74
185k
    size_t num_entries = _footer.num_entries();
75
76
185k
    Slice input(body);
77
3.61M
    for (int i = 0; i < num_entries; ++i) {
78
3.42M
        Slice key;
79
3.42M
        PagePointer value;
80
3.42M
        if (!get_length_prefixed_slice(&input, &key)) {
81
0
            return Status::InternalError("Data corruption");
82
0
        }
83
3.42M
        if (!value.decode_from(&input)) {
84
0
            return Status::InternalError("Data corruption");
85
0
        }
86
3.42M
        _keys.push_back(key);
87
3.42M
        _values.push_back(value);
88
3.42M
    }
89
90
185k
    update_metadata_size();
91
185k
    _parsed = true;
92
185k
    return Status::OK();
93
185k
}
94
///////////////////////////////////////////////////////////////////////////////
95
96
3.86M
Status IndexPageIterator::seek_at_or_before(const Slice& search_key) {
97
3.86M
    int32_t left = 0;
98
3.86M
    auto right = cast_set<int32_t>(_reader->count() - 1);
99
22.0M
    while (left <= right) {
100
18.0M
        int32_t mid = left + (right - left) / 2;
101
18.0M
        int cmp = search_key.compare(_reader->get_key(mid));
102
18.0M
        if (cmp < 0) {
103
6.88M
            right = mid - 1;
104
11.2M
        } else if (cmp > 0) {
105
11.2M
            left = mid + 1;
106
18.4E
        } else {
107
18.4E
            _pos = mid;
108
18.4E
            return Status::OK();
109
18.4E
        }
110
18.0M
    }
111
    // no exact match, the insertion point is `left`
112
3.98M
    if (left == 0) {
113
        // search key is smaller than all keys
114
253
        return Status::Error<ErrorCode::ENTRY_NOT_FOUND>(
115
253
                "given key is smaller than all keys in page");
116
253
    }
117
    // index entry records the first key of the indexed page,
118
    // therefore the first page with keys >= searched key is the one before the insertion point
119
3.98M
    _pos = left - 1;
120
3.98M
    return Status::OK();
121
3.98M
}
122
123
#include "common/compile_check_end.h"
124
} // namespace segment_v2
125
} // namespace doris