Coverage Report

Created: 2024-11-21 10:56

/root/doris/be/src/olap/page_cache.h
Line
Count
Source (jump to first uncovered line)
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 <stddef.h>
23
#include <stdint.h>
24
25
#include <memory>
26
#include <string>
27
#include <utility>
28
29
#include "olap/lru_cache.h"
30
#include "runtime/memory/lru_cache_policy.h"
31
#include "runtime/memory/mem_tracker_limiter.h"
32
#include "util/slice.h"
33
#include "vec/common/allocator.h"
34
#include "vec/common/allocator_fwd.h"
35
36
namespace doris {
37
38
class PageCacheHandle;
39
40
template <typename TAllocator>
41
class PageBase : private TAllocator, public LRUCacheValueBase {
42
public:
43
    PageBase() = default;
44
    PageBase(size_t b, bool use_cache, segment_v2::PageTypePB page_type);
45
    PageBase(const PageBase&) = delete;
46
    PageBase& operator=(const PageBase&) = delete;
47
    ~PageBase() override;
48
49
36.7k
    char* data() { return _data; }
_ZN5doris8PageBaseI9AllocatorILb0ELb0ELb0E22DefaultMemoryAllocatorEE4dataEv
Line
Count
Source
49
36.7k
    char* data() { return _data; }
Unexecuted instantiation: _ZN5doris8PageBaseI9AllocatorILb1ELb0ELb0E22DefaultMemoryAllocatorEE4dataEv
50
214
    size_t size() { return _size; }
_ZN5doris8PageBaseI9AllocatorILb0ELb0ELb0E22DefaultMemoryAllocatorEE4sizeEv
Line
Count
Source
50
214
    size_t size() { return _size; }
Unexecuted instantiation: _ZN5doris8PageBaseI9AllocatorILb1ELb0ELb0E22DefaultMemoryAllocatorEE4sizeEv
51
27.0k
    size_t capacity() { return _capacity; }
_ZN5doris8PageBaseI9AllocatorILb0ELb0ELb0E22DefaultMemoryAllocatorEE8capacityEv
Line
Count
Source
51
27.0k
    size_t capacity() { return _capacity; }
Unexecuted instantiation: _ZN5doris8PageBaseI9AllocatorILb1ELb0ELb0E22DefaultMemoryAllocatorEE8capacityEv
52
53
15.6k
    void reset_size(size_t n) {
54
15.6k
        DCHECK(n <= _capacity);
55
15.6k
        _size = n;
56
15.6k
    }
Unexecuted instantiation: _ZN5doris8PageBaseI9AllocatorILb1ELb0ELb0E22DefaultMemoryAllocatorEE10reset_sizeEm
_ZN5doris8PageBaseI9AllocatorILb0ELb0ELb0E22DefaultMemoryAllocatorEE10reset_sizeEm
Line
Count
Source
53
15.6k
    void reset_size(size_t n) {
54
15.6k
        DCHECK(n <= _capacity);
55
15.6k
        _size = n;
56
15.6k
    }
57
58
private:
59
    char* _data = nullptr;
60
    // Effective size, smaller than capacity, such as data page remove checksum suffix.
61
    size_t _size = 0;
62
    size_t _capacity = 0;
63
    std::shared_ptr<MemTrackerLimiter> _mem_tracker_by_allocator;
64
};
65
66
using DataPage = PageBase<Allocator<false>>;
67
68
// Wrapper around Cache, and used for cache page of column data
69
// in Segment.
70
// TODO(zc): We should add some metric to see cache hit/miss rate.
71
class StoragePageCache {
72
public:
73
    // The unique key identifying entries in the page cache.
74
    // Each cached page corresponds to a specific offset within
75
    // a file.
76
    //
77
    // TODO(zc): Now we use file name(std::string) as a part of
78
    // key, which is not efficient. We should make it better later
79
    struct CacheKey {
80
        CacheKey(std::string fname_, size_t fsize_, int64_t offset_)
81
16.3k
                : fname(std::move(fname_)), fsize(fsize_), offset(offset_) {}
82
        std::string fname;
83
        size_t fsize;
84
        int64_t offset;
85
86
        // Encode to a flat binary which can be used as LRUCache's key
87
10.6k
        std::string encode() const {
88
10.6k
            std::string key_buf(fname);
89
10.6k
            key_buf.append((char*)&fsize, sizeof(fsize));
90
10.6k
            key_buf.append((char*)&offset, sizeof(offset));
91
10.6k
            return key_buf;
92
10.6k
        }
93
    };
94
95
    class DataPageCache : public LRUCachePolicy {
96
    public:
97
        DataPageCache(size_t capacity, uint32_t num_shards)
98
                : LRUCachePolicy(CachePolicy::CacheType::DATA_PAGE_CACHE, capacity,
99
                                 LRUCacheType::SIZE, config::data_page_cache_stale_sweep_time_sec,
100
3
                                 num_shards) {}
101
    };
102
103
    class IndexPageCache : public LRUCachePolicy {
104
    public:
105
        IndexPageCache(size_t capacity, uint32_t num_shards)
106
                : LRUCachePolicy(CachePolicy::CacheType::INDEXPAGE_CACHE, capacity,
107
                                 LRUCacheType::SIZE, config::index_page_cache_stale_sweep_time_sec,
108
3
                                 num_shards) {}
109
    };
110
111
    class PKIndexPageCache : public LRUCachePolicy {
112
    public:
113
        PKIndexPageCache(size_t capacity, uint32_t num_shards)
114
                : LRUCachePolicy(CachePolicy::CacheType::PK_INDEX_PAGE_CACHE, capacity,
115
                                 LRUCacheType::SIZE,
116
4
                                 config::pk_index_page_cache_stale_sweep_time_sec, num_shards) {}
117
    };
118
119
    static constexpr uint32_t kDefaultNumShards = 16;
120
121
    // Create global instance of this class
122
    static StoragePageCache* create_global_cache(size_t capacity, int32_t index_cache_percentage,
123
                                                 int64_t pk_index_cache_capacity,
124
                                                 uint32_t num_shards = kDefaultNumShards);
125
126
    // Return global instance.
127
    // Client should call create_global_cache before.
128
21.5k
    static StoragePageCache* instance() { return ExecEnv::GetInstance()->get_storage_page_cache(); }
129
130
    StoragePageCache(size_t capacity, int32_t index_cache_percentage,
131
                     int64_t pk_index_cache_capacity, uint32_t num_shards);
132
133
    // Lookup the given page in the cache.
134
    //
135
    // If the page is found, the cache entry will be written into handle.
136
    // PageCacheHandle will release cache entry to cache when it
137
    // destructs.
138
    //
139
    // Cache type selection is determined by page_type argument
140
    //
141
    // Return true if entry is found, otherwise return false.
142
    bool lookup(const CacheKey& key, PageCacheHandle* handle, segment_v2::PageTypePB page_type);
143
144
    // Insert a page with key into this cache.
145
    // Given handle will be set to valid reference.
146
    // This function is thread-safe, and when two clients insert two same key
147
    // concurrently, this function can assure that only one page is cached.
148
    // The in_memory page will have higher priority.
149
    void insert(const CacheKey& key, DataPage* data, PageCacheHandle* handle,
150
                segment_v2::PageTypePB page_type, bool in_memory = false);
151
152
5.66k
    std::shared_ptr<MemTrackerLimiter> mem_tracker(segment_v2::PageTypePB page_type) {
153
5.66k
        return _get_page_cache(page_type)->mem_tracker();
154
5.66k
    }
155
156
private:
157
    StoragePageCache();
158
159
    int32_t _index_cache_percentage = 0;
160
    std::unique_ptr<DataPageCache> _data_page_cache;
161
    std::unique_ptr<IndexPageCache> _index_page_cache;
162
    // Cache data for primary key index data page, seperated from data
163
    // page cache to make it for flexible. we need this cache When construct
164
    // delete bitmap in unique key with mow
165
    std::unique_ptr<PKIndexPageCache> _pk_index_page_cache;
166
167
16.3k
    LRUCachePolicy* _get_page_cache(segment_v2::PageTypePB page_type) {
168
16.3k
        switch (page_type) {
169
740
        case segment_v2::DATA_PAGE: {
170
740
            return _data_page_cache.get();
171
0
        }
172
14.9k
        case segment_v2::INDEX_PAGE: {
173
14.9k
            return _index_page_cache.get();
174
0
        }
175
647
        case segment_v2::PRIMARY_KEY_INDEX_PAGE: {
176
647
            return _pk_index_page_cache.get();
177
0
        }
178
0
        default:
179
0
            LOG(FATAL) << "get error type page cache";
180
0
            __builtin_unreachable();
181
16.3k
        }
182
0
        LOG(FATAL) << "__builtin_unreachable";
183
0
        __builtin_unreachable();
184
16.3k
    }
185
};
186
187
// A handle for StoragePageCache entry. This class make it easy to handle
188
// Cache entry. Users don't need to release the obtained cache entry. This
189
// class will release the cache entry when it is destroyed.
190
class PageCacheHandle {
191
public:
192
74.0k
    PageCacheHandle() = default;
193
    PageCacheHandle(LRUCachePolicy* cache, Cache::Handle* handle)
194
5.75k
            : _cache(cache), _handle(handle) {}
195
100k
    ~PageCacheHandle() {
196
100k
        if (_handle != nullptr) {
197
5.75k
            _cache->release(_handle);
198
5.75k
        }
199
100k
    }
200
201
20.9k
    PageCacheHandle(PageCacheHandle&& other) noexcept {
202
        // we can use std::exchange if we switch c++14 on
203
20.9k
        std::swap(_cache, other._cache);
204
20.9k
        std::swap(_handle, other._handle);
205
20.9k
    }
206
207
32.4k
    PageCacheHandle& operator=(PageCacheHandle&& other) noexcept {
208
32.4k
        std::swap(_cache, other._cache);
209
32.4k
        std::swap(_handle, other._handle);
210
32.4k
        return *this;
211
32.4k
    }
212
213
0
    LRUCachePolicy* cache() const { return _cache; }
214
214
    Slice data() const {
215
214
        auto* cache_value = (DataPage*)_cache->value(_handle);
216
214
        return {cache_value->data(), cache_value->size()};
217
214
    }
218
219
private:
220
    LRUCachePolicy* _cache = nullptr;
221
    Cache::Handle* _handle = nullptr;
222
223
    // Don't allow copy and assign
224
    DISALLOW_COPY_AND_ASSIGN(PageCacheHandle);
225
};
226
227
} // namespace doris