CacheActivityLogger, component to log cache activity into a file
Summary: Simple component that will add a new entry in a log file every time we lookup/insert a key in SimCache. API: ``` SimCache::StartActivityLogging(<file_name>, <env>, <optional_max_size>) SimCache::StopActivityLogging() ``` Sending for review, Still need to add more comments. I was thinking about a better approach, but I ended up deciding I will use a mutex to sync the writes to the file, since this feature should not be heavily used and only used to collect info that will be analyzed offline. I think it's okay to hold the mutex every time we lookup/add to the SimCache. Closes https://github.com/facebook/rocksdb/pull/2295 Differential Revision: D5063826 Pulled By: IslamAbdelRahman fbshipit-source-id: f3b5daed8b201987c9a071146ddd5c5740a2dd8c
This commit is contained in:
parent
6083bc79f8
commit
50a969131f
@ -727,6 +727,7 @@ set(TESTS
|
|||||||
utilities/persistent_cache/persistent_cache_test.cc
|
utilities/persistent_cache/persistent_cache_test.cc
|
||||||
utilities/redis/redis_lists_test.cc
|
utilities/redis/redis_lists_test.cc
|
||||||
utilities/spatialdb/spatial_db_test.cc
|
utilities/spatialdb/spatial_db_test.cc
|
||||||
|
utilities/simulator_cache/sim_cache_test.cc
|
||||||
utilities/table_properties_collectors/compact_on_deletion_collector_test.cc
|
utilities/table_properties_collectors/compact_on_deletion_collector_test.cc
|
||||||
utilities/transactions/optimistic_transaction_test.cc
|
utilities/transactions/optimistic_transaction_test.cc
|
||||||
utilities/transactions/transaction_test.cc
|
utilities/transactions/transaction_test.cc
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "rocksdb/cache.h"
|
#include "rocksdb/cache.h"
|
||||||
|
#include "rocksdb/env.h"
|
||||||
#include "rocksdb/slice.h"
|
#include "rocksdb/slice.h"
|
||||||
#include "rocksdb/statistics.h"
|
#include "rocksdb/statistics.h"
|
||||||
#include "rocksdb/status.h"
|
#include "rocksdb/status.h"
|
||||||
@ -67,6 +68,19 @@ class SimCache : public Cache {
|
|||||||
// String representation of the statistics of the simcache
|
// String representation of the statistics of the simcache
|
||||||
virtual std::string ToString() const = 0;
|
virtual std::string ToString() const = 0;
|
||||||
|
|
||||||
|
// Start storing logs of the cache activity (Add/Lookup) into
|
||||||
|
// a file located at activity_log_file, max_logging_size option can be used to
|
||||||
|
// stop logging to the file automatically after reaching a specific size in
|
||||||
|
// bytes, a values of 0 disable this feature
|
||||||
|
virtual Status StartActivityLogging(const std::string& activity_log_file,
|
||||||
|
Env* env, uint64_t max_logging_size = 0) = 0;
|
||||||
|
|
||||||
|
// Stop cache activity logging if any
|
||||||
|
virtual void StopActivityLogging() = 0;
|
||||||
|
|
||||||
|
// Status of cache logging happening in background
|
||||||
|
virtual Status GetActivityLoggingStatus() = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SimCache(const SimCache&);
|
SimCache(const SimCache&);
|
||||||
SimCache& operator=(const SimCache&);
|
SimCache& operator=(const SimCache&);
|
||||||
|
@ -7,10 +7,144 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include "monitoring/statistics.h"
|
#include "monitoring/statistics.h"
|
||||||
#include "port/port.h"
|
#include "port/port.h"
|
||||||
|
#include "rocksdb/env.h"
|
||||||
|
#include "util/file_reader_writer.h"
|
||||||
|
#include "util/mutexlock.h"
|
||||||
|
#include "util/string_util.h"
|
||||||
|
|
||||||
namespace rocksdb {
|
namespace rocksdb {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
class CacheActivityLogger {
|
||||||
|
public:
|
||||||
|
CacheActivityLogger()
|
||||||
|
: activity_logging_enabled_(false), max_logging_size_(0) {}
|
||||||
|
|
||||||
|
~CacheActivityLogger() {
|
||||||
|
MutexLock l(&mutex_);
|
||||||
|
|
||||||
|
StopLoggingInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
Status StartLogging(const std::string& activity_log_file, Env* env,
|
||||||
|
uint64_t max_logging_size = 0) {
|
||||||
|
assert(activity_log_file != "");
|
||||||
|
assert(env != nullptr);
|
||||||
|
|
||||||
|
Status status;
|
||||||
|
EnvOptions env_opts;
|
||||||
|
std::unique_ptr<WritableFile> log_file;
|
||||||
|
|
||||||
|
MutexLock l(&mutex_);
|
||||||
|
|
||||||
|
// Stop existing logging if any
|
||||||
|
StopLoggingInternal();
|
||||||
|
|
||||||
|
// Open log file
|
||||||
|
status = env->NewWritableFile(activity_log_file, &log_file, env_opts);
|
||||||
|
if (!status.ok()) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
file_writer_.reset(new WritableFileWriter(std::move(log_file), env_opts));
|
||||||
|
|
||||||
|
max_logging_size_ = max_logging_size;
|
||||||
|
activity_logging_enabled_.store(true);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopLogging() {
|
||||||
|
MutexLock l(&mutex_);
|
||||||
|
|
||||||
|
StopLoggingInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportLookup(const Slice& key) {
|
||||||
|
if (activity_logging_enabled_.load() == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string log_line = "LOOKUP - " + key.ToString(true) + "\n";
|
||||||
|
|
||||||
|
// line format: "LOOKUP - <KEY>"
|
||||||
|
MutexLock l(&mutex_);
|
||||||
|
Status s = file_writer_->Append(log_line);
|
||||||
|
if (!s.ok() && bg_status_.ok()) {
|
||||||
|
bg_status_ = s;
|
||||||
|
}
|
||||||
|
if (MaxLoggingSizeReached() || !bg_status_.ok()) {
|
||||||
|
// Stop logging if we have reached the max file size or
|
||||||
|
// encountered an error
|
||||||
|
StopLoggingInternal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportAdd(const Slice& key, size_t size) {
|
||||||
|
if (activity_logging_enabled_.load() == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string log_line = "ADD - ";
|
||||||
|
log_line += key.ToString(true);
|
||||||
|
log_line += " - ";
|
||||||
|
AppendNumberTo(&log_line, size);
|
||||||
|
log_line += "\n";
|
||||||
|
|
||||||
|
// line format: "ADD - <KEY> - <KEY-SIZE>"
|
||||||
|
MutexLock l(&mutex_);
|
||||||
|
Status s = file_writer_->Append(log_line);
|
||||||
|
if (!s.ok() && bg_status_.ok()) {
|
||||||
|
bg_status_ = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaxLoggingSizeReached() || !bg_status_.ok()) {
|
||||||
|
// Stop logging if we have reached the max file size or
|
||||||
|
// encountered an error
|
||||||
|
StopLoggingInternal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Status& bg_status() {
|
||||||
|
MutexLock l(&mutex_);
|
||||||
|
return bg_status_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool MaxLoggingSizeReached() {
|
||||||
|
mutex_.AssertHeld();
|
||||||
|
|
||||||
|
return (max_logging_size_ > 0 &&
|
||||||
|
file_writer_->GetFileSize() >= max_logging_size_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopLoggingInternal() {
|
||||||
|
mutex_.AssertHeld();
|
||||||
|
|
||||||
|
if (!activity_logging_enabled_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
activity_logging_enabled_.store(false);
|
||||||
|
Status s = file_writer_->Close();
|
||||||
|
if (!s.ok() && bg_status_.ok()) {
|
||||||
|
bg_status_ = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mutex to sync writes to file_writer, and all following
|
||||||
|
// class data members
|
||||||
|
port::Mutex mutex_;
|
||||||
|
// Indicates if logging is currently enabled
|
||||||
|
// atomic to allow reads without mutex
|
||||||
|
std::atomic<bool> activity_logging_enabled_;
|
||||||
|
// When reached, we will stop logging and close the file
|
||||||
|
// Value of 0 means unlimited
|
||||||
|
uint64_t max_logging_size_;
|
||||||
|
std::unique_ptr<WritableFileWriter> file_writer_;
|
||||||
|
Status bg_status_;
|
||||||
|
};
|
||||||
|
|
||||||
// SimCacheImpl definition
|
// SimCacheImpl definition
|
||||||
class SimCacheImpl : public SimCache {
|
class SimCacheImpl : public SimCache {
|
||||||
public:
|
public:
|
||||||
@ -48,6 +182,9 @@ class SimCacheImpl : public SimCache {
|
|||||||
} else {
|
} else {
|
||||||
key_only_cache_->Release(h);
|
key_only_cache_->Release(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cache_activity_logger_.ReportAdd(key, charge);
|
||||||
|
|
||||||
return cache_->Insert(key, value, charge, deleter, handle, priority);
|
return cache_->Insert(key, value, charge, deleter, handle, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +198,9 @@ class SimCacheImpl : public SimCache {
|
|||||||
inc_miss_counter();
|
inc_miss_counter();
|
||||||
RecordTick(stats, SIM_BLOCK_CACHE_MISS);
|
RecordTick(stats, SIM_BLOCK_CACHE_MISS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cache_activity_logger_.ReportLookup(key);
|
||||||
|
|
||||||
return cache_->Lookup(key, stats);
|
return cache_->Lookup(key, stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,12 +298,29 @@ class SimCacheImpl : public SimCache {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Status StartActivityLogging(const std::string& activity_log_file,
|
||||||
|
Env* env,
|
||||||
|
uint64_t max_logging_size = 0) override {
|
||||||
|
return cache_activity_logger_.StartLogging(activity_log_file, env,
|
||||||
|
max_logging_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void StopActivityLogging() override {
|
||||||
|
cache_activity_logger_.StopLogging();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Status GetActivityLoggingStatus() override {
|
||||||
|
return cache_activity_logger_.bg_status();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Cache> cache_;
|
std::shared_ptr<Cache> cache_;
|
||||||
std::shared_ptr<Cache> key_only_cache_;
|
std::shared_ptr<Cache> key_only_cache_;
|
||||||
std::atomic<uint64_t> miss_times_;
|
std::atomic<uint64_t> miss_times_;
|
||||||
std::atomic<uint64_t> hit_times_;
|
std::atomic<uint64_t> hit_times_;
|
||||||
Statistics* stats_;
|
Statistics* stats_;
|
||||||
|
CacheActivityLogger cache_activity_logger_;
|
||||||
|
|
||||||
void inc_miss_counter() {
|
void inc_miss_counter() {
|
||||||
miss_times_.fetch_add(1, std::memory_order_relaxed);
|
miss_times_.fetch_add(1, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,77 @@ TEST_F(SimCacheTest, SimCache) {
|
|||||||
ASSERT_EQ(6, simCache->get_hit_counter());
|
ASSERT_EQ(6, simCache->get_hit_counter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SimCacheTest, SimCacheLogging) {
|
||||||
|
auto table_options = GetTableOptions();
|
||||||
|
auto options = GetOptions(table_options);
|
||||||
|
options.disable_auto_compactions = true;
|
||||||
|
std::shared_ptr<SimCache> sim_cache =
|
||||||
|
NewSimCache(NewLRUCache(1024 * 1024), 20000, 0);
|
||||||
|
table_options.block_cache = sim_cache;
|
||||||
|
options.table_factory.reset(new BlockBasedTableFactory(table_options));
|
||||||
|
Reopen(options);
|
||||||
|
|
||||||
|
int num_block_entries = 20;
|
||||||
|
for (int i = 0; i < num_block_entries; i++) {
|
||||||
|
Put(Key(i), "val");
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string log_file = test::TmpDir(env_) + "/cache_log.txt";
|
||||||
|
ASSERT_OK(sim_cache->StartActivityLogging(log_file, env_));
|
||||||
|
for (int i = 0; i < num_block_entries; i++) {
|
||||||
|
ASSERT_EQ(Get(Key(i)), "val");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < num_block_entries; i++) {
|
||||||
|
ASSERT_EQ(Get(Key(i)), "val");
|
||||||
|
}
|
||||||
|
sim_cache->StopActivityLogging();
|
||||||
|
ASSERT_OK(sim_cache->GetActivityLoggingStatus());
|
||||||
|
|
||||||
|
std::string file_contents = "";
|
||||||
|
ReadFileToString(env_, log_file, &file_contents);
|
||||||
|
|
||||||
|
int lookup_num = 0;
|
||||||
|
int add_num = 0;
|
||||||
|
std::string::size_type pos;
|
||||||
|
|
||||||
|
// count number of lookups
|
||||||
|
pos = 0;
|
||||||
|
while ((pos = file_contents.find("LOOKUP -", pos)) != std::string::npos) {
|
||||||
|
++lookup_num;
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// count number of additions
|
||||||
|
pos = 0;
|
||||||
|
while ((pos = file_contents.find("ADD -", pos)) != std::string::npos) {
|
||||||
|
++add_num;
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We asked for every block twice
|
||||||
|
ASSERT_EQ(lookup_num, num_block_entries * 2);
|
||||||
|
|
||||||
|
// We added every block only once, since the cache can hold all blocks
|
||||||
|
ASSERT_EQ(add_num, num_block_entries);
|
||||||
|
|
||||||
|
// Log things again but stop logging automatically after reaching 512 bytes
|
||||||
|
int max_size = 512;
|
||||||
|
ASSERT_OK(sim_cache->StartActivityLogging(log_file, env_, max_size));
|
||||||
|
for (int it = 0; it < 10; it++) {
|
||||||
|
for (int i = 0; i < num_block_entries; i++) {
|
||||||
|
ASSERT_EQ(Get(Key(i)), "val");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT_OK(sim_cache->GetActivityLoggingStatus());
|
||||||
|
|
||||||
|
uint64_t fsize = 0;
|
||||||
|
ASSERT_OK(env_->GetFileSize(log_file, &fsize));
|
||||||
|
// error margin of 100 bytes
|
||||||
|
ASSERT_LT(fsize, max_size + 100);
|
||||||
|
ASSERT_GT(fsize, max_size - 100);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace rocksdb
|
} // namespace rocksdb
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
Loading…
Reference in New Issue
Block a user