Coverage Report

Created: 2026-04-10 10:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/cache/page_cache.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/cache/page_cache.h"
19
20
#include <gen_cpp/segment_v2.pb.h>
21
#include <glog/logging.h>
22
23
#include <ostream>
24
25
#include "runtime/exec_env.h"
26
27
namespace doris {
28
29
template <typename T>
30
MemoryTrackedPageBase<T>::MemoryTrackedPageBase(size_t size, bool use_cache,
31
                                                segment_v2::PageTypePB page_type)
32
2.28M
        : _size(size) {
33
2.28M
    if (use_cache) {
34
771k
        _mem_tracker_by_allocator = StoragePageCache::instance()->mem_tracker(page_type);
35
1.51M
    } else {
36
1.51M
        _mem_tracker_by_allocator =
37
1.51M
                thread_context()->thread_mem_tracker_mgr->limiter_mem_tracker_sptr();
38
1.51M
    }
39
2.28M
}
_ZN5doris21MemoryTrackedPageBaseISt10shared_ptrINS_10segment_v215SegmentFooterPBEEEC2EmbNS2_10PageTypePBE
Line
Count
Source
32
73.2k
        : _size(size) {
33
73.3k
    if (use_cache) {
34
73.3k
        _mem_tracker_by_allocator = StoragePageCache::instance()->mem_tracker(page_type);
35
18.4E
    } else {
36
18.4E
        _mem_tracker_by_allocator =
37
18.4E
                thread_context()->thread_mem_tracker_mgr->limiter_mem_tracker_sptr();
38
18.4E
    }
39
73.2k
}
_ZN5doris21MemoryTrackedPageBaseIPcEC2EmbNS_10segment_v210PageTypePBE
Line
Count
Source
32
2.21M
        : _size(size) {
33
2.21M
    if (use_cache) {
34
697k
        _mem_tracker_by_allocator = StoragePageCache::instance()->mem_tracker(page_type);
35
1.51M
    } else {
36
1.51M
        _mem_tracker_by_allocator =
37
1.51M
                thread_context()->thread_mem_tracker_mgr->limiter_mem_tracker_sptr();
38
1.51M
    }
39
2.21M
}
40
41
template <typename T>
42
MemoryTrackedPageBase<T>::MemoryTrackedPageBase(size_t size,
43
                                                std::shared_ptr<MemTrackerLimiter> mem_tracker)
44
32
        : _size(size), _mem_tracker_by_allocator(std::move(mem_tracker)) {}
45
46
MemoryTrackedPageWithPageEntity::MemoryTrackedPageWithPageEntity(size_t size, bool use_cache,
47
                                                                 segment_v2::PageTypePB page_type)
48
2.21M
        : MemoryTrackedPageBase<char*>(size, use_cache, page_type), _capacity(size) {
49
2.21M
    {
50
2.21M
        SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER(this->_mem_tracker_by_allocator);
51
2.21M
        this->_data = reinterpret_cast<char*>(
52
2.21M
                Allocator<false>::alloc(this->_capacity, ALLOCATOR_ALIGNMENT_16));
53
2.21M
    }
54
2.21M
}
55
56
MemoryTrackedPageWithPageEntity::MemoryTrackedPageWithPageEntity(
57
        size_t size, std::shared_ptr<MemTrackerLimiter> mem_tracker)
58
32
        : MemoryTrackedPageBase<char*>(size, std::move(mem_tracker)), _capacity(size) {
59
32
    {
60
32
        SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER(this->_mem_tracker_by_allocator);
61
32
        this->_data = reinterpret_cast<char*>(
62
32
                Allocator<false>::alloc(this->_capacity, ALLOCATOR_ALIGNMENT_16));
63
32
    }
64
32
}
65
66
2.12M
MemoryTrackedPageWithPageEntity::~MemoryTrackedPageWithPageEntity() {
67
2.12M
    if (this->_data != nullptr) {
68
2.12M
        DCHECK(this->_capacity != 0 && this->_size != 0);
69
2.12M
        SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER(this->_mem_tracker_by_allocator);
70
2.12M
        Allocator<false>::free(this->_data, this->_capacity);
71
2.12M
    }
72
2.12M
}
73
74
template <typename T>
75
MemoryTrackedPageWithPagePtr<T>::MemoryTrackedPageWithPagePtr(size_t size,
76
                                                              segment_v2::PageTypePB page_type)
77
73.2k
        : MemoryTrackedPageBase<std::shared_ptr<T>>(size, true, page_type) {
78
73.2k
    DCHECK(this->_size > 0);
79
73.2k
    this->_size = size;
80
73.2k
    this->_mem_tracker_by_allocator->consume(this->_size);
81
73.2k
}
82
83
template <typename T>
84
47.3k
MemoryTrackedPageWithPagePtr<T>::~MemoryTrackedPageWithPagePtr() {
85
47.3k
    DCHECK(this->_size > 0);
86
47.3k
    this->_mem_tracker_by_allocator->release(this->_size);
87
47.3k
}
88
89
StoragePageCache* StoragePageCache::create_global_cache(size_t capacity,
90
                                                        int32_t index_cache_percentage,
91
                                                        int64_t pk_index_cache_capacity,
92
6
                                                        uint32_t num_shards) {
93
6
    return new StoragePageCache(capacity, index_cache_percentage, pk_index_cache_capacity,
94
6
                                num_shards);
95
6
}
96
97
StoragePageCache::StoragePageCache(size_t capacity, int32_t index_cache_percentage,
98
                                   int64_t pk_index_cache_capacity, uint32_t num_shards)
99
14
        : _index_cache_percentage(index_cache_percentage) {
100
14
    size_t data_page_capacity = 0;
101
14
    size_t index_page_capacity = 0;
102
14
    if (index_cache_percentage == 0) {
103
3
        data_page_capacity = capacity;
104
11
    } else if (index_cache_percentage == 100) {
105
2
        index_page_capacity = capacity;
106
9
    } else if (index_cache_percentage > 0 && index_cache_percentage < 100) {
107
9
        data_page_capacity = capacity * (100 - index_cache_percentage) / 100;
108
9
        index_page_capacity = capacity * index_cache_percentage / 100;
109
9
    } else {
110
0
        CHECK(false) << "invalid index page cache percentage";
111
0
    }
112
113
14
    _data_page_cache = std::make_unique<DataPageCache>(data_page_capacity, num_shards);
114
14
    _index_page_cache = std::make_unique<IndexPageCache>(index_page_capacity, num_shards);
115
14
    _pk_index_page_cache = std::make_unique<PKIndexPageCache>(pk_index_cache_capacity, num_shards);
116
14
}
117
118
bool StoragePageCache::lookup(const CacheKey& key, PageCacheHandle* handle,
119
5.48M
                              segment_v2::PageTypePB page_type) {
120
5.48M
    auto* cache = _get_page_cache(page_type);
121
5.48M
    auto* lru_handle = cache->lookup(key.encode());
122
5.48M
    if (lru_handle == nullptr) {
123
500k
        return false;
124
500k
    }
125
4.98M
    *handle = PageCacheHandle(cache, lru_handle);
126
4.98M
    return true;
127
5.48M
}
128
129
void StoragePageCache::insert(const CacheKey& key, DataPage* data, PageCacheHandle* handle,
130
428k
                              segment_v2::PageTypePB page_type, bool in_memory) {
131
428k
    CachePriority priority = CachePriority::NORMAL;
132
428k
    if (in_memory) {
133
8
        priority = CachePriority::DURABLE;
134
8
    }
135
136
428k
    auto* cache = _get_page_cache(page_type);
137
428k
    auto* lru_handle = cache->insert(key.encode(), data, data->capacity(), 0, priority);
138
428k
    DCHECK(lru_handle != nullptr);
139
428k
    *handle = PageCacheHandle(cache, lru_handle);
140
428k
}
141
142
template <typename T>
143
void StoragePageCache::insert(const CacheKey& key, T data, size_t size, PageCacheHandle* handle,
144
73.3k
                              segment_v2::PageTypePB page_type, bool in_memory) {
145
73.3k
    static_assert(std::is_same<typename std::remove_cv<T>::type,
146
73.3k
                               std::shared_ptr<typename T::element_type>>::value,
147
73.3k
                  "Second argument must be a std::shared_ptr");
148
73.3k
    using ValueType = typename T::element_type; // Type that shared_ptr points to
149
150
73.3k
    CachePriority priority = CachePriority::NORMAL;
151
73.3k
    if (in_memory) {
152
0
        priority = CachePriority::DURABLE;
153
0
    }
154
155
73.3k
    auto* cache = _get_page_cache(page_type);
156
    // Lify cycle of page will be managed by StoragePageCache
157
73.3k
    auto page = std::make_unique<MemoryTrackedPageWithPagePtr<ValueType>>(size, page_type);
158
    // Lify cycle of data will be managed by StoragePageCache and user at the same time.
159
73.3k
    page->set_data(data);
160
161
73.3k
    auto* lru_handle = cache->insert(key.encode(), page.get(), size, 0, priority);
162
73.3k
    DCHECK(lru_handle != nullptr);
163
73.3k
    *handle = PageCacheHandle(cache, lru_handle);
164
    // Now page is managed by StoragePageCache.
165
73.3k
    page.release();
166
73.3k
}
167
168
4.91M
Slice PageCacheHandle::data() const {
169
4.91M
    auto* cache_value = (DataPage*)_cache->value(_handle);
170
4.91M
    return {cache_value->data(), cache_value->size()};
171
4.91M
}
172
173
template void StoragePageCache::insert(const CacheKey& key,
174
                                       std::shared_ptr<segment_v2::SegmentFooterPB> data,
175
                                       size_t size, PageCacheHandle* handle,
176
                                       segment_v2::PageTypePB page_type, bool in_memory);
177
178
template class MemoryTrackedPageWithPagePtr<segment_v2::SegmentFooterPB>;
179
180
} // namespace doris