Skip to content

Commit

Permalink
CacheActivityLogger, component to log cache activity into a file
Browse files Browse the repository at this point in the history
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 facebook#2295

Differential Revision: D5063826

Pulled By: IslamAbdelRahman

fbshipit-source-id: f3b5daed8b201987c9a071146ddd5c5740a2dd8c
  • Loading branch information
IslamAbdelRahman authored and facebook-github-bot committed Jul 28, 2017
1 parent 6083bc7 commit 50a9691
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,7 @@ set(TESTS
utilities/persistent_cache/persistent_cache_test.cc
utilities/redis/redis_lists_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/transactions/optimistic_transaction_test.cc
utilities/transactions/transaction_test.cc
Expand Down
14 changes: 14 additions & 0 deletions include/rocksdb/utilities/sim_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <memory>
#include <string>
#include "rocksdb/cache.h"
#include "rocksdb/env.h"
#include "rocksdb/slice.h"
#include "rocksdb/statistics.h"
#include "rocksdb/status.h"
Expand Down Expand Up @@ -67,6 +68,19 @@ class SimCache : public Cache {
// String representation of the statistics of the simcache
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:
SimCache(const SimCache&);
SimCache& operator=(const SimCache&);
Expand Down
157 changes: 157 additions & 0 deletions utilities/simulator_cache/sim_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,144 @@
#include <atomic>
#include "monitoring/statistics.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 {

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
class SimCacheImpl : public SimCache {
public:
Expand Down Expand Up @@ -48,6 +182,9 @@ class SimCacheImpl : public SimCache {
} else {
key_only_cache_->Release(h);
}

cache_activity_logger_.ReportAdd(key, charge);

return cache_->Insert(key, value, charge, deleter, handle, priority);
}

Expand All @@ -61,6 +198,9 @@ class SimCacheImpl : public SimCache {
inc_miss_counter();
RecordTick(stats, SIM_BLOCK_CACHE_MISS);
}

cache_activity_logger_.ReportLookup(key);

return cache_->Lookup(key, stats);
}

Expand Down Expand Up @@ -158,12 +298,29 @@ class SimCacheImpl : public SimCache {
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:
std::shared_ptr<Cache> cache_;
std::shared_ptr<Cache> key_only_cache_;
std::atomic<uint64_t> miss_times_;
std::atomic<uint64_t> hit_times_;
Statistics* stats_;
CacheActivityLogger cache_activity_logger_;

void inc_miss_counter() {
miss_times_.fetch_add(1, std::memory_order_relaxed);
}
Expand Down
71 changes: 71 additions & 0 deletions utilities/simulator_cache/sim_cache_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,77 @@ TEST_F(SimCacheTest, SimCache) {
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

int main(int argc, char** argv) {
Expand Down

0 comments on commit 50a9691

Please sign in to comment.