Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / objectstore / store_test.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7  *
8  * This is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License version 2.1, as published by the Free Software
11  * Foundation.  See file COPYING.
12  *
13  */
14
15 #include <glob.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <iostream>
19 #include <time.h>
20 #include <sys/mount.h>
21 #include <boost/scoped_ptr.hpp>
22 #include <boost/random/mersenne_twister.hpp>
23 #include <boost/random/uniform_int.hpp>
24 #include <boost/random/binomial_distribution.hpp>
25 #include <gtest/gtest.h>
26
27 #include "os/ObjectStore.h"
28 #include "os/filestore/FileStore.h"
29 #if defined(HAVE_LIBAIO)
30 #include "os/bluestore/BlueStore.h"
31 #endif
32 #include "include/Context.h"
33 #include "common/ceph_argparse.h"
34 #include "global/global_init.h"
35 #include "common/Mutex.h"
36 #include "common/Cond.h"
37 #include "common/errno.h"
38 #include "include/stringify.h"
39 #include "include/coredumpctl.h"
40
41 #include "include/unordered_map.h"
42 #include "store_test_fixture.h"
43
44
45 typedef boost::mt11213b gen_type;
46
47 #define dout_context g_ceph_context
48
49 #if GTEST_HAS_PARAM_TEST
50
51 static bool bl_eq(bufferlist& expected, bufferlist& actual)
52 {
53   if (expected.contents_equal(actual))
54     return true;
55
56   unsigned first = 0;
57   if(expected.length() != actual.length()) {
58     cout << "--- buffer lengths mismatch " << std::hex
59          << "expected 0x" << expected.length() << " != actual 0x"
60          << actual.length() << std::dec << std::endl;
61     derr << "--- buffer lengths mismatch " << std::hex
62          << "expected 0x" << expected.length() << " != actual 0x"
63          << actual.length() << std::dec << dendl;
64   }
65   auto len = MIN(expected.length(), actual.length());
66   while ( first<len && expected[first] == actual[first])
67     ++first;
68   unsigned last = len;
69   while (last > 0 && expected[last-1] == actual[last-1])
70     --last;
71   if(len > 0) {
72     cout << "--- buffer mismatch between offset 0x" << std::hex << first
73          << " and 0x" << last << ", total 0x" << len << std::dec
74          << std::endl;
75     derr << "--- buffer mismatch between offset 0x" << std::hex << first
76          << " and 0x" << last << ", total 0x" << len << std::dec
77          << dendl;
78     cout << "--- expected:\n";
79     expected.hexdump(cout);
80     cout << "--- actual:\n";
81     actual.hexdump(cout);
82   }
83   return false;
84 }
85
86
87
88 template <typename T>
89 int apply_transaction(
90   T &store,
91   ObjectStore::Sequencer *osr,
92   ObjectStore::Transaction &&t) {
93   if (rand() % 2) {
94     ObjectStore::Transaction t2;
95     t2.append(t);
96     return store->apply_transaction(osr, std::move(t2));
97   } else {
98     return store->apply_transaction(osr, std::move(t));
99   }
100 }
101
102
103 bool sorted(const vector<ghobject_t> &in) {
104   ghobject_t start;
105   for (vector<ghobject_t>::const_iterator i = in.begin();
106        i != in.end();
107        ++i) {
108     if (start > *i) {
109       cout << start << " should follow " << *i << std::endl;
110       return false;
111     }
112     start = *i;
113   }
114   return true;
115 }
116
117 class StoreTest : public StoreTestFixture,
118                   public ::testing::WithParamInterface<const char*> {
119 public:
120   StoreTest()
121     : StoreTestFixture(GetParam())
122   {}
123 };
124
125 class StoreTestDeferredSetup : public StoreTest {
126   void SetUp() override {
127     //do nothing
128   }
129
130 protected:
131   void DeferredSetup() {
132     StoreTest::SetUp();
133   }
134
135 public:
136 };
137
138 class StoreTestSpecificAUSize : public StoreTestDeferredSetup {
139
140 public:
141   typedef 
142     std::function<void(
143            boost::scoped_ptr<ObjectStore>& store,
144            uint64_t num_ops,
145            uint64_t max_obj,
146            uint64_t max_wr,
147            uint64_t align)> MatrixTest;
148
149   void StartDeferred(size_t min_alloc_size) {
150     g_conf->set_val("bluestore_min_alloc_size", stringify(min_alloc_size));
151     DeferredSetup();
152   }
153     
154   void TearDown() override {
155     g_conf->set_val("bluestore_min_alloc_size", "0");
156     StoreTestDeferredSetup::TearDown();
157   }
158
159 private:
160   // bluestore matrix testing
161   uint64_t max_write = 40 * 1024;
162   uint64_t max_size = 400 * 1024;
163   uint64_t alignment = 0;
164   uint64_t num_ops = 10000;
165
166 protected:
167   string matrix_get(const char *k) {
168     if (string(k) == "max_write") {
169       return stringify(max_write);
170     } else if (string(k) == "max_size") {
171       return stringify(max_size);
172     } else if (string(k) == "alignment") {
173       return stringify(alignment);
174     } else if (string(k) == "num_ops") {
175       return stringify(num_ops);
176     } else {
177       char *buf;
178       g_conf->get_val(k, &buf, -1);
179       string v = buf;
180       free(buf);
181       return v;
182     }
183   }
184
185   void matrix_set(const char *k, const char *v) {
186     if (string(k) == "max_write") {
187       max_write = atoll(v);
188     } else if (string(k) == "max_size") {
189       max_size = atoll(v);
190     } else if (string(k) == "alignment") {
191       alignment = atoll(v);
192     } else if (string(k) == "num_ops") {
193       num_ops = atoll(v);
194     } else {
195       g_conf->set_val(k, v);
196     }
197   }
198
199   void do_matrix_choose(const char *matrix[][10],
200                         int i, int pos, int num,
201                         boost::scoped_ptr<ObjectStore>& store,
202                         MatrixTest fn) {
203     if (matrix[i][0]) {
204       int count;
205       for (count = 0; matrix[i][count+1]; ++count) ;
206       for (int j = 1; matrix[i][j]; ++j) {
207         matrix_set(matrix[i][0], matrix[i][j]);
208         do_matrix_choose(matrix,
209                          i + 1,
210                          pos * count + j - 1, 
211                          num * count, 
212                          store,
213                          fn);
214       }
215     } else {
216       cout << "---------------------- " << (pos + 1) << " / " << num
217            << " ----------------------" << std::endl;
218       for (unsigned k=0; matrix[k][0]; ++k) {
219         cout << "  " << matrix[k][0] << " = " << matrix_get(matrix[k][0])
220              << std::endl;
221       }
222       g_ceph_context->_conf->apply_changes(NULL);
223       fn(store, num_ops, max_size, max_write, alignment);
224     }
225   }
226
227   void do_matrix(const char *matrix[][10],
228                  boost::scoped_ptr<ObjectStore>& store,
229                  MatrixTest fn) {
230     map<string,string> old;
231     for (unsigned i=0; matrix[i][0]; ++i) {
232       old[matrix[i][0]] = matrix_get(matrix[i][0]);
233     }
234     cout << "saved config options " << old << std::endl;
235
236     if (strcmp(matrix[0][0], "bluestore_min_alloc_size") == 0) {
237       int count;
238       for (count = 0; matrix[0][count+1]; ++count) ;
239       for (size_t j = 1; matrix[0][j]; ++j) {
240         if (j > 1) {
241           TearDown();
242         }
243         StartDeferred(strtoll(matrix[0][j], NULL, 10));
244         do_matrix_choose(matrix, 1, j - 1, count, store, fn);
245       }
246     } else {
247       StartDeferred(0);
248       do_matrix_choose(matrix, 0, 0, 1, store, fn);
249     }
250
251     cout << "restoring config options " << old << std::endl;
252     for (auto p : old) {
253       cout << "  " << p.first << " = " << p.second << std::endl;
254       matrix_set(p.first.c_str(), p.second.c_str());
255     }
256     g_ceph_context->_conf->apply_changes(NULL);
257   }
258
259 };
260
261 TEST_P(StoreTest, collect_metadata) {
262   map<string,string> pm;
263   store->collect_metadata(&pm);
264   if (GetParam() == string("filestore")) {
265     ASSERT_NE(pm.count("filestore_backend"), 0u);
266     ASSERT_NE(pm.count("filestore_f_type"), 0u);
267     ASSERT_NE(pm.count("backend_filestore_partition_path"), 0u);
268     ASSERT_NE(pm.count("backend_filestore_dev_node"), 0u);
269   }
270 }
271
272 TEST_P(StoreTest, Trivial) {
273 }
274
275 TEST_P(StoreTest, TrivialRemount) {
276   int r = store->umount();
277   ASSERT_EQ(0, r);
278   r = store->mount();
279   ASSERT_EQ(0, r);
280 }
281
282 TEST_P(StoreTest, SimpleRemount) {
283   ObjectStore::Sequencer osr("test");
284   coll_t cid;
285   ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
286   ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
287   bufferlist bl;
288   bl.append("1234512345");
289   int r;
290   {
291     cerr << "create collection + write" << std::endl;
292     ObjectStore::Transaction t;
293     t.create_collection(cid, 0);
294     t.write(cid, hoid, 0, bl.length(), bl);
295     r = apply_transaction(store, &osr, std::move(t));
296     ASSERT_EQ(r, 0);
297   }
298   r = store->umount();
299   ASSERT_EQ(0, r);
300   r = store->mount();
301   ASSERT_EQ(0, r);
302   {
303     ObjectStore::Transaction t;
304     t.write(cid, hoid2, 0, bl.length(), bl);
305     r = apply_transaction(store, &osr, std::move(t));
306     ASSERT_EQ(r, 0);
307   }
308   {
309     ObjectStore::Transaction t;
310     t.remove(cid, hoid);
311     t.remove(cid, hoid2);
312     t.remove_collection(cid);
313     cerr << "remove collection" << std::endl;
314     r = apply_transaction(store, &osr, std::move(t));
315     ASSERT_EQ(r, 0);
316   }
317   r = store->umount();
318   ASSERT_EQ(0, r);
319   r = store->mount();
320   ASSERT_EQ(0, r);
321   {
322     ObjectStore::Transaction t;
323     t.create_collection(cid, 0);
324     r = apply_transaction(store, &osr, std::move(t));
325     ASSERT_EQ(r, 0);
326     bool exists = store->exists(cid, hoid);
327     ASSERT_TRUE(!exists);
328   }
329   {
330     ObjectStore::Transaction t;
331     t.remove_collection(cid);
332     cerr << "remove collection" << std::endl;
333     r = apply_transaction(store, &osr, std::move(t));
334     ASSERT_EQ(r, 0);
335   }
336 }
337
338 TEST_P(StoreTest, IORemount) {
339   ObjectStore::Sequencer osr("test");
340   coll_t cid;
341   bufferlist bl;
342   bl.append("1234512345");
343   int r;
344   {
345     cerr << "create collection + objects" << std::endl;
346     ObjectStore::Transaction t;
347     t.create_collection(cid, 0);
348     for (int n=1; n<=100; ++n) {
349       ghobject_t hoid(hobject_t(sobject_t("Object " + stringify(n), CEPH_NOSNAP)));
350       t.write(cid, hoid, 0, bl.length(), bl);
351     }
352     r = apply_transaction(store, &osr, std::move(t));
353     ASSERT_EQ(r, 0);
354   }
355   // overwrites
356   {
357     cout << "overwrites" << std::endl;
358     for (int n=1; n<=100; ++n) {
359       ObjectStore::Transaction t;
360       ghobject_t hoid(hobject_t(sobject_t("Object " + stringify(n), CEPH_NOSNAP)));
361       t.write(cid, hoid, 1, bl.length(), bl);
362       r = apply_transaction(store, &osr, std::move(t));
363       ASSERT_EQ(r, 0);
364     }
365   }
366   r = store->umount();
367   ASSERT_EQ(0, r);
368   r = store->mount();
369   ASSERT_EQ(0, r);
370   {
371     ObjectStore::Transaction t;
372     for (int n=1; n<=100; ++n) {
373       ghobject_t hoid(hobject_t(sobject_t("Object " + stringify(n), CEPH_NOSNAP)));
374       t.remove(cid, hoid);
375     }
376     t.remove_collection(cid);
377     r = apply_transaction(store, &osr, std::move(t));
378     ASSERT_EQ(r, 0);
379   }
380 }
381
382 TEST_P(StoreTest, UnprintableCharsName) {
383   ObjectStore::Sequencer osr("test");
384   coll_t cid;
385   string name = "funnychars_";
386   for (unsigned i = 0; i < 256; ++i) {
387     name.push_back(i);
388   }
389   ghobject_t oid(hobject_t(sobject_t(name, CEPH_NOSNAP)));
390   int r;
391   {
392     cerr << "create collection + object" << std::endl;
393     ObjectStore::Transaction t;
394     t.create_collection(cid, 0);
395     t.touch(cid, oid);
396     r = apply_transaction(store, &osr, std::move(t));
397     ASSERT_EQ(r, 0);
398   }
399   r = store->umount();
400   ASSERT_EQ(0, r);
401   r = store->mount();
402   ASSERT_EQ(0, r);
403   {
404     cout << "removing" << std::endl;
405     ObjectStore::Transaction t;
406     t.remove(cid, oid);
407     t.remove_collection(cid);
408     r = apply_transaction(store, &osr, std::move(t));
409     ASSERT_EQ(r, 0);
410   }
411 }
412
413 TEST_P(StoreTest, FiemapEmpty) {
414   ObjectStore::Sequencer osr("test");
415   coll_t cid;
416   int r = 0;
417   ghobject_t oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP)));
418   {
419     ObjectStore::Transaction t;
420     t.create_collection(cid, 0);
421     t.touch(cid, oid);
422     t.truncate(cid, oid, 100000);
423     r = apply_transaction(store, &osr, std::move(t));
424     ASSERT_EQ(r, 0);
425   }
426   {
427     bufferlist bl;
428     store->fiemap(cid, oid, 0, 100000, bl);
429     map<uint64_t,uint64_t> m, e;
430     bufferlist::iterator p = bl.begin();
431     ::decode(m, p);
432     cout << " got " << m << std::endl;
433     e[0] = 100000;
434     EXPECT_TRUE(m == e || m.empty());
435   }
436   {
437     ObjectStore::Transaction t;
438     t.remove(cid, oid);
439     t.remove_collection(cid);
440     cerr << "remove collection" << std::endl;
441     r = apply_transaction(store, &osr, std::move(t));
442     ASSERT_EQ(r, 0);
443   }
444 }
445
446 TEST_P(StoreTest, FiemapHoles) {
447   ObjectStore::Sequencer osr("test");
448   const uint64_t MAX_EXTENTS = 4000;
449   const uint64_t SKIP_STEP = 65536;
450   coll_t cid;
451   int r = 0;
452   ghobject_t oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP)));
453   bufferlist bl;
454   bl.append("foo");
455   {
456     ObjectStore::Transaction t;
457     t.create_collection(cid, 0);
458     t.touch(cid, oid);
459     for (uint64_t i = 0; i < MAX_EXTENTS; i++)
460       t.write(cid, oid, SKIP_STEP * i, 3, bl);
461     r = apply_transaction(store, &osr, std::move(t));
462     ASSERT_EQ(r, 0);
463   }
464   {
465     //fiemap test from 0 to SKIP_STEP * (MAX_EXTENTS - 1) + 3
466     bufferlist bl;
467     store->fiemap(cid, oid, 0, SKIP_STEP * (MAX_EXTENTS - 1) + 3, bl);
468     map<uint64_t,uint64_t> m, e;
469     bufferlist::iterator p = bl.begin();
470     ::decode(m, p);
471     cout << " got " << m << std::endl;
472     ASSERT_TRUE(!m.empty());
473     ASSERT_GE(m[0], 3u);
474     bool extents_exist = true;
475     if (m.size() == MAX_EXTENTS) {
476       for (uint64_t i = 0; i < MAX_EXTENTS; i++)
477         extents_exist = extents_exist && m.count(SKIP_STEP*i);
478     }
479     ASSERT_TRUE((m.size() == 1 &&
480                  m[0] > SKIP_STEP * (MAX_EXTENTS - 1)) ||
481                  (m.size() == MAX_EXTENTS && extents_exist));
482
483     // fiemap test from SKIP_STEP to SKIP_STEP * (MAX_EXTENTS - 2) + 3
484     // reset bufferlist and map
485     bl.clear();
486     m.clear();
487     e.clear();
488     store->fiemap(cid, oid, SKIP_STEP, SKIP_STEP * (MAX_EXTENTS - 2) + 3, bl);
489     p = bl.begin();
490     ::decode(m, p);
491     cout << " got " << m << std::endl;
492     ASSERT_TRUE(!m.empty());
493     ASSERT_GE(m[SKIP_STEP], 3u);
494     extents_exist = true;
495     if (m.size() == (MAX_EXTENTS - 2)) {
496       for (uint64_t i = 1; i < MAX_EXTENTS - 1; i++)
497         extents_exist = extents_exist && m.count(SKIP_STEP*i);
498     }
499     ASSERT_TRUE((m.size() == 1 &&
500                  m[SKIP_STEP] > SKIP_STEP * (MAX_EXTENTS - 2)) ||
501                  (m.size() == (MAX_EXTENTS - 1) && extents_exist));
502   }
503   {
504     ObjectStore::Transaction t;
505     t.remove(cid, oid);
506     t.remove_collection(cid);
507     cerr << "remove collection" << std::endl;
508     r = apply_transaction(store, &osr, std::move(t));
509     ASSERT_EQ(r, 0);
510   }
511 }
512
513 TEST_P(StoreTest, SimpleMetaColTest) {
514   ObjectStore::Sequencer osr("test");
515   coll_t cid;
516   int r = 0;
517   {
518     ObjectStore::Transaction t;
519     t.create_collection(cid, 0);
520     cerr << "create collection" << std::endl;
521     r = apply_transaction(store, &osr, std::move(t));
522     ASSERT_EQ(r, 0);
523   }
524   {
525     ObjectStore::Transaction t;
526     t.remove_collection(cid);
527     cerr << "remove collection" << std::endl;
528     r = apply_transaction(store, &osr, std::move(t));
529     ASSERT_EQ(r, 0);
530   }
531   {
532     ObjectStore::Transaction t;
533     t.create_collection(cid, 0);
534     cerr << "add collection" << std::endl;
535     r = apply_transaction(store, &osr, std::move(t));
536     ASSERT_EQ(r, 0);
537   }
538   {
539     ObjectStore::Transaction t;
540     t.remove_collection(cid);
541     cerr << "remove collection" << std::endl;
542     r = apply_transaction(store, &osr, std::move(t));
543     ASSERT_EQ(r, 0);
544   }
545 }
546
547 TEST_P(StoreTest, SimplePGColTest) {
548   ObjectStore::Sequencer osr("test");
549   coll_t cid(spg_t(pg_t(1,2), shard_id_t::NO_SHARD));
550   int r = 0;
551   {
552     ObjectStore::Transaction t;
553     t.create_collection(cid, 4);
554     cerr << "create collection" << std::endl;
555     r = apply_transaction(store, &osr, std::move(t));
556     ASSERT_EQ(r, 0);
557   }
558   {
559     ObjectStore::Transaction t;
560     t.remove_collection(cid);
561     cerr << "remove collection" << std::endl;
562     r = apply_transaction(store, &osr, std::move(t));
563     ASSERT_EQ(r, 0);
564   }
565   {
566     ObjectStore::Transaction t;
567     t.create_collection(cid, 4);
568     cerr << "add collection" << std::endl;
569     r = apply_transaction(store, &osr, std::move(t));
570     ASSERT_EQ(r, 0);
571   }
572   {
573     ObjectStore::Transaction t;
574     t.remove_collection(cid);
575     cerr << "remove collection" << std::endl;
576     r = apply_transaction(store, &osr, std::move(t));
577     ASSERT_EQ(r, 0);
578   }
579 }
580
581 TEST_P(StoreTest, SimpleColPreHashTest) {
582   ObjectStore::Sequencer osr("test");
583   // Firstly we will need to revert the value making sure
584   // collection hint actually works
585   int merge_threshold = g_ceph_context->_conf->filestore_merge_threshold;
586   std::ostringstream oss;
587   if (merge_threshold > 0) {
588     oss << "-" << merge_threshold;
589     g_ceph_context->_conf->set_val("filestore_merge_threshold", oss.str().c_str());
590   }
591
592   uint32_t pg_num = 128;
593
594   boost::uniform_int<> pg_id_range(0, pg_num);
595   gen_type rng(time(NULL));
596   int pg_id = pg_id_range(rng);
597
598   int objs_per_folder = abs(merge_threshold) * 16 * g_ceph_context->_conf->filestore_split_multiple;
599   boost::uniform_int<> folders_range(5, 256);
600   uint64_t expected_num_objs = (uint64_t)objs_per_folder * (uint64_t)folders_range(rng);
601
602   coll_t cid(spg_t(pg_t(pg_id, 15), shard_id_t::NO_SHARD));
603   int r;
604   {
605     // Create a collection along with a hint
606     ObjectStore::Transaction t;
607     t.create_collection(cid, 5);
608     cerr << "create collection" << std::endl;
609     bufferlist hint;
610     ::encode(pg_num, hint);
611     ::encode(expected_num_objs, hint);
612     t.collection_hint(cid, ObjectStore::Transaction::COLL_HINT_EXPECTED_NUM_OBJECTS, hint);
613     cerr << "collection hint" << std::endl;
614     r = apply_transaction(store, &osr, std::move(t));
615     ASSERT_EQ(r, 0);
616   }
617   {
618     // Remove the collection
619     ObjectStore::Transaction t;
620     t.remove_collection(cid);
621     cerr << "remove collection" << std::endl;
622     r = apply_transaction(store, &osr, std::move(t));
623     ASSERT_EQ(r, 0);
624   }
625   // Revert the config change so that it does not affect the split/merge tests
626   if (merge_threshold > 0) {
627     oss.str("");
628     oss << merge_threshold;
629     g_ceph_context->_conf->set_val("filestore_merge_threshold", oss.str().c_str());
630   }
631 }
632
633 TEST_P(StoreTest, SmallBlockWrites) {
634   ObjectStore::Sequencer osr("test");
635   int r;
636   coll_t cid;
637   ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
638   {
639     ObjectStore::Transaction t;
640     t.create_collection(cid, 0);
641     cerr << "Creating collection " << cid << std::endl;
642     r = apply_transaction(store, &osr, std::move(t));
643     ASSERT_EQ(r, 0);
644   }
645   bufferlist a;
646   bufferptr ap(0x1000);
647   memset(ap.c_str(), 'a', 0x1000);
648   a.append(ap);
649   bufferlist b;
650   bufferptr bp(0x1000);
651   memset(bp.c_str(), 'b', 0x1000);
652   b.append(bp);
653   bufferlist c;
654   bufferptr cp(0x1000);
655   memset(cp.c_str(), 'c', 0x1000);
656   c.append(cp);
657   bufferptr zp(0x1000);
658   zp.zero();
659   bufferlist z;
660   z.append(zp);
661   {
662     ObjectStore::Transaction t;
663     t.write(cid, hoid, 0, 0x1000, a);
664     r = apply_transaction(store, &osr, std::move(t));
665     ASSERT_EQ(r, 0);
666
667     bufferlist in, exp;
668     r = store->read(cid, hoid, 0, 0x4000, in);
669     ASSERT_EQ(0x1000, r);
670     exp.append(a);
671     ASSERT_TRUE(bl_eq(exp, in));
672   }
673   {
674     ObjectStore::Transaction t;
675     t.write(cid, hoid, 0x1000, 0x1000, b);
676     r = apply_transaction(store, &osr, std::move(t));
677     ASSERT_EQ(r, 0);
678
679     bufferlist in, exp;
680     r = store->read(cid, hoid, 0, 0x4000, in);
681     ASSERT_EQ(0x2000, r);
682     exp.append(a);
683     exp.append(b);
684     ASSERT_TRUE(bl_eq(exp, in));
685   }
686   {
687     ObjectStore::Transaction t;
688     t.write(cid, hoid, 0x3000, 0x1000, c);
689     r = apply_transaction(store, &osr, std::move(t));
690     ASSERT_EQ(r, 0);
691
692     bufferlist in, exp;
693     r = store->read(cid, hoid, 0, 0x4000, in);
694     ASSERT_EQ(0x4000, r);
695     exp.append(a);
696     exp.append(b);
697     exp.append(z);
698     exp.append(c);
699     ASSERT_TRUE(bl_eq(exp, in));
700   }
701   {
702     ObjectStore::Transaction t;
703     t.write(cid, hoid, 0x2000, 0x1000, a);
704     r = apply_transaction(store, &osr, std::move(t));
705     ASSERT_EQ(r, 0);
706
707     bufferlist in, exp;
708     r = store->read(cid, hoid, 0, 0x4000, in);
709     ASSERT_EQ(0x4000, r);
710     exp.append(a);
711     exp.append(b);
712     exp.append(a);
713     exp.append(c);
714     ASSERT_TRUE(bl_eq(exp, in));
715   }
716   {
717     ObjectStore::Transaction t;
718     t.write(cid, hoid, 0, 0x1000, c);
719     r = apply_transaction(store, &osr, std::move(t));
720     ASSERT_EQ(r, 0);
721   }
722   {
723     bufferlist in, exp;
724     r = store->read(cid, hoid, 0, 0x4000, in);
725     ASSERT_EQ(0x4000, r);
726     exp.append(c);
727     exp.append(b);
728     exp.append(a);
729     exp.append(c);
730     ASSERT_TRUE(bl_eq(exp, in));
731   }
732   {
733     ObjectStore::Transaction t;
734     t.remove(cid, hoid);
735     t.remove_collection(cid);
736     cerr << "Cleaning" << std::endl;
737     r = apply_transaction(store, &osr, std::move(t));
738     ASSERT_EQ(r, 0);
739   }
740 }
741
742 TEST_P(StoreTest, BufferCacheReadTest) {
743   ObjectStore::Sequencer osr("test");
744   int r;
745   coll_t cid;
746   ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
747   {
748     bufferlist in;
749     r = store->read(cid, hoid, 0, 5, in);
750     ASSERT_EQ(-ENOENT, r);
751   }
752   {
753     ObjectStore::Transaction t;
754     t.create_collection(cid, 0);
755     cerr << "Creating collection " << cid << std::endl;
756     r = apply_transaction(store, &osr, std::move(t));
757     ASSERT_EQ(r, 0);
758   }
759   {
760     bool exists = store->exists(cid, hoid);
761     ASSERT_TRUE(!exists);
762
763     ObjectStore::Transaction t;
764     t.touch(cid, hoid);
765     cerr << "Creating object " << hoid << std::endl;
766     r = apply_transaction(store, &osr, std::move(t));
767     ASSERT_EQ(r, 0);
768
769     exists = store->exists(cid, hoid);
770     ASSERT_EQ(true, exists);
771   }
772   {
773     ObjectStore::Transaction t;
774     bufferlist bl, newdata;
775     bl.append("abcde");
776     t.write(cid, hoid, 0, 5, bl);
777     t.write(cid, hoid, 10, 5, bl);
778     cerr << "TwinWrite" << std::endl;
779     r = apply_transaction(store, &osr, std::move(t));
780     ASSERT_EQ(r, 0);
781
782     r = store->read(cid, hoid, 0, 15, newdata);
783     ASSERT_EQ(r, 15);
784     {
785       bufferlist expected;
786       expected.append(bl);
787       expected.append_zero(5);
788       expected.append(bl);
789       ASSERT_TRUE(bl_eq(expected, newdata));
790     }
791   }
792   //overwrite over the same extents
793   {
794     ObjectStore::Transaction t;
795     bufferlist bl, newdata;
796     bl.append("edcba");
797     t.write(cid, hoid, 0, 5, bl);
798     t.write(cid, hoid, 10, 5, bl);
799     cerr << "TwinWrite" << std::endl;
800     r = apply_transaction(store, &osr, std::move(t));
801     ASSERT_EQ(r, 0);
802
803     r = store->read(cid, hoid, 0, 15, newdata);
804     ASSERT_EQ(r, 15);
805     {
806       bufferlist expected;
807       expected.append(bl);
808       expected.append_zero(5);
809       expected.append(bl);
810       ASSERT_TRUE(bl_eq(expected, newdata));
811     }
812   }
813   //additional write to an unused region of some blob
814   {
815     ObjectStore::Transaction t;
816     bufferlist bl2, newdata;
817     bl2.append("1234567890");
818
819     t.write(cid, hoid, 20, bl2.length(), bl2);
820     cerr << "Append" << std::endl;
821     r = apply_transaction(store, &osr, std::move(t));
822     ASSERT_EQ(r, 0);
823
824     r = store->read(cid, hoid, 0, 30, newdata);
825     ASSERT_EQ(r, 30);
826     {
827       bufferlist expected;
828       expected.append("edcba");
829       expected.append_zero(5);
830       expected.append("edcba");
831       expected.append_zero(5);
832       expected.append(bl2);
833
834       ASSERT_TRUE(bl_eq(expected, newdata));
835     }
836   }
837   //additional write to an unused region of some blob and partial owerite over existing extents
838   {
839     ObjectStore::Transaction t;
840     bufferlist bl, bl2, bl3, newdata;
841     bl.append("DCB");
842     bl2.append("1234567890");
843     bl3.append("BA");
844
845     t.write(cid, hoid, 30, bl2.length(), bl2);
846     t.write(cid, hoid, 1, bl.length(), bl);
847     t.write(cid, hoid, 13, bl3.length(), bl3);
848     cerr << "TripleWrite" << std::endl;
849     r = apply_transaction(store, &osr, std::move(t));
850     ASSERT_EQ(r, 0);
851
852     r = store->read(cid, hoid, 0, 40, newdata);
853     ASSERT_EQ(r, 40);
854     {
855       bufferlist expected;
856       expected.append("eDCBa");
857       expected.append_zero(5);
858       expected.append("edcBA");
859       expected.append_zero(5);
860       expected.append(bl2);
861       expected.append(bl2);
862
863       ASSERT_TRUE(bl_eq(expected, newdata));
864     }
865   }
866 }
867
868 void doCompressionTest( boost::scoped_ptr<ObjectStore>& store)
869 {
870   ObjectStore::Sequencer osr("test");
871   int r;
872   coll_t cid;
873   ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
874   {
875     bufferlist in;
876     r = store->read(cid, hoid, 0, 5, in);
877     ASSERT_EQ(-ENOENT, r);
878   }
879   {
880     ObjectStore::Transaction t;
881     t.create_collection(cid, 0);
882     cerr << "Creating collection " << cid << std::endl;
883     r = apply_transaction(store, &osr, std::move(t));
884     ASSERT_EQ(r, 0);
885   }
886   {
887     bool exists = store->exists(cid, hoid);
888     ASSERT_TRUE(!exists);
889
890     ObjectStore::Transaction t;
891     t.touch(cid, hoid);
892     cerr << "Creating object " << hoid << std::endl;
893     r = apply_transaction(store, &osr, std::move(t));
894     ASSERT_EQ(r, 0);
895
896     exists = store->exists(cid, hoid);
897     ASSERT_EQ(true, exists);
898   }
899   std::string data;
900   data.resize(0x10000 * 4);
901   for(size_t i = 0;i < data.size(); i++)
902     data[i] = i / 256;
903   {
904     ObjectStore::Transaction t;
905     bufferlist bl, newdata;
906     bl.append(data);
907     t.write(cid, hoid, 0, bl.length(), bl);
908     cerr << "CompressibleData (4xAU) Write" << std::endl;
909     r = apply_transaction(store, &osr, std::move(t));
910     ASSERT_EQ(r, 0);
911
912     r = store->read(cid, hoid, 0, data.size() , newdata);
913
914     ASSERT_EQ(r, (int)data.size());
915     {
916       bufferlist expected;
917       expected.append(data);
918       ASSERT_TRUE(bl_eq(expected, newdata));
919     }
920     newdata.clear();
921     r = store->read(cid, hoid, 0, 711 , newdata);
922     ASSERT_EQ(r, 711);
923     {
924       bufferlist expected;
925       expected.append(data.substr(0,711));
926       ASSERT_TRUE(bl_eq(expected, newdata));
927     }
928     newdata.clear();
929     r = store->read(cid, hoid, 0xf00f, data.size(), newdata);
930     ASSERT_EQ(r, int(data.size() - 0xf00f) );
931     {
932       bufferlist expected;
933       expected.append(data.substr(0xf00f));
934       ASSERT_TRUE(bl_eq(expected, newdata));
935     }
936     {
937       struct store_statfs_t statfs;
938       int r = store->statfs(&statfs);
939       ASSERT_EQ(r, 0);
940       ASSERT_EQ(statfs.stored, (unsigned)data.size());
941       ASSERT_LE(statfs.compressed, (unsigned)data.size());
942       ASSERT_EQ(statfs.compressed_original, (unsigned)data.size());
943       ASSERT_LE(statfs.compressed_allocated, (unsigned)data.size());
944     }
945   }
946   std::string data2;
947   data2.resize(0x10000 * 4 - 0x9000);
948   for(size_t i = 0;i < data2.size(); i++)
949     data2[i] = (i+1) / 256;
950   {
951     ObjectStore::Transaction t;
952     bufferlist bl, newdata;
953     bl.append(data2);
954     t.write(cid, hoid, 0x8000, bl.length(), bl);
955     cerr << "CompressibleData partial overwrite" << std::endl;
956     r = apply_transaction(store, &osr, std::move(t));
957     ASSERT_EQ(r, 0);
958
959     r = store->read(cid, hoid, 0, 0x10000, newdata);
960     ASSERT_EQ(r, (int)0x10000);
961     {
962       bufferlist expected;
963       expected.append(data.substr(0, 0x8000));
964       expected.append(data2.substr(0, 0x8000));
965       ASSERT_TRUE(bl_eq(expected, newdata));
966     }
967     newdata.clear();
968     r = store->read(cid, hoid, 0x9000, 711 , newdata);
969     ASSERT_EQ(r, 711);
970     {
971       bufferlist expected;
972       expected.append(data2.substr(0x1000,711));
973       ASSERT_TRUE(bl_eq(expected, newdata));
974     }
975     newdata.clear();
976     r = store->read(cid, hoid, 0x0, 0x40000, newdata);
977     ASSERT_EQ(r, int(0x40000) );
978     {
979       bufferlist expected;
980       expected.append(data.substr(0, 0x8000));
981       expected.append(data2.substr(0, 0x37000));
982       expected.append(data.substr(0x3f000, 0x1000));
983       ASSERT_TRUE(bl_eq(expected, newdata));
984     }
985   }
986   data2.resize(0x3f000);
987   for(size_t i = 0;i < data2.size(); i++)
988     data2[i] = (i+2) / 256;
989   {
990     ObjectStore::Transaction t;
991     bufferlist bl, newdata;
992     bl.append(data2);
993     t.write(cid, hoid, 0, bl.length(), bl);
994     cerr << "CompressibleData partial overwrite, two extents overlapped, single one to be removed" << std::endl;
995     r = apply_transaction(store, &osr, std::move(t));
996     ASSERT_EQ(r, 0);
997
998     r = store->read(cid, hoid, 0, 0x3e000 - 1, newdata);
999     ASSERT_EQ(r, (int)0x3e000 - 1);
1000     {
1001       bufferlist expected;
1002       expected.append(data2.substr(0, 0x3e000 - 1));
1003       ASSERT_TRUE(bl_eq(expected, newdata));
1004     }
1005     newdata.clear();
1006     r = store->read(cid, hoid, 0x3e000-1, 0x2001, newdata);
1007     ASSERT_EQ(r, 0x2001);
1008     {
1009       bufferlist expected;
1010       expected.append(data2.substr(0x3e000-1, 0x1001));
1011       expected.append(data.substr(0x3f000, 0x1000));
1012       ASSERT_TRUE(bl_eq(expected, newdata));
1013     }
1014     newdata.clear();
1015     r = store->read(cid, hoid, 0x0, 0x40000, newdata);
1016     ASSERT_EQ(r, int(0x40000) );
1017     {
1018       bufferlist expected;
1019       expected.append(data2.substr(0, 0x3f000));
1020       expected.append(data.substr(0x3f000, 0x1000));
1021       ASSERT_TRUE(bl_eq(expected, newdata));
1022     }
1023   }
1024   data.resize(0x1001);
1025   for(size_t i = 0;i < data.size(); i++)
1026     data[i] = (i+3) / 256;
1027   {
1028     ObjectStore::Transaction t;
1029     bufferlist bl, newdata;
1030     bl.append(data);
1031     t.write(cid, hoid, 0x3f000-1, bl.length(), bl);
1032     cerr << "Small chunk partial overwrite, two extents overlapped, single one to be removed" << std::endl;
1033     r = apply_transaction(store, &osr, std::move(t));
1034     ASSERT_EQ(r, 0);
1035
1036     r = store->read(cid, hoid, 0x3e000, 0x2000, newdata);
1037     ASSERT_EQ(r, (int)0x2000);
1038     {
1039       bufferlist expected;
1040       expected.append(data2.substr(0x3e000, 0x1000 - 1));
1041       expected.append(data.substr(0, 0x1001));
1042       ASSERT_TRUE(bl_eq(expected, newdata));
1043     }
1044   }
1045   {
1046     ObjectStore::Transaction t;
1047     t.remove(cid, hoid);
1048     cerr << "Cleaning object" << std::endl;
1049     r = apply_transaction(store, &osr, std::move(t));
1050     ASSERT_EQ(r, 0);
1051   }
1052   //force fsck
1053   EXPECT_EQ(store->umount(), 0);
1054   EXPECT_EQ(store->mount(), 0);
1055   auto orig_min_blob_size = g_conf->bluestore_compression_min_blob_size;
1056   {
1057     g_conf->set_val("bluestore_compression_min_blob_size", "262144");
1058     g_ceph_context->_conf->apply_changes(NULL);
1059     data.resize(0x10000*6);
1060
1061     for(size_t i = 0;i < data.size(); i++)
1062       data[i] = i / 256;
1063     ObjectStore::Transaction t;
1064     bufferlist bl, newdata;
1065     bl.append(data);
1066     t.write(cid, hoid, 0, bl.length(), bl);
1067     cerr << "CompressibleData large blob" << std::endl;
1068     r = apply_transaction(store, &osr, std::move(t));
1069     ASSERT_EQ(r, 0);
1070   }
1071   //force fsck
1072   EXPECT_EQ(store->umount(), 0);
1073   EXPECT_EQ(store->mount(), 0);
1074
1075   {
1076     ObjectStore::Transaction t;
1077     t.remove(cid, hoid);
1078     t.remove_collection(cid);
1079     cerr << "Cleaning" << std::endl;
1080     r = apply_transaction(store, &osr, std::move(t));
1081     ASSERT_EQ(r, 0);
1082   }
1083   g_conf->set_val("bluestore_compression_min_blob_size", stringify(orig_min_blob_size));
1084   g_ceph_context->_conf->apply_changes(NULL);
1085 }
1086
1087 TEST_P(StoreTest, CompressionTest) {
1088   if (string(GetParam()) != "bluestore")
1089     return;
1090
1091   g_conf->set_val("bluestore_compression_algorithm", "snappy");
1092   g_conf->set_val("bluestore_compression_mode", "force");
1093
1094   g_ceph_context->_conf->apply_changes(NULL);
1095
1096   doCompressionTest(store);
1097
1098   g_conf->set_val("bluestore_compression_algorithm", "zlib");
1099   g_conf->set_val("bluestore_compression_mode", "force");
1100   g_ceph_context->_conf->apply_changes(NULL);
1101
1102   doCompressionTest(store);
1103
1104   g_conf->set_val("bluestore_compression_algorithm", "snappy");
1105   g_conf->set_val("bluestore_compression_mode", "none");
1106   g_ceph_context->_conf->apply_changes(NULL);
1107 }
1108
1109 TEST_P(StoreTest, SimpleObjectTest) {
1110   ObjectStore::Sequencer osr("test");
1111   int r;
1112   coll_t cid;
1113   ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1114   {
1115     bufferlist in;
1116     r = store->read(cid, hoid, 0, 5, in);
1117     ASSERT_EQ(-ENOENT, r);
1118   }
1119   {
1120     ObjectStore::Transaction t;
1121     t.create_collection(cid, 0);
1122     cerr << "Creating collection " << cid << std::endl;
1123     r = apply_transaction(store, &osr, std::move(t));
1124     ASSERT_EQ(r, 0);
1125   }
1126   {
1127     bool exists = store->exists(cid, hoid);
1128     ASSERT_TRUE(!exists);
1129
1130     ObjectStore::Transaction t;
1131     t.touch(cid, hoid);
1132     cerr << "Creating object " << hoid << std::endl;
1133     r = apply_transaction(store, &osr, std::move(t));
1134     ASSERT_EQ(r, 0);
1135
1136     exists = store->exists(cid, hoid);
1137     ASSERT_EQ(true, exists);
1138   }
1139   {
1140     ObjectStore::Transaction t;
1141     t.remove(cid, hoid);
1142     t.touch(cid, hoid);
1143     cerr << "Remove then create" << std::endl;
1144     r = apply_transaction(store, &osr, std::move(t));
1145     ASSERT_EQ(r, 0);
1146   }
1147   {
1148     ObjectStore::Transaction t;
1149     bufferlist bl, orig;
1150     bl.append("abcde");
1151     orig = bl;
1152     t.remove(cid, hoid);
1153     t.write(cid, hoid, 0, 5, bl);
1154     cerr << "Remove then create" << std::endl;
1155     r = apply_transaction(store, &osr, std::move(t));
1156     ASSERT_EQ(r, 0);
1157
1158     bufferlist in;
1159     r = store->read(cid, hoid, 0, 5, in);
1160     ASSERT_EQ(5, r);
1161     ASSERT_TRUE(bl_eq(orig, in));
1162   }
1163   {
1164     ObjectStore::Transaction t;
1165     bufferlist bl, exp;
1166     bl.append("abcde");
1167     exp = bl;
1168     exp.append(bl);
1169     t.write(cid, hoid, 5, 5, bl);
1170     cerr << "Append" << std::endl;
1171     r = apply_transaction(store, &osr, std::move(t));
1172     ASSERT_EQ(r, 0);
1173
1174     bufferlist in;
1175     r = store->read(cid, hoid, 0, 10, in);
1176     ASSERT_EQ(10, r);
1177     ASSERT_TRUE(bl_eq(exp, in));
1178   }
1179   {
1180     ObjectStore::Transaction t;
1181     bufferlist bl, exp;
1182     bl.append("abcdeabcde");
1183     exp = bl;
1184     t.write(cid, hoid, 0, 10, bl);
1185     cerr << "Full overwrite" << std::endl;
1186     r = apply_transaction(store, &osr, std::move(t));
1187     ASSERT_EQ(r, 0);
1188
1189     bufferlist in;
1190     r = store->read(cid, hoid, 0, 10, in);
1191     ASSERT_EQ(10, r);
1192     ASSERT_TRUE(bl_eq(exp, in));
1193   }
1194   {
1195     ObjectStore::Transaction t;
1196     bufferlist bl;
1197     bl.append("abcde");
1198     t.write(cid, hoid, 3, 5, bl);
1199     cerr << "Partial overwrite" << std::endl;
1200     r = apply_transaction(store, &osr, std::move(t));
1201     ASSERT_EQ(r, 0);
1202
1203     bufferlist in, exp;
1204     exp.append("abcabcdede");
1205     r = store->read(cid, hoid, 0, 10, in);
1206     ASSERT_EQ(10, r);
1207     in.hexdump(cout);
1208     ASSERT_TRUE(bl_eq(exp, in));
1209   }
1210   {
1211     {
1212       ObjectStore::Transaction t;
1213       bufferlist bl;
1214       bl.append("fghij");
1215       t.truncate(cid, hoid, 0);
1216       t.write(cid, hoid, 5, 5, bl);
1217       cerr << "Truncate + hole" << std::endl;
1218       r = apply_transaction(store, &osr, std::move(t));
1219       ASSERT_EQ(r, 0);
1220     }
1221     {
1222       ObjectStore::Transaction t;
1223       bufferlist bl;
1224       bl.append("abcde");
1225       t.write(cid, hoid, 0, 5, bl);
1226       cerr << "Reverse fill-in" << std::endl;
1227       r = apply_transaction(store, &osr, std::move(t));
1228       ASSERT_EQ(r, 0);
1229     }
1230
1231     bufferlist in, exp;
1232     exp.append("abcdefghij");
1233     r = store->read(cid, hoid, 0, 10, in);
1234     ASSERT_EQ(10, r);
1235     in.hexdump(cout);
1236     ASSERT_TRUE(bl_eq(exp, in));
1237   }
1238   {
1239     ObjectStore::Transaction t;
1240     bufferlist bl;
1241     bl.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1242     t.write(cid, hoid, 0, bl.length(), bl);
1243     cerr << "larger overwrite" << std::endl;
1244     r = apply_transaction(store, &osr, std::move(t));
1245     ASSERT_EQ(r, 0);
1246
1247     bufferlist in;
1248     r = store->read(cid, hoid, 0, bl.length(), in);
1249     ASSERT_EQ((int)bl.length(), r);
1250     in.hexdump(cout);
1251     ASSERT_TRUE(bl_eq(bl, in));
1252   }
1253   {
1254     bufferlist bl;
1255     bl.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1256
1257     //test: offset=len=0 mean read all data
1258     bufferlist in;
1259     r = store->read(cid, hoid, 0, 0, in);
1260     ASSERT_EQ((int)bl.length(), r);
1261     in.hexdump(cout);
1262     ASSERT_TRUE(bl_eq(bl, in));
1263   }
1264   {
1265     //verifying unaligned csums
1266     std::string s1("1"), s2(0x1000, '2'), s3("00");
1267     {
1268       ObjectStore::Transaction t;
1269       bufferlist bl;
1270       bl.append(s1);
1271       bl.append(s2);
1272       t.truncate(cid, hoid, 0);
1273       t.write(cid, hoid, 0x1000-1, bl.length(), bl);
1274       cerr << "Write unaligned csum, stage 1" << std::endl;
1275       r = apply_transaction(store, &osr, std::move(t));
1276       ASSERT_EQ(r, 0);
1277     }
1278
1279     bufferlist in, exp1, exp2, exp3;
1280     exp1.append(s1);
1281     exp2.append(s2);
1282     exp3.append(s3);
1283     r = store->read(cid, hoid, 0x1000-1, 1, in);
1284     ASSERT_EQ(1, r);
1285     ASSERT_TRUE(bl_eq(exp1, in));
1286     in.clear();
1287     r = store->read(cid, hoid, 0x1000, 0x1000, in);
1288     ASSERT_EQ(0x1000, r);
1289     ASSERT_TRUE(bl_eq(exp2, in));
1290
1291     {
1292       ObjectStore::Transaction t;
1293       bufferlist bl;
1294       bl.append(s3);
1295       t.write(cid, hoid, 1, bl.length(), bl);
1296       cerr << "Write unaligned csum, stage 2" << std::endl;
1297       r = apply_transaction(store, &osr, std::move(t));
1298       ASSERT_EQ(r, 0);
1299     }
1300     in.clear();
1301     r = store->read(cid, hoid, 1, 2, in);
1302     ASSERT_EQ(2, r);
1303     ASSERT_TRUE(bl_eq(exp3, in));
1304     in.clear();
1305     r = store->read(cid, hoid, 0x1000-1, 1, in);
1306     ASSERT_EQ(1, r);
1307     ASSERT_TRUE(bl_eq(exp1, in));
1308     in.clear();
1309     r = store->read(cid, hoid, 0x1000, 0x1000, in);
1310     ASSERT_EQ(0x1000, r);
1311     ASSERT_TRUE(bl_eq(exp2, in));
1312
1313   }
1314
1315   {
1316     ObjectStore::Transaction t;
1317     t.remove(cid, hoid);
1318     t.remove_collection(cid);
1319     cerr << "Cleaning" << std::endl;
1320     r = apply_transaction(store, &osr, std::move(t));
1321     ASSERT_EQ(r, 0);
1322   }
1323 }
1324
1325 #if defined(HAVE_LIBAIO)
1326 TEST_P(StoreTestSpecificAUSize, BluestoreStatFSTest) {
1327   if(string(GetParam()) != "bluestore")
1328     return;
1329   StartDeferred(65536);
1330   g_conf->set_val("bluestore_compression_mode", "force");
1331
1332   // just a big number to disble gc
1333   g_conf->set_val("bluestore_gc_enable_total_threshold", "100000");
1334   g_conf->apply_changes(NULL);
1335   int r;
1336
1337   ObjectStore::Sequencer osr("test");
1338   coll_t cid;
1339   ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1340   ghobject_t hoid2 = hoid;
1341   hoid2.hobj.snap = 1;
1342   {
1343     bufferlist in;
1344     r = store->read(cid, hoid, 0, 5, in);
1345     ASSERT_EQ(-ENOENT, r);
1346   }
1347   {
1348     ObjectStore::Transaction t;
1349     t.create_collection(cid, 0);
1350     cerr << "Creating collection " << cid << std::endl;
1351     r = apply_transaction(store, &osr, std::move(t));
1352     ASSERT_EQ(r, 0);
1353   }
1354   {
1355     bool exists = store->exists(cid, hoid);
1356     ASSERT_TRUE(!exists);
1357
1358     ObjectStore::Transaction t;
1359     t.touch(cid, hoid);
1360     cerr << "Creating object " << hoid << std::endl;
1361     r = apply_transaction(store, &osr, std::move(t));
1362     ASSERT_EQ(r, 0);
1363
1364     exists = store->exists(cid, hoid);
1365     ASSERT_EQ(true, exists);
1366   }
1367   {
1368     struct store_statfs_t statfs;
1369     int r = store->statfs(&statfs);
1370     ASSERT_EQ(r, 0);
1371     ASSERT_EQ( 0u, statfs.allocated);
1372     ASSERT_EQ( 0u, statfs.stored);
1373     ASSERT_EQ(g_conf->bluestore_block_size, statfs.total);
1374     ASSERT_TRUE(statfs.available > 0u && statfs.available < g_conf->bluestore_block_size);
1375     //force fsck
1376     EXPECT_EQ(store->umount(), 0);
1377     EXPECT_EQ(store->mount(), 0);
1378   }
1379   {
1380     ObjectStore::Transaction t;
1381     bufferlist bl;
1382     bl.append("abcde");
1383     t.write(cid, hoid, 0, 5, bl);
1384     cerr << "Append 5 bytes" << std::endl;
1385     r = apply_transaction(store, &osr, std::move(t));
1386     ASSERT_EQ(r, 0);
1387
1388     struct store_statfs_t statfs;
1389     int r = store->statfs(&statfs);
1390     ASSERT_EQ(r, 0);
1391     ASSERT_EQ(5, statfs.stored);
1392     ASSERT_EQ(0x10000, statfs.allocated);
1393     ASSERT_EQ(0, statfs.compressed);
1394     ASSERT_EQ(0, statfs.compressed_original);
1395     ASSERT_EQ(0, statfs.compressed_allocated);
1396     //force fsck
1397     EXPECT_EQ(store->umount(), 0);
1398     EXPECT_EQ(store->mount(), 0);
1399   }
1400   {
1401     ObjectStore::Transaction t;
1402     std::string s(0x30000, 'a');
1403     bufferlist bl;
1404     bl.append(s);
1405     t.write(cid, hoid, 0x10000, bl.length(), bl);
1406     cerr << "Append 0x30000 compressible bytes" << std::endl;
1407     r = apply_transaction(store, &osr, std::move(t));
1408     ASSERT_EQ(r, 0);
1409
1410     struct store_statfs_t statfs;
1411     int r = store->statfs(&statfs);
1412     ASSERT_EQ(r, 0);
1413     ASSERT_EQ(0x30005, statfs.stored);
1414     ASSERT_EQ(0x30000, statfs.allocated);
1415     ASSERT_LE(statfs.compressed, 0x10000);
1416     ASSERT_EQ(0x20000, statfs.compressed_original);
1417     ASSERT_EQ(statfs.compressed_allocated, 0x10000);
1418     //force fsck
1419     EXPECT_EQ(store->umount(), 0);
1420     EXPECT_EQ(store->mount(), 0);
1421   }
1422   {
1423     ObjectStore::Transaction t;
1424     t.zero(cid, hoid, 1, 3);
1425     t.zero(cid, hoid, 0x20000, 9);
1426     cerr << "Punch hole at 1~3, 0x20000~9" << std::endl;
1427     r = apply_transaction(store, &osr, std::move(t));
1428     ASSERT_EQ(r, 0);
1429
1430     struct store_statfs_t statfs;
1431     int r = store->statfs(&statfs);
1432     ASSERT_EQ(r, 0);
1433     ASSERT_EQ(0x30005 - 3 - 9, statfs.stored);
1434     ASSERT_EQ(0x30000, statfs.allocated);
1435     ASSERT_LE(statfs.compressed, 0x10000);
1436     ASSERT_EQ(0x20000 - 9, statfs.compressed_original);
1437     ASSERT_EQ(statfs.compressed_allocated, 0x10000);
1438     //force fsck
1439     EXPECT_EQ(store->umount(), 0);
1440     EXPECT_EQ(store->mount(), 0);
1441   }
1442   {
1443     ObjectStore::Transaction t;
1444     std::string s(0x1000, 'b');
1445     bufferlist bl;
1446     bl.append(s);
1447     t.write(cid, hoid, 1, bl.length(), bl);
1448     t.write(cid, hoid, 0x10001, bl.length(), bl);
1449     cerr << "Overwrite first and second(compressible) extents" << std::endl;
1450     r = apply_transaction(store, &osr, std::move(t));
1451     ASSERT_EQ(r, 0);
1452
1453     struct store_statfs_t statfs;
1454     int r = store->statfs(&statfs);
1455     ASSERT_EQ(r, 0);
1456     ASSERT_EQ(0x30001 - 9 + 0x1000, statfs.stored);
1457     ASSERT_EQ(0x40000, statfs.allocated);
1458     ASSERT_LE(statfs.compressed, 0x10000);
1459     ASSERT_EQ(0x20000 - 9 - 0x1000, statfs.compressed_original);
1460     ASSERT_EQ(statfs.compressed_allocated, 0x10000);
1461     //force fsck
1462     EXPECT_EQ(store->umount(), 0);
1463     EXPECT_EQ(store->mount(), 0);
1464   }
1465   {
1466     ObjectStore::Transaction t;
1467     std::string s(0x10000, 'c');
1468     bufferlist bl;
1469     bl.append(s);
1470     t.write(cid, hoid, 0x10000, bl.length(), bl);
1471     t.write(cid, hoid, 0x20000, bl.length(), bl);
1472     t.write(cid, hoid, 0x30000, bl.length(), bl);
1473     cerr << "Overwrite compressed extent with 3 uncompressible ones" << std::endl;
1474     r = apply_transaction(store, &osr, std::move(t));
1475     ASSERT_EQ(r, 0);
1476
1477     struct store_statfs_t statfs;
1478     int r = store->statfs(&statfs);
1479     ASSERT_EQ(r, 0);
1480     ASSERT_EQ(0x30000 + 0x1001, statfs.stored);
1481     ASSERT_EQ(0x40000, statfs.allocated);
1482     ASSERT_LE(statfs.compressed, 0);
1483     ASSERT_EQ(0, statfs.compressed_original);
1484     ASSERT_EQ(0, statfs.compressed_allocated);
1485     //force fsck
1486     EXPECT_EQ(store->umount(), 0);
1487     EXPECT_EQ(store->mount(), 0);
1488   }
1489   {
1490     ObjectStore::Transaction t;
1491     t.zero(cid, hoid, 0, 0x40000);
1492     cerr << "Zero object" << std::endl;
1493     r = apply_transaction(store, &osr, std::move(t));
1494     ASSERT_EQ(r, 0);
1495     struct store_statfs_t statfs;
1496     int r = store->statfs(&statfs);
1497     ASSERT_EQ(r, 0);
1498     ASSERT_EQ(0u, statfs.allocated);
1499     ASSERT_EQ(0u, statfs.stored);
1500     ASSERT_EQ(0u, statfs.compressed_original);
1501     ASSERT_EQ(0u, statfs.compressed);
1502     ASSERT_EQ(0u, statfs.compressed_allocated);
1503     //force fsck
1504     EXPECT_EQ(store->umount(), 0);
1505     EXPECT_EQ(store->mount(), 0);
1506   }
1507   {
1508     ObjectStore::Transaction t;
1509     std::string s(0x10000, 'c');
1510     bufferlist bl;
1511     bl.append(s);
1512     bl.append(s);
1513     bl.append(s);
1514     bl.append(s.substr(0, 0x10000-2));
1515     t.write(cid, hoid, 0, bl.length(), bl);
1516     cerr << "Yet another compressible write" << std::endl;
1517     r = apply_transaction(store, &osr, std::move(t));
1518     ASSERT_EQ(r, 0);
1519     struct store_statfs_t statfs;
1520     r = store->statfs(&statfs);
1521     ASSERT_EQ(r, 0);
1522     ASSERT_EQ(0x40000 - 2, statfs.stored);
1523     ASSERT_EQ(0x30000, statfs.allocated);
1524     ASSERT_LE(statfs.compressed, 0x10000);
1525     ASSERT_EQ(0x20000, statfs.compressed_original);
1526     ASSERT_EQ(0x10000, statfs.compressed_allocated);
1527     //force fsck
1528     EXPECT_EQ(store->umount(), 0);
1529     EXPECT_EQ(store->mount(), 0);
1530   }
1531   {
1532     struct store_statfs_t statfs;
1533     r = store->statfs(&statfs);
1534     ASSERT_EQ(r, 0);
1535
1536     ObjectStore::Transaction t;
1537     t.clone(cid, hoid, hoid2);
1538     cerr << "Clone compressed objecte" << std::endl;
1539     r = apply_transaction(store, &osr, std::move(t));
1540     ASSERT_EQ(r, 0);
1541     struct store_statfs_t statfs2;
1542     r = store->statfs(&statfs2);
1543     ASSERT_EQ(r, 0);
1544     ASSERT_GT(statfs2.stored, statfs.stored);
1545     ASSERT_EQ(statfs2.allocated, statfs.allocated);
1546     ASSERT_GT(statfs2.compressed, statfs.compressed);
1547     ASSERT_GT(statfs2.compressed_original, statfs.compressed_original);
1548     ASSERT_EQ(statfs2.compressed_allocated, statfs.compressed_allocated);
1549   }
1550
1551   {
1552     ObjectStore::Transaction t;
1553     t.remove(cid, hoid);
1554     t.remove(cid, hoid2);
1555     t.remove_collection(cid);
1556     cerr << "Cleaning" << std::endl;
1557     r = apply_transaction(store, &osr, std::move(t));
1558     ASSERT_EQ(r, 0);
1559
1560     struct store_statfs_t statfs;
1561     r = store->statfs(&statfs);
1562     ASSERT_EQ(r, 0);
1563     ASSERT_EQ( 0u, statfs.allocated);
1564     ASSERT_EQ( 0u, statfs.stored);
1565     ASSERT_EQ( 0u, statfs.compressed_original);
1566     ASSERT_EQ( 0u, statfs.compressed);
1567     ASSERT_EQ( 0u, statfs.compressed_allocated);
1568   }
1569   g_conf->set_val("bluestore_gc_enable_total_threshold", "0");
1570   g_conf->set_val("bluestore_compression_mode", "none");
1571   g_ceph_context->_conf->apply_changes(NULL);
1572 }
1573
1574 TEST_P(StoreTestSpecificAUSize, BluestoreFragmentedBlobTest) {
1575   if(string(GetParam()) != "bluestore")
1576     return;
1577   StartDeferred(0x10000);
1578
1579   ObjectStore::Sequencer osr("test");
1580   int r;
1581   coll_t cid;
1582   ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1583   {
1584     ObjectStore::Transaction t;
1585     t.create_collection(cid, 0);
1586     cerr << "Creating collection " << cid << std::endl;
1587     r = apply_transaction(store, &osr, std::move(t));
1588     ASSERT_EQ(r, 0);
1589   }
1590   {
1591     bool exists = store->exists(cid, hoid);
1592     ASSERT_TRUE(!exists);
1593
1594     ObjectStore::Transaction t;
1595     t.touch(cid, hoid);
1596     cerr << "Creating object " << hoid << std::endl;
1597     r = apply_transaction(store, &osr, std::move(t));
1598     ASSERT_EQ(r, 0);
1599
1600     exists = store->exists(cid, hoid);
1601     ASSERT_EQ(true, exists);
1602   }
1603   {
1604     struct store_statfs_t statfs;
1605     int r = store->statfs(&statfs);
1606     ASSERT_EQ(r, 0);
1607     ASSERT_EQ(g_conf->bluestore_block_size, statfs.total);
1608     ASSERT_EQ(0u, statfs.allocated);
1609     ASSERT_EQ(0u, statfs.stored);
1610     ASSERT_TRUE(statfs.available > 0u && statfs.available < g_conf->bluestore_block_size);
1611   }
1612   std::string data;
1613   data.resize(0x10000 * 3);
1614   {
1615     ObjectStore::Transaction t;
1616     for(size_t i = 0;i < data.size(); i++)
1617       data[i] = i / 256 + 1;
1618     bufferlist bl, newdata;
1619     bl.append(data);
1620     t.write(cid, hoid, 0, bl.length(), bl);
1621     t.zero(cid, hoid, 0x10000, 0x10000);
1622     cerr << "Append 3*0x10000 bytes and punch a hole 0x10000~10000" << std::endl;
1623     r = apply_transaction(store, &osr, std::move(t));
1624     ASSERT_EQ(r, 0);
1625
1626     struct store_statfs_t statfs;
1627     int r = store->statfs(&statfs);
1628     ASSERT_EQ(r, 0);
1629     ASSERT_EQ(0x20000, statfs.stored);
1630     ASSERT_EQ(0x20000, statfs.allocated);
1631
1632     r = store->read(cid, hoid, 0, data.size(), newdata);
1633     ASSERT_EQ(r, (int)data.size());
1634     {
1635       bufferlist expected;
1636       expected.append(data.substr(0, 0x10000));
1637       expected.append(string(0x10000, 0));
1638       expected.append(data.substr(0x20000, 0x10000));
1639       ASSERT_TRUE(bl_eq(expected, newdata));
1640     }
1641     newdata.clear();
1642
1643     r = store->read(cid, hoid, 1, data.size()-2, newdata);
1644     ASSERT_EQ(r, (int)data.size()-2);
1645     {
1646       bufferlist expected;
1647       expected.append(data.substr(1, 0x10000-1));
1648       expected.append(string(0x10000, 0));
1649       expected.append(data.substr(0x20000, 0x10000 - 1));
1650       ASSERT_TRUE(bl_eq(expected, newdata));
1651     }
1652     newdata.clear();
1653   }
1654   //force fsck
1655   EXPECT_EQ(store->umount(), 0);
1656   EXPECT_EQ(store->mount(), 0);
1657
1658   {
1659     ObjectStore::Transaction t;
1660     std::string data2(3, 'b');
1661     bufferlist bl, newdata;
1662     bl.append(data2);
1663     t.write(cid, hoid, 0x20000, bl.length(), bl);
1664     cerr << "Write 3 bytes after the hole" << std::endl;
1665     r = apply_transaction(store, &osr, std::move(t));
1666     ASSERT_EQ(r, 0);
1667
1668     struct store_statfs_t statfs;
1669     int r = store->statfs(&statfs);
1670     ASSERT_EQ(r, 0);
1671     ASSERT_EQ(0x20000, statfs.allocated);
1672     ASSERT_EQ(0x20000, statfs.stored);
1673
1674     r = store->read(cid, hoid, 0x20000-1, 21, newdata);
1675     ASSERT_EQ(r, (int)21);
1676     {
1677       bufferlist expected;
1678       expected.append(string(0x1, 0));
1679       expected.append(string(data2));
1680       expected.append(data.substr(0x20003, 21-4));
1681       ASSERT_TRUE(bl_eq(expected, newdata));
1682     }
1683     newdata.clear();
1684   }
1685   //force fsck
1686   EXPECT_EQ(store->umount(), 0);
1687   EXPECT_EQ(store->mount(), 0);
1688
1689   {
1690     ObjectStore::Transaction t;
1691     std::string data2(3, 'a');
1692     bufferlist bl, newdata;
1693     bl.append(data2);
1694     t.write(cid, hoid, 0x10000+1, bl.length(), bl);
1695     cerr << "Write 3 bytes to the hole" << std::endl;
1696     r = apply_transaction(store, &osr, std::move(t));
1697     ASSERT_EQ(r, 0);
1698
1699     struct store_statfs_t statfs;
1700     int r = store->statfs(&statfs);
1701     ASSERT_EQ(r, 0);
1702     ASSERT_EQ(0x30000, statfs.allocated);
1703     ASSERT_EQ(0x20003, statfs.stored);
1704
1705     r = store->read(cid, hoid, 0x10000-1, 0x10000+22, newdata);
1706     ASSERT_EQ(r, (int)0x10000+22);
1707     {
1708       bufferlist expected;
1709       expected.append(data.substr(0x10000-1, 1));
1710       expected.append(string(0x1, 0));
1711       expected.append(data2);
1712       expected.append(string(0x10000-4, 0));
1713       expected.append(string(0x3, 'b'));
1714       expected.append(data.substr(0x20004, 21-3));
1715       ASSERT_TRUE(bl_eq(expected, newdata));
1716     }
1717     newdata.clear();
1718   }
1719   {
1720     ObjectStore::Transaction t;
1721     bufferlist bl, newdata;
1722     bl.append(string(0x30000, 'c'));
1723     t.write(cid, hoid, 0, 0x30000, bl);
1724     t.zero(cid, hoid, 0, 0x10000);
1725     t.zero(cid, hoid, 0x20000, 0x10000);
1726     cerr << "Rewrite an object and create two holes at the begining and the end" << std::endl;
1727     r = apply_transaction(store, &osr, std::move(t));
1728     ASSERT_EQ(r, 0);
1729
1730     struct store_statfs_t statfs;
1731     int r = store->statfs(&statfs);
1732     ASSERT_EQ(r, 0);
1733     ASSERT_EQ(0x10000, statfs.allocated);
1734     ASSERT_EQ(0x10000, statfs.stored);
1735
1736     r = store->read(cid, hoid, 0, 0x30000, newdata);
1737     ASSERT_EQ(r, (int)0x30000);
1738     {
1739       bufferlist expected;
1740       expected.append(string(0x10000, 0));
1741       expected.append(string(0x10000, 'c'));
1742       expected.append(string(0x10000, 0));
1743       ASSERT_TRUE(bl_eq(expected, newdata));
1744     }
1745     newdata.clear();
1746   }
1747
1748   //force fsck
1749   EXPECT_EQ(store->umount(), 0);
1750   EXPECT_EQ(store->mount(), 0);
1751
1752   {
1753     ObjectStore::Transaction t;
1754     t.remove(cid, hoid);
1755     t.remove_collection(cid);
1756     cerr << "Cleaning" << std::endl;
1757     r = apply_transaction(store, &osr, std::move(t));
1758     ASSERT_EQ(r, 0);
1759
1760     struct store_statfs_t statfs;
1761     r = store->statfs(&statfs);
1762     ASSERT_EQ(r, 0);
1763     ASSERT_EQ( 0u, statfs.allocated);
1764     ASSERT_EQ( 0u, statfs.stored);
1765     ASSERT_EQ( 0u, statfs.compressed_original);
1766     ASSERT_EQ( 0u, statfs.compressed);
1767     ASSERT_EQ( 0u, statfs.compressed_allocated);
1768   }
1769 }
1770 #endif
1771
1772 TEST_P(StoreTest, ManySmallWrite) {
1773   ObjectStore::Sequencer osr("test");
1774   int r;
1775   coll_t cid;
1776   ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1777   ghobject_t b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
1778   {
1779     ObjectStore::Transaction t;
1780     t.create_collection(cid, 0);
1781     cerr << "Creating collection " << cid << std::endl;
1782     r = apply_transaction(store, &osr, std::move(t));
1783     ASSERT_EQ(r, 0);
1784   }
1785   bufferlist bl;
1786   bufferptr bp(4096);
1787   bp.zero();
1788   bl.append(bp);
1789   for (int i=0; i<100; ++i) {
1790     ObjectStore::Transaction t;
1791     t.write(cid, a, i*4096, 4096, bl, 0);
1792     r = apply_transaction(store, &osr, std::move(t));
1793     ASSERT_EQ(r, 0);
1794   }
1795   for (int i=0; i<100; ++i) {
1796     ObjectStore::Transaction t;
1797     t.write(cid, b, (rand() % 1024)*4096, 4096, bl, 0);
1798     r = apply_transaction(store, &osr, std::move(t));
1799     ASSERT_EQ(r, 0);
1800   }
1801   {
1802     ObjectStore::Transaction t;
1803     t.remove(cid, a);
1804     t.remove(cid, b);
1805     t.remove_collection(cid);
1806     cerr << "Cleaning" << std::endl;
1807     r = apply_transaction(store, &osr, std::move(t));
1808     ASSERT_EQ(r, 0);
1809   }
1810 }
1811
1812 TEST_P(StoreTest, MultiSmallWriteSameBlock) {
1813   ObjectStore::Sequencer osr("test");
1814   int r;
1815   coll_t cid;
1816   ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1817   {
1818     ObjectStore::Transaction t;
1819     t.create_collection(cid, 0);
1820     cerr << "Creating collection " << cid << std::endl;
1821     r = apply_transaction(store, &osr, std::move(t));
1822     ASSERT_EQ(r, 0);
1823   }
1824   bufferlist bl;
1825   bl.append("short");
1826   C_SaferCond c, d;
1827   // touch same block in both same transaction, tls, and pipelined txns
1828   {
1829     ObjectStore::Transaction t, u;
1830     t.write(cid, a, 0, 5, bl, 0);
1831     t.write(cid, a, 5, 5, bl, 0);
1832     t.write(cid, a, 4094, 5, bl, 0);
1833     t.write(cid, a, 9000, 5, bl, 0);
1834     u.write(cid, a, 10, 5, bl, 0);
1835     u.write(cid, a, 7000, 5, bl, 0);
1836     vector<ObjectStore::Transaction> v = {t, u};
1837     store->queue_transactions(&osr, v, nullptr, &c);
1838   }
1839   {
1840     ObjectStore::Transaction t, u;
1841     t.write(cid, a, 40, 5, bl, 0);
1842     t.write(cid, a, 45, 5, bl, 0);
1843     t.write(cid, a, 4094, 5, bl, 0);
1844     t.write(cid, a, 6000, 5, bl, 0);
1845     u.write(cid, a, 610, 5, bl, 0);
1846     u.write(cid, a, 11000, 5, bl, 0);
1847     vector<ObjectStore::Transaction> v = {t, u};
1848     store->queue_transactions(&osr, v, nullptr, &d);
1849   }
1850   c.wait();
1851   d.wait();
1852   {
1853     bufferlist bl2;
1854     r = store->read(cid, a, 0, 16000, bl2);
1855     ASSERT_GE(r, 0);
1856   }
1857   {
1858     ObjectStore::Transaction t;
1859     t.remove(cid, a);
1860     t.remove_collection(cid);
1861     cerr << "Cleaning" << std::endl;
1862     r = apply_transaction(store, &osr, std::move(t));
1863     ASSERT_EQ(r, 0);
1864   }
1865 }
1866
1867 TEST_P(StoreTest, SmallSkipFront) {
1868   ObjectStore::Sequencer osr("test");
1869   int r;
1870   coll_t cid;
1871   ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1872   {
1873     ObjectStore::Transaction t;
1874     t.create_collection(cid, 0);
1875     cerr << "Creating collection " << cid << std::endl;
1876     r = apply_transaction(store, &osr, std::move(t));
1877     ASSERT_EQ(r, 0);
1878   }
1879   {
1880     ObjectStore::Transaction t;
1881     t.touch(cid, a);
1882     t.truncate(cid, a, 3000);
1883     r = apply_transaction(store, &osr, std::move(t));
1884     ASSERT_EQ(r, 0);
1885   }
1886   {
1887     bufferlist bl;
1888     bufferptr bp(4096);
1889     memset(bp.c_str(), 1, 4096);
1890     bl.append(bp);
1891     ObjectStore::Transaction t;
1892     t.write(cid, a, 4096, 4096, bl);
1893     r = apply_transaction(store, &osr, std::move(t));
1894     ASSERT_EQ(r, 0);
1895   }
1896   {
1897     bufferlist bl;
1898     ASSERT_EQ(8192, store->read(cid, a, 0, 8192, bl));
1899     for (unsigned i=0; i<4096; ++i)
1900       ASSERT_EQ(0, bl[i]);
1901     for (unsigned i=4096; i<8192; ++i)
1902       ASSERT_EQ(1, bl[i]);
1903   }
1904   {
1905     ObjectStore::Transaction t;
1906     t.remove(cid, a);
1907     t.remove_collection(cid);
1908     cerr << "Cleaning" << std::endl;
1909     r = apply_transaction(store, &osr, std::move(t));
1910     ASSERT_EQ(r, 0);
1911   }
1912 }
1913
1914 TEST_P(StoreTest, AppendDeferredVsTailCache) {
1915   ObjectStore::Sequencer osr("test");
1916   int r;
1917   coll_t cid;
1918   ghobject_t a(hobject_t(sobject_t("fooo", CEPH_NOSNAP)));
1919   {
1920     ObjectStore::Transaction t;
1921     t.create_collection(cid, 0);
1922     cerr << "Creating collection " << cid << std::endl;
1923     r = store->apply_transaction(&osr, std::move(t));
1924     ASSERT_EQ(r, 0);
1925   }
1926   unsigned min_alloc = g_conf->bluestore_min_alloc_size;
1927   g_conf->set_val("bluestore_inject_deferred_apply_delay", "1.0");
1928   g_ceph_context->_conf->apply_changes(NULL);
1929   unsigned size = min_alloc / 3;
1930   bufferptr bpa(size);
1931   memset(bpa.c_str(), 1, bpa.length());
1932   bufferlist bla;
1933   bla.append(bpa);
1934   {
1935     ObjectStore::Transaction t;
1936     t.write(cid, a, 0, bla.length(), bla, 0);
1937     r = store->apply_transaction(&osr, std::move(t));
1938     ASSERT_EQ(r, 0);
1939   }
1940
1941   // force cached tail to clear ...
1942   {
1943     int r = store->umount();
1944     ASSERT_EQ(0, r);
1945     r = store->mount();
1946     ASSERT_EQ(0, r);
1947   }
1948
1949   bufferptr bpb(size);
1950   memset(bpb.c_str(), 2, bpb.length());
1951   bufferlist blb;
1952   blb.append(bpb);
1953   {
1954     ObjectStore::Transaction t;
1955     t.write(cid, a, bla.length(), blb.length(), blb, 0);
1956     r = store->apply_transaction(&osr, std::move(t));
1957     ASSERT_EQ(r, 0);
1958   }
1959   bufferptr bpc(size);
1960   memset(bpc.c_str(), 3, bpc.length());
1961   bufferlist blc;
1962   blc.append(bpc);
1963   {
1964     ObjectStore::Transaction t;
1965     t.write(cid, a, bla.length() + blb.length(), blc.length(), blc, 0);
1966     r = store->apply_transaction(&osr, std::move(t));
1967     ASSERT_EQ(r, 0);
1968   }
1969   bufferlist final;
1970   final.append(bla);
1971   final.append(blb);
1972   final.append(blc);
1973   bufferlist actual;
1974   {
1975     ASSERT_EQ((int)final.length(),
1976               store->read(cid, a, 0, final.length(), actual));
1977     ASSERT_TRUE(bl_eq(final, actual));
1978   }
1979   {
1980     ObjectStore::Transaction t;
1981     t.remove(cid, a);
1982     t.remove_collection(cid);
1983     cerr << "Cleaning" << std::endl;
1984     r = store->apply_transaction(&osr, std::move(t));
1985     ASSERT_EQ(r, 0);
1986   }
1987   g_conf->set_val("bluestore_inject_deferred_apply_delay", "0");
1988   g_ceph_context->_conf->apply_changes(NULL);
1989 }
1990
1991 TEST_P(StoreTest, AppendZeroTrailingSharedBlock) {
1992   ObjectStore::Sequencer osr("test");
1993   int r;
1994   coll_t cid;
1995   ghobject_t a(hobject_t(sobject_t("fooo", CEPH_NOSNAP)));
1996   ghobject_t b = a;
1997   b.hobj.snap = 1;
1998   {
1999     ObjectStore::Transaction t;
2000     t.create_collection(cid, 0);
2001     cerr << "Creating collection " << cid << std::endl;
2002     r = store->apply_transaction(&osr, std::move(t));
2003     ASSERT_EQ(r, 0);
2004   }
2005   unsigned min_alloc = g_conf->bluestore_min_alloc_size;
2006   unsigned size = min_alloc / 3;
2007   bufferptr bpa(size);
2008   memset(bpa.c_str(), 1, bpa.length());
2009   bufferlist bla;
2010   bla.append(bpa);
2011   // make sure there is some trailing gunk in the last block
2012   {
2013     bufferlist bt;
2014     bt.append(bla);
2015     bt.append("BADBADBADBAD");
2016     ObjectStore::Transaction t;
2017     t.write(cid, a, 0, bt.length(), bt, 0);
2018     r = store->apply_transaction(&osr, std::move(t));
2019     ASSERT_EQ(r, 0);
2020   }
2021   {
2022     ObjectStore::Transaction t;
2023     t.truncate(cid, a, size);
2024     r = store->apply_transaction(&osr, std::move(t));
2025     ASSERT_EQ(r, 0);
2026   }
2027
2028   // clone
2029   {
2030     ObjectStore::Transaction t;
2031     t.clone(cid, a, b);
2032     r = store->apply_transaction(&osr, std::move(t));
2033     ASSERT_EQ(r, 0);
2034   }
2035
2036   // append with implicit zeroing
2037   bufferptr bpb(size);
2038   memset(bpb.c_str(), 2, bpb.length());
2039   bufferlist blb;
2040   blb.append(bpb);
2041   {
2042     ObjectStore::Transaction t;
2043     t.write(cid, a, min_alloc * 3, blb.length(), blb, 0);
2044     r = store->apply_transaction(&osr, std::move(t));
2045     ASSERT_EQ(r, 0);
2046   }
2047   bufferlist final;
2048   final.append(bla);
2049   bufferlist zeros;
2050   zeros.append_zero(min_alloc * 3 - size);
2051   final.append(zeros);
2052   final.append(blb);
2053   bufferlist actual;
2054   {
2055     ASSERT_EQ((int)final.length(),
2056               store->read(cid, a, 0, final.length(), actual));
2057     final.hexdump(cout);
2058     actual.hexdump(cout);
2059     ASSERT_TRUE(bl_eq(final, actual));
2060   }
2061   {
2062     ObjectStore::Transaction t;
2063     t.remove(cid, a);
2064     t.remove(cid, b);
2065     t.remove_collection(cid);
2066     cerr << "Cleaning" << std::endl;
2067     r = store->apply_transaction(&osr, std::move(t));
2068     ASSERT_EQ(r, 0);
2069   }
2070 }
2071
2072 TEST_P(StoreTest, SmallSequentialUnaligned) {
2073   ObjectStore::Sequencer osr("test");
2074   int r;
2075   coll_t cid;
2076   ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2077   {
2078     ObjectStore::Transaction t;
2079     t.create_collection(cid, 0);
2080     cerr << "Creating collection " << cid << std::endl;
2081     r = apply_transaction(store, &osr, std::move(t));
2082     ASSERT_EQ(r, 0);
2083   }
2084   bufferlist bl;
2085   int len = 1000;
2086   bufferptr bp(len);
2087   bp.zero();
2088   bl.append(bp);
2089   for (int i=0; i<1000; ++i) {
2090     ObjectStore::Transaction t;
2091     t.write(cid, a, i*len, len, bl, 0);
2092     r = apply_transaction(store, &osr, std::move(t));
2093     ASSERT_EQ(r, 0);
2094   }
2095   {
2096     ObjectStore::Transaction t;
2097     t.remove(cid, a);
2098     t.remove_collection(cid);
2099     cerr << "Cleaning" << std::endl;
2100     r = apply_transaction(store, &osr, std::move(t));
2101     ASSERT_EQ(r, 0);
2102   }
2103 }
2104
2105 TEST_P(StoreTest, ManyBigWrite) {
2106   ObjectStore::Sequencer osr("test");
2107   int r;
2108   coll_t cid;
2109   ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2110   ghobject_t b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
2111   {
2112     ObjectStore::Transaction t;
2113     t.create_collection(cid, 0);
2114     cerr << "Creating collection " << cid << std::endl;
2115     r = apply_transaction(store, &osr, std::move(t));
2116     ASSERT_EQ(r, 0);
2117   }
2118   bufferlist bl;
2119   bufferptr bp(4 * 1048576);
2120   bp.zero();
2121   bl.append(bp);
2122   for (int i=0; i<10; ++i) {
2123     ObjectStore::Transaction t;
2124     t.write(cid, a, i*4*1048586, 4*1048576, bl, 0);
2125     r = apply_transaction(store, &osr, std::move(t));
2126     ASSERT_EQ(r, 0);
2127   }
2128   // aligned
2129   for (int i=0; i<10; ++i) {
2130     ObjectStore::Transaction t;
2131     t.write(cid, b, (rand() % 256)*4*1048576, 4*1048576, bl, 0);
2132     r = apply_transaction(store, &osr, std::move(t));
2133     ASSERT_EQ(r, 0);
2134   }
2135   // unaligned
2136   for (int i=0; i<10; ++i) {
2137     ObjectStore::Transaction t;
2138     t.write(cid, b, (rand() % (256*4096))*1024, 4*1048576, bl, 0);
2139     r = apply_transaction(store, &osr, std::move(t));
2140     ASSERT_EQ(r, 0);
2141   }
2142   // do some zeros
2143   for (int i=0; i<10; ++i) {
2144     ObjectStore::Transaction t;
2145     t.zero(cid, b, (rand() % (256*4096))*1024, 16*1048576);
2146     r = apply_transaction(store, &osr, std::move(t));
2147     ASSERT_EQ(r, 0);
2148   }
2149   {
2150     ObjectStore::Transaction t;
2151     t.remove(cid, a);
2152     t.remove(cid, b);
2153     t.remove_collection(cid);
2154     cerr << "Cleaning" << std::endl;
2155     r = apply_transaction(store, &osr, std::move(t));
2156     ASSERT_EQ(r, 0);
2157   }
2158 }
2159
2160 TEST_P(StoreTest, BigWriteBigZero) {
2161   ObjectStore::Sequencer osr("test");
2162   int r;
2163   coll_t cid;
2164   ghobject_t a(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2165   {
2166     ObjectStore::Transaction t;
2167     t.create_collection(cid, 0);
2168     r = apply_transaction(store, &osr, std::move(t));
2169     ASSERT_EQ(r, 0);
2170   }
2171   bufferlist bl;
2172   bufferptr bp(1048576);
2173   memset(bp.c_str(), 'b', bp.length());
2174   bl.append(bp);
2175   bufferlist s;
2176   bufferptr sp(4096);
2177   memset(sp.c_str(), 's', sp.length());
2178   s.append(sp);
2179   {
2180     ObjectStore::Transaction t;
2181     t.write(cid, a, 0, bl.length(), bl);
2182     r = apply_transaction(store, &osr, std::move(t));
2183     ASSERT_EQ(r, 0);
2184   }
2185   {
2186     ObjectStore::Transaction t;
2187     t.zero(cid, a, bl.length() / 4, bl.length() / 2);
2188     r = apply_transaction(store, &osr, std::move(t));
2189     ASSERT_EQ(r, 0);
2190   }
2191   {
2192     ObjectStore::Transaction t;
2193     t.write(cid, a, bl.length() / 2, s.length(), s);
2194     r = apply_transaction(store, &osr, std::move(t));
2195     ASSERT_EQ(r, 0);
2196   }
2197   {
2198     ObjectStore::Transaction t;
2199     t.remove(cid, a);
2200     t.remove_collection(cid);
2201     r = apply_transaction(store, &osr, std::move(t));
2202     ASSERT_EQ(r, 0);
2203   }
2204 }
2205
2206 TEST_P(StoreTest, MiscFragmentTests) {
2207   ObjectStore::Sequencer osr("test");
2208   int r;
2209   coll_t cid;
2210   ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2211   {
2212     ObjectStore::Transaction t;
2213     t.create_collection(cid, 0);
2214     cerr << "Creating collection " << cid << std::endl;
2215     r = apply_transaction(store, &osr, std::move(t));
2216     ASSERT_EQ(r, 0);
2217   }
2218   bufferlist bl;
2219   bufferptr bp(524288);
2220   bp.zero();
2221   bl.append(bp);
2222   {
2223     ObjectStore::Transaction t;
2224     t.write(cid, a, 0, 524288, bl, 0);
2225     r = apply_transaction(store, &osr, std::move(t));
2226     ASSERT_EQ(r, 0);
2227   }
2228   {
2229     ObjectStore::Transaction t;
2230     t.write(cid, a, 1048576, 524288, bl, 0);
2231     r = apply_transaction(store, &osr, std::move(t));
2232     ASSERT_EQ(r, 0);
2233   }
2234   {
2235     bufferlist inbl;
2236     int r = store->read(cid, a, 524288 + 131072, 1024, inbl);
2237     ASSERT_EQ(r, 1024);
2238     ASSERT_EQ(inbl.length(), 1024u);
2239     ASSERT_TRUE(inbl.is_zero());
2240   }
2241   {
2242     ObjectStore::Transaction t;
2243     t.write(cid, a, 1048576 - 4096, 524288, bl, 0);
2244     r = apply_transaction(store, &osr, std::move(t));
2245     ASSERT_EQ(r, 0);
2246   }
2247   {
2248     ObjectStore::Transaction t;
2249     t.remove(cid, a);
2250     t.remove_collection(cid);
2251     cerr << "Cleaning" << std::endl;
2252     r = apply_transaction(store, &osr, std::move(t));
2253     ASSERT_EQ(r, 0);
2254   }
2255
2256 }
2257
2258 TEST_P(StoreTest, ZeroLengthWrite) {
2259   ObjectStore::Sequencer osr("test");
2260   int r;
2261   coll_t cid;
2262   ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2263   {
2264     ObjectStore::Transaction t;
2265     t.create_collection(cid, 0);
2266     t.touch(cid, hoid);
2267     r = apply_transaction(store, &osr, std::move(t));
2268     ASSERT_EQ(r, 0);
2269   }
2270   {
2271     ObjectStore::Transaction t;
2272     bufferlist empty;
2273     t.write(cid, hoid, 1048576, 0, empty);
2274     r = apply_transaction(store, &osr, std::move(t));
2275     ASSERT_EQ(r, 0);
2276   }
2277   struct stat stat;
2278   r = store->stat(cid, hoid, &stat);
2279   ASSERT_EQ(0, r);
2280   ASSERT_EQ(0, stat.st_size);
2281
2282   bufferlist newdata;
2283   r = store->read(cid, hoid, 0, 1048576, newdata);
2284   ASSERT_EQ(0, r);
2285 }
2286
2287 TEST_P(StoreTest, SimpleAttrTest) {
2288   ObjectStore::Sequencer osr("test");
2289   int r;
2290   coll_t cid;
2291   ghobject_t hoid(hobject_t(sobject_t("attr object 1", CEPH_NOSNAP)));
2292   bufferlist val, val2;
2293   val.append("value");
2294   val.append("value2");
2295   {
2296     bufferptr bp;
2297     map<string,bufferptr> aset;
2298     r = store->getattr(cid, hoid, "nofoo", bp);
2299     ASSERT_EQ(-ENOENT, r);
2300     r = store->getattrs(cid, hoid, aset);
2301     ASSERT_EQ(-ENOENT, r);
2302   }
2303   {
2304     ObjectStore::Transaction t;
2305     t.create_collection(cid, 0);
2306     r = apply_transaction(store, &osr, std::move(t));
2307     ASSERT_EQ(r, 0);
2308   }
2309   {
2310     bool empty;
2311     int r = store->collection_empty(cid, &empty);
2312     ASSERT_EQ(0, r);
2313     ASSERT_TRUE(empty);
2314   }
2315   {
2316     bufferptr bp;
2317     r = store->getattr(cid, hoid, "nofoo", bp);
2318     ASSERT_EQ(-ENOENT, r);
2319   }
2320   {
2321     ObjectStore::Transaction t;
2322     t.touch(cid, hoid);
2323     t.setattr(cid, hoid, "foo", val);
2324     t.setattr(cid, hoid, "bar", val2);
2325     r = apply_transaction(store, &osr, std::move(t));
2326     ASSERT_EQ(r, 0);
2327   }
2328   {
2329     bool empty;
2330     int r = store->collection_empty(cid, &empty);
2331     ASSERT_EQ(0, r);
2332     ASSERT_TRUE(!empty);
2333   }
2334   {
2335     bufferptr bp;
2336     r = store->getattr(cid, hoid, "nofoo", bp);
2337     ASSERT_EQ(-ENODATA, r);
2338
2339     r = store->getattr(cid, hoid, "foo", bp);
2340     ASSERT_EQ(0, r);
2341     bufferlist bl;
2342     bl.append(bp);
2343     ASSERT_TRUE(bl_eq(val, bl));
2344
2345     map<string,bufferptr> bm;
2346     r = store->getattrs(cid, hoid, bm);
2347     ASSERT_EQ(0, r);
2348
2349   }
2350   {
2351     ObjectStore::Transaction t;
2352     t.remove(cid, hoid);
2353     t.remove_collection(cid);
2354     r = apply_transaction(store, &osr, std::move(t));
2355     ASSERT_EQ(r, 0);
2356   }
2357 }
2358
2359 TEST_P(StoreTest, SimpleListTest) {
2360   ObjectStore::Sequencer osr("test");
2361   int r;
2362   coll_t cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2363   {
2364     ObjectStore::Transaction t;
2365     t.create_collection(cid, 0);
2366     cerr << "Creating collection " << cid << std::endl;
2367     r = apply_transaction(store, &osr, std::move(t));
2368     ASSERT_EQ(r, 0);
2369   }
2370   set<ghobject_t> all;
2371   {
2372     ObjectStore::Transaction t;
2373     for (int i=0; i<200; ++i) {
2374       string name("object_");
2375       name += stringify(i);
2376       ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)),
2377                       ghobject_t::NO_GEN, shard_id_t(1));
2378       hoid.hobj.pool = 1;
2379       all.insert(hoid);
2380       t.touch(cid, hoid);
2381       cerr << "Creating object " << hoid << std::endl;
2382     }
2383     r = apply_transaction(store, &osr, std::move(t));
2384     ASSERT_EQ(r, 0);
2385   }
2386   {
2387     set<ghobject_t> saw;
2388     vector<ghobject_t> objects;
2389     ghobject_t next, current;
2390     while (!next.is_max()) {
2391       int r = store->collection_list(cid, current, ghobject_t::get_max(),
2392                                      50,
2393                                      &objects, &next);
2394       ASSERT_EQ(r, 0);
2395       ASSERT_TRUE(sorted(objects));
2396       cout << " got " << objects.size() << " next " << next << std::endl;
2397       for (vector<ghobject_t>::iterator p = objects.begin(); p != objects.end();
2398            ++p) {
2399         if (saw.count(*p)) {
2400           cout << "got DUP " << *p << std::endl;
2401         } else {
2402           //cout << "got new " << *p << std::endl;
2403         }
2404         saw.insert(*p);
2405       }
2406       objects.clear();
2407       current = next;
2408     }
2409     ASSERT_EQ(saw.size(), all.size());
2410     ASSERT_EQ(saw, all);
2411   }
2412   {
2413     ObjectStore::Transaction t;
2414     for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
2415       t.remove(cid, *p);
2416     t.remove_collection(cid);
2417     cerr << "Cleaning" << std::endl;
2418     r = apply_transaction(store, &osr, std::move(t));
2419     ASSERT_EQ(r, 0);
2420   }
2421 }
2422
2423 TEST_P(StoreTest, ListEndTest) {
2424   ObjectStore::Sequencer osr("test");
2425   int r;
2426   coll_t cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2427   {
2428     ObjectStore::Transaction t;
2429     t.create_collection(cid, 0);
2430     cerr << "Creating collection " << cid << std::endl;
2431     r = apply_transaction(store, &osr, std::move(t));
2432     ASSERT_EQ(r, 0);
2433   }
2434   set<ghobject_t> all;
2435   {
2436     ObjectStore::Transaction t;
2437     for (int i=0; i<200; ++i) {
2438       string name("object_");
2439       name += stringify(i);
2440       ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)),
2441                       ghobject_t::NO_GEN, shard_id_t(1));
2442       hoid.hobj.pool = 1;
2443       all.insert(hoid);
2444       t.touch(cid, hoid);
2445       cerr << "Creating object " << hoid << std::endl;
2446     }
2447     r = apply_transaction(store, &osr, std::move(t));
2448     ASSERT_EQ(r, 0);
2449   }
2450   {
2451     ghobject_t end(hobject_t(sobject_t("object_100", CEPH_NOSNAP)),
2452                    ghobject_t::NO_GEN, shard_id_t(1));
2453     end.hobj.pool = 1;
2454     vector<ghobject_t> objects;
2455     ghobject_t next;
2456     int r = store->collection_list(cid, ghobject_t(), end, 500,
2457                                    &objects, &next);
2458     ASSERT_EQ(r, 0);
2459     for (auto &p : objects) {
2460       ASSERT_NE(p, end);
2461     }
2462   }
2463   {
2464     ObjectStore::Transaction t;
2465     for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
2466       t.remove(cid, *p);
2467     t.remove_collection(cid);
2468     cerr << "Cleaning" << std::endl;
2469     r = apply_transaction(store, &osr, std::move(t));
2470     ASSERT_EQ(r, 0);
2471   }
2472 }
2473
2474 TEST_P(StoreTest, Sort) {
2475   {
2476     hobject_t a(sobject_t("a", CEPH_NOSNAP));
2477     hobject_t b = a;
2478     ASSERT_EQ(a, b);
2479     b.oid.name = "b";
2480     ASSERT_NE(a, b);
2481     ASSERT_TRUE(a < b);
2482     a.pool = 1;
2483     b.pool = 2;
2484     ASSERT_TRUE(a < b);
2485     a.pool = 3;
2486     ASSERT_TRUE(a > b);
2487   }
2488   {
2489     ghobject_t a(hobject_t(sobject_t("a", CEPH_NOSNAP)));
2490     ghobject_t b(hobject_t(sobject_t("b", CEPH_NOSNAP)));
2491     a.hobj.pool = 1;
2492     b.hobj.pool = 1;
2493     ASSERT_TRUE(a < b);
2494     a.hobj.pool = -3;
2495     ASSERT_TRUE(a < b);
2496     a.hobj.pool = 1;
2497     b.hobj.pool = -3;
2498     ASSERT_TRUE(a > b);
2499   }
2500 }
2501
2502 TEST_P(StoreTest, MultipoolListTest) {
2503   ObjectStore::Sequencer osr("test");
2504   int r;
2505   int poolid = 4373;
2506   coll_t cid = coll_t(spg_t(pg_t(0, poolid), shard_id_t::NO_SHARD));
2507   {
2508     ObjectStore::Transaction t;
2509     t.create_collection(cid, 0);
2510     cerr << "Creating collection " << cid << std::endl;
2511     r = apply_transaction(store, &osr, std::move(t));
2512     ASSERT_EQ(r, 0);
2513   }
2514   set<ghobject_t> all, saw;
2515   {
2516     ObjectStore::Transaction t;
2517     for (int i=0; i<200; ++i) {
2518       string name("object_");
2519       name += stringify(i);
2520       ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)));
2521       if (rand() & 1)
2522         hoid.hobj.pool = -2 - poolid;
2523       else
2524         hoid.hobj.pool = poolid;
2525       all.insert(hoid);
2526       t.touch(cid, hoid);
2527       cerr << "Creating object " << hoid << std::endl;
2528     }
2529     r = apply_transaction(store, &osr, std::move(t));
2530     ASSERT_EQ(r, 0);
2531   }
2532   {
2533     vector<ghobject_t> objects;
2534     ghobject_t next, current;
2535     while (!next.is_max()) {
2536       int r = store->collection_list(cid, current, ghobject_t::get_max(), 50,
2537                                      &objects, &next);
2538       ASSERT_EQ(r, 0);
2539       cout << " got " << objects.size() << " next " << next << std::endl;
2540       for (vector<ghobject_t>::iterator p = objects.begin(); p != objects.end();
2541            ++p) {
2542         saw.insert(*p);
2543       }
2544       objects.clear();
2545       current = next;
2546     }
2547     ASSERT_EQ(saw, all);
2548   }
2549   {
2550     ObjectStore::Transaction t;
2551     for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
2552       t.remove(cid, *p);
2553     t.remove_collection(cid);
2554     cerr << "Cleaning" << std::endl;
2555     r = apply_transaction(store, &osr, std::move(t));
2556     ASSERT_EQ(r, 0);
2557   }
2558 }
2559
2560 TEST_P(StoreTest, SimpleCloneTest) {
2561   ObjectStore::Sequencer osr("test");
2562   int r;
2563   coll_t cid;
2564   {
2565     ObjectStore::Transaction t;
2566     t.create_collection(cid, 0);
2567     cerr << "Creating collection " << cid << std::endl;
2568     r = apply_transaction(store, &osr, std::move(t));
2569     ASSERT_EQ(r, 0);
2570   }
2571   ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP),
2572                             "key", 123, -1, ""));
2573   bufferlist small, large, xlarge, newdata, attr;
2574   small.append("small");
2575   large.append("large");
2576   xlarge.append("xlarge");
2577   {
2578     ObjectStore::Transaction t;
2579     t.touch(cid, hoid);
2580     t.setattr(cid, hoid, "attr1", small);
2581     t.setattr(cid, hoid, "attr2", large);
2582     t.setattr(cid, hoid, "attr3", xlarge);
2583     t.write(cid, hoid, 0, small.length(), small);
2584     t.write(cid, hoid, 10, small.length(), small);
2585     cerr << "Creating object and set attr " << hoid << std::endl;
2586     r = apply_transaction(store, &osr, std::move(t));
2587     ASSERT_EQ(r, 0);
2588   }
2589
2590   ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP),
2591                              "key", 123, -1, ""));
2592   ghobject_t hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP)));
2593   {
2594     ObjectStore::Transaction t;
2595     t.clone(cid, hoid, hoid2);
2596     t.setattr(cid, hoid2, "attr2", small);
2597     t.rmattr(cid, hoid2, "attr1");
2598     t.write(cid, hoid, 10, large.length(), large);
2599     t.setattr(cid, hoid, "attr1", large);
2600     t.setattr(cid, hoid, "attr2", small);
2601     cerr << "Clone object and rm attr" << std::endl;
2602     r = apply_transaction(store, &osr, std::move(t));
2603     ASSERT_EQ(r, 0);
2604
2605     r = store->read(cid, hoid, 10, 5, newdata);
2606     ASSERT_EQ(r, 5);
2607     ASSERT_TRUE(bl_eq(large, newdata));
2608
2609     newdata.clear();
2610     r = store->read(cid, hoid, 0, 5, newdata);
2611     ASSERT_EQ(r, 5);
2612     ASSERT_TRUE(bl_eq(small, newdata));
2613
2614     newdata.clear();
2615     r = store->read(cid, hoid2, 10, 5, newdata);
2616     ASSERT_EQ(r, 5);
2617     ASSERT_TRUE(bl_eq(small, newdata));
2618
2619     r = store->getattr(cid, hoid2, "attr2", attr);
2620     ASSERT_EQ(r, 0);
2621     ASSERT_TRUE(bl_eq(small, attr));
2622
2623     attr.clear();
2624     r = store->getattr(cid, hoid2, "attr3", attr);
2625     ASSERT_EQ(r, 0);
2626     ASSERT_TRUE(bl_eq(xlarge, attr));
2627
2628     attr.clear();
2629     r = store->getattr(cid, hoid, "attr1", attr);
2630     ASSERT_EQ(r, 0);
2631     ASSERT_TRUE(bl_eq(large, attr));
2632   }
2633   {
2634     ObjectStore::Transaction t;
2635     t.remove(cid, hoid);
2636     t.remove(cid, hoid2);
2637     ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2638   }
2639   {
2640     bufferlist final;
2641     bufferptr p(16384);
2642     memset(p.c_str(), 1, p.length());
2643     bufferlist pl;
2644     pl.append(p);
2645     final.append(p);
2646     ObjectStore::Transaction t;
2647     t.write(cid, hoid, 0, pl.length(), pl);
2648     t.clone(cid, hoid, hoid2);
2649     bufferptr a(4096);
2650     memset(a.c_str(), 2, a.length());
2651     bufferlist al;
2652     al.append(a);
2653     final.append(a);
2654     t.write(cid, hoid, pl.length(), a.length(), al);
2655     r = apply_transaction(store, &osr, std::move(t));
2656     ASSERT_EQ(r, 0);
2657     bufferlist rl;
2658     ASSERT_EQ((int)final.length(),
2659               store->read(cid, hoid, 0, final.length(), rl));
2660     ASSERT_TRUE(bl_eq(rl, final));
2661   }
2662   {
2663     ObjectStore::Transaction t;
2664     t.remove(cid, hoid);
2665     t.remove(cid, hoid2);
2666     ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2667   }
2668   {
2669     bufferlist final;
2670     bufferptr p(16384);
2671     memset(p.c_str(), 111, p.length());
2672     bufferlist pl;
2673     pl.append(p);
2674     final.append(p);
2675     ObjectStore::Transaction t;
2676     t.write(cid, hoid, 0, pl.length(), pl);
2677     t.clone(cid, hoid, hoid2);
2678     bufferptr z(4096);
2679     z.zero();
2680     final.append(z);
2681     bufferptr a(4096);
2682     memset(a.c_str(), 112, a.length());
2683     bufferlist al;
2684     al.append(a);
2685     final.append(a);
2686     t.write(cid, hoid, pl.length() + z.length(), a.length(), al);
2687     r = apply_transaction(store, &osr, std::move(t));
2688     ASSERT_EQ(r, 0);
2689     bufferlist rl;
2690     ASSERT_EQ((int)final.length(),
2691               store->read(cid, hoid, 0, final.length(), rl));
2692     ASSERT_TRUE(bl_eq(rl, final));
2693   }
2694   {
2695     ObjectStore::Transaction t;
2696     t.remove(cid, hoid);
2697     t.remove(cid, hoid2);
2698     ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2699   }
2700   {
2701     bufferlist final;
2702     bufferptr p(16000);
2703     memset(p.c_str(), 5, p.length());
2704     bufferlist pl;
2705     pl.append(p);
2706     final.append(p);
2707     ObjectStore::Transaction t;
2708     t.write(cid, hoid, 0, pl.length(), pl);
2709     t.clone(cid, hoid, hoid2);
2710     bufferptr z(1000);
2711     z.zero();
2712     final.append(z);
2713     bufferptr a(8000);
2714     memset(a.c_str(), 6, a.length());
2715     bufferlist al;
2716     al.append(a);
2717     final.append(a);
2718     t.write(cid, hoid, 17000, a.length(), al);
2719     ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2720     bufferlist rl;
2721     ASSERT_EQ((int)final.length(),
2722               store->read(cid, hoid, 0, final.length(), rl));
2723     /*cout << "expected:\n";
2724     final.hexdump(cout);
2725     cout << "got:\n";
2726     rl.hexdump(cout);*/
2727     ASSERT_TRUE(bl_eq(rl, final));
2728   }
2729   {
2730     ObjectStore::Transaction t;
2731     t.remove(cid, hoid);
2732     t.remove(cid, hoid2);
2733     ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2734   }
2735   {
2736     bufferptr p(1048576);
2737     memset(p.c_str(), 3, p.length());
2738     bufferlist pl;
2739     pl.append(p);
2740     ObjectStore::Transaction t;
2741     t.write(cid, hoid, 0, pl.length(), pl);
2742     t.clone(cid, hoid, hoid2);
2743     bufferptr a(65536);
2744     memset(a.c_str(), 4, a.length());
2745     bufferlist al;
2746     al.append(a);
2747     t.write(cid, hoid, a.length(), a.length(), al);
2748     ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2749     bufferlist rl;
2750     bufferlist final;
2751     final.substr_of(pl, 0, al.length());
2752     final.append(al);
2753     bufferlist end;
2754     end.substr_of(pl, al.length()*2, pl.length() - al.length()*2);
2755     final.append(end);
2756     ASSERT_EQ((int)final.length(),
2757               store->read(cid, hoid, 0, final.length(), rl));
2758     /*cout << "expected:\n";
2759     final.hexdump(cout);
2760     cout << "got:\n";
2761     rl.hexdump(cout);*/
2762     ASSERT_TRUE(bl_eq(rl, final));
2763   }
2764   {
2765     ObjectStore::Transaction t;
2766     t.remove(cid, hoid);
2767     t.remove(cid, hoid2);
2768     ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2769   }
2770   {
2771     bufferptr p(65536);
2772     memset(p.c_str(), 7, p.length());
2773     bufferlist pl;
2774     pl.append(p);
2775     ObjectStore::Transaction t;
2776     t.write(cid, hoid, 0, pl.length(), pl);
2777     t.clone(cid, hoid, hoid2);
2778     bufferptr a(4096);
2779     memset(a.c_str(), 8, a.length());
2780     bufferlist al;
2781     al.append(a);
2782     t.write(cid, hoid, 32768, a.length(), al);
2783     ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2784     bufferlist rl;
2785     bufferlist final;
2786     final.substr_of(pl, 0, 32768);
2787     final.append(al);
2788     bufferlist end;
2789     end.substr_of(pl, final.length(), pl.length() - final.length());
2790     final.append(end);
2791     ASSERT_EQ((int)final.length(),
2792               store->read(cid, hoid, 0, final.length(), rl));
2793     /*cout << "expected:\n";
2794     final.hexdump(cout);
2795     cout << "got:\n";
2796     rl.hexdump(cout);*/
2797     ASSERT_TRUE(bl_eq(rl, final));
2798   }
2799   {
2800     ObjectStore::Transaction t;
2801     t.remove(cid, hoid);
2802     t.remove(cid, hoid2);
2803     ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2804   }
2805   {
2806     bufferptr p(65536);
2807     memset(p.c_str(), 9, p.length());
2808     bufferlist pl;
2809     pl.append(p);
2810     ObjectStore::Transaction t;
2811     t.write(cid, hoid, 0, pl.length(), pl);
2812     t.clone(cid, hoid, hoid2);
2813     bufferptr a(4096);
2814     memset(a.c_str(), 10, a.length());
2815     bufferlist al;
2816     al.append(a);
2817     t.write(cid, hoid, 33768, a.length(), al);
2818     ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2819     bufferlist rl;
2820     bufferlist final;
2821     final.substr_of(pl, 0, 33768);
2822     final.append(al);
2823     bufferlist end;
2824     end.substr_of(pl, final.length(), pl.length() - final.length());
2825     final.append(end);
2826     ASSERT_EQ((int)final.length(),
2827               store->read(cid, hoid, 0, final.length(), rl));
2828     /*cout << "expected:\n";
2829     final.hexdump(cout);
2830     cout << "got:\n";
2831     rl.hexdump(cout);*/
2832     ASSERT_TRUE(bl_eq(rl, final));
2833   }
2834
2835   //Unfortunately we need a workaround for filestore since EXPECT_DEATH
2836   // macro has potential issues when using /in multithread environments. 
2837   //It works well for all stores but filestore for now. 
2838   //A fix setting gtest_death_test_style = "threadsafe" doesn't help as well - 
2839   //  test app clone asserts on store folder presence.
2840   //
2841   if (string(GetParam()) != "filestore") { 
2842     //verify if non-empty collection is properly handled after store reload
2843     r = store->umount();
2844     ASSERT_EQ(r, 0);
2845     r = store->mount();
2846     ASSERT_EQ(r, 0);
2847
2848     ObjectStore::Transaction t;
2849     t.remove_collection(cid);
2850     cerr << "Invalid rm coll" << std::endl;
2851     PrCtl unset_dumpable;
2852     EXPECT_DEATH(apply_transaction(store, &osr, std::move(t)), "");
2853   }
2854   {
2855     ObjectStore::Transaction t;
2856     t.touch(cid, hoid3); //new record in db
2857     r = apply_transaction(store, &osr, std::move(t));
2858     ASSERT_EQ(r, 0);
2859   }
2860   //See comment above for "filestore" check explanation.
2861   if (string(GetParam()) != "filestore") {
2862     ObjectStore::Transaction t;
2863     //verify if non-empty collection is properly handled when there are some pending removes and live records in db
2864     cerr << "Invalid rm coll again" << std::endl;
2865     r = store->umount();
2866     ASSERT_EQ(r, 0);
2867     r = store->mount();
2868     ASSERT_EQ(r, 0);
2869
2870     t.remove(cid, hoid);
2871     t.remove(cid, hoid2);
2872     t.remove_collection(cid);
2873     PrCtl unset_dumpable;
2874     EXPECT_DEATH(apply_transaction(store, &osr, std::move(t)), "");
2875   }
2876   {
2877     ObjectStore::Transaction t;
2878     t.remove(cid, hoid);
2879     t.remove(cid, hoid2);
2880     t.remove(cid, hoid3);
2881     t.remove_collection(cid);
2882     cerr << "Cleaning" << std::endl;
2883     r = apply_transaction(store, &osr, std::move(t));
2884     ASSERT_EQ(r, 0);
2885   }
2886 }
2887
2888 TEST_P(StoreTest, OmapSimple) {
2889   ObjectStore::Sequencer osr("test");
2890   int r;
2891   coll_t cid;
2892   {
2893     ObjectStore::Transaction t;
2894     t.create_collection(cid, 0);
2895     cerr << "Creating collection " << cid << std::endl;
2896     r = apply_transaction(store, &osr, std::move(t));
2897     ASSERT_EQ(r, 0);
2898   }
2899   ghobject_t hoid(hobject_t(sobject_t("omap_obj", CEPH_NOSNAP),
2900                             "key", 123, -1, ""));
2901   bufferlist small;
2902   small.append("small");
2903   map<string,bufferlist> km;
2904   km["foo"] = small;
2905   km["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
2906   bufferlist header;
2907   header.append("this is a header");
2908   {
2909     ObjectStore::Transaction t;
2910     t.touch(cid, hoid);
2911     t.omap_setkeys(cid, hoid, km);
2912     t.omap_setheader(cid, hoid, header);
2913     cerr << "Creating object and set omap " << hoid << std::endl;
2914     r = apply_transaction(store, &osr, std::move(t));
2915     ASSERT_EQ(r, 0);
2916   }
2917   // get header, keys
2918   {
2919     bufferlist h;
2920     map<string,bufferlist> r;
2921     store->omap_get(cid, hoid, &h, &r);
2922     ASSERT_TRUE(bl_eq(header, h));
2923     ASSERT_EQ(r.size(), km.size());
2924     cout << "r: " << r << std::endl;
2925   }
2926   // test iterator with seek_to_first
2927   {
2928     map<string,bufferlist> r;
2929     ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(cid, hoid);
2930     for (iter->seek_to_first(); iter->valid(); iter->next(false)) {
2931       r[iter->key()] = iter->value();
2932     }
2933     cout << "r: " << r << std::endl;
2934     ASSERT_EQ(r.size(), km.size());
2935   }
2936   // test iterator with initial lower_bound
2937   {
2938     map<string,bufferlist> r;
2939     ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(cid, hoid);
2940     for (iter->lower_bound(string()); iter->valid(); iter->next(false)) {
2941       r[iter->key()] = iter->value();
2942     }
2943     cout << "r: " << r << std::endl;
2944     ASSERT_EQ(r.size(), km.size());
2945   }
2946   {
2947     ObjectStore::Transaction t;
2948     t.remove(cid, hoid);
2949     t.remove_collection(cid);
2950     cerr << "Cleaning" << std::endl;
2951     r = apply_transaction(store, &osr, std::move(t));
2952     ASSERT_EQ(r, 0);
2953   }
2954 }
2955
2956 TEST_P(StoreTest, OmapCloneTest) {
2957   ObjectStore::Sequencer osr("test");
2958   int r;
2959   coll_t cid;
2960   {
2961     ObjectStore::Transaction t;
2962     t.create_collection(cid, 0);
2963     cerr << "Creating collection " << cid << std::endl;
2964     r = apply_transaction(store, &osr, std::move(t));
2965     ASSERT_EQ(r, 0);
2966   }
2967   ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP),
2968                             "key", 123, -1, ""));
2969   bufferlist small;
2970   small.append("small");
2971   map<string,bufferlist> km;
2972   km["foo"] = small;
2973   km["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
2974   bufferlist header;
2975   header.append("this is a header");
2976   {
2977     ObjectStore::Transaction t;
2978     t.touch(cid, hoid);
2979     t.omap_setkeys(cid, hoid, km);
2980     t.omap_setheader(cid, hoid, header);
2981     cerr << "Creating object and set omap " << hoid << std::endl;
2982     r = apply_transaction(store, &osr, std::move(t));
2983     ASSERT_EQ(r, 0);
2984   }
2985   ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP),
2986                              "key", 123, -1, ""));
2987   {
2988     ObjectStore::Transaction t;
2989     t.clone(cid, hoid, hoid2);
2990     cerr << "Clone object" << std::endl;
2991     r = apply_transaction(store, &osr, std::move(t));
2992     ASSERT_EQ(r, 0);
2993   }
2994   {
2995     map<string,bufferlist> r;
2996     bufferlist h;
2997     store->omap_get(cid, hoid2, &h, &r);
2998     ASSERT_TRUE(bl_eq(header, h));
2999     ASSERT_EQ(r.size(), km.size());
3000   }
3001   {
3002     ObjectStore::Transaction t;
3003     t.remove(cid, hoid);
3004     t.remove(cid, hoid2);
3005     t.remove_collection(cid);
3006     cerr << "Cleaning" << std::endl;
3007     r = apply_transaction(store, &osr, std::move(t));
3008     ASSERT_EQ(r, 0);
3009   }
3010 }
3011
3012 TEST_P(StoreTest, SimpleCloneRangeTest) {
3013   ObjectStore::Sequencer osr("test");
3014   int r;
3015   coll_t cid;
3016   {
3017     ObjectStore::Transaction t;
3018     t.create_collection(cid, 0);
3019     cerr << "Creating collection " << cid << std::endl;
3020     r = apply_transaction(store, &osr, std::move(t));
3021     ASSERT_EQ(r, 0);
3022   }
3023   ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
3024   hoid.hobj.pool = -1;
3025   bufferlist small, newdata;
3026   small.append("small");
3027   {
3028     ObjectStore::Transaction t;
3029     t.write(cid, hoid, 10, 5, small);
3030     cerr << "Creating object and write bl " << hoid << std::endl;
3031     r = apply_transaction(store, &osr, std::move(t));
3032     ASSERT_EQ(r, 0);
3033   }
3034   ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
3035   hoid2.hobj.pool = -1;
3036   {
3037     ObjectStore::Transaction t;
3038     t.clone_range(cid, hoid, hoid2, 10, 5, 10);
3039     cerr << "Clone range object" << std::endl;
3040     r = apply_transaction(store, &osr, std::move(t));
3041     ASSERT_EQ(r, 0);
3042     r = store->read(cid, hoid2, 10, 5, newdata);
3043     ASSERT_EQ(r, 5);
3044     ASSERT_TRUE(bl_eq(small, newdata));
3045   }
3046   {
3047     ObjectStore::Transaction t;
3048     t.truncate(cid, hoid, 1024*1024);
3049     t.clone_range(cid, hoid, hoid2, 0, 1024*1024, 0);
3050     cerr << "Clone range object" << std::endl;
3051     r = apply_transaction(store, &osr, std::move(t));
3052     ASSERT_EQ(r, 0);
3053     struct stat stat, stat2;
3054     r = store->stat(cid, hoid, &stat);
3055     r = store->stat(cid, hoid2, &stat2);
3056     ASSERT_EQ(stat.st_size, stat2.st_size);
3057     ASSERT_EQ(1024*1024, stat2.st_size);
3058   }
3059   {
3060     ObjectStore::Transaction t;
3061     t.remove(cid, hoid);
3062     t.remove(cid, hoid2);
3063     t.remove_collection(cid);
3064     cerr << "Cleaning" << std::endl;
3065     r = apply_transaction(store, &osr, std::move(t));
3066     ASSERT_EQ(r, 0);
3067   }
3068 }
3069
3070
3071 TEST_P(StoreTest, SimpleObjectLongnameTest) {
3072   ObjectStore::Sequencer osr("test");
3073   int r;
3074   coll_t cid;
3075   {
3076     ObjectStore::Transaction t;
3077     t.create_collection(cid, 0);
3078     cerr << "Creating collection " << cid << std::endl;
3079     r = apply_transaction(store, &osr, std::move(t));
3080     ASSERT_EQ(r, 0);
3081   }
3082   ghobject_t hoid(hobject_t(sobject_t("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaObjectaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1", CEPH_NOSNAP)));
3083   {
3084     ObjectStore::Transaction t;
3085     t.touch(cid, hoid);
3086     cerr << "Creating object " << hoid << std::endl;
3087     r = apply_transaction(store, &osr, std::move(t));
3088     ASSERT_EQ(r, 0);
3089   }
3090   {
3091     ObjectStore::Transaction t;
3092     t.remove(cid, hoid);
3093     t.remove_collection(cid);
3094     cerr << "Cleaning" << std::endl;
3095     r = apply_transaction(store, &osr, std::move(t));
3096     ASSERT_EQ(r, 0);
3097   }
3098 }
3099
3100 ghobject_t generate_long_name(unsigned i)
3101 {
3102   stringstream name;
3103   name << "object id " << i << " ";
3104   for (unsigned j = 0; j < 500; ++j) name << 'a';
3105   ghobject_t hoid(hobject_t(sobject_t(name.str(), CEPH_NOSNAP)));
3106   hoid.hobj.set_hash(i % 2);
3107   return hoid;
3108 }
3109
3110 TEST_P(StoreTest, LongnameSplitTest) {
3111   ObjectStore::Sequencer osr("test");
3112   int r;
3113   coll_t cid;
3114   {
3115     ObjectStore::Transaction t;
3116     t.create_collection(cid, 0);
3117     cerr << "Creating collection " << cid << std::endl;
3118     r = apply_transaction(store, &osr, std::move(t));
3119     ASSERT_EQ(0, r);
3120   }
3121   for (unsigned i = 0; i < 320; ++i) {
3122     ObjectStore::Transaction t;
3123     ghobject_t hoid = generate_long_name(i);
3124     t.touch(cid, hoid);
3125     cerr << "Creating object " << hoid << std::endl;
3126     r = apply_transaction(store, &osr, std::move(t));
3127     ASSERT_EQ(0, r);
3128   }
3129
3130   ghobject_t test_obj = generate_long_name(319);
3131   ghobject_t test_obj_2 = test_obj;
3132   test_obj_2.generation = 0;
3133   {
3134     ObjectStore::Transaction t;
3135     // should cause a split
3136     t.collection_move_rename(
3137       cid, test_obj,
3138       cid, test_obj_2);
3139     r = apply_transaction(store, &osr, std::move(t));
3140     ASSERT_EQ(0, r);
3141   }
3142
3143   for (unsigned i = 0; i < 319; ++i) {
3144     ObjectStore::Transaction t;
3145     ghobject_t hoid = generate_long_name(i);
3146     t.remove(cid, hoid);
3147     cerr << "Removing object " << hoid << std::endl;
3148     r = apply_transaction(store, &osr, std::move(t));
3149     ASSERT_EQ(0, r);
3150   }
3151   {
3152     ObjectStore::Transaction t;
3153     t.remove(cid, test_obj_2);
3154     t.remove_collection(cid);
3155     cerr << "Cleaning" << std::endl;
3156     r = apply_transaction(store, &osr, std::move(t));
3157     ASSERT_EQ(0, r);
3158   }
3159
3160 }
3161
3162 TEST_P(StoreTest, ManyObjectTest) {
3163   ObjectStore::Sequencer osr("test");
3164   int NUM_OBJS = 2000;
3165   int r = 0;
3166   coll_t cid;
3167   string base = "";
3168   for (int i = 0; i < 100; ++i) base.append("aaaaa");
3169   set<ghobject_t> created;
3170   {
3171     ObjectStore::Transaction t;
3172     t.create_collection(cid, 0);
3173     r = apply_transaction(store, &osr, std::move(t));
3174     ASSERT_EQ(r, 0);
3175   }
3176   for (int i = 0; i < NUM_OBJS; ++i) {
3177     if (!(i % 5)) {
3178       cerr << "Object " << i << std::endl;
3179     }
3180     ObjectStore::Transaction t;
3181     char buf[100];
3182     snprintf(buf, sizeof(buf), "%d", i);
3183     ghobject_t hoid(hobject_t(sobject_t(string(buf) + base, CEPH_NOSNAP)));
3184     t.touch(cid, hoid);
3185     created.insert(hoid);
3186     r = apply_transaction(store, &osr, std::move(t));
3187     ASSERT_EQ(r, 0);
3188   }
3189
3190   for (set<ghobject_t>::iterator i = created.begin();
3191        i != created.end();
3192        ++i) {
3193     struct stat buf;
3194     ASSERT_TRUE(!store->stat(cid, *i, &buf));
3195   }
3196
3197   set<ghobject_t> listed, listed2;
3198   vector<ghobject_t> objects;
3199   r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(), INT_MAX, &objects, 0);
3200   ASSERT_EQ(r, 0);
3201
3202   cerr << "objects.size() is " << objects.size() << std::endl;
3203   for (vector<ghobject_t> ::iterator i = objects.begin();
3204        i != objects.end();
3205        ++i) {
3206     listed.insert(*i);
3207     ASSERT_TRUE(created.count(*i));
3208   }
3209   ASSERT_TRUE(listed.size() == created.size());
3210
3211   ghobject_t start, next;
3212   objects.clear();
3213   r = store->collection_list(
3214     cid,
3215     ghobject_t::get_max(),
3216     ghobject_t::get_max(),
3217     50,
3218     &objects,
3219     &next
3220     );
3221   ASSERT_EQ(r, 0);
3222   ASSERT_TRUE(objects.empty());
3223
3224   objects.clear();
3225   listed.clear();
3226   ghobject_t start2, next2;
3227   while (1) {
3228     r = store->collection_list(cid, start, ghobject_t::get_max(),
3229                                50,
3230                                &objects,
3231                                &next);
3232     ASSERT_TRUE(sorted(objects));
3233     ASSERT_EQ(r, 0);
3234     listed.insert(objects.begin(), objects.end());
3235     if (objects.size() < 50) {
3236       ASSERT_TRUE(next.is_max());
3237       break;
3238     }
3239     objects.clear();
3240
3241     start = next;
3242   }
3243   cerr << "listed.size() is " << listed.size() << std::endl;
3244   ASSERT_TRUE(listed.size() == created.size());
3245   if (listed2.size()) {
3246     ASSERT_EQ(listed.size(), listed2.size());
3247   }
3248   for (set<ghobject_t>::iterator i = listed.begin();
3249        i != listed.end();
3250        ++i) {
3251     ASSERT_TRUE(created.count(*i));
3252   }
3253
3254   for (set<ghobject_t>::iterator i = created.begin();
3255        i != created.end();
3256        ++i) {
3257     ObjectStore::Transaction t;
3258     t.remove(cid, *i);
3259     r = apply_transaction(store, &osr, std::move(t));
3260     ASSERT_EQ(r, 0);
3261   }
3262   cerr << "cleaning up" << std::endl;
3263   {
3264     ObjectStore::Transaction t;
3265     t.remove_collection(cid);
3266     r = apply_transaction(store, &osr, std::move(t));
3267     ASSERT_EQ(r, 0);
3268   }
3269 }
3270
3271
3272 class ObjectGenerator {
3273 public:
3274   virtual ghobject_t create_object(gen_type *gen) = 0;
3275   virtual ~ObjectGenerator() {}
3276 };
3277
3278 class MixedGenerator : public ObjectGenerator {
3279 public:
3280   unsigned seq;
3281   int64_t poolid;
3282   explicit MixedGenerator(int64_t p) : seq(0), poolid(p) {}
3283   ghobject_t create_object(gen_type *gen) override {
3284     char buf[100];
3285     snprintf(buf, sizeof(buf), "OBJ_%u", seq);
3286     string name(buf);
3287     if (seq % 2) {
3288       for (unsigned i = 0; i < 300; ++i) {
3289         name.push_back('a');
3290       }
3291     }
3292     ++seq;
3293     return ghobject_t(
3294       hobject_t(
3295         name, string(), rand() & 2 ? CEPH_NOSNAP : rand(),
3296         (((seq / 1024) % 2) * 0xF00 ) +
3297         (seq & 0xFF),
3298         poolid, ""));
3299   }
3300 };
3301
3302 class SyntheticWorkloadState {
3303   struct Object {
3304     bufferlist data;
3305     map<string, bufferlist> attrs;
3306   };
3307 public:
3308   static const unsigned max_in_flight = 16;
3309   static const unsigned max_objects = 3000;
3310   static const unsigned max_attr_size = 5;
3311   static const unsigned max_attr_name_len = 100;
3312   static const unsigned max_attr_value_len = 1024 * 64;
3313   coll_t cid;
3314   unsigned write_alignment;
3315   unsigned max_object_len, max_write_len;
3316   unsigned in_flight;
3317   map<ghobject_t, Object> contents;
3318   set<ghobject_t> available_objects;
3319   set<ghobject_t> in_flight_objects;
3320   ObjectGenerator *object_gen;
3321   gen_type *rng;
3322   ObjectStore *store;
3323   ObjectStore::Sequencer *osr;
3324
3325   Mutex lock;
3326   Cond cond;
3327
3328   struct EnterExit {
3329     const char *msg;
3330     explicit EnterExit(const char *m) : msg(m) {
3331       //cout << pthread_self() << " enter " << msg << std::endl;
3332     }
3333     ~EnterExit() {
3334       //cout << pthread_self() << " exit " << msg << std::endl;
3335     }
3336   };
3337
3338   class C_SyntheticOnReadable : public Context {
3339   public:
3340     SyntheticWorkloadState *state;
3341     ghobject_t hoid;
3342     C_SyntheticOnReadable(SyntheticWorkloadState *state, ghobject_t hoid)
3343       : state(state), hoid(hoid) {}
3344
3345     void finish(int r) override {
3346       Mutex::Locker locker(state->lock);
3347       EnterExit ee("onreadable finish");
3348       ASSERT_TRUE(state->in_flight_objects.count(hoid));
3349       ASSERT_EQ(r, 0);
3350       state->in_flight_objects.erase(hoid);
3351       if (state->contents.count(hoid))
3352         state->available_objects.insert(hoid);
3353       --(state->in_flight);
3354       state->cond.Signal();
3355
3356       bufferlist r2;
3357       r = state->store->read(state->cid, hoid, 0, state->contents[hoid].data.length(), r2);
3358       assert(bl_eq(state->contents[hoid].data, r2));
3359       state->cond.Signal();
3360     }
3361   };
3362
3363   class C_SyntheticOnStash : public Context {
3364   public:
3365     SyntheticWorkloadState *state;
3366     ghobject_t oid, noid;
3367
3368     C_SyntheticOnStash(SyntheticWorkloadState *state,
3369                        ghobject_t oid, ghobject_t noid)
3370       : state(state), oid(oid), noid(noid) {}
3371
3372     void finish(int r) override {
3373       Mutex::Locker locker(state->lock);
3374       EnterExit ee("stash finish");
3375       ASSERT_TRUE(state->in_flight_objects.count(oid));
3376       ASSERT_EQ(r, 0);
3377       state->in_flight_objects.erase(oid);
3378       if (state->contents.count(noid))
3379         state->available_objects.insert(noid);
3380       --(state->in_flight);
3381       bufferlist r2;
3382       r = state->store->read(
3383         state->cid, noid, 0,
3384         state->contents[noid].data.length(), r2);
3385       assert(bl_eq(state->contents[noid].data, r2));
3386       state->cond.Signal();
3387     }
3388   };
3389
3390   class C_SyntheticOnClone : public Context {
3391   public:
3392     SyntheticWorkloadState *state;
3393     ghobject_t oid, noid;
3394
3395     C_SyntheticOnClone(SyntheticWorkloadState *state,
3396                        ghobject_t oid, ghobject_t noid)
3397       : state(state), oid(oid), noid(noid) {}
3398
3399     void finish(int r) override {
3400       Mutex::Locker locker(state->lock);
3401       EnterExit ee("clone finish");
3402       ASSERT_TRUE(state->in_flight_objects.count(oid));
3403       ASSERT_EQ(r, 0);
3404       state->in_flight_objects.erase(oid);
3405       if (state->contents.count(oid))
3406         state->available_objects.insert(oid);
3407       if (state->contents.count(noid))
3408         state->available_objects.insert(noid);
3409       --(state->in_flight);
3410       bufferlist r2;
3411       r = state->store->read(state->cid, noid, 0, state->contents[noid].data.length(), r2);
3412       assert(bl_eq(state->contents[noid].data, r2));
3413       state->cond.Signal();
3414     }
3415   };
3416
3417   static void filled_byte_array(bufferlist& bl, size_t size)
3418   {
3419     static const char alphanum[] = "0123456789"
3420       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3421       "abcdefghijklmnopqrstuvwxyz";
3422     if (!size) {
3423       return;
3424     }
3425     bufferptr bp(size);
3426     for (unsigned int i = 0; i < size - 1; i++) {
3427       // severely limit entropy so we can compress...
3428       bp[i] = alphanum[rand() % 10]; //(sizeof(alphanum) - 1)];
3429     }
3430     bp[size - 1] = '\0';
3431
3432     bl.append(bp);
3433   }
3434   
3435   SyntheticWorkloadState(ObjectStore *store,
3436                          ObjectGenerator *gen,
3437                          gen_type *rng,
3438                          ObjectStore::Sequencer *osr,
3439                          coll_t cid,
3440                          unsigned max_size,
3441                          unsigned max_write,
3442                          unsigned alignment)
3443     : cid(cid), write_alignment(alignment), max_object_len(max_size),
3444       max_write_len(max_write), in_flight(0), object_gen(gen),
3445       rng(rng), store(store), osr(osr), lock("State lock") {}
3446
3447   int init() {
3448     ObjectStore::Transaction t;
3449     t.create_collection(cid, 0);
3450     return apply_transaction(store, osr, std::move(t));
3451   }
3452   void shutdown() {
3453     while (1) {
3454       vector<ghobject_t> objects;
3455       int r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(),
3456                                      10, &objects, 0);
3457       assert(r >= 0);
3458       if (objects.empty())
3459         break;
3460       ObjectStore::Transaction t;
3461       for (vector<ghobject_t>::iterator p = objects.begin();
3462            p != objects.end(); ++p) {
3463         t.remove(cid, *p);
3464       }
3465       apply_transaction(store, osr, std::move(t));
3466     }
3467     ObjectStore::Transaction t;
3468     t.remove_collection(cid);
3469     apply_transaction(store, osr, std::move(t));
3470   }
3471   void statfs(store_statfs_t& stat) {
3472     store->statfs(&stat);
3473   }
3474
3475   ghobject_t get_uniform_random_object() {
3476     while (in_flight >= max_in_flight || available_objects.empty())
3477       cond.Wait(lock);
3478     boost::uniform_int<> choose(0, available_objects.size() - 1);
3479     int index = choose(*rng);
3480     set<ghobject_t>::iterator i = available_objects.begin();
3481     for ( ; index > 0; --index, ++i) ;
3482     ghobject_t ret = *i;
3483     return ret;
3484   }
3485
3486   void wait_for_ready() {
3487     while (in_flight >= max_in_flight)
3488       cond.Wait(lock);
3489   }
3490
3491   void wait_for_done() {
3492     osr->flush();
3493     Mutex::Locker locker(lock);
3494     while (in_flight)
3495       cond.Wait(lock);
3496   }
3497
3498   bool can_create() {
3499     return (available_objects.size() + in_flight_objects.size()) < max_objects;
3500   }
3501
3502   bool can_unlink() {
3503     return (available_objects.size() + in_flight_objects.size()) > 0;
3504   }
3505
3506   unsigned get_random_alloc_hints() {
3507     unsigned f = 0;
3508     {
3509       boost::uniform_int<> u(0, 3);
3510       switch (u(*rng)) {
3511       case 1:
3512         f |= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE;
3513         break;
3514       case 2:
3515         f |= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE;
3516         break;
3517       }
3518     }
3519     {
3520       boost::uniform_int<> u(0, 3);
3521       switch (u(*rng)) {
3522       case 1:
3523         f |= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ;
3524         break;
3525       case 2:
3526         f |= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ;
3527         break;
3528       }
3529     }
3530     {
3531       // append_only, immutable
3532       boost::uniform_int<> u(0, 4);
3533       f |= u(*rng) << 4;
3534     }
3535     {
3536       boost::uniform_int<> u(0, 3);
3537       switch (u(*rng)) {
3538       case 1:
3539         f |= CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED;
3540         break;
3541       case 2:
3542         f |= CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED;
3543         break;
3544       }
3545     }
3546     {
3547       boost::uniform_int<> u(0, 3);
3548       switch (u(*rng)) {
3549       case 1:
3550         f |= CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE;
3551         break;
3552       case 2:
3553         f |= CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE;
3554         break;
3555       }
3556     }
3557     return f;
3558   }
3559
3560   int touch() {
3561     Mutex::Locker locker(lock);
3562     EnterExit ee("touch");
3563     if (!can_create())
3564       return -ENOSPC;
3565     wait_for_ready();
3566     ghobject_t new_obj = object_gen->create_object(rng);
3567     available_objects.erase(new_obj);
3568     ObjectStore::Transaction t;
3569     t.touch(cid, new_obj);
3570     boost::uniform_int<> u(17, 22);
3571     boost::uniform_int<> v(12, 17);
3572     t.set_alloc_hint(cid, new_obj,
3573                       1ull << u(*rng),
3574                       1ull << v(*rng),
3575                       get_random_alloc_hints());
3576     ++in_flight;
3577     in_flight_objects.insert(new_obj);
3578     if (!contents.count(new_obj))
3579       contents[new_obj] = Object();
3580     int status = store->queue_transaction(osr, std::move(t), new C_SyntheticOnReadable(this, new_obj));
3581     return status;
3582   }
3583
3584   int stash() {
3585     Mutex::Locker locker(lock);
3586     EnterExit ee("stash");
3587     if (!can_unlink())
3588       return -ENOENT;
3589     if (!can_create())
3590       return -ENOSPC;
3591     wait_for_ready();
3592
3593     ghobject_t old_obj;
3594     int max = 20;
3595     do {
3596       old_obj = get_uniform_random_object();
3597     } while (--max && !contents[old_obj].data.length());
3598     available_objects.erase(old_obj);
3599     ghobject_t new_obj = old_obj;
3600     new_obj.generation++;
3601     available_objects.erase(new_obj);
3602
3603     ObjectStore::Transaction t;
3604     t.collection_move_rename(cid, old_obj, cid, new_obj);
3605     ++in_flight;
3606     in_flight_objects.insert(old_obj);
3607
3608     contents[new_obj].attrs = contents[old_obj].attrs;
3609     contents[new_obj].data = contents[old_obj].data;
3610     contents.erase(old_obj);
3611     int status = store->queue_transaction(
3612       osr, std::move(t),
3613       new C_SyntheticOnStash(this, old_obj, new_obj));
3614     return status;
3615   }
3616
3617   int clone() {
3618     Mutex::Locker locker(lock);
3619     EnterExit ee("clone");
3620     if (!can_unlink())
3621       return -ENOENT;
3622     if (!can_create())
3623       return -ENOSPC;
3624     wait_for_ready();
3625
3626     ghobject_t old_obj;
3627     int max = 20;
3628     do {
3629       old_obj = get_uniform_random_object();
3630     } while (--max && !contents[old_obj].data.length());
3631     available_objects.erase(old_obj);
3632     ghobject_t new_obj = object_gen->create_object(rng);
3633     // make the hash match
3634     new_obj.hobj.set_hash(old_obj.hobj.get_hash());
3635     available_objects.erase(new_obj);
3636
3637     ObjectStore::Transaction t;
3638     t.clone(cid, old_obj, new_obj);
3639     ++in_flight;
3640     in_flight_objects.insert(old_obj);
3641
3642     contents[new_obj].attrs = contents[old_obj].attrs;
3643     contents[new_obj].data = contents[old_obj].data;
3644
3645     int status = store->queue_transaction(
3646       osr, std::move(t),
3647       new C_SyntheticOnClone(this, old_obj, new_obj));
3648     return status;
3649   }
3650
3651   int clone_range() {
3652     Mutex::Locker locker(lock);
3653     EnterExit ee("clone_range");
3654     if (!can_unlink())
3655       return -ENOENT;
3656     if (!can_create())
3657       return -ENOSPC;
3658     wait_for_ready();
3659
3660     ghobject_t old_obj;
3661     int max = 20;
3662     do {
3663       old_obj = get_uniform_random_object();
3664     } while (--max && !contents[old_obj].data.length());
3665     bufferlist &srcdata = contents[old_obj].data;
3666     if (srcdata.length() == 0) {
3667       return 0;
3668     }
3669     available_objects.erase(old_obj);
3670     ghobject_t new_obj = get_uniform_random_object();
3671     available_objects.erase(new_obj);
3672
3673     boost::uniform_int<> u1(0, max_object_len - max_write_len);
3674     boost::uniform_int<> u2(0, max_write_len);
3675     uint64_t srcoff = u1(*rng);
3676     // make src and dst offsets match, since that's what the osd does
3677     uint64_t dstoff = srcoff; //u1(*rng);
3678     uint64_t len = u2(*rng);
3679     if (write_alignment) {
3680       srcoff = ROUND_UP_TO(srcoff, write_alignment);
3681       dstoff = ROUND_UP_TO(dstoff, write_alignment);
3682       len = ROUND_UP_TO(len, write_alignment);
3683     }
3684
3685     if (srcoff > srcdata.length() - 1) {
3686       srcoff = srcdata.length() - 1;
3687     }
3688     if (srcoff + len > srcdata.length()) {
3689       len = srcdata.length() - srcoff;
3690     }
3691     if (0)
3692       cout << __func__ << " from " << srcoff << "~" << len
3693          << " (size " << srcdata.length() << ") to "
3694          << dstoff << "~" << len << std::endl;
3695
3696     ObjectStore::Transaction t;
3697     t.clone_range(cid, old_obj, new_obj, srcoff, len, dstoff);
3698     ++in_flight;
3699     in_flight_objects.insert(old_obj);
3700
3701     bufferlist bl;
3702     if (srcoff < srcdata.length()) {
3703       if (srcoff + len > srcdata.length()) {
3704         bl.substr_of(srcdata, srcoff, srcdata.length() - srcoff);
3705       } else {
3706         bl.substr_of(srcdata, srcoff, len);
3707       }
3708     }
3709
3710     bufferlist& dstdata = contents[new_obj].data;
3711     if (dstdata.length() <= dstoff) {
3712       if (bl.length() > 0) {
3713         dstdata.append_zero(dstoff - dstdata.length());
3714         dstdata.append(bl);
3715       }
3716     } else {
3717       bufferlist value;
3718       assert(dstdata.length() > dstoff);
3719       dstdata.copy(0, dstoff, value);
3720       value.append(bl);
3721       if (value.length() < dstdata.length())
3722         dstdata.copy(value.length(),
3723                      dstdata.length() - value.length(), value);
3724       value.swap(dstdata);
3725     }
3726
3727     int status = store->queue_transaction(
3728       osr, std::move(t), new C_SyntheticOnClone(this, old_obj, new_obj));
3729     return status;
3730   }
3731
3732
3733   int write() {
3734     Mutex::Locker locker(lock);
3735     EnterExit ee("write");
3736     if (!can_unlink())
3737       return -ENOENT;
3738     wait_for_ready();
3739
3740     ghobject_t new_obj = get_uniform_random_object();
3741     available_objects.erase(new_obj);
3742     ObjectStore::Transaction t;
3743
3744     boost::uniform_int<> u1(0, max_object_len - max_write_len);
3745     boost::uniform_int<> u2(0, max_write_len);
3746     uint64_t offset = u1(*rng);
3747     uint64_t len = u2(*rng);
3748     bufferlist bl;
3749     if (write_alignment) {
3750       offset = ROUND_UP_TO(offset, write_alignment);
3751       len = ROUND_UP_TO(len, write_alignment);
3752     }
3753
3754     filled_byte_array(bl, len);
3755
3756     bufferlist& data = contents[new_obj].data;
3757     if (data.length() <= offset) {
3758       if (len > 0) {
3759         data.append_zero(offset-data.length());
3760         data.append(bl);
3761       }
3762     } else {
3763       bufferlist value;
3764       assert(data.length() > offset);
3765       data.copy(0, offset, value);
3766       value.append(bl);
3767       if (value.length() < data.length())
3768         data.copy(value.length(),
3769                   data.length()-value.length(), value);
3770       value.swap(data);
3771     }
3772
3773     t.write(cid, new_obj, offset, len, bl);
3774     ++in_flight;
3775     in_flight_objects.insert(new_obj);
3776     int status = store->queue_transaction(
3777       osr, std::move(t), new C_SyntheticOnReadable(this, new_obj));
3778     return status;
3779   }
3780
3781   int truncate() {
3782     Mutex::Locker locker(lock);
3783     EnterExit ee("truncate");
3784     if (!can_unlink())
3785       return -ENOENT;
3786     wait_for_ready();
3787
3788     ghobject_t obj = get_uniform_random_object();
3789     available_objects.erase(obj);
3790     ObjectStore::Transaction t;
3791
3792     boost::uniform_int<> choose(0, max_object_len);
3793     size_t len = choose(*rng);
3794     if (write_alignment) {
3795       len = ROUND_UP_TO(len, write_alignment);
3796     }
3797
3798     t.truncate(cid, obj, len);
3799     ++in_flight;
3800     in_flight_objects.insert(obj);
3801     bufferlist& data = contents[obj].data;
3802     if (data.length() <= len) {
3803       data.append_zero(len - data.length());
3804     } else {
3805       bufferlist bl;
3806       data.copy(0, len, bl);
3807       bl.swap(data);
3808     }
3809
3810     int status = store->queue_transaction(
3811       osr, std::move(t), new C_SyntheticOnReadable(this, obj));
3812     return status;
3813   }
3814
3815   int zero() {
3816     Mutex::Locker locker(lock);
3817     EnterExit ee("zero");
3818     if (!can_unlink())
3819       return -ENOENT;
3820     wait_for_ready();
3821
3822     ghobject_t new_obj = get_uniform_random_object();
3823     available_objects.erase(new_obj);
3824     ObjectStore::Transaction t;
3825
3826     boost::uniform_int<> u1(0, max_object_len - max_write_len);
3827     boost::uniform_int<> u2(0, max_write_len);
3828     uint64_t offset = u1(*rng);
3829     uint64_t len = u2(*rng);
3830     if (write_alignment) {
3831       offset = ROUND_UP_TO(offset, write_alignment);
3832       len = ROUND_UP_TO(len, write_alignment);
3833     }
3834
3835     auto& data = contents[new_obj].data;
3836     if (data.length() < offset + len) {
3837       data.append_zero(offset+len-data.length());
3838     }
3839     bufferlist n;
3840     n.substr_of(data, 0, offset);
3841     n.append_zero(len);
3842     if (data.length() > offset + len)
3843       data.copy(offset + len, data.length() - offset - len, n);
3844     data.swap(n);
3845
3846     t.zero(cid, new_obj, offset, len);
3847     ++in_flight;
3848     in_flight_objects.insert(new_obj);
3849     int status = store->queue_transaction(
3850       osr, std::move(t), new C_SyntheticOnReadable(this, new_obj));
3851     return status;
3852   }
3853
3854   void read() {
3855     EnterExit ee("read");
3856     boost::uniform_int<> u1(0, max_object_len/2);
3857     boost::uniform_int<> u2(0, max_object_len);
3858     uint64_t offset = u1(*rng);
3859     uint64_t len = u2(*rng);
3860     if (offset > len)
3861       swap(offset, len);
3862
3863     ghobject_t obj;
3864     bufferlist expected;
3865     int r;
3866     {
3867       Mutex::Locker locker(lock);
3868       EnterExit ee("read locked");
3869       if (!can_unlink())
3870         return ;
3871       wait_for_ready();
3872
3873       obj = get_uniform_random_object();
3874       expected = contents[obj].data;
3875     }
3876     bufferlist bl, result;
3877     if (0) cout << " obj " << obj
3878          << " size " << expected.length()
3879          << " offset " << offset
3880          << " len " << len << std::endl;
3881     r = store->read(cid, obj, offset, len, result);
3882     if (offset >= expected.length()) {
3883       ASSERT_EQ(r, 0);
3884     } else {
3885       size_t max_len = expected.length() - offset;
3886       if (len > max_len)
3887         len = max_len;
3888       assert(len == result.length());
3889       ASSERT_EQ(len, result.length());
3890       expected.copy(offset, len, bl);
3891       ASSERT_EQ(r, (int)len);
3892       ASSERT_TRUE(bl_eq(bl, result));
3893     }
3894   }
3895
3896   int setattrs() {
3897     Mutex::Locker locker(lock);
3898     EnterExit ee("setattrs");
3899     if (!can_unlink())
3900       return -ENOENT;
3901     wait_for_ready();
3902
3903     ghobject_t obj = get_uniform_random_object();
3904     available_objects.erase(obj);
3905     ObjectStore::Transaction t;
3906
3907     boost::uniform_int<> u0(1, max_attr_size);
3908     boost::uniform_int<> u1(4, max_attr_name_len);
3909     boost::uniform_int<> u2(4, max_attr_value_len);
3910     boost::uniform_int<> u3(0, 100);
3911     uint64_t size = u0(*rng);
3912     uint64_t name_len;
3913     map<string, bufferlist> attrs;
3914     set<string> keys;
3915     for (map<string, bufferlist>::iterator it = contents[obj].attrs.begin();
3916          it != contents[obj].attrs.end(); ++it)
3917       keys.insert(it->first);
3918
3919     while (size--) {
3920       bufferlist name, value;
3921       uint64_t get_exist = u3(*rng);
3922       uint64_t value_len = u2(*rng);
3923       filled_byte_array(value, value_len);
3924       if (get_exist < 50 && keys.size()) {
3925         set<string>::iterator k = keys.begin();
3926         attrs[*k] = value;
3927         contents[obj].attrs[*k] = value;
3928         keys.erase(k);
3929       } else {
3930         name_len = u1(*rng);
3931         filled_byte_array(name, name_len);
3932         attrs[name.c_str()] = value;
3933         contents[obj].attrs[name.c_str()] = value;
3934       }
3935     }
3936     t.setattrs(cid, obj, attrs);
3937     ++in_flight;
3938     in_flight_objects.insert(obj);
3939     int status = store->queue_transaction(
3940       osr, std::move(t), new C_SyntheticOnReadable(this, obj));
3941     return status;
3942   }
3943
3944   void getattrs() {
3945     EnterExit ee("getattrs");
3946     ghobject_t obj;
3947     map<string, bufferlist> expected;
3948     {
3949       Mutex::Locker locker(lock);
3950       EnterExit ee("getattrs locked");
3951       if (!can_unlink())
3952         return ;
3953       wait_for_ready();
3954
3955       int retry = 10;
3956       do {
3957         obj = get_uniform_random_object();
3958         if (!--retry)
3959           return ;
3960       } while (contents[obj].attrs.empty());
3961       expected = contents[obj].attrs;
3962     }
3963     map<string, bufferlist> attrs;
3964     int r = store->getattrs(cid, obj, attrs);
3965     ASSERT_TRUE(r == 0);
3966     ASSERT_TRUE(attrs.size() == expected.size());
3967     for (map<string, bufferlist>::iterator it = expected.begin();
3968          it != expected.end(); ++it) {
3969       ASSERT_TRUE(bl_eq(attrs[it->first], it->second));
3970     }
3971   }
3972
3973   void getattr() {
3974     EnterExit ee("getattr");
3975     ghobject_t obj;
3976     int r;
3977     int retry;
3978     map<string, bufferlist> expected;
3979     {
3980       Mutex::Locker locker(lock);
3981       EnterExit ee("getattr locked");
3982       if (!can_unlink())
3983         return ;
3984       wait_for_ready();
3985
3986       retry = 10;
3987       do {
3988         obj = get_uniform_random_object();
3989         if (!--retry)
3990           return ;
3991       } while (contents[obj].attrs.empty());
3992       expected = contents[obj].attrs;
3993     }
3994     boost::uniform_int<> u(0, expected.size()-1);
3995     retry = u(*rng);
3996     map<string, bufferlist>::iterator it = expected.begin();
3997     while (retry) {
3998       retry--;
3999       ++it;
4000     }
4001
4002     bufferlist bl;
4003     r = store->getattr(cid, obj, it->first, bl);
4004     ASSERT_EQ(r, 0);
4005     ASSERT_TRUE(bl_eq(it->second, bl));
4006   }
4007
4008   int rmattr() {
4009     Mutex::Locker locker(lock);
4010     EnterExit ee("rmattr");
4011     if (!can_unlink())
4012       return -ENOENT;
4013     wait_for_ready();
4014
4015     ghobject_t obj;
4016     int retry = 10;
4017     do {
4018       obj = get_uniform_random_object();
4019       if (!--retry)
4020         return 0;
4021     } while (contents[obj].attrs.empty());
4022
4023     boost::uniform_int<> u(0, contents[obj].attrs.size()-1);
4024     retry = u(*rng);
4025     map<string, bufferlist>::iterator it = contents[obj].attrs.begin();
4026     while (retry) {
4027       retry--;
4028       ++it;
4029     }
4030
4031     available_objects.erase(obj);
4032     ObjectStore::Transaction t;
4033     t.rmattr(cid, obj, it->first);
4034
4035     contents[obj].attrs.erase(it->first);
4036     ++in_flight;
4037     in_flight_objects.insert(obj);
4038     int status = store->queue_transaction(
4039       osr, std::move(t), new C_SyntheticOnReadable(this, obj));
4040     return status;
4041   }
4042
4043   void fsck(bool deep) {
4044     Mutex::Locker locker(lock);
4045     EnterExit ee("fsck");
4046     while (in_flight)
4047       cond.Wait(lock);
4048     store->umount();
4049     int r = store->fsck(deep);
4050     assert(r == 0 || r == -EOPNOTSUPP);
4051     store->mount();
4052   }
4053
4054   void scan() {
4055     Mutex::Locker locker(lock);
4056     EnterExit ee("scan");
4057     while (in_flight)
4058       cond.Wait(lock);
4059     vector<ghobject_t> objects;
4060     set<ghobject_t> objects_set, objects_set2;
4061     ghobject_t next, current;
4062     while (1) {
4063       //cerr << "scanning..." << std::endl;
4064       int r = store->collection_list(cid, current, ghobject_t::get_max(), 100,
4065                                      &objects, &next);
4066       ASSERT_EQ(r, 0);
4067       ASSERT_TRUE(sorted(objects));
4068       objects_set.insert(objects.begin(), objects.end());
4069       objects.clear();
4070       if (next.is_max()) break;
4071       current = next;
4072     }
4073     if (objects_set.size() != available_objects.size()) {
4074       for (set<ghobject_t>::iterator p = objects_set.begin();
4075            p != objects_set.end();
4076            ++p)
4077         if (available_objects.count(*p) == 0) {
4078           cerr << "+ " << *p << std::endl;
4079           ceph_abort();
4080         }
4081       for (set<ghobject_t>::iterator p = available_objects.begin();
4082            p != available_objects.end();
4083            ++p)
4084         if (objects_set.count(*p) == 0)
4085           cerr << "- " << *p << std::endl;
4086       //cerr << " objects_set: " << objects_set << std::endl;
4087       //cerr << " available_set: " << available_objects << std::endl;
4088       assert(0 == "badness");
4089     }
4090
4091     ASSERT_EQ(objects_set.size(), available_objects.size());
4092     for (set<ghobject_t>::iterator i = objects_set.begin();
4093          i != objects_set.end();
4094          ++i) {
4095       ASSERT_GT(available_objects.count(*i), (unsigned)0);
4096     }
4097
4098     int r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(),
4099                                    INT_MAX, &objects, 0);
4100     ASSERT_EQ(r, 0);
4101     objects_set2.insert(objects.begin(), objects.end());
4102     ASSERT_EQ(objects_set2.size(), available_objects.size());
4103     for (set<ghobject_t>::iterator i = objects_set2.begin();
4104          i != objects_set2.end();
4105          ++i) {
4106       ASSERT_GT(available_objects.count(*i), (unsigned)0);
4107       if (available_objects.count(*i) == 0) {
4108         cerr << "+ " << *i << std::endl;
4109       }
4110     }
4111   }
4112
4113   void stat() {
4114     EnterExit ee("stat");
4115     ghobject_t hoid;
4116     uint64_t expected;
4117     {
4118       Mutex::Locker locker(lock);
4119       EnterExit ee("stat lock1");
4120       if (!can_unlink())
4121         return ;
4122       hoid = get_uniform_random_object();
4123       in_flight_objects.insert(hoid);
4124       available_objects.erase(hoid);
4125       ++in_flight;
4126       expected = contents[hoid].data.length();
4127     }
4128     struct stat buf;
4129     int r = store->stat(cid, hoid, &buf);
4130     ASSERT_EQ(0, r);
4131     assert((uint64_t)buf.st_size == expected);
4132     ASSERT_TRUE((uint64_t)buf.st_size == expected);
4133     {
4134       Mutex::Locker locker(lock);
4135       EnterExit ee("stat lock2");
4136       --in_flight;
4137       cond.Signal();
4138       in_flight_objects.erase(hoid);
4139       available_objects.insert(hoid);
4140     }
4141   }
4142
4143   int unlink() {
4144     Mutex::Locker locker(lock);
4145     EnterExit ee("unlink");
4146     if (!can_unlink())
4147       return -ENOENT;
4148     ghobject_t to_remove = get_uniform_random_object();
4149     ObjectStore::Transaction t;
4150     t.remove(cid, to_remove);
4151     ++in_flight;
4152     available_objects.erase(to_remove);
4153     in_flight_objects.insert(to_remove);
4154     contents.erase(to_remove);
4155     int status = store->queue_transaction(osr, std::move(t), new C_SyntheticOnReadable(this, to_remove));
4156     return status;
4157   }
4158
4159   void print_internal_state() {
4160     Mutex::Locker locker(lock);
4161     cerr << "available_objects: " << available_objects.size()
4162          << " in_flight_objects: " << in_flight_objects.size()
4163          << " total objects: " << in_flight_objects.size() + available_objects.size()
4164          << " in_flight " << in_flight << std::endl;
4165   }
4166 };
4167
4168
4169 void doSyntheticTest(boost::scoped_ptr<ObjectStore>& store,
4170                      int num_ops,
4171                      uint64_t max_obj, uint64_t max_wr, uint64_t align)
4172 {
4173   ObjectStore::Sequencer osr("test");
4174   MixedGenerator gen(555);
4175   gen_type rng(time(NULL));
4176   coll_t cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD));
4177
4178   g_ceph_context->_conf->set_val("bluestore_fsck_on_mount", "false");
4179   g_ceph_context->_conf->set_val("bluestore_fsck_on_umount", "false");
4180   g_ceph_context->_conf->apply_changes(NULL);
4181
4182   SyntheticWorkloadState test_obj(store.get(), &gen, &rng, &osr, cid,
4183                                   max_obj, max_wr, align);
4184   test_obj.init();
4185   for (int i = 0; i < num_ops/10; ++i) {
4186     if (!(i % 500)) cerr << "seeding object " << i << std::endl;
4187     test_obj.touch();
4188   }
4189   for (int i = 0; i < num_ops; ++i) {
4190     if (!(i % 1000)) {
4191       cerr << "Op " << i << std::endl;
4192       test_obj.print_internal_state();
4193     }
4194     boost::uniform_int<> true_false(0, 999);
4195     int val = true_false(rng);
4196     if (val > 998) {
4197       test_obj.fsck(true);
4198     } else if (val > 997) {
4199       test_obj.fsck(false);
4200     } else if (val > 970) {
4201       test_obj.scan();
4202     } else if (val > 950) {
4203       test_obj.stat();
4204     } else if (val > 850) {
4205       test_obj.zero();
4206     } else if (val > 800) {
4207       test_obj.unlink();
4208     } else if (val > 550) {
4209       test_obj.write();
4210     } else if (val > 500) {
4211       test_obj.clone();
4212     } else if (val > 450) {
4213       test_obj.clone_range();
4214     } else if (val > 300) {
4215       test_obj.stash();
4216     } else if (val > 100) {
4217       test_obj.read();
4218     } else {
4219       test_obj.truncate();
4220     }
4221   }
4222   test_obj.wait_for_done();
4223   test_obj.shutdown();
4224
4225   g_ceph_context->_conf->set_val("bluestore_fsck_on_mount", "true");
4226   g_ceph_context->_conf->set_val("bluestore_fsck_on_umount", "true");
4227   g_ceph_context->_conf->apply_changes(NULL);
4228 }
4229
4230 TEST_P(StoreTest, Synthetic) {
4231   doSyntheticTest(store, 10000, 400*1024, 40*1024, 0);
4232 }
4233
4234
4235 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixSharding) {
4236   if (string(GetParam()) != "bluestore")
4237     return;
4238   
4239   const char *m[][10] = {
4240     { "bluestore_min_alloc_size", "4096", 0 }, // must be the first!
4241     { "num_ops", "50000", 0 },
4242     { "max_write", "65536", 0 },
4243     { "max_size", "262144", 0 },
4244     { "alignment", "4096", 0 },
4245     { "bluestore_max_blob_size", "65536", 0 },
4246     { "bluestore_extent_map_shard_min_size", "60", 0 },
4247     { "bluestore_extent_map_shard_max_size", "300", 0 },
4248     { "bluestore_extent_map_shard_target_size", "150", 0 },
4249     { "bluestore_default_buffered_read", "true", 0 },
4250     { "bluestore_default_buffered_write", "true", 0 },
4251     { 0 },
4252   };
4253   do_matrix(m, store, doSyntheticTest);
4254 }
4255
4256 TEST_P(StoreTestSpecificAUSize, ZipperPatternSharded) {
4257   if(string(GetParam()) != "bluestore")
4258     return;
4259   StartDeferred(4096);
4260
4261   int r;
4262   ObjectStore::Sequencer osr("test");
4263   coll_t cid;
4264   ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
4265   {
4266     ObjectStore::Transaction t;
4267     t.create_collection(cid, 0);
4268     cerr << "Creating collection " << cid << std::endl;
4269     r = apply_transaction(store, &osr, std::move(t));
4270     ASSERT_EQ(r, 0);
4271   }
4272   bufferlist bl;
4273   int len = 4096;
4274   bufferptr bp(len);
4275   bp.zero();
4276   bl.append(bp);
4277   for (int i=0; i<1000; ++i) {
4278     ObjectStore::Transaction t;
4279     t.write(cid, a, i*2*len, len, bl, 0);
4280     r = apply_transaction(store, &osr, std::move(t));
4281     ASSERT_EQ(r, 0);
4282   }
4283   for (int i=0; i<1000; ++i) {
4284     ObjectStore::Transaction t;
4285     t.write(cid, a, i*2*len + 1, len, bl, 0);
4286     r = apply_transaction(store, &osr, std::move(t));
4287     ASSERT_EQ(r, 0);
4288   }
4289   {
4290     ObjectStore::Transaction t;
4291     t.remove(cid, a);
4292     t.remove_collection(cid);
4293     cerr << "Cleaning" << std::endl;
4294     r = apply_transaction(store, &osr, std::move(t));
4295     ASSERT_EQ(r, 0);
4296   }
4297 }
4298
4299 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCsumAlgorithm) {
4300   if (string(GetParam()) != "bluestore")
4301     return;
4302
4303   const char *m[][10] = {
4304     { "bluestore_min_alloc_size", "65536", 0 }, // must be the first!
4305     { "max_write", "65536", 0 },
4306     { "max_size", "1048576", 0 },
4307     { "alignment", "16", 0 },
4308     { "bluestore_csum_type", "crc32c", "crc32c_16", "crc32c_8", "xxhash32",
4309       "xxhash64", "none", 0 },
4310     { "bluestore_default_buffered_write", "false", 0 },
4311     { 0 },
4312   };
4313   do_matrix(m, store, doSyntheticTest);
4314 }
4315
4316 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCsumVsCompression) {
4317   if (string(GetParam()) != "bluestore")
4318     return;
4319
4320   const char *m[][10] = {
4321     { "bluestore_min_alloc_size", "4096", "16384", 0 }, //to be the first!
4322     { "max_write", "131072", 0 },
4323     { "max_size", "262144", 0 },
4324     { "alignment", "512", 0 },
4325     { "bluestore_compression_mode", "force", 0},
4326     { "bluestore_compression_algorithm", "snappy", "zlib", 0 },
4327     { "bluestore_csum_type", "crc32c", 0 },
4328     { "bluestore_default_buffered_read", "true", "false", 0 },
4329     { "bluestore_default_buffered_write", "true", "false", 0 },
4330     { "bluestore_sync_submit_transaction", "false", 0 },
4331     { 0 },
4332   };
4333   do_matrix(m, store, doSyntheticTest);
4334 }
4335
4336 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCompression) {
4337   if (string(GetParam()) != "bluestore")
4338     return;
4339
4340   const char *m[][10] = {
4341     { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4342     { "max_write", "1048576", 0 },
4343     { "max_size", "4194304", 0 },
4344     { "alignment", "65536", 0 },
4345     { "bluestore_compression_mode", "force", "aggressive", "passive", "none", 0},
4346     { "bluestore_default_buffered_write", "false", 0 },
4347     { "bluestore_sync_submit_transaction", "true", 0 },
4348     { 0 },
4349   };
4350   do_matrix(m, store, doSyntheticTest);
4351 }
4352
4353 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCompressionAlgorithm) {
4354   if (string(GetParam()) != "bluestore")
4355     return;
4356
4357   const char *m[][10] = {
4358     { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4359     { "max_write", "1048576", 0 },
4360     { "max_size", "4194304", 0 },
4361     { "alignment", "65536", 0 },
4362     { "bluestore_compression_algorithm", "zlib", "snappy", 0 },
4363     { "bluestore_compression_mode", "force", 0 },
4364     { "bluestore_default_buffered_write", "false", 0 },
4365     { 0 },
4366   };
4367   do_matrix(m, store, doSyntheticTest);
4368 }
4369
4370 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixNoCsum) {
4371   if (string(GetParam()) != "bluestore")
4372     return;
4373
4374   const char *m[][10] = {
4375     { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4376     { "max_write", "65536", 0 },
4377     { "max_size", "1048576", 0 },
4378     { "alignment", "512", 0 },
4379     { "bluestore_max_blob_size", "262144", 0 },
4380     { "bluestore_compression_mode", "force", "none", 0},
4381     { "bluestore_csum_type", "none", 0},
4382     { "bluestore_default_buffered_read", "true", "false", 0 },
4383     { "bluestore_default_buffered_write", "true", 0 },
4384     { "bluestore_sync_submit_transaction", "true", "false", 0 },
4385     { 0 },
4386   };
4387   do_matrix(m, store, doSyntheticTest);
4388 }
4389
4390 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixPreferDeferred) {
4391   if (string(GetParam()) != "bluestore")
4392     return;
4393
4394   const char *m[][10] = {
4395     { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4396     { "max_write", "65536", 0 },
4397     { "max_size", "1048576", 0 },
4398     { "alignment", "512", 0 },
4399     { "bluestore_max_blob_size", "262144", 0 },
4400     { "bluestore_compression_mode", "force", "none", 0},
4401     { "bluestore_prefer_deferred_size", "32768", "0", 0},
4402     { 0 },
4403   };
4404   do_matrix(m, store, doSyntheticTest);
4405 }
4406
4407 TEST_P(StoreTest, AttrSynthetic) {
4408   ObjectStore::Sequencer osr("test");
4409   MixedGenerator gen(447);
4410   gen_type rng(time(NULL));
4411   coll_t cid(spg_t(pg_t(0,447),shard_id_t::NO_SHARD));
4412
4413   SyntheticWorkloadState test_obj(store.get(), &gen, &rng, &osr, cid, 40*1024, 4*1024, 0);
4414   test_obj.init();
4415   for (int i = 0; i < 500; ++i) {
4416     if (!(i % 10)) cerr << "seeding object " << i << std::endl;
4417     test_obj.touch();
4418   }
4419   for (int i = 0; i < 1000; ++i) {
4420     if (!(i % 100)) {
4421       cerr << "Op " << i << std::endl;
4422       test_obj.print_internal_state();
4423     }
4424     boost::uniform_int<> true_false(0, 99);
4425     int val = true_false(rng);
4426     if (val > 97) {
4427       test_obj.scan();
4428     } else if (val > 93) {
4429       test_obj.stat();
4430     } else if (val > 75) {
4431       test_obj.rmattr();
4432     } else if (val > 47) {
4433       test_obj.setattrs();
4434     } else if (val > 45) {
4435       test_obj.clone();
4436     } else if (val > 37) {
4437       test_obj.stash();
4438     } else if (val > 30) {
4439       test_obj.getattrs();
4440     } else {
4441       test_obj.getattr();
4442     }
4443   }
4444   test_obj.wait_for_done();
4445   test_obj.shutdown();
4446 }
4447
4448 TEST_P(StoreTest, HashCollisionTest) {
4449   ObjectStore::Sequencer osr("test");
4450   int64_t poolid = 11;
4451   coll_t cid(spg_t(pg_t(0,poolid),shard_id_t::NO_SHARD));
4452   int r;
4453   {
4454     ObjectStore::Transaction t;
4455     t.create_collection(cid, 0);
4456     r = apply_transaction(store, &osr, std::move(t));
4457     ASSERT_EQ(r, 0);
4458   }
4459   string base = "";
4460   for (int i = 0; i < 100; ++i) base.append("aaaaa");
4461   set<ghobject_t> created;
4462   for (int n = 0; n < 10; ++n) {
4463     char nbuf[100];
4464     sprintf(nbuf, "n%d", n);
4465   for (int i = 0; i < 1000; ++i) {
4466     char buf[100];
4467     sprintf(buf, "%d", i);
4468     if (!(i % 100)) {
4469       cerr << "Object n" << n << " "<< i << std::endl;
4470     }
4471     ghobject_t hoid(hobject_t(string(buf) + base, string(), CEPH_NOSNAP, 0, poolid, string(nbuf)));
4472     {
4473       ObjectStore::Transaction t;
4474       t.touch(cid, hoid);
4475       r = apply_transaction(store, &osr, std::move(t));
4476       ASSERT_EQ(r, 0);
4477     }
4478     created.insert(hoid);
4479   }
4480   }
4481   vector<ghobject_t> objects;
4482   r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(), INT_MAX, &objects, 0);
4483   ASSERT_EQ(r, 0);
4484   set<ghobject_t> listed(objects.begin(), objects.end());
4485   cerr << "listed.size() is " << listed.size() << " and created.size() is " << created.size() << std::endl;
4486   ASSERT_TRUE(listed.size() == created.size());
4487   objects.clear();
4488   listed.clear();
4489   ghobject_t current, next;
4490   while (1) {
4491     r = store->collection_list(cid, current, ghobject_t::get_max(), 60,
4492                                &objects, &next);
4493     ASSERT_EQ(r, 0);
4494     ASSERT_TRUE(sorted(objects));
4495     for (vector<ghobject_t>::iterator i = objects.begin();
4496          i != objects.end();
4497          ++i) {
4498       if (listed.count(*i))
4499         cerr << *i << " repeated" << std::endl;
4500       listed.insert(*i);
4501     }
4502     if (objects.size() < 50) {
4503       ASSERT_TRUE(next.is_max());
4504       break;
4505     }
4506     objects.clear();
4507     current = next;
4508   }
4509   cerr << "listed.size() is " << listed.size() << std::endl;
4510   ASSERT_TRUE(listed.size() == created.size());
4511   for (set<ghobject_t>::iterator i = listed.begin();
4512        i != listed.end();
4513        ++i) {
4514     ASSERT_TRUE(created.count(*i));
4515   }
4516
4517   for (set<ghobject_t>::iterator i = created.begin();
4518        i != created.end();
4519        ++i) {
4520     ObjectStore::Transaction t;
4521     t.remove(cid, *i);
4522     r = apply_transaction(store, &osr, std::move(t));
4523     ASSERT_EQ(r, 0);
4524   }
4525   ObjectStore::Transaction t;
4526   t.remove_collection(cid);
4527   r = apply_transaction(store, &osr, std::move(t));
4528   ASSERT_EQ(r, 0);
4529 }
4530
4531 TEST_P(StoreTest, ScrubTest) {
4532   ObjectStore::Sequencer osr("test");
4533   int64_t poolid = 111;
4534   coll_t cid(spg_t(pg_t(0, poolid),shard_id_t(1)));
4535   int r;
4536   {
4537     ObjectStore::Transaction t;
4538     t.create_collection(cid, 0);
4539     r = apply_transaction(store, &osr, std::move(t));
4540     ASSERT_EQ(r, 0);
4541   }
4542   string base = "aaaaa";
4543   set<ghobject_t> created;
4544   for (int i = 0; i < 1000; ++i) {
4545     char buf[100];
4546     sprintf(buf, "%d", i);
4547     if (!(i % 5)) {
4548       cerr << "Object " << i << std::endl;
4549     }
4550     ghobject_t hoid(hobject_t(string(buf) + base, string(), CEPH_NOSNAP, i,
4551                               poolid, ""),
4552                     ghobject_t::NO_GEN, shard_id_t(1));
4553     {
4554       ObjectStore::Transaction t;
4555       t.touch(cid, hoid);
4556       r = apply_transaction(store, &osr, std::move(t));
4557       ASSERT_EQ(r, 0);
4558     }
4559     created.insert(hoid);
4560   }
4561
4562   // Add same hobject_t but different generation
4563   {
4564     ghobject_t hoid1(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""),
4565                      ghobject_t::NO_GEN, shard_id_t(1));
4566     ghobject_t hoid2(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""), (gen_t)1, shard_id_t(1));
4567     ghobject_t hoid3(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""), (gen_t)2, shard_id_t(1));
4568     ObjectStore::Transaction t;
4569     t.touch(cid, hoid1);
4570     t.touch(cid, hoid2);
4571     t.touch(cid, hoid3);
4572     r = apply_transaction(store, &osr, std::move(t));
4573     created.insert(hoid1);
4574     created.insert(hoid2);
4575     created.insert(hoid3);
4576     ASSERT_EQ(r, 0);
4577   }
4578
4579   vector<ghobject_t> objects;
4580   r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(),
4581                              INT_MAX, &objects, 0);
4582   ASSERT_EQ(r, 0);
4583   set<ghobject_t> listed(objects.begin(), objects.end());
4584   cerr << "listed.size() is " << listed.size() << " and created.size() is " << created.size() << std::endl;
4585   ASSERT_TRUE(listed.size() == created.size());
4586   objects.clear();
4587   listed.clear();
4588   ghobject_t current, next;
4589   while (1) {
4590     r = store->collection_list(cid, current, ghobject_t::get_max(), 60,
4591                                &objects, &next);
4592     ASSERT_EQ(r, 0);
4593     ASSERT_TRUE(sorted(objects));
4594     for (vector<ghobject_t>::iterator i = objects.begin();
4595          i != objects.end(); ++i) {
4596       if (listed.count(*i))
4597         cerr << *i << " repeated" << std::endl;
4598       listed.insert(*i);
4599     }
4600     if (objects.size() < 50) {
4601       ASSERT_TRUE(next.is_max());
4602       break;
4603     }
4604     objects.clear();
4605     current = next.get_boundary();
4606   }
4607   cerr << "listed.size() is " << listed.size() << std::endl;
4608   ASSERT_TRUE(listed.size() == created.size());
4609   for (set<ghobject_t>::iterator i = listed.begin();
4610        i != listed.end();
4611        ++i) {
4612     ASSERT_TRUE(created.count(*i));
4613   }
4614
4615   for (set<ghobject_t>::iterator i = created.begin();
4616        i != created.end();
4617        ++i) {
4618     ObjectStore::Transaction t;
4619     t.remove(cid, *i);
4620     r = apply_transaction(store, &osr, std::move(t));
4621     ASSERT_EQ(r, 0);
4622   }
4623   ObjectStore::Transaction t;
4624   t.remove_collection(cid);
4625   r = apply_transaction(store, &osr, std::move(t));
4626   ASSERT_EQ(r, 0);
4627 }
4628
4629
4630 TEST_P(StoreTest, OMapTest) {
4631   ObjectStore::Sequencer osr("test");
4632   coll_t cid;
4633   ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
4634   int r;
4635   {
4636     ObjectStore::Transaction t;
4637     t.create_collection(cid, 0);
4638     r = apply_transaction(store, &osr, std::move(t));
4639     ASSERT_EQ(r, 0);
4640   }
4641
4642   map<string, bufferlist> attrs;
4643   {
4644     ObjectStore::Transaction t;
4645     t.touch(cid, hoid);
4646     t.omap_clear(cid, hoid);
4647     map<string, bufferlist> start_set;
4648     t.omap_setkeys(cid, hoid, start_set);
4649     r = apply_transaction(store, &osr, std::move(t));
4650     ASSERT_EQ(r, 0);
4651   }
4652
4653   for (int i = 0; i < 100; i++) {
4654     if (!(i%5)) {
4655       std::cout << "On iteration " << i << std::endl;
4656     }
4657     ObjectStore::Transaction t;
4658     bufferlist bl;
4659     map<string, bufferlist> cur_attrs;
4660     r = store->omap_get(cid, hoid, &bl, &cur_attrs);
4661     ASSERT_EQ(r, 0);
4662     for (map<string, bufferlist>::iterator j = attrs.begin();
4663          j != attrs.end();
4664          ++j) {
4665       bool correct = cur_attrs.count(j->first) && string(cur_attrs[j->first].c_str()) == string(j->second.c_str());
4666       if (!correct) {
4667         std::cout << j->first << " is present in cur_attrs " << cur_attrs.count(j->first) << " times " << std::endl;
4668         if (cur_attrs.count(j->first) > 0) {
4669           std::cout << j->second.c_str() << " : " << cur_attrs[j->first].c_str() << std::endl;
4670         }
4671       }
4672       ASSERT_EQ(correct, true);
4673     }
4674     ASSERT_EQ(attrs.size(), cur_attrs.size());
4675
4676     char buf[100];
4677     snprintf(buf, sizeof(buf), "%d", i);
4678     bl.clear();
4679     bufferptr bp(buf, strlen(buf) + 1);
4680     bl.append(bp);
4681     map<string, bufferlist> to_add;
4682     to_add.insert(pair<string, bufferlist>("key-" + string(buf), bl));
4683     attrs.insert(pair<string, bufferlist>("key-" + string(buf), bl));
4684     t.omap_setkeys(cid, hoid, to_add);
4685     r = apply_transaction(store, &osr, std::move(t));
4686     ASSERT_EQ(r, 0);
4687   }
4688
4689   int i = 0;
4690   while (attrs.size()) {
4691     if (!(i%5)) {
4692       std::cout << "removal: On iteration " << i << std::endl;
4693     }
4694     ObjectStore::Transaction t;
4695     bufferlist bl;
4696     map<string, bufferlist> cur_attrs;
4697     r = store->omap_get(cid, hoid, &bl, &cur_attrs);
4698     ASSERT_EQ(r, 0);
4699     for (map<string, bufferlist>::iterator j = attrs.begin();
4700          j != attrs.end();
4701          ++j) {
4702       bool correct = cur_attrs.count(j->first) && string(cur_attrs[j->first].c_str()) == string(j->second.c_str());
4703       if (!correct) {
4704         std::cout << j->first << " is present in cur_attrs " << cur_attrs.count(j->first) << " times " << std::endl;
4705         if (cur_attrs.count(j->first) > 0) {
4706           std::cout << j->second.c_str() << " : " << cur_attrs[j->first].c_str() << std::endl;
4707         }
4708       }
4709       ASSERT_EQ(correct, true);
4710     }
4711
4712     string to_remove = attrs.begin()->first;
4713     set<string> keys_to_remove;
4714     keys_to_remove.insert(to_remove);
4715     t.omap_rmkeys(cid, hoid, keys_to_remove);
4716     r = apply_transaction(store, &osr, std::move(t));
4717     ASSERT_EQ(r, 0);
4718
4719     attrs.erase(to_remove);
4720
4721     ++i;
4722   }
4723
4724   {
4725     bufferlist bl1;
4726     bl1.append("omap_header");
4727     ObjectStore::Transaction t;
4728     t.omap_setheader(cid, hoid, bl1);
4729     r = apply_transaction(store, &osr, std::move(t));
4730     ASSERT_EQ(r, 0);
4731     t = ObjectStore::Transaction();
4732  
4733     bufferlist bl2;
4734     bl2.append("value");
4735     map<string, bufferlist> to_add;
4736     to_add.insert(pair<string, bufferlist>("key", bl2));
4737     t.omap_setkeys(cid, hoid, to_add);
4738     r = apply_transaction(store, &osr, std::move(t));
4739     ASSERT_EQ(r, 0);
4740
4741     bufferlist bl3;
4742     map<string, bufferlist> cur_attrs;
4743     r = store->omap_get(cid, hoid, &bl3, &cur_attrs);
4744     ASSERT_EQ(r, 0);
4745     ASSERT_EQ(cur_attrs.size(), size_t(1));
4746     ASSERT_TRUE(bl_eq(bl1, bl3));
4747  
4748     set<string> keys;
4749     r = store->omap_get_keys(cid, hoid, &keys);
4750     ASSERT_EQ(r, 0);
4751     ASSERT_EQ(keys.size(), size_t(1));
4752   }
4753
4754   // test omap_clear, omap_rmkey_range
4755   {
4756     {
4757       map<string,bufferlist> to_set;
4758       for (int n=0; n<10; ++n) {
4759         to_set[stringify(n)].append("foo");
4760       }
4761       bufferlist h;
4762       h.append("header");
4763       ObjectStore::Transaction t;
4764       t.remove(cid, hoid);
4765       t.touch(cid, hoid);
4766       t.omap_setheader(cid, hoid, h);
4767       t.omap_setkeys(cid, hoid, to_set);
4768       r = apply_transaction(store, &osr, std::move(t));
4769       ASSERT_EQ(r, 0);
4770     }
4771     {
4772       ObjectStore::Transaction t;
4773       t.omap_rmkeyrange(cid, hoid, "3", "7");
4774       r = apply_transaction(store, &osr, std::move(t));
4775       ASSERT_EQ(r, 0);
4776     }
4777     {
4778       bufferlist hdr;
4779       map<string,bufferlist> m;
4780       store->omap_get(cid, hoid, &hdr, &m);
4781       ASSERT_EQ(6u, hdr.length());
4782       ASSERT_TRUE(m.count("2"));
4783       ASSERT_TRUE(!m.count("3"));
4784       ASSERT_TRUE(!m.count("6"));
4785       ASSERT_TRUE(m.count("7"));
4786       ASSERT_TRUE(m.count("8"));
4787       //cout << m << std::endl;
4788       ASSERT_EQ(6u, m.size());
4789     }
4790     {
4791       ObjectStore::Transaction t;
4792       t.omap_clear(cid, hoid);
4793       r = apply_transaction(store, &osr, std::move(t));
4794       ASSERT_EQ(r, 0);
4795     }
4796     {
4797       bufferlist hdr;
4798       map<string,bufferlist> m;
4799       store->omap_get(cid, hoid, &hdr, &m);
4800       ASSERT_EQ(0u, hdr.length());
4801       ASSERT_EQ(0u, m.size());
4802     }
4803   }
4804
4805   ObjectStore::Transaction t;
4806   t.remove(cid, hoid);
4807   t.remove_collection(cid);
4808   r = apply_transaction(store, &osr, std::move(t));
4809   ASSERT_EQ(r, 0);
4810 }
4811
4812 TEST_P(StoreTest, OMapIterator) {
4813   ObjectStore::Sequencer osr("test");
4814   coll_t cid;
4815   ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
4816   int count = 0;
4817   int r;
4818   {
4819     ObjectStore::Transaction t;
4820     t.create_collection(cid, 0);
4821     r = apply_transaction(store, &osr, std::move(t));
4822     ASSERT_EQ(r, 0);
4823   }
4824
4825   map<string, bufferlist> attrs;
4826   {
4827     ObjectStore::Transaction t;
4828     t.touch(cid, hoid);
4829     t.omap_clear(cid, hoid);
4830     map<string, bufferlist> start_set;
4831     t.omap_setkeys(cid, hoid, start_set);
4832     r = apply_transaction(store, &osr, std::move(t));
4833     ASSERT_EQ(r, 0);
4834   }
4835   ObjectMap::ObjectMapIterator iter;
4836   bool correct;
4837   //basic iteration
4838   for (int i = 0; i < 100; i++) {
4839     if (!(i%5)) {
4840       std::cout << "On iteration " << i << std::endl;
4841     }
4842     bufferlist bl;
4843
4844     // FileStore may deadlock two active iterators over the same data
4845     iter = ObjectMap::ObjectMapIterator();
4846
4847     iter = store->get_omap_iterator(cid, hoid);
4848     for (iter->seek_to_first(), count=0; iter->valid(); iter->next(), count++) {
4849       string key = iter->key();
4850       bufferlist value = iter->value();
4851       correct = attrs.count(key) && (string(value.c_str()) == string(attrs[key].c_str()));
4852       if (!correct) {
4853         if (attrs.count(key) > 0) {
4854           std::cout << "key " << key << "in omap , " << value.c_str() << " : " << attrs[key].c_str() << std::endl;
4855         }
4856         else
4857           std::cout << "key " << key << "should not exists in omap" << std::endl;
4858       }
4859       ASSERT_EQ(correct, true);
4860     }
4861     ASSERT_EQ((int)attrs.size(), count);
4862
4863     // FileStore may deadlock an active iterator vs apply_transaction
4864     iter = ObjectMap::ObjectMapIterator();
4865
4866     char buf[100];
4867     snprintf(buf, sizeof(buf), "%d", i);
4868     bl.clear();
4869     bufferptr bp(buf, strlen(buf) + 1);
4870     bl.append(bp);
4871     map<string, bufferlist> to_add;
4872     to_add.insert(pair<string, bufferlist>("key-" + string(buf), bl));
4873     attrs.insert(pair<string, bufferlist>("key-" + string(buf), bl));
4874     ObjectStore::Transaction t;
4875     t.omap_setkeys(cid, hoid, to_add);
4876     r = apply_transaction(store, &osr, std::move(t));
4877     ASSERT_EQ(r, 0);
4878   }
4879
4880   iter = store->get_omap_iterator(cid, hoid);
4881   //lower bound
4882   string bound_key = "key-5";
4883   iter->lower_bound(bound_key);
4884   correct = bound_key <= iter->key();
4885   if (!correct) {
4886     std::cout << "lower bound, bound key is " << bound_key << " < iter key is " << iter->key() << std::endl;
4887   }
4888   ASSERT_EQ(correct, true);
4889   //upper bound
4890   iter->upper_bound(bound_key);
4891   correct = iter->key() > bound_key;
4892   if (!correct) {
4893     std::cout << "upper bound, bound key is " << bound_key << " >= iter key is " << iter->key() << std::endl;
4894   }
4895   ASSERT_EQ(correct, true);
4896
4897   // FileStore may deadlock an active iterator vs apply_transaction
4898   iter = ObjectMap::ObjectMapIterator();
4899   {
4900     ObjectStore::Transaction t;
4901     t.remove(cid, hoid);
4902     t.remove_collection(cid);
4903     r = apply_transaction(store, &osr, std::move(t));
4904     ASSERT_EQ(r, 0);
4905   }
4906 }
4907
4908 TEST_P(StoreTest, XattrTest) {
4909   ObjectStore::Sequencer osr("test");
4910   coll_t cid;
4911   ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
4912   bufferlist big;
4913   for (unsigned i = 0; i < 10000; ++i) {
4914     big.append('\0');
4915   }
4916   bufferlist small;
4917   for (unsigned i = 0; i < 10; ++i) {
4918     small.append('\0');
4919   }
4920   int r;
4921   {
4922     ObjectStore::Transaction t;
4923     t.create_collection(cid, 0);
4924     t.touch(cid, hoid);
4925     r = apply_transaction(store, &osr, std::move(t));
4926     ASSERT_EQ(r, 0);
4927   }
4928
4929   map<string, bufferlist> attrs;
4930   {
4931     ObjectStore::Transaction t;
4932     t.setattr(cid, hoid, "attr1", small);
4933     attrs["attr1"] = small;
4934     t.setattr(cid, hoid, "attr2", big);
4935     attrs["attr2"] = big;
4936     t.setattr(cid, hoid, "attr3", small);
4937     attrs["attr3"] = small;
4938     t.setattr(cid, hoid, "attr1", small);
4939     attrs["attr1"] = small;
4940     t.setattr(cid, hoid, "attr4", big);
4941     attrs["attr4"] = big;
4942     t.setattr(cid, hoid, "attr3", big);
4943     attrs["attr3"] = big;
4944     r = apply_transaction(store, &osr, std::move(t));
4945     ASSERT_EQ(r, 0);
4946   }
4947
4948   map<string, bufferptr> aset;
4949   store->getattrs(cid, hoid, aset);
4950   ASSERT_EQ(aset.size(), attrs.size());
4951   for (map<string, bufferptr>::iterator i = aset.begin();
4952        i != aset.end();
4953        ++i) {
4954     bufferlist bl;
4955     bl.push_back(i->second);
4956     ASSERT_TRUE(attrs[i->first] == bl);
4957   }
4958
4959   {
4960     ObjectStore::Transaction t;
4961     t.rmattr(cid, hoid, "attr2");
4962     attrs.erase("attr2");
4963     r = apply_transaction(store, &osr, std::move(t));
4964     ASSERT_EQ(r, 0);
4965   }
4966
4967   aset.clear();
4968   store->getattrs(cid, hoid, aset);
4969   ASSERT_EQ(aset.size(), attrs.size());
4970   for (map<string, bufferptr>::iterator i = aset.begin();
4971        i != aset.end();
4972        ++i) {
4973     bufferlist bl;
4974     bl.push_back(i->second);
4975     ASSERT_TRUE(attrs[i->first] == bl);
4976   }
4977
4978   bufferptr bp;
4979   r = store->getattr(cid, hoid, "attr2", bp);
4980   ASSERT_EQ(r, -ENODATA);
4981
4982   r = store->getattr(cid, hoid, "attr3", bp);
4983   ASSERT_EQ(r, 0);
4984   bufferlist bl2;
4985   bl2.push_back(bp);
4986   ASSERT_TRUE(bl2 == attrs["attr3"]);
4987
4988   ObjectStore::Transaction t;
4989   t.remove(cid, hoid);
4990   t.remove_collection(cid);
4991   r = apply_transaction(store, &osr, std::move(t));
4992   ASSERT_EQ(r, 0);
4993 }
4994
4995 void colsplittest(
4996   ObjectStore *store,
4997   unsigned num_objects,
4998   unsigned common_suffix_size,
4999   bool clones
5000   ) {
5001   ObjectStore::Sequencer osr("test");
5002   coll_t cid(spg_t(pg_t(0,52),shard_id_t::NO_SHARD));
5003   coll_t tid(spg_t(pg_t(1<<common_suffix_size,52),shard_id_t::NO_SHARD));
5004   int r = 0;
5005   {
5006     ObjectStore::Transaction t;
5007     t.create_collection(cid, common_suffix_size);
5008     r = apply_transaction(store, &osr, std::move(t));
5009     ASSERT_EQ(r, 0);
5010   }
5011   bufferlist small;
5012   small.append("small");
5013   {
5014     ObjectStore::Transaction t;
5015     for (uint32_t i = 0; i < (2 - (int)clones)*num_objects; ++i) {
5016       stringstream objname;
5017       objname << "obj" << i;
5018       ghobject_t a(hobject_t(
5019                      objname.str(),
5020                      "",
5021                      CEPH_NOSNAP,
5022                      i<<common_suffix_size,
5023                      52, ""));
5024       t.write(cid, a, 0, small.length(), small,
5025               CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5026       if (clones) {
5027         objname << "-clone";
5028         ghobject_t b(hobject_t(
5029                        objname.str(),
5030                        "",
5031                        CEPH_NOSNAP,
5032                        i<<common_suffix_size,
5033                        52, ""));
5034         t.clone(cid, a, b);
5035       }
5036       if (i % 100) {
5037         r = apply_transaction(store, &osr, std::move(t));
5038         ASSERT_EQ(r, 0);
5039         t = ObjectStore::Transaction();
5040       }
5041     }
5042     r = apply_transaction(store, &osr, std::move(t));
5043     ASSERT_EQ(r, 0);
5044   }
5045   {
5046     ObjectStore::Transaction t;
5047     t.create_collection(tid, common_suffix_size + 1);
5048     t.split_collection(cid, common_suffix_size+1, 1<<common_suffix_size, tid);
5049     r = apply_transaction(store, &osr, std::move(t));
5050     ASSERT_EQ(r, 0);
5051   }
5052
5053   ObjectStore::Transaction t;
5054   vector<ghobject_t> objects;
5055   r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(),
5056                              INT_MAX, &objects, 0);
5057   ASSERT_EQ(r, 0);
5058   ASSERT_EQ(objects.size(), num_objects);
5059   unsigned size = 0;
5060   for (vector<ghobject_t>::iterator i = objects.begin();
5061        i != objects.end();
5062        ++i) {
5063     ASSERT_EQ(!!(i->hobj.get_hash() & (1<<common_suffix_size)), 0u);
5064     t.remove(cid, *i);
5065     if (++size > 100) {
5066       size = 0;
5067       r = apply_transaction(store, &osr, std::move(t));
5068       ASSERT_EQ(r, 0);
5069       t = ObjectStore::Transaction();
5070     }
5071   }
5072
5073   objects.clear();
5074   r = store->collection_list(tid, ghobject_t(), ghobject_t::get_max(),
5075                              INT_MAX, &objects, 0);
5076   ASSERT_EQ(r, 0);
5077   ASSERT_EQ(objects.size(), num_objects);
5078   for (vector<ghobject_t>::iterator i = objects.begin();
5079        i != objects.end();
5080        ++i) {
5081     ASSERT_EQ(!(i->hobj.get_hash() & (1<<common_suffix_size)), 0u);
5082     t.remove(tid, *i);
5083     if (++size > 100) {
5084       size = 0;
5085       r = apply_transaction(store, &osr, std::move(t));
5086       ASSERT_EQ(r, 0);
5087       t = ObjectStore::Transaction();
5088     }
5089   }
5090
5091   t.remove_collection(cid);
5092   t.remove_collection(tid);
5093   r = apply_transaction(store, &osr, std::move(t));
5094   ASSERT_EQ(r, 0);
5095 }
5096
5097 TEST_P(StoreTest, ColSplitTest1) {
5098   colsplittest(store.get(), 10000, 11, false);
5099 }
5100 TEST_P(StoreTest, ColSplitTest1Clones) {
5101   colsplittest(store.get(), 10000, 11, true);
5102 }
5103 TEST_P(StoreTest, ColSplitTest2) {
5104   colsplittest(store.get(), 100, 7, false);
5105 }
5106 TEST_P(StoreTest, ColSplitTest2Clones) {
5107   colsplittest(store.get(), 100, 7, true);
5108 }
5109
5110 #if 0
5111 TEST_P(StoreTest, ColSplitTest3) {
5112   colsplittest(store.get(), 100000, 25);
5113 }
5114 #endif
5115
5116 /**
5117  * This test tests adding two different groups
5118  * of objects, each with 1 common prefix and 1
5119  * different prefix.  We then remove half
5120  * in order to verify that the merging correctly
5121  * stops at the common prefix subdir.  See bug
5122  * #5273 */
5123 TEST_P(StoreTest, TwoHash) {
5124   ObjectStore::Sequencer osr("test");
5125   coll_t cid;
5126   int r;
5127   {
5128     ObjectStore::Transaction t;
5129     t.create_collection(cid, 0);
5130     r = apply_transaction(store, &osr, std::move(t));
5131     ASSERT_EQ(r, 0);
5132   }
5133   std::cout << "Making objects" << std::endl;
5134   for (int i = 0; i < 360; ++i) {
5135     ObjectStore::Transaction t;
5136     ghobject_t o;
5137     o.hobj.pool = -1;
5138     if (i < 8) {
5139       o.hobj.set_hash((i << 16) | 0xA1);
5140       t.touch(cid, o);
5141     }
5142     o.hobj.set_hash((i << 16) | 0xB1);
5143     t.touch(cid, o);
5144     r = apply_transaction(store, &osr, std::move(t));
5145     ASSERT_EQ(r, 0);
5146   }
5147   std::cout << "Removing half" << std::endl;
5148   for (int i = 1; i < 8; ++i) {
5149     ObjectStore::Transaction t;
5150     ghobject_t o;
5151     o.hobj.pool = -1;
5152     o.hobj.set_hash((i << 16) | 0xA1);
5153     t.remove(cid, o);
5154     r = apply_transaction(store, &osr, std::move(t));
5155     ASSERT_EQ(r, 0);
5156   }
5157   std::cout << "Checking" << std::endl;
5158   for (int i = 1; i < 8; ++i) {
5159     ObjectStore::Transaction t;
5160     ghobject_t o;
5161     o.hobj.set_hash((i << 16) | 0xA1);
5162     o.hobj.pool = -1;
5163     bool exists = store->exists(cid, o);
5164     ASSERT_EQ(exists, false);
5165   }
5166   {
5167     ghobject_t o;
5168     o.hobj.set_hash(0xA1);
5169     o.hobj.pool = -1;
5170     bool exists = store->exists(cid, o);
5171     ASSERT_EQ(exists, true);
5172   }
5173   std::cout << "Cleanup" << std::endl;
5174   for (int i = 0; i < 360; ++i) {
5175     ObjectStore::Transaction t;
5176     ghobject_t o;
5177     o.hobj.set_hash((i << 16) | 0xA1);
5178     o.hobj.pool = -1;
5179     t.remove(cid, o);
5180     o.hobj.set_hash((i << 16) | 0xB1);
5181     t.remove(cid, o);
5182     r = apply_transaction(store, &osr, std::move(t));
5183     ASSERT_EQ(r, 0);
5184   }
5185   ObjectStore::Transaction t;
5186   t.remove_collection(cid);
5187   r = apply_transaction(store, &osr, std::move(t));
5188   ASSERT_EQ(r, 0);
5189 }
5190
5191 TEST_P(StoreTest, Rename) {
5192   ObjectStore::Sequencer osr("test");
5193   coll_t cid(spg_t(pg_t(0, 2122),shard_id_t::NO_SHARD));
5194   ghobject_t srcoid(hobject_t("src_oid", "", CEPH_NOSNAP, 0, 0, ""));
5195   ghobject_t dstoid(hobject_t("dest_oid", "", CEPH_NOSNAP, 0, 0, ""));
5196   bufferlist a, b;
5197   a.append("foo");
5198   b.append("bar");
5199   int r;
5200   {
5201     ObjectStore::Transaction t;
5202     t.create_collection(cid, 0);
5203     t.write(cid, srcoid, 0, a.length(), a);
5204     r = apply_transaction(store, &osr, std::move(t));
5205     ASSERT_EQ(r, 0);
5206   }
5207   ASSERT_TRUE(store->exists(cid, srcoid));
5208   {
5209     ObjectStore::Transaction t;
5210     t.collection_move_rename(cid, srcoid, cid, dstoid);
5211     t.write(cid, srcoid, 0, b.length(), b);
5212     t.setattr(cid, srcoid, "attr", b);
5213     r = apply_transaction(store, &osr, std::move(t));
5214     ASSERT_EQ(r, 0);
5215   }
5216   ASSERT_TRUE(store->exists(cid, srcoid));
5217   ASSERT_TRUE(store->exists(cid, dstoid));
5218   {
5219     bufferlist bl;
5220     store->read(cid, srcoid, 0, 3, bl);
5221     ASSERT_TRUE(bl_eq(b, bl));
5222     store->read(cid, dstoid, 0, 3, bl);
5223     ASSERT_TRUE(bl_eq(a, bl));
5224   }
5225   {
5226     ObjectStore::Transaction t;
5227     t.remove(cid, dstoid);
5228     t.collection_move_rename(cid, srcoid, cid, dstoid);
5229     r = apply_transaction(store, &osr, std::move(t));
5230     ASSERT_EQ(r, 0);
5231   }
5232   ASSERT_TRUE(store->exists(cid, dstoid));
5233   ASSERT_FALSE(store->exists(cid, srcoid));
5234   {
5235     bufferlist bl;
5236     store->read(cid, dstoid, 0, 3, bl);
5237     ASSERT_TRUE(bl_eq(b, bl));
5238   }
5239   {
5240     ObjectStore::Transaction t;
5241     t.remove(cid, dstoid);
5242     t.remove_collection(cid);
5243     r = apply_transaction(store, &osr, std::move(t));
5244     ASSERT_EQ(r, 0);
5245   }
5246 }
5247
5248 TEST_P(StoreTest, MoveRename) {
5249   ObjectStore::Sequencer osr("test");
5250   coll_t cid(spg_t(pg_t(0, 212),shard_id_t::NO_SHARD));
5251   ghobject_t temp_oid(hobject_t("tmp_oid", "", CEPH_NOSNAP, 0, 0, ""));
5252   ghobject_t oid(hobject_t("dest_oid", "", CEPH_NOSNAP, 0, 0, ""));
5253   int r;
5254   {
5255     ObjectStore::Transaction t;
5256     t.create_collection(cid, 0);
5257     t.touch(cid, oid);
5258     r = apply_transaction(store, &osr, std::move(t));
5259     ASSERT_EQ(r, 0);
5260   }
5261   ASSERT_TRUE(store->exists(cid, oid));
5262   bufferlist data, attr;
5263   map<string, bufferlist> omap;
5264   data.append("data payload");
5265   attr.append("attr value");
5266   omap["omap_key"].append("omap value");
5267   {
5268     ObjectStore::Transaction t;
5269     t.touch(cid, temp_oid);
5270     t.write(cid, temp_oid, 0, data.length(), data);
5271     t.setattr(cid, temp_oid, "attr", attr);
5272     t.omap_setkeys(cid, temp_oid, omap);
5273     r = apply_transaction(store, &osr, std::move(t));
5274     ASSERT_EQ(r, 0);
5275   }
5276   ASSERT_TRUE(store->exists(cid, temp_oid));
5277   {
5278     ObjectStore::Transaction t;
5279     t.remove(cid, oid);
5280     t.collection_move_rename(cid, temp_oid, cid, oid);
5281     r = apply_transaction(store, &osr, std::move(t));
5282     ASSERT_EQ(r, 0);
5283   }
5284   ASSERT_TRUE(store->exists(cid, oid));
5285   ASSERT_FALSE(store->exists(cid, temp_oid));
5286   {
5287     bufferlist newdata;
5288     r = store->read(cid, oid, 0, 1000, newdata);
5289     ASSERT_GE(r, 0);
5290     ASSERT_TRUE(bl_eq(data, newdata));
5291     bufferlist newattr;
5292     r = store->getattr(cid, oid, "attr", newattr);
5293     ASSERT_EQ(r, 0);
5294     ASSERT_TRUE(bl_eq(attr, newattr));
5295     set<string> keys;
5296     keys.insert("omap_key");
5297     map<string, bufferlist> newomap;
5298     r = store->omap_get_values(cid, oid, keys, &newomap);
5299     ASSERT_GE(r, 0);
5300     ASSERT_EQ(1u, newomap.size());
5301     ASSERT_TRUE(newomap.count("omap_key"));
5302     ASSERT_TRUE(bl_eq(omap["omap_key"], newomap["omap_key"]));
5303   }
5304   {
5305     ObjectStore::Transaction t;
5306     t.remove(cid, oid);
5307     t.remove_collection(cid);
5308     r = apply_transaction(store, &osr, std::move(t));
5309     ASSERT_EQ(r, 0);
5310   }
5311 }
5312
5313 TEST_P(StoreTest, BigRGWObjectName) {
5314   ObjectStore::Sequencer osr("test");
5315   coll_t cid(spg_t(pg_t(0,12),shard_id_t::NO_SHARD));
5316   ghobject_t oid(
5317     hobject_t(
5318       "default.4106.50_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
5319       "",
5320       CEPH_NOSNAP,
5321       0x81920472,
5322       12,
5323       ""),
5324     15,
5325     shard_id_t::NO_SHARD);
5326   ghobject_t oid2(oid);
5327   oid2.generation = 17;
5328   ghobject_t oidhead(oid);
5329   oidhead.generation = ghobject_t::NO_GEN;
5330
5331   int r;
5332   {
5333     ObjectStore::Transaction t;
5334     t.create_collection(cid, 0);
5335     t.touch(cid, oidhead);
5336     t.collection_move_rename(cid, oidhead, cid, oid);
5337     t.touch(cid, oidhead);
5338     t.collection_move_rename(cid, oidhead, cid, oid2);
5339     r = apply_transaction(store, &osr, std::move(t));
5340     ASSERT_EQ(r, 0);
5341   }
5342
5343   {
5344     ObjectStore::Transaction t;
5345     t.remove(cid, oid);
5346     r = apply_transaction(store, &osr, std::move(t));
5347     ASSERT_EQ(r, 0);
5348   }
5349
5350   {
5351     vector<ghobject_t> objects;
5352     r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(),
5353                                INT_MAX, &objects, 0);
5354     ASSERT_EQ(r, 0);
5355     ASSERT_EQ(objects.size(), 1u);
5356     ASSERT_EQ(objects[0], oid2);
5357   }
5358
5359   ASSERT_FALSE(store->exists(cid, oid));
5360
5361   {
5362     ObjectStore::Transaction t;
5363     t.remove(cid, oid2);
5364     t.remove_collection(cid);
5365     r = apply_transaction(store, &osr, std::move(t));
5366     ASSERT_EQ(r, 0);
5367
5368   }
5369 }
5370
5371 TEST_P(StoreTest, SetAllocHint) {
5372   ObjectStore::Sequencer osr("test");
5373   coll_t cid;
5374   ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, 0, ""));
5375   int r;
5376   {
5377     ObjectStore::Transaction t;
5378     t.create_collection(cid, 0);
5379     t.touch(cid, hoid);
5380     r = apply_transaction(store, &osr, std::move(t));
5381     ASSERT_EQ(r, 0);
5382   }
5383   {
5384     ObjectStore::Transaction t;
5385     t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*4, 0);
5386     r = apply_transaction(store, &osr, std::move(t));
5387     ASSERT_EQ(r, 0);
5388   }
5389   {
5390     ObjectStore::Transaction t;
5391     t.remove(cid, hoid);
5392     r = apply_transaction(store, &osr, std::move(t));
5393     ASSERT_EQ(r, 0);
5394   }
5395   {
5396     ObjectStore::Transaction t;
5397     t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*4, 0);
5398     r = apply_transaction(store, &osr, std::move(t));
5399     ASSERT_EQ(r, 0);
5400   }
5401   {
5402     ObjectStore::Transaction t;
5403     t.remove_collection(cid);
5404     r = apply_transaction(store, &osr, std::move(t));
5405     ASSERT_EQ(r, 0);
5406   }
5407 }
5408
5409 TEST_P(StoreTest, TryMoveRename) {
5410   ObjectStore::Sequencer osr("test");
5411   coll_t cid;
5412   ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
5413   ghobject_t hoid2(hobject_t("test_hint2", "", CEPH_NOSNAP, 0, -1, ""));
5414   int r;
5415   {
5416     ObjectStore::Transaction t;
5417     t.create_collection(cid, 0);
5418     r = apply_transaction(store, &osr, std::move(t));
5419     ASSERT_EQ(r, 0);
5420   }
5421   {
5422     ObjectStore::Transaction t;
5423     t.try_rename(cid, hoid, hoid2);
5424     r = apply_transaction(store, &osr, std::move(t));
5425     ASSERT_EQ(r, 0);
5426   }
5427   {
5428     ObjectStore::Transaction t;
5429     t.touch(cid, hoid);
5430     r = apply_transaction(store, &osr, std::move(t));
5431     ASSERT_EQ(r, 0);
5432   }
5433   {
5434     ObjectStore::Transaction t;
5435     t.try_rename(cid, hoid, hoid2);
5436     r = apply_transaction(store, &osr, std::move(t));
5437     ASSERT_EQ(r, 0);
5438   }
5439   struct stat st;
5440   ASSERT_EQ(store->stat(cid, hoid, &st), -ENOENT);
5441   ASSERT_EQ(store->stat(cid, hoid2, &st), 0);
5442 }
5443
5444 #if defined(HAVE_LIBAIO)
5445 TEST_P(StoreTest, BluestoreOnOffCSumTest) {
5446   if (string(GetParam()) != "bluestore")
5447     return;
5448   g_conf->set_val("bluestore_csum_type", "crc32c");
5449   g_conf->apply_changes(NULL);
5450
5451   ObjectStore::Sequencer osr("test");
5452   int r;
5453   coll_t cid;
5454   ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
5455   {
5456     bufferlist in;
5457     r = store->read(cid, hoid, 0, 5, in);
5458     ASSERT_EQ(-ENOENT, r);
5459   }
5460   {
5461     ObjectStore::Transaction t;
5462     t.create_collection(cid, 0);
5463     cerr << "Creating collection " << cid << std::endl;
5464     r = apply_transaction(store, &osr, std::move(t));
5465     ASSERT_EQ(r, 0);
5466   }
5467   {
5468     //write with csum enabled followed by read with csum disabled
5469     size_t block_size = 64*1024;
5470     ObjectStore::Transaction t;
5471     bufferlist bl, orig;
5472     bl.append(std::string(block_size, 'a'));
5473     orig = bl;
5474     t.remove(cid, hoid);
5475     t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
5476     t.write(cid, hoid, 0, bl.length(), bl);
5477     cerr << "Remove then create" << std::endl;
5478     r = apply_transaction(store, &osr, std::move(t));
5479     ASSERT_EQ(r, 0);
5480
5481     g_conf->set_val("bluestore_csum_type", "none");
5482     g_conf->apply_changes(NULL);
5483
5484     bufferlist in;
5485     r = store->read(cid, hoid, 0, block_size, in);
5486     ASSERT_EQ((int)block_size, r);
5487     ASSERT_TRUE(bl_eq(orig, in));
5488
5489   }
5490   {
5491     //write with csum disabled followed by read with csum enabled
5492
5493     size_t block_size = 64*1024;
5494     ObjectStore::Transaction t;
5495     bufferlist bl, orig;
5496     bl.append(std::string(block_size, 'a'));
5497     orig = bl;
5498     t.remove(cid, hoid);
5499     t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
5500     t.write(cid, hoid, 0, bl.length(), bl);
5501     cerr << "Remove then create" << std::endl;
5502     r = apply_transaction(store, &osr, std::move(t));
5503     ASSERT_EQ(r, 0);
5504
5505     g_conf->set_val("bluestore_csum_type", "crc32c");
5506     g_conf->apply_changes(NULL);
5507
5508     bufferlist in;
5509     r = store->read(cid, hoid, 0, block_size, in);
5510     ASSERT_EQ((int)block_size, r);
5511     ASSERT_TRUE(bl_eq(orig, in));
5512   }
5513   {
5514     //'mixed' non-overlapping writes to the same blob 
5515
5516     ObjectStore::Transaction t;
5517     bufferlist bl, orig;
5518     size_t block_size = 8000;
5519     bl.append(std::string(block_size, 'a'));
5520     orig = bl;
5521     t.remove(cid, hoid);
5522     t.write(cid, hoid, 0, bl.length(), bl);
5523     cerr << "Remove then create" << std::endl;
5524     r = apply_transaction(store, &osr, std::move(t));
5525     ASSERT_EQ(r, 0);
5526
5527     g_conf->set_val("bluestore_csum_type", "none");
5528     g_conf->apply_changes(NULL);
5529
5530     ObjectStore::Transaction t2;
5531     t2.write(cid, hoid, block_size*2, bl.length(), bl);
5532     cerr << "Append 'unprotected'" << std::endl;
5533     r = apply_transaction(store, &osr, std::move(t2));
5534     ASSERT_EQ(r, 0);
5535
5536     bufferlist in;
5537     r = store->read(cid, hoid, 0, block_size, in);
5538     ASSERT_EQ((int)block_size, r);
5539     ASSERT_TRUE(bl_eq(orig, in));
5540     in.clear();
5541     r = store->read(cid, hoid, block_size*2, block_size, in);
5542     ASSERT_EQ((int)block_size, r);
5543     ASSERT_TRUE(bl_eq(orig, in));
5544
5545     g_conf->set_val("bluestore_csum_type", "crc32c");
5546     g_conf->apply_changes(NULL);
5547     in.clear();
5548     r = store->read(cid, hoid, 0, block_size, in);
5549     ASSERT_EQ((int)block_size, r);
5550     ASSERT_TRUE(bl_eq(orig, in));
5551     in.clear();
5552     r = store->read(cid, hoid, block_size*2, block_size, in);
5553     ASSERT_EQ((int)block_size, r);
5554     ASSERT_TRUE(bl_eq(orig, in));
5555   }
5556   {
5557     //partially blob overwrite under a different csum enablement mode
5558
5559     ObjectStore::Transaction t;
5560     bufferlist bl, orig, orig2;
5561     size_t block_size0 = 0x10000;
5562     size_t block_size = 9000;
5563     size_t block_size2 = 5000;
5564     bl.append(std::string(block_size0, 'a'));
5565     t.remove(cid, hoid);
5566     t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
5567     t.write(cid, hoid, 0, bl.length(), bl);
5568     cerr << "Remove then create" << std::endl;
5569     r = apply_transaction(store, &osr, std::move(t));
5570     ASSERT_EQ(r, 0);
5571
5572     g_conf->set_val("bluestore_csum_type", "none");
5573     g_conf->apply_changes(NULL);
5574
5575     ObjectStore::Transaction t2;
5576     bl.clear();
5577     bl.append(std::string(block_size, 'b'));
5578     t2.write(cid, hoid, 0, bl.length(), bl);
5579     t2.write(cid, hoid, block_size0, bl.length(), bl);
5580     cerr << "Overwrite with unprotected data" << std::endl;
5581     r = apply_transaction(store, &osr, std::move(t2));
5582     ASSERT_EQ(r, 0);
5583
5584     orig = bl;
5585     orig2 = bl;
5586     orig.append( std::string(block_size0 - block_size, 'a'));
5587
5588     bufferlist in;
5589     r = store->read(cid, hoid, 0, block_size0, in);
5590     ASSERT_EQ((int)block_size0, r);
5591     ASSERT_TRUE(bl_eq(orig, in));
5592
5593     r = store->read(cid, hoid, block_size0, block_size, in);
5594     ASSERT_EQ((int)block_size, r);
5595     ASSERT_TRUE(bl_eq(orig2, in));
5596
5597     g_conf->set_val("bluestore_csum_type", "crc32c");
5598     g_conf->apply_changes(NULL);
5599
5600     ObjectStore::Transaction t3;
5601     bl.clear();
5602     bl.append(std::string(block_size2, 'c'));
5603     t3.write(cid, hoid, block_size0, bl.length(), bl);
5604     cerr << "Overwrite with protected data" << std::endl;
5605     r = apply_transaction(store, &osr, std::move(t3));
5606     ASSERT_EQ(r, 0);
5607
5608     in.clear();
5609     orig = bl;
5610     orig.append( std::string(block_size - block_size2, 'b'));
5611     r = store->read(cid, hoid, block_size0, block_size, in);
5612     ASSERT_EQ((int)block_size, r);
5613     ASSERT_TRUE(bl_eq(orig, in));
5614   }
5615
5616   {
5617     ObjectStore::Transaction t;
5618     t.remove(cid, hoid);
5619     t.remove_collection(cid);
5620     cerr << "Cleaning" << std::endl;
5621     r = apply_transaction(store, &osr, std::move(t));
5622     ASSERT_EQ(r, 0);
5623   }
5624 }
5625 #endif
5626
5627 INSTANTIATE_TEST_CASE_P(
5628   ObjectStore,
5629   StoreTest,
5630   ::testing::Values(
5631     "memstore",
5632     "filestore",
5633 #if defined(HAVE_LIBAIO)
5634     "bluestore",
5635 #endif
5636     "kstore"));
5637
5638 // Note: instantiate all stores to preserve store numbering order only
5639 INSTANTIATE_TEST_CASE_P(
5640   ObjectStore,
5641   StoreTestSpecificAUSize,
5642   ::testing::Values(
5643     "memstore",
5644     "filestore",
5645 #if defined(HAVE_LIBAIO)
5646     "bluestore",
5647 #endif
5648     "kstore"));
5649
5650 #else
5651
5652 // Google Test may not support value-parameterized tests with some
5653 // compilers. If we use conditional compilation to compile out all
5654 // code referring to the gtest_main library, MSVC linker will not link
5655 // that library at all and consequently complain about missing entry
5656 // point defined in that library (fatal error LNK1561: entry point
5657 // must be defined). This dummy test keeps gtest_main linked in.
5658 TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
5659
5660 #endif
5661
5662 void doMany4KWritesTest(boost::scoped_ptr<ObjectStore>& store,
5663                         unsigned max_objects,
5664                         unsigned max_ops,
5665                         unsigned max_object_size,
5666                         unsigned max_write_size,
5667                         unsigned write_alignment,
5668                         store_statfs_t* res_stat)
5669 {
5670   ObjectStore::Sequencer osr("test");
5671   MixedGenerator gen(555);
5672   gen_type rng(time(NULL));
5673   coll_t cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD));
5674
5675   SyntheticWorkloadState test_obj(store.get(),
5676                                   &gen,
5677                                   &rng,
5678                                   &osr,
5679                                   cid,
5680                                   max_object_size,
5681                                   max_write_size,
5682                                   write_alignment);
5683   test_obj.init();
5684   for (unsigned i = 0; i < max_objects; ++i) {
5685     if (!(i % 500)) cerr << "seeding object " << i << std::endl;
5686     test_obj.touch();
5687   }
5688   for (unsigned i = 0; i < max_ops; ++i) {
5689     if (!(i % 200)) {
5690       cerr << "Op " << i << std::endl;
5691       test_obj.print_internal_state();
5692     }
5693     test_obj.write();
5694   }
5695   test_obj.wait_for_done();
5696   if (res_stat) {
5697     test_obj.statfs(*res_stat);
5698   }
5699   test_obj.shutdown();
5700 }
5701
5702 TEST_P(StoreTestSpecificAUSize, Many4KWritesTest) {
5703   if (string(GetParam()) != "bluestore")
5704     return;
5705
5706   StartDeferred(0x10000);
5707
5708   store_statfs_t res_stat;
5709   unsigned max_object = 4*1024*1024;
5710
5711   doMany4KWritesTest(store, 1, 1000, 4*1024*1024, 4*1024, 0, &res_stat);
5712
5713   ASSERT_LE(res_stat.stored, max_object);
5714   ASSERT_EQ(res_stat.allocated, max_object);
5715 }
5716
5717 TEST_P(StoreTestSpecificAUSize, Many4KWritesNoCSumTest) {
5718   if (string(GetParam()) != "bluestore")
5719     return;
5720   StartDeferred(0x10000);
5721   g_conf->set_val("bluestore_csum_type", "none");
5722   g_ceph_context->_conf->apply_changes(NULL);
5723   store_statfs_t res_stat;
5724   unsigned max_object = 4*1024*1024;
5725
5726   doMany4KWritesTest(store, 1, 1000, max_object, 4*1024, 0, &res_stat );
5727
5728   ASSERT_LE(res_stat.stored, max_object);
5729   ASSERT_EQ(res_stat.allocated, max_object);
5730   g_conf->set_val("bluestore_csum_type", "crc32c");
5731 }
5732
5733 TEST_P(StoreTestSpecificAUSize, TooManyBlobsTest) {
5734   if (string(GetParam()) != "bluestore")
5735     return;
5736   StartDeferred(0x10000);
5737   store_statfs_t res_stat;
5738   unsigned max_object = 4*1024*1024;
5739   doMany4KWritesTest(store, 1, 1000, max_object, 4*1024, 0, &res_stat);
5740   ASSERT_LE(res_stat.stored, max_object);
5741   ASSERT_EQ(res_stat.allocated, max_object);
5742 }
5743
5744 #if defined(HAVE_LIBAIO)
5745 void get_mempool_stats(uint64_t* total_bytes, uint64_t* total_items)
5746 {
5747   uint64_t onode_allocated = mempool::bluestore_cache_onode::allocated_bytes();
5748   uint64_t other_allocated = mempool::bluestore_cache_other::allocated_bytes();
5749
5750   uint64_t onode_items = mempool::bluestore_cache_onode::allocated_items();
5751   uint64_t other_items = mempool::bluestore_cache_other::allocated_items();
5752   cout << "onode(" << onode_allocated << "/" << onode_items
5753        << ") other(" << other_allocated << "/" << other_items
5754        << ")" << std::endl;
5755   *total_bytes = onode_allocated + other_allocated;
5756   *total_items = onode_items;
5757 }
5758
5759 TEST_P(StoreTestSpecificAUSize, OnodeSizeTracking) {
5760
5761   if (string(GetParam()) != "bluestore")
5762     return;
5763
5764   size_t block_size = 4096;
5765   StartDeferred(block_size);
5766   g_conf->set_val("bluestore_compression_mode", "none");
5767   g_conf->set_val("bluestore_csum_type", "none");
5768   g_conf->set_val("bluestore_cache_size_hdd", "400000000");
5769   g_conf->set_val("bluestore_cache_size_ssd", "400000000");
5770   g_conf->apply_changes(NULL);
5771
5772   ObjectStore::Sequencer osr("test");
5773   int r;
5774   coll_t cid;
5775   ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
5776   size_t obj_size = 4 * 1024  * 1024;
5777   uint64_t total_bytes, total_bytes2;
5778   uint64_t total_onodes;
5779   get_mempool_stats(&total_bytes, &total_onodes);
5780   ASSERT_EQ(total_onodes, 0u);
5781
5782   {
5783     ObjectStore::Transaction t;
5784     t.create_collection(cid, 0);
5785     r = apply_transaction(store, &osr, std::move(t));
5786     ASSERT_EQ(r, 0);
5787   }
5788   {
5789     ObjectStore::Transaction t;
5790     bufferlist bl, orig, orig2;
5791     
5792     bl.append(std::string(obj_size, 'a'));
5793     t.write(cid, hoid, 0, bl.length(), bl);
5794     r = apply_transaction(store, &osr, std::move(t));
5795     ASSERT_EQ(r, 0);
5796   }
5797   get_mempool_stats(&total_bytes, &total_onodes);
5798   ASSERT_NE(total_bytes, 0u);
5799   ASSERT_EQ(total_onodes, 1u);
5800
5801   {
5802     ObjectStore::Transaction t;
5803     t.truncate(cid, hoid, 0);
5804     r = apply_transaction(store, &osr, std::move(t));
5805     ASSERT_EQ(r, 0);
5806   }
5807  
5808   for(size_t i = 0; i < 1; ++i) {
5809     bufferlist bl;
5810     bl.append(std::string(block_size * (i+1), 'a'));
5811     for( size_t j = 0; j < obj_size; j+= bl.length()) {
5812       ObjectStore::Transaction t;
5813       t.write(cid, hoid, j, bl.length(), bl);
5814       r = apply_transaction(store, &osr, std::move(t));
5815       ASSERT_EQ(r, 0);
5816     }
5817     get_mempool_stats(&total_bytes2, &total_onodes);
5818     ASSERT_NE(total_bytes2, 0u);
5819     ASSERT_EQ(total_onodes, 1u);
5820   }
5821   {
5822     cout <<" mempool dump:\n";
5823     JSONFormatter f(true);
5824     f.open_object_section("transaction");
5825     mempool::dump(&f);
5826     f.close_section();
5827     f.flush(cout);
5828     cout << std::endl;
5829   }
5830   {
5831     bufferlist bl;
5832     for (size_t i = 0; i < obj_size; i += 0x1000) {
5833       store->read(cid, hoid, i, 0x1000, bl);
5834     }
5835   }
5836   get_mempool_stats(&total_bytes, &total_onodes);
5837   ASSERT_NE(total_bytes, 0u);
5838   ASSERT_EQ(total_onodes, 1u);
5839
5840   {
5841     cout <<" mempool dump:\n";
5842     JSONFormatter f(true);
5843     f.open_object_section("transaction");
5844     mempool::dump(&f);
5845     f.close_section();
5846     f.flush(cout);
5847     cout << std::endl;
5848   }
5849   {
5850     ObjectStore::Transaction t;
5851     t.remove(cid, hoid);
5852     t.remove_collection(cid);
5853     cerr << "Cleaning" << std::endl;
5854     r = apply_transaction(store, &osr, std::move(t));
5855     ASSERT_EQ(r, 0);
5856   }
5857   g_ceph_context->_conf->set_val("bluestore_cache_size_hdd", "4000000");
5858   g_ceph_context->_conf->set_val("bluestore_cache_size_ssd", "4000000");
5859   g_conf->set_val("bluestore_compression_mode", "none");
5860   g_conf->set_val("bluestore_csum_type", "crc32c");
5861
5862 }
5863
5864 TEST_P(StoreTestSpecificAUSize, BlobReuseOnOverwrite) {
5865
5866   if (string(GetParam()) != "bluestore")
5867     return;
5868
5869   size_t block_size = 4096;
5870   StartDeferred(block_size);
5871   g_conf->set_val("bluestore_max_blob_size", "65536");
5872   g_conf->apply_changes(NULL);
5873
5874   ObjectStore::Sequencer osr("test");
5875   int r;
5876   coll_t cid;
5877   ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
5878
5879   const PerfCounters* logger = store->get_perf_counters();
5880
5881   {
5882     ObjectStore::Transaction t;
5883     t.create_collection(cid, 0);
5884     r = apply_transaction(store, &osr, std::move(t));
5885     ASSERT_EQ(r, 0);
5886   }
5887   {
5888     ObjectStore::Transaction t;
5889     bufferlist bl;
5890
5891     bl.append(std::string(block_size * 2, 'a'));
5892     t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5893     r = apply_transaction(store, &osr, std::move(t));
5894     ASSERT_EQ(r, 0);
5895   }
5896   {
5897     // overwrite at the beginning
5898     ObjectStore::Transaction t;
5899     bufferlist bl;
5900
5901     bl.append(std::string(block_size, 'b'));
5902     t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5903     r = apply_transaction(store, &osr, std::move(t));
5904     ASSERT_EQ(r, 0);
5905   }
5906   {
5907     // append
5908     ObjectStore::Transaction t;
5909     bufferlist bl;
5910
5911     bl.append(std::string(block_size * 2, 'c'));
5912     t.write(cid, hoid, block_size * 2, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5913     r = apply_transaction(store, &osr, std::move(t));
5914     ASSERT_EQ(r, 0);
5915   }
5916   {
5917     // append with a gap
5918     ObjectStore::Transaction t;
5919     bufferlist bl;
5920
5921     bl.append(std::string(block_size * 2, 'd'));
5922     t.write(cid, hoid, block_size * 5, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5923     r = apply_transaction(store, &osr, std::move(t));
5924     ASSERT_EQ(r, 0);
5925   }
5926   {
5927     // We need to issue a read to trigger cache stat update that refresh
5928     // perf counters. additionally we need to wait some time for mempool
5929     // thread to update stats.
5930     sleep(1);
5931     bufferlist bl, expected;
5932     r = store->read(cid, hoid, 0, block_size, bl);
5933     ASSERT_EQ(r, (int)block_size);
5934     expected.append(string(block_size, 'b'));
5935     ASSERT_TRUE(bl_eq(expected, bl));
5936     ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
5937     ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
5938   }
5939   {
5940     // overwrite at end
5941     ObjectStore::Transaction t;
5942     bufferlist bl;
5943
5944     bl.append(std::string(block_size * 2, 'e'));
5945
5946     // Currently we are unable to reuse blob when overwriting in a single step
5947     t.write(cid, hoid, block_size * 6, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5948     r = apply_transaction(store, &osr, std::move(t));
5949     ASSERT_EQ(r, 0);
5950   }
5951   {
5952     // We need to issue a read to trigger cache stat update that refresh
5953     // perf counters. additionally we need to wait some time for mempool
5954     // thread to update stats.
5955     sleep(1);
5956     bufferlist bl, expected;
5957     r = store->read(cid, hoid, 0, block_size, bl);
5958     ASSERT_EQ(r, (int)block_size);
5959     expected.append(string(block_size, 'b'));
5960     ASSERT_TRUE(bl_eq(expected, bl));
5961     ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
5962     ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
5963   }
5964   {
5965     // fill the gap
5966     ObjectStore::Transaction t;
5967     bufferlist bl;
5968
5969     bl.append(std::string(block_size, 'f'));
5970
5971     t.write(cid, hoid, block_size * 4, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5972     r = apply_transaction(store, &osr, std::move(t));
5973     ASSERT_EQ(r, 0);
5974   }
5975   {
5976     // we need to wait some time for mempool
5977     // thread to update stats to be able to check blob/extent numbers from
5978     // perf counters.
5979     sleep(1);
5980
5981     bufferlist bl, expected;
5982     r = store->read(cid, hoid, 0, block_size, bl);
5983     ASSERT_EQ(r, (int)block_size);
5984     expected.append(string(block_size, 'b'));
5985     ASSERT_TRUE(bl_eq(expected, bl));
5986
5987     bl.clear();
5988     expected.clear();
5989     r = store->read(cid, hoid, block_size, block_size, bl);
5990     ASSERT_EQ(r, (int)block_size);
5991     expected.append(string(block_size, 'a'));
5992     ASSERT_TRUE(bl_eq(expected, bl));
5993
5994     bl.clear();
5995     expected.clear();
5996     r = store->read(cid, hoid, block_size * 2, block_size * 2, bl);
5997     ASSERT_EQ(r, (int)block_size * 2);
5998     expected.append(string(block_size * 2, 'c'));
5999     ASSERT_TRUE(bl_eq(expected, bl));
6000
6001     bl.clear();
6002     expected.clear();
6003     r = store->read(cid, hoid, block_size * 4, block_size, bl);
6004     ASSERT_EQ(r, (int)block_size);
6005     expected.append(string(block_size, 'f'));
6006     ASSERT_TRUE(bl_eq(expected, bl));
6007
6008     bl.clear();
6009     expected.clear();
6010     r = store->read(cid, hoid, block_size * 5, block_size, bl);
6011     ASSERT_EQ(r, (int)block_size);
6012     expected.append(string(block_size, 'd'));
6013     ASSERT_TRUE(bl_eq(expected, bl));
6014
6015     bl.clear();
6016     expected.clear();
6017     r = store->read(cid, hoid, block_size * 5, block_size * 3, bl);
6018     ASSERT_EQ(r, (int)block_size * 3);
6019     expected.append(string(block_size, 'd'));
6020     expected.append(string(block_size * 2, 'e'));
6021     ASSERT_TRUE(bl_eq(expected, bl));
6022   }
6023   ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6024   ASSERT_EQ(logger->get(l_bluestore_extents), 1u);
6025
6026
6027   {
6028     ObjectStore::Transaction t;
6029     t.remove(cid, hoid);
6030     t.remove_collection(cid);
6031     cerr << "Cleaning" << std::endl;
6032     r = apply_transaction(store, &osr, std::move(t));
6033     ASSERT_EQ(r, 0);
6034   }
6035   g_conf->set_val("bluestore_max_blob_size", "0");
6036
6037 }
6038
6039 TEST_P(StoreTestSpecificAUSize, BlobReuseOnOverwriteReverse) {
6040
6041   if (string(GetParam()) != "bluestore")
6042     return;
6043
6044   size_t block_size = 4096;
6045   StartDeferred(block_size);
6046   g_conf->set_val("bluestore_max_blob_size", "65536");
6047
6048   g_conf->apply_changes(NULL);
6049
6050   ObjectStore::Sequencer osr("test");
6051   int r;
6052   coll_t cid;
6053   ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
6054
6055   const PerfCounters* logger = store->get_perf_counters();
6056   {
6057     ObjectStore::Transaction t;
6058     t.create_collection(cid, 0);
6059     r = apply_transaction(store, &osr, std::move(t));
6060     ASSERT_EQ(r, 0);
6061   }
6062   {
6063     ObjectStore::Transaction t;
6064     bufferlist bl;
6065
6066     bl.append(std::string(block_size * 2, 'a'));
6067     t.write(cid, hoid, block_size * 10, bl.length(), bl, 
6068             CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6069     r = apply_transaction(store, &osr, std::move(t));
6070     ASSERT_EQ(r, 0);
6071   }
6072   {
6073     // prepend existing
6074     ObjectStore::Transaction t;
6075     bufferlist bl;
6076
6077     bl.append(std::string(block_size, 'b'));
6078     t.write(cid, hoid, block_size * 9, bl.length(), bl,
6079             CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6080     r = apply_transaction(store, &osr, std::move(t));
6081     ASSERT_EQ(r, 0);
6082   }
6083   {
6084     // We need to issue a read to trigger cache stat update that refresh
6085     // perf counters. additionally we need to wait some time for mempool
6086     // thread to update stats.
6087     sleep(1);
6088     bufferlist bl, expected;
6089     r = store->read(cid, hoid, block_size * 9, block_size * 2, bl);
6090     ASSERT_EQ(r, (int)block_size * 2);
6091     expected.append(string(block_size, 'b'));
6092     expected.append(string(block_size, 'a'));
6093     ASSERT_TRUE(bl_eq(expected, bl));
6094     ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6095     ASSERT_EQ(logger->get(l_bluestore_extents), 1u);
6096   }
6097
6098
6099   {
6100     // prepend existing with a gap
6101     ObjectStore::Transaction t;
6102     bufferlist bl;
6103
6104     bl.append(std::string(block_size, 'c'));
6105     t.write(cid, hoid, block_size * 7, bl.length(), bl,
6106             CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6107     r = apply_transaction(store, &osr, std::move(t));
6108     ASSERT_EQ(r, 0);
6109   }
6110   {
6111     // We need to issue a read to trigger cache stat update that refresh
6112     // perf counters. additionally we need to wait some time for mempool
6113     // thread to update stats.
6114     sleep(1);
6115     bufferlist bl, expected;
6116     r = store->read(cid, hoid, block_size * 7, block_size * 3, bl);
6117     ASSERT_EQ(r, (int)block_size * 3);
6118     expected.append(string(block_size, 'c'));
6119     expected.append(string(block_size, 0));
6120     expected.append(string(block_size, 'b'));
6121     ASSERT_TRUE(bl_eq(expected, bl));
6122     ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6123     ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
6124   }
6125
6126   {
6127     // append after existing with a gap
6128     ObjectStore::Transaction t;
6129     bufferlist bl;
6130
6131     bl.append(std::string(block_size, 'd'));
6132     t.write(cid, hoid, block_size * 13, bl.length(), bl,
6133             CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6134     r = apply_transaction(store, &osr, std::move(t));
6135     ASSERT_EQ(r, 0);
6136   }
6137   {
6138     // We need to issue a read to trigger cache stat update that refresh
6139     // perf counters. additionally we need to wait some time for mempool
6140     // thread to update stats.
6141     sleep(1);
6142     bufferlist bl, expected;
6143     r = store->read(cid, hoid, block_size * 11, block_size * 3, bl);
6144     ASSERT_EQ(r, (int)block_size * 3);
6145     expected.append(string(block_size, 'a'));
6146     expected.append(string(block_size, 0));
6147     expected.append(string(block_size, 'd'));
6148     ASSERT_TRUE(bl_eq(expected, bl));
6149     ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6150     ASSERT_EQ(logger->get(l_bluestore_extents), 3u);
6151   }
6152
6153   {
6154     // append twice to the next max_blob slot
6155     ObjectStore::Transaction t;
6156     bufferlist bl;
6157
6158     bl.append(std::string(block_size, 'e'));
6159     t.write(cid, hoid, block_size * 17, bl.length(), bl,
6160             CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6161     t.write(cid, hoid, block_size * 19, bl.length(), bl,
6162             CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6163     r = apply_transaction(store, &osr, std::move(t));
6164     ASSERT_EQ(r, 0);
6165   }
6166   {
6167     // We need to issue a read to trigger cache stat update that refresh
6168     // perf counters. additionally we need to wait some time for mempool
6169     // thread to update stats.
6170     sleep(1);
6171     bufferlist bl, expected;
6172     r = store->read(cid, hoid, block_size * 17, block_size * 3, bl);
6173     ASSERT_EQ(r, (int)block_size * 3);
6174     expected.append(string(block_size, 'e'));
6175     expected.append(string(block_size, 0));
6176     expected.append(string(block_size, 'e'));
6177     ASSERT_TRUE(bl_eq(expected, bl));
6178     ASSERT_EQ(logger->get(l_bluestore_blobs), 2u);
6179     ASSERT_EQ(logger->get(l_bluestore_extents), 5u);
6180   }
6181   {
6182     // fill gaps at the second slot
6183     ObjectStore::Transaction t;
6184     bufferlist bl;
6185
6186     bl.append(std::string(block_size, 'f'));
6187     t.write(cid, hoid, block_size * 16, bl.length(), bl,
6188             CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6189     t.write(cid, hoid, block_size * 18, bl.length(), bl,
6190             CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6191     r = apply_transaction(store, &osr, std::move(t));
6192     ASSERT_EQ(r, 0);
6193   }
6194   {
6195     // We need to issue a read to trigger cache stat update that refresh
6196     // perf counters. additionally we need to wait some time for mempool
6197     // thread to update stats.
6198     sleep(1);
6199     bufferlist bl, expected;
6200     r = store->read(cid, hoid, block_size * 16, block_size * 4, bl);
6201     ASSERT_EQ(r, (int)block_size * 4);
6202     expected.append(string(block_size, 'f'));
6203     expected.append(string(block_size, 'e'));
6204     expected.append(string(block_size, 'f'));
6205     expected.append(string(block_size, 'e'));
6206     ASSERT_TRUE(bl_eq(expected, bl));
6207     ASSERT_EQ(logger->get(l_bluestore_blobs), 2u);
6208     ASSERT_EQ(logger->get(l_bluestore_extents), 4u);
6209   }
6210   {
6211     ObjectStore::Transaction t;
6212     t.remove(cid, hoid);
6213     t.remove_collection(cid);
6214     cerr << "Cleaning" << std::endl;
6215     r = apply_transaction(store, &osr, std::move(t));
6216     ASSERT_EQ(r, 0);
6217   }
6218   g_conf->set_val("bluestore_max_blob_size", "0");
6219 }
6220
6221 TEST_P(StoreTestSpecificAUSize, BlobReuseOnSmallOverwrite) {
6222
6223   if (string(GetParam()) != "bluestore")
6224     return;
6225
6226   size_t block_size = 4096;
6227   StartDeferred(block_size);
6228   g_conf->set_val("bluestore_max_blob_size", "65536");
6229   g_conf->apply_changes(NULL);
6230
6231   ObjectStore::Sequencer osr("test");
6232   int r;
6233   coll_t cid;
6234   ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
6235
6236   const PerfCounters* logger = store->get_perf_counters();
6237
6238   {
6239     ObjectStore::Transaction t;
6240     t.create_collection(cid, 0);
6241     r = apply_transaction(store, &osr, std::move(t));
6242     ASSERT_EQ(r, 0);
6243   }
6244   {
6245     ObjectStore::Transaction t;
6246     bufferlist bl;
6247
6248     bl.append(std::string(block_size, 'a'));
6249     t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6250     t.write(cid, hoid, block_size * 2, bl.length(), bl,
6251       CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6252     r = apply_transaction(store, &osr, std::move(t));
6253     ASSERT_EQ(r, 0);
6254   }
6255   {
6256     // write small into the gap
6257     ObjectStore::Transaction t;
6258     bufferlist bl;
6259
6260     bl.append(std::string(3, 'b'));
6261     t.write(cid, hoid, block_size + 1, bl.length(), bl,
6262       CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6263     r = apply_transaction(store, &osr, std::move(t));
6264     ASSERT_EQ(r, 0);
6265   }
6266   {
6267     // We need to issue a read to trigger cache stat update that refresh
6268     // perf counters. additionally we need to wait some time for mempool
6269     // thread to update stats.
6270     sleep(1);
6271     bufferlist bl, expected;
6272     r = store->read(cid, hoid, 0, block_size * 3, bl);
6273     ASSERT_EQ(r, (int)block_size * 3);
6274     expected.append(string(block_size, 'a'));
6275     expected.append(string(1, 0));
6276     expected.append(string(3, 'b'));
6277     expected.append(string(block_size - 4, 0));
6278     expected.append(string(block_size, 'a'));
6279     ASSERT_TRUE(bl_eq(expected, bl));
6280
6281     ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6282     ASSERT_EQ(logger->get(l_bluestore_extents), 3u);
6283   }
6284   {
6285     ObjectStore::Transaction t;
6286     t.remove(cid, hoid);
6287     t.remove_collection(cid);
6288     cerr << "Cleaning" << std::endl;
6289     r = apply_transaction(store, &osr, std::move(t));
6290     ASSERT_EQ(r, 0);
6291   }
6292   g_conf->set_val("bluestore_max_blob_size", "0");
6293 }
6294
6295 // The test case to reproduce an issue when write happens
6296 // to a zero space between the extents sharing the same spanning blob
6297 // with unloaded shard map.
6298 // Second extent might be filled with zeros this way due to wrong result
6299 // returned by has_any_extents() call in do_write_small. The latter is caused
6300 // by incompletly loaded extent map.
6301 TEST_P(StoreTestSpecificAUSize, SmallWriteOnShardedExtents) {
6302   if (string(GetParam()) != "bluestore")
6303     return;
6304
6305   size_t block_size = 0x10000;
6306   StartDeferred(block_size);
6307
6308   g_conf->set_val("bluestore_csum_type", "xxhash64");
6309   g_conf->set_val("bluestore_max_target_blob", "524288"); // for sure
6310
6311   g_conf->apply_changes(NULL);
6312
6313   ObjectStore::Sequencer osr("test");
6314   int r;
6315   coll_t cid;
6316   ghobject_t hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
6317
6318   {
6319     ObjectStore::Transaction t;
6320     t.create_collection(cid, 0);
6321     r = apply_transaction(store, &osr, std::move(t));
6322     ASSERT_EQ(r, 0);
6323   }
6324   {
6325    //doing some tricks to have sharded extents/spanning objects
6326     ObjectStore::Transaction t;
6327     bufferlist bl, bl2;
6328
6329     bl.append(std::string(0x80000, 'a'));
6330     t.write(cid, hoid1, 0, bl.length(), bl, 0);
6331     t.zero(cid, hoid1, 0x719e0, 0x75b0 );
6332     r = apply_transaction(store, &osr, std::move(t));
6333     ASSERT_EQ(r, 0);
6334
6335     bl2.append(std::string(0x70000, 'b'));
6336     t.write(cid, hoid1, 0, bl2.length(), bl2, 0);
6337     t.zero(cid, hoid1, 0, 0x50000);
6338     r = apply_transaction(store, &osr, std::move(t));
6339     ASSERT_EQ(r, 0);
6340
6341   }
6342   store->umount();
6343   store->mount();
6344
6345   {
6346     // do a write to zero space in between some extents sharing the same blob
6347     ObjectStore::Transaction t;
6348     bufferlist bl, bl2;
6349
6350     bl.append(std::string(0x6520, 'c'));
6351     t.write(cid, hoid1, 0x71c00, bl.length(), bl, 0);
6352
6353     r = apply_transaction(store, &osr, std::move(t));
6354     ASSERT_EQ(r, 0);
6355   }
6356
6357   {
6358     ObjectStore::Transaction t;
6359     bufferlist bl, expected;
6360
6361     r = store->read(cid, hoid1, 0x70000, 0x9c00, bl);
6362     ASSERT_EQ(r, (int)0x9c00);
6363     expected.append(string(0x19e0, 'a'));
6364     expected.append(string(0x220, 0));
6365     expected.append(string(0x6520, 'c'));
6366     expected.append(string(0xe70, 0));
6367     expected.append(string(0xc70, 'a'));
6368     ASSERT_TRUE(bl_eq(expected, bl));
6369     bl.clear();
6370
6371   }
6372
6373   {
6374     ObjectStore::Transaction t;
6375     t.remove(cid, hoid1);
6376     t.remove_collection(cid);
6377     cerr << "Cleaning" << std::endl;
6378     r = apply_transaction(store, &osr, std::move(t));
6379     ASSERT_EQ(r, 0);
6380   }
6381   g_conf->set_val("bluestore_max_target_blob", "524288");
6382   g_conf->set_val("bluestore_csum_type", "crc32c");
6383 }
6384
6385 #endif //#if defined(HAVE_LIBAIO)
6386
6387 TEST_P(StoreTest, KVDBHistogramTest) {
6388   if (string(GetParam()) != "bluestore")
6389     return;
6390
6391   ObjectStore::Sequencer osr("test");
6392   int NUM_OBJS = 200;
6393   int r = 0;
6394   coll_t cid;
6395   string base("testobj.");
6396   bufferlist a;
6397   bufferptr ap(0x1000);
6398   memset(ap.c_str(), 'a', 0x1000);
6399   a.append(ap);
6400   {
6401     ObjectStore::Transaction t;
6402     t.create_collection(cid, 0);
6403     r = apply_transaction(store, &osr, std::move(t));
6404     ASSERT_EQ(r, 0);
6405   }
6406   for (int i = 0; i < NUM_OBJS; ++i) {
6407     ObjectStore::Transaction t;
6408     char buf[100];
6409     snprintf(buf, sizeof(buf), "%d", i);
6410     ghobject_t hoid(hobject_t(sobject_t(base + string(buf), CEPH_NOSNAP)));
6411     t.write(cid, hoid, 0, 0x1000, a);
6412     r = apply_transaction(store, &osr, std::move(t));
6413     ASSERT_EQ(r, 0);
6414   }
6415
6416   Formatter *f = Formatter::create("store_test", "json-pretty", "json-pretty");
6417   store->generate_db_histogram(f);
6418   f->flush(cout);
6419   cout << std::endl;
6420 }
6421
6422 TEST_P(StoreTest, KVDBStatsTest) {
6423   if (string(GetParam()) != "bluestore")
6424     return;
6425
6426   g_conf->set_val("rocksdb_perf", "true");
6427   g_conf->set_val("rocksdb_collect_compaction_stats", "true");
6428   g_conf->set_val("rocksdb_collect_extended_stats","true");
6429   g_conf->set_val("rocksdb_collect_memory_stats","true");
6430   g_ceph_context->_conf->apply_changes(NULL);
6431   int r = store->umount();
6432   ASSERT_EQ(r, 0);
6433   r = store->mount(); //to force rocksdb stats
6434   ASSERT_EQ(r, 0);
6435
6436   ObjectStore::Sequencer osr("test");
6437   int NUM_OBJS = 200;
6438   coll_t cid;
6439   string base("testobj.");
6440   bufferlist a;
6441   bufferptr ap(0x1000);
6442   memset(ap.c_str(), 'a', 0x1000);
6443   a.append(ap);
6444   {
6445     ObjectStore::Transaction t;
6446     t.create_collection(cid, 0);
6447     r = apply_transaction(store, &osr, std::move(t));
6448     ASSERT_EQ(r, 0);
6449   }
6450   for (int i = 0; i < NUM_OBJS; ++i) {
6451     ObjectStore::Transaction t;
6452     char buf[100];
6453     snprintf(buf, sizeof(buf), "%d", i);
6454     ghobject_t hoid(hobject_t(sobject_t(base + string(buf), CEPH_NOSNAP)));
6455     t.write(cid, hoid, 0, 0x1000, a);
6456     r = apply_transaction(store, &osr, std::move(t));
6457     ASSERT_EQ(r, 0);
6458   }
6459
6460   Formatter *f = Formatter::create("store_test", "json-pretty", "json-pretty");
6461   store->get_db_statistics(f);
6462   f->flush(cout);
6463   cout << std::endl;
6464   g_conf->set_val("rocksdb_perf", "false");
6465   g_conf->set_val("rocksdb_collect_compaction_stats", "false");
6466   g_conf->set_val("rocksdb_collect_extended_stats","false");
6467   g_conf->set_val("rocksdb_collect_memory_stats","false");
6468 }
6469
6470 #if defined(HAVE_LIBAIO)
6471 TEST_P(StoreTestSpecificAUSize, garbageCollection) {
6472   ObjectStore::Sequencer osr("test");
6473   int r;
6474   coll_t cid;
6475   int buf_len = 256 * 1024;
6476   int overlap_offset = 64 * 1024;
6477   int write_offset = buf_len;
6478   if (string(GetParam()) != "bluestore")
6479     return;
6480
6481 #define WRITE_AT(offset, _length) {\
6482       ObjectStore::Transaction t;\
6483       if ((uint64_t)_length != bl.length()) { \
6484         buffer::ptr p(bl.c_str(), _length);\
6485         bufferlist bl_tmp;\
6486         bl_tmp.push_back(p);\
6487         t.write(cid, hoid, offset, bl_tmp.length(), bl_tmp);\
6488       } else {\
6489         t.write(cid, hoid, offset, bl.length(), bl);\
6490       }\
6491       r = apply_transaction(store, &osr, std::move(t));\
6492       ASSERT_EQ(r, 0);\
6493   }
6494
6495   StartDeferred(65536);
6496
6497   g_conf->set_val("bluestore_compression_max_blob_size", "524288");
6498   g_conf->set_val("bluestore_compression_min_blob_size", "262144");
6499   g_conf->set_val("bluestore_compression_mode", "force");
6500   g_conf->apply_changes(NULL);
6501
6502   ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
6503   {
6504     bufferlist in;
6505     r = store->read(cid, hoid, 0, 5, in);
6506     ASSERT_EQ(-ENOENT, r);
6507   }
6508   {
6509     ObjectStore::Transaction t;
6510     t.create_collection(cid, 0);
6511     cerr << "Creating collection " << cid << std::endl;
6512     r = apply_transaction(store, &osr, std::move(t));
6513     ASSERT_EQ(r, 0);
6514   }
6515
6516   std::string data;
6517   data.resize(buf_len);
6518
6519   {
6520     { 
6521       bool exists = store->exists(cid, hoid);
6522       ASSERT_TRUE(!exists);
6523
6524       ObjectStore::Transaction t;
6525       t.touch(cid, hoid);
6526       cerr << "Creating object " << hoid << std::endl;
6527       r = apply_transaction(store, &osr, std::move(t));
6528       ASSERT_EQ(r, 0);
6529
6530       exists = store->exists(cid, hoid);
6531       ASSERT_EQ(true, exists);
6532     } 
6533     bufferlist bl;
6534
6535     for(size_t i = 0; i < data.size(); i++)
6536       data[i] = i % 256;
6537
6538     bl.append(data);
6539
6540     {
6541       struct store_statfs_t statfs;
6542       WRITE_AT(0, buf_len);
6543       int r = store->statfs(&statfs);
6544       ASSERT_EQ(r, 0);
6545       ASSERT_EQ(statfs.compressed_allocated, 0x10000);
6546     }
6547     {
6548       struct store_statfs_t statfs;
6549       WRITE_AT(write_offset - 2 * overlap_offset, buf_len);
6550       int r = store->statfs(&statfs);
6551       ASSERT_EQ(r, 0);
6552       ASSERT_EQ(statfs.compressed_allocated, 0x20000);
6553       const PerfCounters* counters = store->get_perf_counters();
6554       ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0u);
6555     }
6556
6557     {
6558       struct store_statfs_t statfs;
6559       WRITE_AT(write_offset - overlap_offset, buf_len);
6560       int r = store->statfs(&statfs);
6561       ASSERT_EQ(r, 0);
6562       ASSERT_EQ(statfs.compressed_allocated, 0x20000);
6563       const PerfCounters* counters = store->get_perf_counters();
6564       ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x10000u);
6565     }
6566     {
6567       struct store_statfs_t statfs;
6568       WRITE_AT(write_offset - 3 * overlap_offset, buf_len);
6569       int r = store->statfs(&statfs);
6570       ASSERT_EQ(r, 0);
6571       ASSERT_EQ(statfs.compressed_allocated, 0x20000);
6572       const PerfCounters* counters = store->get_perf_counters();
6573       ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x20000u);
6574     }
6575     {
6576       struct store_statfs_t statfs;
6577       WRITE_AT(write_offset + 1, overlap_offset-1);
6578       int r = store->statfs(&statfs);
6579       ASSERT_EQ(r, 0);
6580       ASSERT_EQ(statfs.compressed_allocated, 0x20000);
6581       const PerfCounters* counters = store->get_perf_counters();
6582       ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x20000u);
6583     }
6584     {
6585       struct store_statfs_t statfs;
6586       WRITE_AT(write_offset + 1, overlap_offset);
6587       int r = store->statfs(&statfs);
6588       ASSERT_EQ(r, 0);
6589       ASSERT_EQ(statfs.compressed_allocated, 0x10000);
6590       const PerfCounters* counters = store->get_perf_counters();
6591       ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x3ffffu);
6592     }
6593     {
6594       struct store_statfs_t statfs;
6595       WRITE_AT(0, buf_len-1);
6596       int r = store->statfs(&statfs);
6597       ASSERT_EQ(r, 0);
6598       ASSERT_EQ(statfs.compressed_allocated, 0x10000);
6599       const PerfCounters* counters = store->get_perf_counters();
6600       ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40001u);
6601     }
6602     g_conf->set_val("bluestore_gc_enable_total_threshold", "1"); //forbid GC when saving = 0
6603     {
6604       struct store_statfs_t statfs;
6605       WRITE_AT(1, overlap_offset-2);
6606       WRITE_AT(overlap_offset * 2 + 1, overlap_offset-2);
6607       int r = store->statfs(&statfs);
6608       ASSERT_EQ(r, 0);
6609       ASSERT_EQ(statfs.compressed_allocated, 0x10000);
6610       const PerfCounters* counters = store->get_perf_counters();
6611       ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40001u);
6612     }
6613     {
6614       struct store_statfs_t statfs;
6615       WRITE_AT(overlap_offset + 1, overlap_offset-2);
6616       int r = store->statfs(&statfs);
6617       ASSERT_EQ(r, 0);
6618       ASSERT_EQ(statfs.compressed_allocated, 0x0);
6619       const PerfCounters* counters = store->get_perf_counters();
6620       ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40007u);
6621     }
6622     {
6623       ObjectStore::Transaction t;
6624       t.remove(cid, hoid);
6625       cerr << "Cleaning" << std::endl;
6626       r = apply_transaction(store, &osr, std::move(t));
6627       ASSERT_EQ(r, 0);
6628     }
6629   }
6630   g_conf->set_val("bluestore_gc_enable_total_threshold", "0");
6631   g_conf->set_val("bluestore_compression_min_blob_size", "0");
6632   g_conf->set_val("bluestore_compression_max_blob_size", "0");
6633   g_conf->set_val("bluestore_compression_mode", "none");
6634   g_conf->apply_changes(NULL);
6635 }
6636 #endif
6637
6638 int main(int argc, char **argv) {
6639   vector<const char*> args;
6640   argv_to_vec(argc, (const char **)argv, args);
6641   env_to_vec(args);
6642
6643   auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
6644                          CODE_ENVIRONMENT_UTILITY, 0);
6645   common_init_finish(g_ceph_context);
6646
6647   g_ceph_context->_conf->set_val("osd_journal_size", "400");
6648   g_ceph_context->_conf->set_val("filestore_index_retry_probability", "0.5");
6649   g_ceph_context->_conf->set_val("filestore_op_thread_timeout", "1000");
6650   g_ceph_context->_conf->set_val("filestore_op_thread_suicide_timeout", "10000");
6651   //g_ceph_context->_conf->set_val("filestore_fiemap", "true");
6652   g_ceph_context->_conf->set_val("bluestore_fsck_on_mount", "true");
6653   g_ceph_context->_conf->set_val("bluestore_fsck_on_umount", "true");
6654   g_ceph_context->_conf->set_val("bluestore_debug_misc", "true");
6655   g_ceph_context->_conf->set_val("bluestore_debug_small_allocations", "4");
6656   g_ceph_context->_conf->set_val("bluestore_debug_freelist", "true");
6657   g_ceph_context->_conf->set_val("bluestore_clone_cow", "true");
6658   g_ceph_context->_conf->set_val("bluestore_max_alloc_size", "196608");
6659
6660   // set small cache sizes so we see trimming during Synthetic tests
6661   g_ceph_context->_conf->set_val("bluestore_cache_size_hdd", "4000000");
6662   g_ceph_context->_conf->set_val("bluestore_cache_size_ssd", "4000000");
6663
6664   // very short *_max prealloc so that we fall back to async submits
6665   g_ceph_context->_conf->set_val("bluestore_blobid_prealloc", "10");
6666   g_ceph_context->_conf->set_val("bluestore_nid_prealloc", "10");
6667   g_ceph_context->_conf->set_val("bluestore_debug_randomize_serial_transaction",
6668                                  "10");
6669
6670   g_ceph_context->_conf->set_val("bdev_debug_aio", "true");
6671
6672   // specify device size
6673   g_ceph_context->_conf->set_val("bluestore_block_size", "10240000000");
6674
6675   g_ceph_context->_conf->set_val(
6676     "enable_experimental_unrecoverable_data_corrupting_features", "*");
6677   g_ceph_context->_conf->apply_changes(NULL);
6678
6679   ::testing::InitGoogleTest(&argc, argv);
6680   return RUN_ALL_TESTS();
6681 }
6682
6683 /*
6684  * Local Variables:
6685  * compile-command: "cd ../.. ; make ceph_test_objectstore && 
6686  *    ./ceph_test_objectstore \
6687  *        --gtest_filter=*.collect_metadata* --log-to-stderr=true --debug-filestore=20
6688  *  "
6689  * End:
6690  */