]>
Commit | Line | Data |
---|---|---|
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 | ||
18 | namespace 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 | ||
42 | template <class T> | |
43 | class 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 |