]> git.proxmox.com Git - ceph.git/blame - ceph/src/os/bluestore/StupidAllocator.cc
update sources to v12.1.2
[ceph.git] / ceph / src / os / bluestore / StupidAllocator.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "StupidAllocator.h"
5#include "bluestore_types.h"
6#include "common/debug.h"
7
8#define dout_context cct
9#define dout_subsys ceph_subsys_bluestore
10#undef dout_prefix
11#define dout_prefix *_dout << "stupidalloc "
12
13StupidAllocator::StupidAllocator(CephContext* cct)
14 : cct(cct), num_free(0),
15 num_reserved(0),
16 free(10),
17 last_alloc(0)
18{
19}
20
21StupidAllocator::~StupidAllocator()
22{
23}
24
25unsigned StupidAllocator::_choose_bin(uint64_t orig_len)
26{
27 uint64_t len = orig_len / cct->_conf->bdev_block_size;
28 int bin = std::min((int)cbits(len), (int)free.size() - 1);
29 dout(30) << __func__ << " len 0x" << std::hex << orig_len << std::dec
30 << " -> " << bin << dendl;
31 return bin;
32}
33
34void StupidAllocator::_insert_free(uint64_t off, uint64_t len)
35{
36 unsigned bin = _choose_bin(len);
37 dout(30) << __func__ << " 0x" << std::hex << off << "~" << len << std::dec
38 << " in bin " << bin << dendl;
39 while (true) {
40 free[bin].insert(off, len, &off, &len);
41 unsigned newbin = _choose_bin(len);
42 if (newbin == bin)
43 break;
44 dout(30) << __func__ << " promoting 0x" << std::hex << off << "~" << len
45 << std::dec << " to bin " << newbin << dendl;
46 free[bin].erase(off, len);
47 bin = newbin;
48 }
49}
50
51int StupidAllocator::reserve(uint64_t need)
52{
53 std::lock_guard<std::mutex> l(lock);
54 dout(10) << __func__ << " need 0x" << std::hex << need
55 << " num_free 0x" << num_free
56 << " num_reserved 0x" << num_reserved << std::dec << dendl;
57 if ((int64_t)need > num_free - num_reserved)
58 return -ENOSPC;
59 num_reserved += need;
60 return 0;
61}
62
63void StupidAllocator::unreserve(uint64_t unused)
64{
65 std::lock_guard<std::mutex> l(lock);
66 dout(10) << __func__ << " unused 0x" << std::hex << unused
67 << " num_free 0x" << num_free
68 << " num_reserved 0x" << num_reserved << std::dec << dendl;
69 assert(num_reserved >= (int64_t)unused);
70 num_reserved -= unused;
71}
72
73/// return the effective length of the extent if we align to alloc_unit
74static uint64_t aligned_len(btree_interval_set<uint64_t>::iterator p,
75 uint64_t alloc_unit)
76{
77 uint64_t skew = p.get_start() % alloc_unit;
78 if (skew)
79 skew = alloc_unit - skew;
80 if (skew > p.get_len())
81 return 0;
82 else
83 return p.get_len() - skew;
84}
85
86int64_t StupidAllocator::allocate_int(
87 uint64_t want_size, uint64_t alloc_unit, int64_t hint,
88 uint64_t *offset, uint32_t *length)
89{
90 std::lock_guard<std::mutex> l(lock);
91 dout(10) << __func__ << " want_size 0x" << std::hex << want_size
92 << " alloc_unit 0x" << alloc_unit
93 << " hint 0x" << hint << std::dec
94 << dendl;
95 uint64_t want = MAX(alloc_unit, want_size);
96 int bin = _choose_bin(want);
97 int orig_bin = bin;
98
99 auto p = free[0].begin();
100
101 if (!hint)
102 hint = last_alloc;
103
104 // search up (from hint)
105 if (hint) {
106 for (bin = orig_bin; bin < (int)free.size(); ++bin) {
107 p = free[bin].lower_bound(hint);
108 while (p != free[bin].end()) {
109 if (aligned_len(p, alloc_unit) >= want_size) {
110 goto found;
111 }
112 ++p;
113 }
114 }
115 }
116
117 // search up (from origin, and skip searched extents by hint)
118 for (bin = orig_bin; bin < (int)free.size(); ++bin) {
119 p = free[bin].begin();
120 auto end = hint ? free[bin].lower_bound(hint) : free[bin].end();
121 while (p != end) {
122 if (aligned_len(p, alloc_unit) >= want_size) {
123 goto found;
124 }
125 ++p;
126 }
127 }
128
129 // search down (hint)
130 if (hint) {
131 for (bin = orig_bin; bin >= 0; --bin) {
132 p = free[bin].lower_bound(hint);
133 while (p != free[bin].end()) {
134 if (aligned_len(p, alloc_unit) >= alloc_unit) {
135 goto found;
136 }
137 ++p;
138 }
139 }
140 }
141
142 // search down (from origin, and skip searched extents by hint)
143 for (bin = orig_bin; bin >= 0; --bin) {
144 p = free[bin].begin();
145 auto end = hint ? free[bin].lower_bound(hint) : free[bin].end();
146 while (p != end) {
147 if (aligned_len(p, alloc_unit) >= alloc_unit) {
148 goto found;
149 }
150 ++p;
151 }
152 }
153
154 return -ENOSPC;
155
156 found:
157 uint64_t skew = p.get_start() % alloc_unit;
158 if (skew)
159 skew = alloc_unit - skew;
160 *offset = p.get_start() + skew;
c07f9fc5 161 *length = MIN(MAX(alloc_unit, want_size), P2ALIGN((p.get_len() - skew), alloc_unit));
7c673cae
FG
162 if (cct->_conf->bluestore_debug_small_allocations) {
163 uint64_t max =
164 alloc_unit * (rand() % cct->_conf->bluestore_debug_small_allocations);
165 if (max && *length > max) {
166 dout(10) << __func__ << " shortening allocation of 0x" << std::hex
167 << *length << " -> 0x"
168 << max << " due to debug_small_allocations" << std::dec << dendl;
169 *length = max;
170 }
171 }
172 dout(30) << __func__ << " got 0x" << std::hex << *offset << "~" << *length
173 << " from bin " << std::dec << bin << dendl;
174
175 free[bin].erase(*offset, *length);
176 uint64_t off, len;
177 if (*offset && free[bin].contains(*offset - skew - 1, &off, &len)) {
178 int newbin = _choose_bin(len);
179 if (newbin != bin) {
180 dout(30) << __func__ << " demoting 0x" << std::hex << off << "~" << len
181 << std::dec << " to bin " << newbin << dendl;
182 free[bin].erase(off, len);
183 _insert_free(off, len);
184 }
185 }
186 if (free[bin].contains(*offset + *length, &off, &len)) {
187 int newbin = _choose_bin(len);
188 if (newbin != bin) {
189 dout(30) << __func__ << " demoting 0x" << std::hex << off << "~" << len
190 << std::dec << " to bin " << newbin << dendl;
191 free[bin].erase(off, len);
192 _insert_free(off, len);
193 }
194 }
195
196 num_free -= *length;
197 num_reserved -= *length;
198 assert(num_free >= 0);
199 assert(num_reserved >= 0);
200 last_alloc = *offset + *length;
201 return 0;
202}
203
204int64_t StupidAllocator::allocate(
205 uint64_t want_size,
206 uint64_t alloc_unit,
207 uint64_t max_alloc_size,
208 int64_t hint,
209 mempool::bluestore_alloc::vector<AllocExtent> *extents)
210{
211 uint64_t allocated_size = 0;
212 uint64_t offset = 0;
213 uint32_t length = 0;
214 int res = 0;
215
216 if (max_alloc_size == 0) {
217 max_alloc_size = want_size;
218 }
219
220 ExtentList block_list = ExtentList(extents, 1, max_alloc_size);
221
222 while (allocated_size < want_size) {
223 res = allocate_int(MIN(max_alloc_size, (want_size - allocated_size)),
224 alloc_unit, hint, &offset, &length);
225 if (res != 0) {
226 /*
227 * Allocation failed.
228 */
229 break;
230 }
231 block_list.add_extents(offset, length);
232 allocated_size += length;
233 hint = offset + length;
234 }
235
236 if (allocated_size == 0) {
237 return -ENOSPC;
238 }
239 return allocated_size;
240}
241
242void StupidAllocator::release(
243 uint64_t offset, uint64_t length)
244{
245 std::lock_guard<std::mutex> l(lock);
246 dout(10) << __func__ << " 0x" << std::hex << offset << "~" << length
247 << std::dec << dendl;
248 _insert_free(offset, length);
249 num_free += length;
250}
251
252uint64_t StupidAllocator::get_free()
253{
254 std::lock_guard<std::mutex> l(lock);
255 return num_free;
256}
257
258void StupidAllocator::dump()
259{
260 std::lock_guard<std::mutex> l(lock);
261 for (unsigned bin = 0; bin < free.size(); ++bin) {
262 dout(0) << __func__ << " free bin " << bin << ": "
263 << free[bin].num_intervals() << " extents" << dendl;
264 for (auto p = free[bin].begin();
265 p != free[bin].end();
266 ++p) {
267 dout(0) << __func__ << " 0x" << std::hex << p.get_start() << "~"
268 << p.get_len() << std::dec << dendl;
269 }
270 }
271}
272
273void StupidAllocator::init_add_free(uint64_t offset, uint64_t length)
274{
275 std::lock_guard<std::mutex> l(lock);
276 dout(10) << __func__ << " 0x" << std::hex << offset << "~" << length
277 << std::dec << dendl;
278 _insert_free(offset, length);
279 num_free += length;
280}
281
282void StupidAllocator::init_rm_free(uint64_t offset, uint64_t length)
283{
284 std::lock_guard<std::mutex> l(lock);
285 dout(10) << __func__ << " 0x" << std::hex << offset << "~" << length
286 << std::dec << dendl;
287 btree_interval_set<uint64_t> rm;
288 rm.insert(offset, length);
289 for (unsigned i = 0; i < free.size() && !rm.empty(); ++i) {
290 btree_interval_set<uint64_t> overlap;
291 overlap.intersection_of(rm, free[i]);
292 if (!overlap.empty()) {
293 dout(20) << __func__ << " bin " << i << " rm 0x" << std::hex << overlap
294 << std::dec << dendl;
295 free[i].subtract(overlap);
296 rm.subtract(overlap);
297 }
298 }
299 assert(rm.empty());
300 num_free -= length;
301 assert(num_free >= 0);
302}
303
304
305void StupidAllocator::shutdown()
306{
307 dout(1) << __func__ << dendl;
308}
309