1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "HybridAllocator.h"
8 #include "common/config_proxy.h"
9 #include "common/debug.h"
11 #define dout_context cct
12 #define dout_subsys ceph_subsys_bluestore
14 #define dout_prefix *_dout << "HybridAllocator "
17 int64_t HybridAllocator::allocate(
20 uint64_t max_alloc_size
,
22 PExtentVector
* extents
)
24 ldout(cct
, 10) << __func__
<< std::hex
27 << " max_alloc_size 0x" << max_alloc_size
30 ceph_assert(isp2(unit
));
31 ceph_assert(want
% unit
== 0);
33 if (max_alloc_size
== 0) {
34 max_alloc_size
= want
;
36 if (constexpr auto cap
= std::numeric_limits
<decltype(bluestore_pextent_t::length
)>::max();
37 max_alloc_size
>= cap
) {
38 max_alloc_size
= p2align(uint64_t(cap
), (uint64_t)get_block_size());
41 std::lock_guard
l(lock
);
44 PExtentVector local_extents
;
46 // preserve original 'extents' vector state
47 auto orig_size
= extents
->size();
48 auto orig_pos
= extents
->end();
53 // try bitmap first to avoid unneeded contiguous extents split if
54 // desired amount is less than shortes range in AVL
55 if (bmap_alloc
&& bmap_alloc
->get_free() &&
56 want
< _lowest_size_available()) {
57 res
= bmap_alloc
->allocate(want
, unit
, max_alloc_size
, hint
, extents
);
59 // got a failure, release already allocated and
60 // start over allocation from avl
63 local_extents
.end(), ++orig_pos
, extents
->end());
64 extents
->resize(orig_size
);
66 extents
->swap(local_extents
);
68 bmap_alloc
->release(local_extents
);
71 if ((uint64_t)res
< want
) {
72 auto res2
= _allocate(want
- res
, unit
, max_alloc_size
, hint
, extents
);
74 res
= res2
; // caller to do the release
80 res
= _allocate(want
, unit
, max_alloc_size
, hint
, extents
);
82 // got a failure, release already allocated and
83 // start over allocation from bitmap
86 local_extents
.end(), ++orig_pos
, extents
->end());
87 extents
->resize(orig_size
);
89 extents
->swap(local_extents
);
91 _release(local_extents
);
94 if ((uint64_t)res
< want
) {
95 auto res2
= bmap_alloc
?
96 bmap_alloc
->allocate(want
- res
, unit
, max_alloc_size
, hint
, extents
) :
99 res
= res2
; // caller to do the release
105 return res
? res
: -ENOSPC
;
108 void HybridAllocator::release(const interval_set
<uint64_t>& release_set
) {
109 std::lock_guard
l(lock
);
110 // this will attempt to put free ranges into AvlAllocator first and
111 // fallback to bitmap one via _try_insert_range call
112 _release(release_set
);
115 uint64_t HybridAllocator::get_free()
117 std::lock_guard
l(lock
);
118 return (bmap_alloc
? bmap_alloc
->get_free() : 0) + _get_free();
121 double HybridAllocator::get_fragmentation()
123 std::lock_guard
l(lock
);
124 auto f
= AvlAllocator::_get_fragmentation();
125 auto bmap_free
= bmap_alloc
? bmap_alloc
->get_free() : 0;
127 auto _free
= _get_free() + bmap_free
;
128 auto bf
= bmap_alloc
->get_fragmentation();
130 f
= f
* _get_free() / _free
+ bf
* bmap_free
/ _free
;
135 void HybridAllocator::dump()
137 std::lock_guard
l(lock
);
138 AvlAllocator::_dump();
142 ldout(cct
, 0) << __func__
143 << " avl_free: " << _get_free()
144 << " bmap_free: " << (bmap_alloc
? bmap_alloc
->get_free() : 0)
148 void HybridAllocator::dump(std::function
<void(uint64_t offset
, uint64_t length
)> notify
)
150 AvlAllocator::dump(notify
);
152 bmap_alloc
->dump(notify
);
156 void HybridAllocator::init_rm_free(uint64_t offset
, uint64_t length
)
160 std::lock_guard
l(lock
);
161 ldout(cct
, 10) << __func__
<< std::hex
162 << " offset 0x" << offset
163 << " length 0x" << length
164 << std::dec
<< dendl
;
165 _try_remove_from_tree(offset
, length
,
166 [&](uint64_t o
, uint64_t l
, bool found
) {
169 bmap_alloc
->init_rm_free(o
, l
);
171 lderr(cct
) << "init_rm_free lambda" << std::hex
172 << "Uexpected extent: "
173 << " 0x" << o
<< "~" << l
174 << std::dec
<< dendl
;
181 void HybridAllocator::shutdown()
183 std::lock_guard
l(lock
);
186 bmap_alloc
->shutdown();
188 bmap_alloc
= nullptr;
192 void HybridAllocator::_spillover_range(uint64_t start
, uint64_t end
)
194 auto size
= end
- start
;
197 << start
<< "~" << size
204 << " constructing fallback allocator"
206 bmap_alloc
= new BitmapAllocator(cct
,
209 get_name() + ".fallback");
211 bmap_alloc
->init_add_free(start
, size
);
214 void HybridAllocator::_add_to_tree(uint64_t start
, uint64_t size
)
217 uint64_t head
= bmap_alloc
->claim_free_to_left(start
);
218 uint64_t tail
= bmap_alloc
->claim_free_to_right(start
+ size
);
219 ceph_assert(head
<= start
);
223 AvlAllocator::_add_to_tree(start
, size
);