Skip to content

Commit

Permalink
os/bluestore: refactor allocator's ExtentCollectionTraits
Browse files Browse the repository at this point in the history
Signed-off-by: Igor Fedotov <igor.fedotov@croit.io>
  • Loading branch information
ifed01 committed Mar 28, 2024
1 parent bc37fa9 commit 05c98a4
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 47 deletions.
6 changes: 3 additions & 3 deletions src/os/bluestore/Allocator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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;
}
Expand Down
109 changes: 71 additions & 38 deletions src/os/bluestore/Allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,34 +24,88 @@ 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),
factor(_factor)
{
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*factor*2]
* (base*factor*2, base*factor*4]
* (base*factor*4, base*factor*8]
* ...
*
*/
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)));
Expand All @@ -69,33 +123,12 @@ class Allocator {
/*
* 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();
};
};

/*
Expand Down Expand Up @@ -145,7 +178,7 @@ class Allocator {
* 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,
Expand Down Expand Up @@ -179,7 +212,7 @@ class Allocator {
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();
Expand Down Expand Up @@ -295,7 +328,7 @@ class Allocator {
// - amount of allocation units in aligned extents
//
class FreeStateHistogram {
const Allocator::ExtentCollectionTraits myTraits;
const LenPartitionedSetTraitsPow2 myTraits;
enum {
BASE_BITS = 12, // 4096 bytes
FACTOR = 2,
Expand Down
10 changes: 5 additions & 5 deletions src/os/bluestore/Btree2Allocator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -472,7 +472,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());
Expand Down Expand Up @@ -576,7 +576,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;

Expand All @@ -589,7 +589,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);
Expand Down
2 changes: 1 addition & 1 deletion src/os/bluestore/Btree2Allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 05c98a4

Please sign in to comment.