Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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], AllocExtent(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] == AllocExtent(0x0,0x8000) ||
1316                   to_collect[1] == AllocExtent(0x0,0x8000));
1317     ASSERT_TRUE(to_collect[0] == AllocExtent(0x3f000,0x1000) ||
1318                   to_collect[1] == AllocExtent(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] == AllocExtent(0x0,0x8000) ||
1437                   to_collect[1] == AllocExtent(0x0,0x8000));
1438     ASSERT_TRUE(to_collect[0] == AllocExtent(0x3f000,0x1000) ||
1439                   to_collect[1] == AllocExtent(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 }