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