cachable_entry.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. #pragma once
  10. #include <cassert>
  11. #include "port/likely.h"
  12. #include "rocksdb/cache.h"
  13. #include "rocksdb/cleanable.h"
  14. namespace ROCKSDB_NAMESPACE {
  15. // CachableEntry is a handle to an object that may or may not be in the block
  16. // cache. It is used in a variety of ways:
  17. //
  18. // 1) It may refer to an object in the block cache. In this case, cache_ and
  19. // cache_handle_ are not nullptr, and the cache handle has to be released when
  20. // the CachableEntry is destroyed (the lifecycle of the cached object, on the
  21. // other hand, is managed by the cache itself).
  22. // 2) It may uniquely own the (non-cached) object it refers to (examples include
  23. // a block read directly from file, or uncompressed blocks when there is a
  24. // compressed block cache but no uncompressed block cache). In such cases, the
  25. // object has to be destroyed when the CachableEntry is destroyed.
  26. // 3) It may point to an object (cached or not) without owning it. In this case,
  27. // no action is needed when the CachableEntry is destroyed.
  28. // 4) Sometimes, management of a cached or owned object (see #1 and #2 above)
  29. // is transferred to some other object. This is used for instance with iterators
  30. // (where cleanup is performed using a chain of cleanup functions,
  31. // see Cleanable).
  32. //
  33. // Because of #1 and #2 above, copying a CachableEntry is not safe (and thus not
  34. // allowed); hence, this is a move-only type, where a move transfers the
  35. // management responsibilities, and leaves the source object in an empty state.
  36. template <class T>
  37. class CachableEntry {
  38. public:
  39. CachableEntry() = default;
  40. CachableEntry(T* value, Cache* cache, Cache::Handle* cache_handle,
  41. bool own_value)
  42. : value_(value)
  43. , cache_(cache)
  44. , cache_handle_(cache_handle)
  45. , own_value_(own_value)
  46. {
  47. assert(value_ != nullptr ||
  48. (cache_ == nullptr && cache_handle_ == nullptr && !own_value_));
  49. assert(!!cache_ == !!cache_handle_);
  50. assert(!cache_handle_ || !own_value_);
  51. }
  52. CachableEntry(const CachableEntry&) = delete;
  53. CachableEntry& operator=(const CachableEntry&) = delete;
  54. CachableEntry(CachableEntry&& rhs)
  55. : value_(rhs.value_)
  56. , cache_(rhs.cache_)
  57. , cache_handle_(rhs.cache_handle_)
  58. , own_value_(rhs.own_value_)
  59. {
  60. assert(value_ != nullptr ||
  61. (cache_ == nullptr && cache_handle_ == nullptr && !own_value_));
  62. assert(!!cache_ == !!cache_handle_);
  63. assert(!cache_handle_ || !own_value_);
  64. rhs.ResetFields();
  65. }
  66. CachableEntry& operator=(CachableEntry&& rhs) {
  67. if (UNLIKELY(this == &rhs)) {
  68. return *this;
  69. }
  70. ReleaseResource();
  71. value_ = rhs.value_;
  72. cache_ = rhs.cache_;
  73. cache_handle_ = rhs.cache_handle_;
  74. own_value_ = rhs.own_value_;
  75. assert(value_ != nullptr ||
  76. (cache_ == nullptr && cache_handle_ == nullptr && !own_value_));
  77. assert(!!cache_ == !!cache_handle_);
  78. assert(!cache_handle_ || !own_value_);
  79. rhs.ResetFields();
  80. return *this;
  81. }
  82. ~CachableEntry() {
  83. ReleaseResource();
  84. }
  85. bool IsEmpty() const {
  86. return value_ == nullptr && cache_ == nullptr && cache_handle_ == nullptr &&
  87. !own_value_;
  88. }
  89. bool IsCached() const {
  90. assert(!!cache_ == !!cache_handle_);
  91. return cache_handle_ != nullptr;
  92. }
  93. T* GetValue() const { return value_; }
  94. Cache* GetCache() const { return cache_; }
  95. Cache::Handle* GetCacheHandle() const { return cache_handle_; }
  96. bool GetOwnValue() const { return own_value_; }
  97. void Reset() {
  98. ReleaseResource();
  99. ResetFields();
  100. }
  101. void TransferTo(Cleanable* cleanable) {
  102. if (cleanable) {
  103. if (cache_handle_ != nullptr) {
  104. assert(cache_ != nullptr);
  105. cleanable->RegisterCleanup(&ReleaseCacheHandle, cache_, cache_handle_);
  106. } else if (own_value_) {
  107. cleanable->RegisterCleanup(&DeleteValue, value_, nullptr);
  108. }
  109. }
  110. ResetFields();
  111. }
  112. void SetOwnedValue(T* value) {
  113. assert(value != nullptr);
  114. if (UNLIKELY(value_ == value && own_value_)) {
  115. assert(cache_ == nullptr && cache_handle_ == nullptr);
  116. return;
  117. }
  118. Reset();
  119. value_ = value;
  120. own_value_ = true;
  121. }
  122. void SetUnownedValue(T* value) {
  123. assert(value != nullptr);
  124. if (UNLIKELY(value_ == value && cache_ == nullptr &&
  125. cache_handle_ == nullptr && !own_value_)) {
  126. return;
  127. }
  128. Reset();
  129. value_ = value;
  130. assert(!own_value_);
  131. }
  132. void SetCachedValue(T* value, Cache* cache, Cache::Handle* cache_handle) {
  133. assert(value != nullptr);
  134. assert(cache != nullptr);
  135. assert(cache_handle != nullptr);
  136. if (UNLIKELY(value_ == value && cache_ == cache &&
  137. cache_handle_ == cache_handle && !own_value_)) {
  138. return;
  139. }
  140. Reset();
  141. value_ = value;
  142. cache_ = cache;
  143. cache_handle_ = cache_handle;
  144. assert(!own_value_);
  145. }
  146. private:
  147. void ReleaseResource() {
  148. if (LIKELY(cache_handle_ != nullptr)) {
  149. assert(cache_ != nullptr);
  150. cache_->Release(cache_handle_);
  151. } else if (own_value_) {
  152. delete value_;
  153. }
  154. }
  155. void ResetFields() {
  156. value_ = nullptr;
  157. cache_ = nullptr;
  158. cache_handle_ = nullptr;
  159. own_value_ = false;
  160. }
  161. static void ReleaseCacheHandle(void* arg1, void* arg2) {
  162. Cache* const cache = static_cast<Cache*>(arg1);
  163. assert(cache);
  164. Cache::Handle* const cache_handle = static_cast<Cache::Handle*>(arg2);
  165. assert(cache_handle);
  166. cache->Release(cache_handle);
  167. }
  168. static void DeleteValue(void* arg1, void* /* arg2 */) {
  169. delete static_cast<T*>(arg1);
  170. }
  171. private:
  172. T* value_ = nullptr;
  173. Cache* cache_ = nullptr;
  174. Cache::Handle* cache_handle_ = nullptr;
  175. bool own_value_ = false;
  176. };
  177. } // namespace ROCKSDB_NAMESPACE