]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
os/bluestore: refactor allocator's ExtentCollectionTraits
authorIgor Fedotov <igor.fedotov@croit.io>
Thu, 7 Mar 2024 17:42:18 +0000 (20:42 +0300)
committerJoshua Baergen <jbaergen@digitalocean.com>
Thu, 27 Mar 2025 16:33:02 +0000 (10:33 -0600)
Signed-off-by: Igor Fedotov <igor.fedotov@croit.io>
src/os/bluestore/Allocator.cc
src/os/bluestore/Allocator.h
src/os/bluestore/Btree2Allocator.cc
src/os/bluestore/Btree2Allocator.h

index 90e3224c56ac76a5aae14d7e5430b4fd4a6e6db3..f6a3654ab3c0d9b9feb7a3a2318170943a74dee0 100644 (file)
@@ -284,7 +284,7 @@ void Allocator::FreeStateHistogram::record_extent(uint64_t alloc_unit,
                                                   uint64_t off,
                                                   uint64_t len)
 {
-  size_t idx = myTraits._get_p2_size_bucket(len);
+  size_t idx = myTraits._get_bucket(len);
   ceph_assert(idx < buckets.size());
   ++buckets[idx].total;
 
@@ -293,7 +293,7 @@ void Allocator::FreeStateHistogram::record_extent(uint64_t alloc_unit,
   auto delta = p2roundup(off, alloc_unit) - off;
   if (len >= delta + alloc_unit) {
     len -= delta;
-    idx = myTraits._get_p2_size_bucket(len);
+    idx = myTraits._get_bucket(len);
     ceph_assert(idx < buckets.size());
     ++buckets[idx].aligned;
     buckets[idx].alloc_units += len / alloc_unit;
@@ -307,7 +307,7 @@ void Allocator::FreeStateHistogram::foreach(
 {
   size_t i = 0;
   for (const auto& b : buckets) {
-    cb(myTraits._get_p2_size_bucket_max(i),
+    cb(myTraits._get_bucket_max(i),
       b.total, b.aligned, b.alloc_units);
     ++i;
   }
index 089b699b0762c133b87c045d78f221b86f07050e..e27630776506043a19c2e947f2484fce798b439b 100644 (file)
@@ -24,20 +24,24 @@ typedef release_set_t::value_type release_set_entry_t;
 class Allocator {
 protected:
 
-  struct ExtentCollectionTraits {
+  /**
+   * This is a base set of traits for logical placing entries
+   * into limited collection of buckets depending on their sizes.
+   * Descandants should implement get_bucket(len) method to obtain
+   * bucket index using entry length.
+   */
+  struct LenPartitionedSetTraits {
     size_t num_buckets;
-    size_t base_bits; // min extent size
-    size_t base = 1ull << base_bits;
-    size_t factor;  // single bucket size range to be
-                    // determined as [len, len * factor * 2)
-                    // for log2(len) indexing and
-                    // [len, len + factor * base)
-                    // for linear indexing.
+    size_t base_bits; // bits in min entry size
+    size_t base;      // min entry size
+    size_t factor;    // additional factor to be applied
+                      // to entry size when calculating
+                      // target bucket
 
 
-    ExtentCollectionTraits(size_t _num_buckets,
-                           size_t _base_bits = 12,  //= 4096 bytes
-                           size_t _factor = 1) :
+    LenPartitionedSetTraits(size_t _num_buckets,
+                            size_t _base_bits = 12,  //= 4096 bytes
+                            size_t _factor = 1) :
       num_buckets(_num_buckets),
       base_bits(_base_bits),
       base(1ull << base_bits),
@@ -45,13 +49,63 @@ protected:
     {
       ceph_assert(factor);
     }
+  };
+
+  /**
+   * This extends LenPartitionedSetTraits to implement linear bucket indexing:
+   * bucket index to be determined as entry's size divided by (base * factor),
+   * i.e. buckets are:
+   * [0..base)
+   * [base, base+base*factor)
+   * [base+base*factor, base+base*factor*2)
+   * [base+base*factor*2, base+base*factor*3)
+   * ...
+   */
+  struct LenPartitionedSetTraitsLinear : public LenPartitionedSetTraits {
+    using LenPartitionedSetTraits::LenPartitionedSetTraits;
+    /*
+     * Determines bucket index for a given extent's length in a bucket set
+     * with linear (len / base / factor) indexing.
+     * The first bucket is targeted for lengths < base,
+     * the last bucket is used for lengths above the maximum
+     * detemined by bucket count.
+     */
+    inline size_t _get_bucket(uint64_t len) const {
+      size_t idx = (len / factor) >> base_bits;
+      idx = idx < num_buckets ? idx : num_buckets - 1;
+      return idx;
+    }
+    /*
+     * returns upper bound of a specific bucket
+     */
+    inline size_t _get_bucket_max(size_t bucket) const {
+      return
+        bucket < num_buckets - 1 ?
+        base * factor * (1 + bucket) :
+        std::numeric_limits<uint64_t>::max();
+    }
+  };
 
+  /**
+   * This extends LenPartitionedSetTraits to implement exponential bucket indexing:
+   * target bucket bounds are determined as
+   * [0, base]
+   * (base, base*2^factor]
+   * (base*2^factor, base*2^(factor*2)]
+   * (base*2^(factor*2), base*2^(factor*3)]
+   * ...
+   *
+   */
+  struct LenPartitionedSetTraitsPow2 : public LenPartitionedSetTraits {
     /*
      * Determines bucket index for a given extent's length in a bucket collection
      * with log2(len) indexing.
-     * The last bucket index is returned for lengths above the maximum.
+     * The first bucket is targeted for lengths < base,
+     * The last bucket index is used for lengths above the maximum
+     * detemined by bucket count.
      */
-    inline size_t _get_p2_size_bucket(uint64_t len) const {
+    using LenPartitionedSetTraits::LenPartitionedSetTraits;
+    inline size_t _get_bucket(uint64_t len) const {
       size_t idx;
       const size_t len_p2_max =
         base << ((factor * (num_buckets - 2)));
@@ -69,33 +123,12 @@ protected:
     /*
      * returns upper bound of the bucket with log2(len) indexing.
      */
-    inline size_t _get_p2_size_bucket_max(size_t bucket) const {
+    inline size_t _get_bucket_max(size_t bucket) const {
       return
         bucket < num_buckets - 1 ?
         base << (factor * bucket) :
         std::numeric_limits<uint64_t>::max();
-    };
-
-    /*
-     * Determines bucket index for a given extent's length in a bucket collection
-     * with linear (len / min_extent_size) indexing.
-     * The last bucket index is returned for lengths above the maximum.
-     */
-    inline size_t _get_linear_size_bucket(uint64_t len) const {
-      size_t idx = (len / factor) >> base_bits;
-      idx = idx < num_buckets ? idx : num_buckets - 1;
-      return idx;
     }
-    /*
-     * returns upper bound of the bucket with
-     * linear(len / min_extent_size) indexing.
-     */
-    inline size_t _get_linear_size_bucket_max(size_t bucket) const {
-      return
-        bucket < num_buckets - 1 ?
-        base * factor * (1 + bucket) :
-        std::numeric_limits<uint64_t>::max();
-    };
   };
 
   /*
@@ -145,7 +178,7 @@ protected:
    * extents aren't not cached.
    */
   class OpportunisticExtentCache {
-    const Allocator::ExtentCollectionTraits myTraits;
+    const LenPartitionedSetTraitsLinear myTraits;
     enum {
       BUCKET_COUNT = 16,
       EXTENTS_PER_BUCKET = 16, // amount of entries per single bucket,
@@ -179,7 +212,7 @@ protected:
       bool ret = false;
       ceph_assert(p2aligned(offset, myTraits.base));
       ceph_assert(p2aligned(len, myTraits.base));
-      auto idx = myTraits._get_linear_size_bucket(len);
+      auto idx = myTraits._get_bucket(len);
       if (idx < buckets.size())
         ret = buckets[idx].try_put(offset);
       lock.unlock_shared();
@@ -295,7 +328,7 @@ public:
   // - amount of allocation units in aligned extents
   //
   class FreeStateHistogram {
-    const Allocator::ExtentCollectionTraits myTraits;
+    const LenPartitionedSetTraitsPow2 myTraits;
     enum {
       BASE_BITS = 12, // 4096 bytes
       FACTOR = 2,
index 33ee6348c8e0315908031054ac6fe224fd08e70d..9e421b6762eb05b137cb24912609ded0ab6f4aa4 100644 (file)
@@ -197,7 +197,7 @@ int64_t Btree2Allocator::_allocate(
         continue;
       }
     }
-    size_t bucket0 = myTraits._get_p2_size_bucket(want_now);
+    size_t bucket0 = myTraits._get_bucket(want_now);
     int64_t r = __allocate(bucket0, want_now,
       unit, extents);
     if (r < 0) {
@@ -331,7 +331,7 @@ int64_t Btree2Allocator::__allocate(
   auto rs_p = _pick_block(0, rs_tree, size);
 
   if (rs_p == rs_tree->end()) {
-    auto bucket_center = myTraits._get_p2_size_bucket(weight_center);
+    auto bucket_center = myTraits._get_bucket(weight_center);
 
     // requested size is to the left of weight center
     // hence we try to search up toward it first
@@ -467,7 +467,7 @@ void Btree2Allocator::_remove_from_tree(
   uint64_t end)
 {
   range_seg_t rs(rt_p->first, rt_p->second);
-  size_t bucket = myTraits._get_p2_size_bucket(rs.length());
+  size_t bucket = myTraits._get_bucket(rs.length());
   range_size_tree_t* rs_tree = &range_size_set[bucket];
   auto rs_p = rs_tree->find(rs);
   ceph_assert(rs_p != rs_tree->end());
@@ -571,7 +571,7 @@ bool Btree2Allocator::__try_insert_range(
 void Btree2Allocator::_range_size_tree_add(const range_seg_t& rs) {
   auto l = rs.length();
   ceph_assert(rs.end > rs.start);
-  size_t bucket = myTraits._get_p2_size_bucket(l);
+  size_t bucket = myTraits._get_bucket(l);
   range_size_set[bucket].insert(rs);
   num_free += l;
 
@@ -584,7 +584,7 @@ void Btree2Allocator::_range_size_tree_add(const range_seg_t& rs) {
 }
 void Btree2Allocator::_range_size_tree_rm(const range_seg_t& rs)
 {
-  size_t bucket = myTraits._get_p2_size_bucket(rs.length());
+  size_t bucket = myTraits._get_bucket(rs.length());
   range_size_tree_t* rs_tree = &range_size_set[bucket];
   ceph_assert(rs_tree->size() > 0);
   auto rs_p = rs_tree->find(rs);
index bccdeb6ad057136769f470b6ba2be971c4957531..21787bb6e621a169faa47455edf18aa7a29a3503 100644 (file)
@@ -23,7 +23,7 @@ class Btree2Allocator : public Allocator {
   enum {
     RANGE_SIZE_BUCKET_COUNT = 14,
   };
-  const ExtentCollectionTraits myTraits;
+  const LenPartitionedSetTraitsPow2 myTraits;
 
 public:
   // Making public to share with mempools