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