]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/objectstore/store_test.cc
c3e5c021c241b180d0b7731b542cb7ccc09ea4e9
[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 #include "os/bluestore/BlueFS.h"
32 #endif
33 #include "include/Context.h"
34 #include "common/ceph_argparse.h"
35 #include "common/admin_socket.h"
36 #include "global/global_init.h"
37 #include "common/ceph_mutex.h"
38 #include "common/Cond.h"
39 #include "common/errno.h"
40 #include "include/stringify.h"
41 #include "include/coredumpctl.h"
42
43 #include "include/unordered_map.h"
44 #include "store_test_fixture.h"
45
46 using namespace std::placeholders;
47
48 typedef boost::mt11213b gen_type;
49
50 const uint64_t DEF_STORE_TEST_BLOCKDEV_SIZE = 10240000000;
51 #define dout_context g_ceph_context
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, ReproBug41901Test) {
1319 if(string(GetParam()) != "bluestore")
1320 return;
1321 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
1322 g_conf().apply_changes(nullptr);
1323 StartDeferred(65536);
1324
1325 int r;
1326 coll_t cid;
1327 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1328 const PerfCounters* logger = store->get_perf_counters();
1329 auto ch = store->create_new_collection(cid);
1330 {
1331 ObjectStore::Transaction t;
1332 t.create_collection(cid, 0);
1333 cerr << "Creating collection " << cid << std::endl;
1334 r = queue_transaction(store, ch, std::move(t));
1335 ASSERT_EQ(r, 0);
1336 }
1337 {
1338 bool exists = store->exists(ch, hoid);
1339 ASSERT_TRUE(!exists);
1340
1341 ObjectStore::Transaction t;
1342 t.touch(cid, hoid);
1343 cerr << "Creating object " << hoid << std::endl;
1344 r = queue_transaction(store, ch, std::move(t));
1345 ASSERT_EQ(r, 0);
1346
1347 exists = store->exists(ch, hoid);
1348 ASSERT_EQ(true, exists);
1349 }
1350 {
1351 ObjectStore::Transaction t;
1352 bufferlist bl, orig;
1353 string s(4096, 'a');
1354 bl.append(s);
1355 t.write(cid, hoid, 0x11000, bl.length(), bl);
1356 cerr << "write1" << std::endl;
1357 r = queue_transaction(store, ch, std::move(t));
1358 ASSERT_EQ(r, 0);
1359 }
1360 {
1361 ObjectStore::Transaction t;
1362 bufferlist bl, orig;
1363 string s(4096 * 3, 'a');
1364 bl.append(s);
1365 t.write(cid, hoid, 0x15000, bl.length(), bl);
1366 cerr << "write2" << std::endl;
1367 r = queue_transaction(store, ch, std::move(t));
1368 ASSERT_EQ(r, 0);
1369 }
1370 ASSERT_EQ(logger->get(l_bluestore_write_small), 2u);
1371 ASSERT_EQ(logger->get(l_bluestore_write_small_unused), 1u);
1372
1373 {
1374 ObjectStore::Transaction t;
1375 bufferlist bl, orig;
1376 string s(4096 * 2, 'a');
1377 bl.append(s);
1378 t.write(cid, hoid, 0xe000, bl.length(), bl);
1379 cerr << "write3" << std::endl;
1380 r = queue_transaction(store, ch, std::move(t));
1381 ASSERT_EQ(r, 0);
1382 }
1383 ASSERT_EQ(logger->get(l_bluestore_write_small), 3u);
1384 ASSERT_EQ(logger->get(l_bluestore_write_small_unused), 2u);
1385
1386
1387 {
1388 ObjectStore::Transaction t;
1389 bufferlist bl, orig;
1390 string s(4096, 'a');
1391 bl.append(s);
1392 t.write(cid, hoid, 0xf000, bl.length(), bl);
1393 t.write(cid, hoid, 0x10000, bl.length(), bl);
1394 cerr << "write3" << std::endl;
1395 r = queue_transaction(store, ch, std::move(t));
1396 ASSERT_EQ(r, 0);
1397 }
1398 ASSERT_EQ(logger->get(l_bluestore_write_small), 5u);
1399 ASSERT_EQ(logger->get(l_bluestore_write_small_unused), 2u);
1400 {
1401 ObjectStore::Transaction t;
1402 t.remove(cid, hoid);
1403 t.remove_collection(cid);
1404 cerr << "Cleaning" << std::endl;
1405 r = queue_transaction(store, ch, std::move(t));
1406 ASSERT_EQ(r, 0);
1407 }
1408 }
1409
1410
1411 TEST_P(StoreTestSpecificAUSize, BluestoreStatFSTest) {
1412 if(string(GetParam()) != "bluestore")
1413 return;
1414 StartDeferred(65536);
1415 SetVal(g_conf(), "bluestore_compression_mode", "force");
1416 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
1417 // just a big number to disble gc
1418 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "100000");
1419 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
1420 g_conf().apply_changes(nullptr);
1421 int r;
1422
1423 int poolid = 4373;
1424 coll_t cid = coll_t(spg_t(pg_t(0, poolid), shard_id_t::NO_SHARD));
1425 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP),
1426 string(),
1427 0,
1428 poolid,
1429 string()));
1430 ghobject_t hoid2 = hoid;
1431 hoid2.hobj.snap = 1;
1432 {
1433 auto ch = store->open_collection(cid);
1434 ASSERT_FALSE(ch);
1435 }
1436 auto ch = store->create_new_collection(cid);
1437 {
1438 ObjectStore::Transaction t;
1439 t.create_collection(cid, 0);
1440 cerr << "Creating collection " << cid << std::endl;
1441 r = queue_transaction(store, ch, std::move(t));
1442 ASSERT_EQ(r, 0);
1443 }
1444 {
1445 bool exists = store->exists(ch, hoid);
1446 ASSERT_TRUE(!exists);
1447
1448 ObjectStore::Transaction t;
1449 t.touch(cid, hoid);
1450 cerr << "Creating object " << hoid << std::endl;
1451 r = queue_transaction(store, ch, std::move(t));
1452 ASSERT_EQ(r, 0);
1453
1454 exists = store->exists(ch, hoid);
1455 ASSERT_EQ(true, exists);
1456 }
1457 {
1458 struct store_statfs_t statfs;
1459 int r = store->statfs(&statfs);
1460 ASSERT_EQ(r, 0);
1461 ASSERT_EQ( 0u, statfs.allocated);
1462 ASSERT_EQ( 0u, statfs.data_stored);
1463 ASSERT_EQ(g_conf()->bluestore_block_size, statfs.total);
1464 ASSERT_TRUE(statfs.available > 0u && statfs.available < g_conf()->bluestore_block_size);
1465
1466 struct store_statfs_t statfs_pool;
1467 bool per_pool_omap;
1468 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1469 ASSERT_EQ(r, 0);
1470 ASSERT_EQ( 0u, statfs_pool.allocated);
1471 ASSERT_EQ( 0u, statfs_pool.data_stored);
1472
1473 //force fsck
1474 ch.reset();
1475 EXPECT_EQ(store->umount(), 0);
1476 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1477 EXPECT_EQ(store->mount(), 0);
1478 ch = store->open_collection(cid);
1479 }
1480 {
1481 ObjectStore::Transaction t;
1482 bufferlist bl;
1483 bl.append("abcde");
1484 t.write(cid, hoid, 0, 5, bl);
1485 cerr << "Append 5 bytes" << std::endl;
1486 r = queue_transaction(store, ch, std::move(t));
1487 ASSERT_EQ(r, 0);
1488
1489 struct store_statfs_t statfs;
1490 int r = store->statfs(&statfs);
1491 ASSERT_EQ(r, 0);
1492 ASSERT_EQ(5, statfs.data_stored);
1493 ASSERT_EQ(0x10000, statfs.allocated);
1494 ASSERT_EQ(0, statfs.data_compressed);
1495 ASSERT_EQ(0, statfs.data_compressed_original);
1496 ASSERT_EQ(0, statfs.data_compressed_allocated);
1497
1498 struct store_statfs_t statfs_pool;
1499 bool per_pool_omap;
1500 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1501 ASSERT_EQ(r, 0);
1502 ASSERT_EQ(5, statfs_pool.data_stored);
1503 ASSERT_EQ(0x10000, statfs_pool.allocated);
1504 ASSERT_EQ(0, statfs_pool.data_compressed);
1505 ASSERT_EQ(0, statfs_pool.data_compressed_original);
1506 ASSERT_EQ(0, statfs_pool.data_compressed_allocated);
1507
1508 // accessing unknown pool
1509 r = store->pool_statfs(poolid + 1, &statfs_pool, &per_pool_omap);
1510 ASSERT_EQ(r, 0);
1511 ASSERT_EQ(0, statfs_pool.data_stored);
1512 ASSERT_EQ(0, statfs_pool.allocated);
1513 ASSERT_EQ(0, statfs_pool.data_compressed);
1514 ASSERT_EQ(0, statfs_pool.data_compressed_original);
1515 ASSERT_EQ(0, statfs_pool.data_compressed_allocated);
1516
1517 //force fsck
1518 ch.reset();
1519 EXPECT_EQ(store->umount(), 0);
1520 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1521 EXPECT_EQ(store->mount(), 0);
1522 ch = store->open_collection(cid);
1523 }
1524 {
1525 ObjectStore::Transaction t;
1526 std::string s(0x30000, 'a');
1527 bufferlist bl;
1528 bl.append(s);
1529 t.write(cid, hoid, 0x10000, bl.length(), bl);
1530 cerr << "Append 0x30000 compressible bytes" << std::endl;
1531 r = queue_transaction(store, ch, std::move(t));
1532 ASSERT_EQ(r, 0);
1533
1534 struct store_statfs_t statfs;
1535 int r = store->statfs(&statfs);
1536 ASSERT_EQ(r, 0);
1537 ASSERT_EQ(0x30005, statfs.data_stored);
1538 ASSERT_EQ(0x30000, statfs.allocated);
1539 ASSERT_LE(statfs.data_compressed, 0x10000);
1540 ASSERT_EQ(0x20000, statfs.data_compressed_original);
1541 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
1542
1543 struct store_statfs_t statfs_pool;
1544 bool per_pool_omap;
1545 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1546 ASSERT_EQ(r, 0);
1547 ASSERT_EQ(0x30005, statfs_pool.data_stored);
1548 ASSERT_EQ(0x30000, statfs_pool.allocated);
1549 ASSERT_LE(statfs_pool.data_compressed, 0x10000);
1550 ASSERT_EQ(0x20000, statfs_pool.data_compressed_original);
1551 ASSERT_EQ(statfs_pool.data_compressed_allocated, 0x10000);
1552 //force fsck
1553 ch.reset();
1554 EXPECT_EQ(store->umount(), 0);
1555 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1556 EXPECT_EQ(store->mount(), 0);
1557 ch = store->open_collection(cid);
1558 }
1559 {
1560 ObjectStore::Transaction t;
1561 t.zero(cid, hoid, 1, 3);
1562 t.zero(cid, hoid, 0x20000, 9);
1563 cerr << "Punch hole at 1~3, 0x20000~9" << std::endl;
1564 r = queue_transaction(store, ch, std::move(t));
1565 ASSERT_EQ(r, 0);
1566
1567 struct store_statfs_t statfs;
1568 int r = store->statfs(&statfs);
1569 ASSERT_EQ(r, 0);
1570 ASSERT_EQ(0x30005 - 3 - 9, statfs.data_stored);
1571 ASSERT_EQ(0x30000, statfs.allocated);
1572 ASSERT_LE(statfs.data_compressed, 0x10000);
1573 ASSERT_EQ(0x20000 - 9, statfs.data_compressed_original);
1574 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
1575
1576 struct store_statfs_t statfs_pool;
1577 bool per_pool_omap;
1578 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1579 ASSERT_EQ(r, 0);
1580 ASSERT_EQ(0x30005 - 3 - 9, statfs_pool.data_stored);
1581 ASSERT_EQ(0x30000, statfs_pool.allocated);
1582 ASSERT_LE(statfs_pool.data_compressed, 0x10000);
1583 ASSERT_EQ(0x20000 - 9, statfs_pool.data_compressed_original);
1584 ASSERT_EQ(statfs_pool.data_compressed_allocated, 0x10000);
1585 //force fsck
1586 ch.reset();
1587 EXPECT_EQ(store->umount(), 0);
1588 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1589 EXPECT_EQ(store->mount(), 0);
1590 ch = store->open_collection(cid);
1591 }
1592 {
1593 ObjectStore::Transaction t;
1594 std::string s(0x1000, 'b');
1595 bufferlist bl;
1596 bl.append(s);
1597 t.write(cid, hoid, 1, bl.length(), bl);
1598 t.write(cid, hoid, 0x10001, bl.length(), bl);
1599 cerr << "Overwrite first and second(compressible) extents" << std::endl;
1600 r = queue_transaction(store, ch, std::move(t));
1601 ASSERT_EQ(r, 0);
1602
1603 struct store_statfs_t statfs;
1604 int r = store->statfs(&statfs);
1605 ASSERT_EQ(r, 0);
1606 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs.data_stored);
1607 ASSERT_EQ(0x40000, statfs.allocated);
1608 ASSERT_LE(statfs.data_compressed, 0x10000);
1609 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs.data_compressed_original);
1610 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
1611
1612 struct store_statfs_t statfs_pool;
1613 bool per_pool_omap;
1614 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1615 ASSERT_EQ(r, 0);
1616 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs_pool.data_stored);
1617 ASSERT_EQ(0x40000, statfs_pool.allocated);
1618 ASSERT_LE(statfs_pool.data_compressed, 0x10000);
1619 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs_pool.data_compressed_original);
1620 ASSERT_EQ(statfs_pool.data_compressed_allocated, 0x10000);
1621 //force fsck
1622 ch.reset();
1623 EXPECT_EQ(store->umount(), 0);
1624 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1625 EXPECT_EQ(store->mount(), 0);
1626 ch = store->open_collection(cid);
1627 }
1628 {
1629 ObjectStore::Transaction t;
1630 std::string s(0x10000, 'c');
1631 bufferlist bl;
1632 bl.append(s);
1633 t.write(cid, hoid, 0x10000, bl.length(), bl);
1634 t.write(cid, hoid, 0x20000, bl.length(), bl);
1635 t.write(cid, hoid, 0x30000, bl.length(), bl);
1636 cerr << "Overwrite compressed extent with 3 uncompressible ones" << std::endl;
1637 r = queue_transaction(store, ch, std::move(t));
1638 ASSERT_EQ(r, 0);
1639
1640 struct store_statfs_t statfs;
1641 int r = store->statfs(&statfs);
1642 ASSERT_EQ(r, 0);
1643 ASSERT_EQ(0x30000 + 0x1001, statfs.data_stored);
1644 ASSERT_EQ(0x40000, statfs.allocated);
1645 ASSERT_LE(statfs.data_compressed, 0);
1646 ASSERT_EQ(0, statfs.data_compressed_original);
1647 ASSERT_EQ(0, statfs.data_compressed_allocated);
1648
1649 struct store_statfs_t statfs_pool;
1650 bool per_pool_omap;
1651 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1652 ASSERT_EQ(r, 0);
1653 ASSERT_EQ(0x30000 + 0x1001, statfs_pool.data_stored);
1654 ASSERT_EQ(0x40000, statfs_pool.allocated);
1655 ASSERT_LE(statfs_pool.data_compressed, 0);
1656 ASSERT_EQ(0, statfs_pool.data_compressed_original);
1657 ASSERT_EQ(0, statfs_pool.data_compressed_allocated);
1658 //force fsck
1659 ch.reset();
1660 EXPECT_EQ(store->umount(), 0);
1661 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1662 EXPECT_EQ(store->mount(), 0);
1663 ch = store->open_collection(cid);
1664 }
1665 {
1666 ObjectStore::Transaction t;
1667 t.zero(cid, hoid, 0, 0x40000);
1668 cerr << "Zero object" << std::endl;
1669 r = queue_transaction(store, ch, std::move(t));
1670 ASSERT_EQ(r, 0);
1671 struct store_statfs_t statfs;
1672 int r = store->statfs(&statfs);
1673 ASSERT_EQ(r, 0);
1674 ASSERT_EQ(0u, statfs.allocated);
1675 ASSERT_EQ(0u, statfs.data_stored);
1676 ASSERT_EQ(0u, statfs.data_compressed_original);
1677 ASSERT_EQ(0u, statfs.data_compressed);
1678 ASSERT_EQ(0u, statfs.data_compressed_allocated);
1679
1680 struct store_statfs_t statfs_pool;
1681 bool per_pool_omap;
1682 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1683 ASSERT_EQ(r, 0);
1684 ASSERT_EQ(0u, statfs_pool.allocated);
1685 ASSERT_EQ(0u, statfs_pool.data_stored);
1686 ASSERT_EQ(0u, statfs_pool.data_compressed_original);
1687 ASSERT_EQ(0u, statfs_pool.data_compressed);
1688 ASSERT_EQ(0u, statfs_pool.data_compressed_allocated);
1689 //force fsck
1690 ch.reset();
1691 EXPECT_EQ(store->umount(), 0);
1692 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1693 EXPECT_EQ(store->mount(), 0);
1694 ch = store->open_collection(cid);
1695 }
1696 {
1697 ObjectStore::Transaction t;
1698 std::string s(0x10000, 'c');
1699 bufferlist bl;
1700 bl.append(s);
1701 bl.append(s);
1702 bl.append(s);
1703 bl.append(s.substr(0, 0x10000-2));
1704 t.write(cid, hoid, 0, bl.length(), bl);
1705 cerr << "Yet another compressible write" << std::endl;
1706 r = queue_transaction(store, ch, std::move(t));
1707 ASSERT_EQ(r, 0);
1708 struct store_statfs_t statfs;
1709 r = store->statfs(&statfs);
1710 ASSERT_EQ(r, 0);
1711 ASSERT_EQ(0x40000 - 2, statfs.data_stored);
1712 ASSERT_EQ(0x30000, statfs.allocated);
1713 ASSERT_LE(statfs.data_compressed, 0x10000);
1714 ASSERT_EQ(0x20000, statfs.data_compressed_original);
1715 ASSERT_EQ(0x10000, statfs.data_compressed_allocated);
1716
1717 struct store_statfs_t statfs_pool;
1718 bool per_pool_omap;
1719 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1720 ASSERT_EQ(r, 0);
1721 ASSERT_EQ(0x40000 - 2, statfs_pool.data_stored);
1722 ASSERT_EQ(0x30000, statfs_pool.allocated);
1723 ASSERT_LE(statfs_pool.data_compressed, 0x10000);
1724 ASSERT_EQ(0x20000, statfs_pool.data_compressed_original);
1725 ASSERT_EQ(0x10000, statfs_pool.data_compressed_allocated);
1726 //force fsck
1727 ch.reset();
1728 EXPECT_EQ(store->umount(), 0);
1729 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1730 EXPECT_EQ(store->mount(), 0);
1731 ch = store->open_collection(cid);
1732 }
1733 {
1734 struct store_statfs_t statfs;
1735 r = store->statfs(&statfs);
1736 ASSERT_EQ(r, 0);
1737
1738 struct store_statfs_t statfs_pool;
1739 bool per_pool_omap;
1740 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1741 ASSERT_EQ(r, 0);
1742
1743 ObjectStore::Transaction t;
1744 t.clone(cid, hoid, hoid2);
1745 cerr << "Clone compressed objecte" << std::endl;
1746 r = queue_transaction(store, ch, std::move(t));
1747 ASSERT_EQ(r, 0);
1748 struct store_statfs_t statfs2;
1749 r = store->statfs(&statfs2);
1750 ASSERT_EQ(r, 0);
1751 ASSERT_GT(statfs2.data_stored, statfs.data_stored);
1752 ASSERT_EQ(statfs2.allocated, statfs.allocated);
1753 ASSERT_GT(statfs2.data_compressed, statfs.data_compressed);
1754 ASSERT_GT(statfs2.data_compressed_original, statfs.data_compressed_original);
1755 ASSERT_EQ(statfs2.data_compressed_allocated, statfs.data_compressed_allocated);
1756
1757 struct store_statfs_t statfs2_pool;
1758 r = store->pool_statfs(poolid, &statfs2_pool, &per_pool_omap);
1759 ASSERT_EQ(r, 0);
1760 ASSERT_GT(statfs2_pool.data_stored, statfs_pool.data_stored);
1761 ASSERT_EQ(statfs2_pool.allocated, statfs_pool.allocated);
1762 ASSERT_GT(statfs2_pool.data_compressed, statfs_pool.data_compressed);
1763 ASSERT_GT(statfs2_pool.data_compressed_original,
1764 statfs_pool.data_compressed_original);
1765 ASSERT_EQ(statfs2_pool.data_compressed_allocated,
1766 statfs_pool.data_compressed_allocated);
1767 }
1768
1769 {
1770 // verify no
1771 auto poolid2 = poolid + 1;
1772 coll_t cid2 = coll_t(spg_t(pg_t(20, poolid2), shard_id_t::NO_SHARD));
1773 ghobject_t hoid(hobject_t(sobject_t("Object 2", CEPH_NOSNAP),
1774 string(),
1775 0,
1776 poolid2,
1777 string()));
1778 auto ch = store->create_new_collection(cid2);
1779
1780 {
1781
1782 struct store_statfs_t statfs1_pool;
1783 bool per_pool_omap;
1784 int r = store->pool_statfs(poolid, &statfs1_pool, &per_pool_omap);
1785 ASSERT_EQ(r, 0);
1786
1787 cerr << "Creating second collection " << cid2 << std::endl;
1788 ObjectStore::Transaction t;
1789 t.create_collection(cid2, 0);
1790 r = queue_transaction(store, ch, std::move(t));
1791 ASSERT_EQ(r, 0);
1792
1793 t = ObjectStore::Transaction();
1794 bufferlist bl;
1795 bl.append("abcde");
1796 t.write(cid2, hoid, 0, 5, bl);
1797 r = queue_transaction(store, ch, std::move(t));
1798 ASSERT_EQ(r, 0);
1799
1800 struct store_statfs_t statfs2_pool;
1801 r = store->pool_statfs(poolid2, &statfs2_pool, &per_pool_omap);
1802 ASSERT_EQ(r, 0);
1803 ASSERT_EQ(5, statfs2_pool.data_stored);
1804 ASSERT_EQ(0x10000, statfs2_pool.allocated);
1805 ASSERT_EQ(0, statfs2_pool.data_compressed);
1806 ASSERT_EQ(0, statfs2_pool.data_compressed_original);
1807 ASSERT_EQ(0, statfs2_pool.data_compressed_allocated);
1808
1809 struct store_statfs_t statfs1_pool_again;
1810 r = store->pool_statfs(poolid, &statfs1_pool_again, &per_pool_omap);
1811 ASSERT_EQ(r, 0);
1812 // adjust 'available' since it has changed
1813 statfs1_pool_again.available = statfs1_pool.available;
1814 ASSERT_EQ(statfs1_pool_again, statfs1_pool);
1815
1816 t = ObjectStore::Transaction();
1817 t.remove(cid2, hoid);
1818 t.remove_collection(cid2);
1819 cerr << "Cleaning" << std::endl;
1820 r = queue_transaction(store, ch, std::move(t));
1821 ASSERT_EQ(r, 0);
1822 }
1823 }
1824
1825 {
1826 // verify ops on temporary object
1827
1828 auto poolid3 = poolid + 2;
1829 coll_t cid3 = coll_t(spg_t(pg_t(20, poolid3), shard_id_t::NO_SHARD));
1830 ghobject_t hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP),
1831 string(),
1832 0,
1833 poolid3,
1834 string()));
1835 ghobject_t hoid3_temp;
1836 hoid3_temp.hobj = hoid3.hobj.make_temp_hobject("Object 3 temp");
1837 auto ch3 = store->create_new_collection(cid3);
1838 {
1839 struct store_statfs_t statfs1_pool;
1840 bool per_pool_omap;
1841 int r = store->pool_statfs(poolid, &statfs1_pool, &per_pool_omap);
1842 ASSERT_EQ(r, 0);
1843
1844 cerr << "Creating third collection " << cid3 << std::endl;
1845 ObjectStore::Transaction t;
1846 t.create_collection(cid3, 0);
1847 r = queue_transaction(store, ch3, std::move(t));
1848 ASSERT_EQ(r, 0);
1849
1850 t = ObjectStore::Transaction();
1851 bufferlist bl;
1852 bl.append("abcde");
1853 t.write(cid3, hoid3_temp, 0, 5, bl);
1854 r = queue_transaction(store, ch3, std::move(t));
1855 ASSERT_EQ(r, 0);
1856
1857 struct store_statfs_t statfs3_pool;
1858 r = store->pool_statfs(poolid3, &statfs3_pool, &per_pool_omap);
1859 ASSERT_EQ(r, 0);
1860 ASSERT_EQ(5, statfs3_pool.data_stored);
1861 ASSERT_EQ(0x10000, statfs3_pool.allocated);
1862 ASSERT_EQ(0, statfs3_pool.data_compressed);
1863 ASSERT_EQ(0, statfs3_pool.data_compressed_original);
1864 ASSERT_EQ(0, statfs3_pool.data_compressed_allocated);
1865
1866 struct store_statfs_t statfs1_pool_again;
1867 r = store->pool_statfs(poolid, &statfs1_pool_again, &per_pool_omap);
1868 ASSERT_EQ(r, 0);
1869 // adjust 'available' since it has changed
1870 statfs1_pool_again.available = statfs1_pool.available;
1871 ASSERT_EQ(statfs1_pool_again, statfs1_pool);
1872
1873 //force fsck
1874 ch.reset();
1875 ch3.reset();
1876 EXPECT_EQ(store->umount(), 0);
1877 EXPECT_EQ(store->mount(), 0);
1878 ch = store->open_collection(cid);
1879 ch3 = store->open_collection(cid3);
1880
1881 t = ObjectStore::Transaction();
1882 t.collection_move_rename(
1883 cid3, hoid3_temp,
1884 cid3, hoid3);
1885 r = queue_transaction(store, ch3, std::move(t));
1886 ASSERT_EQ(r, 0);
1887
1888 struct store_statfs_t statfs3_pool_again;
1889 r = store->pool_statfs(poolid3, &statfs3_pool_again, &per_pool_omap);
1890 ASSERT_EQ(r, 0);
1891 ASSERT_EQ(statfs3_pool_again, statfs3_pool);
1892
1893 //force fsck
1894 ch.reset();
1895 ch3.reset();
1896 EXPECT_EQ(store->umount(), 0);
1897 EXPECT_EQ(store->mount(), 0);
1898 ch = store->open_collection(cid);
1899 ch3 = store->open_collection(cid3);
1900
1901 t = ObjectStore::Transaction();
1902 t.remove(cid3, hoid3);
1903 t.remove_collection(cid3);
1904 cerr << "Cleaning" << std::endl;
1905 r = queue_transaction(store, ch3, std::move(t));
1906 ASSERT_EQ(r, 0);
1907 }
1908 }
1909
1910 {
1911 ObjectStore::Transaction t;
1912 t.remove(cid, hoid);
1913 t.remove(cid, hoid2);
1914 t.remove_collection(cid);
1915 cerr << "Cleaning" << std::endl;
1916 r = queue_transaction(store, ch, std::move(t));
1917 ASSERT_EQ(r, 0);
1918
1919 struct store_statfs_t statfs;
1920 r = store->statfs(&statfs);
1921 ASSERT_EQ(r, 0);
1922 ASSERT_EQ( 0u, statfs.allocated);
1923 ASSERT_EQ( 0u, statfs.data_stored);
1924 ASSERT_EQ( 0u, statfs.data_compressed_original);
1925 ASSERT_EQ( 0u, statfs.data_compressed);
1926 ASSERT_EQ( 0u, statfs.data_compressed_allocated);
1927
1928 struct store_statfs_t statfs_pool;
1929 bool per_pool_omap;
1930 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1931 ASSERT_EQ(r, 0);
1932 ASSERT_EQ( 0u, statfs_pool.allocated);
1933 ASSERT_EQ( 0u, statfs_pool.data_stored);
1934 ASSERT_EQ( 0u, statfs_pool.data_compressed_original);
1935 ASSERT_EQ( 0u, statfs_pool.data_compressed);
1936 ASSERT_EQ( 0u, statfs_pool.data_compressed_allocated);
1937 }
1938 }
1939
1940 TEST_P(StoreTestSpecificAUSize, BluestoreFragmentedBlobTest) {
1941 if(string(GetParam()) != "bluestore")
1942 return;
1943 StartDeferred(0x10000);
1944
1945 int r;
1946 coll_t cid;
1947 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1948 auto ch = store->create_new_collection(cid);
1949 {
1950 ObjectStore::Transaction t;
1951 t.create_collection(cid, 0);
1952 cerr << "Creating collection " << cid << std::endl;
1953 r = queue_transaction(store, ch, std::move(t));
1954 ASSERT_EQ(r, 0);
1955 }
1956 {
1957 bool exists = store->exists(ch, hoid);
1958 ASSERT_TRUE(!exists);
1959
1960 ObjectStore::Transaction t;
1961 t.touch(cid, hoid);
1962 cerr << "Creating object " << hoid << std::endl;
1963 r = queue_transaction(store, ch, std::move(t));
1964 ASSERT_EQ(r, 0);
1965
1966 exists = store->exists(ch, hoid);
1967 ASSERT_EQ(true, exists);
1968 }
1969 {
1970 struct store_statfs_t statfs;
1971 int r = store->statfs(&statfs);
1972 ASSERT_EQ(r, 0);
1973 ASSERT_EQ(g_conf()->bluestore_block_size, statfs.total);
1974 ASSERT_EQ(0u, statfs.allocated);
1975 ASSERT_EQ(0u, statfs.data_stored);
1976 ASSERT_TRUE(statfs.available > 0u && statfs.available < g_conf()->bluestore_block_size);
1977 }
1978 std::string data;
1979 data.resize(0x10000 * 3);
1980 {
1981 ObjectStore::Transaction t;
1982 for(size_t i = 0;i < data.size(); i++)
1983 data[i] = i / 256 + 1;
1984 bufferlist bl, newdata;
1985 bl.append(data);
1986 t.write(cid, hoid, 0, bl.length(), bl);
1987 t.zero(cid, hoid, 0x10000, 0x10000);
1988 cerr << "Append 3*0x10000 bytes and punch a hole 0x10000~10000" << std::endl;
1989 r = queue_transaction(store, ch, std::move(t));
1990 ASSERT_EQ(r, 0);
1991
1992 struct store_statfs_t statfs;
1993 int r = store->statfs(&statfs);
1994 ASSERT_EQ(r, 0);
1995 ASSERT_EQ(0x20000, statfs.data_stored);
1996 ASSERT_EQ(0x20000, statfs.allocated);
1997
1998 r = store->read(ch, hoid, 0, data.size(), newdata);
1999 ASSERT_EQ(r, (int)data.size());
2000 {
2001 bufferlist expected;
2002 expected.append(data.substr(0, 0x10000));
2003 expected.append(string(0x10000, 0));
2004 expected.append(data.substr(0x20000, 0x10000));
2005 ASSERT_TRUE(bl_eq(expected, newdata));
2006 }
2007 newdata.clear();
2008
2009 r = store->read(ch, hoid, 1, data.size()-2, newdata);
2010 ASSERT_EQ(r, (int)data.size()-2);
2011 {
2012 bufferlist expected;
2013 expected.append(data.substr(1, 0x10000-1));
2014 expected.append(string(0x10000, 0));
2015 expected.append(data.substr(0x20000, 0x10000 - 1));
2016 ASSERT_TRUE(bl_eq(expected, newdata));
2017 }
2018 newdata.clear();
2019 }
2020 //force fsck
2021 ch.reset();
2022 EXPECT_EQ(store->umount(), 0);
2023 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
2024 EXPECT_EQ(store->mount(), 0);
2025 ch = store->open_collection(cid);
2026
2027 {
2028 ObjectStore::Transaction t;
2029 std::string data2(3, 'b');
2030 bufferlist bl, newdata;
2031 bl.append(data2);
2032 t.write(cid, hoid, 0x20000, bl.length(), bl);
2033 cerr << "Write 3 bytes after the hole" << std::endl;
2034 r = queue_transaction(store, ch, std::move(t));
2035 ASSERT_EQ(r, 0);
2036
2037 struct store_statfs_t statfs;
2038 int r = store->statfs(&statfs);
2039 ASSERT_EQ(r, 0);
2040 ASSERT_EQ(0x20000, statfs.allocated);
2041 ASSERT_EQ(0x20000, statfs.data_stored);
2042
2043 r = store->read(ch, hoid, 0x20000-1, 21, newdata);
2044 ASSERT_EQ(r, (int)21);
2045 {
2046 bufferlist expected;
2047 expected.append(string(0x1, 0));
2048 expected.append(string(data2));
2049 expected.append(data.substr(0x20003, 21-4));
2050 ASSERT_TRUE(bl_eq(expected, newdata));
2051 }
2052 newdata.clear();
2053 }
2054 //force fsck
2055 ch.reset();
2056 EXPECT_EQ(store->umount(), 0);
2057 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
2058 EXPECT_EQ(store->mount(), 0);
2059 ch = store->open_collection(cid);
2060
2061 {
2062 ObjectStore::Transaction t;
2063 std::string data2(3, 'a');
2064 bufferlist bl, newdata;
2065 bl.append(data2);
2066 t.write(cid, hoid, 0x10000+1, bl.length(), bl);
2067 cerr << "Write 3 bytes to the hole" << std::endl;
2068 r = queue_transaction(store, ch, std::move(t));
2069 ASSERT_EQ(r, 0);
2070
2071 struct store_statfs_t statfs;
2072 int r = store->statfs(&statfs);
2073 ASSERT_EQ(r, 0);
2074 ASSERT_EQ(0x30000, statfs.allocated);
2075 ASSERT_EQ(0x20003, statfs.data_stored);
2076
2077 r = store->read(ch, hoid, 0x10000-1, 0x10000+22, newdata);
2078 ASSERT_EQ(r, (int)0x10000+22);
2079 {
2080 bufferlist expected;
2081 expected.append(data.substr(0x10000-1, 1));
2082 expected.append(string(0x1, 0));
2083 expected.append(data2);
2084 expected.append(string(0x10000-4, 0));
2085 expected.append(string(0x3, 'b'));
2086 expected.append(data.substr(0x20004, 21-3));
2087 ASSERT_TRUE(bl_eq(expected, newdata));
2088 }
2089 newdata.clear();
2090 }
2091 {
2092 ObjectStore::Transaction t;
2093 bufferlist bl, newdata;
2094 bl.append(string(0x30000, 'c'));
2095 t.write(cid, hoid, 0, 0x30000, bl);
2096 t.zero(cid, hoid, 0, 0x10000);
2097 t.zero(cid, hoid, 0x20000, 0x10000);
2098 cerr << "Rewrite an object and create two holes at the beginning and the end" << std::endl;
2099 r = queue_transaction(store, ch, std::move(t));
2100 ASSERT_EQ(r, 0);
2101
2102 struct store_statfs_t statfs;
2103 int r = store->statfs(&statfs);
2104 ASSERT_EQ(r, 0);
2105 ASSERT_EQ(0x10000, statfs.allocated);
2106 ASSERT_EQ(0x10000, statfs.data_stored);
2107
2108 r = store->read(ch, hoid, 0, 0x30000, newdata);
2109 ASSERT_EQ(r, (int)0x30000);
2110 {
2111 bufferlist expected;
2112 expected.append(string(0x10000, 0));
2113 expected.append(string(0x10000, 'c'));
2114 expected.append(string(0x10000, 0));
2115 ASSERT_TRUE(bl_eq(expected, newdata));
2116 }
2117 newdata.clear();
2118 }
2119
2120 //force fsck
2121 ch.reset();
2122 EXPECT_EQ(store->umount(), 0);
2123 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
2124 EXPECT_EQ(store->mount(), 0);
2125 ch = store->open_collection(cid);
2126
2127 {
2128 ObjectStore::Transaction t;
2129 t.remove(cid, hoid);
2130 t.remove_collection(cid);
2131 cerr << "Cleaning" << std::endl;
2132 r = queue_transaction(store, ch, std::move(t));
2133 ASSERT_EQ(r, 0);
2134
2135 struct store_statfs_t statfs;
2136 r = store->statfs(&statfs);
2137 ASSERT_EQ(r, 0);
2138 ASSERT_EQ( 0u, statfs.allocated);
2139 ASSERT_EQ( 0u, statfs.data_stored);
2140 ASSERT_EQ( 0u, statfs.data_compressed_original);
2141 ASSERT_EQ( 0u, statfs.data_compressed);
2142 ASSERT_EQ( 0u, statfs.data_compressed_allocated);
2143 }
2144 }
2145 #endif
2146
2147 TEST_P(StoreTest, ManySmallWrite) {
2148 int r;
2149 coll_t cid;
2150 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2151 ghobject_t b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
2152 auto ch = store->create_new_collection(cid);
2153 {
2154 ObjectStore::Transaction t;
2155 t.create_collection(cid, 0);
2156 cerr << "Creating collection " << cid << std::endl;
2157 r = queue_transaction(store, ch, std::move(t));
2158 ASSERT_EQ(r, 0);
2159 }
2160 bufferlist bl;
2161 bufferptr bp(4096);
2162 bp.zero();
2163 bl.append(bp);
2164 for (int i=0; i<100; ++i) {
2165 ObjectStore::Transaction t;
2166 t.write(cid, a, i*4096, 4096, bl, 0);
2167 r = queue_transaction(store, ch, std::move(t));
2168 ASSERT_EQ(r, 0);
2169 }
2170 for (int i=0; i<100; ++i) {
2171 ObjectStore::Transaction t;
2172 t.write(cid, b, (rand() % 1024)*4096, 4096, bl, 0);
2173 r = queue_transaction(store, ch, std::move(t));
2174 ASSERT_EQ(r, 0);
2175 }
2176 {
2177 ObjectStore::Transaction t;
2178 t.remove(cid, a);
2179 t.remove(cid, b);
2180 t.remove_collection(cid);
2181 cerr << "Cleaning" << std::endl;
2182 r = queue_transaction(store, ch, std::move(t));
2183 ASSERT_EQ(r, 0);
2184 }
2185 }
2186
2187 TEST_P(StoreTest, MultiSmallWriteSameBlock) {
2188 int r;
2189 coll_t cid;
2190 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2191 auto ch = store->create_new_collection(cid);
2192 {
2193 ObjectStore::Transaction t;
2194 t.create_collection(cid, 0);
2195 cerr << "Creating collection " << cid << std::endl;
2196 r = queue_transaction(store, ch, std::move(t));
2197 ASSERT_EQ(r, 0);
2198 }
2199 bufferlist bl;
2200 bl.append("short");
2201 C_SaferCond c, d;
2202 // touch same block in both same transaction, tls, and pipelined txns
2203 {
2204 ObjectStore::Transaction t, u;
2205 t.write(cid, a, 0, 5, bl, 0);
2206 t.write(cid, a, 5, 5, bl, 0);
2207 t.write(cid, a, 4094, 5, bl, 0);
2208 t.write(cid, a, 9000, 5, bl, 0);
2209 u.write(cid, a, 10, 5, bl, 0);
2210 u.write(cid, a, 7000, 5, bl, 0);
2211 t.register_on_commit(&c);
2212 vector<ObjectStore::Transaction> v = {t, u};
2213 store->queue_transactions(ch, v);
2214 }
2215 {
2216 ObjectStore::Transaction t, u;
2217 t.write(cid, a, 40, 5, bl, 0);
2218 t.write(cid, a, 45, 5, bl, 0);
2219 t.write(cid, a, 4094, 5, bl, 0);
2220 t.write(cid, a, 6000, 5, bl, 0);
2221 u.write(cid, a, 610, 5, bl, 0);
2222 u.write(cid, a, 11000, 5, bl, 0);
2223 t.register_on_commit(&d);
2224 vector<ObjectStore::Transaction> v = {t, u};
2225 store->queue_transactions(ch, v);
2226 }
2227 c.wait();
2228 d.wait();
2229 {
2230 bufferlist bl2;
2231 r = store->read(ch, a, 0, 16000, bl2);
2232 ASSERT_GE(r, 0);
2233 }
2234 {
2235 ObjectStore::Transaction t;
2236 t.remove(cid, a);
2237 t.remove_collection(cid);
2238 cerr << "Cleaning" << std::endl;
2239 r = queue_transaction(store, ch, std::move(t));
2240 ASSERT_EQ(r, 0);
2241 }
2242 }
2243
2244 TEST_P(StoreTest, SmallSkipFront) {
2245 int r;
2246 coll_t cid;
2247 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2248 auto ch = store->create_new_collection(cid);
2249 {
2250 ObjectStore::Transaction t;
2251 t.create_collection(cid, 0);
2252 cerr << "Creating collection " << cid << std::endl;
2253 r = queue_transaction(store, ch, std::move(t));
2254 ASSERT_EQ(r, 0);
2255 }
2256 {
2257 ObjectStore::Transaction t;
2258 t.touch(cid, a);
2259 t.truncate(cid, a, 3000);
2260 r = queue_transaction(store, ch, std::move(t));
2261 ASSERT_EQ(r, 0);
2262 }
2263 {
2264 bufferlist bl;
2265 bufferptr bp(4096);
2266 memset(bp.c_str(), 1, 4096);
2267 bl.append(bp);
2268 ObjectStore::Transaction t;
2269 t.write(cid, a, 4096, 4096, bl);
2270 r = queue_transaction(store, ch, std::move(t));
2271 ASSERT_EQ(r, 0);
2272 }
2273 {
2274 bufferlist bl;
2275 ASSERT_EQ(8192, store->read(ch, a, 0, 8192, bl));
2276 for (unsigned i=0; i<4096; ++i)
2277 ASSERT_EQ(0, bl[i]);
2278 for (unsigned i=4096; i<8192; ++i)
2279 ASSERT_EQ(1, bl[i]);
2280 }
2281 {
2282 ObjectStore::Transaction t;
2283 t.remove(cid, a);
2284 t.remove_collection(cid);
2285 cerr << "Cleaning" << std::endl;
2286 r = queue_transaction(store, ch, std::move(t));
2287 ASSERT_EQ(r, 0);
2288 }
2289 }
2290
2291 TEST_P(StoreTest, AppendDeferredVsTailCache) {
2292 int r;
2293 coll_t cid;
2294 ghobject_t a(hobject_t(sobject_t("fooo", CEPH_NOSNAP)));
2295 auto ch = store->create_new_collection(cid);
2296 {
2297 ObjectStore::Transaction t;
2298 t.create_collection(cid, 0);
2299 cerr << "Creating collection " << cid << std::endl;
2300 r = store->queue_transaction(ch, std::move(t));
2301 ASSERT_EQ(r, 0);
2302 }
2303 unsigned min_alloc = g_conf()->bluestore_min_alloc_size;
2304 unsigned size = min_alloc / 3;
2305 bufferptr bpa(size);
2306 memset(bpa.c_str(), 1, bpa.length());
2307 bufferlist bla;
2308 bla.append(bpa);
2309 {
2310 ObjectStore::Transaction t;
2311 t.write(cid, a, 0, bla.length(), bla, 0);
2312 r = store->queue_transaction(ch, std::move(t));
2313 ASSERT_EQ(r, 0);
2314 }
2315
2316 // force cached tail to clear ...
2317 {
2318 ch.reset();
2319 int r = store->umount();
2320 ASSERT_EQ(0, r);
2321 r = store->mount();
2322 ASSERT_EQ(0, r);
2323 ch = store->open_collection(cid);
2324 }
2325
2326 bufferptr bpb(size);
2327 memset(bpb.c_str(), 2, bpb.length());
2328 bufferlist blb;
2329 blb.append(bpb);
2330 {
2331 ObjectStore::Transaction t;
2332 t.write(cid, a, bla.length(), blb.length(), blb, 0);
2333 r = store->queue_transaction(ch, std::move(t));
2334 ASSERT_EQ(r, 0);
2335 }
2336 bufferptr bpc(size);
2337 memset(bpc.c_str(), 3, bpc.length());
2338 bufferlist blc;
2339 blc.append(bpc);
2340 {
2341 ObjectStore::Transaction t;
2342 t.write(cid, a, bla.length() + blb.length(), blc.length(), blc, 0);
2343 r = store->queue_transaction(ch, std::move(t));
2344 ASSERT_EQ(r, 0);
2345 }
2346 bufferlist final;
2347 final.append(bla);
2348 final.append(blb);
2349 final.append(blc);
2350 bufferlist actual;
2351 {
2352 ASSERT_EQ((int)final.length(),
2353 store->read(ch, a, 0, final.length(), actual));
2354 ASSERT_TRUE(bl_eq(final, actual));
2355 }
2356 {
2357 ObjectStore::Transaction t;
2358 t.remove(cid, a);
2359 t.remove_collection(cid);
2360 cerr << "Cleaning" << std::endl;
2361 r = store->queue_transaction(ch, std::move(t));
2362 ASSERT_EQ(r, 0);
2363 }
2364 }
2365
2366 TEST_P(StoreTest, AppendZeroTrailingSharedBlock) {
2367 int r;
2368 coll_t cid;
2369 ghobject_t a(hobject_t(sobject_t("fooo", CEPH_NOSNAP)));
2370 ghobject_t b = a;
2371 b.hobj.snap = 1;
2372 auto ch = store->create_new_collection(cid);
2373 {
2374 ObjectStore::Transaction t;
2375 t.create_collection(cid, 0);
2376 cerr << "Creating collection " << cid << std::endl;
2377 r = store->queue_transaction(ch, std::move(t));
2378 ASSERT_EQ(r, 0);
2379 }
2380 unsigned min_alloc = g_conf()->bluestore_min_alloc_size;
2381 unsigned size = min_alloc / 3;
2382 bufferptr bpa(size);
2383 memset(bpa.c_str(), 1, bpa.length());
2384 bufferlist bla;
2385 bla.append(bpa);
2386 // make sure there is some trailing gunk in the last block
2387 {
2388 bufferlist bt;
2389 bt.append(bla);
2390 bt.append("BADBADBADBAD");
2391 ObjectStore::Transaction t;
2392 t.write(cid, a, 0, bt.length(), bt, 0);
2393 r = store->queue_transaction(ch, std::move(t));
2394 ASSERT_EQ(r, 0);
2395 }
2396 {
2397 ObjectStore::Transaction t;
2398 t.truncate(cid, a, size);
2399 r = store->queue_transaction(ch, std::move(t));
2400 ASSERT_EQ(r, 0);
2401 }
2402
2403 // clone
2404 {
2405 ObjectStore::Transaction t;
2406 t.clone(cid, a, b);
2407 r = store->queue_transaction(ch, std::move(t));
2408 ASSERT_EQ(r, 0);
2409 }
2410
2411 // append with implicit zeroing
2412 bufferptr bpb(size);
2413 memset(bpb.c_str(), 2, bpb.length());
2414 bufferlist blb;
2415 blb.append(bpb);
2416 {
2417 ObjectStore::Transaction t;
2418 t.write(cid, a, min_alloc * 3, blb.length(), blb, 0);
2419 r = store->queue_transaction(ch, std::move(t));
2420 ASSERT_EQ(r, 0);
2421 }
2422 bufferlist final;
2423 final.append(bla);
2424 bufferlist zeros;
2425 zeros.append_zero(min_alloc * 3 - size);
2426 final.append(zeros);
2427 final.append(blb);
2428 bufferlist actual;
2429 {
2430 ASSERT_EQ((int)final.length(),
2431 store->read(ch, a, 0, final.length(), actual));
2432 final.hexdump(cout);
2433 actual.hexdump(cout);
2434 ASSERT_TRUE(bl_eq(final, actual));
2435 }
2436 {
2437 ObjectStore::Transaction t;
2438 t.remove(cid, a);
2439 t.remove(cid, b);
2440 t.remove_collection(cid);
2441 cerr << "Cleaning" << std::endl;
2442 r = store->queue_transaction(ch, std::move(t));
2443 ASSERT_EQ(r, 0);
2444 }
2445 }
2446
2447 TEST_P(StoreTest, SmallSequentialUnaligned) {
2448 int r;
2449 coll_t cid;
2450 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2451 auto ch = store->create_new_collection(cid);
2452 {
2453 ObjectStore::Transaction t;
2454 t.create_collection(cid, 0);
2455 cerr << "Creating collection " << cid << std::endl;
2456 r = queue_transaction(store, ch, std::move(t));
2457 ASSERT_EQ(r, 0);
2458 }
2459 bufferlist bl;
2460 int len = 1000;
2461 bufferptr bp(len);
2462 bp.zero();
2463 bl.append(bp);
2464 for (int i=0; i<1000; ++i) {
2465 ObjectStore::Transaction t;
2466 t.write(cid, a, i*len, len, bl, 0);
2467 r = queue_transaction(store, ch, std::move(t));
2468 ASSERT_EQ(r, 0);
2469 }
2470 {
2471 ObjectStore::Transaction t;
2472 t.remove(cid, a);
2473 t.remove_collection(cid);
2474 cerr << "Cleaning" << std::endl;
2475 r = queue_transaction(store, ch, std::move(t));
2476 ASSERT_EQ(r, 0);
2477 }
2478 }
2479
2480 TEST_P(StoreTest, ManyBigWrite) {
2481 int r;
2482 coll_t cid;
2483 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2484 ghobject_t b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
2485 auto ch = store->create_new_collection(cid);
2486 {
2487 ObjectStore::Transaction t;
2488 t.create_collection(cid, 0);
2489 cerr << "Creating collection " << cid << std::endl;
2490 r = queue_transaction(store, ch, std::move(t));
2491 ASSERT_EQ(r, 0);
2492 }
2493 bufferlist bl;
2494 bufferptr bp(4 * 1048576);
2495 bp.zero();
2496 bl.append(bp);
2497 for (int i=0; i<10; ++i) {
2498 ObjectStore::Transaction t;
2499 t.write(cid, a, i*4*1048586, 4*1048576, bl, 0);
2500 r = queue_transaction(store, ch, std::move(t));
2501 ASSERT_EQ(r, 0);
2502 }
2503 // aligned
2504 for (int i=0; i<10; ++i) {
2505 ObjectStore::Transaction t;
2506 t.write(cid, b, (rand() % 256)*4*1048576, 4*1048576, bl, 0);
2507 r = queue_transaction(store, ch, std::move(t));
2508 ASSERT_EQ(r, 0);
2509 }
2510 // unaligned
2511 for (int i=0; i<10; ++i) {
2512 ObjectStore::Transaction t;
2513 t.write(cid, b, (rand() % (256*4096))*1024, 4*1048576, bl, 0);
2514 r = queue_transaction(store, ch, std::move(t));
2515 ASSERT_EQ(r, 0);
2516 }
2517 // do some zeros
2518 for (int i=0; i<10; ++i) {
2519 ObjectStore::Transaction t;
2520 t.zero(cid, b, (rand() % (256*4096))*1024, 16*1048576);
2521 r = queue_transaction(store, ch, std::move(t));
2522 ASSERT_EQ(r, 0);
2523 }
2524 {
2525 ObjectStore::Transaction t;
2526 t.remove(cid, a);
2527 t.remove(cid, b);
2528 t.remove_collection(cid);
2529 cerr << "Cleaning" << std::endl;
2530 r = queue_transaction(store, ch, std::move(t));
2531 ASSERT_EQ(r, 0);
2532 }
2533 }
2534
2535 TEST_P(StoreTest, BigWriteBigZero) {
2536 int r;
2537 coll_t cid;
2538 ghobject_t a(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2539 auto ch = store->create_new_collection(cid);
2540 {
2541 ObjectStore::Transaction t;
2542 t.create_collection(cid, 0);
2543 r = queue_transaction(store, ch, std::move(t));
2544 ASSERT_EQ(r, 0);
2545 }
2546 bufferlist bl;
2547 bufferptr bp(1048576);
2548 memset(bp.c_str(), 'b', bp.length());
2549 bl.append(bp);
2550 bufferlist s;
2551 bufferptr sp(4096);
2552 memset(sp.c_str(), 's', sp.length());
2553 s.append(sp);
2554 {
2555 ObjectStore::Transaction t;
2556 t.write(cid, a, 0, bl.length(), bl);
2557 r = queue_transaction(store, ch, std::move(t));
2558 ASSERT_EQ(r, 0);
2559 }
2560 {
2561 ObjectStore::Transaction t;
2562 t.zero(cid, a, bl.length() / 4, bl.length() / 2);
2563 r = queue_transaction(store, ch, std::move(t));
2564 ASSERT_EQ(r, 0);
2565 }
2566 {
2567 ObjectStore::Transaction t;
2568 t.write(cid, a, bl.length() / 2, s.length(), s);
2569 r = queue_transaction(store, ch, std::move(t));
2570 ASSERT_EQ(r, 0);
2571 }
2572 {
2573 ObjectStore::Transaction t;
2574 t.remove(cid, a);
2575 t.remove_collection(cid);
2576 r = queue_transaction(store, ch, std::move(t));
2577 ASSERT_EQ(r, 0);
2578 }
2579 }
2580
2581 TEST_P(StoreTest, MiscFragmentTests) {
2582 int r;
2583 coll_t cid;
2584 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2585 auto ch = store->create_new_collection(cid);
2586 {
2587 ObjectStore::Transaction t;
2588 t.create_collection(cid, 0);
2589 cerr << "Creating collection " << cid << std::endl;
2590 r = queue_transaction(store, ch, std::move(t));
2591 ASSERT_EQ(r, 0);
2592 }
2593 bufferlist bl;
2594 bufferptr bp(524288);
2595 bp.zero();
2596 bl.append(bp);
2597 {
2598 ObjectStore::Transaction t;
2599 t.write(cid, a, 0, 524288, bl, 0);
2600 r = queue_transaction(store, ch, std::move(t));
2601 ASSERT_EQ(r, 0);
2602 }
2603 {
2604 ObjectStore::Transaction t;
2605 t.write(cid, a, 1048576, 524288, bl, 0);
2606 r = queue_transaction(store, ch, std::move(t));
2607 ASSERT_EQ(r, 0);
2608 }
2609 {
2610 bufferlist inbl;
2611 int r = store->read(ch, a, 524288 + 131072, 1024, inbl);
2612 ASSERT_EQ(r, 1024);
2613 ASSERT_EQ(inbl.length(), 1024u);
2614 ASSERT_TRUE(inbl.is_zero());
2615 }
2616 {
2617 ObjectStore::Transaction t;
2618 t.write(cid, a, 1048576 - 4096, 524288, bl, 0);
2619 r = queue_transaction(store, ch, std::move(t));
2620 ASSERT_EQ(r, 0);
2621 }
2622 {
2623 ObjectStore::Transaction t;
2624 t.remove(cid, a);
2625 t.remove_collection(cid);
2626 cerr << "Cleaning" << std::endl;
2627 r = queue_transaction(store, ch, std::move(t));
2628 ASSERT_EQ(r, 0);
2629 }
2630
2631 }
2632
2633 TEST_P(StoreTest, ZeroVsObjectSize) {
2634 int r;
2635 coll_t cid;
2636 struct stat stat;
2637 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2638 auto ch = store->create_new_collection(cid);
2639 {
2640 ObjectStore::Transaction t;
2641 t.create_collection(cid, 0);
2642 cerr << "Creating collection " << cid << std::endl;
2643 r = queue_transaction(store, ch, std::move(t));
2644 ASSERT_EQ(r, 0);
2645 }
2646 bufferlist a;
2647 a.append("stuff");
2648 {
2649 ObjectStore::Transaction t;
2650 t.write(cid, hoid, 0, 5, a);
2651 r = queue_transaction(store, ch, std::move(t));
2652 ASSERT_EQ(r, 0);
2653 }
2654 ASSERT_EQ(0, store->stat(ch, hoid, &stat));
2655 ASSERT_EQ(5, stat.st_size);
2656 {
2657 ObjectStore::Transaction t;
2658 t.zero(cid, hoid, 1, 2);
2659 r = queue_transaction(store, ch, std::move(t));
2660 ASSERT_EQ(r, 0);
2661 }
2662 ASSERT_EQ(0, store->stat(ch, hoid, &stat));
2663 ASSERT_EQ(5, stat.st_size);
2664 {
2665 ObjectStore::Transaction t;
2666 t.zero(cid, hoid, 3, 200);
2667 r = queue_transaction(store, ch, std::move(t));
2668 ASSERT_EQ(r, 0);
2669 }
2670 ASSERT_EQ(0, store->stat(ch, hoid, &stat));
2671 ASSERT_EQ(203, stat.st_size);
2672 {
2673 ObjectStore::Transaction t;
2674 t.zero(cid, hoid, 100000, 200);
2675 r = queue_transaction(store, ch, std::move(t));
2676 ASSERT_EQ(r, 0);
2677 }
2678 ASSERT_EQ(0, store->stat(ch, hoid, &stat));
2679 ASSERT_EQ(100200, stat.st_size);
2680 }
2681
2682 TEST_P(StoreTest, ZeroLengthWrite) {
2683 int r;
2684 coll_t cid;
2685 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2686 auto ch = store->create_new_collection(cid);
2687 {
2688 ObjectStore::Transaction t;
2689 t.create_collection(cid, 0);
2690 t.touch(cid, hoid);
2691 r = queue_transaction(store, ch, std::move(t));
2692 ASSERT_EQ(r, 0);
2693 }
2694 {
2695 ObjectStore::Transaction t;
2696 bufferlist empty;
2697 t.write(cid, hoid, 1048576, 0, empty);
2698 r = queue_transaction(store, ch, std::move(t));
2699 ASSERT_EQ(r, 0);
2700 }
2701 struct stat stat;
2702 r = store->stat(ch, hoid, &stat);
2703 ASSERT_EQ(0, r);
2704 ASSERT_EQ(0, stat.st_size);
2705
2706 bufferlist newdata;
2707 r = store->read(ch, hoid, 0, 1048576, newdata);
2708 ASSERT_EQ(0, r);
2709 }
2710
2711 TEST_P(StoreTest, ZeroLengthZero) {
2712 int r;
2713 coll_t cid;
2714 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2715 auto ch = store->create_new_collection(cid);
2716 {
2717 ObjectStore::Transaction t;
2718 t.create_collection(cid, 0);
2719 t.touch(cid, hoid);
2720 r = queue_transaction(store, ch, std::move(t));
2721 ASSERT_EQ(0, r);
2722 }
2723 {
2724 ObjectStore::Transaction t;
2725 t.zero(cid, hoid, 1048576, 0);
2726 r = queue_transaction(store, ch, std::move(t));
2727 ASSERT_EQ(0, r);
2728 }
2729 struct stat stat;
2730 r = store->stat(ch, hoid, &stat);
2731 ASSERT_EQ(0, r);
2732 ASSERT_EQ(0, stat.st_size);
2733
2734 bufferlist newdata;
2735 r = store->read(ch, hoid, 0, 1048576, newdata);
2736 ASSERT_EQ(0, r);
2737 }
2738
2739 TEST_P(StoreTest, SimpleAttrTest) {
2740 int r;
2741 coll_t cid;
2742 ghobject_t hoid(hobject_t(sobject_t("attr object 1", CEPH_NOSNAP)));
2743 bufferlist val, val2;
2744 val.append("value");
2745 val.append("value2");
2746 {
2747 auto ch = store->open_collection(cid);
2748 ASSERT_FALSE(ch);
2749 }
2750 auto ch = store->create_new_collection(cid);
2751 {
2752 ObjectStore::Transaction t;
2753 t.create_collection(cid, 0);
2754 r = queue_transaction(store, ch, std::move(t));
2755 ASSERT_EQ(r, 0);
2756 }
2757 {
2758 bool empty;
2759 int r = store->collection_empty(ch, &empty);
2760 ASSERT_EQ(0, r);
2761 ASSERT_TRUE(empty);
2762 }
2763 {
2764 bufferptr bp;
2765 r = store->getattr(ch, hoid, "nofoo", bp);
2766 ASSERT_EQ(-ENOENT, r);
2767 }
2768 {
2769 ObjectStore::Transaction t;
2770 t.touch(cid, hoid);
2771 t.setattr(cid, hoid, "foo", val);
2772 t.setattr(cid, hoid, "bar", val2);
2773 r = queue_transaction(store, ch, std::move(t));
2774 ASSERT_EQ(r, 0);
2775 }
2776 {
2777 bool empty;
2778 int r = store->collection_empty(ch, &empty);
2779 ASSERT_EQ(0, r);
2780 ASSERT_TRUE(!empty);
2781 }
2782 {
2783 bufferptr bp;
2784 r = store->getattr(ch, hoid, "nofoo", bp);
2785 ASSERT_EQ(-ENODATA, r);
2786
2787 r = store->getattr(ch, hoid, "foo", bp);
2788 ASSERT_EQ(0, r);
2789 bufferlist bl;
2790 bl.append(bp);
2791 ASSERT_TRUE(bl_eq(val, bl));
2792
2793 map<string,bufferptr> bm;
2794 r = store->getattrs(ch, hoid, bm);
2795 ASSERT_EQ(0, r);
2796
2797 }
2798 {
2799 ObjectStore::Transaction t;
2800 t.remove(cid, hoid);
2801 t.remove_collection(cid);
2802 r = queue_transaction(store, ch, std::move(t));
2803 ASSERT_EQ(r, 0);
2804 }
2805 }
2806
2807 TEST_P(StoreTest, SimpleListTest) {
2808 int r;
2809 coll_t cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2810 auto ch = store->create_new_collection(cid);
2811 {
2812 ObjectStore::Transaction t;
2813 t.create_collection(cid, 0);
2814 cerr << "Creating collection " << cid << std::endl;
2815 r = queue_transaction(store, ch, std::move(t));
2816 ASSERT_EQ(r, 0);
2817 }
2818 set<ghobject_t> all;
2819 {
2820 ObjectStore::Transaction t;
2821 for (int i=0; i<200; ++i) {
2822 string name("object_");
2823 name += stringify(i);
2824 ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)),
2825 ghobject_t::NO_GEN, shard_id_t(1));
2826 hoid.hobj.pool = 1;
2827 all.insert(hoid);
2828 t.touch(cid, hoid);
2829 cerr << "Creating object " << hoid << std::endl;
2830 }
2831 r = queue_transaction(store, ch, std::move(t));
2832 ASSERT_EQ(r, 0);
2833 }
2834 {
2835 set<ghobject_t> saw;
2836 vector<ghobject_t> objects;
2837 ghobject_t next, current;
2838 while (!next.is_max()) {
2839 int r = store->collection_list(ch, current, ghobject_t::get_max(),
2840 50,
2841 &objects, &next);
2842 ASSERT_EQ(r, 0);
2843 ASSERT_TRUE(sorted(objects));
2844 cout << " got " << objects.size() << " next " << next << std::endl;
2845 for (vector<ghobject_t>::iterator p = objects.begin(); p != objects.end();
2846 ++p) {
2847 if (saw.count(*p)) {
2848 cout << "got DUP " << *p << std::endl;
2849 } else {
2850 //cout << "got new " << *p << std::endl;
2851 }
2852 saw.insert(*p);
2853 }
2854 objects.clear();
2855 current = next;
2856 }
2857 ASSERT_EQ(saw.size(), all.size());
2858 ASSERT_EQ(saw, all);
2859 }
2860 {
2861 ObjectStore::Transaction t;
2862 for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
2863 t.remove(cid, *p);
2864 t.remove_collection(cid);
2865 cerr << "Cleaning" << std::endl;
2866 r = queue_transaction(store, ch, std::move(t));
2867 ASSERT_EQ(r, 0);
2868 }
2869 }
2870
2871 TEST_P(StoreTest, ListEndTest) {
2872 int r;
2873 coll_t cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2874 auto ch = store->create_new_collection(cid);
2875 {
2876 ObjectStore::Transaction t;
2877 t.create_collection(cid, 0);
2878 cerr << "Creating collection " << cid << std::endl;
2879 r = queue_transaction(store, ch, std::move(t));
2880 ASSERT_EQ(r, 0);
2881 }
2882 set<ghobject_t> all;
2883 {
2884 ObjectStore::Transaction t;
2885 for (int i=0; i<200; ++i) {
2886 string name("object_");
2887 name += stringify(i);
2888 ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)),
2889 ghobject_t::NO_GEN, shard_id_t(1));
2890 hoid.hobj.pool = 1;
2891 all.insert(hoid);
2892 t.touch(cid, hoid);
2893 cerr << "Creating object " << hoid << std::endl;
2894 }
2895 r = queue_transaction(store, ch, std::move(t));
2896 ASSERT_EQ(r, 0);
2897 }
2898 {
2899 ghobject_t end(hobject_t(sobject_t("object_100", CEPH_NOSNAP)),
2900 ghobject_t::NO_GEN, shard_id_t(1));
2901 end.hobj.pool = 1;
2902 vector<ghobject_t> objects;
2903 ghobject_t next;
2904 int r = store->collection_list(ch, ghobject_t(), end, 500,
2905 &objects, &next);
2906 ASSERT_EQ(r, 0);
2907 for (auto &p : objects) {
2908 ASSERT_NE(p, end);
2909 }
2910 }
2911 {
2912 ObjectStore::Transaction t;
2913 for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
2914 t.remove(cid, *p);
2915 t.remove_collection(cid);
2916 cerr << "Cleaning" << std::endl;
2917 r = queue_transaction(store, ch, std::move(t));
2918 ASSERT_EQ(r, 0);
2919 }
2920 }
2921
2922 TEST_P(StoreTest, Sort) {
2923 {
2924 hobject_t a(sobject_t("a", CEPH_NOSNAP));
2925 hobject_t b = a;
2926 ASSERT_EQ(a, b);
2927 b.oid.name = "b";
2928 ASSERT_NE(a, b);
2929 ASSERT_TRUE(a < b);
2930 a.pool = 1;
2931 b.pool = 2;
2932 ASSERT_TRUE(a < b);
2933 a.pool = 3;
2934 ASSERT_TRUE(a > b);
2935 }
2936 {
2937 ghobject_t a(hobject_t(sobject_t("a", CEPH_NOSNAP)));
2938 ghobject_t b(hobject_t(sobject_t("b", CEPH_NOSNAP)));
2939 a.hobj.pool = 1;
2940 b.hobj.pool = 1;
2941 ASSERT_TRUE(a < b);
2942 a.hobj.pool = -3;
2943 ASSERT_TRUE(a < b);
2944 a.hobj.pool = 1;
2945 b.hobj.pool = -3;
2946 ASSERT_TRUE(a > b);
2947 }
2948 }
2949
2950 TEST_P(StoreTest, MultipoolListTest) {
2951 int r;
2952 int poolid = 4373;
2953 coll_t cid = coll_t(spg_t(pg_t(0, poolid), shard_id_t::NO_SHARD));
2954 auto ch = store->create_new_collection(cid);
2955 {
2956 ObjectStore::Transaction t;
2957 t.create_collection(cid, 0);
2958 cerr << "Creating collection " << cid << std::endl;
2959 r = queue_transaction(store, ch, std::move(t));
2960 ASSERT_EQ(r, 0);
2961 }
2962 set<ghobject_t> all, saw;
2963 {
2964 ObjectStore::Transaction t;
2965 for (int i=0; i<200; ++i) {
2966 string name("object_");
2967 name += stringify(i);
2968 ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)));
2969 if (rand() & 1)
2970 hoid.hobj.pool = -2 - poolid;
2971 else
2972 hoid.hobj.pool = poolid;
2973 all.insert(hoid);
2974 t.touch(cid, hoid);
2975 cerr << "Creating object " << hoid << std::endl;
2976 }
2977 r = queue_transaction(store, ch, std::move(t));
2978 ASSERT_EQ(r, 0);
2979 }
2980 {
2981 vector<ghobject_t> objects;
2982 ghobject_t next, current;
2983 while (!next.is_max()) {
2984 int r = store->collection_list(ch, current, ghobject_t::get_max(), 50,
2985 &objects, &next);
2986 ASSERT_EQ(r, 0);
2987 cout << " got " << objects.size() << " next " << next << std::endl;
2988 for (vector<ghobject_t>::iterator p = objects.begin(); p != objects.end();
2989 ++p) {
2990 saw.insert(*p);
2991 }
2992 objects.clear();
2993 current = next;
2994 }
2995 ASSERT_EQ(saw, all);
2996 }
2997 {
2998 ObjectStore::Transaction t;
2999 for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
3000 t.remove(cid, *p);
3001 t.remove_collection(cid);
3002 cerr << "Cleaning" << std::endl;
3003 r = queue_transaction(store, ch, std::move(t));
3004 ASSERT_EQ(r, 0);
3005 }
3006 }
3007
3008 TEST_P(StoreTest, SimpleCloneTest) {
3009 int r;
3010 coll_t cid;
3011 auto ch = store->create_new_collection(cid);
3012 {
3013 ObjectStore::Transaction t;
3014 t.create_collection(cid, 0);
3015 cerr << "Creating collection " << cid << std::endl;
3016 r = queue_transaction(store, ch, std::move(t));
3017 ASSERT_EQ(r, 0);
3018 }
3019 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP),
3020 "key", 123, -1, ""));
3021 bufferlist small, large, xlarge, newdata, attr;
3022 small.append("small");
3023 large.append("large");
3024 xlarge.append("xlarge");
3025 {
3026 ObjectStore::Transaction t;
3027 t.touch(cid, hoid);
3028 t.setattr(cid, hoid, "attr1", small);
3029 t.setattr(cid, hoid, "attr2", large);
3030 t.setattr(cid, hoid, "attr3", xlarge);
3031 t.write(cid, hoid, 0, small.length(), small);
3032 t.write(cid, hoid, 10, small.length(), small);
3033 cerr << "Creating object and set attr " << hoid << std::endl;
3034 r = queue_transaction(store, ch, std::move(t));
3035 ASSERT_EQ(r, 0);
3036 }
3037
3038 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP),
3039 "key", 123, -1, ""));
3040 ghobject_t hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP)));
3041 {
3042 ObjectStore::Transaction t;
3043 t.clone(cid, hoid, hoid2);
3044 t.setattr(cid, hoid2, "attr2", small);
3045 t.rmattr(cid, hoid2, "attr1");
3046 t.write(cid, hoid, 10, large.length(), large);
3047 t.setattr(cid, hoid, "attr1", large);
3048 t.setattr(cid, hoid, "attr2", small);
3049 cerr << "Clone object and rm attr" << std::endl;
3050 r = queue_transaction(store, ch, std::move(t));
3051 ASSERT_EQ(r, 0);
3052
3053 r = store->read(ch, hoid, 10, 5, newdata);
3054 ASSERT_EQ(r, 5);
3055 ASSERT_TRUE(bl_eq(large, newdata));
3056
3057 newdata.clear();
3058 r = store->read(ch, hoid, 0, 5, newdata);
3059 ASSERT_EQ(r, 5);
3060 ASSERT_TRUE(bl_eq(small, newdata));
3061
3062 newdata.clear();
3063 r = store->read(ch, hoid2, 10, 5, newdata);
3064 ASSERT_EQ(r, 5);
3065 ASSERT_TRUE(bl_eq(small, newdata));
3066
3067 r = store->getattr(ch, hoid2, "attr2", attr);
3068 ASSERT_EQ(r, 0);
3069 ASSERT_TRUE(bl_eq(small, attr));
3070
3071 attr.clear();
3072 r = store->getattr(ch, hoid2, "attr3", attr);
3073 ASSERT_EQ(r, 0);
3074 ASSERT_TRUE(bl_eq(xlarge, attr));
3075
3076 attr.clear();
3077 r = store->getattr(ch, hoid, "attr1", attr);
3078 ASSERT_EQ(r, 0);
3079 ASSERT_TRUE(bl_eq(large, attr));
3080 }
3081 {
3082 ObjectStore::Transaction t;
3083 t.remove(cid, hoid);
3084 t.remove(cid, hoid2);
3085 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3086 }
3087 {
3088 bufferlist final;
3089 bufferptr p(16384);
3090 memset(p.c_str(), 1, p.length());
3091 bufferlist pl;
3092 pl.append(p);
3093 final.append(p);
3094 ObjectStore::Transaction t;
3095 t.write(cid, hoid, 0, pl.length(), pl);
3096 t.clone(cid, hoid, hoid2);
3097 bufferptr a(4096);
3098 memset(a.c_str(), 2, a.length());
3099 bufferlist al;
3100 al.append(a);
3101 final.append(a);
3102 t.write(cid, hoid, pl.length(), a.length(), al);
3103 r = queue_transaction(store, ch, std::move(t));
3104 ASSERT_EQ(r, 0);
3105 bufferlist rl;
3106 ASSERT_EQ((int)final.length(),
3107 store->read(ch, hoid, 0, final.length(), rl));
3108 ASSERT_TRUE(bl_eq(rl, final));
3109 }
3110 {
3111 ObjectStore::Transaction t;
3112 t.remove(cid, hoid);
3113 t.remove(cid, hoid2);
3114 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3115 }
3116 {
3117 bufferlist final;
3118 bufferptr p(16384);
3119 memset(p.c_str(), 111, p.length());
3120 bufferlist pl;
3121 pl.append(p);
3122 final.append(p);
3123 ObjectStore::Transaction t;
3124 t.write(cid, hoid, 0, pl.length(), pl);
3125 t.clone(cid, hoid, hoid2);
3126 bufferptr z(4096);
3127 z.zero();
3128 final.append(z);
3129 bufferptr a(4096);
3130 memset(a.c_str(), 112, a.length());
3131 bufferlist al;
3132 al.append(a);
3133 final.append(a);
3134 t.write(cid, hoid, pl.length() + z.length(), a.length(), al);
3135 r = queue_transaction(store, ch, std::move(t));
3136 ASSERT_EQ(r, 0);
3137 bufferlist rl;
3138 ASSERT_EQ((int)final.length(),
3139 store->read(ch, hoid, 0, final.length(), rl));
3140 ASSERT_TRUE(bl_eq(rl, final));
3141 }
3142 {
3143 ObjectStore::Transaction t;
3144 t.remove(cid, hoid);
3145 t.remove(cid, hoid2);
3146 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3147 }
3148 {
3149 bufferlist final;
3150 bufferptr p(16000);
3151 memset(p.c_str(), 5, p.length());
3152 bufferlist pl;
3153 pl.append(p);
3154 final.append(p);
3155 ObjectStore::Transaction t;
3156 t.write(cid, hoid, 0, pl.length(), pl);
3157 t.clone(cid, hoid, hoid2);
3158 bufferptr z(1000);
3159 z.zero();
3160 final.append(z);
3161 bufferptr a(8000);
3162 memset(a.c_str(), 6, a.length());
3163 bufferlist al;
3164 al.append(a);
3165 final.append(a);
3166 t.write(cid, hoid, 17000, a.length(), al);
3167 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3168 bufferlist rl;
3169 ASSERT_EQ((int)final.length(),
3170 store->read(ch, hoid, 0, final.length(), rl));
3171 /*cout << "expected:\n";
3172 final.hexdump(cout);
3173 cout << "got:\n";
3174 rl.hexdump(cout);*/
3175 ASSERT_TRUE(bl_eq(rl, final));
3176 }
3177 {
3178 ObjectStore::Transaction t;
3179 t.remove(cid, hoid);
3180 t.remove(cid, hoid2);
3181 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3182 }
3183 {
3184 bufferptr p(1048576);
3185 memset(p.c_str(), 3, p.length());
3186 bufferlist pl;
3187 pl.append(p);
3188 ObjectStore::Transaction t;
3189 t.write(cid, hoid, 0, pl.length(), pl);
3190 t.clone(cid, hoid, hoid2);
3191 bufferptr a(65536);
3192 memset(a.c_str(), 4, a.length());
3193 bufferlist al;
3194 al.append(a);
3195 t.write(cid, hoid, a.length(), a.length(), al);
3196 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3197 bufferlist rl;
3198 bufferlist final;
3199 final.substr_of(pl, 0, al.length());
3200 final.append(al);
3201 bufferlist end;
3202 end.substr_of(pl, al.length()*2, pl.length() - al.length()*2);
3203 final.append(end);
3204 ASSERT_EQ((int)final.length(),
3205 store->read(ch, hoid, 0, final.length(), rl));
3206 /*cout << "expected:\n";
3207 final.hexdump(cout);
3208 cout << "got:\n";
3209 rl.hexdump(cout);*/
3210 ASSERT_TRUE(bl_eq(rl, final));
3211 }
3212 {
3213 ObjectStore::Transaction t;
3214 t.remove(cid, hoid);
3215 t.remove(cid, hoid2);
3216 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3217 }
3218 {
3219 bufferptr p(65536);
3220 memset(p.c_str(), 7, p.length());
3221 bufferlist pl;
3222 pl.append(p);
3223 ObjectStore::Transaction t;
3224 t.write(cid, hoid, 0, pl.length(), pl);
3225 t.clone(cid, hoid, hoid2);
3226 bufferptr a(4096);
3227 memset(a.c_str(), 8, a.length());
3228 bufferlist al;
3229 al.append(a);
3230 t.write(cid, hoid, 32768, a.length(), al);
3231 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3232 bufferlist rl;
3233 bufferlist final;
3234 final.substr_of(pl, 0, 32768);
3235 final.append(al);
3236 bufferlist end;
3237 end.substr_of(pl, final.length(), pl.length() - final.length());
3238 final.append(end);
3239 ASSERT_EQ((int)final.length(),
3240 store->read(ch, hoid, 0, final.length(), rl));
3241 /*cout << "expected:\n";
3242 final.hexdump(cout);
3243 cout << "got:\n";
3244 rl.hexdump(cout);*/
3245 ASSERT_TRUE(bl_eq(rl, final));
3246 }
3247 {
3248 ObjectStore::Transaction t;
3249 t.remove(cid, hoid);
3250 t.remove(cid, hoid2);
3251 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3252 }
3253 {
3254 bufferptr p(65536);
3255 memset(p.c_str(), 9, p.length());
3256 bufferlist pl;
3257 pl.append(p);
3258 ObjectStore::Transaction t;
3259 t.write(cid, hoid, 0, pl.length(), pl);
3260 t.clone(cid, hoid, hoid2);
3261 bufferptr a(4096);
3262 memset(a.c_str(), 10, a.length());
3263 bufferlist al;
3264 al.append(a);
3265 t.write(cid, hoid, 33768, a.length(), al);
3266 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3267 bufferlist rl;
3268 bufferlist final;
3269 final.substr_of(pl, 0, 33768);
3270 final.append(al);
3271 bufferlist end;
3272 end.substr_of(pl, final.length(), pl.length() - final.length());
3273 final.append(end);
3274 ASSERT_EQ((int)final.length(),
3275 store->read(ch, hoid, 0, final.length(), rl));
3276 /*cout << "expected:\n";
3277 final.hexdump(cout);
3278 cout << "got:\n";
3279 rl.hexdump(cout);*/
3280 ASSERT_TRUE(bl_eq(rl, final));
3281 }
3282
3283 //Unfortunately we need a workaround for filestore since EXPECT_DEATH
3284 // macro has potential issues when using /in multithread environments.
3285 //It works well for all stores but filestore for now.
3286 //A fix setting gtest_death_test_style = "threadsafe" doesn't help as well -
3287 // test app clone asserts on store folder presence.
3288 //
3289 if (string(GetParam()) != "filestore") {
3290 //verify if non-empty collection is properly handled after store reload
3291 ch.reset();
3292 r = store->umount();
3293 ASSERT_EQ(r, 0);
3294 r = store->mount();
3295 ASSERT_EQ(r, 0);
3296 ch = store->open_collection(cid);
3297
3298 ObjectStore::Transaction t;
3299 t.remove_collection(cid);
3300 cerr << "Invalid rm coll" << std::endl;
3301 PrCtl unset_dumpable;
3302 EXPECT_DEATH(queue_transaction(store, ch, std::move(t)), "");
3303 }
3304 {
3305 ObjectStore::Transaction t;
3306 t.touch(cid, hoid3); //new record in db
3307 r = queue_transaction(store, ch, std::move(t));
3308 ASSERT_EQ(r, 0);
3309 }
3310 //See comment above for "filestore" check explanation.
3311 if (string(GetParam()) != "filestore") {
3312 ObjectStore::Transaction t;
3313 //verify if non-empty collection is properly handled when there are some pending removes and live records in db
3314 cerr << "Invalid rm coll again" << std::endl;
3315 ch.reset();
3316 r = store->umount();
3317 ASSERT_EQ(r, 0);
3318 r = store->mount();
3319 ASSERT_EQ(r, 0);
3320 ch = store->open_collection(cid);
3321
3322 t.remove(cid, hoid);
3323 t.remove(cid, hoid2);
3324 t.remove_collection(cid);
3325 PrCtl unset_dumpable;
3326 EXPECT_DEATH(queue_transaction(store, ch, std::move(t)), "");
3327 }
3328 {
3329 ObjectStore::Transaction t;
3330 t.remove(cid, hoid);
3331 t.remove(cid, hoid2);
3332 t.remove(cid, hoid3);
3333 t.remove_collection(cid);
3334 cerr << "Cleaning" << std::endl;
3335 r = queue_transaction(store, ch, std::move(t));
3336 ASSERT_EQ(r, 0);
3337 }
3338 }
3339
3340 TEST_P(StoreTest, OmapSimple) {
3341 int r;
3342 coll_t cid;
3343 auto ch = store->create_new_collection(cid);
3344 {
3345 ObjectStore::Transaction t;
3346 t.create_collection(cid, 0);
3347 cerr << "Creating collection " << cid << std::endl;
3348 r = queue_transaction(store, ch, std::move(t));
3349 ASSERT_EQ(r, 0);
3350 }
3351 ghobject_t hoid(hobject_t(sobject_t("omap_obj", CEPH_NOSNAP),
3352 "key", 123, -1, ""));
3353 bufferlist small;
3354 small.append("small");
3355 map<string,bufferlist> km;
3356 km["foo"] = small;
3357 km["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3358 bufferlist header;
3359 header.append("this is a header");
3360 {
3361 ObjectStore::Transaction t;
3362 t.touch(cid, hoid);
3363 t.omap_setkeys(cid, hoid, km);
3364 t.omap_setheader(cid, hoid, header);
3365 cerr << "Creating object and set omap " << hoid << std::endl;
3366 r = queue_transaction(store, ch, std::move(t));
3367 ASSERT_EQ(r, 0);
3368 }
3369 // get header, keys
3370 {
3371 bufferlist h;
3372 map<string,bufferlist> r;
3373 store->omap_get(ch, hoid, &h, &r);
3374 ASSERT_TRUE(bl_eq(header, h));
3375 ASSERT_EQ(r.size(), km.size());
3376 cout << "r: " << r << std::endl;
3377 }
3378 // test iterator with seek_to_first
3379 {
3380 map<string,bufferlist> r;
3381 ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(ch, hoid);
3382 for (iter->seek_to_first(); iter->valid(); iter->next()) {
3383 r[iter->key()] = iter->value();
3384 }
3385 cout << "r: " << r << std::endl;
3386 ASSERT_EQ(r.size(), km.size());
3387 }
3388 // test iterator with initial lower_bound
3389 {
3390 map<string,bufferlist> r;
3391 ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(ch, hoid);
3392 for (iter->lower_bound(string()); iter->valid(); iter->next()) {
3393 r[iter->key()] = iter->value();
3394 }
3395 cout << "r: " << r << std::endl;
3396 ASSERT_EQ(r.size(), km.size());
3397 }
3398 {
3399 ObjectStore::Transaction t;
3400 t.remove(cid, hoid);
3401 t.remove_collection(cid);
3402 cerr << "Cleaning" << std::endl;
3403 r = queue_transaction(store, ch, std::move(t));
3404 ASSERT_EQ(r, 0);
3405 }
3406 }
3407
3408 TEST_P(StoreTest, OmapCloneTest) {
3409 int r;
3410 coll_t cid;
3411 auto ch = store->create_new_collection(cid);
3412 {
3413 ObjectStore::Transaction t;
3414 t.create_collection(cid, 0);
3415 cerr << "Creating collection " << cid << std::endl;
3416 r = queue_transaction(store, ch, std::move(t));
3417 ASSERT_EQ(r, 0);
3418 }
3419 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP),
3420 "key", 123, -1, ""));
3421 bufferlist small;
3422 small.append("small");
3423 map<string,bufferlist> km;
3424 km["foo"] = small;
3425 km["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3426 bufferlist header;
3427 header.append("this is a header");
3428 {
3429 ObjectStore::Transaction t;
3430 t.touch(cid, hoid);
3431 t.omap_setkeys(cid, hoid, km);
3432 t.omap_setheader(cid, hoid, header);
3433 cerr << "Creating object and set omap " << hoid << std::endl;
3434 r = queue_transaction(store, ch, std::move(t));
3435 ASSERT_EQ(r, 0);
3436 }
3437 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP),
3438 "key", 123, -1, ""));
3439 {
3440 ObjectStore::Transaction t;
3441 t.clone(cid, hoid, hoid2);
3442 cerr << "Clone object" << std::endl;
3443 r = queue_transaction(store, ch, std::move(t));
3444 ASSERT_EQ(r, 0);
3445 }
3446 {
3447 map<string,bufferlist> r;
3448 bufferlist h;
3449 store->omap_get(ch, hoid2, &h, &r);
3450 ASSERT_TRUE(bl_eq(header, h));
3451 ASSERT_EQ(r.size(), km.size());
3452 }
3453 {
3454 ObjectStore::Transaction t;
3455 t.remove(cid, hoid);
3456 t.remove(cid, hoid2);
3457 t.remove_collection(cid);
3458 cerr << "Cleaning" << std::endl;
3459 r = queue_transaction(store, ch, std::move(t));
3460 ASSERT_EQ(r, 0);
3461 }
3462 }
3463
3464 TEST_P(StoreTest, SimpleCloneRangeTest) {
3465 int r;
3466 coll_t cid;
3467 auto ch = store->create_new_collection(cid);
3468 {
3469 ObjectStore::Transaction t;
3470 t.create_collection(cid, 0);
3471 cerr << "Creating collection " << cid << std::endl;
3472 r = queue_transaction(store, ch, std::move(t));
3473 ASSERT_EQ(r, 0);
3474 }
3475 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
3476 hoid.hobj.pool = -1;
3477 bufferlist small, newdata;
3478 small.append("small");
3479 {
3480 ObjectStore::Transaction t;
3481 t.write(cid, hoid, 10, 5, small);
3482 cerr << "Creating object and write bl " << hoid << std::endl;
3483 r = queue_transaction(store, ch, std::move(t));
3484 ASSERT_EQ(r, 0);
3485 }
3486 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
3487 hoid2.hobj.pool = -1;
3488 {
3489 ObjectStore::Transaction t;
3490 t.clone_range(cid, hoid, hoid2, 10, 5, 10);
3491 cerr << "Clone range object" << std::endl;
3492 r = queue_transaction(store, ch, std::move(t));
3493 ASSERT_EQ(r, 0);
3494 r = store->read(ch, hoid2, 10, 5, newdata);
3495 ASSERT_EQ(r, 5);
3496 ASSERT_TRUE(bl_eq(small, newdata));
3497 }
3498 {
3499 ObjectStore::Transaction t;
3500 t.truncate(cid, hoid, 1024*1024);
3501 t.clone_range(cid, hoid, hoid2, 0, 1024*1024, 0);
3502 cerr << "Clone range object" << std::endl;
3503 r = queue_transaction(store, ch, std::move(t));
3504 ASSERT_EQ(r, 0);
3505 struct stat stat, stat2;
3506 r = store->stat(ch, hoid, &stat);
3507 r = store->stat(ch, hoid2, &stat2);
3508 ASSERT_EQ(stat.st_size, stat2.st_size);
3509 ASSERT_EQ(1024*1024, stat2.st_size);
3510 }
3511 {
3512 ObjectStore::Transaction t;
3513 t.remove(cid, hoid);
3514 t.remove(cid, hoid2);
3515 t.remove_collection(cid);
3516 cerr << "Cleaning" << std::endl;
3517 r = queue_transaction(store, ch, std::move(t));
3518 ASSERT_EQ(r, 0);
3519 }
3520 }
3521
3522
3523 TEST_P(StoreTest, SimpleObjectLongnameTest) {
3524 int r;
3525 coll_t cid;
3526 auto ch = store->create_new_collection(cid);
3527 {
3528 ObjectStore::Transaction t;
3529 t.create_collection(cid, 0);
3530 cerr << "Creating collection " << cid << std::endl;
3531 r = queue_transaction(store, ch, std::move(t));
3532 ASSERT_EQ(r, 0);
3533 }
3534 ghobject_t hoid(hobject_t(sobject_t("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaObjectaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1", CEPH_NOSNAP)));
3535 {
3536 ObjectStore::Transaction t;
3537 t.touch(cid, hoid);
3538 cerr << "Creating object " << hoid << std::endl;
3539 r = queue_transaction(store, ch, std::move(t));
3540 ASSERT_EQ(r, 0);
3541 }
3542 {
3543 ObjectStore::Transaction t;
3544 t.remove(cid, hoid);
3545 t.remove_collection(cid);
3546 cerr << "Cleaning" << std::endl;
3547 r = queue_transaction(store, ch, std::move(t));
3548 ASSERT_EQ(r, 0);
3549 }
3550 }
3551
3552 ghobject_t generate_long_name(unsigned i)
3553 {
3554 stringstream name;
3555 name << "object id " << i << " ";
3556 for (unsigned j = 0; j < 500; ++j) name << 'a';
3557 ghobject_t hoid(hobject_t(sobject_t(name.str(), CEPH_NOSNAP)));
3558 hoid.hobj.set_hash(i % 2);
3559 return hoid;
3560 }
3561
3562 TEST_P(StoreTest, LongnameSplitTest) {
3563 int r;
3564 coll_t cid;
3565 auto ch = store->create_new_collection(cid);
3566 {
3567 ObjectStore::Transaction t;
3568 t.create_collection(cid, 0);
3569 cerr << "Creating collection " << cid << std::endl;
3570 r = queue_transaction(store, ch, std::move(t));
3571 ASSERT_EQ(0, r);
3572 }
3573 for (unsigned i = 0; i < 320; ++i) {
3574 ObjectStore::Transaction t;
3575 ghobject_t hoid = generate_long_name(i);
3576 t.touch(cid, hoid);
3577 cerr << "Creating object " << hoid << std::endl;
3578 r = queue_transaction(store, ch, std::move(t));
3579 ASSERT_EQ(0, r);
3580 }
3581
3582 ghobject_t test_obj = generate_long_name(319);
3583 ghobject_t test_obj_2 = test_obj;
3584 test_obj_2.generation = 0;
3585 {
3586 ObjectStore::Transaction t;
3587 // should cause a split
3588 t.collection_move_rename(
3589 cid, test_obj,
3590 cid, test_obj_2);
3591 r = queue_transaction(store, ch, std::move(t));
3592 ASSERT_EQ(0, r);
3593 }
3594
3595 for (unsigned i = 0; i < 319; ++i) {
3596 ObjectStore::Transaction t;
3597 ghobject_t hoid = generate_long_name(i);
3598 t.remove(cid, hoid);
3599 cerr << "Removing object " << hoid << std::endl;
3600 r = queue_transaction(store, ch, std::move(t));
3601 ASSERT_EQ(0, r);
3602 }
3603 {
3604 ObjectStore::Transaction t;
3605 t.remove(cid, test_obj_2);
3606 t.remove_collection(cid);
3607 cerr << "Cleaning" << std::endl;
3608 r = queue_transaction(store, ch, std::move(t));
3609 ASSERT_EQ(0, r);
3610 }
3611
3612 }
3613
3614 TEST_P(StoreTest, ManyObjectTest) {
3615 int NUM_OBJS = 2000;
3616 int r = 0;
3617 coll_t cid;
3618 string base = "";
3619 for (int i = 0; i < 100; ++i) base.append("aaaaa");
3620 set<ghobject_t> created;
3621 auto ch = store->create_new_collection(cid);
3622 {
3623 ObjectStore::Transaction t;
3624 t.create_collection(cid, 0);
3625 r = queue_transaction(store, ch, std::move(t));
3626 ASSERT_EQ(r, 0);
3627 }
3628 for (int i = 0; i < NUM_OBJS; ++i) {
3629 if (!(i % 5)) {
3630 cerr << "Object " << i << std::endl;
3631 }
3632 ObjectStore::Transaction t;
3633 char buf[100];
3634 snprintf(buf, sizeof(buf), "%d", i);
3635 ghobject_t hoid(hobject_t(sobject_t(string(buf) + base, CEPH_NOSNAP)));
3636 t.touch(cid, hoid);
3637 created.insert(hoid);
3638 r = queue_transaction(store, ch, std::move(t));
3639 ASSERT_EQ(r, 0);
3640 }
3641
3642 for (set<ghobject_t>::iterator i = created.begin();
3643 i != created.end();
3644 ++i) {
3645 struct stat buf;
3646 ASSERT_TRUE(!store->stat(ch, *i, &buf));
3647 }
3648
3649 set<ghobject_t> listed, listed2;
3650 vector<ghobject_t> objects;
3651 r = store->collection_list(ch, ghobject_t(), ghobject_t::get_max(), INT_MAX, &objects, 0);
3652 ASSERT_EQ(r, 0);
3653
3654 cerr << "objects.size() is " << objects.size() << std::endl;
3655 for (vector<ghobject_t> ::iterator i = objects.begin();
3656 i != objects.end();
3657 ++i) {
3658 listed.insert(*i);
3659 ASSERT_TRUE(created.count(*i));
3660 }
3661 ASSERT_TRUE(listed.size() == created.size());
3662
3663 ghobject_t start, next;
3664 objects.clear();
3665 r = store->collection_list(
3666 ch,
3667 ghobject_t::get_max(),
3668 ghobject_t::get_max(),
3669 50,
3670 &objects,
3671 &next
3672 );
3673 ASSERT_EQ(r, 0);
3674 ASSERT_TRUE(objects.empty());
3675
3676 objects.clear();
3677 listed.clear();
3678 ghobject_t start2, next2;
3679 while (1) {
3680 r = store->collection_list(ch, start, ghobject_t::get_max(),
3681 50,
3682 &objects,
3683 &next);
3684 ASSERT_TRUE(sorted(objects));
3685 ASSERT_EQ(r, 0);
3686 listed.insert(objects.begin(), objects.end());
3687 if (objects.size() < 50) {
3688 ASSERT_TRUE(next.is_max());
3689 break;
3690 }
3691 objects.clear();
3692
3693 start = next;
3694 }
3695 cerr << "listed.size() is " << listed.size() << std::endl;
3696 ASSERT_TRUE(listed.size() == created.size());
3697 if (listed2.size()) {
3698 ASSERT_EQ(listed.size(), listed2.size());
3699 }
3700 for (set<ghobject_t>::iterator i = listed.begin();
3701 i != listed.end();
3702 ++i) {
3703 ASSERT_TRUE(created.count(*i));
3704 }
3705
3706 for (set<ghobject_t>::iterator i = created.begin();
3707 i != created.end();
3708 ++i) {
3709 ObjectStore::Transaction t;
3710 t.remove(cid, *i);
3711 r = queue_transaction(store, ch, std::move(t));
3712 ASSERT_EQ(r, 0);
3713 }
3714 cerr << "cleaning up" << std::endl;
3715 {
3716 ObjectStore::Transaction t;
3717 t.remove_collection(cid);
3718 r = queue_transaction(store, ch, std::move(t));
3719 ASSERT_EQ(r, 0);
3720 }
3721 }
3722
3723
3724 class ObjectGenerator {
3725 public:
3726 virtual ghobject_t create_object(gen_type *gen) = 0;
3727 virtual ~ObjectGenerator() {}
3728 };
3729
3730 class MixedGenerator : public ObjectGenerator {
3731 public:
3732 unsigned seq;
3733 int64_t poolid;
3734 explicit MixedGenerator(int64_t p) : seq(0), poolid(p) {}
3735 ghobject_t create_object(gen_type *gen) override {
3736 char buf[100];
3737 snprintf(buf, sizeof(buf), "OBJ_%u", seq);
3738 string name(buf);
3739 if (seq % 2) {
3740 for (unsigned i = 0; i < 300; ++i) {
3741 name.push_back('a');
3742 }
3743 }
3744 ++seq;
3745 return ghobject_t(
3746 hobject_t(
3747 name, string(), rand() & 2 ? CEPH_NOSNAP : rand(),
3748 (((seq / 1024) % 2) * 0xF00 ) +
3749 (seq & 0xFF),
3750 poolid, ""));
3751 }
3752 };
3753
3754 class SyntheticWorkloadState {
3755 struct Object {
3756 bufferlist data;
3757 map<string, bufferlist> attrs;
3758 };
3759 public:
3760 static const unsigned max_in_flight = 16;
3761 static const unsigned max_objects = 3000;
3762 static const unsigned max_attr_size = 5;
3763 static const unsigned max_attr_name_len = 100;
3764 static const unsigned max_attr_value_len = 1024 * 64;
3765 coll_t cid;
3766 unsigned write_alignment;
3767 unsigned max_object_len, max_write_len;
3768 unsigned in_flight;
3769 map<ghobject_t, Object> contents;
3770 set<ghobject_t> available_objects;
3771 set<ghobject_t> in_flight_objects;
3772 ObjectGenerator *object_gen;
3773 gen_type *rng;
3774 ObjectStore *store;
3775 ObjectStore::CollectionHandle ch;
3776
3777 ceph::mutex lock = ceph::make_mutex("State lock");
3778 ceph::condition_variable cond;
3779
3780 struct EnterExit {
3781 const char *msg;
3782 explicit EnterExit(const char *m) : msg(m) {
3783 //cout << pthread_self() << " enter " << msg << std::endl;
3784 }
3785 ~EnterExit() {
3786 //cout << pthread_self() << " exit " << msg << std::endl;
3787 }
3788 };
3789
3790 class C_SyntheticOnReadable : public Context {
3791 public:
3792 SyntheticWorkloadState *state;
3793 ghobject_t hoid;
3794 C_SyntheticOnReadable(SyntheticWorkloadState *state, ghobject_t hoid)
3795 : state(state), hoid(hoid) {}
3796
3797 void finish(int r) override {
3798 std::lock_guard locker{state->lock};
3799 EnterExit ee("onreadable finish");
3800 ASSERT_TRUE(state->in_flight_objects.count(hoid));
3801 ASSERT_EQ(r, 0);
3802 state->in_flight_objects.erase(hoid);
3803 if (state->contents.count(hoid))
3804 state->available_objects.insert(hoid);
3805 --(state->in_flight);
3806 state->cond.notify_all();
3807
3808 bufferlist r2;
3809 r = state->store->read(state->ch, hoid, 0, state->contents[hoid].data.length(), r2);
3810 ceph_assert(bl_eq(state->contents[hoid].data, r2));
3811 state->cond.notify_all();
3812 }
3813 };
3814
3815 class C_SyntheticOnStash : public Context {
3816 public:
3817 SyntheticWorkloadState *state;
3818 ghobject_t oid, noid;
3819
3820 C_SyntheticOnStash(SyntheticWorkloadState *state,
3821 ghobject_t oid, ghobject_t noid)
3822 : state(state), oid(oid), noid(noid) {}
3823
3824 void finish(int r) override {
3825 std::lock_guard locker{state->lock};
3826 EnterExit ee("stash finish");
3827 ASSERT_TRUE(state->in_flight_objects.count(oid));
3828 ASSERT_EQ(r, 0);
3829 state->in_flight_objects.erase(oid);
3830 if (state->contents.count(noid))
3831 state->available_objects.insert(noid);
3832 --(state->in_flight);
3833 bufferlist r2;
3834 r = state->store->read(
3835 state->ch, noid, 0,
3836 state->contents[noid].data.length(), r2);
3837 ceph_assert(bl_eq(state->contents[noid].data, r2));
3838 state->cond.notify_all();
3839 }
3840 };
3841
3842 class C_SyntheticOnClone : public Context {
3843 public:
3844 SyntheticWorkloadState *state;
3845 ghobject_t oid, noid;
3846
3847 C_SyntheticOnClone(SyntheticWorkloadState *state,
3848 ghobject_t oid, ghobject_t noid)
3849 : state(state), oid(oid), noid(noid) {}
3850
3851 void finish(int r) override {
3852 std::lock_guard locker{state->lock};
3853 EnterExit ee("clone finish");
3854 ASSERT_TRUE(state->in_flight_objects.count(oid));
3855 ASSERT_EQ(r, 0);
3856 state->in_flight_objects.erase(oid);
3857 if (state->contents.count(oid))
3858 state->available_objects.insert(oid);
3859 if (state->contents.count(noid))
3860 state->available_objects.insert(noid);
3861 --(state->in_flight);
3862 bufferlist r2;
3863 r = state->store->read(state->ch, noid, 0, state->contents[noid].data.length(), r2);
3864 ceph_assert(bl_eq(state->contents[noid].data, r2));
3865 state->cond.notify_all();
3866 }
3867 };
3868
3869 static void filled_byte_array(bufferlist& bl, size_t size)
3870 {
3871 static const char alphanum[] = "0123456789"
3872 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3873 "abcdefghijklmnopqrstuvwxyz";
3874 if (!size) {
3875 return;
3876 }
3877 bufferptr bp(size);
3878 for (unsigned int i = 0; i < size - 1; i++) {
3879 // severely limit entropy so we can compress...
3880 bp[i] = alphanum[rand() % 10]; //(sizeof(alphanum) - 1)];
3881 }
3882 bp[size - 1] = '\0';
3883
3884 bl.append(bp);
3885 }
3886
3887 SyntheticWorkloadState(ObjectStore *store,
3888 ObjectGenerator *gen,
3889 gen_type *rng,
3890 coll_t cid,
3891 unsigned max_size,
3892 unsigned max_write,
3893 unsigned alignment)
3894 : cid(cid), write_alignment(alignment), max_object_len(max_size),
3895 max_write_len(max_write), in_flight(0), object_gen(gen),
3896 rng(rng), store(store) {}
3897
3898 int init() {
3899 ObjectStore::Transaction t;
3900 ch = store->create_new_collection(cid);
3901 t.create_collection(cid, 0);
3902 return queue_transaction(store, ch, std::move(t));
3903 }
3904 void shutdown() {
3905 while (1) {
3906 vector<ghobject_t> objects;
3907 int r = store->collection_list(ch, ghobject_t(), ghobject_t::get_max(),
3908 10, &objects, 0);
3909 ceph_assert(r >= 0);
3910 if (objects.empty())
3911 break;
3912 ObjectStore::Transaction t;
3913 for (vector<ghobject_t>::iterator p = objects.begin();
3914 p != objects.end(); ++p) {
3915 t.remove(cid, *p);
3916 }
3917 queue_transaction(store, ch, std::move(t));
3918 }
3919 ObjectStore::Transaction t;
3920 t.remove_collection(cid);
3921 queue_transaction(store, ch, std::move(t));
3922 }
3923 void statfs(store_statfs_t& stat) {
3924 store->statfs(&stat);
3925 }
3926
3927 ghobject_t get_uniform_random_object(std::unique_lock<ceph::mutex>& locker) {
3928 cond.wait(locker, [this] {
3929 return in_flight < max_in_flight && !available_objects.empty();
3930 });
3931 boost::uniform_int<> choose(0, available_objects.size() - 1);
3932 int index = choose(*rng);
3933 set<ghobject_t>::iterator i = available_objects.begin();
3934 for ( ; index > 0; --index, ++i) ;
3935 ghobject_t ret = *i;
3936 return ret;
3937 }
3938
3939 void wait_for_ready(std::unique_lock<ceph::mutex>& locker) {
3940 cond.wait(locker, [this] { return in_flight < max_in_flight; });
3941 }
3942
3943 void wait_for_done() {
3944 std::unique_lock locker{lock};
3945 cond.wait(locker, [this] { return in_flight == 0; });
3946 }
3947
3948 bool can_create() {
3949 return (available_objects.size() + in_flight_objects.size()) < max_objects;
3950 }
3951
3952 bool can_unlink() {
3953 return (available_objects.size() + in_flight_objects.size()) > 0;
3954 }
3955
3956 unsigned get_random_alloc_hints() {
3957 unsigned f = 0;
3958 {
3959 boost::uniform_int<> u(0, 3);
3960 switch (u(*rng)) {
3961 case 1:
3962 f |= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE;
3963 break;
3964 case 2:
3965 f |= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE;
3966 break;
3967 }
3968 }
3969 {
3970 boost::uniform_int<> u(0, 3);
3971 switch (u(*rng)) {
3972 case 1:
3973 f |= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ;
3974 break;
3975 case 2:
3976 f |= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ;
3977 break;
3978 }
3979 }
3980 {
3981 // append_only, immutable
3982 boost::uniform_int<> u(0, 4);
3983 f |= u(*rng) << 4;
3984 }
3985 {
3986 boost::uniform_int<> u(0, 3);
3987 switch (u(*rng)) {
3988 case 1:
3989 f |= CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED;
3990 break;
3991 case 2:
3992 f |= CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED;
3993 break;
3994 }
3995 }
3996 {
3997 boost::uniform_int<> u(0, 3);
3998 switch (u(*rng)) {
3999 case 1:
4000 f |= CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE;
4001 break;
4002 case 2:
4003 f |= CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE;
4004 break;
4005 }
4006 }
4007 return f;
4008 }
4009
4010 int touch() {
4011 std::unique_lock locker{lock};
4012 EnterExit ee("touch");
4013 if (!can_create())
4014 return -ENOSPC;
4015 wait_for_ready(locker);
4016 ghobject_t new_obj = object_gen->create_object(rng);
4017 available_objects.erase(new_obj);
4018 ObjectStore::Transaction t;
4019 t.touch(cid, new_obj);
4020 boost::uniform_int<> u(17, 22);
4021 boost::uniform_int<> v(12, 17);
4022 t.set_alloc_hint(cid, new_obj,
4023 1ull << u(*rng),
4024 1ull << v(*rng),
4025 get_random_alloc_hints());
4026 ++in_flight;
4027 in_flight_objects.insert(new_obj);
4028 if (!contents.count(new_obj))
4029 contents[new_obj] = Object();
4030 t.register_on_applied(new C_SyntheticOnReadable(this, new_obj));
4031 int status = store->queue_transaction(ch, std::move(t));
4032 return status;
4033 }
4034
4035 int stash() {
4036 std::unique_lock locker{lock};
4037 EnterExit ee("stash");
4038 if (!can_unlink())
4039 return -ENOENT;
4040 if (!can_create())
4041 return -ENOSPC;
4042 wait_for_ready(locker);
4043
4044 ghobject_t old_obj;
4045 int max = 20;
4046 do {
4047 old_obj = get_uniform_random_object(locker);
4048 } while (--max && !contents[old_obj].data.length());
4049 available_objects.erase(old_obj);
4050 ghobject_t new_obj = old_obj;
4051 new_obj.generation++;
4052 available_objects.erase(new_obj);
4053
4054 ObjectStore::Transaction t;
4055 t.collection_move_rename(cid, old_obj, cid, new_obj);
4056 ++in_flight;
4057 in_flight_objects.insert(old_obj);
4058
4059 contents[new_obj].attrs = contents[old_obj].attrs;
4060 contents[new_obj].data = contents[old_obj].data;
4061 contents.erase(old_obj);
4062 t.register_on_applied(new C_SyntheticOnStash(this, old_obj, new_obj));
4063 int status = store->queue_transaction(ch, std::move(t));
4064 return status;
4065 }
4066
4067 int clone() {
4068 std::unique_lock locker{lock};
4069 EnterExit ee("clone");
4070 if (!can_unlink())
4071 return -ENOENT;
4072 if (!can_create())
4073 return -ENOSPC;
4074 wait_for_ready(locker);
4075
4076 ghobject_t old_obj;
4077 int max = 20;
4078 do {
4079 old_obj = get_uniform_random_object(locker);
4080 } while (--max && !contents[old_obj].data.length());
4081 available_objects.erase(old_obj);
4082 ghobject_t new_obj = object_gen->create_object(rng);
4083 // make the hash match
4084 new_obj.hobj.set_hash(old_obj.hobj.get_hash());
4085 available_objects.erase(new_obj);
4086
4087 ObjectStore::Transaction t;
4088 t.clone(cid, old_obj, new_obj);
4089 ++in_flight;
4090 in_flight_objects.insert(old_obj);
4091
4092 contents[new_obj].attrs = contents[old_obj].attrs;
4093 contents[new_obj].data = contents[old_obj].data;
4094
4095 t.register_on_applied(new C_SyntheticOnClone(this, old_obj, new_obj));
4096 int status = store->queue_transaction(ch, std::move(t));
4097 return status;
4098 }
4099
4100 int clone_range() {
4101 std::unique_lock locker{lock};
4102 EnterExit ee("clone_range");
4103 if (!can_unlink())
4104 return -ENOENT;
4105 if (!can_create())
4106 return -ENOSPC;
4107 wait_for_ready(locker);
4108
4109 ghobject_t old_obj;
4110 int max = 20;
4111 do {
4112 old_obj = get_uniform_random_object(locker);
4113 } while (--max && !contents[old_obj].data.length());
4114 bufferlist &srcdata = contents[old_obj].data;
4115 if (srcdata.length() == 0) {
4116 return 0;
4117 }
4118 available_objects.erase(old_obj);
4119 ghobject_t new_obj = get_uniform_random_object(locker);
4120 available_objects.erase(new_obj);
4121
4122 boost::uniform_int<> u1(0, max_object_len - max_write_len);
4123 boost::uniform_int<> u2(0, max_write_len);
4124 uint64_t srcoff = u1(*rng);
4125 // make src and dst offsets match, since that's what the osd does
4126 uint64_t dstoff = srcoff; //u1(*rng);
4127 uint64_t len = u2(*rng);
4128 if (write_alignment) {
4129 srcoff = round_up_to(srcoff, write_alignment);
4130 dstoff = round_up_to(dstoff, write_alignment);
4131 len = round_up_to(len, write_alignment);
4132 }
4133
4134 if (srcoff > srcdata.length() - 1) {
4135 srcoff = srcdata.length() - 1;
4136 }
4137 if (srcoff + len > srcdata.length()) {
4138 len = srcdata.length() - srcoff;
4139 }
4140 if (0)
4141 cout << __func__ << " from " << srcoff << "~" << len
4142 << " (size " << srcdata.length() << ") to "
4143 << dstoff << "~" << len << std::endl;
4144
4145 ObjectStore::Transaction t;
4146 t.clone_range(cid, old_obj, new_obj, srcoff, len, dstoff);
4147 ++in_flight;
4148 in_flight_objects.insert(old_obj);
4149
4150 bufferlist bl;
4151 if (srcoff < srcdata.length()) {
4152 if (srcoff + len > srcdata.length()) {
4153 bl.substr_of(srcdata, srcoff, srcdata.length() - srcoff);
4154 } else {
4155 bl.substr_of(srcdata, srcoff, len);
4156 }
4157 }
4158
4159 bufferlist& dstdata = contents[new_obj].data;
4160 if (dstdata.length() <= dstoff) {
4161 if (bl.length() > 0) {
4162 dstdata.append_zero(dstoff - dstdata.length());
4163 dstdata.append(bl);
4164 }
4165 } else {
4166 bufferlist value;
4167 ceph_assert(dstdata.length() > dstoff);
4168 dstdata.cbegin().copy(dstoff, value);
4169 value.append(bl);
4170 if (value.length() < dstdata.length())
4171 dstdata.cbegin(value.length()).copy(
4172 dstdata.length() - value.length(), value);
4173 value.swap(dstdata);
4174 }
4175
4176 t.register_on_applied(new C_SyntheticOnClone(this, old_obj, new_obj));
4177 int status = store->queue_transaction(ch, std::move(t));
4178 return status;
4179 }
4180
4181
4182 int write() {
4183 std::unique_lock locker{lock};
4184 EnterExit ee("write");
4185 if (!can_unlink())
4186 return -ENOENT;
4187 wait_for_ready(locker);
4188
4189 ghobject_t new_obj = get_uniform_random_object(locker);
4190 available_objects.erase(new_obj);
4191 ObjectStore::Transaction t;
4192
4193 boost::uniform_int<> u1(0, max_object_len - max_write_len);
4194 boost::uniform_int<> u2(0, max_write_len);
4195 uint64_t offset = u1(*rng);
4196 uint64_t len = u2(*rng);
4197 bufferlist bl;
4198 if (write_alignment) {
4199 offset = round_up_to(offset, write_alignment);
4200 len = round_up_to(len, write_alignment);
4201 }
4202
4203 filled_byte_array(bl, len);
4204
4205 bufferlist& data = contents[new_obj].data;
4206 if (data.length() <= offset) {
4207 if (len > 0) {
4208 data.append_zero(offset-data.length());
4209 data.append(bl);
4210 }
4211 } else {
4212 bufferlist value;
4213 ceph_assert(data.length() > offset);
4214 data.cbegin().copy(offset, value);
4215 value.append(bl);
4216 if (value.length() < data.length())
4217 data.cbegin(value.length()).copy(
4218 data.length()-value.length(), value);
4219 value.swap(data);
4220 }
4221
4222 t.write(cid, new_obj, offset, len, bl);
4223 ++in_flight;
4224 in_flight_objects.insert(new_obj);
4225 t.register_on_applied(new C_SyntheticOnReadable(this, new_obj));
4226 int status = store->queue_transaction(ch, std::move(t));
4227 return status;
4228 }
4229
4230 int truncate() {
4231 std::unique_lock locker{lock};
4232 EnterExit ee("truncate");
4233 if (!can_unlink())
4234 return -ENOENT;
4235 wait_for_ready(locker);
4236
4237 ghobject_t obj = get_uniform_random_object(locker);
4238 available_objects.erase(obj);
4239 ObjectStore::Transaction t;
4240
4241 boost::uniform_int<> choose(0, max_object_len);
4242 size_t len = choose(*rng);
4243 if (write_alignment) {
4244 len = round_up_to(len, write_alignment);
4245 }
4246
4247 t.truncate(cid, obj, len);
4248 ++in_flight;
4249 in_flight_objects.insert(obj);
4250 bufferlist& data = contents[obj].data;
4251 if (data.length() <= len) {
4252 data.append_zero(len - data.length());
4253 } else {
4254 bufferlist bl;
4255 data.cbegin().copy(len, bl);
4256 bl.swap(data);
4257 }
4258
4259 t.register_on_applied(new C_SyntheticOnReadable(this, obj));
4260 int status = store->queue_transaction(ch, std::move(t));
4261 return status;
4262 }
4263
4264 int zero() {
4265 std::unique_lock locker{lock};
4266 EnterExit ee("zero");
4267 if (!can_unlink())
4268 return -ENOENT;
4269 wait_for_ready(locker);
4270
4271 ghobject_t new_obj = get_uniform_random_object(locker);
4272 available_objects.erase(new_obj);
4273 ObjectStore::Transaction t;
4274
4275 boost::uniform_int<> u1(0, max_object_len - max_write_len);
4276 boost::uniform_int<> u2(0, max_write_len);
4277 uint64_t offset = u1(*rng);
4278 uint64_t len = u2(*rng);
4279 if (write_alignment) {
4280 offset = round_up_to(offset, write_alignment);
4281 len = round_up_to(len, write_alignment);
4282 }
4283
4284 if (len > 0) {
4285 auto& data = contents[new_obj].data;
4286 if (data.length() < offset + len) {
4287 data.append_zero(offset+len-data.length());
4288 }
4289 bufferlist n;
4290 n.substr_of(data, 0, offset);
4291 n.append_zero(len);
4292 if (data.length() > offset + len)
4293 data.cbegin(offset + len).copy(data.length() - offset - len, n);
4294 data.swap(n);
4295 }
4296
4297 t.zero(cid, new_obj, offset, len);
4298 ++in_flight;
4299 in_flight_objects.insert(new_obj);
4300 t.register_on_applied(new C_SyntheticOnReadable(this, new_obj));
4301 int status = store->queue_transaction(ch, std::move(t));
4302 return status;
4303 }
4304
4305 void read() {
4306 EnterExit ee("read");
4307 boost::uniform_int<> u1(0, max_object_len/2);
4308 boost::uniform_int<> u2(0, max_object_len);
4309 uint64_t offset = u1(*rng);
4310 uint64_t len = u2(*rng);
4311 if (offset > len)
4312 swap(offset, len);
4313
4314 ghobject_t obj;
4315 bufferlist expected;
4316 int r;
4317 {
4318 std::unique_lock locker{lock};
4319 EnterExit ee("read locked");
4320 if (!can_unlink())
4321 return ;
4322 wait_for_ready(locker);
4323
4324 obj = get_uniform_random_object(locker);
4325 expected = contents[obj].data;
4326 }
4327 bufferlist bl, result;
4328 if (0) cout << " obj " << obj
4329 << " size " << expected.length()
4330 << " offset " << offset
4331 << " len " << len << std::endl;
4332 r = store->read(ch, obj, offset, len, result);
4333 if (offset >= expected.length()) {
4334 ASSERT_EQ(r, 0);
4335 } else {
4336 size_t max_len = expected.length() - offset;
4337 if (len > max_len)
4338 len = max_len;
4339 ceph_assert(len == result.length());
4340 ASSERT_EQ(len, result.length());
4341 expected.cbegin(offset).copy(len, bl);
4342 ASSERT_EQ(r, (int)len);
4343 ASSERT_TRUE(bl_eq(bl, result));
4344 }
4345 }
4346
4347 int setattrs() {
4348 std::unique_lock locker{lock};
4349 EnterExit ee("setattrs");
4350 if (!can_unlink())
4351 return -ENOENT;
4352 wait_for_ready(locker);
4353
4354 ghobject_t obj = get_uniform_random_object(locker);
4355 available_objects.erase(obj);
4356 ObjectStore::Transaction t;
4357
4358 boost::uniform_int<> u0(1, max_attr_size);
4359 boost::uniform_int<> u1(4, max_attr_name_len);
4360 boost::uniform_int<> u2(4, max_attr_value_len);
4361 boost::uniform_int<> u3(0, 100);
4362 uint64_t size = u0(*rng);
4363 uint64_t name_len;
4364 map<string, bufferlist> attrs;
4365 set<string> keys;
4366 for (map<string, bufferlist>::iterator it = contents[obj].attrs.begin();
4367 it != contents[obj].attrs.end(); ++it)
4368 keys.insert(it->first);
4369
4370 while (size--) {
4371 bufferlist name, value;
4372 uint64_t get_exist = u3(*rng);
4373 uint64_t value_len = u2(*rng);
4374 filled_byte_array(value, value_len);
4375 if (get_exist < 50 && keys.size()) {
4376 set<string>::iterator k = keys.begin();
4377 attrs[*k] = value;
4378 contents[obj].attrs[*k] = value;
4379 keys.erase(k);
4380 } else {
4381 name_len = u1(*rng);
4382 filled_byte_array(name, name_len);
4383 attrs[name.c_str()] = value;
4384 contents[obj].attrs[name.c_str()] = value;
4385 }
4386 }
4387 t.setattrs(cid, obj, attrs);
4388 ++in_flight;
4389 in_flight_objects.insert(obj);
4390 t.register_on_applied(new C_SyntheticOnReadable(this, obj));
4391 int status = store->queue_transaction(ch, std::move(t));
4392 return status;
4393 }
4394
4395 void getattrs() {
4396 EnterExit ee("getattrs");
4397 ghobject_t obj;
4398 map<string, bufferlist> expected;
4399 {
4400 std::unique_lock locker{lock};
4401 EnterExit ee("getattrs locked");
4402 if (!can_unlink())
4403 return ;
4404 wait_for_ready(locker);
4405
4406 int retry = 10;
4407 do {
4408 obj = get_uniform_random_object(locker);
4409 if (!--retry)
4410 return ;
4411 } while (contents[obj].attrs.empty());
4412 expected = contents[obj].attrs;
4413 }
4414 map<string, bufferlist> attrs;
4415 int r = store->getattrs(ch, obj, attrs);
4416 ASSERT_TRUE(r == 0);
4417 ASSERT_TRUE(attrs.size() == expected.size());
4418 for (map<string, bufferlist>::iterator it = expected.begin();
4419 it != expected.end(); ++it) {
4420 ASSERT_TRUE(bl_eq(attrs[it->first], it->second));
4421 }
4422 }
4423
4424 void getattr() {
4425 EnterExit ee("getattr");
4426 ghobject_t obj;
4427 int r;
4428 int retry;
4429 map<string, bufferlist> expected;
4430 {
4431 std::unique_lock locker{lock};
4432 EnterExit ee("getattr locked");
4433 if (!can_unlink())
4434 return ;
4435 wait_for_ready(locker);
4436
4437 retry = 10;
4438 do {
4439 obj = get_uniform_random_object(locker);
4440 if (!--retry)
4441 return ;
4442 } while (contents[obj].attrs.empty());
4443 expected = contents[obj].attrs;
4444 }
4445 boost::uniform_int<> u(0, expected.size()-1);
4446 retry = u(*rng);
4447 map<string, bufferlist>::iterator it = expected.begin();
4448 while (retry) {
4449 retry--;
4450 ++it;
4451 }
4452
4453 bufferlist bl;
4454 r = store->getattr(ch, obj, it->first, bl);
4455 ASSERT_EQ(r, 0);
4456 ASSERT_TRUE(bl_eq(it->second, bl));
4457 }
4458
4459 int rmattr() {
4460 std::unique_lock locker{lock};
4461 EnterExit ee("rmattr");
4462 if (!can_unlink())
4463 return -ENOENT;
4464 wait_for_ready(locker);
4465
4466 ghobject_t obj;
4467 int retry = 10;
4468 do {
4469 obj = get_uniform_random_object(locker);
4470 if (!--retry)
4471 return 0;
4472 } while (contents[obj].attrs.empty());
4473
4474 boost::uniform_int<> u(0, contents[obj].attrs.size()-1);
4475 retry = u(*rng);
4476 map<string, bufferlist>::iterator it = contents[obj].attrs.begin();
4477 while (retry) {
4478 retry--;
4479 ++it;
4480 }
4481
4482 available_objects.erase(obj);
4483 ObjectStore::Transaction t;
4484 t.rmattr(cid, obj, it->first);
4485
4486 contents[obj].attrs.erase(it->first);
4487 ++in_flight;
4488 in_flight_objects.insert(obj);
4489 t.register_on_applied(new C_SyntheticOnReadable(this, obj));
4490 int status = store->queue_transaction(ch, std::move(t));
4491 return status;
4492 }
4493
4494 void fsck(bool deep) {
4495 std::unique_lock locker{lock};
4496 EnterExit ee("fsck");
4497 cond.wait(locker, [this] { return in_flight == 0; });
4498 ch.reset();
4499 store->umount();
4500 int r = store->fsck(deep);
4501 ceph_assert(r == 0 || r == -EOPNOTSUPP);
4502 store->mount();
4503 ch = store->open_collection(cid);
4504 }
4505
4506 void scan() {
4507 std::unique_lock locker{lock};
4508 EnterExit ee("scan");
4509 cond.wait(locker, [this] { return in_flight == 0; });
4510 vector<ghobject_t> objects;
4511 set<ghobject_t> objects_set, objects_set2;
4512 ghobject_t next, current;
4513 while (1) {
4514 //cerr << "scanning..." << std::endl;
4515 int r = store->collection_list(ch, current, ghobject_t::get_max(), 100,
4516 &objects, &next);
4517 ASSERT_EQ(r, 0);
4518 ASSERT_TRUE(sorted(objects));
4519 objects_set.insert(objects.begin(), objects.end());
4520 objects.clear();
4521 if (next.is_max()) break;
4522 current = next;
4523 }
4524 if (objects_set.size() != available_objects.size()) {
4525 for (set<ghobject_t>::iterator p = objects_set.begin();
4526 p != objects_set.end();
4527 ++p)
4528 if (available_objects.count(*p) == 0) {
4529 cerr << "+ " << *p << std::endl;
4530 ceph_abort();
4531 }
4532 for (set<ghobject_t>::iterator p = available_objects.begin();
4533 p != available_objects.end();
4534 ++p)
4535 if (objects_set.count(*p) == 0)
4536 cerr << "- " << *p << std::endl;
4537 //cerr << " objects_set: " << objects_set << std::endl;
4538 //cerr << " available_set: " << available_objects << std::endl;
4539 ceph_abort_msg("badness");
4540 }
4541
4542 ASSERT_EQ(objects_set.size(), available_objects.size());
4543 for (set<ghobject_t>::iterator i = objects_set.begin();
4544 i != objects_set.end();
4545 ++i) {
4546 ASSERT_GT(available_objects.count(*i), (unsigned)0);
4547 }
4548
4549 int r = store->collection_list(ch, ghobject_t(), ghobject_t::get_max(),
4550 INT_MAX, &objects, 0);
4551 ASSERT_EQ(r, 0);
4552 objects_set2.insert(objects.begin(), objects.end());
4553 ASSERT_EQ(objects_set2.size(), available_objects.size());
4554 for (set<ghobject_t>::iterator i = objects_set2.begin();
4555 i != objects_set2.end();
4556 ++i) {
4557 ASSERT_GT(available_objects.count(*i), (unsigned)0);
4558 if (available_objects.count(*i) == 0) {
4559 cerr << "+ " << *i << std::endl;
4560 }
4561 }
4562 }
4563
4564 void stat() {
4565 EnterExit ee("stat");
4566 ghobject_t hoid;
4567 uint64_t expected;
4568 {
4569 std::unique_lock locker{lock};
4570 EnterExit ee("stat lock1");
4571 if (!can_unlink())
4572 return ;
4573 hoid = get_uniform_random_object(locker);
4574 in_flight_objects.insert(hoid);
4575 available_objects.erase(hoid);
4576 ++in_flight;
4577 expected = contents[hoid].data.length();
4578 }
4579 struct stat buf;
4580 int r = store->stat(ch, hoid, &buf);
4581 ASSERT_EQ(0, r);
4582 ceph_assert((uint64_t)buf.st_size == expected);
4583 ASSERT_TRUE((uint64_t)buf.st_size == expected);
4584 {
4585 std::lock_guard locker{lock};
4586 EnterExit ee("stat lock2");
4587 --in_flight;
4588 cond.notify_all();
4589 in_flight_objects.erase(hoid);
4590 available_objects.insert(hoid);
4591 }
4592 }
4593
4594 int unlink() {
4595 std::unique_lock locker{lock};
4596 EnterExit ee("unlink");
4597 if (!can_unlink())
4598 return -ENOENT;
4599 ghobject_t to_remove = get_uniform_random_object(locker);
4600 ObjectStore::Transaction t;
4601 t.remove(cid, to_remove);
4602 ++in_flight;
4603 available_objects.erase(to_remove);
4604 in_flight_objects.insert(to_remove);
4605 contents.erase(to_remove);
4606 t.register_on_applied(new C_SyntheticOnReadable(this, to_remove));
4607 int status = store->queue_transaction(ch, std::move(t));
4608 return status;
4609 }
4610
4611 void print_internal_state() {
4612 std::lock_guard locker{lock};
4613 cerr << "available_objects: " << available_objects.size()
4614 << " in_flight_objects: " << in_flight_objects.size()
4615 << " total objects: " << in_flight_objects.size() + available_objects.size()
4616 << " in_flight " << in_flight << std::endl;
4617 }
4618 };
4619
4620
4621 void StoreTest::doSyntheticTest(
4622 int num_ops,
4623 uint64_t max_obj, uint64_t max_wr, uint64_t align)
4624 {
4625 MixedGenerator gen(555);
4626 gen_type rng(time(NULL));
4627 coll_t cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD));
4628
4629 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
4630 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
4631 g_ceph_context->_conf.apply_changes(nullptr);
4632
4633 SyntheticWorkloadState test_obj(store.get(), &gen, &rng, cid,
4634 max_obj, max_wr, align);
4635 test_obj.init();
4636 for (int i = 0; i < num_ops/10; ++i) {
4637 if (!(i % 500)) cerr << "seeding object " << i << std::endl;
4638 test_obj.touch();
4639 }
4640 for (int i = 0; i < num_ops; ++i) {
4641 if (!(i % 1000)) {
4642 cerr << "Op " << i << std::endl;
4643 test_obj.print_internal_state();
4644 }
4645 boost::uniform_int<> true_false(0, 999);
4646 int val = true_false(rng);
4647 if (val > 998) {
4648 test_obj.fsck(true);
4649 } else if (val > 997) {
4650 test_obj.fsck(false);
4651 } else if (val > 970) {
4652 test_obj.scan();
4653 } else if (val > 950) {
4654 test_obj.stat();
4655 } else if (val > 850) {
4656 test_obj.zero();
4657 } else if (val > 800) {
4658 test_obj.unlink();
4659 } else if (val > 550) {
4660 test_obj.write();
4661 } else if (val > 500) {
4662 test_obj.clone();
4663 } else if (val > 450) {
4664 test_obj.clone_range();
4665 } else if (val > 300) {
4666 test_obj.stash();
4667 } else if (val > 100) {
4668 test_obj.read();
4669 } else {
4670 test_obj.truncate();
4671 }
4672 }
4673 test_obj.wait_for_done();
4674 test_obj.shutdown();
4675 }
4676
4677 TEST_P(StoreTest, Synthetic) {
4678 doSyntheticTest(10000, 400*1024, 40*1024, 0);
4679 }
4680
4681 #if defined(WITH_BLUESTORE)
4682 TEST_P(StoreTestSpecificAUSize, BlueFSExtenderTest) {
4683 if(string(GetParam()) != "bluestore")
4684 return;
4685
4686 SetVal(g_conf(), "bluestore_block_db_size", "0");
4687 SetVal(g_conf(), "bluestore_block_wal_size", "0");
4688 SetVal(g_conf(), "bluestore_bluefs_min", "12582912");
4689 SetVal(g_conf(), "bluestore_bluefs_min_free", "4194304");
4690 SetVal(g_conf(), "bluestore_bluefs_gift_ratio", "0");
4691 SetVal(g_conf(), "bluestore_bluefs_min_ratio", "0");
4692 SetVal(g_conf(), "bluestore_bluefs_balance_interval", "100000");
4693 SetVal(g_conf(), "bluestore_bluefs_db_compatibility", "false");
4694
4695 g_conf().apply_changes(nullptr);
4696
4697 StartDeferred(4096);
4698
4699 doSyntheticTest(10000, 400*1024, 40*1024, 0);
4700
4701 BlueStore* bstore = NULL;
4702 EXPECT_NO_THROW(bstore = dynamic_cast<BlueStore*> (store.get()));
4703
4704 // verify downgrades are broken and repair that
4705 bstore->umount();
4706 ASSERT_EQ(bstore->fsck(false), 0);
4707
4708 SetVal(g_conf(), "bluestore_bluefs_db_compatibility", "true");
4709 g_conf().apply_changes(nullptr);
4710
4711 ASSERT_EQ(bstore->fsck(false), 1);
4712 ASSERT_EQ(bstore->repair(false), 0);
4713 ASSERT_EQ(bstore->fsck(false), 0);
4714 bstore->mount();
4715 }
4716
4717 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixSharding) {
4718 if (string(GetParam()) != "bluestore")
4719 return;
4720
4721 const char *m[][10] = {
4722 { "bluestore_min_alloc_size", "4096", 0 }, // must be the first!
4723 { "num_ops", "50000", 0 },
4724 { "max_write", "65536", 0 },
4725 { "max_size", "262144", 0 },
4726 { "alignment", "4096", 0 },
4727 { "bluestore_max_blob_size", "65536", 0 },
4728 { "bluestore_extent_map_shard_min_size", "60", 0 },
4729 { "bluestore_extent_map_shard_max_size", "300", 0 },
4730 { "bluestore_extent_map_shard_target_size", "150", 0 },
4731 { "bluestore_default_buffered_read", "true", 0 },
4732 { "bluestore_default_buffered_write", "true", 0 },
4733 { 0 },
4734 };
4735 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
4736 }
4737
4738 TEST_P(StoreTestSpecificAUSize, ZipperPatternSharded) {
4739 if(string(GetParam()) != "bluestore")
4740 return;
4741 StartDeferred(4096);
4742
4743 int r;
4744 coll_t cid;
4745 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
4746 auto ch = store->create_new_collection(cid);
4747 {
4748 ObjectStore::Transaction t;
4749 t.create_collection(cid, 0);
4750 cerr << "Creating collection " << cid << std::endl;
4751 r = queue_transaction(store, ch, std::move(t));
4752 ASSERT_EQ(r, 0);
4753 }
4754 bufferlist bl;
4755 int len = 4096;
4756 bufferptr bp(len);
4757 bp.zero();
4758 bl.append(bp);
4759 for (int i=0; i<1000; ++i) {
4760 ObjectStore::Transaction t;
4761 t.write(cid, a, i*2*len, len, bl, 0);
4762 r = queue_transaction(store, ch, std::move(t));
4763 ASSERT_EQ(r, 0);
4764 }
4765 for (int i=0; i<1000; ++i) {
4766 ObjectStore::Transaction t;
4767 t.write(cid, a, i*2*len + 1, len, bl, 0);
4768 r = queue_transaction(store, ch, std::move(t));
4769 ASSERT_EQ(r, 0);
4770 }
4771 {
4772 ObjectStore::Transaction t;
4773 t.remove(cid, a);
4774 t.remove_collection(cid);
4775 cerr << "Cleaning" << std::endl;
4776 r = queue_transaction(store, ch, std::move(t));
4777 ASSERT_EQ(r, 0);
4778 }
4779 }
4780
4781 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCsumAlgorithm) {
4782 if (string(GetParam()) != "bluestore")
4783 return;
4784
4785 const char *m[][10] = {
4786 { "bluestore_min_alloc_size", "65536", 0 }, // must be the first!
4787 { "max_write", "65536", 0 },
4788 { "max_size", "1048576", 0 },
4789 { "alignment", "16", 0 },
4790 { "bluestore_csum_type", "crc32c", "crc32c_16", "crc32c_8", "xxhash32",
4791 "xxhash64", "none", 0 },
4792 { "bluestore_default_buffered_write", "false", 0 },
4793 { 0 },
4794 };
4795 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
4796 }
4797
4798 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCsumVsCompression) {
4799 if (string(GetParam()) != "bluestore")
4800 return;
4801
4802 const char *m[][10] = {
4803 { "bluestore_min_alloc_size", "4096", "16384", 0 }, //to be the first!
4804 { "max_write", "131072", 0 },
4805 { "max_size", "262144", 0 },
4806 { "alignment", "512", 0 },
4807 { "bluestore_compression_mode", "force", 0},
4808 { "bluestore_compression_algorithm", "snappy", "zlib", 0 },
4809 { "bluestore_csum_type", "crc32c", 0 },
4810 { "bluestore_default_buffered_read", "true", "false", 0 },
4811 { "bluestore_default_buffered_write", "true", "false", 0 },
4812 { "bluestore_sync_submit_transaction", "false", 0 },
4813 { 0 },
4814 };
4815 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
4816 }
4817
4818 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCompression) {
4819 if (string(GetParam()) != "bluestore")
4820 return;
4821
4822 const char *m[][10] = {
4823 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4824 { "max_write", "1048576", 0 },
4825 { "max_size", "4194304", 0 },
4826 { "alignment", "65536", 0 },
4827 { "bluestore_compression_mode", "force", "aggressive", "passive", "none", 0},
4828 { "bluestore_default_buffered_write", "false", 0 },
4829 { "bluestore_sync_submit_transaction", "true", 0 },
4830 { 0 },
4831 };
4832 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
4833 }
4834
4835 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCompressionAlgorithm) {
4836 if (string(GetParam()) != "bluestore")
4837 return;
4838
4839 const char *m[][10] = {
4840 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4841 { "max_write", "1048576", 0 },
4842 { "max_size", "4194304", 0 },
4843 { "alignment", "65536", 0 },
4844 { "bluestore_compression_algorithm", "zlib", "snappy", 0 },
4845 { "bluestore_compression_mode", "force", 0 },
4846 { "bluestore_default_buffered_write", "false", 0 },
4847 { 0 },
4848 };
4849 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
4850 }
4851
4852 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixNoCsum) {
4853 if (string(GetParam()) != "bluestore")
4854 return;
4855
4856 const char *m[][10] = {
4857 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4858 { "max_write", "65536", 0 },
4859 { "max_size", "1048576", 0 },
4860 { "alignment", "512", 0 },
4861 { "bluestore_max_blob_size", "262144", 0 },
4862 { "bluestore_compression_mode", "force", "none", 0},
4863 { "bluestore_csum_type", "none", 0},
4864 { "bluestore_default_buffered_read", "true", "false", 0 },
4865 { "bluestore_default_buffered_write", "true", 0 },
4866 { "bluestore_sync_submit_transaction", "true", "false", 0 },
4867 { 0 },
4868 };
4869 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
4870 }
4871
4872 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixPreferDeferred) {
4873 if (string(GetParam()) != "bluestore")
4874 return;
4875
4876 const char *m[][10] = {
4877 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4878 { "max_write", "65536", 0 },
4879 { "max_size", "1048576", 0 },
4880 { "alignment", "512", 0 },
4881 { "bluestore_max_blob_size", "262144", 0 },
4882 { "bluestore_compression_mode", "force", "none", 0},
4883 { "bluestore_prefer_deferred_size", "32768", "0", 0},
4884 { 0 },
4885 };
4886 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
4887 }
4888 #endif // WITH_BLUESTORE
4889
4890 TEST_P(StoreTest, AttrSynthetic) {
4891 MixedGenerator gen(447);
4892 gen_type rng(time(NULL));
4893 coll_t cid(spg_t(pg_t(0,447),shard_id_t::NO_SHARD));
4894
4895 SyntheticWorkloadState test_obj(store.get(), &gen, &rng, cid, 40*1024, 4*1024, 0);
4896 test_obj.init();
4897 for (int i = 0; i < 500; ++i) {
4898 if (!(i % 10)) cerr << "seeding object " << i << std::endl;
4899 test_obj.touch();
4900 }
4901 for (int i = 0; i < 1000; ++i) {
4902 if (!(i % 100)) {
4903 cerr << "Op " << i << std::endl;
4904 test_obj.print_internal_state();
4905 }
4906 boost::uniform_int<> true_false(0, 99);
4907 int val = true_false(rng);
4908 if (val > 97) {
4909 test_obj.scan();
4910 } else if (val > 93) {
4911 test_obj.stat();
4912 } else if (val > 75) {
4913 test_obj.rmattr();
4914 } else if (val > 47) {
4915 test_obj.setattrs();
4916 } else if (val > 45) {
4917 test_obj.clone();
4918 } else if (val > 37) {
4919 test_obj.stash();
4920 } else if (val > 30) {
4921 test_obj.getattrs();
4922 } else {
4923 test_obj.getattr();
4924 }
4925 }
4926 test_obj.wait_for_done();
4927 test_obj.shutdown();
4928 }
4929
4930 TEST_P(StoreTest, HashCollisionTest) {
4931 int64_t poolid = 11;
4932 coll_t cid(spg_t(pg_t(0,poolid),shard_id_t::NO_SHARD));
4933 int r;
4934 auto ch = store->create_new_collection(cid);
4935 {
4936 ObjectStore::Transaction t;
4937 t.create_collection(cid, 0);
4938 r = queue_transaction(store, ch, std::move(t));
4939 ASSERT_EQ(r, 0);
4940 }
4941 string base = "";
4942 for (int i = 0; i < 100; ++i) base.append("aaaaa");
4943 set<ghobject_t> created;
4944 for (int n = 0; n < 10; ++n) {
4945 char nbuf[100];
4946 sprintf(nbuf, "n%d", n);
4947 for (int i = 0; i < 1000; ++i) {
4948 char buf[100];
4949 sprintf(buf, "%d", i);
4950 if (!(i % 100)) {
4951 cerr << "Object n" << n << " "<< i << std::endl;
4952 }
4953 ghobject_t hoid(hobject_t(string(buf) + base, string(), CEPH_NOSNAP, 0, poolid, string(nbuf)));
4954 {
4955 ObjectStore::Transaction t;
4956 t.touch(cid, hoid);
4957 r = queue_transaction(store, ch, std::move(t));
4958 ASSERT_EQ(r, 0);
4959 }
4960 created.insert(hoid);
4961 }
4962 }
4963 vector<ghobject_t> objects;
4964 r = store->collection_list(ch, ghobject_t(), ghobject_t::get_max(), INT_MAX, &objects, 0);
4965 ASSERT_EQ(r, 0);
4966 set<ghobject_t> listed(objects.begin(), objects.end());
4967 cerr << "listed.size() is " << listed.size() << " and created.size() is " << created.size() << std::endl;
4968 ASSERT_TRUE(listed.size() == created.size());
4969 objects.clear();
4970 listed.clear();
4971 ghobject_t current, next;
4972 while (1) {
4973 r = store->collection_list(ch, current, ghobject_t::get_max(), 60,
4974 &objects, &next);
4975 ASSERT_EQ(r, 0);
4976 ASSERT_TRUE(sorted(objects));
4977 for (vector<ghobject_t>::iterator i = objects.begin();
4978 i != objects.end();
4979 ++i) {
4980 if (listed.count(*i))
4981 cerr << *i << " repeated" << std::endl;
4982 listed.insert(*i);
4983 }
4984 if (objects.size() < 50) {
4985 ASSERT_TRUE(next.is_max());
4986 break;
4987 }
4988 objects.clear();
4989 current = next;
4990 }
4991 cerr << "listed.size() is " << listed.size() << std::endl;
4992 ASSERT_TRUE(listed.size() == created.size());
4993 for (set<ghobject_t>::iterator i = listed.begin();
4994 i != listed.end();
4995 ++i) {
4996 ASSERT_TRUE(created.count(*i));
4997 }
4998
4999 for (set<ghobject_t>::iterator i = created.begin();
5000 i != created.end();
5001 ++i) {
5002 ObjectStore::Transaction t;
5003 t.remove(cid, *i);
5004 r = queue_transaction(store, ch, std::move(t));
5005 ASSERT_EQ(r, 0);
5006 }
5007 ObjectStore::Transaction t;
5008 t.remove_collection(cid);
5009 r = queue_transaction(store, ch, std::move(t));
5010 ASSERT_EQ(r, 0);
5011 }
5012
5013 TEST_P(StoreTest, ScrubTest) {
5014 int64_t poolid = 111;
5015 coll_t cid(spg_t(pg_t(0, poolid),shard_id_t(1)));
5016 int r;
5017 auto ch = store->create_new_collection(cid);
5018 {
5019 ObjectStore::Transaction t;
5020 t.create_collection(cid, 0);
5021 r = queue_transaction(store, ch, std::move(t));
5022 ASSERT_EQ(r, 0);
5023 }
5024 string base = "aaaaa";
5025 set<ghobject_t> created;
5026 for (int i = 0; i < 1000; ++i) {
5027 char buf[100];
5028 sprintf(buf, "%d", i);
5029 if (!(i % 5)) {
5030 cerr << "Object " << i << std::endl;
5031 }
5032 ghobject_t hoid(hobject_t(string(buf) + base, string(), CEPH_NOSNAP, i,
5033 poolid, ""),
5034 ghobject_t::NO_GEN, shard_id_t(1));
5035 {
5036 ObjectStore::Transaction t;
5037 t.touch(cid, hoid);
5038 r = queue_transaction(store, ch, std::move(t));
5039 ASSERT_EQ(r, 0);
5040 }
5041 created.insert(hoid);
5042 }
5043
5044 // Add same hobject_t but different generation
5045 {
5046 ghobject_t hoid1(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""),
5047 ghobject_t::NO_GEN, shard_id_t(1));
5048 ghobject_t hoid2(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""), (gen_t)1, shard_id_t(1));
5049 ghobject_t hoid3(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""), (gen_t)2, shard_id_t(1));
5050 ObjectStore::Transaction t;
5051 t.touch(cid, hoid1);
5052 t.touch(cid, hoid2);
5053 t.touch(cid, hoid3);
5054 r = queue_transaction(store, ch, std::move(t));
5055 created.insert(hoid1);
5056 created.insert(hoid2);
5057 created.insert(hoid3);
5058 ASSERT_EQ(r, 0);
5059 }
5060
5061 vector<ghobject_t> objects;
5062 r = store->collection_list(ch, ghobject_t(), ghobject_t::get_max(),
5063 INT_MAX, &objects, 0);
5064 ASSERT_EQ(r, 0);
5065 set<ghobject_t> listed(objects.begin(), objects.end());
5066 cerr << "listed.size() is " << listed.size() << " and created.size() is " << created.size() << std::endl;
5067 ASSERT_TRUE(listed.size() == created.size());
5068 objects.clear();
5069 listed.clear();
5070 ghobject_t current, next;
5071 while (1) {
5072 r = store->collection_list(ch, current, ghobject_t::get_max(), 60,
5073 &objects, &next);
5074 ASSERT_EQ(r, 0);
5075 ASSERT_TRUE(sorted(objects));
5076 for (vector<ghobject_t>::iterator i = objects.begin();
5077 i != objects.end(); ++i) {
5078 if (listed.count(*i))
5079 cerr << *i << " repeated" << std::endl;
5080 listed.insert(*i);
5081 }
5082 if (objects.size() < 50) {
5083 ASSERT_TRUE(next.is_max());
5084 break;
5085 }
5086 objects.clear();
5087 current = next.get_boundary();
5088 }
5089 cerr << "listed.size() is " << listed.size() << std::endl;
5090 ASSERT_TRUE(listed.size() == created.size());
5091 for (set<ghobject_t>::iterator i = listed.begin();
5092 i != listed.end();
5093 ++i) {
5094 ASSERT_TRUE(created.count(*i));
5095 }
5096
5097 for (set<ghobject_t>::iterator i = created.begin();
5098 i != created.end();
5099 ++i) {
5100 ObjectStore::Transaction t;
5101 t.remove(cid, *i);
5102 r = queue_transaction(store, ch, std::move(t));
5103 ASSERT_EQ(r, 0);
5104 }
5105 ObjectStore::Transaction t;
5106 t.remove_collection(cid);
5107 r = queue_transaction(store, ch, std::move(t));
5108 ASSERT_EQ(r, 0);
5109 }
5110
5111
5112 TEST_P(StoreTest, OMapTest) {
5113 coll_t cid;
5114 ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
5115 auto ch = store->create_new_collection(cid);
5116 int r;
5117 {
5118 ObjectStore::Transaction t;
5119 t.create_collection(cid, 0);
5120 r = queue_transaction(store, ch, std::move(t));
5121 ASSERT_EQ(r, 0);
5122 }
5123
5124 map<string, bufferlist> attrs;
5125 {
5126 ObjectStore::Transaction t;
5127 t.touch(cid, hoid);
5128 t.omap_clear(cid, hoid);
5129 map<string, bufferlist> start_set;
5130 t.omap_setkeys(cid, hoid, start_set);
5131 r = queue_transaction(store, ch, std::move(t));
5132 ASSERT_EQ(r, 0);
5133 }
5134
5135 for (int i = 0; i < 100; i++) {
5136 if (!(i%5)) {
5137 std::cout << "On iteration " << i << std::endl;
5138 }
5139 ObjectStore::Transaction t;
5140 bufferlist bl;
5141 map<string, bufferlist> cur_attrs;
5142 r = store->omap_get(ch, hoid, &bl, &cur_attrs);
5143 ASSERT_EQ(r, 0);
5144 for (map<string, bufferlist>::iterator j = attrs.begin();
5145 j != attrs.end();
5146 ++j) {
5147 bool correct = cur_attrs.count(j->first) && string(cur_attrs[j->first].c_str()) == string(j->second.c_str());
5148 if (!correct) {
5149 std::cout << j->first << " is present in cur_attrs " << cur_attrs.count(j->first) << " times " << std::endl;
5150 if (cur_attrs.count(j->first) > 0) {
5151 std::cout << j->second.c_str() << " : " << cur_attrs[j->first].c_str() << std::endl;
5152 }
5153 }
5154 ASSERT_EQ(correct, true);
5155 }
5156 ASSERT_EQ(attrs.size(), cur_attrs.size());
5157
5158 char buf[100];
5159 snprintf(buf, sizeof(buf), "%d", i);
5160 bl.clear();
5161 bufferptr bp(buf, strlen(buf) + 1);
5162 bl.append(bp);
5163 map<string, bufferlist> to_add;
5164 to_add.insert(pair<string, bufferlist>("key-" + string(buf), bl));
5165 attrs.insert(pair<string, bufferlist>("key-" + string(buf), bl));
5166 t.omap_setkeys(cid, hoid, to_add);
5167 r = queue_transaction(store, ch, std::move(t));
5168 ASSERT_EQ(r, 0);
5169 }
5170
5171 int i = 0;
5172 while (attrs.size()) {
5173 if (!(i%5)) {
5174 std::cout << "removal: On iteration " << i << std::endl;
5175 }
5176 ObjectStore::Transaction t;
5177 bufferlist bl;
5178 map<string, bufferlist> cur_attrs;
5179 r = store->omap_get(ch, hoid, &bl, &cur_attrs);
5180 ASSERT_EQ(r, 0);
5181 for (map<string, bufferlist>::iterator j = attrs.begin();
5182 j != attrs.end();
5183 ++j) {
5184 bool correct = cur_attrs.count(j->first) && string(cur_attrs[j->first].c_str()) == string(j->second.c_str());
5185 if (!correct) {
5186 std::cout << j->first << " is present in cur_attrs " << cur_attrs.count(j->first) << " times " << std::endl;
5187 if (cur_attrs.count(j->first) > 0) {
5188 std::cout << j->second.c_str() << " : " << cur_attrs[j->first].c_str() << std::endl;
5189 }
5190 }
5191 ASSERT_EQ(correct, true);
5192 }
5193
5194 string to_remove = attrs.begin()->first;
5195 t.omap_rmkey(cid, hoid, to_remove);
5196 r = queue_transaction(store, ch, std::move(t));
5197 ASSERT_EQ(r, 0);
5198
5199 attrs.erase(to_remove);
5200
5201 ++i;
5202 }
5203
5204 {
5205 bufferlist bl1;
5206 bl1.append("omap_header");
5207 ObjectStore::Transaction t;
5208 t.omap_setheader(cid, hoid, bl1);
5209 r = queue_transaction(store, ch, std::move(t));
5210 ASSERT_EQ(r, 0);
5211 t = ObjectStore::Transaction();
5212
5213 bufferlist bl2;
5214 bl2.append("value");
5215 map<string, bufferlist> to_add;
5216 to_add.insert(pair<string, bufferlist>("key", bl2));
5217 t.omap_setkeys(cid, hoid, to_add);
5218 r = queue_transaction(store, ch, std::move(t));
5219 ASSERT_EQ(r, 0);
5220
5221 bufferlist bl3;
5222 map<string, bufferlist> cur_attrs;
5223 r = store->omap_get(ch, hoid, &bl3, &cur_attrs);
5224 ASSERT_EQ(r, 0);
5225 ASSERT_EQ(cur_attrs.size(), size_t(1));
5226 ASSERT_TRUE(bl_eq(bl1, bl3));
5227
5228 set<string> keys;
5229 r = store->omap_get_keys(ch, hoid, &keys);
5230 ASSERT_EQ(r, 0);
5231 ASSERT_EQ(keys.size(), size_t(1));
5232 }
5233
5234 // test omap_clear, omap_rmkey_range
5235 {
5236 {
5237 map<string,bufferlist> to_set;
5238 for (int n=0; n<10; ++n) {
5239 to_set[stringify(n)].append("foo");
5240 }
5241 bufferlist h;
5242 h.append("header");
5243 ObjectStore::Transaction t;
5244 t.remove(cid, hoid);
5245 t.touch(cid, hoid);
5246 t.omap_setheader(cid, hoid, h);
5247 t.omap_setkeys(cid, hoid, to_set);
5248 r = queue_transaction(store, ch, std::move(t));
5249 ASSERT_EQ(r, 0);
5250 }
5251 {
5252 ObjectStore::Transaction t;
5253 t.omap_rmkeyrange(cid, hoid, "3", "7");
5254 r = queue_transaction(store, ch, std::move(t));
5255 ASSERT_EQ(r, 0);
5256 }
5257 {
5258 bufferlist hdr;
5259 map<string,bufferlist> m;
5260 store->omap_get(ch, hoid, &hdr, &m);
5261 ASSERT_EQ(6u, hdr.length());
5262 ASSERT_TRUE(m.count("2"));
5263 ASSERT_TRUE(!m.count("3"));
5264 ASSERT_TRUE(!m.count("6"));
5265 ASSERT_TRUE(m.count("7"));
5266 ASSERT_TRUE(m.count("8"));
5267 //cout << m << std::endl;
5268 ASSERT_EQ(6u, m.size());
5269 }
5270 {
5271 ObjectStore::Transaction t;
5272 t.omap_clear(cid, hoid);
5273 r = queue_transaction(store, ch, std::move(t));
5274 ASSERT_EQ(r, 0);
5275 }
5276 {
5277 bufferlist hdr;
5278 map<string,bufferlist> m;
5279 store->omap_get(ch, hoid, &hdr, &m);
5280 ASSERT_EQ(0u, hdr.length());
5281 ASSERT_EQ(0u, m.size());
5282 }
5283 }
5284
5285 ObjectStore::Transaction t;
5286 t.remove(cid, hoid);
5287 t.remove_collection(cid);
5288 r = queue_transaction(store, ch, std::move(t));
5289 ASSERT_EQ(r, 0);
5290 }
5291
5292 TEST_P(StoreTest, OMapIterator) {
5293 coll_t cid;
5294 ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
5295 int count = 0;
5296 auto ch = store->create_new_collection(cid);
5297 int r;
5298 {
5299 ObjectStore::Transaction t;
5300 t.create_collection(cid, 0);
5301 r = queue_transaction(store, ch, std::move(t));
5302 ASSERT_EQ(r, 0);
5303 }
5304
5305 map<string, bufferlist> attrs;
5306 {
5307 ObjectStore::Transaction t;
5308 t.touch(cid, hoid);
5309 t.omap_clear(cid, hoid);
5310 map<string, bufferlist> start_set;
5311 t.omap_setkeys(cid, hoid, start_set);
5312 r = queue_transaction(store, ch, std::move(t));
5313 ASSERT_EQ(r, 0);
5314 }
5315 ObjectMap::ObjectMapIterator iter;
5316 bool correct;
5317 //basic iteration
5318 for (int i = 0; i < 100; i++) {
5319 if (!(i%5)) {
5320 std::cout << "On iteration " << i << std::endl;
5321 }
5322 bufferlist bl;
5323
5324 // FileStore may deadlock two active iterators over the same data
5325 iter = ObjectMap::ObjectMapIterator();
5326
5327 iter = store->get_omap_iterator(ch, hoid);
5328 for (iter->seek_to_first(), count=0; iter->valid(); iter->next(), count++) {
5329 string key = iter->key();
5330 bufferlist value = iter->value();
5331 correct = attrs.count(key) && (string(value.c_str()) == string(attrs[key].c_str()));
5332 if (!correct) {
5333 if (attrs.count(key) > 0) {
5334 std::cout << "key " << key << "in omap , " << value.c_str() << " : " << attrs[key].c_str() << std::endl;
5335 }
5336 else
5337 std::cout << "key " << key << "should not exists in omap" << std::endl;
5338 }
5339 ASSERT_EQ(correct, true);
5340 }
5341 ASSERT_EQ((int)attrs.size(), count);
5342
5343 // FileStore may deadlock an active iterator vs queue_transaction
5344 iter = ObjectMap::ObjectMapIterator();
5345
5346 char buf[100];
5347 snprintf(buf, sizeof(buf), "%d", i);
5348 bl.clear();
5349 bufferptr bp(buf, strlen(buf) + 1);
5350 bl.append(bp);
5351 map<string, bufferlist> to_add;
5352 to_add.insert(pair<string, bufferlist>("key-" + string(buf), bl));
5353 attrs.insert(pair<string, bufferlist>("key-" + string(buf), bl));
5354 ObjectStore::Transaction t;
5355 t.omap_setkeys(cid, hoid, to_add);
5356 r = queue_transaction(store, ch, std::move(t));
5357 ASSERT_EQ(r, 0);
5358 }
5359
5360 iter = store->get_omap_iterator(ch, hoid);
5361 //lower bound
5362 string bound_key = "key-5";
5363 iter->lower_bound(bound_key);
5364 correct = bound_key <= iter->key();
5365 if (!correct) {
5366 std::cout << "lower bound, bound key is " << bound_key << " < iter key is " << iter->key() << std::endl;
5367 }
5368 ASSERT_EQ(correct, true);
5369 //upper bound
5370 iter->upper_bound(bound_key);
5371 correct = iter->key() > bound_key;
5372 if (!correct) {
5373 std::cout << "upper bound, bound key is " << bound_key << " >= iter key is " << iter->key() << std::endl;
5374 }
5375 ASSERT_EQ(correct, true);
5376
5377 // FileStore may deadlock an active iterator vs queue_transaction
5378 iter = ObjectMap::ObjectMapIterator();
5379 {
5380 ObjectStore::Transaction t;
5381 t.remove(cid, hoid);
5382 t.remove_collection(cid);
5383 r = queue_transaction(store, ch, std::move(t));
5384 ASSERT_EQ(r, 0);
5385 }
5386 }
5387
5388 TEST_P(StoreTest, XattrTest) {
5389 coll_t cid;
5390 ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
5391 bufferlist big;
5392 for (unsigned i = 0; i < 10000; ++i) {
5393 big.append('\0');
5394 }
5395 bufferlist small;
5396 for (unsigned i = 0; i < 10; ++i) {
5397 small.append('\0');
5398 }
5399 int r;
5400 auto ch = store->create_new_collection(cid);
5401 {
5402 ObjectStore::Transaction t;
5403 t.create_collection(cid, 0);
5404 t.touch(cid, hoid);
5405 r = queue_transaction(store, ch, std::move(t));
5406 ASSERT_EQ(r, 0);
5407 }
5408
5409 map<string, bufferlist> attrs;
5410 {
5411 ObjectStore::Transaction t;
5412 t.setattr(cid, hoid, "attr1", small);
5413 attrs["attr1"] = small;
5414 t.setattr(cid, hoid, "attr2", big);
5415 attrs["attr2"] = big;
5416 t.setattr(cid, hoid, "attr3", small);
5417 attrs["attr3"] = small;
5418 t.setattr(cid, hoid, "attr1", small);
5419 attrs["attr1"] = small;
5420 t.setattr(cid, hoid, "attr4", big);
5421 attrs["attr4"] = big;
5422 t.setattr(cid, hoid, "attr3", big);
5423 attrs["attr3"] = big;
5424 r = queue_transaction(store, ch, std::move(t));
5425 ASSERT_EQ(r, 0);
5426 }
5427
5428 map<string, bufferptr> aset;
5429 store->getattrs(ch, hoid, aset);
5430 ASSERT_EQ(aset.size(), attrs.size());
5431 for (map<string, bufferptr>::iterator i = aset.begin();
5432 i != aset.end();
5433 ++i) {
5434 bufferlist bl;
5435 bl.push_back(i->second);
5436 ASSERT_TRUE(attrs[i->first] == bl);
5437 }
5438
5439 {
5440 ObjectStore::Transaction t;
5441 t.rmattr(cid, hoid, "attr2");
5442 attrs.erase("attr2");
5443 r = queue_transaction(store, ch, std::move(t));
5444 ASSERT_EQ(r, 0);
5445 }
5446
5447 aset.clear();
5448 store->getattrs(ch, hoid, aset);
5449 ASSERT_EQ(aset.size(), attrs.size());
5450 for (map<string, bufferptr>::iterator i = aset.begin();
5451 i != aset.end();
5452 ++i) {
5453 bufferlist bl;
5454 bl.push_back(i->second);
5455 ASSERT_TRUE(attrs[i->first] == bl);
5456 }
5457
5458 bufferptr bp;
5459 r = store->getattr(ch, hoid, "attr2", bp);
5460 ASSERT_EQ(r, -ENODATA);
5461
5462 r = store->getattr(ch, hoid, "attr3", bp);
5463 ASSERT_EQ(r, 0);
5464 bufferlist bl2;
5465 bl2.push_back(bp);
5466 ASSERT_TRUE(bl2 == attrs["attr3"]);
5467
5468 ObjectStore::Transaction t;
5469 t.remove(cid, hoid);
5470 t.remove_collection(cid);
5471 r = queue_transaction(store, ch, std::move(t));
5472 ASSERT_EQ(r, 0);
5473 }
5474
5475 void colsplittest(
5476 ObjectStore *store,
5477 unsigned num_objects,
5478 unsigned common_suffix_size,
5479 bool clones
5480 ) {
5481 coll_t cid(spg_t(pg_t(0,52),shard_id_t::NO_SHARD));
5482 coll_t tid(spg_t(pg_t(1<<common_suffix_size,52),shard_id_t::NO_SHARD));
5483 auto ch = store->create_new_collection(cid);
5484 auto tch = store->create_new_collection(tid);
5485 int r = 0;
5486 {
5487 ObjectStore::Transaction t;
5488 t.create_collection(cid, common_suffix_size);
5489 r = queue_transaction(store, ch, std::move(t));
5490 ASSERT_EQ(r, 0);
5491 }
5492 bufferlist small;
5493 small.append("small");
5494 {
5495 ObjectStore::Transaction t;
5496 for (uint32_t i = 0; i < (2 - (int)clones)*num_objects; ++i) {
5497 stringstream objname;
5498 objname << "obj" << i;
5499 ghobject_t a(hobject_t(
5500 objname.str(),
5501 "",
5502 CEPH_NOSNAP,
5503 i<<common_suffix_size,
5504 52, ""));
5505 t.write(cid, a, 0, small.length(), small,
5506 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5507 if (clones) {
5508 objname << "-clone";
5509 ghobject_t b(hobject_t(
5510 objname.str(),
5511 "",
5512 CEPH_NOSNAP,
5513 i<<common_suffix_size,
5514 52, ""));
5515 t.clone(cid, a, b);
5516 }
5517 if (i % 100) {
5518 r = queue_transaction(store, ch, std::move(t));
5519 ASSERT_EQ(r, 0);
5520 t = ObjectStore::Transaction();
5521 }
5522 }
5523 r = queue_transaction(store, ch, std::move(t));
5524 ASSERT_EQ(r, 0);
5525 }
5526 {
5527 ObjectStore::Transaction t;
5528 t.create_collection(tid, common_suffix_size + 1);
5529 t.split_collection(cid, common_suffix_size+1, 1<<common_suffix_size, tid);
5530 r = queue_transaction(store, ch, std::move(t));
5531 ASSERT_EQ(r, 0);
5532 }
5533 ch->flush();
5534
5535 // check
5536 vector<ghobject_t> objects;
5537 r = store->collection_list(ch, ghobject_t(), ghobject_t::get_max(),
5538 INT_MAX, &objects, 0);
5539 ASSERT_EQ(r, 0);
5540 ASSERT_EQ(objects.size(), num_objects);
5541 for (vector<ghobject_t>::iterator i = objects.begin();
5542 i != objects.end();
5543 ++i) {
5544 ASSERT_EQ(!!(i->hobj.get_hash() & (1<<common_suffix_size)), 0u);
5545 }
5546
5547 objects.clear();
5548 r = store->collection_list(tch, ghobject_t(), ghobject_t::get_max(),
5549 INT_MAX, &objects, 0);
5550 ASSERT_EQ(r, 0);
5551 ASSERT_EQ(objects.size(), num_objects);
5552 for (vector<ghobject_t>::iterator i = objects.begin();
5553 i != objects.end();
5554 ++i) {
5555 ASSERT_EQ(!(i->hobj.get_hash() & (1<<common_suffix_size)), 0u);
5556 }
5557
5558 // merge them again!
5559 {
5560 ObjectStore::Transaction t;
5561 t.merge_collection(tid, cid, common_suffix_size);
5562 r = queue_transaction(store, ch, std::move(t));
5563 ASSERT_EQ(r, 0);
5564 }
5565
5566 // check and clean up
5567 ObjectStore::Transaction t;
5568 {
5569 vector<ghobject_t> objects;
5570 r = store->collection_list(ch, ghobject_t(), ghobject_t::get_max(),
5571 INT_MAX, &objects, 0);
5572 ASSERT_EQ(r, 0);
5573 ASSERT_EQ(objects.size(), num_objects * 2); // both halves
5574 unsigned size = 0;
5575 for (vector<ghobject_t>::iterator i = objects.begin();
5576 i != objects.end();
5577 ++i) {
5578 t.remove(cid, *i);
5579 if (++size > 100) {
5580 size = 0;
5581 r = queue_transaction(store, ch, std::move(t));
5582 ASSERT_EQ(r, 0);
5583 t = ObjectStore::Transaction();
5584 }
5585 }
5586 }
5587 t.remove_collection(cid);
5588 r = queue_transaction(store, ch, std::move(t));
5589 ASSERT_EQ(r, 0);
5590
5591 ch->flush();
5592 ASSERT_TRUE(!store->collection_exists(tid));
5593 }
5594
5595 TEST_P(StoreTest, ColSplitTest0) {
5596 colsplittest(store.get(), 10, 5, false);
5597 }
5598 TEST_P(StoreTest, ColSplitTest1) {
5599 colsplittest(store.get(), 10000, 11, false);
5600 }
5601 TEST_P(StoreTest, ColSplitTest1Clones) {
5602 colsplittest(store.get(), 10000, 11, true);
5603 }
5604 TEST_P(StoreTest, ColSplitTest2) {
5605 colsplittest(store.get(), 100, 7, false);
5606 }
5607 TEST_P(StoreTest, ColSplitTest2Clones) {
5608 colsplittest(store.get(), 100, 7, true);
5609 }
5610
5611 #if 0
5612 TEST_P(StoreTest, ColSplitTest3) {
5613 colsplittest(store.get(), 100000, 25);
5614 }
5615 #endif
5616
5617 void test_merge_skewed(ObjectStore *store,
5618 unsigned base, unsigned bits,
5619 unsigned anum, unsigned bnum)
5620 {
5621 cout << __func__ << " 0x" << std::hex << base << std::dec
5622 << " bits " << bits
5623 << " anum " << anum << " bnum " << bnum << std::endl;
5624 /*
5625 make merge source pgs have radically different # of objects in them,
5626 which should trigger different splitting in filestore, and verify that
5627 post-merge all objects are accessible.
5628 */
5629 int r;
5630 coll_t a(spg_t(pg_t(base, 0), shard_id_t::NO_SHARD));
5631 coll_t b(spg_t(pg_t(base | (1<<bits), 0), shard_id_t::NO_SHARD));
5632
5633 auto cha = store->create_new_collection(a);
5634 auto chb = store->create_new_collection(b);
5635 {
5636 ObjectStore::Transaction t;
5637 t.create_collection(a, bits + 1);
5638 r = queue_transaction(store, cha, std::move(t));
5639 ASSERT_EQ(r, 0);
5640 }
5641 {
5642 ObjectStore::Transaction t;
5643 t.create_collection(b, bits + 1);
5644 r = queue_transaction(store, chb, std::move(t));
5645 ASSERT_EQ(r, 0);
5646 }
5647
5648 bufferlist small;
5649 small.append("small");
5650 string suffix = "ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooaaaaaaaaaa";
5651 set<ghobject_t> aobjects, bobjects;
5652 {
5653 // fill a
5654 ObjectStore::Transaction t;
5655 for (unsigned i = 0; i < 1000; ++i) {
5656 string objname = "a" + stringify(i) + suffix;
5657 ghobject_t o(hobject_t(
5658 objname,
5659 "",
5660 CEPH_NOSNAP,
5661 i<<(bits+1) | base,
5662 52, ""));
5663 aobjects.insert(o);
5664 t.write(a, o, 0, small.length(), small, 0);
5665 if (i % 100) {
5666 r = queue_transaction(store, cha, std::move(t));
5667 ASSERT_EQ(r, 0);
5668 t = ObjectStore::Transaction();
5669 }
5670 }
5671 r = queue_transaction(store, cha, std::move(t));
5672 ASSERT_EQ(r, 0);
5673 }
5674 {
5675 // fill b
5676 ObjectStore::Transaction t;
5677 for (unsigned i = 0; i < 10; ++i) {
5678 string objname = "b" + stringify(i) + suffix;
5679 ghobject_t o(hobject_t(
5680 objname,
5681 "",
5682 CEPH_NOSNAP,
5683 (i<<(base+1)) | base | (1<<bits),
5684 52, ""));
5685 bobjects.insert(o);
5686 t.write(b, o, 0, small.length(), small, 0);
5687 if (i % 100) {
5688 r = queue_transaction(store, chb, std::move(t));
5689 ASSERT_EQ(r, 0);
5690 t = ObjectStore::Transaction();
5691 }
5692 }
5693 r = queue_transaction(store, chb, std::move(t));
5694 ASSERT_EQ(r, 0);
5695 }
5696
5697 // merge b->a
5698 {
5699 ObjectStore::Transaction t;
5700 t.merge_collection(b, a, bits);
5701 r = queue_transaction(store, cha, std::move(t));
5702 ASSERT_EQ(r, 0);
5703 }
5704
5705 // verify
5706 {
5707 vector<ghobject_t> got;
5708 store->collection_list(cha, ghobject_t(), ghobject_t::get_max(), INT_MAX,
5709 &got, 0);
5710 set<ghobject_t> gotset;
5711 for (auto& o : got) {
5712 ASSERT_TRUE(aobjects.count(o) || bobjects.count(o));
5713 gotset.insert(o);
5714 }
5715 // check both listing and stat-ability (different code paths!)
5716 struct stat st;
5717 for (auto& o : aobjects) {
5718 ASSERT_TRUE(gotset.count(o));
5719 int r = store->stat(cha, o, &st, false);
5720 ASSERT_EQ(r, 0);
5721 }
5722 for (auto& o : bobjects) {
5723 ASSERT_TRUE(gotset.count(o));
5724 int r = store->stat(cha, o, &st, false);
5725 ASSERT_EQ(r, 0);
5726 }
5727 }
5728
5729 // clean up
5730 {
5731 ObjectStore::Transaction t;
5732 for (auto &o : aobjects) {
5733 t.remove(a, o);
5734 }
5735 r = queue_transaction(store, cha, std::move(t));
5736 ASSERT_EQ(r, 0);
5737 }
5738 {
5739 ObjectStore::Transaction t;
5740 for (auto &o : bobjects) {
5741 t.remove(a, o);
5742 }
5743 t.remove_collection(a);
5744 r = queue_transaction(store, cha, std::move(t));
5745 ASSERT_EQ(r, 0);
5746 }
5747 }
5748
5749 TEST_P(StoreTest, MergeSkewed) {
5750 if (string(GetParam()) != "filestore")
5751 return;
5752
5753 // this is sufficient to exercise merges with different hashing levels
5754 test_merge_skewed(store.get(), 0xf, 4, 10, 10000);
5755 test_merge_skewed(store.get(), 0xf, 4, 10000, 10);
5756
5757 /*
5758 // this covers a zillion variations that all boil down to the same thing
5759 for (unsigned base = 3; base < 0x1000; base *= 5) {
5760 unsigned bits;
5761 unsigned t = base;
5762 for (bits = 0; t; t >>= 1) {
5763 ++bits;
5764 }
5765 for (unsigned b = bits; b < bits + 10; b += 3) {
5766 for (auto anum : { 10, 1000, 10000 }) {
5767 for (auto bnum : { 10, 1000, 10000 }) {
5768 if (anum == bnum) {
5769 continue;
5770 }
5771 test_merge_skewed(store.get(), base, b, anum, bnum);
5772 }
5773 }
5774 }
5775 }
5776 */
5777 }
5778
5779
5780 /**
5781 * This test tests adding two different groups
5782 * of objects, each with 1 common prefix and 1
5783 * different prefix. We then remove half
5784 * in order to verify that the merging correctly
5785 * stops at the common prefix subdir. See bug
5786 * #5273 */
5787 TEST_P(StoreTest, TwoHash) {
5788 coll_t cid;
5789 int r;
5790 auto ch = store->create_new_collection(cid);
5791 {
5792 ObjectStore::Transaction t;
5793 t.create_collection(cid, 0);
5794 r = queue_transaction(store, ch, std::move(t));
5795 ASSERT_EQ(r, 0);
5796 }
5797 std::cout << "Making objects" << std::endl;
5798 for (int i = 0; i < 360; ++i) {
5799 ObjectStore::Transaction t;
5800 ghobject_t o;
5801 o.hobj.pool = -1;
5802 if (i < 8) {
5803 o.hobj.set_hash((i << 16) | 0xA1);
5804 t.touch(cid, o);
5805 }
5806 o.hobj.set_hash((i << 16) | 0xB1);
5807 t.touch(cid, o);
5808 r = queue_transaction(store, ch, std::move(t));
5809 ASSERT_EQ(r, 0);
5810 }
5811 std::cout << "Removing half" << std::endl;
5812 for (int i = 1; i < 8; ++i) {
5813 ObjectStore::Transaction t;
5814 ghobject_t o;
5815 o.hobj.pool = -1;
5816 o.hobj.set_hash((i << 16) | 0xA1);
5817 t.remove(cid, o);
5818 r = queue_transaction(store, ch, std::move(t));
5819 ASSERT_EQ(r, 0);
5820 }
5821 std::cout << "Checking" << std::endl;
5822 for (int i = 1; i < 8; ++i) {
5823 ObjectStore::Transaction t;
5824 ghobject_t o;
5825 o.hobj.set_hash((i << 16) | 0xA1);
5826 o.hobj.pool = -1;
5827 bool exists = store->exists(ch, o);
5828 ASSERT_EQ(exists, false);
5829 }
5830 {
5831 ghobject_t o;
5832 o.hobj.set_hash(0xA1);
5833 o.hobj.pool = -1;
5834 bool exists = store->exists(ch, o);
5835 ASSERT_EQ(exists, true);
5836 }
5837 std::cout << "Cleanup" << std::endl;
5838 for (int i = 0; i < 360; ++i) {
5839 ObjectStore::Transaction t;
5840 ghobject_t o;
5841 o.hobj.set_hash((i << 16) | 0xA1);
5842 o.hobj.pool = -1;
5843 t.remove(cid, o);
5844 o.hobj.set_hash((i << 16) | 0xB1);
5845 t.remove(cid, o);
5846 r = queue_transaction(store, ch, std::move(t));
5847 ASSERT_EQ(r, 0);
5848 }
5849 ObjectStore::Transaction t;
5850 t.remove_collection(cid);
5851 r = queue_transaction(store, ch, std::move(t));
5852 ASSERT_EQ(r, 0);
5853 }
5854
5855 TEST_P(StoreTest, Rename) {
5856 coll_t cid(spg_t(pg_t(0, 2122),shard_id_t::NO_SHARD));
5857 ghobject_t srcoid(hobject_t("src_oid", "", CEPH_NOSNAP, 0, 0, ""));
5858 ghobject_t dstoid(hobject_t("dest_oid", "", CEPH_NOSNAP, 0, 0, ""));
5859 bufferlist a, b;
5860 a.append("foo");
5861 b.append("bar");
5862 auto ch = store->create_new_collection(cid);
5863 int r;
5864 {
5865 ObjectStore::Transaction t;
5866 t.create_collection(cid, 0);
5867 t.write(cid, srcoid, 0, a.length(), a);
5868 r = queue_transaction(store, ch, std::move(t));
5869 ASSERT_EQ(r, 0);
5870 }
5871 ASSERT_TRUE(store->exists(ch, srcoid));
5872 {
5873 ObjectStore::Transaction t;
5874 t.collection_move_rename(cid, srcoid, cid, dstoid);
5875 t.write(cid, srcoid, 0, b.length(), b);
5876 t.setattr(cid, srcoid, "attr", b);
5877 r = queue_transaction(store, ch, std::move(t));
5878 ASSERT_EQ(r, 0);
5879 }
5880 ASSERT_TRUE(store->exists(ch, srcoid));
5881 ASSERT_TRUE(store->exists(ch, dstoid));
5882 {
5883 bufferlist bl;
5884 store->read(ch, srcoid, 0, 3, bl);
5885 ASSERT_TRUE(bl_eq(b, bl));
5886 store->read(ch, dstoid, 0, 3, bl);
5887 ASSERT_TRUE(bl_eq(a, bl));
5888 }
5889 {
5890 ObjectStore::Transaction t;
5891 t.remove(cid, dstoid);
5892 t.collection_move_rename(cid, srcoid, cid, dstoid);
5893 r = queue_transaction(store, ch, std::move(t));
5894 ASSERT_EQ(r, 0);
5895 }
5896 ASSERT_TRUE(store->exists(ch, dstoid));
5897 ASSERT_FALSE(store->exists(ch, srcoid));
5898 {
5899 bufferlist bl;
5900 store->read(ch, dstoid, 0, 3, bl);
5901 ASSERT_TRUE(bl_eq(b, bl));
5902 }
5903 {
5904 ObjectStore::Transaction t;
5905 t.remove(cid, dstoid);
5906 t.remove_collection(cid);
5907 r = queue_transaction(store, ch, std::move(t));
5908 ASSERT_EQ(r, 0);
5909 }
5910 }
5911
5912 TEST_P(StoreTest, MoveRename) {
5913 coll_t cid(spg_t(pg_t(0, 212),shard_id_t::NO_SHARD));
5914 ghobject_t temp_oid(hobject_t("tmp_oid", "", CEPH_NOSNAP, 0, 0, ""));
5915 ghobject_t oid(hobject_t("dest_oid", "", CEPH_NOSNAP, 0, 0, ""));
5916 auto ch = store->create_new_collection(cid);
5917 int r;
5918 {
5919 ObjectStore::Transaction t;
5920 t.create_collection(cid, 0);
5921 t.touch(cid, oid);
5922 r = queue_transaction(store, ch, std::move(t));
5923 ASSERT_EQ(r, 0);
5924 }
5925 ASSERT_TRUE(store->exists(ch, oid));
5926 bufferlist data, attr;
5927 map<string, bufferlist> omap;
5928 data.append("data payload");
5929 attr.append("attr value");
5930 omap["omap_key"].append("omap value");
5931 {
5932 ObjectStore::Transaction t;
5933 t.touch(cid, temp_oid);
5934 t.write(cid, temp_oid, 0, data.length(), data);
5935 t.setattr(cid, temp_oid, "attr", attr);
5936 t.omap_setkeys(cid, temp_oid, omap);
5937 r = queue_transaction(store, ch, std::move(t));
5938 ASSERT_EQ(r, 0);
5939 }
5940 ASSERT_TRUE(store->exists(ch, temp_oid));
5941 {
5942 ObjectStore::Transaction t;
5943 t.remove(cid, oid);
5944 t.collection_move_rename(cid, temp_oid, cid, oid);
5945 r = queue_transaction(store, ch, std::move(t));
5946 ASSERT_EQ(r, 0);
5947 }
5948 ASSERT_TRUE(store->exists(ch, oid));
5949 ASSERT_FALSE(store->exists(ch, temp_oid));
5950 {
5951 bufferlist newdata;
5952 r = store->read(ch, oid, 0, 1000, newdata);
5953 ASSERT_GE(r, 0);
5954 ASSERT_TRUE(bl_eq(data, newdata));
5955 bufferlist newattr;
5956 r = store->getattr(ch, oid, "attr", newattr);
5957 ASSERT_EQ(r, 0);
5958 ASSERT_TRUE(bl_eq(attr, newattr));
5959 set<string> keys;
5960 keys.insert("omap_key");
5961 map<string, bufferlist> newomap;
5962 r = store->omap_get_values(ch, oid, keys, &newomap);
5963 ASSERT_GE(r, 0);
5964 ASSERT_EQ(1u, newomap.size());
5965 ASSERT_TRUE(newomap.count("omap_key"));
5966 ASSERT_TRUE(bl_eq(omap["omap_key"], newomap["omap_key"]));
5967 }
5968 {
5969 ObjectStore::Transaction t;
5970 t.remove(cid, oid);
5971 t.remove_collection(cid);
5972 r = queue_transaction(store, ch, std::move(t));
5973 ASSERT_EQ(r, 0);
5974 }
5975 }
5976
5977 TEST_P(StoreTest, BigRGWObjectName) {
5978 coll_t cid(spg_t(pg_t(0,12),shard_id_t::NO_SHARD));
5979 ghobject_t oid(
5980 hobject_t(
5981 "default.4106.50_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
5982 "",
5983 CEPH_NOSNAP,
5984 0x81920472,
5985 12,
5986 ""),
5987 15,
5988 shard_id_t::NO_SHARD);
5989 ghobject_t oid2(oid);
5990 oid2.generation = 17;
5991 ghobject_t oidhead(oid);
5992 oidhead.generation = ghobject_t::NO_GEN;
5993
5994 auto ch = store->create_new_collection(cid);
5995
5996 int r;
5997 {
5998 ObjectStore::Transaction t;
5999 t.create_collection(cid, 0);
6000 t.touch(cid, oidhead);
6001 t.collection_move_rename(cid, oidhead, cid, oid);
6002 t.touch(cid, oidhead);
6003 t.collection_move_rename(cid, oidhead, cid, oid2);
6004 r = queue_transaction(store, ch, std::move(t));
6005 ASSERT_EQ(r, 0);
6006 }
6007
6008 {
6009 ObjectStore::Transaction t;
6010 t.remove(cid, oid);
6011 r = queue_transaction(store, ch, std::move(t));
6012 ASSERT_EQ(r, 0);
6013 }
6014
6015 {
6016 vector<ghobject_t> objects;
6017 r = store->collection_list(ch, ghobject_t(), ghobject_t::get_max(),
6018 INT_MAX, &objects, 0);
6019 ASSERT_EQ(r, 0);
6020 ASSERT_EQ(objects.size(), 1u);
6021 ASSERT_EQ(objects[0], oid2);
6022 }
6023
6024 ASSERT_FALSE(store->exists(ch, oid));
6025
6026 {
6027 ObjectStore::Transaction t;
6028 t.remove(cid, oid2);
6029 t.remove_collection(cid);
6030 r = queue_transaction(store, ch, std::move(t));
6031 ASSERT_EQ(r, 0);
6032
6033 }
6034 }
6035
6036 TEST_P(StoreTest, SetAllocHint) {
6037 coll_t cid;
6038 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, 0, ""));
6039 auto ch = store->create_new_collection(cid);
6040 int r;
6041 {
6042 ObjectStore::Transaction t;
6043 t.create_collection(cid, 0);
6044 t.touch(cid, hoid);
6045 r = queue_transaction(store, ch, std::move(t));
6046 ASSERT_EQ(r, 0);
6047 }
6048 {
6049 ObjectStore::Transaction t;
6050 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*4, 0);
6051 r = queue_transaction(store, ch, std::move(t));
6052 ASSERT_EQ(r, 0);
6053 }
6054 {
6055 ObjectStore::Transaction t;
6056 t.remove(cid, hoid);
6057 r = queue_transaction(store, ch, std::move(t));
6058 ASSERT_EQ(r, 0);
6059 }
6060 {
6061 ObjectStore::Transaction t;
6062 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*4, 0);
6063 r = queue_transaction(store, ch, std::move(t));
6064 ASSERT_EQ(r, 0);
6065 }
6066 {
6067 ObjectStore::Transaction t;
6068 t.remove_collection(cid);
6069 r = queue_transaction(store, ch, std::move(t));
6070 ASSERT_EQ(r, 0);
6071 }
6072 }
6073
6074 TEST_P(StoreTest, TryMoveRename) {
6075 coll_t cid;
6076 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
6077 ghobject_t hoid2(hobject_t("test_hint2", "", CEPH_NOSNAP, 0, -1, ""));
6078 auto ch = store->create_new_collection(cid);
6079 int r;
6080 {
6081 ObjectStore::Transaction t;
6082 t.create_collection(cid, 0);
6083 r = queue_transaction(store, ch, std::move(t));
6084 ASSERT_EQ(r, 0);
6085 }
6086 {
6087 ObjectStore::Transaction t;
6088 t.try_rename(cid, hoid, hoid2);
6089 r = queue_transaction(store, ch, std::move(t));
6090 ASSERT_EQ(r, 0);
6091 }
6092 {
6093 ObjectStore::Transaction t;
6094 t.touch(cid, hoid);
6095 r = queue_transaction(store, ch, std::move(t));
6096 ASSERT_EQ(r, 0);
6097 }
6098 {
6099 ObjectStore::Transaction t;
6100 t.try_rename(cid, hoid, hoid2);
6101 r = queue_transaction(store, ch, std::move(t));
6102 ASSERT_EQ(r, 0);
6103 }
6104 struct stat st;
6105 ASSERT_EQ(store->stat(ch, hoid, &st), -ENOENT);
6106 ASSERT_EQ(store->stat(ch, hoid2, &st), 0);
6107 }
6108
6109 #if defined(WITH_BLUESTORE)
6110 TEST_P(StoreTest, BluestoreOnOffCSumTest) {
6111 if (string(GetParam()) != "bluestore")
6112 return;
6113 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6114 g_conf().apply_changes(nullptr);
6115
6116 int r;
6117 coll_t cid;
6118 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
6119 {
6120 auto ch = store->open_collection(cid);
6121 ASSERT_FALSE(ch);
6122 }
6123 auto ch = store->create_new_collection(cid);
6124 {
6125 ObjectStore::Transaction t;
6126 t.create_collection(cid, 0);
6127 cerr << "Creating collection " << cid << std::endl;
6128 r = queue_transaction(store, ch, std::move(t));
6129 ASSERT_EQ(r, 0);
6130 }
6131 {
6132 //write with csum enabled followed by read with csum disabled
6133 size_t block_size = 64*1024;
6134 ObjectStore::Transaction t;
6135 bufferlist bl, orig;
6136 bl.append(std::string(block_size, 'a'));
6137 orig = bl;
6138 t.remove(cid, hoid);
6139 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
6140 t.write(cid, hoid, 0, bl.length(), bl);
6141 cerr << "Remove then create" << std::endl;
6142 r = queue_transaction(store, ch, std::move(t));
6143 ASSERT_EQ(r, 0);
6144
6145 SetVal(g_conf(), "bluestore_csum_type", "none");
6146 g_conf().apply_changes(nullptr);
6147
6148 bufferlist in;
6149 r = store->read(ch, hoid, 0, block_size, in);
6150 ASSERT_EQ((int)block_size, r);
6151 ASSERT_TRUE(bl_eq(orig, in));
6152
6153 }
6154 {
6155 //write with csum disabled followed by read with csum enabled
6156
6157 size_t block_size = 64*1024;
6158 ObjectStore::Transaction t;
6159 bufferlist bl, orig;
6160 bl.append(std::string(block_size, 'a'));
6161 orig = bl;
6162 t.remove(cid, hoid);
6163 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
6164 t.write(cid, hoid, 0, bl.length(), bl);
6165 cerr << "Remove then create" << std::endl;
6166 r = queue_transaction(store, ch, std::move(t));
6167 ASSERT_EQ(r, 0);
6168
6169 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6170 g_conf().apply_changes(nullptr);
6171
6172 bufferlist in;
6173 r = store->read(ch, hoid, 0, block_size, in);
6174 ASSERT_EQ((int)block_size, r);
6175 ASSERT_TRUE(bl_eq(orig, in));
6176 }
6177 {
6178 //'mixed' non-overlapping writes to the same blob
6179
6180 ObjectStore::Transaction t;
6181 bufferlist bl, orig;
6182 size_t block_size = 8000;
6183 bl.append(std::string(block_size, 'a'));
6184 orig = bl;
6185 t.remove(cid, hoid);
6186 t.write(cid, hoid, 0, bl.length(), bl);
6187 cerr << "Remove then create" << std::endl;
6188 r = queue_transaction(store, ch, std::move(t));
6189 ASSERT_EQ(r, 0);
6190
6191 SetVal(g_conf(), "bluestore_csum_type", "none");
6192 g_conf().apply_changes(nullptr);
6193
6194 ObjectStore::Transaction t2;
6195 t2.write(cid, hoid, block_size*2, bl.length(), bl);
6196 cerr << "Append 'unprotected'" << std::endl;
6197 r = queue_transaction(store, ch, std::move(t2));
6198 ASSERT_EQ(r, 0);
6199
6200 bufferlist in;
6201 r = store->read(ch, hoid, 0, block_size, in);
6202 ASSERT_EQ((int)block_size, r);
6203 ASSERT_TRUE(bl_eq(orig, in));
6204 in.clear();
6205 r = store->read(ch, hoid, block_size*2, block_size, in);
6206 ASSERT_EQ((int)block_size, r);
6207 ASSERT_TRUE(bl_eq(orig, in));
6208
6209 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6210 g_conf().apply_changes(nullptr);
6211 in.clear();
6212 r = store->read(ch, hoid, 0, block_size, in);
6213 ASSERT_EQ((int)block_size, r);
6214 ASSERT_TRUE(bl_eq(orig, in));
6215 in.clear();
6216 r = store->read(ch, hoid, block_size*2, block_size, in);
6217 ASSERT_EQ((int)block_size, r);
6218 ASSERT_TRUE(bl_eq(orig, in));
6219 }
6220 {
6221 //partially blob overwrite under a different csum enablement mode
6222
6223 ObjectStore::Transaction t;
6224 bufferlist bl, orig, orig2;
6225 size_t block_size0 = 0x10000;
6226 size_t block_size = 9000;
6227 size_t block_size2 = 5000;
6228 bl.append(std::string(block_size0, 'a'));
6229 t.remove(cid, hoid);
6230 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
6231 t.write(cid, hoid, 0, bl.length(), bl);
6232 cerr << "Remove then create" << std::endl;
6233 r = queue_transaction(store, ch, std::move(t));
6234 ASSERT_EQ(r, 0);
6235
6236 SetVal(g_conf(), "bluestore_csum_type", "none");
6237 g_conf().apply_changes(nullptr);
6238
6239 ObjectStore::Transaction t2;
6240 bl.clear();
6241 bl.append(std::string(block_size, 'b'));
6242 t2.write(cid, hoid, 0, bl.length(), bl);
6243 t2.write(cid, hoid, block_size0, bl.length(), bl);
6244 cerr << "Overwrite with unprotected data" << std::endl;
6245 r = queue_transaction(store, ch, std::move(t2));
6246 ASSERT_EQ(r, 0);
6247
6248 orig = bl;
6249 orig2 = bl;
6250 orig.append( std::string(block_size0 - block_size, 'a'));
6251
6252 bufferlist in;
6253 r = store->read(ch, hoid, 0, block_size0, in);
6254 ASSERT_EQ((int)block_size0, r);
6255 ASSERT_TRUE(bl_eq(orig, in));
6256
6257 r = store->read(ch, hoid, block_size0, block_size, in);
6258 ASSERT_EQ((int)block_size, r);
6259 ASSERT_TRUE(bl_eq(orig2, in));
6260
6261 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6262 g_conf().apply_changes(nullptr);
6263
6264 ObjectStore::Transaction t3;
6265 bl.clear();
6266 bl.append(std::string(block_size2, 'c'));
6267 t3.write(cid, hoid, block_size0, bl.length(), bl);
6268 cerr << "Overwrite with protected data" << std::endl;
6269 r = queue_transaction(store, ch, std::move(t3));
6270 ASSERT_EQ(r, 0);
6271
6272 in.clear();
6273 orig = bl;
6274 orig.append( std::string(block_size - block_size2, 'b'));
6275 r = store->read(ch, hoid, block_size0, block_size, in);
6276 ASSERT_EQ((int)block_size, r);
6277 ASSERT_TRUE(bl_eq(orig, in));
6278 }
6279
6280 {
6281 ObjectStore::Transaction t;
6282 t.remove(cid, hoid);
6283 t.remove_collection(cid);
6284 cerr << "Cleaning" << std::endl;
6285 r = queue_transaction(store, ch, std::move(t));
6286 ASSERT_EQ(r, 0);
6287 }
6288 }
6289 #endif
6290
6291 INSTANTIATE_TEST_SUITE_P(
6292 ObjectStore,
6293 StoreTest,
6294 ::testing::Values(
6295 "memstore",
6296 "filestore",
6297 #if defined(WITH_BLUESTORE)
6298 "bluestore",
6299 #endif
6300 "kstore"));
6301
6302 // Note: instantiate all stores to preserve store numbering order only
6303 INSTANTIATE_TEST_SUITE_P(
6304 ObjectStore,
6305 StoreTestSpecificAUSize,
6306 ::testing::Values(
6307 "memstore",
6308 "filestore",
6309 #if defined(WITH_BLUESTORE)
6310 "bluestore",
6311 #endif
6312 "kstore"));
6313
6314 void doMany4KWritesTest(boost::scoped_ptr<ObjectStore>& store,
6315 unsigned max_objects,
6316 unsigned max_ops,
6317 unsigned max_object_size,
6318 unsigned max_write_size,
6319 unsigned write_alignment)
6320 {
6321 MixedGenerator gen(555);
6322 gen_type rng(time(NULL));
6323 coll_t cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD));
6324 store_statfs_t res_stat;
6325
6326 SyntheticWorkloadState test_obj(store.get(),
6327 &gen,
6328 &rng,
6329 cid,
6330 max_object_size,
6331 max_write_size,
6332 write_alignment);
6333 test_obj.init();
6334 for (unsigned i = 0; i < max_objects; ++i) {
6335 if (!(i % 500)) cerr << "seeding object " << i << std::endl;
6336 test_obj.touch();
6337 }
6338 for (unsigned i = 0; i < max_ops; ++i) {
6339 if (!(i % 200)) {
6340 cerr << "Op " << i << std::endl;
6341 test_obj.print_internal_state();
6342 }
6343 test_obj.write();
6344 }
6345 test_obj.wait_for_done();
6346 test_obj.statfs(res_stat);
6347 if (!(res_stat.data_stored <= max_object_size) ||
6348 !(res_stat.allocated <= max_object_size)) {
6349 // this will provide more insight on the mismatch and
6350 // helps to avoid any races during stats collection
6351 test_obj.fsck(false);
6352 // retrieving stats once again and assert if still broken
6353 test_obj.statfs(res_stat);
6354 ASSERT_LE(res_stat.data_stored, max_object_size);
6355 ASSERT_LE(res_stat.allocated, max_object_size);
6356 }
6357 test_obj.shutdown();
6358 }
6359
6360 TEST_P(StoreTestSpecificAUSize, Many4KWritesTest) {
6361 if (string(GetParam()) != "bluestore")
6362 return;
6363
6364 StartDeferred(0x10000);
6365
6366 const unsigned max_object = 4*1024*1024;
6367 doMany4KWritesTest(store, 1, 1000, max_object, 4*1024, 0);
6368 }
6369
6370 TEST_P(StoreTestSpecificAUSize, Many4KWritesNoCSumTest) {
6371 if (string(GetParam()) != "bluestore")
6372 return;
6373 StartDeferred(0x10000);
6374 SetVal(g_conf(), "bluestore_csum_type", "none");
6375 g_ceph_context->_conf.apply_changes(nullptr);
6376 const unsigned max_object = 4*1024*1024;
6377
6378 doMany4KWritesTest(store, 1, 1000, max_object, 4*1024, 0 );
6379 }
6380
6381 TEST_P(StoreTestSpecificAUSize, TooManyBlobsTest) {
6382 if (string(GetParam()) != "bluestore")
6383 return;
6384 StartDeferred(0x10000);
6385 const unsigned max_object = 4*1024*1024;
6386 doMany4KWritesTest(store, 1, 1000, max_object, 4*1024, 0);
6387 }
6388
6389 #if defined(WITH_BLUESTORE)
6390 void get_mempool_stats(uint64_t* total_bytes, uint64_t* total_items)
6391 {
6392 uint64_t onode_allocated = mempool::bluestore_cache_onode::allocated_bytes();
6393 uint64_t other_allocated = mempool::bluestore_cache_other::allocated_bytes();
6394
6395 uint64_t onode_items = mempool::bluestore_cache_onode::allocated_items();
6396 uint64_t other_items = mempool::bluestore_cache_other::allocated_items();
6397 cout << "onode(" << onode_allocated << "/" << onode_items
6398 << ") other(" << other_allocated << "/" << other_items
6399 << ")" << std::endl;
6400 *total_bytes = onode_allocated + other_allocated;
6401 *total_items = onode_items;
6402 }
6403
6404 TEST_P(StoreTestSpecificAUSize, OnodeSizeTracking) {
6405
6406 if (string(GetParam()) != "bluestore")
6407 return;
6408
6409 size_t block_size = 4096;
6410 StartDeferred(block_size);
6411 SetVal(g_conf(), "bluestore_compression_mode", "none");
6412 SetVal(g_conf(), "bluestore_csum_type", "none");
6413 SetVal(g_conf(), "bluestore_cache_size_hdd", "400000000");
6414 SetVal(g_conf(), "bluestore_cache_size_ssd", "400000000");
6415 g_conf().apply_changes(nullptr);
6416
6417 int r;
6418 coll_t cid;
6419 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
6420 size_t obj_size = 4 * 1024 * 1024;
6421 uint64_t total_bytes, total_bytes2;
6422 uint64_t total_onodes;
6423 get_mempool_stats(&total_bytes, &total_onodes);
6424 ASSERT_EQ(total_onodes, 0u);
6425
6426 auto ch = store->create_new_collection(cid);
6427 {
6428 ObjectStore::Transaction t;
6429 t.create_collection(cid, 0);
6430 r = queue_transaction(store, ch, std::move(t));
6431 ASSERT_EQ(r, 0);
6432 }
6433 {
6434 ObjectStore::Transaction t;
6435 bufferlist bl, orig, orig2;
6436
6437 bl.append(std::string(obj_size, 'a'));
6438 t.write(cid, hoid, 0, bl.length(), bl);
6439 r = queue_transaction(store, ch, std::move(t));
6440 ASSERT_EQ(r, 0);
6441 }
6442 get_mempool_stats(&total_bytes, &total_onodes);
6443 ASSERT_NE(total_bytes, 0u);
6444 ASSERT_EQ(total_onodes, 1u);
6445
6446 {
6447 ObjectStore::Transaction t;
6448 t.truncate(cid, hoid, 0);
6449 r = queue_transaction(store, ch, std::move(t));
6450 ASSERT_EQ(r, 0);
6451 }
6452
6453 for(size_t i = 0; i < 1; ++i) {
6454 bufferlist bl;
6455 bl.append(std::string(block_size * (i+1), 'a'));
6456 for( size_t j = 0; j < obj_size; j+= bl.length()) {
6457 ObjectStore::Transaction t;
6458 t.write(cid, hoid, j, bl.length(), bl);
6459 r = queue_transaction(store, ch, std::move(t));
6460 ASSERT_EQ(r, 0);
6461 }
6462 get_mempool_stats(&total_bytes2, &total_onodes);
6463 ASSERT_NE(total_bytes2, 0u);
6464 ASSERT_EQ(total_onodes, 1u);
6465 }
6466 {
6467 cout <<" mempool dump:\n";
6468 JSONFormatter f(true);
6469 f.open_object_section("transaction");
6470 mempool::dump(&f);
6471 f.close_section();
6472 f.flush(cout);
6473 cout << std::endl;
6474 }
6475 {
6476 bufferlist bl;
6477 for (size_t i = 0; i < obj_size; i += 0x1000) {
6478 store->read(ch, hoid, i, 0x1000, bl);
6479 }
6480 }
6481 get_mempool_stats(&total_bytes, &total_onodes);
6482 ASSERT_NE(total_bytes, 0u);
6483 ASSERT_EQ(total_onodes, 1u);
6484
6485 {
6486 cout <<" mempool dump:\n";
6487 JSONFormatter f(true);
6488 f.open_object_section("transaction");
6489 mempool::dump(&f);
6490 f.close_section();
6491 f.flush(cout);
6492 cout << std::endl;
6493 }
6494 {
6495 ObjectStore::Transaction t;
6496 t.remove(cid, hoid);
6497 t.remove_collection(cid);
6498 cerr << "Cleaning" << std::endl;
6499 r = queue_transaction(store, ch, std::move(t));
6500 ASSERT_EQ(r, 0);
6501 }
6502 }
6503
6504 TEST_P(StoreTestSpecificAUSize, BlobReuseOnOverwrite) {
6505
6506 if (string(GetParam()) != "bluestore")
6507 return;
6508
6509 size_t block_size = 4096;
6510 StartDeferred(block_size);
6511 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6512 g_conf().apply_changes(nullptr);
6513
6514 int r;
6515 coll_t cid;
6516 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
6517
6518 const PerfCounters* logger = store->get_perf_counters();
6519
6520 auto ch = store->create_new_collection(cid);
6521 {
6522 ObjectStore::Transaction t;
6523 t.create_collection(cid, 0);
6524 r = queue_transaction(store, ch, std::move(t));
6525 ASSERT_EQ(r, 0);
6526 }
6527 {
6528 ObjectStore::Transaction t;
6529 bufferlist bl;
6530
6531 bl.append(std::string(block_size * 2, 'a'));
6532 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6533 r = queue_transaction(store, ch, std::move(t));
6534 ASSERT_EQ(r, 0);
6535 }
6536 {
6537 // overwrite at the beginning
6538 ObjectStore::Transaction t;
6539 bufferlist bl;
6540
6541 bl.append(std::string(block_size, 'b'));
6542 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6543 r = queue_transaction(store, ch, std::move(t));
6544 ASSERT_EQ(r, 0);
6545 }
6546 {
6547 // append
6548 ObjectStore::Transaction t;
6549 bufferlist bl;
6550
6551 bl.append(std::string(block_size * 2, 'c'));
6552 t.write(cid, hoid, block_size * 2, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6553 r = queue_transaction(store, ch, std::move(t));
6554 ASSERT_EQ(r, 0);
6555 }
6556 {
6557 // append with a gap
6558 ObjectStore::Transaction t;
6559 bufferlist bl;
6560
6561 bl.append(std::string(block_size * 2, 'd'));
6562 t.write(cid, hoid, block_size * 5, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6563 r = queue_transaction(store, ch, std::move(t));
6564 ASSERT_EQ(r, 0);
6565 }
6566 {
6567 // We need to issue a read to trigger cache stat update that refresh
6568 // perf counters. additionally we need to wait some time for mempool
6569 // thread to update stats.
6570 sleep(1);
6571 bufferlist bl, expected;
6572 r = store->read(ch, hoid, 0, block_size, bl);
6573 ASSERT_EQ(r, (int)block_size);
6574 expected.append(string(block_size, 'b'));
6575 ASSERT_TRUE(bl_eq(expected, bl));
6576 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6577 ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
6578 }
6579 {
6580 // overwrite at end
6581 ObjectStore::Transaction t;
6582 bufferlist bl;
6583
6584 bl.append(std::string(block_size * 2, 'e'));
6585
6586 // Currently we are unable to reuse blob when overwriting in a single step
6587 t.write(cid, hoid, block_size * 6, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6588 r = queue_transaction(store, ch, std::move(t));
6589 ASSERT_EQ(r, 0);
6590 }
6591 {
6592 // We need to issue a read to trigger cache stat update that refresh
6593 // perf counters. additionally we need to wait some time for mempool
6594 // thread to update stats.
6595 sleep(1);
6596 bufferlist bl, expected;
6597 r = store->read(ch, hoid, 0, block_size, bl);
6598 ASSERT_EQ(r, (int)block_size);
6599 expected.append(string(block_size, 'b'));
6600 ASSERT_TRUE(bl_eq(expected, bl));
6601 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6602 ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
6603 }
6604 {
6605 // fill the gap
6606 ObjectStore::Transaction t;
6607 bufferlist bl;
6608
6609 bl.append(std::string(block_size, 'f'));
6610
6611 t.write(cid, hoid, block_size * 4, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6612 r = queue_transaction(store, ch, std::move(t));
6613 ASSERT_EQ(r, 0);
6614 }
6615 {
6616 // we need to wait some time for mempool
6617 // thread to update stats to be able to check blob/extent numbers from
6618 // perf counters.
6619 sleep(1);
6620
6621 bufferlist bl, expected;
6622 r = store->read(ch, hoid, 0, block_size, bl);
6623 ASSERT_EQ(r, (int)block_size);
6624 expected.append(string(block_size, 'b'));
6625 ASSERT_TRUE(bl_eq(expected, bl));
6626
6627 bl.clear();
6628 expected.clear();
6629 r = store->read(ch, hoid, block_size, block_size, bl);
6630 ASSERT_EQ(r, (int)block_size);
6631 expected.append(string(block_size, 'a'));
6632 ASSERT_TRUE(bl_eq(expected, bl));
6633
6634 bl.clear();
6635 expected.clear();
6636 r = store->read(ch, hoid, block_size * 2, block_size * 2, bl);
6637 ASSERT_EQ(r, (int)block_size * 2);
6638 expected.append(string(block_size * 2, 'c'));
6639 ASSERT_TRUE(bl_eq(expected, bl));
6640
6641 bl.clear();
6642 expected.clear();
6643 r = store->read(ch, hoid, block_size * 4, block_size, bl);
6644 ASSERT_EQ(r, (int)block_size);
6645 expected.append(string(block_size, 'f'));
6646 ASSERT_TRUE(bl_eq(expected, bl));
6647
6648 bl.clear();
6649 expected.clear();
6650 r = store->read(ch, hoid, block_size * 5, block_size, bl);
6651 ASSERT_EQ(r, (int)block_size);
6652 expected.append(string(block_size, 'd'));
6653 ASSERT_TRUE(bl_eq(expected, bl));
6654
6655 bl.clear();
6656 expected.clear();
6657 r = store->read(ch, hoid, block_size * 5, block_size * 3, bl);
6658 ASSERT_EQ(r, (int)block_size * 3);
6659 expected.append(string(block_size, 'd'));
6660 expected.append(string(block_size * 2, 'e'));
6661 ASSERT_TRUE(bl_eq(expected, bl));
6662 }
6663 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6664 ASSERT_EQ(logger->get(l_bluestore_extents), 1u);
6665
6666
6667 {
6668 ObjectStore::Transaction t;
6669 t.remove(cid, hoid);
6670 t.remove_collection(cid);
6671 cerr << "Cleaning" << std::endl;
6672 r = queue_transaction(store, ch, std::move(t));
6673 ASSERT_EQ(r, 0);
6674 }
6675 }
6676
6677 TEST_P(StoreTestSpecificAUSize, BlobReuseOnOverwriteReverse) {
6678
6679 if (string(GetParam()) != "bluestore")
6680 return;
6681
6682 size_t block_size = 4096;
6683 StartDeferred(block_size);
6684 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6685 g_conf().apply_changes(nullptr);
6686
6687 int r;
6688 coll_t cid;
6689 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
6690
6691 auto ch = store->create_new_collection(cid);
6692
6693 const PerfCounters* logger = store->get_perf_counters();
6694 {
6695 ObjectStore::Transaction t;
6696 t.create_collection(cid, 0);
6697 r = queue_transaction(store, ch, std::move(t));
6698 ASSERT_EQ(r, 0);
6699 }
6700 {
6701 ObjectStore::Transaction t;
6702 bufferlist bl;
6703
6704 bl.append(std::string(block_size * 2, 'a'));
6705 t.write(cid, hoid, block_size * 10, bl.length(), bl,
6706 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6707 r = queue_transaction(store, ch, std::move(t));
6708 ASSERT_EQ(r, 0);
6709 }
6710 {
6711 // prepend existing
6712 ObjectStore::Transaction t;
6713 bufferlist bl;
6714
6715 bl.append(std::string(block_size, 'b'));
6716 t.write(cid, hoid, block_size * 9, bl.length(), bl,
6717 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6718 r = queue_transaction(store, ch, std::move(t));
6719 ASSERT_EQ(r, 0);
6720 }
6721 {
6722 // We need to issue a read to trigger cache stat update that refresh
6723 // perf counters. additionally we need to wait some time for mempool
6724 // thread to update stats.
6725 sleep(1);
6726 bufferlist bl, expected;
6727 r = store->read(ch, hoid, block_size * 9, block_size * 2, bl);
6728 ASSERT_EQ(r, (int)block_size * 2);
6729 expected.append(string(block_size, 'b'));
6730 expected.append(string(block_size, 'a'));
6731 ASSERT_TRUE(bl_eq(expected, bl));
6732 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6733 ASSERT_EQ(logger->get(l_bluestore_extents), 1u);
6734 }
6735
6736
6737 {
6738 // prepend existing with a gap
6739 ObjectStore::Transaction t;
6740 bufferlist bl;
6741
6742 bl.append(std::string(block_size, 'c'));
6743 t.write(cid, hoid, block_size * 7, bl.length(), bl,
6744 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6745 r = queue_transaction(store, ch, std::move(t));
6746 ASSERT_EQ(r, 0);
6747 }
6748 {
6749 // We need to issue a read to trigger cache stat update that refresh
6750 // perf counters. additionally we need to wait some time for mempool
6751 // thread to update stats.
6752 sleep(1);
6753 bufferlist bl, expected;
6754 r = store->read(ch, hoid, block_size * 7, block_size * 3, bl);
6755 ASSERT_EQ(r, (int)block_size * 3);
6756 expected.append(string(block_size, 'c'));
6757 expected.append(string(block_size, 0));
6758 expected.append(string(block_size, 'b'));
6759 ASSERT_TRUE(bl_eq(expected, bl));
6760 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6761 ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
6762 }
6763
6764 {
6765 // append after existing with a gap
6766 ObjectStore::Transaction t;
6767 bufferlist bl;
6768
6769 bl.append(std::string(block_size, 'd'));
6770 t.write(cid, hoid, block_size * 13, bl.length(), bl,
6771 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6772 r = queue_transaction(store, ch, std::move(t));
6773 ASSERT_EQ(r, 0);
6774 }
6775 {
6776 // We need to issue a read to trigger cache stat update that refresh
6777 // perf counters. additionally we need to wait some time for mempool
6778 // thread to update stats.
6779 sleep(1);
6780 bufferlist bl, expected;
6781 r = store->read(ch, hoid, block_size * 11, block_size * 3, bl);
6782 ASSERT_EQ(r, (int)block_size * 3);
6783 expected.append(string(block_size, 'a'));
6784 expected.append(string(block_size, 0));
6785 expected.append(string(block_size, 'd'));
6786 ASSERT_TRUE(bl_eq(expected, bl));
6787 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6788 ASSERT_EQ(logger->get(l_bluestore_extents), 3u);
6789 }
6790
6791 {
6792 // append twice to the next max_blob slot
6793 ObjectStore::Transaction t;
6794 bufferlist bl;
6795
6796 bl.append(std::string(block_size, 'e'));
6797 t.write(cid, hoid, block_size * 17, bl.length(), bl,
6798 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6799 t.write(cid, hoid, block_size * 19, 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 // We need to issue a read to trigger cache stat update that refresh
6806 // perf counters. additionally we need to wait some time for mempool
6807 // thread to update stats.
6808 sleep(1);
6809 bufferlist bl, expected;
6810 r = store->read(ch, hoid, block_size * 17, block_size * 3, bl);
6811 ASSERT_EQ(r, (int)block_size * 3);
6812 expected.append(string(block_size, 'e'));
6813 expected.append(string(block_size, 0));
6814 expected.append(string(block_size, 'e'));
6815 ASSERT_TRUE(bl_eq(expected, bl));
6816 ASSERT_EQ(logger->get(l_bluestore_blobs), 2u);
6817 ASSERT_EQ(logger->get(l_bluestore_extents), 5u);
6818 }
6819 {
6820 // fill gaps at the second slot
6821 ObjectStore::Transaction t;
6822 bufferlist bl;
6823
6824 bl.append(std::string(block_size, 'f'));
6825 t.write(cid, hoid, block_size * 16, bl.length(), bl,
6826 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6827 t.write(cid, hoid, block_size * 18, bl.length(), bl,
6828 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6829 r = queue_transaction(store, ch, std::move(t));
6830 ASSERT_EQ(r, 0);
6831 }
6832 {
6833 // We need to issue a read to trigger cache stat update that refresh
6834 // perf counters. additionally we need to wait some time for mempool
6835 // thread to update stats.
6836 sleep(1);
6837 bufferlist bl, expected;
6838 r = store->read(ch, hoid, block_size * 16, block_size * 4, bl);
6839 ASSERT_EQ(r, (int)block_size * 4);
6840 expected.append(string(block_size, 'f'));
6841 expected.append(string(block_size, 'e'));
6842 expected.append(string(block_size, 'f'));
6843 expected.append(string(block_size, 'e'));
6844 ASSERT_TRUE(bl_eq(expected, bl));
6845 ASSERT_EQ(logger->get(l_bluestore_blobs), 2u);
6846 ASSERT_EQ(logger->get(l_bluestore_extents), 4u);
6847 }
6848 {
6849 ObjectStore::Transaction t;
6850 t.remove(cid, hoid);
6851 t.remove_collection(cid);
6852 cerr << "Cleaning" << std::endl;
6853 r = queue_transaction(store, ch, std::move(t));
6854 ASSERT_EQ(r, 0);
6855 }
6856 }
6857
6858 TEST_P(StoreTestSpecificAUSize, BlobReuseOnSmallOverwrite) {
6859
6860 if (string(GetParam()) != "bluestore")
6861 return;
6862
6863 size_t block_size = 4096;
6864 StartDeferred(block_size);
6865 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6866 g_conf().apply_changes(nullptr);
6867
6868 int r;
6869 coll_t cid;
6870 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
6871
6872 const PerfCounters* logger = store->get_perf_counters();
6873 auto ch = store->create_new_collection(cid);
6874
6875 {
6876 ObjectStore::Transaction t;
6877 t.create_collection(cid, 0);
6878 r = queue_transaction(store, ch, std::move(t));
6879 ASSERT_EQ(r, 0);
6880 }
6881 {
6882 ObjectStore::Transaction t;
6883 bufferlist bl;
6884
6885 bl.append(std::string(block_size, 'a'));
6886 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6887 t.write(cid, hoid, block_size * 2, bl.length(), bl,
6888 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6889 r = queue_transaction(store, ch, std::move(t));
6890 ASSERT_EQ(r, 0);
6891 }
6892 {
6893 // write small into the gap
6894 ObjectStore::Transaction t;
6895 bufferlist bl;
6896
6897 bl.append(std::string(3, 'b'));
6898 t.write(cid, hoid, block_size + 1, bl.length(), bl,
6899 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6900 r = queue_transaction(store, ch, std::move(t));
6901 ASSERT_EQ(r, 0);
6902 }
6903 {
6904 // We need to issue a read to trigger cache stat update that refresh
6905 // perf counters. additionally we need to wait some time for mempool
6906 // thread to update stats.
6907 sleep(1);
6908 bufferlist bl, expected;
6909 r = store->read(ch, hoid, 0, block_size * 3, bl);
6910 ASSERT_EQ(r, (int)block_size * 3);
6911 expected.append(string(block_size, 'a'));
6912 expected.append(string(1, 0));
6913 expected.append(string(3, 'b'));
6914 expected.append(string(block_size - 4, 0));
6915 expected.append(string(block_size, 'a'));
6916 ASSERT_TRUE(bl_eq(expected, bl));
6917
6918 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6919 ASSERT_EQ(logger->get(l_bluestore_extents), 3u);
6920 }
6921 {
6922 ObjectStore::Transaction t;
6923 t.remove(cid, hoid);
6924 t.remove_collection(cid);
6925 cerr << "Cleaning" << std::endl;
6926 r = queue_transaction(store, ch, std::move(t));
6927 ASSERT_EQ(r, 0);
6928 }
6929 }
6930
6931 // The test case to reproduce an issue when write happens
6932 // to a zero space between the extents sharing the same spanning blob
6933 // with unloaded shard map.
6934 // Second extent might be filled with zeros this way due to wrong result
6935 // returned by has_any_extents() call in do_write_small. The latter is caused
6936 // by incompletly loaded extent map.
6937 TEST_P(StoreTestSpecificAUSize, SmallWriteOnShardedExtents) {
6938 if (string(GetParam()) != "bluestore")
6939 return;
6940
6941 size_t block_size = 0x10000;
6942 StartDeferred(block_size);
6943
6944 SetVal(g_conf(), "bluestore_csum_type", "xxhash64");
6945 SetVal(g_conf(), "bluestore_max_blob_size", "524288"); // for sure
6946
6947 g_conf().apply_changes(nullptr);
6948
6949 int r;
6950 coll_t cid;
6951 ghobject_t hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
6952 auto ch = store->create_new_collection(cid);
6953
6954 {
6955 ObjectStore::Transaction t;
6956 t.create_collection(cid, 0);
6957 r = queue_transaction(store, ch, std::move(t));
6958 ASSERT_EQ(r, 0);
6959 }
6960 {
6961 //doing some tricks to have sharded extents/spanning objects
6962 ObjectStore::Transaction t;
6963 bufferlist bl, bl2;
6964
6965 bl.append(std::string(0x80000, 'a'));
6966 t.write(cid, hoid1, 0, bl.length(), bl, 0);
6967 t.zero(cid, hoid1, 0x719e0, 0x75b0 );
6968 r = queue_transaction(store, ch, std::move(t));
6969 ASSERT_EQ(r, 0);
6970
6971 bl2.append(std::string(0x70000, 'b'));
6972 t.write(cid, hoid1, 0, bl2.length(), bl2, 0);
6973 t.zero(cid, hoid1, 0, 0x50000);
6974 r = queue_transaction(store, ch, std::move(t));
6975 ASSERT_EQ(r, 0);
6976
6977 }
6978 ch.reset();
6979 store->umount();
6980 store->mount();
6981 ch = store->open_collection(cid);
6982
6983 {
6984 // do a write to zero space in between some extents sharing the same blob
6985 ObjectStore::Transaction t;
6986 bufferlist bl, bl2;
6987
6988 bl.append(std::string(0x6520, 'c'));
6989 t.write(cid, hoid1, 0x71c00, bl.length(), bl, 0);
6990
6991 r = queue_transaction(store, ch, std::move(t));
6992 ASSERT_EQ(r, 0);
6993 }
6994
6995 {
6996 ObjectStore::Transaction t;
6997 bufferlist bl, expected;
6998
6999 r = store->read(ch, hoid1, 0x70000, 0x9c00, bl);
7000 ASSERT_EQ(r, (int)0x9c00);
7001 expected.append(string(0x19e0, 'a'));
7002 expected.append(string(0x220, 0));
7003 expected.append(string(0x6520, 'c'));
7004 expected.append(string(0xe70, 0));
7005 expected.append(string(0xc70, 'a'));
7006 ASSERT_TRUE(bl_eq(expected, bl));
7007 bl.clear();
7008
7009 }
7010
7011 {
7012 ObjectStore::Transaction t;
7013 t.remove(cid, hoid1);
7014 t.remove_collection(cid);
7015 cerr << "Cleaning" << std::endl;
7016 r = queue_transaction(store, ch, std::move(t));
7017 ASSERT_EQ(r, 0);
7018 }
7019 }
7020
7021 TEST_P(StoreTestSpecificAUSize, ExcessiveFragmentation) {
7022 if (string(GetParam()) != "bluestore")
7023 return;
7024
7025 SetVal(g_conf(), "bluestore_block_size",
7026 stringify((uint64_t)2048 * 1024 * 1024).c_str());
7027
7028 ASSERT_EQ(g_conf().get_val<Option::size_t>("bluefs_alloc_size"),
7029 1024 * 1024U);
7030
7031 size_t block_size = 0x10000;
7032 StartDeferred(block_size);
7033
7034 int r;
7035 coll_t cid;
7036 ghobject_t hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
7037 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
7038 auto ch = store->create_new_collection(cid);
7039
7040 {
7041 ObjectStore::Transaction t;
7042 t.create_collection(cid, 0);
7043 r = queue_transaction(store, ch, std::move(t));
7044 ASSERT_EQ(r, 0);
7045 }
7046 {
7047 // create 2x400MB objects in a way that their pextents are interleaved
7048 ObjectStore::Transaction t;
7049 bufferlist bl;
7050
7051 bl.append(std::string(block_size * 4, 'a')); // 256KB
7052 uint64_t offs = 0;
7053 while(offs < (uint64_t)400 * 1024 * 1024) {
7054 t.write(cid, hoid1, offs, bl.length(), bl, 0);
7055 t.write(cid, hoid2, offs, bl.length(), bl, 0);
7056 r = queue_transaction(store, ch, std::move(t));
7057 ASSERT_EQ(r, 0);
7058 offs += bl.length();
7059 if( (offs % (100 * 1024 * 1024)) == 0) {
7060 std::cout<<"written " << offs << std::endl;
7061 }
7062 }
7063 }
7064 std::cout<<"written 800MB"<<std::endl;
7065 {
7066 // Partially overwrite objects with 100MB each leaving space
7067 // fragmented and occuping still unfragmented space at the end
7068 // So we'll have enough free space but it'll lack long enough (e.g. 1MB)
7069 // contiguous pextents.
7070 ObjectStore::Transaction t;
7071 bufferlist bl;
7072
7073 bl.append(std::string(block_size * 4, 'a'));
7074 uint64_t offs = 0;
7075 while(offs < 112 * 1024 * 1024) {
7076 t.write(cid, hoid1, offs, bl.length(), bl, 0);
7077 t.write(cid, hoid2, offs, bl.length(), bl, 0);
7078 r = queue_transaction(store, ch, std::move(t));
7079 ASSERT_EQ(r, 0);
7080 // this will produce high fragmentation if original allocations
7081 // were contiguous
7082 offs += bl.length();
7083 if( (offs % (10 * 1024 * 1024)) == 0) {
7084 std::cout<<"written " << offs << std::endl;
7085 }
7086 }
7087 }
7088 {
7089 // remove one of the object producing much free space
7090 // and hence triggering bluefs rebalance.
7091 // Which should fail as there is no long enough pextents.
7092 ObjectStore::Transaction t;
7093 t.remove(cid, hoid2);
7094 r = queue_transaction(store, ch, std::move(t));
7095 ASSERT_EQ(r, 0);
7096 }
7097
7098 auto to_sleep = 5 *
7099 (int)g_conf().get_val<double>("bluestore_bluefs_balance_interval");
7100 std::cout<<"sleeping... " << std::endl;
7101 sleep(to_sleep);
7102
7103 {
7104 // touch another object to triggerrebalance
7105 ObjectStore::Transaction t;
7106 t.touch(cid, hoid1);
7107 r = queue_transaction(store, ch, std::move(t));
7108 ASSERT_EQ(r, 0);
7109 }
7110 {
7111 ObjectStore::Transaction t;
7112 t.remove(cid, hoid1);
7113 t.remove(cid, hoid2);
7114 t.remove_collection(cid);
7115 cerr << "Cleaning" << std::endl;
7116 r = queue_transaction(store, ch, std::move(t));
7117 ASSERT_EQ(r, 0);
7118 }
7119 }
7120
7121 #endif //#if defined(WITH_BLUESTORE)
7122
7123 TEST_P(StoreTest, KVDBHistogramTest) {
7124 if (string(GetParam()) != "bluestore")
7125 return;
7126
7127 int NUM_OBJS = 200;
7128 int r = 0;
7129 coll_t cid;
7130 string base("testobj.");
7131 bufferlist a;
7132 bufferptr ap(0x1000);
7133 memset(ap.c_str(), 'a', 0x1000);
7134 a.append(ap);
7135 auto ch = store->create_new_collection(cid);
7136 {
7137 ObjectStore::Transaction t;
7138 t.create_collection(cid, 0);
7139 r = queue_transaction(store, ch, std::move(t));
7140 ASSERT_EQ(r, 0);
7141 }
7142 for (int i = 0; i < NUM_OBJS; ++i) {
7143 ObjectStore::Transaction t;
7144 char buf[100];
7145 snprintf(buf, sizeof(buf), "%d", i);
7146 ghobject_t hoid(hobject_t(sobject_t(base + string(buf), CEPH_NOSNAP)));
7147 t.write(cid, hoid, 0, 0x1000, a);
7148 r = queue_transaction(store, ch, std::move(t));
7149 ASSERT_EQ(r, 0);
7150 }
7151
7152 Formatter *f = Formatter::create("store_test", "json-pretty", "json-pretty");
7153 store->generate_db_histogram(f);
7154 f->flush(cout);
7155 cout << std::endl;
7156 }
7157
7158 TEST_P(StoreTest, KVDBStatsTest) {
7159 if (string(GetParam()) != "bluestore")
7160 return;
7161
7162 SetVal(g_conf(), "rocksdb_perf", "true");
7163 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
7164 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
7165 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
7166 g_ceph_context->_conf.apply_changes(nullptr);
7167 int r = store->umount();
7168 ASSERT_EQ(r, 0);
7169 r = store->mount(); //to force rocksdb stats
7170 ASSERT_EQ(r, 0);
7171
7172 int NUM_OBJS = 200;
7173 coll_t cid;
7174 string base("testobj.");
7175 bufferlist a;
7176 bufferptr ap(0x1000);
7177 memset(ap.c_str(), 'a', 0x1000);
7178 a.append(ap);
7179 auto ch = store->create_new_collection(cid);
7180 {
7181 ObjectStore::Transaction t;
7182 t.create_collection(cid, 0);
7183 r = queue_transaction(store, ch, std::move(t));
7184 ASSERT_EQ(r, 0);
7185 }
7186 for (int i = 0; i < NUM_OBJS; ++i) {
7187 ObjectStore::Transaction t;
7188 char buf[100];
7189 snprintf(buf, sizeof(buf), "%d", i);
7190 ghobject_t hoid(hobject_t(sobject_t(base + string(buf), CEPH_NOSNAP)));
7191 t.write(cid, hoid, 0, 0x1000, a);
7192 r = queue_transaction(store, ch, std::move(t));
7193 ASSERT_EQ(r, 0);
7194 }
7195
7196 Formatter *f = Formatter::create("store_test", "json-pretty", "json-pretty");
7197 store->get_db_statistics(f);
7198 f->flush(cout);
7199 cout << std::endl;
7200 }
7201
7202 #if defined(WITH_BLUESTORE)
7203 TEST_P(StoreTestSpecificAUSize, garbageCollection) {
7204 int r;
7205 coll_t cid;
7206 int buf_len = 256 * 1024;
7207 int overlap_offset = 64 * 1024;
7208 int write_offset = buf_len;
7209 if (string(GetParam()) != "bluestore")
7210 return;
7211
7212 #define WRITE_AT(offset, _length) {\
7213 ObjectStore::Transaction t;\
7214 if ((uint64_t)_length != bl.length()) { \
7215 buffer::ptr p(bl.c_str(), _length);\
7216 bufferlist bl_tmp;\
7217 bl_tmp.push_back(p);\
7218 t.write(cid, hoid, offset, bl_tmp.length(), bl_tmp);\
7219 } else {\
7220 t.write(cid, hoid, offset, bl.length(), bl);\
7221 }\
7222 r = queue_transaction(store, ch, std::move(t));\
7223 ASSERT_EQ(r, 0);\
7224 }
7225
7226 StartDeferred(65536);
7227
7228 SetVal(g_conf(), "bluestore_compression_max_blob_size", "524288");
7229 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
7230 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
7231 SetVal(g_conf(), "bluestore_compression_mode", "force");
7232 g_conf().apply_changes(nullptr);
7233
7234 auto ch = store->create_new_collection(cid);
7235
7236 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
7237 {
7238 bufferlist in;
7239 r = store->read(ch, hoid, 0, 5, in);
7240 ASSERT_EQ(-ENOENT, r);
7241 }
7242 {
7243 ObjectStore::Transaction t;
7244 t.create_collection(cid, 0);
7245 cerr << "Creating collection " << cid << std::endl;
7246 r = queue_transaction(store, ch, std::move(t));
7247 ASSERT_EQ(r, 0);
7248 }
7249
7250 std::string data;
7251 data.resize(buf_len);
7252
7253 {
7254 {
7255 bool exists = store->exists(ch, hoid);
7256 ASSERT_TRUE(!exists);
7257
7258 ObjectStore::Transaction t;
7259 t.touch(cid, hoid);
7260 cerr << "Creating object " << hoid << std::endl;
7261 r = queue_transaction(store, ch, std::move(t));
7262 ASSERT_EQ(r, 0);
7263
7264 exists = store->exists(ch, hoid);
7265 ASSERT_EQ(true, exists);
7266 }
7267 bufferlist bl;
7268
7269 for(size_t i = 0; i < data.size(); i++)
7270 data[i] = i % 256;
7271
7272 bl.append(data);
7273
7274 {
7275 struct store_statfs_t statfs;
7276 WRITE_AT(0, buf_len);
7277 int r = store->statfs(&statfs);
7278 ASSERT_EQ(r, 0);
7279 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
7280 }
7281 {
7282 struct store_statfs_t statfs;
7283 WRITE_AT(write_offset - 2 * overlap_offset, buf_len);
7284 int r = store->statfs(&statfs);
7285 ASSERT_EQ(r, 0);
7286 ASSERT_EQ(statfs.data_compressed_allocated, 0x20000);
7287 const PerfCounters* counters = store->get_perf_counters();
7288 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0u);
7289 }
7290
7291 {
7292 struct store_statfs_t statfs;
7293 WRITE_AT(write_offset - overlap_offset, buf_len);
7294 int r = store->statfs(&statfs);
7295 ASSERT_EQ(r, 0);
7296 ASSERT_EQ(statfs.data_compressed_allocated, 0x20000);
7297 const PerfCounters* counters = store->get_perf_counters();
7298 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x10000u);
7299 }
7300 {
7301 struct store_statfs_t statfs;
7302 WRITE_AT(write_offset - 3 * overlap_offset, buf_len);
7303 int r = store->statfs(&statfs);
7304 ASSERT_EQ(r, 0);
7305 ASSERT_EQ(statfs.data_compressed_allocated, 0x20000);
7306 const PerfCounters* counters = store->get_perf_counters();
7307 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x20000u);
7308 }
7309 {
7310 struct store_statfs_t statfs;
7311 WRITE_AT(write_offset + 1, overlap_offset-1);
7312 int r = store->statfs(&statfs);
7313 ASSERT_EQ(r, 0);
7314 ASSERT_EQ(statfs.data_compressed_allocated, 0x20000);
7315 const PerfCounters* counters = store->get_perf_counters();
7316 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x20000u);
7317 }
7318 {
7319 struct store_statfs_t statfs;
7320 WRITE_AT(write_offset + 1, overlap_offset);
7321 int r = store->statfs(&statfs);
7322 ASSERT_EQ(r, 0);
7323 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
7324 const PerfCounters* counters = store->get_perf_counters();
7325 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x3ffffu);
7326 }
7327 {
7328 struct store_statfs_t statfs;
7329 WRITE_AT(0, buf_len-1);
7330 int r = store->statfs(&statfs);
7331 ASSERT_EQ(r, 0);
7332 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
7333 const PerfCounters* counters = store->get_perf_counters();
7334 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40001u);
7335 }
7336 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "1"); //forbid GC when saving = 0
7337 {
7338 struct store_statfs_t statfs;
7339 WRITE_AT(1, overlap_offset-2);
7340 WRITE_AT(overlap_offset * 2 + 1, overlap_offset-2);
7341 int r = store->statfs(&statfs);
7342 ASSERT_EQ(r, 0);
7343 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
7344 const PerfCounters* counters = store->get_perf_counters();
7345 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40001u);
7346 }
7347 {
7348 struct store_statfs_t statfs;
7349 WRITE_AT(overlap_offset + 1, overlap_offset-2);
7350 int r = store->statfs(&statfs);
7351 ASSERT_EQ(r, 0);
7352 ASSERT_EQ(statfs.data_compressed_allocated, 0x0);
7353 const PerfCounters* counters = store->get_perf_counters();
7354 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40007u);
7355 }
7356 {
7357 ObjectStore::Transaction t;
7358 t.remove(cid, hoid);
7359 cerr << "Cleaning" << std::endl;
7360 r = queue_transaction(store, ch, std::move(t));
7361 ASSERT_EQ(r, 0);
7362 }
7363 }
7364 }
7365
7366 TEST_P(StoreTestSpecificAUSize, fsckOnUnalignedDevice) {
7367 if (string(GetParam()) != "bluestore")
7368 return;
7369
7370 SetVal(g_conf(), "bluestore_block_size",
7371 stringify(0x280005000).c_str()); //10 Gb + 4K
7372 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7373 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7374 StartDeferred(0x4000);
7375 store->umount();
7376 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
7377 store->mount();
7378
7379 }
7380
7381 TEST_P(StoreTestSpecificAUSize, fsckOnUnalignedDevice2) {
7382 if (string(GetParam()) != "bluestore")
7383 return;
7384
7385 SetVal(g_conf(), "bluestore_block_size",
7386 stringify(0x280005000).c_str()); //10 Gb + 20K
7387 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7388 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7389 StartDeferred(0x1000);
7390 store->umount();
7391 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
7392 store->mount();
7393 }
7394
7395 namespace {
7396 ghobject_t make_object(const char* name, int64_t pool) {
7397 sobject_t soid{name, CEPH_NOSNAP};
7398 uint32_t hash = std::hash<sobject_t>{}(soid);
7399 return ghobject_t{hobject_t{soid, "", hash, pool, ""}};
7400 }
7401 }
7402
7403 TEST_P(StoreTestSpecificAUSize, BluestoreRepairTest) {
7404 if (string(GetParam()) != "bluestore")
7405 return;
7406 const size_t offs_base = 65536 / 2;
7407
7408 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7409 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7410 SetVal(g_conf(), "bluestore_max_blob_size",
7411 stringify(2 * offs_base).c_str());
7412 SetVal(g_conf(), "bluestore_extent_map_shard_max_size", "12000");
7413 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "false");
7414
7415 StartDeferred(0x10000);
7416
7417 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
7418
7419 // fill the store with some data
7420 const uint64_t pool = 555;
7421 coll_t cid(spg_t(pg_t(0, pool), shard_id_t::NO_SHARD));
7422 auto ch = store->create_new_collection(cid);
7423
7424 ghobject_t hoid = make_object("Object 1", pool);
7425 ghobject_t hoid_dup = make_object("Object 1(dup)", pool);
7426 ghobject_t hoid2 = make_object("Object 2", pool);
7427 ghobject_t hoid_cloned = hoid2;
7428 hoid_cloned.hobj.snap = 1;
7429 ghobject_t hoid3 = make_object("Object 3", pool);
7430 ghobject_t hoid3_cloned = hoid3;
7431 hoid3_cloned.hobj.snap = 1;
7432 bufferlist bl;
7433 bl.append("1234512345");
7434 int r;
7435 const size_t repeats = 16;
7436 {
7437 auto ch = store->create_new_collection(cid);
7438 cerr << "create collection + write" << std::endl;
7439 ObjectStore::Transaction t;
7440 t.create_collection(cid, 0);
7441 for( auto i = 0ul; i < repeats; ++i ) {
7442 t.write(cid, hoid, i * offs_base, bl.length(), bl);
7443 t.write(cid, hoid_dup, i * offs_base, bl.length(), bl);
7444 }
7445 for( auto i = 0ul; i < repeats; ++i ) {
7446 t.write(cid, hoid2, i * offs_base, bl.length(), bl);
7447 }
7448 t.clone(cid, hoid2, hoid_cloned);
7449
7450 r = queue_transaction(store, ch, std::move(t));
7451 ASSERT_EQ(r, 0);
7452 }
7453
7454 bstore->umount();
7455 //////////// leaked pextent fix ////////////
7456 cerr << "fix leaked pextents" << std::endl;
7457 ASSERT_EQ(bstore->fsck(false), 0);
7458 ASSERT_EQ(bstore->repair(false), 0);
7459 bstore->mount();
7460 bstore->inject_leaked(0x30000);
7461 bstore->umount();
7462 ASSERT_EQ(bstore->fsck(false), 1);
7463 ASSERT_EQ(bstore->repair(false), 0);
7464 ASSERT_EQ(bstore->fsck(false), 0);
7465
7466 //////////// false free fix ////////////
7467 cerr << "fix false free pextents" << std::endl;
7468 bstore->mount();
7469 bstore->inject_false_free(cid, hoid);
7470 bstore->umount();
7471 ASSERT_EQ(bstore->fsck(false), 2);
7472 ASSERT_EQ(bstore->repair(false), 0);
7473 ASSERT_EQ(bstore->fsck(false), 0);
7474
7475 //////////// verify invalid statfs ///////////
7476 cerr << "fix invalid statfs" << std::endl;
7477 store_statfs_t statfs0, statfs;
7478 bstore->mount();
7479 ASSERT_EQ(bstore->statfs(&statfs0), 0);
7480 statfs = statfs0;
7481 statfs.allocated += 0x10000;
7482 statfs.data_stored += 0x10000;
7483 ASSERT_FALSE(statfs0 == statfs);
7484 bstore->inject_statfs("bluestore_statfs", statfs);
7485 bstore->umount();
7486
7487 ASSERT_EQ(bstore->fsck(false), 2);
7488 ASSERT_EQ(bstore->repair(false), 0);
7489 ASSERT_EQ(bstore->fsck(false), 0);
7490 ASSERT_EQ(bstore->mount(), 0);
7491 ASSERT_EQ(bstore->statfs(&statfs), 0);
7492 // adjust free space to success in comparison
7493 statfs0.available = statfs.available;
7494 ASSERT_EQ(statfs0, statfs);
7495
7496 ///////// undecodable shared blob key / stray shared blob records ///////
7497 cerr << "undecodable shared blob key" << std::endl;
7498 bstore->inject_broken_shared_blob_key("undec1",
7499 bufferlist());
7500 bstore->inject_broken_shared_blob_key("undecodable key 2",
7501 bufferlist());
7502 bstore->inject_broken_shared_blob_key("undecodable key 3",
7503 bufferlist());
7504 bstore->umount();
7505 ASSERT_EQ(bstore->fsck(false), 3);
7506 ASSERT_EQ(bstore->repair(false), 0);
7507 ASSERT_EQ(bstore->fsck(false), 0);
7508
7509 cerr << "misreferencing" << std::endl;
7510 bstore->mount();
7511 bstore->inject_misreference(cid, hoid, cid, hoid_dup, 0);
7512 bstore->inject_misreference(cid, hoid, cid, hoid_dup, (offs_base * repeats) / 2);
7513 bstore->inject_misreference(cid, hoid, cid, hoid_dup, offs_base * (repeats -1) );
7514
7515 bstore->umount();
7516 ASSERT_EQ(bstore->fsck(false), 6);
7517 ASSERT_EQ(bstore->repair(false), 0);
7518
7519 ASSERT_EQ(bstore->fsck(true), 0);
7520
7521 // reproducing issues #21040 & 20983
7522 SetVal(g_conf(), "bluestore_debug_inject_bug21040", "true");
7523 g_ceph_context->_conf.apply_changes(nullptr);
7524 bstore->mount();
7525
7526 cerr << "repro bug #21040" << std::endl;
7527 {
7528 auto ch = store->open_collection(cid);
7529 {
7530 ObjectStore::Transaction t;
7531 bl.append("0123456789012345");
7532 t.write(cid, hoid3, offs_base, bl.length(), bl);
7533 bl.clear();
7534 bl.append('!');
7535 t.write(cid, hoid3, 0, bl.length(), bl);
7536
7537 r = queue_transaction(store, ch, std::move(t));
7538 ASSERT_EQ(r, 0);
7539 }
7540 {
7541 ObjectStore::Transaction t;
7542 t.clone(cid, hoid3, hoid3_cloned);
7543 r = queue_transaction(store, ch, std::move(t));
7544 ASSERT_EQ(r, 0);
7545 }
7546
7547 bstore->umount();
7548 ASSERT_EQ(bstore->fsck(false), 3);
7549 ASSERT_LE(bstore->repair(false), 0);
7550 ASSERT_EQ(bstore->fsck(false), 0);
7551 }
7552
7553 cerr << "Completing" << std::endl;
7554 bstore->mount();
7555
7556 }
7557
7558 TEST_P(StoreTest, BluestoreRepairGlobalStats)
7559 {
7560 if (string(GetParam()) != "bluestore")
7561 return;
7562 const size_t offs_base = 65536 / 2;
7563
7564 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
7565
7566 // start with global stats
7567 bstore->inject_global_statfs({});
7568 bstore->umount();
7569 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
7570 bstore->mount();
7571
7572 // fill the store with some data
7573 const uint64_t pool = 555;
7574 coll_t cid(spg_t(pg_t(0, pool), shard_id_t::NO_SHARD));
7575 auto ch = store->create_new_collection(cid);
7576
7577 ghobject_t hoid = make_object("Object 1", pool);
7578 ghobject_t hoid_dup = make_object("Object 1(dup)", pool);
7579 ghobject_t hoid2 = make_object("Object 2", pool);
7580 ghobject_t hoid_cloned = hoid2;
7581 hoid_cloned.hobj.snap = 1;
7582 ghobject_t hoid3 = make_object("Object 3", pool);
7583 ghobject_t hoid3_cloned = hoid3;
7584 hoid3_cloned.hobj.snap = 1;
7585 bufferlist bl;
7586 bl.append("1234512345");
7587 int r;
7588 const size_t repeats = 16;
7589 {
7590 auto ch = store->create_new_collection(cid);
7591 cerr << "create collection + write" << std::endl;
7592 ObjectStore::Transaction t;
7593 t.create_collection(cid, 0);
7594 for( auto i = 0ul; i < repeats; ++i ) {
7595 t.write(cid, hoid, i * offs_base, bl.length(), bl);
7596 t.write(cid, hoid_dup, i * offs_base, bl.length(), bl);
7597 }
7598 for( auto i = 0ul; i < repeats; ++i ) {
7599 t.write(cid, hoid2, i * offs_base, bl.length(), bl);
7600 }
7601 t.clone(cid, hoid2, hoid_cloned);
7602
7603 r = queue_transaction(store, ch, std::move(t));
7604 ASSERT_EQ(r, 0);
7605 }
7606
7607 bstore->umount();
7608
7609 // enable per-pool stats collection hence causing fsck to fail
7610 cerr << "per-pool statfs" << std::endl;
7611 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
7612 g_ceph_context->_conf.apply_changes(nullptr);
7613
7614 ASSERT_EQ(bstore->fsck(false), 1);
7615 ASSERT_EQ(bstore->repair(false), 0);
7616 ASSERT_EQ(bstore->fsck(false), 0);
7617
7618 bstore->mount();
7619 }
7620
7621 TEST_P(StoreTest, BluestoreRepairGlobalStatsFixOnMount)
7622 {
7623 if (string(GetParam()) != "bluestore")
7624 return;
7625 const size_t offs_base = 65536 / 2;
7626
7627 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
7628
7629 // start with global stats
7630 bstore->inject_global_statfs({});
7631 bstore->umount();
7632 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
7633 bstore->mount();
7634
7635 // fill the store with some data
7636 const uint64_t pool = 555;
7637 coll_t cid(spg_t(pg_t(0, pool), shard_id_t::NO_SHARD));
7638 auto ch = store->create_new_collection(cid);
7639
7640 ghobject_t hoid = make_object("Object 1", pool);
7641 ghobject_t hoid_dup = make_object("Object 1(dup)", pool);
7642 ghobject_t hoid2 = make_object("Object 2", pool);
7643 ghobject_t hoid_cloned = hoid2;
7644 hoid_cloned.hobj.snap = 1;
7645 ghobject_t hoid3 = make_object("Object 3", pool);
7646 ghobject_t hoid3_cloned = hoid3;
7647 hoid3_cloned.hobj.snap = 1;
7648 bufferlist bl;
7649 bl.append("1234512345");
7650 int r;
7651 const size_t repeats = 16;
7652 {
7653 auto ch = store->create_new_collection(cid);
7654 cerr << "create collection + write" << std::endl;
7655 ObjectStore::Transaction t;
7656 t.create_collection(cid, 0);
7657 for( auto i = 0ul; i < repeats; ++i ) {
7658 t.write(cid, hoid, i * offs_base, bl.length(), bl);
7659 t.write(cid, hoid_dup, i * offs_base, bl.length(), bl);
7660 }
7661 for( auto i = 0ul; i < repeats; ++i ) {
7662 t.write(cid, hoid2, i * offs_base, bl.length(), bl);
7663 }
7664 t.clone(cid, hoid2, hoid_cloned);
7665
7666 r = queue_transaction(store, ch, std::move(t));
7667 ASSERT_EQ(r, 0);
7668 }
7669
7670 bstore->umount();
7671
7672 // enable per-pool stats collection hence causing fsck to fail
7673 cerr << "per-pool statfs" << std::endl;
7674 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
7675 g_ceph_context->_conf.apply_changes(nullptr);
7676
7677 ASSERT_EQ(bstore->fsck(false), 1);
7678
7679 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
7680 bstore->mount();
7681 bstore->umount();
7682 ASSERT_EQ(bstore->fsck(false), 0);
7683
7684 bstore->mount();
7685 }
7686
7687 TEST_P(StoreTest, BluestoreStatistics) {
7688 if (string(GetParam()) != "bluestore")
7689 return;
7690
7691 SetVal(g_conf(), "rocksdb_perf", "true");
7692 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
7693 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
7694 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
7695
7696 // disable cache
7697 SetVal(g_conf(), "bluestore_cache_size_ssd", "0");
7698 SetVal(g_conf(), "bluestore_cache_size_hdd", "0");
7699 SetVal(g_conf(), "bluestore_cache_size", "0");
7700 g_ceph_context->_conf.apply_changes(nullptr);
7701
7702 int r = store->umount();
7703 ASSERT_EQ(r, 0);
7704 r = store->mount();
7705 ASSERT_EQ(r, 0);
7706
7707 BlueStore* bstore = NULL;
7708 EXPECT_NO_THROW(bstore = dynamic_cast<BlueStore*> (store.get()));
7709
7710 coll_t cid;
7711 ghobject_t hoid(hobject_t("test_db_statistics", "", CEPH_NOSNAP, 0, 0, ""));
7712 auto ch = bstore->create_new_collection(cid);
7713 bufferlist bl;
7714 bl.append("0123456789abcdefghi");
7715 {
7716 ObjectStore::Transaction t;
7717 t.create_collection(cid, 0);
7718 t.touch(cid, hoid);
7719 t.write(cid, hoid, 0, bl.length(), bl);
7720 cerr << "Write object" << std::endl;
7721 r = queue_transaction(bstore, ch, std::move(t));
7722 ASSERT_EQ(r, 0);
7723 }
7724 {
7725 bufferlist readback;
7726 r = store->read(ch, hoid, 0, bl.length(), readback);
7727 ASSERT_EQ(static_cast<int>(bl.length()), r);
7728 ASSERT_TRUE(bl_eq(bl, readback));
7729 }
7730 Formatter *f = Formatter::create("store_test", "json-pretty", "json-pretty");
7731 EXPECT_NO_THROW(store->get_db_statistics(f));
7732 f->flush(cout);
7733 cout << std::endl;
7734 }
7735
7736 TEST_P(StoreTest, BluestorePerPoolOmapFixOnMount)
7737 {
7738 if (string(GetParam()) != "bluestore")
7739 return;
7740
7741 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
7742 const uint64_t pool = 555;
7743 coll_t cid(spg_t(pg_t(0, pool), shard_id_t::NO_SHARD));
7744 ghobject_t oid = make_object("Object 1", pool);
7745 ghobject_t oid2 = make_object("Object 2", pool);
7746 // fill the store with some data
7747 auto ch = store->create_new_collection(cid);
7748 map<string, bufferlist> omap;
7749 bufferlist h;
7750 h.append("header");
7751 {
7752 omap["omap_key"].append("omap value");
7753 ObjectStore::Transaction t;
7754 t.create_collection(cid, 0);
7755 t.touch(cid, oid);
7756 t.omap_setheader(cid, oid, h);
7757 t.touch(cid, oid2);
7758 t.omap_setheader(cid, oid2, h);
7759 int r = queue_transaction(store, ch, std::move(t));
7760 ASSERT_EQ(r, 0);
7761 }
7762
7763 // inject legacy omaps
7764 bstore->inject_legacy_omap();
7765 bstore->inject_legacy_omap(cid, oid);
7766 bstore->inject_legacy_omap(cid, oid2);
7767
7768 bstore->umount();
7769
7770 // check we injected an issue
7771 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
7772 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
7773 g_ceph_context->_conf.apply_changes(nullptr);
7774 ASSERT_EQ(bstore->fsck(false), 3);
7775
7776 // set autofix and mount
7777 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
7778 g_ceph_context->_conf.apply_changes(nullptr);
7779 bstore->mount();
7780 bstore->umount();
7781
7782 // check we fixed it..
7783 ASSERT_EQ(bstore->fsck(false), 0);
7784 bstore->mount();
7785
7786 //
7787 // Now repro https://tracker.ceph.com/issues/43824
7788 //
7789 // inject legacy omaps again
7790 bstore->inject_legacy_omap();
7791 bstore->inject_legacy_omap(cid, oid);
7792 bstore->inject_legacy_omap(cid, oid2);
7793 bstore->umount();
7794
7795 // check we injected an issue
7796 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
7797 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
7798 g_ceph_context->_conf.apply_changes(nullptr);
7799 bstore->mount();
7800 ch = store->open_collection(cid);
7801
7802 {
7803 // write to onode which will partiall revert per-pool
7804 // omap repair done on mount due to #43824.
7805 // And object removal will leave stray per-pool omap recs
7806 //
7807 ObjectStore::Transaction t;
7808 bufferlist bl;
7809 bl.append("data");
7810 //this triggers onode rec update and hence legacy omap
7811 t.write(cid, oid, 0, bl.length(), bl);
7812 t.remove(cid, oid2); // this will trigger stray per-pool omap
7813 int r = queue_transaction(store, ch, std::move(t));
7814 ASSERT_EQ(r, 0);
7815 }
7816 bstore->umount();
7817 // check omap's been fixed.
7818 ASSERT_EQ(bstore->fsck(false), 0); // this will fail without fix for #43824
7819
7820 bstore->mount();
7821 }
7822
7823 TEST_P(StoreTestSpecificAUSize, BluestoreTinyDevFailure) {
7824 if (string(GetParam()) != "bluestore")
7825 return;
7826 // This caused superblock overwrite by bluefs, see
7827 // https://tracker.ceph.com/issues/24480
7828 SetVal(g_conf(), "bluestore_block_size",
7829 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7830 SetVal(g_conf(), "bluestore_block_db_size", "0");
7831 SetVal(g_conf(), "bluestore_block_db_create", "false");
7832 SetVal(g_conf(), "bluestore_bluefs_min",
7833 stringify(1024 * 1024 * 1024).c_str());
7834 StartDeferred(0x1000);
7835 store->umount();
7836 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
7837 store->mount();
7838 }
7839
7840 TEST_P(StoreTestSpecificAUSize, BluestoreTinyDevFailure2) {
7841 if (string(GetParam()) != "bluestore")
7842 return;
7843
7844 // This caused assert in allocator as initial bluefs extent as slow device
7845 // overlaped with superblock
7846 // https://tracker.ceph.com/issues/24480
7847 SetVal(g_conf(), "bluestore_block_size",
7848 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7849 SetVal(g_conf(), "bluestore_block_db_size",
7850 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7851 SetVal(g_conf(), "bluestore_block_db_create", "true");
7852 SetVal(g_conf(), "bluestore_bluefs_min",
7853 stringify(1024 * 1024 * 1024).c_str());
7854 StartDeferred(0x1000);
7855 store->umount();
7856 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
7857 store->mount();
7858 }
7859
7860 TEST_P(StoreTest, SpuriousReadErrorTest) {
7861 if (string(GetParam()) != "bluestore")
7862 return;
7863
7864 int r;
7865 auto logger = store->get_perf_counters();
7866 coll_t cid;
7867 auto ch = store->create_new_collection(cid);
7868 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
7869 {
7870 ObjectStore::Transaction t;
7871 t.create_collection(cid, 0);
7872 cerr << "Creating collection " << cid << std::endl;
7873 r = queue_transaction(store, ch, std::move(t));
7874 ASSERT_EQ(r, 0);
7875 }
7876 bufferlist test_data;
7877 bufferptr ap(0x2000);
7878 memset(ap.c_str(), 'a', 0x2000);
7879 test_data.append(ap);
7880 {
7881 ObjectStore::Transaction t;
7882 t.write(cid, hoid, 0, 0x2000, test_data);
7883 r = queue_transaction(store, ch, std::move(t));
7884 ASSERT_EQ(r, 0);
7885 // force cache clear
7886 EXPECT_EQ(store->umount(), 0);
7887 EXPECT_EQ(store->mount(), 0);
7888 }
7889
7890 cerr << "Injecting CRC error with no retry, expecting EIO" << std::endl;
7891 SetVal(g_conf(), "bluestore_retry_disk_reads", "0");
7892 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "1");
7893 g_ceph_context->_conf.apply_changes(nullptr);
7894 {
7895 bufferlist in;
7896 r = store->read(ch, hoid, 0, 0x2000, in, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
7897 ASSERT_EQ(-EIO, r);
7898 ASSERT_EQ(logger->get(l_bluestore_read_eio), 1u);
7899 ASSERT_EQ(logger->get(l_bluestore_reads_with_retries), 0u);
7900 }
7901
7902 cerr << "Injecting CRC error with retries, expecting success after several retries" << std::endl;
7903 SetVal(g_conf(), "bluestore_retry_disk_reads", "255");
7904 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "0.8");
7905 /**
7906 * Probabilistic test: 25 reads, each has a 80% chance of failing with 255 retries
7907 * Probability of at least one retried read: 1 - (0.2 ** 25) = 100% - 3e-18
7908 * Probability of a random test failure: 1 - ((1 - (0.8 ** 255)) ** 25) ~= 5e-24
7909 */
7910 g_ceph_context->_conf.apply_changes(nullptr);
7911 {
7912 for (int i = 0; i < 25; ++i) {
7913 bufferlist in;
7914 r = store->read(ch, hoid, 0, 0x2000, in, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
7915 ASSERT_EQ(0x2000, r);
7916 ASSERT_TRUE(bl_eq(test_data, in));
7917 }
7918 ASSERT_GE(logger->get(l_bluestore_reads_with_retries), 1u);
7919 }
7920 }
7921
7922 TEST_P(StoreTest, allocateBlueFSTest) {
7923 if (string(GetParam()) != "bluestore")
7924 return;
7925
7926 BlueStore* bstore = NULL;
7927 EXPECT_NO_THROW(bstore = dynamic_cast<BlueStore*> (store.get()));
7928
7929 struct store_statfs_t statfs;
7930 store->statfs(&statfs);
7931
7932 uint64_t to_alloc = g_conf().get_val<Option::size_t>("bluefs_alloc_size");
7933
7934 int r = bstore->allocate_bluefs_freespace(to_alloc, to_alloc, nullptr);
7935 ASSERT_EQ(r, 0);
7936 r = bstore->allocate_bluefs_freespace(statfs.total, statfs.total, nullptr);
7937 ASSERT_EQ(r, -ENOSPC);
7938 r = bstore->allocate_bluefs_freespace(to_alloc * 16, to_alloc * 16, nullptr);
7939 ASSERT_EQ(r, 0);
7940 store->umount();
7941 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
7942 r = store->mount();
7943 ASSERT_EQ(r, 0);
7944 }
7945
7946 TEST_P(StoreTest, mergeRegionTest) {
7947 if (string(GetParam()) != "bluestore")
7948 return;
7949
7950 SetVal(g_conf(), "bluestore_fsck_on_mount", "true");
7951 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
7952 SetVal(g_conf(), "bdev_debug_inflight_ios", "true");
7953 g_ceph_context->_conf.apply_changes(nullptr);
7954
7955 uint32_t chunk_size = g_ceph_context->_conf->bdev_block_size;
7956 int r = -1;
7957 coll_t cid;
7958 ghobject_t hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP)));
7959 auto ch = store->create_new_collection(cid);
7960 {
7961 ObjectStore::Transaction t;
7962 t.create_collection(cid, 0);
7963 r = queue_transaction(store, ch, std::move(t));
7964 ASSERT_EQ(r, 0);
7965 }
7966 {
7967 ObjectStore::Transaction t;
7968 t.touch(cid, hoid);
7969 cerr << "Creating object " << hoid << std::endl;
7970 r = queue_transaction(store, ch, std::move(t));
7971 ASSERT_EQ(r, 0);
7972 }
7973 bufferlist bl5;
7974 bl5.append("abcde");
7975 uint64_t offset = 0;
7976 { // 1. same region
7977 ObjectStore::Transaction t;
7978 t.write(cid, hoid, offset, 5, bl5);
7979 t.write(cid, hoid, 0xa + offset, 5, bl5);
7980 t.write(cid, hoid, 0x14 + offset, 5, bl5);
7981 r = queue_transaction(store, ch, std::move(t));
7982 ASSERT_EQ(r, 0);
7983 }
7984 { // 2. adjacent regions
7985 ObjectStore::Transaction t;
7986 offset = chunk_size;
7987 t.write(cid, hoid, offset, 5, bl5);
7988 t.write(cid, hoid, offset + chunk_size + 3, 5, bl5);
7989 r = queue_transaction(store, ch, std::move(t));
7990 ASSERT_EQ(r, 0);
7991 }
7992 { // 3. front merge
7993 ObjectStore::Transaction t;
7994 offset = chunk_size * 2;
7995 t.write(cid, hoid, offset, 5, bl5);
7996 t.write(cid, hoid, offset + chunk_size - 2, 5, bl5);
7997 r = queue_transaction(store, ch, std::move(t));
7998 ASSERT_EQ(r, 0);
7999 }
8000 { // 4. back merge
8001 ObjectStore::Transaction t;
8002 bufferlist blc2;
8003 blc2.append_zero(chunk_size + 2);
8004
8005 offset = chunk_size * 3;
8006 t.write(cid, hoid, offset, chunk_size + 2, blc2);
8007 t.write(cid, hoid, offset + chunk_size + 3, 5, bl5);
8008 r = queue_transaction(store, ch, std::move(t));
8009 ASSERT_EQ(r, 0);
8010 }
8011 { // 5. overlapping
8012 ObjectStore::Transaction t;
8013 uint64_t final_len = 0;
8014 offset = chunk_size * 10;
8015 bufferlist bl2c2;
8016 bl2c2.append_zero(chunk_size * 2);
8017 t.write(cid, hoid, offset + chunk_size * 3 - 3, chunk_size * 2, bl2c2);
8018 bl2c2.append_zero(2);
8019 t.write(cid, hoid, offset + chunk_size - 2, chunk_size * 2 + 2, bl2c2);
8020 r = queue_transaction(store, ch, std::move(t));
8021 ASSERT_EQ(r, 0);
8022
8023 final_len = (offset + chunk_size * 3 - 3) + (chunk_size * 2);
8024 bufferlist bl;
8025 r = store->read(ch, hoid, 0, final_len, bl);
8026 ASSERT_EQ(final_len, static_cast<uint64_t>(r));
8027 }
8028 }
8029
8030 TEST_P(StoreTestSpecificAUSize, BluestoreEnforceHWSettingsHdd) {
8031 if (string(GetParam()) != "bluestore")
8032 return;
8033
8034 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
8035 StartDeferred(0x1000);
8036
8037 int r;
8038 coll_t cid;
8039 ghobject_t hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP)));
8040 auto ch = store->create_new_collection(cid);
8041 {
8042 ObjectStore::Transaction t;
8043 t.create_collection(cid, 0);
8044 cerr << "Creating collection " << cid << std::endl;
8045 r = queue_transaction(store, ch, std::move(t));
8046 ASSERT_EQ(r, 0);
8047 }
8048 {
8049 ObjectStore::Transaction t;
8050 bufferlist bl, orig;
8051 string s(g_ceph_context->_conf->bluestore_max_blob_size_hdd, '0');
8052 bl.append(s);
8053 t.write(cid, hoid, 0, bl.length(), bl);
8054 cerr << "write" << std::endl;
8055 r = queue_transaction(store, ch, std::move(t));
8056 ASSERT_EQ(r, 0);
8057
8058 const PerfCounters* logger = store->get_perf_counters();
8059 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 1u);
8060 }
8061 }
8062
8063 TEST_P(StoreTestSpecificAUSize, BluestoreEnforceHWSettingsSsd) {
8064 if (string(GetParam()) != "bluestore")
8065 return;
8066
8067 SetVal(g_conf(), "bluestore_debug_enforce_settings", "ssd");
8068 StartDeferred(0x1000);
8069
8070 int r;
8071 coll_t cid;
8072 ghobject_t hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP)));
8073 auto ch = store->create_new_collection(cid);
8074 {
8075 ObjectStore::Transaction t;
8076 t.create_collection(cid, 0);
8077 cerr << "Creating collection " << cid << std::endl;
8078 r = queue_transaction(store, ch, std::move(t));
8079 ASSERT_EQ(r, 0);
8080 }
8081 {
8082 ObjectStore::Transaction t;
8083 bufferlist bl, orig;
8084 string s(g_ceph_context->_conf->bluestore_max_blob_size_ssd * 8, '0');
8085 bl.append(s);
8086 t.write(cid, hoid, 0, bl.length(), bl);
8087 cerr << "write" << std::endl;
8088 r = queue_transaction(store, ch, std::move(t));
8089 ASSERT_EQ(r, 0);
8090
8091 const PerfCounters* logger = store->get_perf_counters();
8092 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 8u);
8093 }
8094 }
8095
8096 TEST_P(StoreTestSpecificAUSize, ReproNoBlobMultiTest) {
8097
8098 if(string(GetParam()) != "bluestore")
8099 return;
8100
8101 SetVal(g_conf(), "bluestore_block_db_create", "true");
8102 SetVal(g_conf(), "bluestore_block_db_size", "4294967296");
8103 SetVal(g_conf(), "bluestore_block_size", "12884901888");
8104 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
8105
8106 g_conf().apply_changes(nullptr);
8107
8108 StartDeferred(65536);
8109
8110 int r;
8111 coll_t cid;
8112 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
8113 ghobject_t hoid2 = hoid;
8114 hoid2.hobj.snap = 1;
8115
8116 auto ch = store->create_new_collection(cid);
8117 {
8118 ObjectStore::Transaction t;
8119 t.create_collection(cid, 0);
8120 cerr << "Creating collection " << cid << std::endl;
8121 r = queue_transaction(store, ch, std::move(t));
8122 ASSERT_EQ(r, 0);
8123 }
8124 {
8125 bool exists = store->exists(ch, hoid);
8126 ASSERT_TRUE(!exists);
8127
8128 ObjectStore::Transaction t;
8129 t.touch(cid, hoid);
8130 cerr << "Creating object " << hoid << std::endl;
8131 r = queue_transaction(store, ch, std::move(t));
8132 ASSERT_EQ(r, 0);
8133
8134 exists = store->exists(ch, hoid);
8135 ASSERT_EQ(true, exists);
8136 }
8137 {
8138 uint64_t offs = 0;
8139 bufferlist bl;
8140 const int size = 0x100;
8141 bufferptr ap(size);
8142 memset(ap.c_str(), 'a', size);
8143 bl.append(ap);
8144 int i = 0;
8145 uint64_t blob_size = 524288;
8146 uint64_t total = 0;
8147 for (i = 0; i <= 512; i++) {
8148 offs = 0 + i * size;
8149 ObjectStore::Transaction t;
8150 ghobject_t hoid2 = hoid;
8151 hoid2.hobj.snap = i + 1;
8152 while (offs < 128 * 1024 * 1024) {
8153
8154 t.write(cid, hoid, offs, ap.length(), bl);
8155 offs += blob_size;
8156 total += ap.length();
8157 }
8158 t.clone(cid, hoid, hoid2);
8159 r = queue_transaction(store, ch, std::move(t));
8160 ASSERT_EQ(r, 0);
8161 }
8162 cerr << "Total written = " << total << std::endl;
8163 }
8164 {
8165 cerr << "Finalizing" << std::endl;
8166 const PerfCounters* logger = store->get_perf_counters();
8167 ASSERT_GE(logger->get(l_bluestore_gc_merged), 1024*1024*1024);
8168 }
8169 }
8170
8171 void doManySetAttr(ObjectStore* store,
8172 std::function<void(ObjectStore*)> do_check_fn)
8173 {
8174 MixedGenerator gen(447);
8175 gen_type rng(time(NULL));
8176 coll_t cid(spg_t(pg_t(0, 447), shard_id_t::NO_SHARD));
8177
8178 SyntheticWorkloadState test_obj(store, &gen, &rng, cid, 40 * 1024, 4 * 1024, 0);
8179 test_obj.init();
8180 for (int i = 0; i < 1500; ++i) {
8181 if (!(i % 10)) cerr << "seeding object " << i << std::endl;
8182 test_obj.touch();
8183 }
8184 for (int i = 0; i < 10000; ++i) {
8185 if (!(i % 100)) {
8186 cerr << "Op " << i << std::endl;
8187 test_obj.print_internal_state();
8188 }
8189 boost::uniform_int<> true_false(0, 99);
8190 test_obj.setattrs();
8191 }
8192 test_obj.wait_for_done();
8193
8194 AdminSocket* admin_socket = g_ceph_context->get_admin_socket();
8195 ceph_assert(admin_socket);
8196
8197 ceph::bufferlist in, out;
8198 ostringstream err;
8199
8200 bool b = admin_socket->execute_command(
8201 { "{\"prefix\": \"bluestore bluefs stats\"}" },
8202 in, err, &out);
8203 if (!b) {
8204 cerr << "failure querying " << std::endl;
8205 }
8206 std::cout << std::string(out.c_str(), out.length()) << std::endl;
8207 do_check_fn(store);
8208 test_obj.shutdown();
8209 }
8210
8211 TEST_P(StoreTestSpecificAUSize, SpilloverTest) {
8212 if (string(GetParam()) != "bluestore")
8213 return;
8214
8215 SetVal(g_conf(), "bluestore_block_db_create", "true");
8216 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
8217 SetVal(g_conf(), "bluestore_volume_selection_policy", "rocksdb_original");
8218
8219 g_conf().apply_changes(nullptr);
8220
8221 StartDeferred(65536);
8222 doManySetAttr(store.get(),
8223 [&](ObjectStore* _store) {
8224
8225 BlueStore* bstore = dynamic_cast<BlueStore*> (_store);
8226 ceph_assert(bstore);
8227 const PerfCounters* logger = bstore->get_bluefs_perf_counters();
8228 //experimentally it was discovered that this case results in 400+MB spillover
8229 //using lower 300MB threshold just to be safe enough
8230 ASSERT_GE(logger->get(l_bluefs_slow_used_bytes), 300 * 1024 * 1024);
8231
8232 }
8233 );
8234 }
8235
8236 TEST_P(StoreTestSpecificAUSize, SpilloverFixedTest) {
8237 if (string(GetParam()) != "bluestore")
8238 return;
8239
8240 SetVal(g_conf(), "bluestore_block_db_create", "true");
8241 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
8242 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
8243 SetVal(g_conf(), "bluestore_volume_selection_reserved", "1"); // just use non-zero to enable
8244
8245 g_conf().apply_changes(nullptr);
8246
8247 StartDeferred(65536);
8248 doManySetAttr(store.get(),
8249 [&](ObjectStore* _store) {
8250
8251 BlueStore* bstore = dynamic_cast<BlueStore*> (_store);
8252 ceph_assert(bstore);
8253 const PerfCounters* logger = bstore->get_bluefs_perf_counters();
8254 ASSERT_EQ(0, logger->get(l_bluefs_slow_used_bytes));
8255 }
8256 );
8257 }
8258
8259 TEST_P(StoreTestSpecificAUSize, SpilloverFixed2Test) {
8260 if (string(GetParam()) != "bluestore")
8261 return;
8262
8263 SetVal(g_conf(), "bluestore_block_db_create", "true");
8264 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
8265 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
8266 //default 2.0 factor results in too high threshold, using less value
8267 // that results in less but still present spillover.
8268 SetVal(g_conf(), "bluestore_volume_selection_reserved_factor", "0.5");
8269
8270 g_conf().apply_changes(nullptr);
8271
8272 StartDeferred(65536);
8273 doManySetAttr(store.get(),
8274 [&](ObjectStore* _store) {
8275
8276 BlueStore* bstore = dynamic_cast<BlueStore*> (_store);
8277 ceph_assert(bstore);
8278 const PerfCounters* logger = bstore->get_bluefs_perf_counters();
8279 ASSERT_LE(logger->get(l_bluefs_slow_used_bytes), 300 * 1024 * 1024); // see SpilloverTest for 300MB choice rationale
8280 }
8281 );
8282 }
8283
8284 #endif // WITH_BLUESTORE
8285
8286 int main(int argc, char **argv) {
8287 vector<const char*> args;
8288 argv_to_vec(argc, (const char **)argv, args);
8289
8290 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
8291 CODE_ENVIRONMENT_UTILITY,
8292 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
8293 common_init_finish(g_ceph_context);
8294
8295 // make sure we can adjust any config settings
8296 g_ceph_context->_conf._clear_safe_to_start_threads();
8297
8298 g_ceph_context->_conf.set_val_or_die("osd_journal_size", "400");
8299 g_ceph_context->_conf.set_val_or_die("filestore_index_retry_probability", "0.5");
8300 g_ceph_context->_conf.set_val_or_die("filestore_op_thread_timeout", "1000");
8301 g_ceph_context->_conf.set_val_or_die("filestore_op_thread_suicide_timeout", "10000");
8302 //g_ceph_context->_conf.set_val_or_die("filestore_fiemap", "true");
8303 g_ceph_context->_conf.set_val_or_die("bluestore_fsck_on_mkfs", "false");
8304 g_ceph_context->_conf.set_val_or_die("bluestore_fsck_on_mount", "false");
8305 g_ceph_context->_conf.set_val_or_die("bluestore_fsck_on_umount", "false");
8306 g_ceph_context->_conf.set_val_or_die("bluestore_debug_misc", "true");
8307 g_ceph_context->_conf.set_val_or_die("bluestore_debug_small_allocations", "4");
8308 g_ceph_context->_conf.set_val_or_die("bluestore_debug_freelist", "true");
8309 g_ceph_context->_conf.set_val_or_die("bluestore_clone_cow", "true");
8310 g_ceph_context->_conf.set_val_or_die("bluestore_max_alloc_size", "196608");
8311
8312 // set small cache sizes so we see trimming during Synthetic tests
8313 g_ceph_context->_conf.set_val_or_die("bluestore_cache_size_hdd", "4000000");
8314 g_ceph_context->_conf.set_val_or_die("bluestore_cache_size_ssd", "4000000");
8315
8316 // very short *_max prealloc so that we fall back to async submits
8317 g_ceph_context->_conf.set_val_or_die("bluestore_blobid_prealloc", "10");
8318 g_ceph_context->_conf.set_val_or_die("bluestore_nid_prealloc", "10");
8319 g_ceph_context->_conf.set_val_or_die("bluestore_debug_randomize_serial_transaction",
8320 "10");
8321
8322 g_ceph_context->_conf.set_val_or_die("bdev_debug_aio", "true");
8323
8324 // specify device size
8325 g_ceph_context->_conf.set_val_or_die("bluestore_block_size",
8326 stringify(DEF_STORE_TEST_BLOCKDEV_SIZE));
8327
8328 g_ceph_context->_conf.set_val_or_die(
8329 "enable_experimental_unrecoverable_data_corrupting_features", "*");
8330 g_ceph_context->_conf.apply_changes(nullptr);
8331
8332 ::testing::InitGoogleTest(&argc, argv);
8333 return RUN_ALL_TESTS();
8334 }
8335
8336 /*
8337 * Local Variables:
8338 * compile-command: "cd ../.. ; make ceph_test_objectstore &&
8339 * ./ceph_test_objectstore \
8340 * --gtest_filter=*.collect_metadata* --log-to-stderr=true --debug-filestore=20
8341 * "
8342 * End:
8343 */