Coverage Report

Created: 2026-03-14 06:50

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
54.7k
void IndexPageBuilder::add(const Slice& key, const PagePointer& ptr) {
32
54.7k
    DCHECK(!_finished) << "must reset() after finish() to add new entry";
33
54.7k
    put_length_prefixed_slice(&_buffer, key);
34
54.7k
    ptr.encode_to(&_buffer);
35
54.7k
    _count++;
36
54.7k
}
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
1.67k
void IndexPageBuilder::finish(OwnedSlice* body, PageFooterPB* footer) {
44
1.67k
    DCHECK(!_finished) << "already called finish()";
45
1.67k
    *body = _buffer.build();
46
47
1.67k
    footer->set_type(INDEX_PAGE);
48
1.67k
    footer->set_uncompressed_size(cast_set<uint32_t>(body->slice().get_size()));
49
1.67k
    footer->mutable_index_page_footer()->set_num_entries(_count);
50
1.67k
    footer->mutable_index_page_footer()->set_type(_is_leaf ? IndexPageFooterPB::LEAF
51
1.67k
                                                           : IndexPageFooterPB::INTERNAL);
52
1.67k
}
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
1.74k
int64_t IndexPageReader::get_metadata_size() const {
69
1.74k
    return sizeof(IndexPageReader) + _footer.ByteSizeLong();
70
1.74k
}
71
72
1.74k
Status IndexPageReader::parse(const Slice& body, const IndexPageFooterPB& footer) {
73
1.74k
    _footer = footer;
74
1.74k
    size_t num_entries = _footer.num_entries();
75
76
1.74k
    Slice input(body);
77
22.2k
    for (int i = 0; i < num_entries; ++i) {
78
20.4k
        Slice key;
79
20.4k
        PagePointer value;
80
20.4k
        if (!get_length_prefixed_slice(&input, &key)) {
81
0
            return Status::InternalError("Data corruption");
82
0
        }
83
20.4k
        if (!value.decode_from(&input)) {
84
0
            return Status::InternalError("Data corruption");
85
0
        }
86
20.4k
        _keys.push_back(key);
87
20.4k
        _values.push_back(value);
88
20.4k
    }
89
90
1.74k
    update_metadata_size();
91
1.74k
    _parsed = true;
92
1.74k
    return Status::OK();
93
1.74k
}
94
///////////////////////////////////////////////////////////////////////////////
95
96
140
Status IndexPageIterator::seek_at_or_before(const Slice& search_key) {
97
140
    int32_t left = 0;
98
140
    auto right = cast_set<int32_t>(_reader->count() - 1);
99
388
    while (left <= right) {
100
276
        int32_t mid = left + (right - left) / 2;
101
276
        int cmp = search_key.compare(_reader->get_key(mid));
102
276
        if (cmp < 0) {
103
82
            right = mid - 1;
104
194
        } else if (cmp > 0) {
105
166
            left = mid + 1;
106
166
        } else {
107
28
            _pos = mid;
108
28
            return Status::OK();
109
28
        }
110
276
    }
111
    // no exact match, the insertion point is `left`
112
112
    if (left == 0) {
113
        // search key is smaller than all keys
114
0
        return Status::Error<ErrorCode::ENTRY_NOT_FOUND>(
115
0
                "given key is smaller than all keys in page");
116
0
    }
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
112
    _pos = left - 1;
120
112
    return Status::OK();
121
112
}
122
123
#include "common/compile_check_end.h"
124
} // namespace segment_v2
125
} // namespace doris