From 277e573e4a30ed0b0e384a6308f6448b3a4f7280 Mon Sep 17 00:00:00 2001 From: Samuel Just Date: Mon, 1 Nov 2021 13:48:28 -0700 Subject: [PATCH] crimson/os/seastore/cache: add lru Signed-off-by: Samuel Just --- src/common/options/crimson.yaml.in | 5 + src/crimson/os/seastore/cache.cc | 44 ++++++-- src/crimson/os/seastore/cache.h | 100 ++++++++++++++++++ src/crimson/os/seastore/cached_extent.h | 5 + .../os/seastore/transaction_manager.cc | 4 +- 5 files changed, 150 insertions(+), 8 deletions(-) diff --git a/src/common/options/crimson.yaml.in b/src/common/options/crimson.yaml.in index d110842c75955..6ce7b68be0db8 100644 --- a/src/common/options/crimson.yaml.in +++ b/src/common/options/crimson.yaml.in @@ -75,3 +75,8 @@ options: level: dev desc: default logical address space reservation for seastore objects' metadata default: 16777216 +- name: seastore_cache_lru_size + type: size + level: advanced + desc: Size in bytes of extents to keep in cache. + default: 64_M diff --git a/src/crimson/os/seastore/cache.cc b/src/crimson/os/seastore/cache.cc index 2813864375629..6f7f6833f38d8 100644 --- a/src/crimson/os/seastore/cache.cc +++ b/src/crimson/os/seastore/cache.cc @@ -7,6 +7,7 @@ #include #include "crimson/os/seastore/logging.h" +#include "crimson/common/config_proxy.h" // included for get_extent_by_type #include "crimson/os/seastore/collection_manager/collection_flat_node.h" @@ -23,7 +24,9 @@ namespace crimson::os::seastore { Cache::Cache( ExtentReader &reader) - : reader(reader) + : reader(reader), + lru(crimson::common::get_conf( + "seastore_cache_lru_size")) { register_metrics(); } @@ -31,6 +34,7 @@ Cache::Cache( Cache::~Cache() { LOG_PREFIX(Cache::~Cache); + lru.clear(); for (auto &i: extents) { ERROR("extent {} still alive", i); } @@ -453,6 +457,20 @@ void Cache::register_metrics() stats.dirty_bytes, sm::description("total bytes of dirty extents") ), + sm::make_counter( + "cache_lru_size_bytes", + [this] { + return lru.get_current_contents_bytes(); + }, + sm::description("total bytes pinned by the lru") + ), + sm::make_counter( + "cache_lru_size_extents", + [this] { + return lru.get_current_contents_extents(); + }, + sm::description("total extents pinned by the lru") + ), } ); @@ -600,9 +618,9 @@ void Cache::add_extent(CachedExtentRef ref) if (ref->is_dirty()) { add_to_dirty(ref); - } else { - ceph_assert(!ref->primary_ref_list_hook.is_linked()); - } + } else if (!ref->is_placeholder()) { + lru.add_to_lru(*ref); + } DEBUG("extent {}", *ref); } @@ -614,6 +632,7 @@ void Cache::mark_dirty(CachedExtentRef ref) return; } + lru.remove_from_lru(*ref); add_to_dirty(ref); ref->state = CachedExtent::extent_state_t::DIRTY; @@ -646,7 +665,11 @@ void Cache::remove_extent(CachedExtentRef ref) LOG_PREFIX(Cache::remove_extent); DEBUG("extent {}", *ref); assert(ref->is_valid()); - remove_from_dirty(ref); + if (ref->is_dirty()) { + remove_from_dirty(ref); + } else { + lru.remove_from_lru(*ref); + } extents.erase(*ref); } @@ -658,7 +681,12 @@ void Cache::commit_retire_extent( DEBUGT("extent {}", t, *ref); assert(ref->is_valid()); - remove_from_dirty(ref); + // TODO: why does this duplicate remove_extent? + if (ref->is_dirty()) { + remove_from_dirty(ref); + } else { + lru.remove_from_lru(*ref); + } ref->dirty_from_or_retired_at = JOURNAL_SEQ_MAX; invalidate_extent(t, *ref); @@ -694,6 +722,7 @@ void Cache::commit_replace_extent( intrusive_ptr_release(&*prev); intrusive_ptr_add_ref(&*next); } else { + lru.remove_from_lru(*prev); add_to_dirty(next); } @@ -1147,7 +1176,7 @@ void Cache::init() { } root = new RootBlock(); root->state = CachedExtent::extent_state_t::CLEAN; - add_extent(root); + extents.insert(*root); } Cache::mkfs_iertr::future<> Cache::mkfs(Transaction &t) @@ -1173,6 +1202,7 @@ Cache::close_ertr::future<> Cache::close() intrusive_ptr_release(ptr); } assert(stats.dirty_bytes == 0); + clear_lru(); return close_ertr::now(); } diff --git a/src/crimson/os/seastore/cache.h b/src/crimson/os/seastore/cache.h index 08f2b6b350ccf..3181fa58cc824 100644 --- a/src/crimson/os/seastore/cache.h +++ b/src/crimson/os/seastore/cache.h @@ -280,6 +280,7 @@ public: "Found extent at offset {} in cache: {}", t, offset, *ret); t.add_to_read_set(ret); + touch_extent(*ret); return ret->wait_io().then([ret] { return get_extent_if_cached_iertr::make_ready_future< CachedExtentRef>(ret); @@ -330,6 +331,7 @@ public: DEBUGT( "Read extent at offset {} in cache: {}", t, offset, *ref); + touch_extent(*ref); t.add_to_read_set(ref); return get_extent_iertr::make_ready_future>( std::move(ref)); @@ -418,6 +420,7 @@ private: mark_transaction_conflicted(t, *ret.get()); return get_extent_ertr::make_ready_future(); } else { + touch_extent(*ret); t.add_to_read_set(ret); return get_extent_ertr::make_ready_future( std::move(ret)); @@ -474,6 +477,10 @@ public: return ret; } + void clear_lru() { + lru.clear(); + } + void mark_delayed_extent_inline( Transaction& t, LogicalCachedExtentRef& ref) { @@ -698,6 +705,91 @@ private: */ CachedExtent::list dirty; + /** + * lru + * + * holds references to recently used extents + */ + class LRU { + // max size (bytes) + const size_t capacity = 0; + + // current size (bytes) + size_t contents = 0; + + CachedExtent::list lru; + + void trim_to_capacity() { + while (contents > capacity) { + assert(lru.size() > 0); + remove_from_lru(lru.front()); + } + } + public: + LRU(size_t capacity) : capacity(capacity) {} + + size_t get_current_contents_bytes() const { + return contents; + } + + size_t get_current_contents_extents() const { + return lru.size(); + } + + void add_to_lru(CachedExtent &extent) { + assert( + extent.is_clean() && + !extent.is_pending() && + !extent.is_placeholder()); + + if (!extent.primary_ref_list_hook.is_linked()) { + contents += extent.get_length(); + intrusive_ptr_add_ref(&extent); + lru.push_back(extent); + } + } + + void remove_from_lru(CachedExtent &extent) { + assert(extent.is_clean()); + assert(!extent.is_pending()); + assert(!extent.is_placeholder()); + + if (extent.primary_ref_list_hook.is_linked()) { + lru.erase(lru.s_iterator_to(extent)); + assert(contents >= extent.get_length()); + contents -= extent.get_length(); + intrusive_ptr_release(&extent); + } + } + + void move_to_top(CachedExtent &extent) { + assert( + extent.is_clean() && + !extent.is_pending() && + !extent.is_placeholder()); + + if (extent.primary_ref_list_hook.is_linked()) { + lru.erase(lru.s_iterator_to(extent)); + intrusive_ptr_release(&extent); + assert(contents >= extent.get_length()); + contents -= extent.get_length(); + } + add_to_lru(extent); + } + + void clear() { + LOG_PREFIX(Cache::LRU::clear); + for (auto iter = lru.begin(); iter != lru.end();) { + DEBUG("clearing {}", *iter); + remove_from_lru(*(iter++)); + } + } + + ~LRU() { + assert(lru.empty()); + } + } lru; + struct query_counters_t { uint64_t access = 0; uint64_t hit = 0; @@ -850,6 +942,14 @@ private: return bp; } + /// Update lru for access to ref + void touch_extent(CachedExtent &ext) { + assert(!ext.is_pending()); + if (ext.is_clean() && !ext.is_placeholder()) { + lru.move_to_top(ext); + } + } + /// Add extent to extents handling dirty and refcounting void add_extent(CachedExtentRef ref); diff --git a/src/crimson/os/seastore/cached_extent.h b/src/crimson/os/seastore/cached_extent.h index ad54b540ce994..99efa03914007 100644 --- a/src/crimson/os/seastore/cached_extent.h +++ b/src/crimson/os/seastore/cached_extent.h @@ -277,6 +277,11 @@ public: return !is_valid() || (prior_instance && !prior_instance->is_valid()); } + /// Returns true if extent is a plcaeholder + bool is_placeholder() const { + return get_type() == extent_types_t::RETIRED_PLACEHOLDER; + } + /// Return journal location of oldest relevant delta, only valid while DIRTY auto get_dirty_from() const { ceph_assert(is_dirty()); diff --git a/src/crimson/os/seastore/transaction_manager.cc b/src/crimson/os/seastore/transaction_manager.cc index a04c45ef17b32..255b082ee991d 100644 --- a/src/crimson/os/seastore/transaction_manager.cc +++ b/src/crimson/os/seastore/transaction_manager.cc @@ -470,7 +470,9 @@ TransactionManager::get_extent_if_live_ret TransactionManager::get_extent_if_liv }); } -TransactionManager::~TransactionManager() {} +TransactionManager::~TransactionManager() { + cache->clear_lru(); +} void TransactionManager::register_metrics() { -- 2.39.5