volatile_tier_impl.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // Copyright (c) 2013, 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. #include "utilities/persistent_cache/volatile_tier_impl.h"
  7. #include <string>
  8. namespace ROCKSDB_NAMESPACE {
  9. void VolatileCacheTier::DeleteCacheData(VolatileCacheTier::CacheData* data) {
  10. assert(data);
  11. delete data;
  12. }
  13. VolatileCacheTier::~VolatileCacheTier() { index_.Clear(&DeleteCacheData); }
  14. PersistentCache::StatsType VolatileCacheTier::Stats() {
  15. std::map<std::string, double> stat;
  16. stat.insert({"persistent_cache.volatile_cache.hits",
  17. static_cast<double>(stats_.cache_hits_)});
  18. stat.insert({"persistent_cache.volatile_cache.misses",
  19. static_cast<double>(stats_.cache_misses_)});
  20. stat.insert({"persistent_cache.volatile_cache.inserts",
  21. static_cast<double>(stats_.cache_inserts_)});
  22. stat.insert({"persistent_cache.volatile_cache.evicts",
  23. static_cast<double>(stats_.cache_evicts_)});
  24. stat.insert({"persistent_cache.volatile_cache.hit_pct",
  25. static_cast<double>(stats_.CacheHitPct())});
  26. stat.insert({"persistent_cache.volatile_cache.miss_pct",
  27. static_cast<double>(stats_.CacheMissPct())});
  28. auto out = PersistentCacheTier::Stats();
  29. out.push_back(stat);
  30. return out;
  31. }
  32. Status VolatileCacheTier::Insert(const Slice& page_key, const char* data,
  33. const size_t size) {
  34. // precondition
  35. assert(data);
  36. assert(size);
  37. // increment the size
  38. size_ += size;
  39. // check if we have overshot the limit, if so evict some space
  40. while (size_ > max_size_) {
  41. if (!Evict()) {
  42. // unable to evict data, we give up so we don't spike read
  43. // latency
  44. assert(size_ >= size);
  45. size_ -= size;
  46. return Status::TryAgain("Unable to evict any data");
  47. }
  48. }
  49. assert(size_ >= size);
  50. // insert order: LRU, followed by index
  51. std::string key(page_key.data(), page_key.size());
  52. std::string value(data, size);
  53. std::unique_ptr<CacheData> cache_data(
  54. new CacheData(std::move(key), std::move(value)));
  55. bool ok = index_.Insert(cache_data.get());
  56. if (!ok) {
  57. // decrement the size that we incremented ahead of time
  58. assert(size_ >= size);
  59. size_ -= size;
  60. // failed to insert to cache, block already in cache
  61. return Status::TryAgain("key already exists in volatile cache");
  62. }
  63. cache_data.release();
  64. stats_.cache_inserts_++;
  65. return Status::OK();
  66. }
  67. Status VolatileCacheTier::Lookup(const Slice& page_key,
  68. std::unique_ptr<char[]>* result,
  69. size_t* size) {
  70. CacheData key(std::move(page_key.ToString()));
  71. CacheData* kv;
  72. bool ok = index_.Find(&key, &kv);
  73. if (ok) {
  74. // set return data
  75. result->reset(new char[kv->value.size()]);
  76. memcpy(result->get(), kv->value.c_str(), kv->value.size());
  77. *size = kv->value.size();
  78. // drop the reference on cache data
  79. kv->refs_--;
  80. // update stats
  81. stats_.cache_hits_++;
  82. return Status::OK();
  83. }
  84. stats_.cache_misses_++;
  85. if (next_tier()) {
  86. return next_tier()->Lookup(page_key, result, size);
  87. }
  88. return Status::NotFound("key not found in volatile cache");
  89. }
  90. bool VolatileCacheTier::Erase(const Slice& /*key*/) {
  91. assert(!"not supported");
  92. return true;
  93. }
  94. bool VolatileCacheTier::Evict() {
  95. CacheData* edata = index_.Evict();
  96. if (!edata) {
  97. // not able to evict any object
  98. return false;
  99. }
  100. stats_.cache_evicts_++;
  101. // push the evicted object to the next level
  102. if (next_tier()) {
  103. // TODO: Should the insert error be ignored?
  104. Status s = next_tier()->Insert(Slice(edata->key), edata->value.c_str(),
  105. edata->value.size());
  106. s.PermitUncheckedError();
  107. }
  108. // adjust size and destroy data
  109. size_ -= edata->value.size();
  110. delete edata;
  111. return true;
  112. }
  113. } // namespace ROCKSDB_NAMESPACE