]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
crimson/os/seastore/cache: add lru
authorSamuel Just <sjust@redhat.com>
Mon, 1 Nov 2021 20:48:28 +0000 (13:48 -0700)
committerXinyu Huang <xinyu.huang@intel.com>
Wed, 29 Dec 2021 02:22:22 +0000 (10:22 +0800)
Signed-off-by: Samuel Just <sjust@redhat.com>
src/common/options/crimson.yaml.in
src/crimson/os/seastore/cache.cc
src/crimson/os/seastore/cache.h
src/crimson/os/seastore/cached_extent.h
src/crimson/os/seastore/transaction_manager.cc

index d110842c759559d9cf460c7d77a1d7f61f43951c..6ce7b68be0db884a56b091d577e696cd81e956b5 100644 (file)
@@ -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
index 2813864375629b4414849127fdec2d45b0a85c39..6f7f6833f38d828a32fc1647cbadae184bb5a1b6 100644 (file)
@@ -7,6 +7,7 @@
 #include <string_view>
 
 #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<Option::size_t>(
+         "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();
 }
 
index 08f2b6b350ccfdea93c3d5bde553c8ce9852ac2a..3181fa58cc824f8e001a1b818c5b9001298adf25 100644 (file)
@@ -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<TCachedExtentRef<T>>(
            std::move(ref));
@@ -418,6 +420,7 @@ private:
           mark_transaction_conflicted(t, *ret.get());
           return get_extent_ertr::make_ready_future<CachedExtentRef>();
         } else {
+         touch_extent(*ret);
           t.add_to_read_set(ret);
           return get_extent_ertr::make_ready_future<CachedExtentRef>(
             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);
 
index ad54b540ce9942170c0cc917b52422e8161ff58b..99efa03914007c388546d399d20df7418f63b69c 100644 (file)
@@ -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());
index a04c45ef17b32a50300d95948f59437246563da5..255b082ee991db598eb921edbc7fa957b9d64192 100644 (file)
@@ -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()
 {