]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/utilities/simulator_cache/sim_cache.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rocksdb / utilities / simulator_cache / sim_cache.cc
CommitLineData
7c673cae 1// Copyright (c) 2011-present, 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#include "rocksdb/utilities/sim_cache.h"
7#include <atomic>
8#include "monitoring/statistics.h"
9#include "port/port.h"
11fdf7f2
TL
10#include "rocksdb/env.h"
11#include "util/file_reader_writer.h"
12#include "util/mutexlock.h"
13#include "util/string_util.h"
7c673cae
FG
14
15namespace rocksdb {
16
17namespace {
11fdf7f2
TL
18
19class CacheActivityLogger {
20 public:
21 CacheActivityLogger()
22 : activity_logging_enabled_(false), max_logging_size_(0) {}
23
24 ~CacheActivityLogger() {
25 MutexLock l(&mutex_);
26
27 StopLoggingInternal();
28 }
29
30 Status StartLogging(const std::string& activity_log_file, Env* env,
31 uint64_t max_logging_size = 0) {
32 assert(activity_log_file != "");
33 assert(env != nullptr);
34
35 Status status;
36 EnvOptions env_opts;
37 std::unique_ptr<WritableFile> log_file;
38
39 MutexLock l(&mutex_);
40
41 // Stop existing logging if any
42 StopLoggingInternal();
43
44 // Open log file
45 status = env->NewWritableFile(activity_log_file, &log_file, env_opts);
46 if (!status.ok()) {
47 return status;
48 }
49 file_writer_.reset(new WritableFileWriter(std::move(log_file),
50 activity_log_file, env_opts));
51
52 max_logging_size_ = max_logging_size;
53 activity_logging_enabled_.store(true);
54
55 return status;
56 }
57
58 void StopLogging() {
59 MutexLock l(&mutex_);
60
61 StopLoggingInternal();
62 }
63
64 void ReportLookup(const Slice& key) {
65 if (activity_logging_enabled_.load() == false) {
66 return;
67 }
68
69 std::string log_line = "LOOKUP - " + key.ToString(true) + "\n";
70
71 // line format: "LOOKUP - <KEY>"
72 MutexLock l(&mutex_);
73 Status s = file_writer_->Append(log_line);
74 if (!s.ok() && bg_status_.ok()) {
75 bg_status_ = s;
76 }
77 if (MaxLoggingSizeReached() || !bg_status_.ok()) {
78 // Stop logging if we have reached the max file size or
79 // encountered an error
80 StopLoggingInternal();
81 }
82 }
83
84 void ReportAdd(const Slice& key, size_t size) {
85 if (activity_logging_enabled_.load() == false) {
86 return;
87 }
88
89 std::string log_line = "ADD - ";
90 log_line += key.ToString(true);
91 log_line += " - ";
92 AppendNumberTo(&log_line, size);
93 // @lint-ignore TXT2 T25377293 Grandfathered in
94 log_line += "\n";
95
96 // line format: "ADD - <KEY> - <KEY-SIZE>"
97 MutexLock l(&mutex_);
98 Status s = file_writer_->Append(log_line);
99 if (!s.ok() && bg_status_.ok()) {
100 bg_status_ = s;
101 }
102
103 if (MaxLoggingSizeReached() || !bg_status_.ok()) {
104 // Stop logging if we have reached the max file size or
105 // encountered an error
106 StopLoggingInternal();
107 }
108 }
109
110 Status& bg_status() {
111 MutexLock l(&mutex_);
112 return bg_status_;
113 }
114
115 private:
116 bool MaxLoggingSizeReached() {
117 mutex_.AssertHeld();
118
119 return (max_logging_size_ > 0 &&
120 file_writer_->GetFileSize() >= max_logging_size_);
121 }
122
123 void StopLoggingInternal() {
124 mutex_.AssertHeld();
125
126 if (!activity_logging_enabled_) {
127 return;
128 }
129
130 activity_logging_enabled_.store(false);
131 Status s = file_writer_->Close();
132 if (!s.ok() && bg_status_.ok()) {
133 bg_status_ = s;
134 }
135 }
136
137 // Mutex to sync writes to file_writer, and all following
138 // class data members
139 port::Mutex mutex_;
140 // Indicates if logging is currently enabled
141 // atomic to allow reads without mutex
142 std::atomic<bool> activity_logging_enabled_;
143 // When reached, we will stop logging and close the file
144 // Value of 0 means unlimited
145 uint64_t max_logging_size_;
146 std::unique_ptr<WritableFileWriter> file_writer_;
147 Status bg_status_;
148};
149
7c673cae
FG
150// SimCacheImpl definition
151class SimCacheImpl : public SimCache {
152 public:
153 // capacity for real cache (ShardedLRUCache)
154 // test_capacity for key only cache
155 SimCacheImpl(std::shared_ptr<Cache> cache, size_t sim_capacity,
156 int num_shard_bits)
157 : cache_(cache),
158 key_only_cache_(NewLRUCache(sim_capacity, num_shard_bits)),
159 miss_times_(0),
11fdf7f2
TL
160 hit_times_(0),
161 stats_(nullptr) {}
7c673cae
FG
162
163 virtual ~SimCacheImpl() {}
164 virtual void SetCapacity(size_t capacity) override {
165 cache_->SetCapacity(capacity);
166 }
167
168 virtual void SetStrictCapacityLimit(bool strict_capacity_limit) override {
169 cache_->SetStrictCapacityLimit(strict_capacity_limit);
170 }
171
172 virtual Status Insert(const Slice& key, void* value, size_t charge,
173 void (*deleter)(const Slice& key, void* value),
174 Handle** handle, Priority priority) override {
175 // The handle and value passed in are for real cache, so we pass nullptr
176 // to key_only_cache_ for both instead. Also, the deleter function pointer
177 // will be called by user to perform some external operation which should
178 // be applied only once. Thus key_only_cache accepts an empty function.
179 // *Lambda function without capture can be assgined to a function pointer
180 Handle* h = key_only_cache_->Lookup(key);
181 if (h == nullptr) {
182 key_only_cache_->Insert(key, nullptr, charge,
11fdf7f2 183 [](const Slice& /*k*/, void* /*v*/) {}, nullptr,
7c673cae
FG
184 priority);
185 } else {
186 key_only_cache_->Release(h);
187 }
11fdf7f2
TL
188
189 cache_activity_logger_.ReportAdd(key, charge);
190
7c673cae
FG
191 return cache_->Insert(key, value, charge, deleter, handle, priority);
192 }
193
194 virtual Handle* Lookup(const Slice& key, Statistics* stats) override {
195 Handle* h = key_only_cache_->Lookup(key);
196 if (h != nullptr) {
197 key_only_cache_->Release(h);
198 inc_hit_counter();
199 RecordTick(stats, SIM_BLOCK_CACHE_HIT);
200 } else {
201 inc_miss_counter();
202 RecordTick(stats, SIM_BLOCK_CACHE_MISS);
203 }
11fdf7f2
TL
204
205 cache_activity_logger_.ReportLookup(key);
206
7c673cae
FG
207 return cache_->Lookup(key, stats);
208 }
209
210 virtual bool Ref(Handle* handle) override { return cache_->Ref(handle); }
211
212 virtual bool Release(Handle* handle, bool force_erase = false) override {
213 return cache_->Release(handle, force_erase);
214 }
215
216 virtual void Erase(const Slice& key) override {
217 cache_->Erase(key);
218 key_only_cache_->Erase(key);
219 }
220
221 virtual void* Value(Handle* handle) override { return cache_->Value(handle); }
222
223 virtual uint64_t NewId() override { return cache_->NewId(); }
224
225 virtual size_t GetCapacity() const override { return cache_->GetCapacity(); }
226
227 virtual bool HasStrictCapacityLimit() const override {
228 return cache_->HasStrictCapacityLimit();
229 }
230
231 virtual size_t GetUsage() const override { return cache_->GetUsage(); }
232
233 virtual size_t GetUsage(Handle* handle) const override {
234 return cache_->GetUsage(handle);
235 }
236
237 virtual size_t GetPinnedUsage() const override {
238 return cache_->GetPinnedUsage();
239 }
240
241 virtual void DisownData() override {
242 cache_->DisownData();
243 key_only_cache_->DisownData();
244 }
245
246 virtual void ApplyToAllCacheEntries(void (*callback)(void*, size_t),
247 bool thread_safe) override {
248 // only apply to _cache since key_only_cache doesn't hold value
249 cache_->ApplyToAllCacheEntries(callback, thread_safe);
250 }
251
252 virtual void EraseUnRefEntries() override {
253 cache_->EraseUnRefEntries();
254 key_only_cache_->EraseUnRefEntries();
255 }
256
257 virtual size_t GetSimCapacity() const override {
258 return key_only_cache_->GetCapacity();
259 }
260 virtual size_t GetSimUsage() const override {
261 return key_only_cache_->GetUsage();
262 }
263 virtual void SetSimCapacity(size_t capacity) override {
264 key_only_cache_->SetCapacity(capacity);
265 }
266
267 virtual uint64_t get_miss_counter() const override {
268 return miss_times_.load(std::memory_order_relaxed);
269 }
270
271 virtual uint64_t get_hit_counter() const override {
272 return hit_times_.load(std::memory_order_relaxed);
273 }
274
275 virtual void reset_counter() override {
276 miss_times_.store(0, std::memory_order_relaxed);
277 hit_times_.store(0, std::memory_order_relaxed);
278 SetTickerCount(stats_, SIM_BLOCK_CACHE_HIT, 0);
279 SetTickerCount(stats_, SIM_BLOCK_CACHE_MISS, 0);
280 }
281
282 virtual std::string ToString() const override {
283 std::string res;
284 res.append("SimCache MISSes: " + std::to_string(get_miss_counter()) + "\n");
285 res.append("SimCache HITs: " + std::to_string(get_hit_counter()) + "\n");
286 char buff[350];
287 auto lookups = get_miss_counter() + get_hit_counter();
288 snprintf(buff, sizeof(buff), "SimCache HITRATE: %.2f%%\n",
289 (lookups == 0 ? 0 : get_hit_counter() * 100.0f / lookups));
290 res.append(buff);
291 return res;
292 }
293
294 virtual std::string GetPrintableOptions() const override {
295 std::string ret;
296 ret.reserve(20000);
297 ret.append(" cache_options:\n");
298 ret.append(cache_->GetPrintableOptions());
299 ret.append(" sim_cache_options:\n");
300 ret.append(key_only_cache_->GetPrintableOptions());
301 return ret;
302 }
303
11fdf7f2
TL
304 virtual Status StartActivityLogging(const std::string& activity_log_file,
305 Env* env,
306 uint64_t max_logging_size = 0) override {
307 return cache_activity_logger_.StartLogging(activity_log_file, env,
308 max_logging_size);
309 }
310
311 virtual void StopActivityLogging() override {
312 cache_activity_logger_.StopLogging();
313 }
314
315 virtual Status GetActivityLoggingStatus() override {
316 return cache_activity_logger_.bg_status();
317 }
318
7c673cae
FG
319 private:
320 std::shared_ptr<Cache> cache_;
321 std::shared_ptr<Cache> key_only_cache_;
322 std::atomic<uint64_t> miss_times_;
323 std::atomic<uint64_t> hit_times_;
324 Statistics* stats_;
11fdf7f2
TL
325 CacheActivityLogger cache_activity_logger_;
326
7c673cae
FG
327 void inc_miss_counter() {
328 miss_times_.fetch_add(1, std::memory_order_relaxed);
329 }
330 void inc_hit_counter() { hit_times_.fetch_add(1, std::memory_order_relaxed); }
331};
332
333} // end anonymous namespace
334
335// For instrumentation purpose, use NewSimCache instead
336std::shared_ptr<SimCache> NewSimCache(std::shared_ptr<Cache> cache,
337 size_t sim_capacity, int num_shard_bits) {
338 if (num_shard_bits >= 20) {
339 return nullptr; // the cache cannot be sharded into too many fine pieces
340 }
341 return std::make_shared<SimCacheImpl>(cache, sim_capacity, num_shard_bits);
342}
343
344} // end namespace rocksdb