volatile_tier_impl.cc 3.9 KB

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