cache.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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) 2011 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. #include "rocksdb/cache.h"
  10. #include "cache/lru_cache.h"
  11. #include "rocksdb/secondary_cache.h"
  12. #include "rocksdb/utilities/customizable_util.h"
  13. #include "rocksdb/utilities/options_type.h"
  14. #include "util/string_util.h"
  15. namespace ROCKSDB_NAMESPACE {
  16. const Cache::CacheItemHelper kNoopCacheItemHelper{};
  17. static std::unordered_map<std::string, OptionTypeInfo>
  18. lru_cache_options_type_info = {
  19. {"capacity",
  20. {offsetof(struct LRUCacheOptions, capacity), OptionType::kSizeT,
  21. OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
  22. {"num_shard_bits",
  23. {offsetof(struct LRUCacheOptions, num_shard_bits), OptionType::kInt,
  24. OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
  25. {"strict_capacity_limit",
  26. {offsetof(struct LRUCacheOptions, strict_capacity_limit),
  27. OptionType::kBoolean, OptionVerificationType::kNormal,
  28. OptionTypeFlags::kMutable}},
  29. {"high_pri_pool_ratio",
  30. {offsetof(struct LRUCacheOptions, high_pri_pool_ratio),
  31. OptionType::kDouble, OptionVerificationType::kNormal,
  32. OptionTypeFlags::kMutable}},
  33. {"low_pri_pool_ratio",
  34. {offsetof(struct LRUCacheOptions, low_pri_pool_ratio),
  35. OptionType::kDouble, OptionVerificationType::kNormal,
  36. OptionTypeFlags::kMutable}},
  37. };
  38. static std::unordered_map<std::string, OptionTypeInfo>
  39. comp_sec_cache_options_type_info = {
  40. {"capacity",
  41. {offsetof(struct CompressedSecondaryCacheOptions, capacity),
  42. OptionType::kSizeT, OptionVerificationType::kNormal,
  43. OptionTypeFlags::kMutable}},
  44. {"num_shard_bits",
  45. {offsetof(struct CompressedSecondaryCacheOptions, num_shard_bits),
  46. OptionType::kInt, OptionVerificationType::kNormal,
  47. OptionTypeFlags::kMutable}},
  48. {"compression_type",
  49. {offsetof(struct CompressedSecondaryCacheOptions, compression_type),
  50. OptionType::kCompressionType, OptionVerificationType::kNormal,
  51. OptionTypeFlags::kMutable}},
  52. {"compress_format_version",
  53. {offsetof(struct CompressedSecondaryCacheOptions,
  54. compress_format_version),
  55. OptionType::kUInt32T, OptionVerificationType::kNormal,
  56. OptionTypeFlags::kMutable}},
  57. {"enable_custom_split_merge",
  58. {offsetof(struct CompressedSecondaryCacheOptions,
  59. enable_custom_split_merge),
  60. OptionType::kBoolean, OptionVerificationType::kNormal,
  61. OptionTypeFlags::kMutable}},
  62. };
  63. namespace {
  64. static void NoopDelete(Cache::ObjectPtr /*obj*/,
  65. MemoryAllocator* /*allocator*/) {
  66. assert(false);
  67. }
  68. static size_t SliceSize(Cache::ObjectPtr obj) {
  69. return static_cast<Slice*>(obj)->size();
  70. }
  71. static Status SliceSaveTo(Cache::ObjectPtr from_obj, size_t from_offset,
  72. size_t length, char* out) {
  73. const Slice& slice = *static_cast<Slice*>(from_obj);
  74. std::memcpy(out, slice.data() + from_offset, length);
  75. return Status::OK();
  76. }
  77. static Status NoopCreate(const Slice& /*data*/, CompressionType /*type*/,
  78. CacheTier /*source*/, Cache::CreateContext* /*ctx*/,
  79. MemoryAllocator* /*allocator*/,
  80. Cache::ObjectPtr* /*out_obj*/,
  81. size_t* /*out_charge*/) {
  82. assert(false);
  83. return Status::NotSupported();
  84. }
  85. static Cache::CacheItemHelper kBasicCacheItemHelper(CacheEntryRole::kMisc,
  86. &NoopDelete);
  87. } // namespace
  88. const Cache::CacheItemHelper kSliceCacheItemHelper{
  89. CacheEntryRole::kMisc, &NoopDelete, &SliceSize,
  90. &SliceSaveTo, &NoopCreate, &kBasicCacheItemHelper,
  91. };
  92. Status SecondaryCache::CreateFromString(
  93. const ConfigOptions& config_options, const std::string& value,
  94. std::shared_ptr<SecondaryCache>* result) {
  95. if (value.find("compressed_secondary_cache://") == 0) {
  96. std::string args = value;
  97. args.erase(0, std::strlen("compressed_secondary_cache://"));
  98. Status status;
  99. std::shared_ptr<SecondaryCache> sec_cache;
  100. CompressedSecondaryCacheOptions sec_cache_opts;
  101. status = OptionTypeInfo::ParseStruct(config_options, "",
  102. &comp_sec_cache_options_type_info, "",
  103. args, &sec_cache_opts);
  104. if (status.ok()) {
  105. sec_cache = NewCompressedSecondaryCache(sec_cache_opts);
  106. }
  107. if (status.ok()) {
  108. result->swap(sec_cache);
  109. }
  110. return status;
  111. } else {
  112. return LoadSharedObject<SecondaryCache>(config_options, value, result);
  113. }
  114. }
  115. Status Cache::CreateFromString(const ConfigOptions& config_options,
  116. const std::string& value,
  117. std::shared_ptr<Cache>* result) {
  118. Status status;
  119. std::shared_ptr<Cache> cache;
  120. if (StartsWith(value, "null")) {
  121. cache = nullptr;
  122. } else if (value.find("://") == std::string::npos) {
  123. if (value.find('=') == std::string::npos) {
  124. cache = NewLRUCache(ParseSizeT(value));
  125. } else {
  126. LRUCacheOptions cache_opts;
  127. status = OptionTypeInfo::ParseStruct(config_options, "",
  128. &lru_cache_options_type_info, "",
  129. value, &cache_opts);
  130. if (status.ok()) {
  131. cache = NewLRUCache(cache_opts);
  132. }
  133. }
  134. if (status.ok()) {
  135. result->swap(cache);
  136. }
  137. } else {
  138. status = LoadSharedObject<Cache>(config_options, value, result);
  139. }
  140. return status;
  141. }
  142. bool Cache::AsyncLookupHandle::IsReady() {
  143. return pending_handle == nullptr || pending_handle->IsReady();
  144. }
  145. bool Cache::AsyncLookupHandle::IsPending() { return pending_handle != nullptr; }
  146. Cache::Handle* Cache::AsyncLookupHandle::Result() {
  147. assert(!IsPending());
  148. return result_handle;
  149. }
  150. void Cache::StartAsyncLookup(AsyncLookupHandle& async_handle) {
  151. async_handle.found_dummy_entry = false; // in case re-used
  152. assert(!async_handle.IsPending());
  153. async_handle.result_handle =
  154. Lookup(async_handle.key, async_handle.helper, async_handle.create_context,
  155. async_handle.priority, async_handle.stats);
  156. }
  157. Cache::Handle* Cache::Wait(AsyncLookupHandle& async_handle) {
  158. WaitAll(&async_handle, 1);
  159. return async_handle.Result();
  160. }
  161. void Cache::WaitAll(AsyncLookupHandle* async_handles, size_t count) {
  162. for (size_t i = 0; i < count; ++i) {
  163. if (async_handles[i].IsPending()) {
  164. // If a pending handle gets here, it should be marked at "to be handled
  165. // by a caller" by that caller erasing the pending_cache on it.
  166. assert(async_handles[i].pending_cache == nullptr);
  167. }
  168. }
  169. }
  170. void Cache::SetEvictionCallback(EvictionCallback&& fn) {
  171. // Overwriting non-empty with non-empty could indicate a bug
  172. assert(!eviction_callback_ || !fn);
  173. eviction_callback_ = std::move(fn);
  174. }
  175. } // namespace ROCKSDB_NAMESPACE