]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/objectstore/test_bluestore_types.cc
import 15.2.4
[ceph.git] / ceph / src / test / objectstore / test_bluestore_types.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "include/types.h"
5 #include "os/bluestore/bluestore_types.h"
6 #include "gtest/gtest.h"
7 #include "include/stringify.h"
8 #include "common/ceph_time.h"
9 #include "os/bluestore/BlueStore.h"
10 #include "os/bluestore/AvlAllocator.h"
11 #include "common/ceph_argparse.h"
12 #include "global/global_init.h"
13 #include "global/global_context.h"
14
15 #include <sstream>
16
17 #define _STR(x) #x
18 #define STRINGIFY(x) _STR(x)
19
20 TEST(bluestore, sizeof) {
21 #define P(t) cout << STRINGIFY(t) << "\t" << sizeof(t) << std::endl
22 P(BlueStore::Onode);
23 P(BlueStore::Extent);
24 P(BlueStore::Blob);
25 P(BlueStore::SharedBlob);
26 P(BlueStore::ExtentMap);
27 P(BlueStore::extent_map_t);
28 P(BlueStore::blob_map_t);
29 P(BlueStore::BufferSpace);
30 P(BlueStore::Buffer);
31 P(bluestore_onode_t);
32 P(bluestore_blob_t);
33 P(PExtentVector);
34 P(bluestore_shared_blob_t);
35 P(bluestore_extent_ref_map_t);
36 P(bluestore_extent_ref_map_t::record_t);
37 P(bluestore_blob_use_tracker_t);
38 P(std::atomic_int);
39 P(BlueStore::SharedBlobRef);
40 P(boost::intrusive::set_base_hook<>);
41 P(boost::intrusive::unordered_set_base_hook<>);
42 P(bufferlist);
43 P(bufferptr);
44 P(range_seg_t);
45 cout << "map<uint64_t,uint64_t>\t" << sizeof(map<uint64_t,uint64_t>) << std::endl;
46 cout << "map<char,char>\t" << sizeof(map<char,char>) << std::endl;
47 }
48
49 TEST(bluestore_extent_ref_map_t, add)
50 {
51 bluestore_extent_ref_map_t m;
52 m.get(10, 10);
53 ASSERT_EQ(1u, m.ref_map.size());
54 cout << m << std::endl;
55 m.get(20, 10);
56 cout << m << std::endl;
57 ASSERT_EQ(1u, m.ref_map.size());
58 ASSERT_EQ(20u, m.ref_map[10].length);
59 ASSERT_EQ(1u, m.ref_map[10].refs);
60 m.get(40, 10);
61 cout << m << std::endl;
62 ASSERT_EQ(2u, m.ref_map.size());
63 m.get(30, 10);
64 cout << m << std::endl;
65 ASSERT_EQ(1u, m.ref_map.size());
66 m.get(50, 10);
67 cout << m << std::endl;
68 ASSERT_EQ(1u, m.ref_map.size());
69 m.get(5, 5);
70 cout << m << std::endl;
71 ASSERT_EQ(1u, m.ref_map.size());
72 }
73
74 TEST(bluestore_extent_ref_map_t, get)
75 {
76 bluestore_extent_ref_map_t m;
77 m.get(00, 30);
78 cout << m << std::endl;
79 m.get(10, 10);
80 cout << m << std::endl;
81 ASSERT_EQ(3u, m.ref_map.size());
82 ASSERT_EQ(10u, m.ref_map[0].length);
83 ASSERT_EQ(1u, m.ref_map[0].refs);
84 ASSERT_EQ(10u, m.ref_map[10].length);
85 ASSERT_EQ(2u, m.ref_map[10].refs);
86 ASSERT_EQ(10u, m.ref_map[20].length);
87 ASSERT_EQ(1u, m.ref_map[20].refs);
88 m.get(20, 5);
89 cout << m << std::endl;
90 ASSERT_EQ(3u, m.ref_map.size());
91 ASSERT_EQ(15u, m.ref_map[10].length);
92 ASSERT_EQ(2u, m.ref_map[10].refs);
93 ASSERT_EQ(5u, m.ref_map[25].length);
94 ASSERT_EQ(1u, m.ref_map[25].refs);
95 m.get(5, 20);
96 cout << m << std::endl;
97 ASSERT_EQ(4u, m.ref_map.size());
98 ASSERT_EQ(5u, m.ref_map[0].length);
99 ASSERT_EQ(1u, m.ref_map[0].refs);
100 ASSERT_EQ(5u, m.ref_map[5].length);
101 ASSERT_EQ(2u, m.ref_map[5].refs);
102 ASSERT_EQ(15u, m.ref_map[10].length);
103 ASSERT_EQ(3u, m.ref_map[10].refs);
104 ASSERT_EQ(5u, m.ref_map[25].length);
105 ASSERT_EQ(1u, m.ref_map[25].refs);
106 m.get(25, 3);
107 cout << m << std::endl;
108 ASSERT_EQ(5u, m.ref_map.size());
109 ASSERT_EQ(5u, m.ref_map[0].length);
110 ASSERT_EQ(1u, m.ref_map[0].refs);
111 ASSERT_EQ(5u, m.ref_map[5].length);
112 ASSERT_EQ(2u, m.ref_map[5].refs);
113 ASSERT_EQ(15u, m.ref_map[10].length);
114 ASSERT_EQ(3u, m.ref_map[10].refs);
115 ASSERT_EQ(3u, m.ref_map[25].length);
116 ASSERT_EQ(2u, m.ref_map[25].refs);
117 ASSERT_EQ(2u, m.ref_map[28].length);
118 ASSERT_EQ(1u, m.ref_map[28].refs);
119 }
120
121 TEST(bluestore_extent_ref_map_t, put)
122 {
123 bluestore_extent_ref_map_t m;
124 PExtentVector r;
125 bool maybe_unshared = false;
126 m.get(10, 30);
127 maybe_unshared = true;
128 m.put(10, 30, &r, &maybe_unshared);
129 cout << m << " " << r << " " << (int)maybe_unshared << std::endl;
130 ASSERT_EQ(0u, m.ref_map.size());
131 ASSERT_EQ(1u, r.size());
132 ASSERT_EQ(10u, r[0].offset);
133 ASSERT_EQ(30u, r[0].length);
134 ASSERT_TRUE(maybe_unshared);
135 r.clear();
136 m.get(10, 30);
137 m.get(20, 10);
138 maybe_unshared = true;
139 m.put(10, 30, &r, &maybe_unshared);
140 cout << m << " " << r << " " << (int)maybe_unshared << std::endl;
141 ASSERT_EQ(1u, m.ref_map.size());
142 ASSERT_EQ(10u, m.ref_map[20].length);
143 ASSERT_EQ(1u, m.ref_map[20].refs);
144 ASSERT_EQ(2u, r.size());
145 ASSERT_EQ(10u, r[0].offset);
146 ASSERT_EQ(10u, r[0].length);
147 ASSERT_EQ(30u, r[1].offset);
148 ASSERT_EQ(10u, r[1].length);
149 ASSERT_TRUE(maybe_unshared);
150 r.clear();
151 m.get(30, 10);
152 m.get(30, 10);
153 maybe_unshared = true;
154 m.put(20, 15, &r, &maybe_unshared);
155 cout << m << " " << r << " " << (int)maybe_unshared << std::endl;
156 ASSERT_EQ(2u, m.ref_map.size());
157 ASSERT_EQ(5u, m.ref_map[30].length);
158 ASSERT_EQ(1u, m.ref_map[30].refs);
159 ASSERT_EQ(5u, m.ref_map[35].length);
160 ASSERT_EQ(2u, m.ref_map[35].refs);
161 ASSERT_EQ(1u, r.size());
162 ASSERT_EQ(20u, r[0].offset);
163 ASSERT_EQ(10u, r[0].length);
164 ASSERT_FALSE(maybe_unshared);
165 r.clear();
166 maybe_unshared = true;
167 m.put(33, 5, &r, &maybe_unshared);
168 cout << m << " " << r << " " << (int)maybe_unshared << std::endl;
169 ASSERT_EQ(3u, m.ref_map.size());
170 ASSERT_EQ(3u, m.ref_map[30].length);
171 ASSERT_EQ(1u, m.ref_map[30].refs);
172 ASSERT_EQ(3u, m.ref_map[35].length);
173 ASSERT_EQ(1u, m.ref_map[35].refs);
174 ASSERT_EQ(2u, m.ref_map[38].length);
175 ASSERT_EQ(2u, m.ref_map[38].refs);
176 ASSERT_EQ(1u, r.size());
177 ASSERT_EQ(33u, r[0].offset);
178 ASSERT_EQ(2u, r[0].length);
179 ASSERT_FALSE(maybe_unshared);
180 r.clear();
181 maybe_unshared = true;
182 m.put(38, 2, &r, &maybe_unshared);
183 cout << m << " " << r << " " << (int)maybe_unshared << std::endl;
184 ASSERT_TRUE(maybe_unshared);
185 }
186
187 TEST(bluestore_extent_ref_map_t, contains)
188 {
189 bluestore_extent_ref_map_t m;
190 m.get(10, 30);
191 ASSERT_TRUE(m.contains(10, 30));
192 ASSERT_TRUE(m.contains(10, 10));
193 ASSERT_TRUE(m.contains(30, 10));
194 ASSERT_FALSE(m.contains(0, 10));
195 ASSERT_FALSE(m.contains(0, 20));
196 ASSERT_FALSE(m.contains(0, 100));
197 ASSERT_FALSE(m.contains(40, 10));
198 ASSERT_FALSE(m.contains(30, 11));
199 m.get(40, 10);
200 m.get(40, 10);
201 ASSERT_TRUE(m.contains(30, 11));
202 ASSERT_TRUE(m.contains(30, 20));
203 ASSERT_TRUE(m.contains(10, 40));
204 ASSERT_FALSE(m.contains(0, 50));
205 ASSERT_FALSE(m.contains(40, 20));
206 m.get(60, 100);
207 ASSERT_TRUE(m.contains(60, 10));
208 ASSERT_TRUE(m.contains(40, 10));
209 ASSERT_FALSE(m.contains(40, 11));
210 ASSERT_FALSE(m.contains(40, 20));
211 ASSERT_FALSE(m.contains(40, 30));
212 ASSERT_FALSE(m.contains(40, 3000));
213 ASSERT_FALSE(m.contains(4000, 30));
214 }
215
216 TEST(bluestore_extent_ref_map_t, intersects)
217 {
218 bluestore_extent_ref_map_t m;
219 m.get(10, 30);
220 ASSERT_TRUE(m.intersects(10, 30));
221 ASSERT_TRUE(m.intersects(0, 11));
222 ASSERT_TRUE(m.intersects(10, 40));
223 ASSERT_TRUE(m.intersects(15, 40));
224 ASSERT_FALSE(m.intersects(0, 10));
225 ASSERT_FALSE(m.intersects(0, 5));
226 ASSERT_FALSE(m.intersects(40, 20));
227 ASSERT_FALSE(m.intersects(41, 20));
228 m.get(40, 10);
229 m.get(40, 10);
230 ASSERT_TRUE(m.intersects(0, 100));
231 ASSERT_TRUE(m.intersects(10, 35));
232 ASSERT_TRUE(m.intersects(45, 10));
233 ASSERT_FALSE(m.intersects(50, 5));
234 m.get(60, 100);
235 ASSERT_TRUE(m.intersects(45, 10));
236 ASSERT_TRUE(m.intersects(55, 10));
237 ASSERT_TRUE(m.intersects(50, 11));
238 ASSERT_FALSE(m.intersects(50, 10));
239 ASSERT_FALSE(m.intersects(51, 9));
240 ASSERT_FALSE(m.intersects(55, 1));
241 }
242
243 TEST(bluestore_blob_t, calc_csum)
244 {
245 bufferlist bl;
246 bl.append("asdfghjkqwertyuizxcvbnm,");
247 bufferlist bl2;
248 bl2.append("xxxxXXXXyyyyYYYYzzzzZZZZ");
249 bufferlist f;
250 f.substr_of(bl, 0, 8);
251 bufferlist m;
252 m.substr_of(bl, 8, 8);
253 bufferlist e;
254 e.substr_of(bl, 16, 8);
255 bufferlist n;
256 n.append("12345678");
257
258 for (unsigned csum_type = Checksummer::CSUM_NONE + 1;
259 csum_type < Checksummer::CSUM_MAX;
260 ++csum_type) {
261 cout << "csum_type " << Checksummer::get_csum_type_string(csum_type)
262 << std::endl;
263
264 bluestore_blob_t b;
265 int bad_off;
266 uint64_t bad_csum;
267 ASSERT_EQ(0, b.verify_csum(0, bl, &bad_off, &bad_csum));
268 ASSERT_EQ(-1, bad_off);
269
270 b.init_csum(csum_type, 3, 24);
271 cout << " value size " << b.get_csum_value_size() << std::endl;
272 b.calc_csum(0, bl);
273 ASSERT_EQ(0, b.verify_csum(0, bl, &bad_off, &bad_csum));
274 ASSERT_EQ(-1, bad_off);
275 ASSERT_EQ(-1, b.verify_csum(0, bl2, &bad_off, &bad_csum));
276 ASSERT_EQ(0, bad_off);
277
278 ASSERT_EQ(0, b.verify_csum(0, f, &bad_off, &bad_csum));
279 ASSERT_EQ(-1, bad_off);
280 ASSERT_EQ(-1, b.verify_csum(8, f, &bad_off, &bad_csum));
281 ASSERT_EQ(8, bad_off);
282 ASSERT_EQ(-1, b.verify_csum(16, f, &bad_off, &bad_csum));
283 ASSERT_EQ(16, bad_off);
284
285 ASSERT_EQ(-1, b.verify_csum(0, m, &bad_off, &bad_csum));
286 ASSERT_EQ(0, bad_off);
287 ASSERT_EQ(0, b.verify_csum(8, m, &bad_off, &bad_csum));
288 ASSERT_EQ(-1, bad_off);
289 ASSERT_EQ(-1, b.verify_csum(16, m, &bad_off, &bad_csum));
290 ASSERT_EQ(16, bad_off);
291
292 ASSERT_EQ(-1, b.verify_csum(0, e, &bad_off, &bad_csum));
293 ASSERT_EQ(0, bad_off);
294 ASSERT_EQ(-1, b.verify_csum(8, e, &bad_off, &bad_csum));
295 ASSERT_EQ(8, bad_off);
296 ASSERT_EQ(0, b.verify_csum(16, e, &bad_off, &bad_csum));
297 ASSERT_EQ(-1, bad_off);
298
299 b.calc_csum(8, n);
300 ASSERT_EQ(0, b.verify_csum(0, f, &bad_off, &bad_csum));
301 ASSERT_EQ(-1, bad_off);
302 ASSERT_EQ(0, b.verify_csum(8, n, &bad_off, &bad_csum));
303 ASSERT_EQ(-1, bad_off);
304 ASSERT_EQ(0, b.verify_csum(16, e, &bad_off, &bad_csum));
305 ASSERT_EQ(-1, bad_off);
306 ASSERT_EQ(-1, b.verify_csum(0, bl, &bad_off, &bad_csum));
307 ASSERT_EQ(8, bad_off);
308 }
309 }
310
311 TEST(bluestore_blob_t, csum_bench)
312 {
313 bufferlist bl;
314 bufferptr bp(10485760);
315 for (char *a = bp.c_str(); a < bp.c_str() + bp.length(); ++a)
316 *a = (unsigned long)a & 0xff;
317 bl.append(bp);
318 int count = 256;
319 for (unsigned csum_type = 1;
320 csum_type < Checksummer::CSUM_MAX;
321 ++csum_type) {
322 bluestore_blob_t b;
323 b.init_csum(csum_type, 12, bl.length());
324 ceph::mono_clock::time_point start = ceph::mono_clock::now();
325 for (int i = 0; i<count; ++i) {
326 b.calc_csum(0, bl);
327 }
328 ceph::mono_clock::time_point end = ceph::mono_clock::now();
329 auto dur = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
330 double mbsec = (double)count * (double)bl.length() / 1000000.0 / (double)dur.count() * 1000000000.0;
331 cout << "csum_type " << Checksummer::get_csum_type_string(csum_type)
332 << ", " << dur << " seconds, "
333 << mbsec << " MB/sec" << std::endl;
334 }
335 }
336
337 TEST(Blob, put_ref)
338 {
339 {
340 BlueStore store(g_ceph_context, "", 4096);
341 BlueStore::OnodeCacheShard *oc = BlueStore::OnodeCacheShard::create(
342 g_ceph_context, "lru", NULL);
343 BlueStore::BufferCacheShard *bc = BlueStore::BufferCacheShard::create(
344 g_ceph_context, "lru", NULL);
345
346 auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
347 BlueStore::Blob b;
348 b.shared_blob = new BlueStore::SharedBlob(nullptr);
349 b.shared_blob->get(); // hack to avoid dtor from running
350 b.dirty_blob().allocated_test(bluestore_pextent_t(0x40715000, 0x2000));
351 b.dirty_blob().allocated_test(
352 bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET, 0x8000));
353 b.dirty_blob().allocated_test(bluestore_pextent_t(0x4071f000, 0x5000));
354 b.get_ref(coll.get(), 0, 0x1200);
355 b.get_ref(coll.get(), 0xae00, 0x4200);
356 ASSERT_EQ(0x5400u, b.get_referenced_bytes());
357 cout << b << std::endl;
358 PExtentVector r;
359
360 ASSERT_FALSE(b.put_ref(coll.get(), 0, 0x1200, &r));
361 ASSERT_EQ(0x4200u, b.get_referenced_bytes());
362 cout << " r " << r << std::endl;
363 cout << b << std::endl;
364
365 r.clear();
366 ASSERT_TRUE(b.put_ref(coll.get(), 0xae00, 0x4200, &r));
367 ASSERT_EQ(0u, b.get_referenced_bytes());
368 cout << " r " << r << std::endl;
369 cout << b << std::endl;
370 }
371
372 unsigned mas = 4096;
373 BlueStore store(g_ceph_context, "", 8192);
374 BlueStore::OnodeCacheShard *oc = BlueStore::OnodeCacheShard::create(
375 g_ceph_context, "lru", NULL);
376 BlueStore::BufferCacheShard *bc = BlueStore::BufferCacheShard::create(
377 g_ceph_context, "lru", NULL);
378 auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
379
380 {
381 BlueStore::Blob B;
382 B.shared_blob = new BlueStore::SharedBlob(nullptr);
383 B.shared_blob->get(); // hack to avoid dtor from running
384 bluestore_blob_t& b = B.dirty_blob();
385 PExtentVector r;
386 b.allocated_test(bluestore_pextent_t(0, mas * 2));
387 B.get_ref(coll.get(), 0, mas*2);
388 ASSERT_EQ(mas * 2, B.get_referenced_bytes());
389 ASSERT_TRUE(b.is_allocated(0, mas*2));
390 ASSERT_TRUE(B.put_ref(coll.get(), 0, mas*2, &r));
391 ASSERT_EQ(0u, B.get_referenced_bytes());
392 cout << "r " << r << " " << b << std::endl;
393 ASSERT_EQ(1u, r.size());
394 ASSERT_EQ(0u, r[0].offset);
395 ASSERT_EQ(mas*2, r[0].length);
396 ASSERT_FALSE(b.is_allocated(0, mas*2));
397 ASSERT_FALSE(b.is_allocated(0, mas));
398 ASSERT_FALSE(b.is_allocated(mas, 0));
399 ASSERT_FALSE(b.get_extents()[0].is_valid());
400 ASSERT_EQ(mas*2, b.get_extents()[0].length);
401 }
402 {
403 BlueStore::Blob B;
404 B.shared_blob = new BlueStore::SharedBlob(nullptr);
405 B.shared_blob->get(); // hack to avoid dtor from running
406 bluestore_blob_t& b = B.dirty_blob();
407 PExtentVector r;
408 b.allocated_test(bluestore_pextent_t(123, mas * 2));
409 B.get_ref(coll.get(), 0, mas*2);
410 ASSERT_EQ(mas * 2, B.get_referenced_bytes());
411 ASSERT_FALSE(B.put_ref(coll.get(), 0, mas, &r));
412 ASSERT_EQ(mas, B.get_referenced_bytes());
413 cout << "r " << r << " " << b << std::endl;
414 ASSERT_EQ(0u, r.size());
415 ASSERT_TRUE(b.is_allocated(0, mas*2));
416 ASSERT_TRUE(B.put_ref(coll.get(), mas, mas, &r));
417 ASSERT_EQ(0u, B.get_referenced_bytes());
418 ASSERT_EQ(0u, B.get_referenced_bytes());
419 cout << "r " << r << " " << b << std::endl;
420 ASSERT_EQ(1u, r.size());
421 ASSERT_EQ(123u, r[0].offset);
422 ASSERT_EQ(mas*2, r[0].length);
423 ASSERT_FALSE(b.is_allocated(0, mas*2));
424 ASSERT_FALSE(b.get_extents()[0].is_valid());
425 ASSERT_EQ(mas*2, b.get_extents()[0].length);
426 }
427 {
428 BlueStore::Blob B;
429 B.shared_blob = new BlueStore::SharedBlob(nullptr);
430 B.shared_blob->get(); // hack to avoid dtor from running
431 bluestore_blob_t& b = B.dirty_blob();
432 PExtentVector r;
433 b.allocated_test(bluestore_pextent_t(1, mas));
434 b.allocated_test(bluestore_pextent_t(2, mas));
435 b.allocated_test(bluestore_pextent_t(3, mas));
436 b.allocated_test(bluestore_pextent_t(4, mas));
437 B.get_ref(coll.get(), 0, mas*4);
438 ASSERT_EQ(mas * 4, B.get_referenced_bytes());
439 ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
440 ASSERT_EQ(mas * 3, B.get_referenced_bytes());
441 cout << "r " << r << " " << b << std::endl;
442 ASSERT_EQ(0u, r.size());
443 ASSERT_TRUE(b.is_allocated(0, mas*4));
444 ASSERT_TRUE(b.is_allocated(mas, mas));
445 ASSERT_FALSE(B.put_ref(coll.get(), mas*2, mas, &r));
446 ASSERT_EQ(mas * 2, B.get_referenced_bytes());
447 cout << "r " << r << " " << b << std::endl;
448 ASSERT_EQ(0u, r.size());
449 ASSERT_TRUE(b.is_allocated(mas*2, mas));
450 ASSERT_TRUE(b.is_allocated(0, mas*4));
451 ASSERT_FALSE(B.put_ref(coll.get(), mas*3, mas, &r));
452 ASSERT_EQ(mas, B.get_referenced_bytes());
453 cout << "r " << r << " " << b << std::endl;
454 ASSERT_EQ(2u, r.size());
455 ASSERT_EQ(3u, r[0].offset);
456 ASSERT_EQ(mas, r[0].length);
457 ASSERT_EQ(4u, r[1].offset);
458 ASSERT_EQ(mas, r[1].length);
459 ASSERT_TRUE(b.is_allocated(0, mas*2));
460 ASSERT_FALSE(b.is_allocated(mas*2, mas*2));
461 ASSERT_TRUE(b.get_extents()[0].is_valid());
462 ASSERT_TRUE(b.get_extents()[1].is_valid());
463 ASSERT_FALSE(b.get_extents()[2].is_valid());
464 ASSERT_EQ(3u, b.get_extents().size());
465 }
466 {
467 BlueStore::Blob B;
468 B.shared_blob = new BlueStore::SharedBlob(nullptr);
469 B.shared_blob->get(); // hack to avoid dtor from running
470 bluestore_blob_t& b = B.dirty_blob();
471 PExtentVector r;
472 b.allocated_test(bluestore_pextent_t(1, mas));
473 b.allocated_test(bluestore_pextent_t(2, mas));
474 b.allocated_test(bluestore_pextent_t(3, mas));
475 b.allocated_test(bluestore_pextent_t(4, mas));
476 b.allocated_test(bluestore_pextent_t(5, mas));
477 b.allocated_test(bluestore_pextent_t(6, mas));
478 B.get_ref(coll.get(), 0, mas*6);
479 ASSERT_EQ(mas * 6, B.get_referenced_bytes());
480 ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
481 ASSERT_EQ(mas * 5, B.get_referenced_bytes());
482 cout << "r " << r << " " << b << std::endl;
483 ASSERT_EQ(0u, r.size());
484 ASSERT_TRUE(b.is_allocated(0, mas*6));
485 ASSERT_FALSE(B.put_ref(coll.get(), mas*2, mas, &r));
486 ASSERT_EQ(mas * 4, B.get_referenced_bytes());
487 cout << "r " << r << " " << b << std::endl;
488 ASSERT_EQ(0u, r.size());
489 ASSERT_TRUE(b.is_allocated(0, mas*6));
490 ASSERT_FALSE(B.put_ref(coll.get(), mas*3, mas, &r));
491 ASSERT_EQ(mas * 3, B.get_referenced_bytes());
492 cout << "r " << r << " " << b << std::endl;
493 ASSERT_EQ(2u, r.size());
494 ASSERT_EQ(3u, r[0].offset);
495 ASSERT_EQ(mas, r[0].length);
496 ASSERT_EQ(4u, r[1].offset);
497 ASSERT_EQ(mas, r[1].length);
498 ASSERT_TRUE(b.is_allocated(0, mas*2));
499 ASSERT_FALSE(b.is_allocated(mas*2, mas*2));
500 ASSERT_TRUE(b.is_allocated(mas*4, mas*2));
501 ASSERT_EQ(5u, b.get_extents().size());
502 ASSERT_TRUE(b.get_extents()[0].is_valid());
503 ASSERT_TRUE(b.get_extents()[1].is_valid());
504 ASSERT_FALSE(b.get_extents()[2].is_valid());
505 ASSERT_TRUE(b.get_extents()[3].is_valid());
506 ASSERT_TRUE(b.get_extents()[4].is_valid());
507 }
508 {
509 BlueStore::Blob B;
510 B.shared_blob = new BlueStore::SharedBlob(nullptr);
511 B.shared_blob->get(); // hack to avoid dtor from running
512 bluestore_blob_t& b = B.dirty_blob();
513 PExtentVector r;
514 b.allocated_test(bluestore_pextent_t(1, mas * 6));
515 B.get_ref(coll.get(), 0, mas*6);
516 ASSERT_EQ(mas * 6, B.get_referenced_bytes());
517 ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
518 ASSERT_EQ(mas * 5, B.get_referenced_bytes());
519 cout << "r " << r << " " << b << std::endl;
520 ASSERT_EQ(0u, r.size());
521 ASSERT_TRUE(b.is_allocated(0, mas*6));
522 ASSERT_FALSE(B.put_ref(coll.get(), mas*2, mas, &r));
523 ASSERT_EQ(mas * 4, B.get_referenced_bytes());
524 cout << "r " << r << " " << b << std::endl;
525 ASSERT_EQ(0u, r.size());
526 ASSERT_TRUE(b.is_allocated(0, mas*6));
527 ASSERT_FALSE(B.put_ref(coll.get(), mas*3, mas, &r));
528 ASSERT_EQ(mas * 3, B.get_referenced_bytes());
529 cout << "r " << r << " " << b << std::endl;
530 ASSERT_EQ(1u, r.size());
531 ASSERT_EQ(0x2001u, r[0].offset);
532 ASSERT_EQ(mas*2, r[0].length);
533 ASSERT_TRUE(b.is_allocated(0, mas*2));
534 ASSERT_FALSE(b.is_allocated(mas*2, mas*2));
535 ASSERT_TRUE(b.is_allocated(mas*4, mas*2));
536 ASSERT_EQ(3u, b.get_extents().size());
537 ASSERT_TRUE(b.get_extents()[0].is_valid());
538 ASSERT_FALSE(b.get_extents()[1].is_valid());
539 ASSERT_TRUE(b.get_extents()[2].is_valid());
540 }
541 {
542 BlueStore::Blob B;
543 B.shared_blob = new BlueStore::SharedBlob(nullptr);
544 B.shared_blob->get(); // hack to avoid dtor from running
545 bluestore_blob_t& b = B.dirty_blob();
546 PExtentVector r;
547 b.allocated_test(bluestore_pextent_t(1, mas * 4));
548 b.allocated_test(bluestore_pextent_t(2, mas * 4));
549 b.allocated_test(bluestore_pextent_t(3, mas * 4));
550 B.get_ref(coll.get(), 0, mas*12);
551 ASSERT_EQ(mas * 12, B.get_referenced_bytes());
552 ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
553 ASSERT_EQ(mas * 11, B.get_referenced_bytes());
554 cout << "r " << r << " " << b << std::endl;
555 ASSERT_EQ(0u, r.size());
556 ASSERT_TRUE(b.is_allocated(0, mas*12));
557 ASSERT_FALSE(B.put_ref(coll.get(), mas*9, mas, &r));
558 ASSERT_EQ(mas * 10, B.get_referenced_bytes());
559 cout << "r " << r << " " << b << std::endl;
560 ASSERT_EQ(0u, r.size());
561 ASSERT_TRUE(b.is_allocated(0, mas*12));
562 ASSERT_FALSE(B.put_ref(coll.get(), mas*2, mas*7, &r));
563 ASSERT_EQ(mas * 3, B.get_referenced_bytes());
564 cout << "r " << r << " " << b << std::endl;
565 ASSERT_EQ(3u, r.size());
566 ASSERT_EQ(0x2001u, r[0].offset);
567 ASSERT_EQ(mas*2, r[0].length);
568 ASSERT_EQ(0x2u, r[1].offset);
569 ASSERT_EQ(mas*4, r[1].length);
570 ASSERT_EQ(0x3u, r[2].offset);
571 ASSERT_EQ(mas*2, r[2].length);
572 ASSERT_TRUE(b.is_allocated(0, mas*2));
573 ASSERT_FALSE(b.is_allocated(mas*2, mas*8));
574 ASSERT_TRUE(b.is_allocated(mas*10, mas*2));
575 ASSERT_EQ(3u, b.get_extents().size());
576 ASSERT_TRUE(b.get_extents()[0].is_valid());
577 ASSERT_FALSE(b.get_extents()[1].is_valid());
578 ASSERT_TRUE(b.get_extents()[2].is_valid());
579 }
580 {
581 BlueStore::Blob B;
582 B.shared_blob = new BlueStore::SharedBlob(nullptr);
583 B.shared_blob->get(); // hack to avoid dtor from running
584 bluestore_blob_t& b = B.dirty_blob();
585 PExtentVector r;
586 b.allocated_test(bluestore_pextent_t(1, mas * 4));
587 b.allocated_test(bluestore_pextent_t(2, mas * 4));
588 b.allocated_test(bluestore_pextent_t(3, mas * 4));
589 B.get_ref(coll.get(), 0, mas*12);
590 ASSERT_EQ(mas * 12, B.get_referenced_bytes());
591 ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
592 ASSERT_EQ(mas * 11, B.get_referenced_bytes());
593 cout << "r " << r << " " << b << std::endl;
594 ASSERT_EQ(0u, r.size());
595 ASSERT_TRUE(b.is_allocated(0, mas*12));
596 ASSERT_FALSE(B.put_ref(coll.get(), mas*9, mas, &r));
597 ASSERT_EQ(mas * 10, B.get_referenced_bytes());
598 cout << "r " << r << " " << b << std::endl;
599 ASSERT_EQ(0u, r.size());
600 ASSERT_TRUE(b.is_allocated(0, mas*12));
601 ASSERT_FALSE(B.put_ref(coll.get(), mas*2, mas*7, &r));
602 ASSERT_EQ(mas * 3, B.get_referenced_bytes());
603 cout << "r " << r << " " << b << std::endl;
604 ASSERT_EQ(3u, r.size());
605 ASSERT_EQ(0x2001u, r[0].offset);
606 ASSERT_EQ(mas*2, r[0].length);
607 ASSERT_EQ(0x2u, r[1].offset);
608 ASSERT_EQ(mas*4, r[1].length);
609 ASSERT_EQ(0x3u, r[2].offset);
610 ASSERT_EQ(mas*2, r[2].length);
611 ASSERT_TRUE(b.is_allocated(0, mas*2));
612 ASSERT_FALSE(b.is_allocated(mas*2, mas*8));
613 ASSERT_TRUE(b.is_allocated(mas*10, mas*2));
614 ASSERT_EQ(3u, b.get_extents().size());
615 ASSERT_TRUE(b.get_extents()[0].is_valid());
616 ASSERT_FALSE(b.get_extents()[1].is_valid());
617 ASSERT_TRUE(b.get_extents()[2].is_valid());
618 ASSERT_FALSE(B.put_ref(coll.get(), 0, mas, &r));
619 ASSERT_EQ(mas * 2, B.get_referenced_bytes());
620 cout << "r " << r << " " << b << std::endl;
621 ASSERT_EQ(1u, r.size());
622 ASSERT_EQ(0x1u, r[0].offset);
623 ASSERT_EQ(mas*2, r[0].length);
624 ASSERT_EQ(2u, b.get_extents().size());
625 ASSERT_FALSE(b.get_extents()[0].is_valid());
626 ASSERT_TRUE(b.get_extents()[1].is_valid());
627 ASSERT_TRUE(B.put_ref(coll.get(), mas*10, mas*2, &r));
628 ASSERT_EQ(mas * 0, B.get_referenced_bytes());
629 cout << "r " << r << " " << b << std::endl;
630 ASSERT_EQ(1u, r.size());
631 ASSERT_EQ(0x2003u, r[0].offset);
632 ASSERT_EQ(mas*2, r[0].length);
633 ASSERT_EQ(1u, b.get_extents().size());
634 ASSERT_FALSE(b.get_extents()[0].is_valid());
635 }
636 {
637 BlueStore::Blob B;
638 B.shared_blob = new BlueStore::SharedBlob(nullptr);
639 B.shared_blob->get(); // hack to avoid dtor from running
640 bluestore_blob_t& b = B.dirty_blob();
641 PExtentVector r;
642 b.allocated_test(bluestore_pextent_t(1, mas * 4));
643 b.allocated_test(bluestore_pextent_t(2, mas * 4));
644 b.allocated_test(bluestore_pextent_t(3, mas * 4));
645 B.get_ref(coll.get(), 0, mas*12);
646 ASSERT_EQ(mas * 12, B.get_referenced_bytes());
647 ASSERT_FALSE(B.put_ref(coll.get(), mas, mas, &r));
648 ASSERT_EQ(mas * 11, B.get_referenced_bytes());
649 cout << "r " << r << " " << b << std::endl;
650 ASSERT_EQ(0u, r.size());
651 ASSERT_TRUE(b.is_allocated(0, mas*12));
652 ASSERT_FALSE(B.put_ref(coll.get(), mas*9, mas, &r));
653 ASSERT_EQ(mas * 10, B.get_referenced_bytes());
654 cout << "r " << r << " " << b << std::endl;
655 ASSERT_EQ(0u, r.size());
656 ASSERT_TRUE(b.is_allocated(0, mas*12));
657 ASSERT_FALSE(B.put_ref(coll.get(), mas*2, mas*7, &r));
658 ASSERT_EQ(mas * 3, B.get_referenced_bytes());
659 cout << "r " << r << " " << b << std::endl;
660 ASSERT_EQ(3u, r.size());
661 ASSERT_EQ(0x2001u, r[0].offset);
662 ASSERT_EQ(mas*2, r[0].length);
663 ASSERT_EQ(0x2u, r[1].offset);
664 ASSERT_EQ(mas*4, r[1].length);
665 ASSERT_EQ(0x3u, r[2].offset);
666 ASSERT_EQ(mas*2, r[2].length);
667 ASSERT_TRUE(b.is_allocated(0, mas*2));
668 ASSERT_FALSE(b.is_allocated(mas*2, mas*8));
669 ASSERT_TRUE(b.is_allocated(mas*10, mas*2));
670 ASSERT_EQ(3u, b.get_extents().size());
671 ASSERT_TRUE(b.get_extents()[0].is_valid());
672 ASSERT_FALSE(b.get_extents()[1].is_valid());
673 ASSERT_TRUE(b.get_extents()[2].is_valid());
674 ASSERT_FALSE(B.put_ref(coll.get(), mas*10, mas*2, &r));
675 ASSERT_EQ(mas * 1, B.get_referenced_bytes());
676 cout << "r " << r << " " << b << std::endl;
677 ASSERT_EQ(1u, r.size());
678 ASSERT_EQ(0x2003u, r[0].offset);
679 ASSERT_EQ(mas*2, r[0].length);
680 ASSERT_EQ(2u, b.get_extents().size());
681 ASSERT_TRUE(b.get_extents()[0].is_valid());
682 ASSERT_FALSE(b.get_extents()[1].is_valid());
683 ASSERT_TRUE(B.put_ref(coll.get(), 0, mas, &r));
684 ASSERT_EQ(mas * 0, B.get_referenced_bytes());
685 cout << "r " << r << " " << b << std::endl;
686 ASSERT_EQ(1u, r.size());
687 ASSERT_EQ(0x1u, r[0].offset);
688 ASSERT_EQ(mas*2, r[0].length);
689 ASSERT_EQ(1u, b.get_extents().size());
690 ASSERT_FALSE(b.get_extents()[0].is_valid());
691 }
692 {
693 BlueStore::Blob B;
694 B.shared_blob = new BlueStore::SharedBlob(nullptr);
695 B.shared_blob->get(); // hack to avoid dtor from running
696 bluestore_blob_t& b = B.dirty_blob();
697 PExtentVector r;
698 b.allocated_test(bluestore_pextent_t(1, mas * 8));
699 B.get_ref(coll.get(), 0, mas*8);
700 ASSERT_EQ(mas * 8, B.get_referenced_bytes());
701 ASSERT_FALSE(B.put_ref(coll.get(), 0, mas, &r));
702 ASSERT_EQ(mas * 7, B.get_referenced_bytes());
703 cout << "r " << r << " " << b << std::endl;
704 ASSERT_EQ(0u, r.size());
705 ASSERT_TRUE(b.is_allocated(0, mas*8));
706 ASSERT_FALSE(B.put_ref(coll.get(), mas*7, mas, &r));
707 ASSERT_EQ(mas * 6, B.get_referenced_bytes());
708 cout << "r " << r << " " << b << std::endl;
709 ASSERT_EQ(0u, r.size());
710 ASSERT_TRUE(b.is_allocated(0, mas*8));
711 ASSERT_FALSE(B.put_ref(coll.get(), mas*2, mas, &r));
712 ASSERT_EQ(mas * 5, B.get_referenced_bytes());
713 cout << "r " << r << " " << b << std::endl;
714 ASSERT_EQ(0u, r.size());
715 ASSERT_TRUE(b.is_allocated(0, 8));
716 ASSERT_FALSE(B.put_ref(coll.get(), mas*3, mas*4, &r));
717 ASSERT_EQ(mas * 1, B.get_referenced_bytes());
718 ASSERT_EQ(1u, r.size());
719 ASSERT_EQ(0x2001u, r[0].offset);
720 ASSERT_EQ(mas*6, r[0].length);
721 ASSERT_TRUE(b.is_allocated(0, mas*2));
722 ASSERT_FALSE(b.is_allocated(mas*2, mas*6));
723 ASSERT_EQ(2u, b.get_extents().size());
724 ASSERT_TRUE(b.get_extents()[0].is_valid());
725 ASSERT_FALSE(b.get_extents()[1].is_valid());
726 ASSERT_TRUE(B.put_ref(coll.get(), mas, mas, &r));
727 ASSERT_EQ(mas * 0, B.get_referenced_bytes());
728 cout << "r " << r << " " << b << std::endl;
729 ASSERT_EQ(1u, r.size());
730 ASSERT_EQ(0x1u, r[0].offset);
731 ASSERT_EQ(mas*2, r[0].length);
732 ASSERT_EQ(1u, b.get_extents().size());
733 ASSERT_FALSE(b.get_extents()[0].is_valid());
734 }
735 // verify csum chunk size if factored in properly
736 {
737 BlueStore::Blob B;
738 B.shared_blob = new BlueStore::SharedBlob(nullptr);
739 B.shared_blob->get(); // hack to avoid dtor from running
740 bluestore_blob_t& b = B.dirty_blob();
741 PExtentVector r;
742 b.allocated_test(bluestore_pextent_t(0, mas*4));
743 b.init_csum(Checksummer::CSUM_CRC32C, 14, mas * 4);
744 B.get_ref(coll.get(), 0, mas*4);
745 ASSERT_EQ(mas * 4, B.get_referenced_bytes());
746 ASSERT_TRUE(b.is_allocated(0, mas*4));
747 ASSERT_FALSE(B.put_ref(coll.get(), 0, mas*3, &r));
748 ASSERT_EQ(mas * 1, B.get_referenced_bytes());
749 cout << "r " << r << " " << b << std::endl;
750 ASSERT_EQ(0u, r.size());
751 ASSERT_TRUE(b.is_allocated(0, mas*4));
752 ASSERT_TRUE(b.get_extents()[0].is_valid());
753 ASSERT_EQ(mas*4, b.get_extents()[0].length);
754 }
755 {
756 BlueStore::Blob B;
757 B.shared_blob = new BlueStore::SharedBlob(nullptr);
758 B.shared_blob->get(); // hack to avoid dtor from running
759 bluestore_blob_t& b = B.dirty_blob();
760 b.allocated_test(bluestore_pextent_t(0x40101000, 0x4000));
761 b.allocated_test(bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET,
762 0x13000));
763
764 b.allocated_test(bluestore_pextent_t(0x40118000, 0x7000));
765 B.get_ref(coll.get(), 0x0, 0x3800);
766 B.get_ref(coll.get(), 0x17c00, 0x6400);
767 ASSERT_EQ(0x3800u + 0x6400u, B.get_referenced_bytes());
768 b.set_flag(bluestore_blob_t::FLAG_SHARED);
769 b.init_csum(Checksummer::CSUM_CRC32C, 12, 0x1e000);
770
771 cout << "before: " << B << std::endl;
772 PExtentVector r;
773 ASSERT_FALSE(B.put_ref(coll.get(), 0x1800, 0x2000, &r));
774 ASSERT_EQ(0x3800u + 0x6400u - 0x2000u, B.get_referenced_bytes());
775 cout << "after: " << B << std::endl;
776 cout << "r " << r << std::endl;
777 }
778 {
779 BlueStore::Blob B;
780 B.shared_blob = new BlueStore::SharedBlob(nullptr);
781 B.shared_blob->get(); // hack to avoid dtor from running
782 bluestore_blob_t& b = B.dirty_blob();
783 b.allocated_test(bluestore_pextent_t(1, 0x5000));
784 b.allocated_test(bluestore_pextent_t(2, 0x5000));
785 B.get_ref(coll.get(), 0x0, 0xa000);
786 ASSERT_EQ(0xa000u, B.get_referenced_bytes());
787 cout << "before: " << B << std::endl;
788 PExtentVector r;
789 ASSERT_FALSE(B.put_ref(coll.get(), 0x8000, 0x2000, &r));
790 cout << "after: " << B << std::endl;
791 cout << "r " << r << std::endl;
792 ASSERT_EQ(0x8000u, B.get_referenced_bytes());
793 ASSERT_EQ(1u, r.size());
794 ASSERT_EQ(0x3002u, r[0].offset);
795 ASSERT_EQ(0x2000u, r[0].length);
796 }
797 {
798 BlueStore::Blob B;
799 B.shared_blob = new BlueStore::SharedBlob(nullptr);
800 B.shared_blob->get(); // hack to avoid dtor from running
801 bluestore_blob_t& b = B.dirty_blob();
802 b.allocated_test(bluestore_pextent_t(1, 0x7000));
803 b.allocated_test(bluestore_pextent_t(2, 0x7000));
804 B.get_ref(coll.get(), 0x0, 0xe000);
805 ASSERT_EQ(0xe000u, B.get_referenced_bytes());
806 cout << "before: " << B << std::endl;
807 PExtentVector r;
808 ASSERT_FALSE(B.put_ref(coll.get(), 0, 0xb000, &r));
809 ASSERT_EQ(0x3000u, B.get_referenced_bytes());
810 cout << "after: " << B << std::endl;
811 cout << "r " << r << std::endl;
812 ASSERT_EQ(0x3000u, B.get_referenced_bytes());
813 ASSERT_EQ(2u, r.size());
814 ASSERT_EQ(1u, r[0].offset);
815 ASSERT_EQ(0x7000u, r[0].length);
816 ASSERT_EQ(2u, r[1].offset);
817 ASSERT_EQ(0x3000u, r[1].length); // we have 0x1000 bytes less due to
818 // alignment caused by min_alloc_size = 0x2000
819 }
820 {
821 BlueStore store(g_ceph_context, "", 0x4000);
822 BlueStore::OnodeCacheShard *oc = BlueStore::OnodeCacheShard::create(
823 g_ceph_context, "lru", NULL);
824 BlueStore::BufferCacheShard *bc = BlueStore::BufferCacheShard::create(
825 g_ceph_context, "lru", NULL);
826
827 auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
828 BlueStore::Blob B;
829 B.shared_blob = new BlueStore::SharedBlob(nullptr);
830 B.shared_blob->get(); // hack to avoid dtor from running
831 bluestore_blob_t& b = B.dirty_blob();
832 b.allocated_test(bluestore_pextent_t(1, 0x5000));
833 b.allocated_test(bluestore_pextent_t(2, 0x7000));
834 B.get_ref(coll.get(), 0x0, 0xc000);
835 ASSERT_EQ(0xc000u, B.get_referenced_bytes());
836 cout << "before: " << B << std::endl;
837 PExtentVector r;
838 ASSERT_FALSE(B.put_ref(coll.get(), 0x2000, 0xa000, &r));
839 cout << "after: " << B << std::endl;
840 cout << "r " << r << std::endl;
841 ASSERT_EQ(0x2000u, B.get_referenced_bytes());
842 ASSERT_EQ(2u, r.size());
843 ASSERT_EQ(0x4001u, r[0].offset);
844 ASSERT_EQ(0x1000u, r[0].length);
845 ASSERT_EQ(2u, r[1].offset);
846 ASSERT_EQ(0x7000u, r[1].length);
847 ASSERT_EQ(1u, b.get_extents()[0].offset);
848 ASSERT_EQ(0x4000u, b.get_extents()[0].length);
849 }
850 }
851
852 TEST(bluestore_blob_t, can_split)
853 {
854 bluestore_blob_t a;
855 ASSERT_TRUE(a.can_split());
856 a.flags = bluestore_blob_t::FLAG_SHARED;
857 ASSERT_FALSE(a.can_split());
858 a.flags = bluestore_blob_t::FLAG_COMPRESSED;
859 ASSERT_FALSE(a.can_split());
860 a.flags = bluestore_blob_t::FLAG_HAS_UNUSED;
861 ASSERT_FALSE(a.can_split());
862 }
863
864 TEST(bluestore_blob_t, can_split_at)
865 {
866 bluestore_blob_t a;
867 a.allocated_test(bluestore_pextent_t(0x10000, 0x2000));
868 a.allocated_test(bluestore_pextent_t(0x20000, 0x2000));
869 ASSERT_TRUE(a.can_split_at(0x1000));
870 ASSERT_TRUE(a.can_split_at(0x1800));
871 a.init_csum(Checksummer::CSUM_CRC32C, 12, 0x4000);
872 ASSERT_TRUE(a.can_split_at(0x1000));
873 ASSERT_TRUE(a.can_split_at(0x2000));
874 ASSERT_TRUE(a.can_split_at(0x3000));
875 ASSERT_FALSE(a.can_split_at(0x2800));
876 }
877
878 TEST(bluestore_blob_t, prune_tail)
879 {
880 bluestore_blob_t a;
881 a.allocated_test(bluestore_pextent_t(0x10000, 0x2000));
882 a.allocated_test(bluestore_pextent_t(0x20000, 0x2000));
883 ASSERT_FALSE(a.can_prune_tail());
884 a.allocated_test(
885 bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET, 0x2000));
886 ASSERT_TRUE(a.can_prune_tail());
887 a.prune_tail();
888 ASSERT_FALSE(a.can_prune_tail());
889 ASSERT_EQ(2u, a.get_extents().size());
890 ASSERT_EQ(0x4000u, a.get_logical_length());
891
892 a.allocated_test(
893 bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET, 0x2000));
894 a.init_csum(Checksummer::CSUM_CRC32C_8, 12, 0x6000);
895 ASSERT_EQ(6u, a.csum_data.length());
896 ASSERT_TRUE(a.can_prune_tail());
897 a.prune_tail();
898 ASSERT_FALSE(a.can_prune_tail());
899 ASSERT_EQ(2u, a.get_extents().size());
900 ASSERT_EQ(0x4000u, a.get_logical_length());
901 ASSERT_EQ(4u, a.csum_data.length());
902
903 bluestore_blob_t b;
904 b.allocated_test(
905 bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET, 0x2000));
906 ASSERT_FALSE(a.can_prune_tail());
907 }
908
909 TEST(Blob, split)
910 {
911 BlueStore store(g_ceph_context, "", 4096);
912 BlueStore::OnodeCacheShard *oc = BlueStore::OnodeCacheShard::create(
913 g_ceph_context, "lru", NULL);
914 BlueStore::BufferCacheShard *bc = BlueStore::BufferCacheShard::create(
915 g_ceph_context, "lru", NULL);
916 auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
917 {
918 BlueStore::Blob L, R;
919 L.shared_blob = new BlueStore::SharedBlob(coll.get());
920 L.shared_blob->get(); // hack to avoid dtor from running
921 R.shared_blob = new BlueStore::SharedBlob(coll.get());
922 R.shared_blob->get(); // hack to avoid dtor from running
923 L.dirty_blob().allocated_test(bluestore_pextent_t(0x2000, 0x2000));
924 L.dirty_blob().init_csum(Checksummer::CSUM_CRC32C, 12, 0x2000);
925 L.get_ref(coll.get(), 0, 0x2000);
926 L.split(coll.get(), 0x1000, &R);
927 ASSERT_EQ(0x1000u, L.get_blob().get_logical_length());
928 ASSERT_EQ(4u, L.get_blob().csum_data.length());
929 ASSERT_EQ(1u, L.get_blob().get_extents().size());
930 ASSERT_EQ(0x2000u, L.get_blob().get_extents().front().offset);
931 ASSERT_EQ(0x1000u, L.get_blob().get_extents().front().length);
932 ASSERT_EQ(0x1000u, L.get_referenced_bytes());
933 ASSERT_EQ(0x1000u, R.get_blob().get_logical_length());
934 ASSERT_EQ(4u, R.get_blob().csum_data.length());
935 ASSERT_EQ(1u, R.get_blob().get_extents().size());
936 ASSERT_EQ(0x3000u, R.get_blob().get_extents().front().offset);
937 ASSERT_EQ(0x1000u, R.get_blob().get_extents().front().length);
938 ASSERT_EQ(0x1000u, R.get_referenced_bytes());
939 }
940 {
941 BlueStore::Blob L, R;
942 L.shared_blob = new BlueStore::SharedBlob(coll.get());
943 L.shared_blob->get(); // hack to avoid dtor from running
944 R.shared_blob = new BlueStore::SharedBlob(coll.get());
945 R.shared_blob->get(); // hack to avoid dtor from running
946 L.dirty_blob().allocated_test(bluestore_pextent_t(0x2000, 0x1000));
947 L.dirty_blob().allocated_test(bluestore_pextent_t(0x12000, 0x1000));
948 L.dirty_blob().init_csum(Checksummer::CSUM_CRC32C, 12, 0x2000);
949 L.get_ref(coll.get(), 0, 0x1000);
950 L.get_ref(coll.get(), 0x1000, 0x1000);
951 L.split(coll.get(), 0x1000, &R);
952 ASSERT_EQ(0x1000u, L.get_blob().get_logical_length());
953 ASSERT_EQ(4u, L.get_blob().csum_data.length());
954 ASSERT_EQ(1u, L.get_blob().get_extents().size());
955 ASSERT_EQ(0x2000u, L.get_blob().get_extents().front().offset);
956 ASSERT_EQ(0x1000u, L.get_blob().get_extents().front().length);
957 ASSERT_EQ(0x1000u, L.get_referenced_bytes());
958 ASSERT_EQ(0x1000u, R.get_blob().get_logical_length());
959 ASSERT_EQ(4u, R.get_blob().csum_data.length());
960 ASSERT_EQ(1u, R.get_blob().get_extents().size());
961 ASSERT_EQ(0x12000u, R.get_blob().get_extents().front().offset);
962 ASSERT_EQ(0x1000u, R.get_blob().get_extents().front().length);
963 ASSERT_EQ(0x1000u, R.get_referenced_bytes());
964 }
965 }
966
967 TEST(Blob, legacy_decode)
968 {
969 BlueStore store(g_ceph_context, "", 4096);
970 BlueStore::OnodeCacheShard *oc = BlueStore::OnodeCacheShard::create(
971 g_ceph_context, "lru", NULL);
972 BlueStore::BufferCacheShard *bc = BlueStore::BufferCacheShard::create(
973 g_ceph_context, "lru", NULL);
974 auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
975 bufferlist bl, bl2;
976 {
977 BlueStore::Blob B;
978
979 B.shared_blob = new BlueStore::SharedBlob(coll.get());
980 B.dirty_blob().allocated_test(bluestore_pextent_t(0x1, 0x2000));
981 B.dirty_blob().init_csum(Checksummer::CSUM_CRC32C, 12, 0x2000);
982 B.get_ref(coll.get(), 0, 0xff0);
983 B.get_ref(coll.get(), 0x1fff, 1);
984
985 bluestore_extent_ref_map_t fake_ref_map;
986 fake_ref_map.get(0, 0xff0);
987 fake_ref_map.get(0x1fff, 1);
988
989 size_t bound = 0, bound2 = 0;
990
991 B.bound_encode(
992 bound,
993 1, /*struct_v*/
994 0, /*sbid*/
995 false);
996 fake_ref_map.bound_encode(bound);
997
998 B.bound_encode(
999 bound2,
1000 2, /*struct_v*/
1001 0, /*sbid*/
1002 true);
1003
1004 {
1005 auto app = bl.get_contiguous_appender(bound);
1006 auto app2 = bl2.get_contiguous_appender(bound2);
1007 B.encode(
1008 app,
1009 1, /*struct_v*/
1010 0, /*sbid*/
1011 false);
1012 fake_ref_map.encode(app);
1013
1014 B.encode(
1015 app2,
1016 2, /*struct_v*/
1017 0, /*sbid*/
1018 true);
1019 }
1020
1021 auto p = bl.front().begin_deep();
1022 auto p2 = bl2.front().begin_deep();
1023 BlueStore::Blob Bres, Bres2;
1024 Bres.shared_blob = new BlueStore::SharedBlob(coll.get());
1025 Bres2.shared_blob = new BlueStore::SharedBlob(coll.get());
1026
1027 uint64_t sbid, sbid2;
1028 Bres.decode(
1029 coll.get(),
1030 p,
1031 1, /*struct_v*/
1032 &sbid,
1033 true);
1034 Bres2.decode(
1035 coll.get(),
1036 p2,
1037 2, /*struct_v*/
1038 &sbid2,
1039 true);
1040
1041 ASSERT_EQ(0xff0u + 1u, Bres.get_blob_use_tracker().get_referenced_bytes());
1042 ASSERT_EQ(0xff0u + 1u, Bres2.get_blob_use_tracker().get_referenced_bytes());
1043 ASSERT_TRUE(Bres.get_blob_use_tracker().equal(Bres2.get_blob_use_tracker()));
1044 }
1045 }
1046
1047 TEST(ExtentMap, seek_lextent)
1048 {
1049 BlueStore store(g_ceph_context, "", 4096);
1050 BlueStore::OnodeCacheShard *oc = BlueStore::OnodeCacheShard::create(
1051 g_ceph_context, "lru", NULL);
1052 BlueStore::BufferCacheShard *bc = BlueStore::BufferCacheShard::create(
1053 g_ceph_context, "lru", NULL);
1054
1055 auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
1056 BlueStore::Onode onode(coll.get(), ghobject_t(), "");
1057 BlueStore::ExtentMap em(&onode);
1058 BlueStore::BlobRef br(new BlueStore::Blob);
1059 br->shared_blob = new BlueStore::SharedBlob(coll.get());
1060
1061 ASSERT_EQ(em.extent_map.end(), em.seek_lextent(0));
1062 ASSERT_EQ(em.extent_map.end(), em.seek_lextent(100));
1063
1064 em.extent_map.insert(*new BlueStore::Extent(100, 0, 100, br));
1065 auto a = em.find(100);
1066 ASSERT_EQ(a, em.seek_lextent(0));
1067 ASSERT_EQ(a, em.seek_lextent(99));
1068 ASSERT_EQ(a, em.seek_lextent(100));
1069 ASSERT_EQ(a, em.seek_lextent(101));
1070 ASSERT_EQ(a, em.seek_lextent(199));
1071 ASSERT_EQ(em.extent_map.end(), em.seek_lextent(200));
1072
1073 em.extent_map.insert(*new BlueStore::Extent(200, 0, 100, br));
1074 auto b = em.find(200);
1075 ASSERT_EQ(a, em.seek_lextent(0));
1076 ASSERT_EQ(a, em.seek_lextent(99));
1077 ASSERT_EQ(a, em.seek_lextent(100));
1078 ASSERT_EQ(a, em.seek_lextent(101));
1079 ASSERT_EQ(a, em.seek_lextent(199));
1080 ASSERT_EQ(b, em.seek_lextent(200));
1081 ASSERT_EQ(b, em.seek_lextent(299));
1082 ASSERT_EQ(em.extent_map.end(), em.seek_lextent(300));
1083
1084 em.extent_map.insert(*new BlueStore::Extent(400, 0, 100, br));
1085 auto d = em.find(400);
1086 ASSERT_EQ(a, em.seek_lextent(0));
1087 ASSERT_EQ(a, em.seek_lextent(99));
1088 ASSERT_EQ(a, em.seek_lextent(100));
1089 ASSERT_EQ(a, em.seek_lextent(101));
1090 ASSERT_EQ(a, em.seek_lextent(199));
1091 ASSERT_EQ(b, em.seek_lextent(200));
1092 ASSERT_EQ(b, em.seek_lextent(299));
1093 ASSERT_EQ(d, em.seek_lextent(300));
1094 ASSERT_EQ(d, em.seek_lextent(399));
1095 ASSERT_EQ(d, em.seek_lextent(400));
1096 ASSERT_EQ(d, em.seek_lextent(499));
1097 ASSERT_EQ(em.extent_map.end(), em.seek_lextent(500));
1098 }
1099
1100 TEST(ExtentMap, has_any_lextents)
1101 {
1102 BlueStore store(g_ceph_context, "", 4096);
1103 BlueStore::OnodeCacheShard *oc = BlueStore::OnodeCacheShard::create(
1104 g_ceph_context, "lru", NULL);
1105 BlueStore::BufferCacheShard *bc = BlueStore::BufferCacheShard::create(
1106 g_ceph_context, "lru", NULL);
1107 auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
1108 BlueStore::Onode onode(coll.get(), ghobject_t(), "");
1109 BlueStore::ExtentMap em(&onode);
1110 BlueStore::BlobRef b(new BlueStore::Blob);
1111 b->shared_blob = new BlueStore::SharedBlob(coll.get());
1112
1113 ASSERT_FALSE(em.has_any_lextents(0, 0));
1114 ASSERT_FALSE(em.has_any_lextents(0, 1000));
1115 ASSERT_FALSE(em.has_any_lextents(1000, 1000));
1116
1117 em.extent_map.insert(*new BlueStore::Extent(100, 0, 100, b));
1118 ASSERT_FALSE(em.has_any_lextents(0, 50));
1119 ASSERT_FALSE(em.has_any_lextents(0, 100));
1120 ASSERT_FALSE(em.has_any_lextents(50, 50));
1121 ASSERT_TRUE(em.has_any_lextents(50, 51));
1122 ASSERT_TRUE(em.has_any_lextents(50, 100051));
1123 ASSERT_TRUE(em.has_any_lextents(100, 100));
1124 ASSERT_TRUE(em.has_any_lextents(100, 1));
1125 ASSERT_TRUE(em.has_any_lextents(199, 1));
1126 ASSERT_TRUE(em.has_any_lextents(199, 2));
1127 ASSERT_FALSE(em.has_any_lextents(200, 2));
1128
1129 em.extent_map.insert(*new BlueStore::Extent(200, 0, 100, b));
1130 ASSERT_TRUE(em.has_any_lextents(199, 1));
1131 ASSERT_TRUE(em.has_any_lextents(199, 2));
1132 ASSERT_TRUE(em.has_any_lextents(200, 2));
1133 ASSERT_TRUE(em.has_any_lextents(200, 200));
1134 ASSERT_TRUE(em.has_any_lextents(299, 1));
1135 ASSERT_FALSE(em.has_any_lextents(300, 1));
1136
1137 em.extent_map.insert(*new BlueStore::Extent(400, 0, 100, b));
1138 ASSERT_TRUE(em.has_any_lextents(0, 10000));
1139 ASSERT_TRUE(em.has_any_lextents(199, 1));
1140 ASSERT_FALSE(em.has_any_lextents(300, 1));
1141 ASSERT_FALSE(em.has_any_lextents(300, 100));
1142 ASSERT_FALSE(em.has_any_lextents(399, 1));
1143 ASSERT_TRUE(em.has_any_lextents(400, 1));
1144 ASSERT_TRUE(em.has_any_lextents(400, 100));
1145 ASSERT_TRUE(em.has_any_lextents(400, 1000));
1146 ASSERT_TRUE(em.has_any_lextents(499, 1000));
1147 ASSERT_FALSE(em.has_any_lextents(500, 1000));
1148 }
1149
1150 TEST(ExtentMap, compress_extent_map)
1151 {
1152 BlueStore store(g_ceph_context, "", 4096);
1153 BlueStore::OnodeCacheShard *oc = BlueStore::OnodeCacheShard::create(
1154 g_ceph_context, "lru", NULL);
1155 BlueStore::BufferCacheShard *bc = BlueStore::BufferCacheShard::create(
1156 g_ceph_context, "lru", NULL);
1157
1158 auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
1159 BlueStore::Onode onode(coll.get(), ghobject_t(), "");
1160 BlueStore::ExtentMap em(&onode);
1161 BlueStore::BlobRef b1(new BlueStore::Blob);
1162 BlueStore::BlobRef b2(new BlueStore::Blob);
1163 BlueStore::BlobRef b3(new BlueStore::Blob);
1164 b1->shared_blob = new BlueStore::SharedBlob(coll.get());
1165 b2->shared_blob = new BlueStore::SharedBlob(coll.get());
1166 b3->shared_blob = new BlueStore::SharedBlob(coll.get());
1167
1168 em.extent_map.insert(*new BlueStore::Extent(0, 0, 100, b1));
1169 em.extent_map.insert(*new BlueStore::Extent(100, 0, 100, b2));
1170 ASSERT_EQ(0, em.compress_extent_map(0, 10000));
1171 ASSERT_EQ(2u, em.extent_map.size());
1172
1173 em.extent_map.insert(*new BlueStore::Extent(200, 100, 100, b2));
1174 em.extent_map.insert(*new BlueStore::Extent(300, 200, 100, b2));
1175 ASSERT_EQ(0, em.compress_extent_map(0, 0));
1176 ASSERT_EQ(0, em.compress_extent_map(100000, 1000));
1177 ASSERT_EQ(2, em.compress_extent_map(0, 100000));
1178 ASSERT_EQ(2u, em.extent_map.size());
1179
1180 em.extent_map.erase(em.find(100));
1181 em.extent_map.insert(*new BlueStore::Extent(100, 0, 100, b2));
1182 em.extent_map.insert(*new BlueStore::Extent(200, 100, 100, b3));
1183 em.extent_map.insert(*new BlueStore::Extent(300, 200, 100, b2));
1184 ASSERT_EQ(0, em.compress_extent_map(0, 1));
1185 ASSERT_EQ(0, em.compress_extent_map(0, 100000));
1186 ASSERT_EQ(4u, em.extent_map.size());
1187
1188 em.extent_map.insert(*new BlueStore::Extent(400, 300, 100, b2));
1189 em.extent_map.insert(*new BlueStore::Extent(500, 500, 100, b2));
1190 em.extent_map.insert(*new BlueStore::Extent(600, 600, 100, b2));
1191 em.extent_map.insert(*new BlueStore::Extent(700, 0, 100, b1));
1192 em.extent_map.insert(*new BlueStore::Extent(800, 0, 100, b3));
1193 ASSERT_EQ(0, em.compress_extent_map(0, 99));
1194 ASSERT_EQ(0, em.compress_extent_map(800, 1000));
1195 ASSERT_EQ(2, em.compress_extent_map(100, 500));
1196 ASSERT_EQ(7u, em.extent_map.size());
1197 em.extent_map.erase(em.find(300));
1198 em.extent_map.erase(em.find(500));
1199 em.extent_map.erase(em.find(700));
1200 em.extent_map.insert(*new BlueStore::Extent(400, 300, 100, b2));
1201 em.extent_map.insert(*new BlueStore::Extent(500, 400, 100, b2));
1202 em.extent_map.insert(*new BlueStore::Extent(700, 500, 100, b2));
1203 ASSERT_EQ(1, em.compress_extent_map(0, 1000));
1204 ASSERT_EQ(6u, em.extent_map.size());
1205 }
1206
1207 TEST(GarbageCollector, BasicTest)
1208 {
1209 BlueStore::OnodeCacheShard *oc = BlueStore::OnodeCacheShard::create(
1210 g_ceph_context, "lru", NULL);
1211 BlueStore::BufferCacheShard *bc = BlueStore::BufferCacheShard::create(
1212 g_ceph_context, "lru", NULL);
1213
1214 BlueStore store(g_ceph_context, "", 4096);
1215 auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
1216 BlueStore::Onode onode(coll.get(), ghobject_t(), "");
1217 BlueStore::ExtentMap em(&onode);
1218
1219 BlueStore::old_extent_map_t old_extents;
1220
1221
1222 /*
1223 min_alloc_size = 4096
1224 original disposition
1225 extent1 <loffs = 100, boffs = 100, len = 10>
1226 -> blob1<compressed, len_on_disk=4096, logical_len=8192>
1227 extent2 <loffs = 200, boffs = 200, len = 10>
1228 -> blob2<raw, len_on_disk=4096, llen=4096>
1229 extent3 <loffs = 300, boffs = 300, len = 10>
1230 -> blob1<compressed, len_on_disk=4096, llen=8192>
1231 extent4 <loffs = 4096, boffs = 0, len = 10>
1232 -> blob3<raw, len_on_disk=4096, llen=4096>
1233 on write(300~100) resulted in
1234 extent1 <loffs = 100, boffs = 100, len = 10>
1235 -> blob1<compressed, len_on_disk=4096, logical_len=8192>
1236 extent2 <loffs = 200, boffs = 200, len = 10>
1237 -> blob2<raw, len_on_disk=4096, llen=4096>
1238 extent3 <loffs = 300, boffs = 300, len = 100>
1239 -> blob4<raw, len_on_disk=4096, llen=4096>
1240 extent4 <loffs = 4096, boffs = 0, len = 10>
1241 -> blob3<raw, len_on_disk=4096, llen=4096>
1242 */
1243 {
1244 BlueStore::GarbageCollector gc(g_ceph_context);
1245 int64_t saving;
1246 BlueStore::BlobRef b1(new BlueStore::Blob);
1247 BlueStore::BlobRef b2(new BlueStore::Blob);
1248 BlueStore::BlobRef b3(new BlueStore::Blob);
1249 BlueStore::BlobRef b4(new BlueStore::Blob);
1250 b1->shared_blob = new BlueStore::SharedBlob(coll.get());
1251 b2->shared_blob = new BlueStore::SharedBlob(coll.get());
1252 b3->shared_blob = new BlueStore::SharedBlob(coll.get());
1253 b4->shared_blob = new BlueStore::SharedBlob(coll.get());
1254 b1->dirty_blob().set_compressed(0x2000, 0x1000);
1255 b1->dirty_blob().allocated_test(bluestore_pextent_t(0, 0x1000));
1256 b2->dirty_blob().allocated_test(bluestore_pextent_t(1, 0x1000));
1257 b3->dirty_blob().allocated_test(bluestore_pextent_t(2, 0x1000));
1258 b4->dirty_blob().allocated_test(bluestore_pextent_t(3, 0x1000));
1259 em.extent_map.insert(*new BlueStore::Extent(100, 100, 10, b1));
1260 b1->get_ref(coll.get(), 100, 10);
1261 em.extent_map.insert(*new BlueStore::Extent(200, 200, 10, b2));
1262 b2->get_ref(coll.get(), 200, 10);
1263 em.extent_map.insert(*new BlueStore::Extent(300, 300, 100, b4));
1264 b4->get_ref(coll.get(), 300, 100);
1265 em.extent_map.insert(*new BlueStore::Extent(4096, 0, 10, b3));
1266 b3->get_ref(coll.get(), 0, 10);
1267
1268 old_extents.push_back(*new BlueStore::OldExtent(300, 300, 10, b1));
1269
1270 saving = gc.estimate(300, 100, em, old_extents, 4096);
1271 ASSERT_EQ(saving, 1);
1272 auto& to_collect = gc.get_extents_to_collect();
1273 ASSERT_EQ(to_collect.num_intervals(), 1u);
1274 {
1275 auto it = to_collect.begin();
1276 using p = decltype(*it);
1277 auto v = p{100ul, 10ul};
1278 ASSERT_EQ(*it, v);
1279 }
1280
1281 em.clear();
1282 old_extents.clear();
1283 }
1284 /*
1285 original disposition
1286 min_alloc_size = 0x10000
1287 extent1 <loffs = 0, boffs = 0, len = 0x40000>
1288 -> blob1<compressed, len_on_disk=0x20000, logical_len=0x40000>
1289 Write 0x8000~37000 resulted in the following extent map prior to GC
1290 for the last write_small(0x30000~0xf000):
1291
1292 extent1 <loffs = 0, boffs = 0, len = 0x8000>
1293 -> blob1<compressed, len_on_disk=0x20000, logical_len=0x40000>
1294 extent2 <loffs = 0x8000, boffs = 0x8000, len = 0x8000>
1295 -> blob2<raw, len_on_disk=0x10000, llen=0x10000>
1296 extent3 <loffs = 0x10000, boffs = 0, len = 0x20000>
1297 -> blob3<raw, len_on_disk=0x20000, llen=0x20000>
1298 extent4 <loffs = 0x30000, boffs = 0, len = 0xf000>
1299 -> blob4<raw, len_on_disk=0x10000, llen=0x10000>
1300 extent5 <loffs = 0x3f000, boffs = 0x3f000, len = 0x1000>
1301 -> blob1<compressed, len_on_disk=0x20000, llen=0x40000>
1302 */
1303 {
1304 BlueStore store(g_ceph_context, "", 0x10000);
1305 auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
1306 BlueStore::Onode onode(coll.get(), ghobject_t(), "");
1307 BlueStore::ExtentMap em(&onode);
1308
1309 BlueStore::old_extent_map_t old_extents;
1310 BlueStore::GarbageCollector gc(g_ceph_context);
1311 int64_t saving;
1312 BlueStore::BlobRef b1(new BlueStore::Blob);
1313 BlueStore::BlobRef b2(new BlueStore::Blob);
1314 BlueStore::BlobRef b3(new BlueStore::Blob);
1315 BlueStore::BlobRef b4(new BlueStore::Blob);
1316 b1->shared_blob = new BlueStore::SharedBlob(coll.get());
1317 b2->shared_blob = new BlueStore::SharedBlob(coll.get());
1318 b3->shared_blob = new BlueStore::SharedBlob(coll.get());
1319 b4->shared_blob = new BlueStore::SharedBlob(coll.get());
1320 b1->dirty_blob().set_compressed(0x40000, 0x20000);
1321 b1->dirty_blob().allocated_test(bluestore_pextent_t(0, 0x20000));
1322 b2->dirty_blob().allocated_test(bluestore_pextent_t(1, 0x10000));
1323 b3->dirty_blob().allocated_test(bluestore_pextent_t(2, 0x20000));
1324 b4->dirty_blob().allocated_test(bluestore_pextent_t(3, 0x10000));
1325
1326 em.extent_map.insert(*new BlueStore::Extent(0, 0, 0x8000, b1));
1327 b1->get_ref(coll.get(), 0, 0x8000);
1328 em.extent_map.insert(
1329 *new BlueStore::Extent(0x8000, 0x8000, 0x8000, b2)); // new extent
1330 b2->get_ref(coll.get(), 0x8000, 0x8000);
1331 em.extent_map.insert(
1332 *new BlueStore::Extent(0x10000, 0, 0x20000, b3)); // new extent
1333 b3->get_ref(coll.get(), 0, 0x20000);
1334 em.extent_map.insert(
1335 *new BlueStore::Extent(0x30000, 0, 0xf000, b4)); // new extent
1336 b4->get_ref(coll.get(), 0, 0xf000);
1337 em.extent_map.insert(*new BlueStore::Extent(0x3f000, 0x3f000, 0x1000, b1));
1338 b1->get_ref(coll.get(), 0x3f000, 0x1000);
1339
1340 old_extents.push_back(*new BlueStore::OldExtent(0x8000, 0x8000, 0x8000, b1));
1341 old_extents.push_back(
1342 *new BlueStore::OldExtent(0x10000, 0x10000, 0x20000, b1));
1343 old_extents.push_back(*new BlueStore::OldExtent(0x30000, 0x30000, 0xf000, b1));
1344
1345 saving = gc.estimate(0x30000, 0xf000, em, old_extents, 0x10000);
1346 ASSERT_EQ(saving, 2);
1347 auto& to_collect = gc.get_extents_to_collect();
1348 ASSERT_EQ(to_collect.num_intervals(), 2u);
1349 {
1350 auto it1 = to_collect.begin();
1351 auto it2 = ++to_collect.begin();
1352 using p = decltype(*it1);
1353 {
1354 auto v1 = p{0x0ul ,0x8000ul};
1355 auto v2 = p{0x0ul, 0x8000ul};
1356 ASSERT_TRUE(*it1 == v1 || *it2 == v2);
1357 }
1358 {
1359 auto v1 = p{0x3f000ul, 0x1000ul};
1360 auto v2 = p{0x3f000ul, 0x1000ul};
1361 ASSERT_TRUE(*it1 == v1 || *it2 == v2);
1362 }
1363 }
1364
1365 em.clear();
1366 old_extents.clear();
1367 }
1368 /*
1369 original disposition
1370 min_alloc_size = 0x1000
1371 extent1 <loffs = 0, boffs = 0, len = 0x4000>
1372 -> blob1<compressed, len_on_disk=0x2000, logical_len=0x4000>
1373 write 0x3000~4000 resulted in the following extent map
1374 (future feature - suppose we can compress incoming write prior to
1375 GC invocation)
1376
1377 extent1 <loffs = 0, boffs = 0, len = 0x4000>
1378 -> blob1<compressed, len_on_disk=0x2000, logical_len=0x4000>
1379 extent2 <loffs = 0x3000, boffs = 0, len = 0x4000>
1380 -> blob2<compressed, len_on_disk=0x2000, llen=0x4000>
1381 */
1382 {
1383 BlueStore::GarbageCollector gc(g_ceph_context);
1384 int64_t saving;
1385 BlueStore::BlobRef b1(new BlueStore::Blob);
1386 BlueStore::BlobRef b2(new BlueStore::Blob);
1387 b1->shared_blob = new BlueStore::SharedBlob(coll.get());
1388 b2->shared_blob = new BlueStore::SharedBlob(coll.get());
1389 b1->dirty_blob().set_compressed(0x4000, 0x2000);
1390 b1->dirty_blob().allocated_test(bluestore_pextent_t(0, 0x2000));
1391 b2->dirty_blob().set_compressed(0x4000, 0x2000);
1392 b2->dirty_blob().allocated_test(bluestore_pextent_t(0, 0x2000));
1393
1394 em.extent_map.insert(*new BlueStore::Extent(0, 0, 0x3000, b1));
1395 b1->get_ref(coll.get(), 0, 0x3000);
1396 em.extent_map.insert(
1397 *new BlueStore::Extent(0x3000, 0, 0x4000, b2)); // new extent
1398 b2->get_ref(coll.get(), 0, 0x4000);
1399
1400 old_extents.push_back(*new BlueStore::OldExtent(0x3000, 0x3000, 0x1000, b1));
1401
1402 saving = gc.estimate(0x3000, 0x4000, em, old_extents, 0x1000);
1403 ASSERT_EQ(saving, 0);
1404 auto& to_collect = gc.get_extents_to_collect();
1405 ASSERT_EQ(to_collect.num_intervals(), 0u);
1406 em.clear();
1407 old_extents.clear();
1408 }
1409 /*
1410 original disposition
1411 min_alloc_size = 0x10000
1412 extent0 <loffs = 0, boffs = 0, len = 0x20000>
1413 -> blob0<compressed, len_on_disk=0x10000, logical_len=0x20000>
1414 extent1 <loffs = 0x20000, boffs = 0, len = 0x20000>
1415 -> blob1<compressed, len_on_disk=0x10000, logical_len=0x20000>
1416 write 0x8000~37000 resulted in the following extent map prior
1417 to GC for the last write_small(0x30000~0xf000)
1418
1419 extent0 <loffs = 0, boffs = 0, len = 0x8000>
1420 -> blob0<compressed, len_on_disk=0x10000, logical_len=0x20000>
1421 extent2 <loffs = 0x8000, boffs = 0x8000, len = 0x8000>
1422 -> blob2<raw, len_on_disk=0x10000, llen=0x10000>
1423 extent3 <loffs = 0x10000, boffs = 0, len = 0x20000>
1424 -> blob3<raw, len_on_disk=0x20000, llen=0x20000>
1425 extent4 <loffs = 0x30000, boffs = 0, len = 0xf000>
1426 -> blob4<raw, len_on_disk=0x1000, llen=0x1000>
1427 extent5 <loffs = 0x3f000, boffs = 0x1f000, len = 0x1000>
1428 -> blob1<compressed, len_on_disk=0x10000, llen=0x20000>
1429 */
1430 {
1431 BlueStore store(g_ceph_context, "", 0x10000);
1432 auto coll = ceph::make_ref<BlueStore::Collection>(&store, oc, bc, coll_t());
1433 BlueStore::Onode onode(coll.get(), ghobject_t(), "");
1434 BlueStore::ExtentMap em(&onode);
1435
1436 BlueStore::old_extent_map_t old_extents;
1437 BlueStore::GarbageCollector gc(g_ceph_context);
1438 int64_t saving;
1439 BlueStore::BlobRef b0(new BlueStore::Blob);
1440 BlueStore::BlobRef b1(new BlueStore::Blob);
1441 BlueStore::BlobRef b2(new BlueStore::Blob);
1442 BlueStore::BlobRef b3(new BlueStore::Blob);
1443 BlueStore::BlobRef b4(new BlueStore::Blob);
1444 b0->shared_blob = new BlueStore::SharedBlob(coll.get());
1445 b1->shared_blob = new BlueStore::SharedBlob(coll.get());
1446 b2->shared_blob = new BlueStore::SharedBlob(coll.get());
1447 b3->shared_blob = new BlueStore::SharedBlob(coll.get());
1448 b4->shared_blob = new BlueStore::SharedBlob(coll.get());
1449 b0->dirty_blob().set_compressed(0x2000, 0x1000);
1450 b0->dirty_blob().allocated_test(bluestore_pextent_t(0, 0x10000));
1451 b1->dirty_blob().set_compressed(0x20000, 0x10000);
1452 b1->dirty_blob().allocated_test(bluestore_pextent_t(0, 0x10000));
1453 b2->dirty_blob().allocated_test(bluestore_pextent_t(1, 0x10000));
1454 b3->dirty_blob().allocated_test(bluestore_pextent_t(2, 0x20000));
1455 b4->dirty_blob().allocated_test(bluestore_pextent_t(3, 0x1000));
1456
1457 em.extent_map.insert(*new BlueStore::Extent(0, 0, 0x8000, b0));
1458 b0->get_ref(coll.get(), 0, 0x8000);
1459 em.extent_map.insert(
1460 *new BlueStore::Extent(0x8000, 0x8000, 0x8000, b2)); // new extent
1461 b2->get_ref(coll.get(), 0x8000, 0x8000);
1462 em.extent_map.insert(
1463 *new BlueStore::Extent(0x10000, 0, 0x20000, b3)); // new extent
1464 b3->get_ref(coll.get(), 0, 0x20000);
1465 em.extent_map.insert(
1466 *new BlueStore::Extent(0x30000, 0, 0xf000, b4)); // new extent
1467 b4->get_ref(coll.get(), 0, 0xf000);
1468 em.extent_map.insert(*new BlueStore::Extent(0x3f000, 0x1f000, 0x1000, b1));
1469 b1->get_ref(coll.get(), 0x1f000, 0x1000);
1470
1471 old_extents.push_back(*new BlueStore::OldExtent(0x8000, 0x8000, 0x8000, b0));
1472 old_extents.push_back(
1473 *new BlueStore::OldExtent(0x10000, 0x10000, 0x10000, b0));
1474 old_extents.push_back(
1475 *new BlueStore::OldExtent(0x20000, 0x00000, 0x1f000, b1));
1476
1477 saving = gc.estimate(0x30000, 0xf000, em, old_extents, 0x10000);
1478 ASSERT_EQ(saving, 2);
1479 auto& to_collect = gc.get_extents_to_collect();
1480 ASSERT_EQ(to_collect.num_intervals(), 2u);
1481 {
1482 auto it1 = to_collect.begin();
1483 auto it2 = ++to_collect.begin();
1484 using p = decltype(*it1);
1485 {
1486 auto v1 = p{0x0ul, 0x8000ul};
1487 auto v2 = p{0x0ul, 0x8000ul};
1488 ASSERT_TRUE(*it1 == v1 || *it2 == v2);
1489 }
1490 {
1491 auto v1 = p{0x3f000ul, 0x1000ul};
1492 auto v2 = p{0x3f000ul, 0x1000ul};
1493 ASSERT_TRUE(*it1 == v1 || *it2 == v2);
1494 }
1495 }
1496
1497 em.clear();
1498 old_extents.clear();
1499 }
1500 }
1501
1502 TEST(BlueStoreRepairer, StoreSpaceTracker)
1503 {
1504 BlueStoreRepairer::StoreSpaceTracker bmap0;
1505 bmap0.init((uint64_t)4096 * 1024 * 1024 * 1024, 0x1000);
1506 ASSERT_EQ(bmap0.granularity, 2 * 1024 * 1024U);
1507 ASSERT_EQ(bmap0.collections_bfs.size(), 2048u * 1024u);
1508 ASSERT_EQ(bmap0.objects_bfs.size(), 2048u * 1024u);
1509
1510 BlueStoreRepairer::StoreSpaceTracker bmap;
1511 bmap.init(0x2000 * 0x1000 - 1, 0x1000, 512 * 1024);
1512 ASSERT_EQ(bmap.granularity, 0x1000u);
1513 ASSERT_EQ(bmap.collections_bfs.size(), 0x2000u);
1514 ASSERT_EQ(bmap.objects_bfs.size(), 0x2000u);
1515
1516 coll_t cid;
1517 ghobject_t hoid;
1518
1519 ASSERT_FALSE(bmap.is_used(cid, 0));
1520 ASSERT_FALSE(bmap.is_used(hoid, 0));
1521 bmap.set_used(0, 1, cid, hoid);
1522 ASSERT_TRUE(bmap.is_used(cid, 0));
1523 ASSERT_TRUE(bmap.is_used(hoid, 0));
1524
1525 ASSERT_FALSE(bmap.is_used(cid, 0x1023));
1526 ASSERT_FALSE(bmap.is_used(hoid, 0x1023));
1527 ASSERT_FALSE(bmap.is_used(cid, 0x2023));
1528 ASSERT_FALSE(bmap.is_used(hoid, 0x2023));
1529 ASSERT_FALSE(bmap.is_used(cid, 0x3023));
1530 ASSERT_FALSE(bmap.is_used(hoid, 0x3023));
1531 bmap.set_used(0x1023, 0x3000, cid, hoid);
1532 ASSERT_TRUE(bmap.is_used(cid, 0x1023));
1533 ASSERT_TRUE(bmap.is_used(hoid, 0x1023));
1534 ASSERT_TRUE(bmap.is_used(cid, 0x2023));
1535 ASSERT_TRUE(bmap.is_used(hoid, 0x2023));
1536 ASSERT_TRUE(bmap.is_used(cid, 0x3023));
1537 ASSERT_TRUE(bmap.is_used(hoid, 0x3023));
1538
1539 ASSERT_FALSE(bmap.is_used(cid, 0x9001));
1540 ASSERT_FALSE(bmap.is_used(hoid, 0x9001));
1541 ASSERT_FALSE(bmap.is_used(cid, 0xa001));
1542 ASSERT_FALSE(bmap.is_used(hoid, 0xa001));
1543 ASSERT_FALSE(bmap.is_used(cid, 0xb000));
1544 ASSERT_FALSE(bmap.is_used(hoid, 0xb000));
1545 ASSERT_FALSE(bmap.is_used(cid, 0xc000));
1546 ASSERT_FALSE(bmap.is_used(hoid, 0xc000));
1547 bmap.set_used(0x9001, 0x2fff, cid, hoid);
1548 ASSERT_TRUE(bmap.is_used(cid, 0x9001));
1549 ASSERT_TRUE(bmap.is_used(hoid, 0x9001));
1550 ASSERT_TRUE(bmap.is_used(cid, 0xa001));
1551 ASSERT_TRUE(bmap.is_used(hoid, 0xa001));
1552 ASSERT_TRUE(bmap.is_used(cid, 0xb001));
1553 ASSERT_TRUE(bmap.is_used(hoid, 0xb001));
1554 ASSERT_FALSE(bmap.is_used(cid, 0xc000));
1555 ASSERT_FALSE(bmap.is_used(hoid, 0xc000));
1556
1557 bmap.set_used(0xa001, 0x2, cid, hoid);
1558 ASSERT_TRUE(bmap.is_used(cid, 0x9001));
1559 ASSERT_TRUE(bmap.is_used(hoid, 0x9001));
1560 ASSERT_TRUE(bmap.is_used(cid, 0xa001));
1561 ASSERT_TRUE(bmap.is_used(hoid, 0xa001));
1562 ASSERT_TRUE(bmap.is_used(cid, 0xb001));
1563 ASSERT_TRUE(bmap.is_used(hoid, 0xb001));
1564 ASSERT_FALSE(bmap.is_used(cid, 0xc000));
1565 ASSERT_FALSE(bmap.is_used(hoid, 0xc000));
1566
1567 ASSERT_FALSE(bmap.is_used(cid, 0xc0000));
1568 ASSERT_FALSE(bmap.is_used(hoid, 0xc0000));
1569 ASSERT_FALSE(bmap.is_used(cid, 0xc1000));
1570 ASSERT_FALSE(bmap.is_used(hoid, 0xc1000));
1571
1572 bmap.set_used(0xc0000, 0x2000, cid, hoid);
1573 ASSERT_TRUE(bmap.is_used(cid, 0xc0000));
1574 ASSERT_TRUE(bmap.is_used(hoid, 0xc0000));
1575 ASSERT_TRUE(bmap.is_used(cid, 0xc1000));
1576 ASSERT_TRUE(bmap.is_used(hoid, 0xc1000));
1577
1578 interval_set<uint64_t> extents;
1579 extents.insert(0,0x500);
1580 extents.insert(0x800,0x100);
1581 extents.insert(0x1000,0x1000);
1582 extents.insert(0xa001,1);
1583 extents.insert(0xa0000,0xff8);
1584
1585 ASSERT_EQ(3u, bmap.filter_out(extents));
1586 ASSERT_TRUE(bmap.is_used(cid));
1587 ASSERT_TRUE(bmap.is_used(hoid));
1588
1589 BlueStoreRepairer::StoreSpaceTracker bmap2;
1590 bmap2.init((uint64_t)0x3223b1d1000, 0x10000);
1591 ASSERT_EQ(0x1a0000u, bmap2.granularity);
1592 ASSERT_EQ(0x1edae4u, bmap2.collections_bfs.size());
1593 ASSERT_EQ(0x1edae4u, bmap2.objects_bfs.size());
1594 bmap2.set_used(0x3223b190000, 0x10000, cid, hoid);
1595 ASSERT_TRUE(bmap2.is_used(cid, 0x3223b190000));
1596 ASSERT_TRUE(bmap2.is_used(hoid, 0x3223b190000));
1597 ASSERT_TRUE(bmap2.is_used(cid, 0x3223b19f000));
1598 ASSERT_TRUE(bmap2.is_used(hoid, 0x3223b19ffff));
1599 }
1600
1601 TEST(bluestore_blob_t, unused)
1602 {
1603 {
1604 bluestore_blob_t b;
1605 uint64_t min_alloc_size = 64 << 10; // 64 kB
1606
1607 // _do_write_small 0x0~1000
1608 uint64_t offset = 0x0;
1609 uint64_t length = 0x1000; // 4kB
1610 uint64_t suggested_boff = 0;
1611 PExtentVector extents;
1612 extents.emplace_back(0x1a560000, min_alloc_size);
1613 b.allocated(p2align(suggested_boff, min_alloc_size), 0 /*no matter*/, extents);
1614 b.mark_used(offset, length);
1615 ASSERT_FALSE(b.is_unused(offset, length));
1616
1617 // _do_write_small 0x2000~1000
1618 offset = 0x2000;
1619 length = 0x1000;
1620 b.add_unused(0, 0x10000);
1621 ASSERT_TRUE(b.is_unused(offset, length));
1622 b.mark_used(offset, length);
1623 ASSERT_FALSE(b.is_unused(offset, length));
1624
1625 // _do_write_small 0xc000~2000
1626 offset = 0xc000;
1627 length = 0x2000;
1628 ASSERT_TRUE(b.is_unused(offset, length));
1629 b.mark_used(offset, length);
1630 ASSERT_FALSE(b.is_unused(offset, length));
1631 }
1632
1633 {
1634 bluestore_blob_t b;
1635 uint64_t min_alloc_size = 64 << 10; // 64 kB
1636
1637 // _do_write_small 0x11000~1000
1638 uint64_t offset = 0x11000;
1639 uint64_t length = 0x1000; // 4kB
1640 uint64_t suggested_boff = 0x11000;
1641 PExtentVector extents;
1642 extents.emplace_back(0x1a560000, min_alloc_size);
1643 b.allocated(p2align(suggested_boff, min_alloc_size), 0 /*no matter*/, extents);
1644 b.add_unused(0, offset);
1645 b.add_unused(offset + length, min_alloc_size * 2 - offset - length);
1646 b.mark_used(offset, length);
1647 ASSERT_FALSE(b.is_unused(offset, length));
1648
1649 // _do_write_small 0x15000~3000
1650 offset = 0x15000;
1651 length = 0x3000;
1652 ASSERT_TRUE(b.is_unused(offset, length));
1653 b.mark_used(offset, length);
1654 ASSERT_FALSE(b.is_unused(offset, length));
1655 }
1656
1657 {
1658 // reuse blob
1659 bluestore_blob_t b;
1660 uint64_t min_alloc_size = 64 << 10; // 64 kB
1661
1662 // _do_write_small 0x2a000~1000
1663 // and 0x1d000~1000
1664 uint64_t unused_granularity = 0x3000;
1665 // offsets and lenght below are selected to
1666 // be aligned with unused_granularity
1667 uint64_t offset0 = 0x2a000;
1668 uint64_t offset = 0x1d000;
1669 uint64_t length = 0x1000; // 4kB
1670 PExtentVector extents;
1671 extents.emplace_back(0x410000, min_alloc_size);
1672 b.allocated(p2align(offset0, min_alloc_size), min_alloc_size, extents);
1673 b.add_unused(0, min_alloc_size * 3);
1674 b.mark_used(offset0, length);
1675 ASSERT_FALSE(b.is_unused(offset0, length));
1676 ASSERT_TRUE(b.is_unused(offset, length));
1677
1678 extents.clear();
1679 extents.emplace_back(0x430000, min_alloc_size);
1680 b.allocated(p2align(offset, min_alloc_size), min_alloc_size, extents);
1681 b.mark_used(offset, length);
1682 ASSERT_FALSE(b.is_unused(offset0, length));
1683 ASSERT_FALSE(b.is_unused(offset, length));
1684 ASSERT_FALSE(b.is_unused(offset, unused_granularity));
1685
1686 ASSERT_TRUE(b.is_unused(0, offset / unused_granularity * unused_granularity));
1687 ASSERT_TRUE(b.is_unused(offset + length, offset0 - offset - length));
1688 auto end0_aligned = round_up_to(offset0 + length, unused_granularity);
1689 ASSERT_TRUE(b.is_unused(end0_aligned, min_alloc_size * 3 - end0_aligned));
1690 }
1691 }
1692
1693 int main(int argc, char **argv) {
1694 vector<const char*> args;
1695 argv_to_vec(argc, (const char **)argv, args);
1696 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
1697 CODE_ENVIRONMENT_UTILITY,
1698 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
1699 common_init_finish(g_ceph_context);
1700 ::testing::InitGoogleTest(&argc, argv);
1701 return RUN_ALL_TESTS();
1702 }