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