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