]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/table/block_based/cachable_entry.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / table / block_based / cachable_entry.h
CommitLineData
f67539c2
TL
1// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2// This source code is licensed under both the GPLv2 (found in the
3// COPYING file in the root directory) and Apache 2.0 License
4// (found in the LICENSE.Apache file in the root directory).
5//
6// Copyright (c) 2012 The LevelDB Authors. All rights reserved.
7// Use of this source code is governed by a BSD-style license that can be
8// found in the LICENSE file. See the AUTHORS file for names of contributors.
9
10#pragma once
11
12#include <cassert>
1e59de90 13
f67539c2
TL
14#include "port/likely.h"
15#include "rocksdb/cache.h"
16#include "rocksdb/cleanable.h"
17
18namespace ROCKSDB_NAMESPACE {
19
20// CachableEntry is a handle to an object that may or may not be in the block
21// cache. It is used in a variety of ways:
22//
23// 1) It may refer to an object in the block cache. In this case, cache_ and
24// cache_handle_ are not nullptr, and the cache handle has to be released when
25// the CachableEntry is destroyed (the lifecycle of the cached object, on the
26// other hand, is managed by the cache itself).
27// 2) It may uniquely own the (non-cached) object it refers to (examples include
28// a block read directly from file, or uncompressed blocks when there is a
29// compressed block cache but no uncompressed block cache). In such cases, the
30// object has to be destroyed when the CachableEntry is destroyed.
31// 3) It may point to an object (cached or not) without owning it. In this case,
32// no action is needed when the CachableEntry is destroyed.
33// 4) Sometimes, management of a cached or owned object (see #1 and #2 above)
34// is transferred to some other object. This is used for instance with iterators
35// (where cleanup is performed using a chain of cleanup functions,
36// see Cleanable).
37//
38// Because of #1 and #2 above, copying a CachableEntry is not safe (and thus not
39// allowed); hence, this is a move-only type, where a move transfers the
40// management responsibilities, and leaves the source object in an empty state.
41
42template <class T>
43class CachableEntry {
1e59de90 44 public:
f67539c2
TL
45 CachableEntry() = default;
46
47 CachableEntry(T* value, Cache* cache, Cache::Handle* cache_handle,
1e59de90
TL
48 bool own_value)
49 : value_(value),
50 cache_(cache),
51 cache_handle_(cache_handle),
52 own_value_(own_value) {
f67539c2 53 assert(value_ != nullptr ||
1e59de90 54 (cache_ == nullptr && cache_handle_ == nullptr && !own_value_));
f67539c2
TL
55 assert(!!cache_ == !!cache_handle_);
56 assert(!cache_handle_ || !own_value_);
57 }
58
59 CachableEntry(const CachableEntry&) = delete;
60 CachableEntry& operator=(const CachableEntry&) = delete;
61
1e59de90
TL
62 CachableEntry(CachableEntry&& rhs) noexcept
63 : value_(rhs.value_),
64 cache_(rhs.cache_),
65 cache_handle_(rhs.cache_handle_),
66 own_value_(rhs.own_value_) {
f67539c2 67 assert(value_ != nullptr ||
1e59de90 68 (cache_ == nullptr && cache_handle_ == nullptr && !own_value_));
f67539c2
TL
69 assert(!!cache_ == !!cache_handle_);
70 assert(!cache_handle_ || !own_value_);
71
72 rhs.ResetFields();
73 }
74
1e59de90 75 CachableEntry& operator=(CachableEntry&& rhs) noexcept {
f67539c2
TL
76 if (UNLIKELY(this == &rhs)) {
77 return *this;
78 }
79
80 ReleaseResource();
81
82 value_ = rhs.value_;
83 cache_ = rhs.cache_;
84 cache_handle_ = rhs.cache_handle_;
85 own_value_ = rhs.own_value_;
86
87 assert(value_ != nullptr ||
1e59de90 88 (cache_ == nullptr && cache_handle_ == nullptr && !own_value_));
f67539c2
TL
89 assert(!!cache_ == !!cache_handle_);
90 assert(!cache_handle_ || !own_value_);
91
92 rhs.ResetFields();
93
94 return *this;
95 }
96
1e59de90 97 ~CachableEntry() { ReleaseResource(); }
f67539c2
TL
98
99 bool IsEmpty() const {
100 return value_ == nullptr && cache_ == nullptr && cache_handle_ == nullptr &&
1e59de90 101 !own_value_;
f67539c2
TL
102 }
103
104 bool IsCached() const {
105 assert(!!cache_ == !!cache_handle_);
106
107 return cache_handle_ != nullptr;
108 }
109
110 T* GetValue() const { return value_; }
111 Cache* GetCache() const { return cache_; }
112 Cache::Handle* GetCacheHandle() const { return cache_handle_; }
113 bool GetOwnValue() const { return own_value_; }
114
115 void Reset() {
116 ReleaseResource();
117 ResetFields();
118 }
119
120 void TransferTo(Cleanable* cleanable) {
121 if (cleanable) {
122 if (cache_handle_ != nullptr) {
123 assert(cache_ != nullptr);
124 cleanable->RegisterCleanup(&ReleaseCacheHandle, cache_, cache_handle_);
125 } else if (own_value_) {
126 cleanable->RegisterCleanup(&DeleteValue, value_, nullptr);
127 }
128 }
129
130 ResetFields();
131 }
132
1e59de90
TL
133 void SetOwnedValue(std::unique_ptr<T>&& value) {
134 assert(value.get() != nullptr);
f67539c2 135
1e59de90 136 if (UNLIKELY(value_ == value.get() && own_value_)) {
f67539c2
TL
137 assert(cache_ == nullptr && cache_handle_ == nullptr);
138 return;
139 }
140
141 Reset();
142
1e59de90 143 value_ = value.release();
f67539c2
TL
144 own_value_ = true;
145 }
146
147 void SetUnownedValue(T* value) {
148 assert(value != nullptr);
149
150 if (UNLIKELY(value_ == value && cache_ == nullptr &&
151 cache_handle_ == nullptr && !own_value_)) {
152 return;
153 }
154
155 Reset();
156
157 value_ = value;
158 assert(!own_value_);
159 }
160
161 void SetCachedValue(T* value, Cache* cache, Cache::Handle* cache_handle) {
f67539c2
TL
162 assert(cache != nullptr);
163 assert(cache_handle != nullptr);
164
165 if (UNLIKELY(value_ == value && cache_ == cache &&
166 cache_handle_ == cache_handle && !own_value_)) {
167 return;
168 }
169
170 Reset();
171
172 value_ = value;
173 cache_ = cache;
174 cache_handle_ = cache_handle;
175 assert(!own_value_);
176 }
177
1e59de90
TL
178 void UpdateCachedValue() {
179 assert(cache_ != nullptr);
180 assert(cache_handle_ != nullptr);
181
182 value_ = static_cast<T*>(cache_->Value(cache_handle_));
183 }
184
185 bool IsReady() {
186 if (!own_value_) {
187 assert(cache_ != nullptr);
188 assert(cache_handle_ != nullptr);
189 return cache_->IsReady(cache_handle_);
190 }
191 return true;
192 }
193
194 private:
195 void ReleaseResource() noexcept {
f67539c2
TL
196 if (LIKELY(cache_handle_ != nullptr)) {
197 assert(cache_ != nullptr);
198 cache_->Release(cache_handle_);
199 } else if (own_value_) {
200 delete value_;
201 }
202 }
203
1e59de90 204 void ResetFields() noexcept {
f67539c2
TL
205 value_ = nullptr;
206 cache_ = nullptr;
207 cache_handle_ = nullptr;
208 own_value_ = false;
209 }
210
211 static void ReleaseCacheHandle(void* arg1, void* arg2) {
212 Cache* const cache = static_cast<Cache*>(arg1);
213 assert(cache);
214
215 Cache::Handle* const cache_handle = static_cast<Cache::Handle*>(arg2);
216 assert(cache_handle);
217
218 cache->Release(cache_handle);
219 }
220
221 static void DeleteValue(void* arg1, void* /* arg2 */) {
222 delete static_cast<T*>(arg1);
223 }
224
1e59de90 225 private:
f67539c2
TL
226 T* value_ = nullptr;
227 Cache* cache_ = nullptr;
228 Cache::Handle* cache_handle_ = nullptr;
229 bool own_value_ = false;
230};
231
232} // namespace ROCKSDB_NAMESPACE