From 8537cca439bc7e8d3456ce59838994d274a7452f Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Sat, 18 Aug 2018 17:59:31 -0700 Subject: [PATCH] ircd::db: Improvements to cache interface. --- include/ircd/db/cache.h | 32 +++++-- ircd/db.cc | 193 +++++++++++++++++++++++++++++++++------- 2 files changed, 183 insertions(+), 42 deletions(-) diff --git a/include/ircd/db/cache.h b/include/ircd/db/cache.h index d66a968f1..87f529765 100644 --- a/include/ircd/db/cache.h +++ b/include/ircd/db/cache.h @@ -34,19 +34,35 @@ namespace ircd::db size_t usage(const rocksdb::Cache *const &); // Test if key exists - bool exists(rocksdb::Cache &, const string_view &key); - bool exists(rocksdb::Cache *const &, const string_view &key); + bool exists(const rocksdb::Cache &, const string_view &key); + bool exists(const rocksdb::Cache *const &, const string_view &key); + + // Iterate the cache entries. + using cache_closure = std::function; + void for_each(const rocksdb::Cache &, const cache_closure &); + void for_each(const rocksdb::Cache *const &, const cache_closure &); + + // Manually cache a key/value directly + bool insert(rocksdb::Cache &, const string_view &key, unique_buffer); + bool insert(rocksdb::Cache *const &, const string_view &key, unique_buffer); + + // Manually cache a copy of key/value + bool insert(rocksdb::Cache &, const string_view &key, const string_view &value); + bool insert(rocksdb::Cache *const &, const string_view &key, const string_view &value); // Remove key if it exists - void remove(rocksdb::Cache &, const string_view &key); - void remove(rocksdb::Cache *const &, const string_view &key); + bool remove(rocksdb::Cache &, const string_view &key); + bool remove(rocksdb::Cache *const &, const string_view &key); // Clear the cache (won't clear entries which are actively referenced) void clear(rocksdb::Cache &); void clear(rocksdb::Cache *const &); - // Iterate the cache entries. - using cache_closure = std::function; - void for_each(rocksdb::Cache &, const cache_closure &); - void for_each(rocksdb::Cache *const &, const cache_closure &); + // Read the key from disk into cache; yields when done; returns exists. + bool fetch(rocksdb::Cache &, column &, const string_view &key); + bool fetch(rocksdb::Cache *const &, column &, const string_view &key); + + // Read the key from disk into cache asynchronously; returns immediately. + void prefetch(rocksdb::Cache &, column &, const string_view &key); + void prefetch(rocksdb::Cache *const &, column &, const string_view &key); } diff --git a/ircd/db.cc b/ircd/db.cc index b0e7a1e1f..eabe4d0e9 100644 --- a/ircd/db.cc +++ b/ircd/db.cc @@ -5785,7 +5785,159 @@ ircd::db::_seek_(rocksdb::Iterator &it, // void -ircd::db::for_each(rocksdb::Cache *const &cache, +ircd::db::prefetch(rocksdb::Cache *const &cache, + column &column, + const string_view &key) +{ + if(cache) + return prefetch(*cache, column, key); +} + +void +ircd::db::prefetch(rocksdb::Cache &cache, + column &column, + const string_view &key) +{ + assert(0); +} + +bool +ircd::db::fetch(rocksdb::Cache *const &cache, + column &column, + const string_view &key) +{ + if(cache) + return fetch(*cache, column, key); +} + +bool +ircd::db::fetch(rocksdb::Cache &cache, + column &column, + const string_view &key) +{ + const db::gopts opts + { + // skip rocksdb inserting this into the columns cache twice. + &cache == db::cache(column) || &cache == db::cache_compressed(column)? + db::get::NO_CACHE: + (enum db::get)0 + }; + + const auto closure{[&cache, &key] + (const string_view &value) + { + insert(cache, key, value); + }}; + + return column(key, std::nothrow, closure, opts); +} + +void +ircd::db::clear(rocksdb::Cache *const &cache) +{ + if(cache) + return clear(*cache); +} + +void +ircd::db::clear(rocksdb::Cache &cache) +{ + cache.EraseUnRefEntries(); +} + +bool +ircd::db::remove(rocksdb::Cache *const &cache, + const string_view &key) +{ + if(cache) + return remove(*cache, key); +} + +bool +ircd::db::remove(rocksdb::Cache &cache, + const string_view &key) +{ + cache.Erase(slice(key)); + return true; +} + +bool +ircd::db::insert(rocksdb::Cache *const &cache, + const string_view &key, + const string_view &value) +{ + if(cache) + return insert(*cache, key, value); +} + +bool +ircd::db::insert(rocksdb::Cache &cache, + const string_view &key, + const string_view &value) +{ + unique_buffer buf + { + const_buffer{value} + }; + + return insert(cache, key, std::move(buf)); +} + +bool +ircd::db::insert(rocksdb::Cache *const &cache, + const string_view &key, + unique_buffer value) +{ + if(cache) + return insert(*cache, key, std::move(value)); +} + +bool +ircd::db::insert(rocksdb::Cache &cache, + const string_view &key, + unique_buffer value) +{ + static const auto deleter{[] + (const rocksdb::Slice &key, void *const value) + { + if(!value) + return; + + const rocksdb::Slice *const &s + { + reinterpret_cast(value) + }; + + const char *const &buf + { + reinterpret_cast(data(slice(*s))) + }; + + delete[] buf; + delete s; + }}; + + auto s + { + std::make_unique(data(value), size(value)) + }; + + // Note that because of the nullptr handle argument below, rocksdb + // will run the deleter if the insert throws; otherwise these + // operations have to be moved below the insert so the cleanup can + // happen out here. Right now this is all just here gratuitiously. + s.release(); + value.release(); + throw_on_error + { + cache.Insert(slice(key), s.get(), size(value), deleter, nullptr) + }; + + return true; +} + +void +ircd::db::for_each(const rocksdb::Cache *const &cache, const cache_closure &closure) { if(cache) @@ -5793,16 +5945,16 @@ ircd::db::for_each(rocksdb::Cache *const &cache, } void -ircd::db::for_each(rocksdb::Cache &cache, +ircd::db::for_each(const rocksdb::Cache &cache, const cache_closure &closure) { thread_local rocksdb::Cache *_cache; - _cache = &cache; + _cache = const_cast(&cache); thread_local const cache_closure *_closure; _closure = &closure; - cache.ApplyToAllCacheEntries([] + _cache->ApplyToAllCacheEntries([] (void *const data, const size_t charge) { assert(_cache); @@ -5828,45 +5980,18 @@ ircd::db::for_each(rocksdb::Cache &cache, false); } -void -ircd::db::clear(rocksdb::Cache *const &cache) -{ - if(cache) - clear(*cache); -} - -void -ircd::db::clear(rocksdb::Cache &cache) -{ - cache.EraseUnRefEntries(); -} - -void -ircd::db::remove(rocksdb::Cache *const &cache, - const string_view &key) -{ - if(cache) - remove(*cache, key); -} - -void -ircd::db::remove(rocksdb::Cache &cache, - const string_view &key) -{ - cache.Erase(slice(key)); -} - bool -ircd::db::exists(rocksdb::Cache *const &cache, +ircd::db::exists(const rocksdb::Cache *const &cache, const string_view &key) { return cache? exists(*cache, key) : false; } bool -ircd::db::exists(rocksdb::Cache &cache, +ircd::db::exists(const rocksdb::Cache &cache_, const string_view &key) { + auto &cache(const_cast(cache_)); const custom_ptr handle { cache.Lookup(slice(key)), [&cache](auto *const &handle)