1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
18 #define STRINGIFY(x) _STR(x)
20 TEST(bluestore
, sizeof) {
21 #define P(t) cout << STRINGIFY(t) << "\t" << sizeof(t) << std::endl
25 P(BlueStore::SharedBlob
);
26 P(BlueStore::ExtentMap
);
27 P(BlueStore::extent_map_t
);
28 P(BlueStore::blob_map_t
);
29 P(BlueStore::BufferSpace
);
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
);
39 P(BlueStore::SharedBlobRef
);
40 P(boost::intrusive::set_base_hook
<>);
41 P(boost::intrusive::unordered_set_base_hook
<>);
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
;
49 TEST(bluestore_extent_ref_map_t
, add
)
51 bluestore_extent_ref_map_t m
;
53 ASSERT_EQ(1u, m
.ref_map
.size());
54 cout
<< m
<< std::endl
;
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
);
61 cout
<< m
<< std::endl
;
62 ASSERT_EQ(2u, m
.ref_map
.size());
64 cout
<< m
<< std::endl
;
65 ASSERT_EQ(1u, m
.ref_map
.size());
67 cout
<< m
<< std::endl
;
68 ASSERT_EQ(1u, m
.ref_map
.size());
70 cout
<< m
<< std::endl
;
71 ASSERT_EQ(1u, m
.ref_map
.size());
74 TEST(bluestore_extent_ref_map_t
, get
)
76 bluestore_extent_ref_map_t m
;
78 cout
<< m
<< std::endl
;
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
);
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
);
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
);
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
);
121 TEST(bluestore_extent_ref_map_t
, put
)
123 bluestore_extent_ref_map_t m
;
125 bool maybe_unshared
= false;
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
);
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
);
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
);
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
);
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
);
187 TEST(bluestore_extent_ref_map_t
, contains
)
189 bluestore_extent_ref_map_t m
;
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));
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));
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));
216 TEST(bluestore_extent_ref_map_t
, intersects
)
218 bluestore_extent_ref_map_t m
;
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));
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));
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));
243 TEST(bluestore_blob_t
, calc_csum
)
246 bl
.append("asdfghjkqwertyuizxcvbnm,");
248 bl2
.append("xxxxXXXXyyyyYYYYzzzzZZZZ");
250 f
.substr_of(bl
, 0, 8);
252 m
.substr_of(bl
, 8, 8);
254 e
.substr_of(bl
, 16, 8);
256 n
.append("12345678");
258 for (unsigned csum_type
= Checksummer::CSUM_NONE
+ 1;
259 csum_type
< Checksummer::CSUM_MAX
;
261 cout
<< "csum_type " << Checksummer::get_csum_type_string(csum_type
)
267 ASSERT_EQ(0, b
.verify_csum(0, bl
, &bad_off
, &bad_csum
));
268 ASSERT_EQ(-1, bad_off
);
270 b
.init_csum(csum_type
, 3, 24);
271 cout
<< " value size " << b
.get_csum_value_size() << std::endl
;
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
);
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
);
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
);
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
);
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
);
311 TEST(bluestore_blob_t
, csum_bench
)
314 bufferptr
bp(10485760);
315 for (char *a
= bp
.c_str(); a
< bp
.c_str() + bp
.length(); ++a
)
316 *a
= (unsigned long)a
& 0xff;
319 for (unsigned csum_type
= 1;
320 csum_type
< Checksummer::CSUM_MAX
;
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
) {
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
;
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
);
346 auto coll
= ceph::make_ref
<BlueStore::Collection
>(&store
, oc
, bc
, coll_t());
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
;
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
;
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
;
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());
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();
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
);
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();
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
);
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();
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());
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();
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());
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();
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());
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();
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());
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();
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());
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();
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());
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();
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());
735 // verify csum chunk size if factored in properly
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();
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
);
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
,
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);
771 cout
<< "before: " << B
<< std::endl
;
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
;
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
;
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
);
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
;
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
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
);
827 auto coll
= ceph::make_ref
<BlueStore::Collection
>(&store
, oc
, bc
, coll_t());
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
;
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
);
852 TEST(bluestore_blob_t
, can_split
)
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());
864 TEST(bluestore_blob_t
, can_split_at
)
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));
878 TEST(bluestore_blob_t
, prune_tail
)
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());
885 bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET
, 0x2000));
886 ASSERT_TRUE(a
.can_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());
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());
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());
905 bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET
, 0x2000));
906 ASSERT_FALSE(a
.can_prune_tail());
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());
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());
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());
967 TEST(Blob
, legacy_decode
)
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());
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);
985 bluestore_extent_ref_map_t fake_ref_map
;
986 fake_ref_map
.get(0, 0xff0);
987 fake_ref_map
.get(0x1fff, 1);
989 size_t bound
= 0, bound2
= 0;
996 fake_ref_map
.bound_encode(bound
);
1005 auto app
= bl
.get_contiguous_appender(bound
);
1006 auto app2
= bl2
.get_contiguous_appender(bound2
);
1012 fake_ref_map
.encode(app
);
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());
1027 uint64_t sbid
, sbid2
;
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()));
1047 TEST(ExtentMap
, seek_lextent
)
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
);
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());
1061 ASSERT_EQ(em
.extent_map
.end(), em
.seek_lextent(0));
1062 ASSERT_EQ(em
.extent_map
.end(), em
.seek_lextent(100));
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));
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));
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));
1100 TEST(ExtentMap
, has_any_lextents
)
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());
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));
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));
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));
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));
1150 TEST(ExtentMap
, compress_extent_map
)
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
);
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());
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());
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());
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());
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());
1207 TEST(GarbageCollector
, BasicTest
)
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
);
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
);
1219 BlueStore::old_extent_map_t old_extents
;
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>
1244 BlueStore::GarbageCollector
gc(g_ceph_context
);
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);
1268 old_extents
.push_back(*new BlueStore::OldExtent(300, 300, 10, b1
));
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);
1275 auto it
= to_collect
.begin();
1276 using p
= decltype(*it
);
1277 auto v
= p
{100ul, 10ul};
1282 old_extents
.clear();
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):
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>
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
);
1309 BlueStore::old_extent_map_t old_extents
;
1310 BlueStore::GarbageCollector
gc(g_ceph_context
);
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));
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);
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
));
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);
1350 auto it1
= to_collect
.begin();
1351 auto it2
= ++to_collect
.begin();
1352 using p
= decltype(*it1
);
1354 auto v1
= p
{0x0ul
,0x8000ul
};
1355 auto v2
= p
{0x0ul
, 0x8000ul
};
1356 ASSERT_TRUE(*it1
== v1
|| *it2
== v2
);
1359 auto v1
= p
{0x3f000ul
, 0x1000ul
};
1360 auto v2
= p
{0x3f000ul
, 0x1000ul
};
1361 ASSERT_TRUE(*it1
== v1
|| *it2
== v2
);
1366 old_extents
.clear();
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
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>
1383 BlueStore::GarbageCollector
gc(g_ceph_context
);
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));
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);
1400 old_extents
.push_back(*new BlueStore::OldExtent(0x3000, 0x3000, 0x1000, b1
));
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);
1407 old_extents
.clear();
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)
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>
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
);
1436 BlueStore::old_extent_map_t old_extents
;
1437 BlueStore::GarbageCollector
gc(g_ceph_context
);
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));
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);
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
));
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);
1482 auto it1
= to_collect
.begin();
1483 auto it2
= ++to_collect
.begin();
1484 using p
= decltype(*it1
);
1486 auto v1
= p
{0x0ul
, 0x8000ul
};
1487 auto v2
= p
{0x0ul
, 0x8000ul
};
1488 ASSERT_TRUE(*it1
== v1
|| *it2
== v2
);
1491 auto v1
= p
{0x3f000ul
, 0x1000ul
};
1492 auto v2
= p
{0x3f000ul
, 0x1000ul
};
1493 ASSERT_TRUE(*it1
== v1
|| *it2
== v2
);
1498 old_extents
.clear();
1502 TEST(BlueStoreRepairer
, StoreSpaceTracker
)
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);
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
);
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));
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));
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));
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));
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));
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));
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);
1585 ASSERT_EQ(3u, bmap
.filter_out(extents
));
1586 ASSERT_TRUE(bmap
.is_used(cid
));
1587 ASSERT_TRUE(bmap
.is_used(hoid
));
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));
1601 TEST(bluestore_blob_t
, unused
)
1605 uint64_t min_alloc_size
= 64 << 10; // 64 kB
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
));
1617 // _do_write_small 0x2000~1000
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
));
1625 // _do_write_small 0xc000~2000
1628 ASSERT_TRUE(b
.is_unused(offset
, length
));
1629 b
.mark_used(offset
, length
);
1630 ASSERT_FALSE(b
.is_unused(offset
, length
));
1635 uint64_t min_alloc_size
= 64 << 10; // 64 kB
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
));
1649 // _do_write_small 0x15000~3000
1652 ASSERT_TRUE(b
.is_unused(offset
, length
));
1653 b
.mark_used(offset
, length
);
1654 ASSERT_FALSE(b
.is_unused(offset
, length
));
1660 uint64_t min_alloc_size
= 64 << 10; // 64 kB
1662 // _do_write_small 0x2a000~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
));
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
));
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
));
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();