1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
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>
27 #include "os/ObjectStore.h"
28 #include "os/filestore/FileStore.h"
29 #if defined(WITH_BLUESTORE)
30 #include "os/bluestore/BlueStore.h"
32 #include "include/Context.h"
33 #include "common/ceph_argparse.h"
34 #include "global/global_init.h"
35 #include "common/Mutex.h"
36 #include "common/Cond.h"
37 #include "common/errno.h"
38 #include "include/stringify.h"
39 #include "include/coredumpctl.h"
41 #include "include/unordered_map.h"
42 #include "store_test_fixture.h"
44 using namespace std::placeholders
;
46 typedef boost::mt11213b gen_type
;
48 const uint64_t DEF_STORE_TEST_BLOCKDEV_SIZE
= 10240000000;
49 #define dout_context g_ceph_context
51 #if GTEST_HAS_PARAM_TEST
53 static bool bl_eq(bufferlist
& expected
, bufferlist
& actual
)
55 if (expected
.contents_equal(actual
))
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
;
67 auto len
= std::min(expected
.length(), actual
.length());
68 while ( first
<len
&& expected
[first
] == actual
[first
])
71 while (last
> 0 && expected
[last
-1] == actual
[last
-1])
74 cout
<< "--- buffer mismatch between offset 0x" << std::hex
<< first
75 << " and 0x" << last
<< ", total 0x" << len
<< std::dec
77 derr
<< "--- buffer mismatch between offset 0x" << std::hex
<< first
78 << " and 0x" << last
<< ", total 0x" << len
<< std::dec
80 cout
<< "--- expected:\n";
81 expected
.hexdump(cout
);
82 cout
<< "--- actual:\n";
91 int queue_transaction(
93 ObjectStore::CollectionHandle ch
,
94 ObjectStore::Transaction
&&t
) {
96 ObjectStore::Transaction t2
;
98 return store
->queue_transaction(ch
, std::move(t2
));
100 return store
->queue_transaction(ch
, std::move(t
));
105 bool sorted(const vector
<ghobject_t
> &in
) {
107 for (vector
<ghobject_t
>::const_iterator i
= in
.begin();
111 cout
<< start
<< " should follow " << *i
<< std::endl
;
119 class StoreTest
: public StoreTestFixture
,
120 public ::testing::WithParamInterface
<const char*> {
123 : StoreTestFixture(GetParam())
125 void doCompressionTest();
126 void doSyntheticTest(
128 uint64_t max_obj
, uint64_t max_wr
, uint64_t align
);
131 class StoreTestDeferredSetup
: public StoreTest
{
132 void SetUp() override
{
137 void DeferredSetup() {
144 class StoreTestSpecificAUSize
: public StoreTestDeferredSetup
{
152 uint64_t align
)> MatrixTest
;
154 void StartDeferred(size_t min_alloc_size
) {
155 SetVal(g_conf(), "bluestore_min_alloc_size", stringify(min_alloc_size
).c_str());
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;
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
);
178 g_conf().get_val(k
, &buf
, -1);
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") {
190 } else if (string(k
) == "alignment") {
191 alignment
= atoll(v
);
192 } else if (string(k
) == "num_ops") {
195 SetVal(g_conf(), k
, v
);
199 void do_matrix_choose(const char *matrix
[][10],
200 int i
, int pos
, int num
,
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
,
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])
220 g_ceph_context
->_conf
.apply_changes(nullptr);
221 fn(num_ops
, max_size
, max_write
, alignment
);
225 void do_matrix(const char *matrix
[][10],
228 if (strcmp(matrix
[0][0], "bluestore_min_alloc_size") == 0) {
230 for (count
= 0; matrix
[0][count
+1]; ++count
) ;
231 for (size_t j
= 1; matrix
[0][j
]; ++j
) {
235 StartDeferred(strtoll(matrix
[0][j
], NULL
, 10));
236 do_matrix_choose(matrix
, 1, j
- 1, count
, fn
);
240 do_matrix_choose(matrix
, 0, 0, 1, fn
);
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);
257 TEST_P(StoreTest
, Trivial
) {
260 TEST_P(StoreTest
, TrivialRemount
) {
261 int r
= store
->umount();
267 TEST_P(StoreTest
, SimpleRemount
) {
269 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
270 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
272 bl
.append("1234512345");
274 auto ch
= store
->create_new_collection(cid
);
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
));
288 ch
= store
->open_collection(cid
);
290 ObjectStore::Transaction t
;
291 t
.write(cid
, hoid2
, 0, bl
.length(), bl
);
292 r
= queue_transaction(store
, ch
, std::move(t
));
296 ObjectStore::Transaction t
;
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
));
309 ch
= store
->create_new_collection(cid
);
311 ObjectStore::Transaction t
;
312 t
.create_collection(cid
, 0);
313 r
= queue_transaction(store
, ch
, std::move(t
));
315 bool exists
= store
->exists(ch
, hoid
);
316 ASSERT_TRUE(!exists
);
319 ObjectStore::Transaction t
;
320 t
.remove_collection(cid
);
321 cerr
<< "remove collection" << std::endl
;
322 r
= queue_transaction(store
, ch
, std::move(t
));
327 TEST_P(StoreTest
, IORemount
) {
330 bl
.append("1234512345");
332 auto ch
= store
->create_new_collection(cid
);
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
);
341 r
= queue_transaction(store
, ch
, std::move(t
));
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
));
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
)));
366 t
.remove_collection(cid
);
367 auto ch
= store
->open_collection(cid
);
368 r
= queue_transaction(store
, ch
, std::move(t
));
373 TEST_P(StoreTest
, UnprintableCharsName
) {
375 string name
= "funnychars_";
376 for (unsigned i
= 0; i
< 256; ++i
) {
379 ghobject_t
oid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)));
381 auto ch
= store
->create_new_collection(cid
);
383 cerr
<< "create collection + object" << std::endl
;
384 ObjectStore::Transaction t
;
385 t
.create_collection(cid
, 0);
387 r
= queue_transaction(store
, ch
, std::move(t
));
396 cout
<< "removing" << std::endl
;
397 ObjectStore::Transaction t
;
399 t
.remove_collection(cid
);
400 auto ch
= store
->open_collection(cid
);
401 r
= queue_transaction(store
, ch
, std::move(t
));
406 TEST_P(StoreTest
, FiemapEmpty
) {
409 ghobject_t
oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP
)));
410 auto ch
= store
->create_new_collection(cid
);
412 ObjectStore::Transaction t
;
413 t
.create_collection(cid
, 0);
415 t
.truncate(cid
, oid
, 100000);
416 r
= queue_transaction(store
, ch
, std::move(t
));
421 store
->fiemap(ch
, oid
, 0, 100000, bl
);
422 map
<uint64_t,uint64_t> m
, e
;
423 auto p
= bl
.cbegin();
425 cout
<< " got " << m
<< std::endl
;
427 EXPECT_TRUE(m
== e
|| m
.empty());
430 ObjectStore::Transaction t
;
432 t
.remove_collection(cid
);
433 cerr
<< "remove collection" << std::endl
;
434 r
= queue_transaction(store
, ch
, std::move(t
));
439 TEST_P(StoreTest
, FiemapHoles
) {
440 const uint64_t MAX_EXTENTS
= 4000;
441 const uint64_t SKIP_STEP
= 65536;
444 ghobject_t
oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP
)));
447 auto ch
= store
->create_new_collection(cid
);
449 ObjectStore::Transaction t
;
450 t
.create_collection(cid
, 0);
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
));
458 //fiemap test from 0 to SKIP_STEP * (MAX_EXTENTS - 1) + 3
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();
464 cout
<< " got " << m
<< std::endl
;
465 ASSERT_TRUE(!m
.empty());
467 auto last
= m
.crbegin();
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
));
475 ASSERT_GT(last
->first
+ last
->second
, SKIP_STEP
* (MAX_EXTENTS
- 1));
478 // fiemap test from SKIP_STEP to SKIP_STEP * (MAX_EXTENTS - 2) + 3
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();
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();
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
));
498 ASSERT_GT(last
->first
+ last
->second
, SKIP_STEP
* (MAX_EXTENTS
- 1));
502 ObjectStore::Transaction t
;
504 t
.remove_collection(cid
);
505 cerr
<< "remove collection" << std::endl
;
506 r
= queue_transaction(store
, ch
, std::move(t
));
511 TEST_P(StoreTest
, SimpleMetaColTest
) {
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
));
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
));
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
));
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
));
548 TEST_P(StoreTest
, SimplePGColTest
) {
549 coll_t
cid(spg_t(pg_t(1,2), shard_id_t::NO_SHARD
));
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
));
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
));
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
));
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
));
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());
595 uint32_t pg_num
= 128;
597 boost::uniform_int
<> pg_id_range(0, pg_num
);
598 gen_type
rng(time(NULL
));
599 int pg_id
= pg_id_range(rng
);
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
);
605 coll_t
cid(spg_t(pg_t(pg_id
, 15), shard_id_t::NO_SHARD
));
607 auto ch
= store
->create_new_collection(cid
);
609 // Create a collection along with a hint
610 ObjectStore::Transaction t
;
611 t
.create_collection(cid
, 5);
612 cerr
<< "create collection" << std::endl
;
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
));
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
));
631 TEST_P(StoreTest
, SmallBlockWrites
) {
634 auto ch
= store
->create_new_collection(cid
);
635 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
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
));
644 bufferptr
ap(0x1000);
645 memset(ap
.c_str(), 'a', 0x1000);
648 bufferptr
bp(0x1000);
649 memset(bp
.c_str(), 'b', 0x1000);
652 bufferptr
cp(0x1000);
653 memset(cp
.c_str(), 'c', 0x1000);
655 bufferptr
zp(0x1000);
660 ObjectStore::Transaction t
;
661 t
.write(cid
, hoid
, 0, 0x1000, a
);
662 r
= queue_transaction(store
, ch
, std::move(t
));
666 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
667 ASSERT_EQ(0x1000, r
);
669 ASSERT_TRUE(bl_eq(exp
, in
));
672 ObjectStore::Transaction t
;
673 t
.write(cid
, hoid
, 0x1000, 0x1000, b
);
674 r
= queue_transaction(store
, ch
, std::move(t
));
678 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
679 ASSERT_EQ(0x2000, r
);
682 ASSERT_TRUE(bl_eq(exp
, in
));
685 ObjectStore::Transaction t
;
686 t
.write(cid
, hoid
, 0x3000, 0x1000, c
);
687 r
= queue_transaction(store
, ch
, std::move(t
));
691 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
692 ASSERT_EQ(0x4000, r
);
697 ASSERT_TRUE(bl_eq(exp
, in
));
700 ObjectStore::Transaction t
;
701 t
.write(cid
, hoid
, 0x2000, 0x1000, a
);
702 r
= queue_transaction(store
, ch
, std::move(t
));
706 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
707 ASSERT_EQ(0x4000, r
);
712 ASSERT_TRUE(bl_eq(exp
, in
));
715 ObjectStore::Transaction t
;
716 t
.write(cid
, hoid
, 0, 0x1000, c
);
717 r
= queue_transaction(store
, ch
, std::move(t
));
722 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
723 ASSERT_EQ(0x4000, r
);
728 ASSERT_TRUE(bl_eq(exp
, in
));
731 ObjectStore::Transaction t
;
733 t
.remove_collection(cid
);
734 cerr
<< "Cleaning" << std::endl
;
735 r
= queue_transaction(store
, ch
, std::move(t
));
740 TEST_P(StoreTest
, BufferCacheReadTest
) {
743 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
745 auto ch
= store
->open_collection(cid
);
748 auto ch
= store
->create_new_collection(cid
);
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
));
757 bool exists
= store
->exists(ch
, hoid
);
758 ASSERT_TRUE(!exists
);
760 ObjectStore::Transaction t
;
762 cerr
<< "Creating object " << hoid
<< std::endl
;
763 r
= queue_transaction(store
, ch
, std::move(t
));
766 exists
= store
->exists(ch
, hoid
);
767 ASSERT_EQ(true, exists
);
770 ObjectStore::Transaction t
;
771 bufferlist bl
, newdata
;
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
));
779 r
= store
->read(ch
, hoid
, 0, 15, newdata
);
784 expected
.append_zero(5);
786 ASSERT_TRUE(bl_eq(expected
, newdata
));
789 //overwrite over the same extents
791 ObjectStore::Transaction t
;
792 bufferlist bl
, newdata
;
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
));
800 r
= store
->read(ch
, hoid
, 0, 15, newdata
);
805 expected
.append_zero(5);
807 ASSERT_TRUE(bl_eq(expected
, newdata
));
810 //additional write to an unused region of some blob
812 ObjectStore::Transaction t
;
813 bufferlist bl2
, newdata
;
814 bl2
.append("1234567890");
816 t
.write(cid
, hoid
, 20, bl2
.length(), bl2
);
817 cerr
<< "Append" << std::endl
;
818 r
= queue_transaction(store
, ch
, std::move(t
));
821 r
= store
->read(ch
, hoid
, 0, 30, newdata
);
825 expected
.append("edcba");
826 expected
.append_zero(5);
827 expected
.append("edcba");
828 expected
.append_zero(5);
829 expected
.append(bl2
);
831 ASSERT_TRUE(bl_eq(expected
, newdata
));
834 //additional write to an unused region of some blob and partial owerite over existing extents
836 ObjectStore::Transaction t
;
837 bufferlist bl
, bl2
, bl3
, newdata
;
839 bl2
.append("1234567890");
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
));
849 r
= store
->read(ch
, hoid
, 0, 40, newdata
);
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
);
860 ASSERT_TRUE(bl_eq(expected
, newdata
));
865 void StoreTest::doCompressionTest()
869 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
871 auto ch
= store
->open_collection(cid
);
874 auto ch
= store
->create_new_collection(cid
);
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
));
883 bool exists
= store
->exists(ch
, hoid
);
884 ASSERT_TRUE(!exists
);
886 ObjectStore::Transaction t
;
888 cerr
<< "Creating object " << hoid
<< std::endl
;
889 r
= queue_transaction(store
, ch
, std::move(t
));
892 exists
= store
->exists(ch
, hoid
);
893 ASSERT_EQ(true, exists
);
896 data
.resize(0x10000 * 4);
897 for(size_t i
= 0;i
< data
.size(); i
++)
900 ObjectStore::Transaction t
;
901 bufferlist bl
, newdata
;
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
));
908 r
= store
->read(ch
, hoid
, 0, data
.size() , newdata
);
910 ASSERT_EQ(r
, (int)data
.size());
913 expected
.append(data
);
914 ASSERT_TRUE(bl_eq(expected
, newdata
));
917 r
= store
->read(ch
, hoid
, 0, 711 , newdata
);
921 expected
.append(data
.substr(0,711));
922 ASSERT_TRUE(bl_eq(expected
, newdata
));
925 r
= store
->read(ch
, hoid
, 0xf00f, data
.size(), newdata
);
926 ASSERT_EQ(r
, int(data
.size() - 0xf00f) );
929 expected
.append(data
.substr(0xf00f));
930 ASSERT_TRUE(bl_eq(expected
, newdata
));
933 struct store_statfs_t statfs
;
934 int r
= store
->statfs(&statfs
);
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());
943 data2
.resize(0x10000 * 4 - 0x9000);
944 for(size_t i
= 0;i
< data2
.size(); i
++)
945 data2
[i
] = (i
+1) / 256;
947 ObjectStore::Transaction t
;
948 bufferlist bl
, newdata
;
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
));
955 r
= store
->read(ch
, hoid
, 0, 0x10000, newdata
);
956 ASSERT_EQ(r
, (int)0x10000);
959 expected
.append(data
.substr(0, 0x8000));
960 expected
.append(data2
.substr(0, 0x8000));
961 ASSERT_TRUE(bl_eq(expected
, newdata
));
964 r
= store
->read(ch
, hoid
, 0x9000, 711 , newdata
);
968 expected
.append(data2
.substr(0x1000,711));
969 ASSERT_TRUE(bl_eq(expected
, newdata
));
972 r
= store
->read(ch
, hoid
, 0x0, 0x40000, newdata
);
973 ASSERT_EQ(r
, int(0x40000) );
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
));
982 data2
.resize(0x3f000);
983 for(size_t i
= 0;i
< data2
.size(); i
++)
984 data2
[i
] = (i
+2) / 256;
986 ObjectStore::Transaction t
;
987 bufferlist bl
, newdata
;
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
));
994 r
= store
->read(ch
, hoid
, 0, 0x3e000 - 1, newdata
);
995 ASSERT_EQ(r
, (int)0x3e000 - 1);
998 expected
.append(data2
.substr(0, 0x3e000 - 1));
999 ASSERT_TRUE(bl_eq(expected
, newdata
));
1002 r
= store
->read(ch
, hoid
, 0x3e000-1, 0x2001, newdata
);
1003 ASSERT_EQ(r
, 0x2001);
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
));
1011 r
= store
->read(ch
, hoid
, 0x0, 0x40000, newdata
);
1012 ASSERT_EQ(r
, int(0x40000) );
1014 bufferlist expected
;
1015 expected
.append(data2
.substr(0, 0x3f000));
1016 expected
.append(data
.substr(0x3f000, 0x1000));
1017 ASSERT_TRUE(bl_eq(expected
, newdata
));
1020 data
.resize(0x1001);
1021 for(size_t i
= 0;i
< data
.size(); i
++)
1022 data
[i
] = (i
+3) / 256;
1024 ObjectStore::Transaction t
;
1025 bufferlist bl
, newdata
;
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
));
1032 r
= store
->read(ch
, hoid
, 0x3e000, 0x2000, newdata
);
1033 ASSERT_EQ(r
, (int)0x2000);
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
));
1042 ObjectStore::Transaction t
;
1043 t
.remove(cid
, hoid
);
1044 cerr
<< "Cleaning object" << std::endl
;
1045 r
= queue_transaction(store
, ch
, std::move(t
));
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);
1058 data
.resize(0x10000*6);
1060 for(size_t i
= 0;i
< data
.size(); i
++)
1062 ObjectStore::Transaction t
;
1063 bufferlist bl
, newdata
;
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
));
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
);
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
));
1086 TEST_P(StoreTest
, CompressionTest
) {
1087 if (string(GetParam()) != "bluestore")
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();
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();
1101 TEST_P(StoreTest
, SimpleObjectTest
) {
1104 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1106 auto ch
= store
->open_collection(cid
);
1109 auto ch
= store
->create_new_collection(cid
);
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
));
1118 bool exists
= store
->exists(ch
, hoid
);
1119 ASSERT_TRUE(!exists
);
1121 ObjectStore::Transaction t
;
1123 cerr
<< "Creating object " << hoid
<< std::endl
;
1124 r
= queue_transaction(store
, ch
, std::move(t
));
1127 exists
= store
->exists(ch
, hoid
);
1128 ASSERT_EQ(true, exists
);
1131 ObjectStore::Transaction t
;
1132 t
.remove(cid
, hoid
);
1134 cerr
<< "Remove then create" << std::endl
;
1135 r
= queue_transaction(store
, ch
, std::move(t
));
1139 ObjectStore::Transaction t
;
1140 bufferlist bl
, orig
;
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
));
1150 r
= store
->read(ch
, hoid
, 0, 5, in
);
1152 ASSERT_TRUE(bl_eq(orig
, in
));
1155 ObjectStore::Transaction t
;
1160 t
.write(cid
, hoid
, 5, 5, bl
);
1161 cerr
<< "Append" << std::endl
;
1162 r
= queue_transaction(store
, ch
, std::move(t
));
1166 r
= store
->read(ch
, hoid
, 0, 10, in
);
1168 ASSERT_TRUE(bl_eq(exp
, in
));
1171 ObjectStore::Transaction t
;
1173 bl
.append("abcdeabcde");
1175 t
.write(cid
, hoid
, 0, 10, bl
);
1176 cerr
<< "Full overwrite" << std::endl
;
1177 r
= queue_transaction(store
, ch
, std::move(t
));
1181 r
= store
->read(ch
, hoid
, 0, 10, in
);
1183 ASSERT_TRUE(bl_eq(exp
, in
));
1186 ObjectStore::Transaction t
;
1189 t
.write(cid
, hoid
, 3, 5, bl
);
1190 cerr
<< "Partial overwrite" << std::endl
;
1191 r
= queue_transaction(store
, ch
, std::move(t
));
1195 exp
.append("abcabcdede");
1196 r
= store
->read(ch
, hoid
, 0, 10, in
);
1199 ASSERT_TRUE(bl_eq(exp
, in
));
1203 ObjectStore::Transaction t
;
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
));
1213 ObjectStore::Transaction t
;
1216 t
.write(cid
, hoid
, 0, 5, bl
);
1217 cerr
<< "Reverse fill-in" << std::endl
;
1218 r
= queue_transaction(store
, ch
, std::move(t
));
1223 exp
.append("abcdefghij");
1224 r
= store
->read(ch
, hoid
, 0, 10, in
);
1227 ASSERT_TRUE(bl_eq(exp
, in
));
1230 ObjectStore::Transaction t
;
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
));
1239 r
= store
->read(ch
, hoid
, 0, bl
.length(), in
);
1240 ASSERT_EQ((int)bl
.length(), r
);
1242 ASSERT_TRUE(bl_eq(bl
, in
));
1246 bl
.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1248 //test: offset=len=0 mean read all data
1250 r
= store
->read(ch
, hoid
, 0, 0, in
);
1251 ASSERT_EQ((int)bl
.length(), r
);
1253 ASSERT_TRUE(bl_eq(bl
, in
));
1256 //verifying unaligned csums
1257 std::string
s1("1"), s2(0x1000, '2'), s3("00");
1259 ObjectStore::Transaction t
;
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
));
1270 bufferlist in
, exp1
, exp2
, exp3
;
1274 r
= store
->read(ch
, hoid
, 0x1000-1, 1, in
);
1276 ASSERT_TRUE(bl_eq(exp1
, in
));
1278 r
= store
->read(ch
, hoid
, 0x1000, 0x1000, in
);
1279 ASSERT_EQ(0x1000, r
);
1280 ASSERT_TRUE(bl_eq(exp2
, in
));
1283 ObjectStore::Transaction t
;
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
));
1292 r
= store
->read(ch
, hoid
, 1, 2, in
);
1294 ASSERT_TRUE(bl_eq(exp3
, in
));
1296 r
= store
->read(ch
, hoid
, 0x1000-1, 1, in
);
1298 ASSERT_TRUE(bl_eq(exp1
, in
));
1300 r
= store
->read(ch
, hoid
, 0x1000, 0x1000, in
);
1301 ASSERT_EQ(0x1000, r
);
1302 ASSERT_TRUE(bl_eq(exp2
, in
));
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
));
1316 #if defined(WITH_BLUESTORE)
1318 TEST_P(StoreTestSpecificAUSize
, BluestoreStatFSTest
) {
1319 if(string(GetParam()) != "bluestore")
1321 StartDeferred(65536);
1322 SetVal(g_conf(), "bluestore_compression_mode", "force");
1323 // just a big number to disble gc
1324 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "100000");
1325 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
1326 g_conf().apply_changes(nullptr);
1330 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
1331 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
1336 ghobject_t hoid2
= hoid
;
1337 hoid2
.hobj
.snap
= 1;
1339 auto ch
= store
->open_collection(cid
);
1342 auto ch
= store
->create_new_collection(cid
);
1344 ObjectStore::Transaction t
;
1345 t
.create_collection(cid
, 0);
1346 cerr
<< "Creating collection " << cid
<< std::endl
;
1347 r
= queue_transaction(store
, ch
, std::move(t
));
1351 bool exists
= store
->exists(ch
, hoid
);
1352 ASSERT_TRUE(!exists
);
1354 ObjectStore::Transaction t
;
1356 cerr
<< "Creating object " << hoid
<< std::endl
;
1357 r
= queue_transaction(store
, ch
, std::move(t
));
1360 exists
= store
->exists(ch
, hoid
);
1361 ASSERT_EQ(true, exists
);
1364 struct store_statfs_t statfs
;
1365 int r
= store
->statfs(&statfs
);
1367 ASSERT_EQ( 0u, statfs
.allocated
);
1368 ASSERT_EQ( 0u, statfs
.data_stored
);
1369 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
1370 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
1372 struct store_statfs_t statfs_pool
;
1373 r
= store
->pool_statfs(poolid
, &statfs_pool
);
1375 ASSERT_EQ( 0u, statfs_pool
.allocated
);
1376 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
1380 EXPECT_EQ(store
->umount(), 0);
1381 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1382 EXPECT_EQ(store
->mount(), 0);
1383 ch
= store
->open_collection(cid
);
1386 ObjectStore::Transaction t
;
1389 t
.write(cid
, hoid
, 0, 5, bl
);
1390 cerr
<< "Append 5 bytes" << std::endl
;
1391 r
= queue_transaction(store
, ch
, std::move(t
));
1394 struct store_statfs_t statfs
;
1395 int r
= store
->statfs(&statfs
);
1397 ASSERT_EQ(5, statfs
.data_stored
);
1398 ASSERT_EQ(0x10000, statfs
.allocated
);
1399 ASSERT_EQ(0, statfs
.data_compressed
);
1400 ASSERT_EQ(0, statfs
.data_compressed_original
);
1401 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1403 struct store_statfs_t statfs_pool
;
1404 r
= store
->pool_statfs(poolid
, &statfs_pool
);
1406 ASSERT_EQ(5, statfs_pool
.data_stored
);
1407 ASSERT_EQ(0x10000, statfs_pool
.allocated
);
1408 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1409 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1410 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1412 // accessing unknown pool
1413 r
= store
->pool_statfs(poolid
+ 1, &statfs_pool
);
1415 ASSERT_EQ(0, statfs_pool
.data_stored
);
1416 ASSERT_EQ(0, statfs_pool
.allocated
);
1417 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1418 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1419 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1423 EXPECT_EQ(store
->umount(), 0);
1424 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1425 EXPECT_EQ(store
->mount(), 0);
1426 ch
= store
->open_collection(cid
);
1429 ObjectStore::Transaction t
;
1430 std::string
s(0x30000, 'a');
1433 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1434 cerr
<< "Append 0x30000 compressible bytes" << std::endl
;
1435 r
= queue_transaction(store
, ch
, std::move(t
));
1438 struct store_statfs_t statfs
;
1439 int r
= store
->statfs(&statfs
);
1441 ASSERT_EQ(0x30005, statfs
.data_stored
);
1442 ASSERT_EQ(0x30000, statfs
.allocated
);
1443 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1444 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1445 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1447 struct store_statfs_t statfs_pool
;
1448 r
= store
->pool_statfs(poolid
, &statfs_pool
);
1450 ASSERT_EQ(0x30005, statfs_pool
.data_stored
);
1451 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1452 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1453 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1454 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1457 EXPECT_EQ(store
->umount(), 0);
1458 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1459 EXPECT_EQ(store
->mount(), 0);
1460 ch
= store
->open_collection(cid
);
1463 ObjectStore::Transaction t
;
1464 t
.zero(cid
, hoid
, 1, 3);
1465 t
.zero(cid
, hoid
, 0x20000, 9);
1466 cerr
<< "Punch hole at 1~3, 0x20000~9" << std::endl
;
1467 r
= queue_transaction(store
, ch
, std::move(t
));
1470 struct store_statfs_t statfs
;
1471 int r
= store
->statfs(&statfs
);
1473 ASSERT_EQ(0x30005 - 3 - 9, statfs
.data_stored
);
1474 ASSERT_EQ(0x30000, statfs
.allocated
);
1475 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1476 ASSERT_EQ(0x20000 - 9, statfs
.data_compressed_original
);
1477 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1479 struct store_statfs_t statfs_pool
;
1480 r
= store
->pool_statfs(poolid
, &statfs_pool
);
1482 ASSERT_EQ(0x30005 - 3 - 9, statfs_pool
.data_stored
);
1483 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1484 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1485 ASSERT_EQ(0x20000 - 9, statfs_pool
.data_compressed_original
);
1486 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1489 EXPECT_EQ(store
->umount(), 0);
1490 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1491 EXPECT_EQ(store
->mount(), 0);
1492 ch
= store
->open_collection(cid
);
1495 ObjectStore::Transaction t
;
1496 std::string
s(0x1000, 'b');
1499 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
1500 t
.write(cid
, hoid
, 0x10001, bl
.length(), bl
);
1501 cerr
<< "Overwrite first and second(compressible) extents" << std::endl
;
1502 r
= queue_transaction(store
, ch
, std::move(t
));
1505 struct store_statfs_t statfs
;
1506 int r
= store
->statfs(&statfs
);
1508 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs
.data_stored
);
1509 ASSERT_EQ(0x40000, statfs
.allocated
);
1510 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1511 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs
.data_compressed_original
);
1512 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1514 struct store_statfs_t statfs_pool
;
1515 r
= store
->pool_statfs(poolid
, &statfs_pool
);
1517 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs_pool
.data_stored
);
1518 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1519 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1520 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs_pool
.data_compressed_original
);
1521 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1524 EXPECT_EQ(store
->umount(), 0);
1525 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1526 EXPECT_EQ(store
->mount(), 0);
1527 ch
= store
->open_collection(cid
);
1530 ObjectStore::Transaction t
;
1531 std::string
s(0x10000, 'c');
1534 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1535 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
1536 t
.write(cid
, hoid
, 0x30000, bl
.length(), bl
);
1537 cerr
<< "Overwrite compressed extent with 3 uncompressible ones" << std::endl
;
1538 r
= queue_transaction(store
, ch
, std::move(t
));
1541 struct store_statfs_t statfs
;
1542 int r
= store
->statfs(&statfs
);
1544 ASSERT_EQ(0x30000 + 0x1001, statfs
.data_stored
);
1545 ASSERT_EQ(0x40000, statfs
.allocated
);
1546 ASSERT_LE(statfs
.data_compressed
, 0);
1547 ASSERT_EQ(0, statfs
.data_compressed_original
);
1548 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1550 struct store_statfs_t statfs_pool
;
1551 r
= store
->pool_statfs(poolid
, &statfs_pool
);
1553 ASSERT_EQ(0x30000 + 0x1001, statfs_pool
.data_stored
);
1554 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1555 ASSERT_LE(statfs_pool
.data_compressed
, 0);
1556 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1557 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1560 EXPECT_EQ(store
->umount(), 0);
1561 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1562 EXPECT_EQ(store
->mount(), 0);
1563 ch
= store
->open_collection(cid
);
1566 ObjectStore::Transaction t
;
1567 t
.zero(cid
, hoid
, 0, 0x40000);
1568 cerr
<< "Zero object" << std::endl
;
1569 r
= queue_transaction(store
, ch
, std::move(t
));
1571 struct store_statfs_t statfs
;
1572 int r
= store
->statfs(&statfs
);
1574 ASSERT_EQ(0u, statfs
.allocated
);
1575 ASSERT_EQ(0u, statfs
.data_stored
);
1576 ASSERT_EQ(0u, statfs
.data_compressed_original
);
1577 ASSERT_EQ(0u, statfs
.data_compressed
);
1578 ASSERT_EQ(0u, statfs
.data_compressed_allocated
);
1580 struct store_statfs_t statfs_pool
;
1581 r
= store
->pool_statfs(poolid
, &statfs_pool
);
1583 ASSERT_EQ(0u, statfs_pool
.allocated
);
1584 ASSERT_EQ(0u, statfs_pool
.data_stored
);
1585 ASSERT_EQ(0u, statfs_pool
.data_compressed_original
);
1586 ASSERT_EQ(0u, statfs_pool
.data_compressed
);
1587 ASSERT_EQ(0u, statfs_pool
.data_compressed_allocated
);
1590 EXPECT_EQ(store
->umount(), 0);
1591 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1592 EXPECT_EQ(store
->mount(), 0);
1593 ch
= store
->open_collection(cid
);
1596 ObjectStore::Transaction t
;
1597 std::string
s(0x10000, 'c');
1602 bl
.append(s
.substr(0, 0x10000-2));
1603 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1604 cerr
<< "Yet another compressible write" << std::endl
;
1605 r
= queue_transaction(store
, ch
, std::move(t
));
1607 struct store_statfs_t statfs
;
1608 r
= store
->statfs(&statfs
);
1610 ASSERT_EQ(0x40000 - 2, statfs
.data_stored
);
1611 ASSERT_EQ(0x30000, statfs
.allocated
);
1612 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1613 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1614 ASSERT_EQ(0x10000, statfs
.data_compressed_allocated
);
1616 struct store_statfs_t statfs_pool
;
1617 r
= store
->pool_statfs(poolid
, &statfs_pool
);
1619 ASSERT_EQ(0x40000 - 2, statfs_pool
.data_stored
);
1620 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1621 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1622 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1623 ASSERT_EQ(0x10000, statfs_pool
.data_compressed_allocated
);
1626 EXPECT_EQ(store
->umount(), 0);
1627 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1628 EXPECT_EQ(store
->mount(), 0);
1629 ch
= store
->open_collection(cid
);
1632 struct store_statfs_t statfs
;
1633 r
= store
->statfs(&statfs
);
1636 struct store_statfs_t statfs_pool
;
1637 r
= store
->pool_statfs(poolid
, &statfs_pool
);
1640 ObjectStore::Transaction t
;
1641 t
.clone(cid
, hoid
, hoid2
);
1642 cerr
<< "Clone compressed objecte" << std::endl
;
1643 r
= queue_transaction(store
, ch
, std::move(t
));
1645 struct store_statfs_t statfs2
;
1646 r
= store
->statfs(&statfs2
);
1648 ASSERT_GT(statfs2
.data_stored
, statfs
.data_stored
);
1649 ASSERT_EQ(statfs2
.allocated
, statfs
.allocated
);
1650 ASSERT_GT(statfs2
.data_compressed
, statfs
.data_compressed
);
1651 ASSERT_GT(statfs2
.data_compressed_original
, statfs
.data_compressed_original
);
1652 ASSERT_EQ(statfs2
.data_compressed_allocated
, statfs
.data_compressed_allocated
);
1654 struct store_statfs_t statfs2_pool
;
1655 r
= store
->pool_statfs(poolid
, &statfs2_pool
);
1657 ASSERT_GT(statfs2_pool
.data_stored
, statfs_pool
.data_stored
);
1658 ASSERT_EQ(statfs2_pool
.allocated
, statfs_pool
.allocated
);
1659 ASSERT_GT(statfs2_pool
.data_compressed
, statfs_pool
.data_compressed
);
1660 ASSERT_GT(statfs2_pool
.data_compressed_original
,
1661 statfs_pool
.data_compressed_original
);
1662 ASSERT_EQ(statfs2_pool
.data_compressed_allocated
,
1663 statfs_pool
.data_compressed_allocated
);
1668 auto poolid2
= poolid
+ 1;
1669 coll_t cid2
= coll_t(spg_t(pg_t(20, poolid2
), shard_id_t::NO_SHARD
));
1670 ghobject_t
hoid(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
1675 auto ch
= store
->create_new_collection(cid2
);
1679 struct store_statfs_t statfs1_pool
;
1680 int r
= store
->pool_statfs(poolid
, &statfs1_pool
);
1683 cerr
<< "Creating second collection " << cid2
<< std::endl
;
1684 ObjectStore::Transaction t
;
1685 t
.create_collection(cid2
, 0);
1686 r
= queue_transaction(store
, ch
, std::move(t
));
1689 t
= ObjectStore::Transaction();
1692 t
.write(cid2
, hoid
, 0, 5, bl
);
1693 r
= queue_transaction(store
, ch
, std::move(t
));
1696 struct store_statfs_t statfs2_pool
;
1697 r
= store
->pool_statfs(poolid2
, &statfs2_pool
);
1699 ASSERT_EQ(5, statfs2_pool
.data_stored
);
1700 ASSERT_EQ(0x10000, statfs2_pool
.allocated
);
1701 ASSERT_EQ(0, statfs2_pool
.data_compressed
);
1702 ASSERT_EQ(0, statfs2_pool
.data_compressed_original
);
1703 ASSERT_EQ(0, statfs2_pool
.data_compressed_allocated
);
1705 struct store_statfs_t statfs1_pool_again
;
1706 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
);
1708 // adjust 'available' since it has changed
1709 statfs1_pool_again
.available
= statfs1_pool
.available
;
1710 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
1712 t
= ObjectStore::Transaction();
1713 t
.remove(cid2
, hoid
);
1714 t
.remove_collection(cid2
);
1715 cerr
<< "Cleaning" << std::endl
;
1716 r
= queue_transaction(store
, ch
, std::move(t
));
1722 // verify ops on temporary object
1724 auto poolid3
= poolid
+ 2;
1725 coll_t cid3
= coll_t(spg_t(pg_t(20, poolid3
), shard_id_t::NO_SHARD
));
1726 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
),
1731 ghobject_t hoid3_temp
;
1732 hoid3_temp
.hobj
= hoid3
.hobj
.make_temp_hobject("Object 3 temp");
1733 auto ch3
= store
->create_new_collection(cid3
);
1735 struct store_statfs_t statfs1_pool
;
1736 int r
= store
->pool_statfs(poolid
, &statfs1_pool
);
1739 cerr
<< "Creating third collection " << cid3
<< std::endl
;
1740 ObjectStore::Transaction t
;
1741 t
.create_collection(cid3
, 0);
1742 r
= queue_transaction(store
, ch3
, std::move(t
));
1745 t
= ObjectStore::Transaction();
1748 t
.write(cid3
, hoid3_temp
, 0, 5, bl
);
1749 r
= queue_transaction(store
, ch3
, std::move(t
));
1752 struct store_statfs_t statfs3_pool
;
1753 r
= store
->pool_statfs(poolid3
, &statfs3_pool
);
1755 ASSERT_EQ(5, statfs3_pool
.data_stored
);
1756 ASSERT_EQ(0x10000, statfs3_pool
.allocated
);
1757 ASSERT_EQ(0, statfs3_pool
.data_compressed
);
1758 ASSERT_EQ(0, statfs3_pool
.data_compressed_original
);
1759 ASSERT_EQ(0, statfs3_pool
.data_compressed_allocated
);
1761 struct store_statfs_t statfs1_pool_again
;
1762 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
);
1764 // adjust 'available' since it has changed
1765 statfs1_pool_again
.available
= statfs1_pool
.available
;
1766 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
1771 EXPECT_EQ(store
->umount(), 0);
1772 EXPECT_EQ(store
->mount(), 0);
1773 ch
= store
->open_collection(cid
);
1774 ch3
= store
->open_collection(cid3
);
1776 t
= ObjectStore::Transaction();
1777 t
.collection_move_rename(
1780 r
= queue_transaction(store
, ch3
, std::move(t
));
1783 struct store_statfs_t statfs3_pool_again
;
1784 r
= store
->pool_statfs(poolid3
, &statfs3_pool_again
);
1786 ASSERT_EQ(statfs3_pool_again
, statfs3_pool
);
1791 EXPECT_EQ(store
->umount(), 0);
1792 EXPECT_EQ(store
->mount(), 0);
1793 ch
= store
->open_collection(cid
);
1794 ch3
= store
->open_collection(cid3
);
1796 t
= ObjectStore::Transaction();
1797 t
.remove(cid3
, hoid3
);
1798 t
.remove_collection(cid3
);
1799 cerr
<< "Cleaning" << std::endl
;
1800 r
= queue_transaction(store
, ch3
, std::move(t
));
1806 ObjectStore::Transaction t
;
1807 t
.remove(cid
, hoid
);
1808 t
.remove(cid
, hoid2
);
1809 t
.remove_collection(cid
);
1810 cerr
<< "Cleaning" << std::endl
;
1811 r
= queue_transaction(store
, ch
, std::move(t
));
1814 struct store_statfs_t statfs
;
1815 r
= store
->statfs(&statfs
);
1817 ASSERT_EQ( 0u, statfs
.allocated
);
1818 ASSERT_EQ( 0u, statfs
.data_stored
);
1819 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
1820 ASSERT_EQ( 0u, statfs
.data_compressed
);
1821 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
1823 struct store_statfs_t statfs_pool
;
1824 r
= store
->pool_statfs(poolid
, &statfs_pool
);
1826 ASSERT_EQ( 0u, statfs_pool
.allocated
);
1827 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
1828 ASSERT_EQ( 0u, statfs_pool
.data_compressed_original
);
1829 ASSERT_EQ( 0u, statfs_pool
.data_compressed
);
1830 ASSERT_EQ( 0u, statfs_pool
.data_compressed_allocated
);
1834 TEST_P(StoreTestSpecificAUSize
, BluestoreFragmentedBlobTest
) {
1835 if(string(GetParam()) != "bluestore")
1837 StartDeferred(0x10000);
1841 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1842 auto ch
= store
->create_new_collection(cid
);
1844 ObjectStore::Transaction t
;
1845 t
.create_collection(cid
, 0);
1846 cerr
<< "Creating collection " << cid
<< std::endl
;
1847 r
= queue_transaction(store
, ch
, std::move(t
));
1851 bool exists
= store
->exists(ch
, hoid
);
1852 ASSERT_TRUE(!exists
);
1854 ObjectStore::Transaction t
;
1856 cerr
<< "Creating object " << hoid
<< std::endl
;
1857 r
= queue_transaction(store
, ch
, std::move(t
));
1860 exists
= store
->exists(ch
, hoid
);
1861 ASSERT_EQ(true, exists
);
1864 struct store_statfs_t statfs
;
1865 int r
= store
->statfs(&statfs
);
1867 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
1868 ASSERT_EQ(0u, statfs
.allocated
);
1869 ASSERT_EQ(0u, statfs
.data_stored
);
1870 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
1873 data
.resize(0x10000 * 3);
1875 ObjectStore::Transaction t
;
1876 for(size_t i
= 0;i
< data
.size(); i
++)
1877 data
[i
] = i
/ 256 + 1;
1878 bufferlist bl
, newdata
;
1880 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1881 t
.zero(cid
, hoid
, 0x10000, 0x10000);
1882 cerr
<< "Append 3*0x10000 bytes and punch a hole 0x10000~10000" << std::endl
;
1883 r
= queue_transaction(store
, ch
, std::move(t
));
1886 struct store_statfs_t statfs
;
1887 int r
= store
->statfs(&statfs
);
1889 ASSERT_EQ(0x20000, statfs
.data_stored
);
1890 ASSERT_EQ(0x20000, statfs
.allocated
);
1892 r
= store
->read(ch
, hoid
, 0, data
.size(), newdata
);
1893 ASSERT_EQ(r
, (int)data
.size());
1895 bufferlist expected
;
1896 expected
.append(data
.substr(0, 0x10000));
1897 expected
.append(string(0x10000, 0));
1898 expected
.append(data
.substr(0x20000, 0x10000));
1899 ASSERT_TRUE(bl_eq(expected
, newdata
));
1903 r
= store
->read(ch
, hoid
, 1, data
.size()-2, newdata
);
1904 ASSERT_EQ(r
, (int)data
.size()-2);
1906 bufferlist expected
;
1907 expected
.append(data
.substr(1, 0x10000-1));
1908 expected
.append(string(0x10000, 0));
1909 expected
.append(data
.substr(0x20000, 0x10000 - 1));
1910 ASSERT_TRUE(bl_eq(expected
, newdata
));
1916 EXPECT_EQ(store
->umount(), 0);
1917 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1918 EXPECT_EQ(store
->mount(), 0);
1919 ch
= store
->open_collection(cid
);
1922 ObjectStore::Transaction t
;
1923 std::string
data2(3, 'b');
1924 bufferlist bl
, newdata
;
1926 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
1927 cerr
<< "Write 3 bytes after the hole" << std::endl
;
1928 r
= queue_transaction(store
, ch
, std::move(t
));
1931 struct store_statfs_t statfs
;
1932 int r
= store
->statfs(&statfs
);
1934 ASSERT_EQ(0x20000, statfs
.allocated
);
1935 ASSERT_EQ(0x20000, statfs
.data_stored
);
1937 r
= store
->read(ch
, hoid
, 0x20000-1, 21, newdata
);
1938 ASSERT_EQ(r
, (int)21);
1940 bufferlist expected
;
1941 expected
.append(string(0x1, 0));
1942 expected
.append(string(data2
));
1943 expected
.append(data
.substr(0x20003, 21-4));
1944 ASSERT_TRUE(bl_eq(expected
, newdata
));
1950 EXPECT_EQ(store
->umount(), 0);
1951 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1952 EXPECT_EQ(store
->mount(), 0);
1953 ch
= store
->open_collection(cid
);
1956 ObjectStore::Transaction t
;
1957 std::string
data2(3, 'a');
1958 bufferlist bl
, newdata
;
1960 t
.write(cid
, hoid
, 0x10000+1, bl
.length(), bl
);
1961 cerr
<< "Write 3 bytes to the hole" << std::endl
;
1962 r
= queue_transaction(store
, ch
, std::move(t
));
1965 struct store_statfs_t statfs
;
1966 int r
= store
->statfs(&statfs
);
1968 ASSERT_EQ(0x30000, statfs
.allocated
);
1969 ASSERT_EQ(0x20003, statfs
.data_stored
);
1971 r
= store
->read(ch
, hoid
, 0x10000-1, 0x10000+22, newdata
);
1972 ASSERT_EQ(r
, (int)0x10000+22);
1974 bufferlist expected
;
1975 expected
.append(data
.substr(0x10000-1, 1));
1976 expected
.append(string(0x1, 0));
1977 expected
.append(data2
);
1978 expected
.append(string(0x10000-4, 0));
1979 expected
.append(string(0x3, 'b'));
1980 expected
.append(data
.substr(0x20004, 21-3));
1981 ASSERT_TRUE(bl_eq(expected
, newdata
));
1986 ObjectStore::Transaction t
;
1987 bufferlist bl
, newdata
;
1988 bl
.append(string(0x30000, 'c'));
1989 t
.write(cid
, hoid
, 0, 0x30000, bl
);
1990 t
.zero(cid
, hoid
, 0, 0x10000);
1991 t
.zero(cid
, hoid
, 0x20000, 0x10000);
1992 cerr
<< "Rewrite an object and create two holes at the beginning and the end" << std::endl
;
1993 r
= queue_transaction(store
, ch
, std::move(t
));
1996 struct store_statfs_t statfs
;
1997 int r
= store
->statfs(&statfs
);
1999 ASSERT_EQ(0x10000, statfs
.allocated
);
2000 ASSERT_EQ(0x10000, statfs
.data_stored
);
2002 r
= store
->read(ch
, hoid
, 0, 0x30000, newdata
);
2003 ASSERT_EQ(r
, (int)0x30000);
2005 bufferlist expected
;
2006 expected
.append(string(0x10000, 0));
2007 expected
.append(string(0x10000, 'c'));
2008 expected
.append(string(0x10000, 0));
2009 ASSERT_TRUE(bl_eq(expected
, newdata
));
2016 EXPECT_EQ(store
->umount(), 0);
2017 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2018 EXPECT_EQ(store
->mount(), 0);
2019 ch
= store
->open_collection(cid
);
2022 ObjectStore::Transaction t
;
2023 t
.remove(cid
, hoid
);
2024 t
.remove_collection(cid
);
2025 cerr
<< "Cleaning" << std::endl
;
2026 r
= queue_transaction(store
, ch
, std::move(t
));
2029 struct store_statfs_t statfs
;
2030 r
= store
->statfs(&statfs
);
2032 ASSERT_EQ( 0u, statfs
.allocated
);
2033 ASSERT_EQ( 0u, statfs
.data_stored
);
2034 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
2035 ASSERT_EQ( 0u, statfs
.data_compressed
);
2036 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
2041 TEST_P(StoreTest
, ManySmallWrite
) {
2044 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2045 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2046 auto ch
= store
->create_new_collection(cid
);
2048 ObjectStore::Transaction t
;
2049 t
.create_collection(cid
, 0);
2050 cerr
<< "Creating collection " << cid
<< std::endl
;
2051 r
= queue_transaction(store
, ch
, std::move(t
));
2058 for (int i
=0; i
<100; ++i
) {
2059 ObjectStore::Transaction t
;
2060 t
.write(cid
, a
, i
*4096, 4096, bl
, 0);
2061 r
= queue_transaction(store
, ch
, std::move(t
));
2064 for (int i
=0; i
<100; ++i
) {
2065 ObjectStore::Transaction t
;
2066 t
.write(cid
, b
, (rand() % 1024)*4096, 4096, bl
, 0);
2067 r
= queue_transaction(store
, ch
, std::move(t
));
2071 ObjectStore::Transaction t
;
2074 t
.remove_collection(cid
);
2075 cerr
<< "Cleaning" << std::endl
;
2076 r
= queue_transaction(store
, ch
, std::move(t
));
2081 TEST_P(StoreTest
, MultiSmallWriteSameBlock
) {
2084 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2085 auto ch
= store
->create_new_collection(cid
);
2087 ObjectStore::Transaction t
;
2088 t
.create_collection(cid
, 0);
2089 cerr
<< "Creating collection " << cid
<< std::endl
;
2090 r
= queue_transaction(store
, ch
, std::move(t
));
2096 // touch same block in both same transaction, tls, and pipelined txns
2098 ObjectStore::Transaction t
, u
;
2099 t
.write(cid
, a
, 0, 5, bl
, 0);
2100 t
.write(cid
, a
, 5, 5, bl
, 0);
2101 t
.write(cid
, a
, 4094, 5, bl
, 0);
2102 t
.write(cid
, a
, 9000, 5, bl
, 0);
2103 u
.write(cid
, a
, 10, 5, bl
, 0);
2104 u
.write(cid
, a
, 7000, 5, bl
, 0);
2105 t
.register_on_commit(&c
);
2106 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2107 store
->queue_transactions(ch
, v
);
2110 ObjectStore::Transaction t
, u
;
2111 t
.write(cid
, a
, 40, 5, bl
, 0);
2112 t
.write(cid
, a
, 45, 5, bl
, 0);
2113 t
.write(cid
, a
, 4094, 5, bl
, 0);
2114 t
.write(cid
, a
, 6000, 5, bl
, 0);
2115 u
.write(cid
, a
, 610, 5, bl
, 0);
2116 u
.write(cid
, a
, 11000, 5, bl
, 0);
2117 t
.register_on_commit(&d
);
2118 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2119 store
->queue_transactions(ch
, v
);
2125 r
= store
->read(ch
, a
, 0, 16000, bl2
);
2129 ObjectStore::Transaction t
;
2131 t
.remove_collection(cid
);
2132 cerr
<< "Cleaning" << std::endl
;
2133 r
= queue_transaction(store
, ch
, std::move(t
));
2138 TEST_P(StoreTest
, SmallSkipFront
) {
2141 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2142 auto ch
= store
->create_new_collection(cid
);
2144 ObjectStore::Transaction t
;
2145 t
.create_collection(cid
, 0);
2146 cerr
<< "Creating collection " << cid
<< std::endl
;
2147 r
= queue_transaction(store
, ch
, std::move(t
));
2151 ObjectStore::Transaction t
;
2153 t
.truncate(cid
, a
, 3000);
2154 r
= queue_transaction(store
, ch
, std::move(t
));
2160 memset(bp
.c_str(), 1, 4096);
2162 ObjectStore::Transaction t
;
2163 t
.write(cid
, a
, 4096, 4096, bl
);
2164 r
= queue_transaction(store
, ch
, std::move(t
));
2169 ASSERT_EQ(8192, store
->read(ch
, a
, 0, 8192, bl
));
2170 for (unsigned i
=0; i
<4096; ++i
)
2171 ASSERT_EQ(0, bl
[i
]);
2172 for (unsigned i
=4096; i
<8192; ++i
)
2173 ASSERT_EQ(1, bl
[i
]);
2176 ObjectStore::Transaction t
;
2178 t
.remove_collection(cid
);
2179 cerr
<< "Cleaning" << std::endl
;
2180 r
= queue_transaction(store
, ch
, std::move(t
));
2185 TEST_P(StoreTest
, AppendDeferredVsTailCache
) {
2188 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2189 auto ch
= store
->create_new_collection(cid
);
2191 ObjectStore::Transaction t
;
2192 t
.create_collection(cid
, 0);
2193 cerr
<< "Creating collection " << cid
<< std::endl
;
2194 r
= store
->queue_transaction(ch
, std::move(t
));
2197 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2198 unsigned size
= min_alloc
/ 3;
2199 bufferptr
bpa(size
);
2200 memset(bpa
.c_str(), 1, bpa
.length());
2204 ObjectStore::Transaction t
;
2205 t
.write(cid
, a
, 0, bla
.length(), bla
, 0);
2206 r
= store
->queue_transaction(ch
, std::move(t
));
2210 // force cached tail to clear ...
2213 int r
= store
->umount();
2217 ch
= store
->open_collection(cid
);
2220 bufferptr
bpb(size
);
2221 memset(bpb
.c_str(), 2, bpb
.length());
2225 ObjectStore::Transaction t
;
2226 t
.write(cid
, a
, bla
.length(), blb
.length(), blb
, 0);
2227 r
= store
->queue_transaction(ch
, std::move(t
));
2230 bufferptr
bpc(size
);
2231 memset(bpc
.c_str(), 3, bpc
.length());
2235 ObjectStore::Transaction t
;
2236 t
.write(cid
, a
, bla
.length() + blb
.length(), blc
.length(), blc
, 0);
2237 r
= store
->queue_transaction(ch
, std::move(t
));
2246 ASSERT_EQ((int)final
.length(),
2247 store
->read(ch
, a
, 0, final
.length(), actual
));
2248 ASSERT_TRUE(bl_eq(final
, actual
));
2251 ObjectStore::Transaction t
;
2253 t
.remove_collection(cid
);
2254 cerr
<< "Cleaning" << std::endl
;
2255 r
= store
->queue_transaction(ch
, std::move(t
));
2260 TEST_P(StoreTest
, AppendZeroTrailingSharedBlock
) {
2263 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2266 auto ch
= store
->create_new_collection(cid
);
2268 ObjectStore::Transaction t
;
2269 t
.create_collection(cid
, 0);
2270 cerr
<< "Creating collection " << cid
<< std::endl
;
2271 r
= store
->queue_transaction(ch
, std::move(t
));
2274 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2275 unsigned size
= min_alloc
/ 3;
2276 bufferptr
bpa(size
);
2277 memset(bpa
.c_str(), 1, bpa
.length());
2280 // make sure there is some trailing gunk in the last block
2284 bt
.append("BADBADBADBAD");
2285 ObjectStore::Transaction t
;
2286 t
.write(cid
, a
, 0, bt
.length(), bt
, 0);
2287 r
= store
->queue_transaction(ch
, std::move(t
));
2291 ObjectStore::Transaction t
;
2292 t
.truncate(cid
, a
, size
);
2293 r
= store
->queue_transaction(ch
, std::move(t
));
2299 ObjectStore::Transaction t
;
2301 r
= store
->queue_transaction(ch
, std::move(t
));
2305 // append with implicit zeroing
2306 bufferptr
bpb(size
);
2307 memset(bpb
.c_str(), 2, bpb
.length());
2311 ObjectStore::Transaction t
;
2312 t
.write(cid
, a
, min_alloc
* 3, blb
.length(), blb
, 0);
2313 r
= store
->queue_transaction(ch
, std::move(t
));
2319 zeros
.append_zero(min_alloc
* 3 - size
);
2320 final
.append(zeros
);
2324 ASSERT_EQ((int)final
.length(),
2325 store
->read(ch
, a
, 0, final
.length(), actual
));
2326 final
.hexdump(cout
);
2327 actual
.hexdump(cout
);
2328 ASSERT_TRUE(bl_eq(final
, actual
));
2331 ObjectStore::Transaction t
;
2334 t
.remove_collection(cid
);
2335 cerr
<< "Cleaning" << std::endl
;
2336 r
= store
->queue_transaction(ch
, std::move(t
));
2341 TEST_P(StoreTest
, SmallSequentialUnaligned
) {
2344 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2345 auto ch
= store
->create_new_collection(cid
);
2347 ObjectStore::Transaction t
;
2348 t
.create_collection(cid
, 0);
2349 cerr
<< "Creating collection " << cid
<< std::endl
;
2350 r
= queue_transaction(store
, ch
, std::move(t
));
2358 for (int i
=0; i
<1000; ++i
) {
2359 ObjectStore::Transaction t
;
2360 t
.write(cid
, a
, i
*len
, len
, bl
, 0);
2361 r
= queue_transaction(store
, ch
, std::move(t
));
2365 ObjectStore::Transaction t
;
2367 t
.remove_collection(cid
);
2368 cerr
<< "Cleaning" << std::endl
;
2369 r
= queue_transaction(store
, ch
, std::move(t
));
2374 TEST_P(StoreTest
, ManyBigWrite
) {
2377 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2378 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2379 auto ch
= store
->create_new_collection(cid
);
2381 ObjectStore::Transaction t
;
2382 t
.create_collection(cid
, 0);
2383 cerr
<< "Creating collection " << cid
<< std::endl
;
2384 r
= queue_transaction(store
, ch
, std::move(t
));
2388 bufferptr
bp(4 * 1048576);
2391 for (int i
=0; i
<10; ++i
) {
2392 ObjectStore::Transaction t
;
2393 t
.write(cid
, a
, i
*4*1048586, 4*1048576, bl
, 0);
2394 r
= queue_transaction(store
, ch
, std::move(t
));
2398 for (int i
=0; i
<10; ++i
) {
2399 ObjectStore::Transaction t
;
2400 t
.write(cid
, b
, (rand() % 256)*4*1048576, 4*1048576, bl
, 0);
2401 r
= queue_transaction(store
, ch
, std::move(t
));
2405 for (int i
=0; i
<10; ++i
) {
2406 ObjectStore::Transaction t
;
2407 t
.write(cid
, b
, (rand() % (256*4096))*1024, 4*1048576, bl
, 0);
2408 r
= queue_transaction(store
, ch
, std::move(t
));
2412 for (int i
=0; i
<10; ++i
) {
2413 ObjectStore::Transaction t
;
2414 t
.zero(cid
, b
, (rand() % (256*4096))*1024, 16*1048576);
2415 r
= queue_transaction(store
, ch
, std::move(t
));
2419 ObjectStore::Transaction t
;
2422 t
.remove_collection(cid
);
2423 cerr
<< "Cleaning" << std::endl
;
2424 r
= queue_transaction(store
, ch
, std::move(t
));
2429 TEST_P(StoreTest
, BigWriteBigZero
) {
2432 ghobject_t
a(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2433 auto ch
= store
->create_new_collection(cid
);
2435 ObjectStore::Transaction t
;
2436 t
.create_collection(cid
, 0);
2437 r
= queue_transaction(store
, ch
, std::move(t
));
2441 bufferptr
bp(1048576);
2442 memset(bp
.c_str(), 'b', bp
.length());
2446 memset(sp
.c_str(), 's', sp
.length());
2449 ObjectStore::Transaction t
;
2450 t
.write(cid
, a
, 0, bl
.length(), bl
);
2451 r
= queue_transaction(store
, ch
, std::move(t
));
2455 ObjectStore::Transaction t
;
2456 t
.zero(cid
, a
, bl
.length() / 4, bl
.length() / 2);
2457 r
= queue_transaction(store
, ch
, std::move(t
));
2461 ObjectStore::Transaction t
;
2462 t
.write(cid
, a
, bl
.length() / 2, s
.length(), s
);
2463 r
= queue_transaction(store
, ch
, std::move(t
));
2467 ObjectStore::Transaction t
;
2469 t
.remove_collection(cid
);
2470 r
= queue_transaction(store
, ch
, std::move(t
));
2475 TEST_P(StoreTest
, MiscFragmentTests
) {
2478 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2479 auto ch
= store
->create_new_collection(cid
);
2481 ObjectStore::Transaction t
;
2482 t
.create_collection(cid
, 0);
2483 cerr
<< "Creating collection " << cid
<< std::endl
;
2484 r
= queue_transaction(store
, ch
, std::move(t
));
2488 bufferptr
bp(524288);
2492 ObjectStore::Transaction t
;
2493 t
.write(cid
, a
, 0, 524288, bl
, 0);
2494 r
= queue_transaction(store
, ch
, std::move(t
));
2498 ObjectStore::Transaction t
;
2499 t
.write(cid
, a
, 1048576, 524288, bl
, 0);
2500 r
= queue_transaction(store
, ch
, std::move(t
));
2505 int r
= store
->read(ch
, a
, 524288 + 131072, 1024, inbl
);
2507 ASSERT_EQ(inbl
.length(), 1024u);
2508 ASSERT_TRUE(inbl
.is_zero());
2511 ObjectStore::Transaction t
;
2512 t
.write(cid
, a
, 1048576 - 4096, 524288, bl
, 0);
2513 r
= queue_transaction(store
, ch
, std::move(t
));
2517 ObjectStore::Transaction t
;
2519 t
.remove_collection(cid
);
2520 cerr
<< "Cleaning" << std::endl
;
2521 r
= queue_transaction(store
, ch
, std::move(t
));
2527 TEST_P(StoreTest
, ZeroVsObjectSize
) {
2531 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2532 auto ch
= store
->create_new_collection(cid
);
2534 ObjectStore::Transaction t
;
2535 t
.create_collection(cid
, 0);
2536 cerr
<< "Creating collection " << cid
<< std::endl
;
2537 r
= queue_transaction(store
, ch
, std::move(t
));
2543 ObjectStore::Transaction t
;
2544 t
.write(cid
, hoid
, 0, 5, a
);
2545 r
= queue_transaction(store
, ch
, std::move(t
));
2548 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2549 ASSERT_EQ(5, stat
.st_size
);
2551 ObjectStore::Transaction t
;
2552 t
.zero(cid
, hoid
, 1, 2);
2553 r
= queue_transaction(store
, ch
, std::move(t
));
2556 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2557 ASSERT_EQ(5, stat
.st_size
);
2559 ObjectStore::Transaction t
;
2560 t
.zero(cid
, hoid
, 3, 200);
2561 r
= queue_transaction(store
, ch
, std::move(t
));
2564 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2565 ASSERT_EQ(203, stat
.st_size
);
2567 ObjectStore::Transaction t
;
2568 t
.zero(cid
, hoid
, 100000, 200);
2569 r
= queue_transaction(store
, ch
, std::move(t
));
2572 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2573 ASSERT_EQ(100200, stat
.st_size
);
2576 TEST_P(StoreTest
, ZeroLengthWrite
) {
2579 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2580 auto ch
= store
->create_new_collection(cid
);
2582 ObjectStore::Transaction t
;
2583 t
.create_collection(cid
, 0);
2585 r
= queue_transaction(store
, ch
, std::move(t
));
2589 ObjectStore::Transaction t
;
2591 t
.write(cid
, hoid
, 1048576, 0, empty
);
2592 r
= queue_transaction(store
, ch
, std::move(t
));
2596 r
= store
->stat(ch
, hoid
, &stat
);
2598 ASSERT_EQ(0, stat
.st_size
);
2601 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2605 TEST_P(StoreTest
, ZeroLengthZero
) {
2608 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2609 auto ch
= store
->create_new_collection(cid
);
2611 ObjectStore::Transaction t
;
2612 t
.create_collection(cid
, 0);
2614 r
= queue_transaction(store
, ch
, std::move(t
));
2618 ObjectStore::Transaction t
;
2619 t
.zero(cid
, hoid
, 1048576, 0);
2620 r
= queue_transaction(store
, ch
, std::move(t
));
2624 r
= store
->stat(ch
, hoid
, &stat
);
2626 ASSERT_EQ(0, stat
.st_size
);
2629 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2633 TEST_P(StoreTest
, SimpleAttrTest
) {
2636 ghobject_t
hoid(hobject_t(sobject_t("attr object 1", CEPH_NOSNAP
)));
2637 bufferlist val
, val2
;
2638 val
.append("value");
2639 val
.append("value2");
2641 auto ch
= store
->open_collection(cid
);
2644 auto ch
= store
->create_new_collection(cid
);
2646 ObjectStore::Transaction t
;
2647 t
.create_collection(cid
, 0);
2648 r
= queue_transaction(store
, ch
, std::move(t
));
2653 int r
= store
->collection_empty(ch
, &empty
);
2659 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2660 ASSERT_EQ(-ENOENT
, r
);
2663 ObjectStore::Transaction t
;
2665 t
.setattr(cid
, hoid
, "foo", val
);
2666 t
.setattr(cid
, hoid
, "bar", val2
);
2667 r
= queue_transaction(store
, ch
, std::move(t
));
2672 int r
= store
->collection_empty(ch
, &empty
);
2674 ASSERT_TRUE(!empty
);
2678 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2679 ASSERT_EQ(-ENODATA
, r
);
2681 r
= store
->getattr(ch
, hoid
, "foo", bp
);
2685 ASSERT_TRUE(bl_eq(val
, bl
));
2687 map
<string
,bufferptr
> bm
;
2688 r
= store
->getattrs(ch
, hoid
, bm
);
2693 ObjectStore::Transaction t
;
2694 t
.remove(cid
, hoid
);
2695 t
.remove_collection(cid
);
2696 r
= queue_transaction(store
, ch
, std::move(t
));
2701 TEST_P(StoreTest
, SimpleListTest
) {
2703 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2704 auto ch
= store
->create_new_collection(cid
);
2706 ObjectStore::Transaction t
;
2707 t
.create_collection(cid
, 0);
2708 cerr
<< "Creating collection " << cid
<< std::endl
;
2709 r
= queue_transaction(store
, ch
, std::move(t
));
2712 set
<ghobject_t
> all
;
2714 ObjectStore::Transaction t
;
2715 for (int i
=0; i
<200; ++i
) {
2716 string
name("object_");
2717 name
+= stringify(i
);
2718 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
2719 ghobject_t::NO_GEN
, shard_id_t(1));
2723 cerr
<< "Creating object " << hoid
<< std::endl
;
2725 r
= queue_transaction(store
, ch
, std::move(t
));
2729 set
<ghobject_t
> saw
;
2730 vector
<ghobject_t
> objects
;
2731 ghobject_t next
, current
;
2732 while (!next
.is_max()) {
2733 int r
= store
->collection_list(ch
, current
, ghobject_t::get_max(),
2737 ASSERT_TRUE(sorted(objects
));
2738 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
2739 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
2741 if (saw
.count(*p
)) {
2742 cout
<< "got DUP " << *p
<< std::endl
;
2744 //cout << "got new " << *p << std::endl;
2751 ASSERT_EQ(saw
.size(), all
.size());
2752 ASSERT_EQ(saw
, all
);
2755 ObjectStore::Transaction t
;
2756 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
2758 t
.remove_collection(cid
);
2759 cerr
<< "Cleaning" << std::endl
;
2760 r
= queue_transaction(store
, ch
, std::move(t
));
2765 TEST_P(StoreTest
, ListEndTest
) {
2767 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2768 auto ch
= store
->create_new_collection(cid
);
2770 ObjectStore::Transaction t
;
2771 t
.create_collection(cid
, 0);
2772 cerr
<< "Creating collection " << cid
<< std::endl
;
2773 r
= queue_transaction(store
, ch
, std::move(t
));
2776 set
<ghobject_t
> all
;
2778 ObjectStore::Transaction t
;
2779 for (int i
=0; i
<200; ++i
) {
2780 string
name("object_");
2781 name
+= stringify(i
);
2782 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
2783 ghobject_t::NO_GEN
, shard_id_t(1));
2787 cerr
<< "Creating object " << hoid
<< std::endl
;
2789 r
= queue_transaction(store
, ch
, std::move(t
));
2793 ghobject_t
end(hobject_t(sobject_t("object_100", CEPH_NOSNAP
)),
2794 ghobject_t::NO_GEN
, shard_id_t(1));
2796 vector
<ghobject_t
> objects
;
2798 int r
= store
->collection_list(ch
, ghobject_t(), end
, 500,
2801 for (auto &p
: objects
) {
2806 ObjectStore::Transaction t
;
2807 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
2809 t
.remove_collection(cid
);
2810 cerr
<< "Cleaning" << std::endl
;
2811 r
= queue_transaction(store
, ch
, std::move(t
));
2816 TEST_P(StoreTest
, Sort
) {
2818 hobject_t
a(sobject_t("a", CEPH_NOSNAP
));
2831 ghobject_t
a(hobject_t(sobject_t("a", CEPH_NOSNAP
)));
2832 ghobject_t
b(hobject_t(sobject_t("b", CEPH_NOSNAP
)));
2844 TEST_P(StoreTest
, MultipoolListTest
) {
2847 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
2848 auto ch
= store
->create_new_collection(cid
);
2850 ObjectStore::Transaction t
;
2851 t
.create_collection(cid
, 0);
2852 cerr
<< "Creating collection " << cid
<< std::endl
;
2853 r
= queue_transaction(store
, ch
, std::move(t
));
2856 set
<ghobject_t
> all
, saw
;
2858 ObjectStore::Transaction t
;
2859 for (int i
=0; i
<200; ++i
) {
2860 string
name("object_");
2861 name
+= stringify(i
);
2862 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)));
2864 hoid
.hobj
.pool
= -2 - poolid
;
2866 hoid
.hobj
.pool
= poolid
;
2869 cerr
<< "Creating object " << hoid
<< std::endl
;
2871 r
= queue_transaction(store
, ch
, std::move(t
));
2875 vector
<ghobject_t
> objects
;
2876 ghobject_t next
, current
;
2877 while (!next
.is_max()) {
2878 int r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 50,
2881 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
2882 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
2889 ASSERT_EQ(saw
, all
);
2892 ObjectStore::Transaction t
;
2893 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
2895 t
.remove_collection(cid
);
2896 cerr
<< "Cleaning" << std::endl
;
2897 r
= queue_transaction(store
, ch
, std::move(t
));
2902 TEST_P(StoreTest
, SimpleCloneTest
) {
2905 auto ch
= store
->create_new_collection(cid
);
2907 ObjectStore::Transaction t
;
2908 t
.create_collection(cid
, 0);
2909 cerr
<< "Creating collection " << cid
<< std::endl
;
2910 r
= queue_transaction(store
, ch
, std::move(t
));
2913 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
2914 "key", 123, -1, ""));
2915 bufferlist small
, large
, xlarge
, newdata
, attr
;
2916 small
.append("small");
2917 large
.append("large");
2918 xlarge
.append("xlarge");
2920 ObjectStore::Transaction t
;
2922 t
.setattr(cid
, hoid
, "attr1", small
);
2923 t
.setattr(cid
, hoid
, "attr2", large
);
2924 t
.setattr(cid
, hoid
, "attr3", xlarge
);
2925 t
.write(cid
, hoid
, 0, small
.length(), small
);
2926 t
.write(cid
, hoid
, 10, small
.length(), small
);
2927 cerr
<< "Creating object and set attr " << hoid
<< std::endl
;
2928 r
= queue_transaction(store
, ch
, std::move(t
));
2932 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
2933 "key", 123, -1, ""));
2934 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
)));
2936 ObjectStore::Transaction t
;
2937 t
.clone(cid
, hoid
, hoid2
);
2938 t
.setattr(cid
, hoid2
, "attr2", small
);
2939 t
.rmattr(cid
, hoid2
, "attr1");
2940 t
.write(cid
, hoid
, 10, large
.length(), large
);
2941 t
.setattr(cid
, hoid
, "attr1", large
);
2942 t
.setattr(cid
, hoid
, "attr2", small
);
2943 cerr
<< "Clone object and rm attr" << std::endl
;
2944 r
= queue_transaction(store
, ch
, std::move(t
));
2947 r
= store
->read(ch
, hoid
, 10, 5, newdata
);
2949 ASSERT_TRUE(bl_eq(large
, newdata
));
2952 r
= store
->read(ch
, hoid
, 0, 5, newdata
);
2954 ASSERT_TRUE(bl_eq(small
, newdata
));
2957 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
2959 ASSERT_TRUE(bl_eq(small
, newdata
));
2961 r
= store
->getattr(ch
, hoid2
, "attr2", attr
);
2963 ASSERT_TRUE(bl_eq(small
, attr
));
2966 r
= store
->getattr(ch
, hoid2
, "attr3", attr
);
2968 ASSERT_TRUE(bl_eq(xlarge
, attr
));
2971 r
= store
->getattr(ch
, hoid
, "attr1", attr
);
2973 ASSERT_TRUE(bl_eq(large
, attr
));
2976 ObjectStore::Transaction t
;
2977 t
.remove(cid
, hoid
);
2978 t
.remove(cid
, hoid2
);
2979 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
2984 memset(p
.c_str(), 1, p
.length());
2988 ObjectStore::Transaction t
;
2989 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
2990 t
.clone(cid
, hoid
, hoid2
);
2992 memset(a
.c_str(), 2, a
.length());
2996 t
.write(cid
, hoid
, pl
.length(), a
.length(), al
);
2997 r
= queue_transaction(store
, ch
, std::move(t
));
3000 ASSERT_EQ((int)final
.length(),
3001 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3002 ASSERT_TRUE(bl_eq(rl
, final
));
3005 ObjectStore::Transaction t
;
3006 t
.remove(cid
, hoid
);
3007 t
.remove(cid
, hoid2
);
3008 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3013 memset(p
.c_str(), 111, p
.length());
3017 ObjectStore::Transaction t
;
3018 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3019 t
.clone(cid
, hoid
, hoid2
);
3024 memset(a
.c_str(), 112, a
.length());
3028 t
.write(cid
, hoid
, pl
.length() + z
.length(), a
.length(), al
);
3029 r
= queue_transaction(store
, ch
, std::move(t
));
3032 ASSERT_EQ((int)final
.length(),
3033 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3034 ASSERT_TRUE(bl_eq(rl
, final
));
3037 ObjectStore::Transaction t
;
3038 t
.remove(cid
, hoid
);
3039 t
.remove(cid
, hoid2
);
3040 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3045 memset(p
.c_str(), 5, p
.length());
3049 ObjectStore::Transaction t
;
3050 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3051 t
.clone(cid
, hoid
, hoid2
);
3056 memset(a
.c_str(), 6, a
.length());
3060 t
.write(cid
, hoid
, 17000, a
.length(), al
);
3061 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3063 ASSERT_EQ((int)final
.length(),
3064 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3065 /*cout << "expected:\n";
3066 final.hexdump(cout);
3069 ASSERT_TRUE(bl_eq(rl
, final
));
3072 ObjectStore::Transaction t
;
3073 t
.remove(cid
, hoid
);
3074 t
.remove(cid
, hoid2
);
3075 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3078 bufferptr
p(1048576);
3079 memset(p
.c_str(), 3, p
.length());
3082 ObjectStore::Transaction t
;
3083 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3084 t
.clone(cid
, hoid
, hoid2
);
3086 memset(a
.c_str(), 4, a
.length());
3089 t
.write(cid
, hoid
, a
.length(), a
.length(), al
);
3090 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3093 final
.substr_of(pl
, 0, al
.length());
3096 end
.substr_of(pl
, al
.length()*2, pl
.length() - al
.length()*2);
3098 ASSERT_EQ((int)final
.length(),
3099 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3100 /*cout << "expected:\n";
3101 final.hexdump(cout);
3104 ASSERT_TRUE(bl_eq(rl
, final
));
3107 ObjectStore::Transaction t
;
3108 t
.remove(cid
, hoid
);
3109 t
.remove(cid
, hoid2
);
3110 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3114 memset(p
.c_str(), 7, p
.length());
3117 ObjectStore::Transaction t
;
3118 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3119 t
.clone(cid
, hoid
, hoid2
);
3121 memset(a
.c_str(), 8, a
.length());
3124 t
.write(cid
, hoid
, 32768, a
.length(), al
);
3125 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3128 final
.substr_of(pl
, 0, 32768);
3131 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3133 ASSERT_EQ((int)final
.length(),
3134 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3135 /*cout << "expected:\n";
3136 final.hexdump(cout);
3139 ASSERT_TRUE(bl_eq(rl
, final
));
3142 ObjectStore::Transaction t
;
3143 t
.remove(cid
, hoid
);
3144 t
.remove(cid
, hoid2
);
3145 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3149 memset(p
.c_str(), 9, p
.length());
3152 ObjectStore::Transaction t
;
3153 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3154 t
.clone(cid
, hoid
, hoid2
);
3156 memset(a
.c_str(), 10, a
.length());
3159 t
.write(cid
, hoid
, 33768, a
.length(), al
);
3160 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3163 final
.substr_of(pl
, 0, 33768);
3166 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3168 ASSERT_EQ((int)final
.length(),
3169 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3170 /*cout << "expected:\n";
3171 final.hexdump(cout);
3174 ASSERT_TRUE(bl_eq(rl
, final
));
3177 //Unfortunately we need a workaround for filestore since EXPECT_DEATH
3178 // macro has potential issues when using /in multithread environments.
3179 //It works well for all stores but filestore for now.
3180 //A fix setting gtest_death_test_style = "threadsafe" doesn't help as well -
3181 // test app clone asserts on store folder presence.
3183 if (string(GetParam()) != "filestore") {
3184 //verify if non-empty collection is properly handled after store reload
3186 r
= store
->umount();
3190 ch
= store
->open_collection(cid
);
3192 ObjectStore::Transaction t
;
3193 t
.remove_collection(cid
);
3194 cerr
<< "Invalid rm coll" << std::endl
;
3195 PrCtl unset_dumpable
;
3196 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3199 ObjectStore::Transaction t
;
3200 t
.touch(cid
, hoid3
); //new record in db
3201 r
= queue_transaction(store
, ch
, std::move(t
));
3204 //See comment above for "filestore" check explanation.
3205 if (string(GetParam()) != "filestore") {
3206 ObjectStore::Transaction t
;
3207 //verify if non-empty collection is properly handled when there are some pending removes and live records in db
3208 cerr
<< "Invalid rm coll again" << std::endl
;
3210 r
= store
->umount();
3214 ch
= store
->open_collection(cid
);
3216 t
.remove(cid
, hoid
);
3217 t
.remove(cid
, hoid2
);
3218 t
.remove_collection(cid
);
3219 PrCtl unset_dumpable
;
3220 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3223 ObjectStore::Transaction t
;
3224 t
.remove(cid
, hoid
);
3225 t
.remove(cid
, hoid2
);
3226 t
.remove(cid
, hoid3
);
3227 t
.remove_collection(cid
);
3228 cerr
<< "Cleaning" << std::endl
;
3229 r
= queue_transaction(store
, ch
, std::move(t
));
3234 TEST_P(StoreTest
, OmapSimple
) {
3237 auto ch
= store
->create_new_collection(cid
);
3239 ObjectStore::Transaction t
;
3240 t
.create_collection(cid
, 0);
3241 cerr
<< "Creating collection " << cid
<< std::endl
;
3242 r
= queue_transaction(store
, ch
, std::move(t
));
3245 ghobject_t
hoid(hobject_t(sobject_t("omap_obj", CEPH_NOSNAP
),
3246 "key", 123, -1, ""));
3248 small
.append("small");
3249 map
<string
,bufferlist
> km
;
3251 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3253 header
.append("this is a header");
3255 ObjectStore::Transaction t
;
3257 t
.omap_setkeys(cid
, hoid
, km
);
3258 t
.omap_setheader(cid
, hoid
, header
);
3259 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3260 r
= queue_transaction(store
, ch
, std::move(t
));
3266 map
<string
,bufferlist
> r
;
3267 store
->omap_get(ch
, hoid
, &h
, &r
);
3268 ASSERT_TRUE(bl_eq(header
, h
));
3269 ASSERT_EQ(r
.size(), km
.size());
3270 cout
<< "r: " << r
<< std::endl
;
3272 // test iterator with seek_to_first
3274 map
<string
,bufferlist
> r
;
3275 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3276 for (iter
->seek_to_first(); iter
->valid(); iter
->next()) {
3277 r
[iter
->key()] = iter
->value();
3279 cout
<< "r: " << r
<< std::endl
;
3280 ASSERT_EQ(r
.size(), km
.size());
3282 // test iterator with initial lower_bound
3284 map
<string
,bufferlist
> r
;
3285 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3286 for (iter
->lower_bound(string()); iter
->valid(); iter
->next()) {
3287 r
[iter
->key()] = iter
->value();
3289 cout
<< "r: " << r
<< std::endl
;
3290 ASSERT_EQ(r
.size(), km
.size());
3293 ObjectStore::Transaction t
;
3294 t
.remove(cid
, hoid
);
3295 t
.remove_collection(cid
);
3296 cerr
<< "Cleaning" << std::endl
;
3297 r
= queue_transaction(store
, ch
, std::move(t
));
3302 TEST_P(StoreTest
, OmapCloneTest
) {
3305 auto ch
= store
->create_new_collection(cid
);
3307 ObjectStore::Transaction t
;
3308 t
.create_collection(cid
, 0);
3309 cerr
<< "Creating collection " << cid
<< std::endl
;
3310 r
= queue_transaction(store
, ch
, std::move(t
));
3313 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
3314 "key", 123, -1, ""));
3316 small
.append("small");
3317 map
<string
,bufferlist
> km
;
3319 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3321 header
.append("this is a header");
3323 ObjectStore::Transaction t
;
3325 t
.omap_setkeys(cid
, hoid
, km
);
3326 t
.omap_setheader(cid
, hoid
, header
);
3327 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3328 r
= queue_transaction(store
, ch
, std::move(t
));
3331 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
3332 "key", 123, -1, ""));
3334 ObjectStore::Transaction t
;
3335 t
.clone(cid
, hoid
, hoid2
);
3336 cerr
<< "Clone object" << std::endl
;
3337 r
= queue_transaction(store
, ch
, std::move(t
));
3341 map
<string
,bufferlist
> r
;
3343 store
->omap_get(ch
, hoid2
, &h
, &r
);
3344 ASSERT_TRUE(bl_eq(header
, h
));
3345 ASSERT_EQ(r
.size(), km
.size());
3348 ObjectStore::Transaction t
;
3349 t
.remove(cid
, hoid
);
3350 t
.remove(cid
, hoid2
);
3351 t
.remove_collection(cid
);
3352 cerr
<< "Cleaning" << std::endl
;
3353 r
= queue_transaction(store
, ch
, std::move(t
));
3358 TEST_P(StoreTest
, SimpleCloneRangeTest
) {
3361 auto ch
= store
->create_new_collection(cid
);
3363 ObjectStore::Transaction t
;
3364 t
.create_collection(cid
, 0);
3365 cerr
<< "Creating collection " << cid
<< std::endl
;
3366 r
= queue_transaction(store
, ch
, std::move(t
));
3369 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3370 hoid
.hobj
.pool
= -1;
3371 bufferlist small
, newdata
;
3372 small
.append("small");
3374 ObjectStore::Transaction t
;
3375 t
.write(cid
, hoid
, 10, 5, small
);
3376 cerr
<< "Creating object and write bl " << hoid
<< std::endl
;
3377 r
= queue_transaction(store
, ch
, std::move(t
));
3380 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
3381 hoid2
.hobj
.pool
= -1;
3383 ObjectStore::Transaction t
;
3384 t
.clone_range(cid
, hoid
, hoid2
, 10, 5, 10);
3385 cerr
<< "Clone range object" << std::endl
;
3386 r
= queue_transaction(store
, ch
, std::move(t
));
3388 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
3390 ASSERT_TRUE(bl_eq(small
, newdata
));
3393 ObjectStore::Transaction t
;
3394 t
.truncate(cid
, hoid
, 1024*1024);
3395 t
.clone_range(cid
, hoid
, hoid2
, 0, 1024*1024, 0);
3396 cerr
<< "Clone range object" << std::endl
;
3397 r
= queue_transaction(store
, ch
, std::move(t
));
3399 struct stat stat
, stat2
;
3400 r
= store
->stat(ch
, hoid
, &stat
);
3401 r
= store
->stat(ch
, hoid2
, &stat2
);
3402 ASSERT_EQ(stat
.st_size
, stat2
.st_size
);
3403 ASSERT_EQ(1024*1024, stat2
.st_size
);
3406 ObjectStore::Transaction t
;
3407 t
.remove(cid
, hoid
);
3408 t
.remove(cid
, hoid2
);
3409 t
.remove_collection(cid
);
3410 cerr
<< "Cleaning" << std::endl
;
3411 r
= queue_transaction(store
, ch
, std::move(t
));
3417 TEST_P(StoreTest
, SimpleObjectLongnameTest
) {
3420 auto ch
= store
->create_new_collection(cid
);
3422 ObjectStore::Transaction t
;
3423 t
.create_collection(cid
, 0);
3424 cerr
<< "Creating collection " << cid
<< std::endl
;
3425 r
= queue_transaction(store
, ch
, std::move(t
));
3428 ghobject_t
hoid(hobject_t(sobject_t("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaObjectaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1", CEPH_NOSNAP
)));
3430 ObjectStore::Transaction t
;
3432 cerr
<< "Creating object " << hoid
<< std::endl
;
3433 r
= queue_transaction(store
, ch
, std::move(t
));
3437 ObjectStore::Transaction t
;
3438 t
.remove(cid
, hoid
);
3439 t
.remove_collection(cid
);
3440 cerr
<< "Cleaning" << std::endl
;
3441 r
= queue_transaction(store
, ch
, std::move(t
));
3446 ghobject_t
generate_long_name(unsigned i
)
3449 name
<< "object id " << i
<< " ";
3450 for (unsigned j
= 0; j
< 500; ++j
) name
<< 'a';
3451 ghobject_t
hoid(hobject_t(sobject_t(name
.str(), CEPH_NOSNAP
)));
3452 hoid
.hobj
.set_hash(i
% 2);
3456 TEST_P(StoreTest
, LongnameSplitTest
) {
3459 auto ch
= store
->create_new_collection(cid
);
3461 ObjectStore::Transaction t
;
3462 t
.create_collection(cid
, 0);
3463 cerr
<< "Creating collection " << cid
<< std::endl
;
3464 r
= queue_transaction(store
, ch
, std::move(t
));
3467 for (unsigned i
= 0; i
< 320; ++i
) {
3468 ObjectStore::Transaction t
;
3469 ghobject_t hoid
= generate_long_name(i
);
3471 cerr
<< "Creating object " << hoid
<< std::endl
;
3472 r
= queue_transaction(store
, ch
, std::move(t
));
3476 ghobject_t test_obj
= generate_long_name(319);
3477 ghobject_t test_obj_2
= test_obj
;
3478 test_obj_2
.generation
= 0;
3480 ObjectStore::Transaction t
;
3481 // should cause a split
3482 t
.collection_move_rename(
3485 r
= queue_transaction(store
, ch
, std::move(t
));
3489 for (unsigned i
= 0; i
< 319; ++i
) {
3490 ObjectStore::Transaction t
;
3491 ghobject_t hoid
= generate_long_name(i
);
3492 t
.remove(cid
, hoid
);
3493 cerr
<< "Removing object " << hoid
<< std::endl
;
3494 r
= queue_transaction(store
, ch
, std::move(t
));
3498 ObjectStore::Transaction t
;
3499 t
.remove(cid
, test_obj_2
);
3500 t
.remove_collection(cid
);
3501 cerr
<< "Cleaning" << std::endl
;
3502 r
= queue_transaction(store
, ch
, std::move(t
));
3508 TEST_P(StoreTest
, ManyObjectTest
) {
3509 int NUM_OBJS
= 2000;
3513 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
3514 set
<ghobject_t
> created
;
3515 auto ch
= store
->create_new_collection(cid
);
3517 ObjectStore::Transaction t
;
3518 t
.create_collection(cid
, 0);
3519 r
= queue_transaction(store
, ch
, std::move(t
));
3522 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
3524 cerr
<< "Object " << i
<< std::endl
;
3526 ObjectStore::Transaction t
;
3528 snprintf(buf
, sizeof(buf
), "%d", i
);
3529 ghobject_t
hoid(hobject_t(sobject_t(string(buf
) + base
, CEPH_NOSNAP
)));
3531 created
.insert(hoid
);
3532 r
= queue_transaction(store
, ch
, std::move(t
));
3536 for (set
<ghobject_t
>::iterator i
= created
.begin();
3540 ASSERT_TRUE(!store
->stat(ch
, *i
, &buf
));
3543 set
<ghobject_t
> listed
, listed2
;
3544 vector
<ghobject_t
> objects
;
3545 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
, &objects
, 0);
3548 cerr
<< "objects.size() is " << objects
.size() << std::endl
;
3549 for (vector
<ghobject_t
> ::iterator i
= objects
.begin();
3553 ASSERT_TRUE(created
.count(*i
));
3555 ASSERT_TRUE(listed
.size() == created
.size());
3557 ghobject_t start
, next
;
3559 r
= store
->collection_list(
3561 ghobject_t::get_max(),
3562 ghobject_t::get_max(),
3568 ASSERT_TRUE(objects
.empty());
3572 ghobject_t start2
, next2
;
3574 r
= store
->collection_list(ch
, start
, ghobject_t::get_max(),
3578 ASSERT_TRUE(sorted(objects
));
3580 listed
.insert(objects
.begin(), objects
.end());
3581 if (objects
.size() < 50) {
3582 ASSERT_TRUE(next
.is_max());
3589 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
3590 ASSERT_TRUE(listed
.size() == created
.size());
3591 if (listed2
.size()) {
3592 ASSERT_EQ(listed
.size(), listed2
.size());
3594 for (set
<ghobject_t
>::iterator i
= listed
.begin();
3597 ASSERT_TRUE(created
.count(*i
));
3600 for (set
<ghobject_t
>::iterator i
= created
.begin();
3603 ObjectStore::Transaction t
;
3605 r
= queue_transaction(store
, ch
, std::move(t
));
3608 cerr
<< "cleaning up" << std::endl
;
3610 ObjectStore::Transaction t
;
3611 t
.remove_collection(cid
);
3612 r
= queue_transaction(store
, ch
, std::move(t
));
3618 class ObjectGenerator
{
3620 virtual ghobject_t
create_object(gen_type
*gen
) = 0;
3621 virtual ~ObjectGenerator() {}
3624 class MixedGenerator
: public ObjectGenerator
{
3628 explicit MixedGenerator(int64_t p
) : seq(0), poolid(p
) {}
3629 ghobject_t
create_object(gen_type
*gen
) override
{
3631 snprintf(buf
, sizeof(buf
), "OBJ_%u", seq
);
3634 for (unsigned i
= 0; i
< 300; ++i
) {
3635 name
.push_back('a');
3641 name
, string(), rand() & 2 ? CEPH_NOSNAP
: rand(),
3642 (((seq
/ 1024) % 2) * 0xF00 ) +
3648 class SyntheticWorkloadState
{
3651 map
<string
, bufferlist
> attrs
;
3654 static const unsigned max_in_flight
= 16;
3655 static const unsigned max_objects
= 3000;
3656 static const unsigned max_attr_size
= 5;
3657 static const unsigned max_attr_name_len
= 100;
3658 static const unsigned max_attr_value_len
= 1024 * 64;
3660 unsigned write_alignment
;
3661 unsigned max_object_len
, max_write_len
;
3663 map
<ghobject_t
, Object
> contents
;
3664 set
<ghobject_t
> available_objects
;
3665 set
<ghobject_t
> in_flight_objects
;
3666 ObjectGenerator
*object_gen
;
3669 ObjectStore::CollectionHandle ch
;
3676 explicit EnterExit(const char *m
) : msg(m
) {
3677 //cout << pthread_self() << " enter " << msg << std::endl;
3680 //cout << pthread_self() << " exit " << msg << std::endl;
3684 class C_SyntheticOnReadable
: public Context
{
3686 SyntheticWorkloadState
*state
;
3688 C_SyntheticOnReadable(SyntheticWorkloadState
*state
, ghobject_t hoid
)
3689 : state(state
), hoid(hoid
) {}
3691 void finish(int r
) override
{
3692 Mutex::Locker
locker(state
->lock
);
3693 EnterExit
ee("onreadable finish");
3694 ASSERT_TRUE(state
->in_flight_objects
.count(hoid
));
3696 state
->in_flight_objects
.erase(hoid
);
3697 if (state
->contents
.count(hoid
))
3698 state
->available_objects
.insert(hoid
);
3699 --(state
->in_flight
);
3700 state
->cond
.Signal();
3703 r
= state
->store
->read(state
->ch
, hoid
, 0, state
->contents
[hoid
].data
.length(), r2
);
3704 ceph_assert(bl_eq(state
->contents
[hoid
].data
, r2
));
3705 state
->cond
.Signal();
3709 class C_SyntheticOnStash
: public Context
{
3711 SyntheticWorkloadState
*state
;
3712 ghobject_t oid
, noid
;
3714 C_SyntheticOnStash(SyntheticWorkloadState
*state
,
3715 ghobject_t oid
, ghobject_t noid
)
3716 : state(state
), oid(oid
), noid(noid
) {}
3718 void finish(int r
) override
{
3719 Mutex::Locker
locker(state
->lock
);
3720 EnterExit
ee("stash finish");
3721 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
3723 state
->in_flight_objects
.erase(oid
);
3724 if (state
->contents
.count(noid
))
3725 state
->available_objects
.insert(noid
);
3726 --(state
->in_flight
);
3728 r
= state
->store
->read(
3730 state
->contents
[noid
].data
.length(), r2
);
3731 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
3732 state
->cond
.Signal();
3736 class C_SyntheticOnClone
: public Context
{
3738 SyntheticWorkloadState
*state
;
3739 ghobject_t oid
, noid
;
3741 C_SyntheticOnClone(SyntheticWorkloadState
*state
,
3742 ghobject_t oid
, ghobject_t noid
)
3743 : state(state
), oid(oid
), noid(noid
) {}
3745 void finish(int r
) override
{
3746 Mutex::Locker
locker(state
->lock
);
3747 EnterExit
ee("clone finish");
3748 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
3750 state
->in_flight_objects
.erase(oid
);
3751 if (state
->contents
.count(oid
))
3752 state
->available_objects
.insert(oid
);
3753 if (state
->contents
.count(noid
))
3754 state
->available_objects
.insert(noid
);
3755 --(state
->in_flight
);
3757 r
= state
->store
->read(state
->ch
, noid
, 0, state
->contents
[noid
].data
.length(), r2
);
3758 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
3759 state
->cond
.Signal();
3763 static void filled_byte_array(bufferlist
& bl
, size_t size
)
3765 static const char alphanum
[] = "0123456789"
3766 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3767 "abcdefghijklmnopqrstuvwxyz";
3772 for (unsigned int i
= 0; i
< size
- 1; i
++) {
3773 // severely limit entropy so we can compress...
3774 bp
[i
] = alphanum
[rand() % 10]; //(sizeof(alphanum) - 1)];
3776 bp
[size
- 1] = '\0';
3781 SyntheticWorkloadState(ObjectStore
*store
,
3782 ObjectGenerator
*gen
,
3788 : cid(cid
), write_alignment(alignment
), max_object_len(max_size
),
3789 max_write_len(max_write
), in_flight(0), object_gen(gen
),
3790 rng(rng
), store(store
),
3791 lock("State lock") {}
3794 ObjectStore::Transaction t
;
3795 ch
= store
->create_new_collection(cid
);
3796 t
.create_collection(cid
, 0);
3797 return queue_transaction(store
, ch
, std::move(t
));
3801 vector
<ghobject_t
> objects
;
3802 int r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
3804 ceph_assert(r
>= 0);
3805 if (objects
.empty())
3807 ObjectStore::Transaction t
;
3808 for (vector
<ghobject_t
>::iterator p
= objects
.begin();
3809 p
!= objects
.end(); ++p
) {
3812 queue_transaction(store
, ch
, std::move(t
));
3814 ObjectStore::Transaction t
;
3815 t
.remove_collection(cid
);
3816 queue_transaction(store
, ch
, std::move(t
));
3818 void statfs(store_statfs_t
& stat
) {
3819 store
->statfs(&stat
);
3822 ghobject_t
get_uniform_random_object() {
3823 while (in_flight
>= max_in_flight
|| available_objects
.empty())
3825 boost::uniform_int
<> choose(0, available_objects
.size() - 1);
3826 int index
= choose(*rng
);
3827 set
<ghobject_t
>::iterator i
= available_objects
.begin();
3828 for ( ; index
> 0; --index
, ++i
) ;
3829 ghobject_t ret
= *i
;
3833 void wait_for_ready() {
3834 while (in_flight
>= max_in_flight
)
3838 void wait_for_done() {
3839 Mutex::Locker
locker(lock
);
3845 return (available_objects
.size() + in_flight_objects
.size()) < max_objects
;
3849 return (available_objects
.size() + in_flight_objects
.size()) > 0;
3852 unsigned get_random_alloc_hints() {
3855 boost::uniform_int
<> u(0, 3);
3858 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE
;
3861 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE
;
3866 boost::uniform_int
<> u(0, 3);
3869 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
;
3872 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ
;
3877 // append_only, immutable
3878 boost::uniform_int
<> u(0, 4);
3882 boost::uniform_int
<> u(0, 3);
3885 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED
;
3888 f
|= CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED
;
3893 boost::uniform_int
<> u(0, 3);
3896 f
|= CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE
;
3899 f
|= CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE
;
3907 Mutex::Locker
locker(lock
);
3908 EnterExit
ee("touch");
3912 ghobject_t new_obj
= object_gen
->create_object(rng
);
3913 available_objects
.erase(new_obj
);
3914 ObjectStore::Transaction t
;
3915 t
.touch(cid
, new_obj
);
3916 boost::uniform_int
<> u(17, 22);
3917 boost::uniform_int
<> v(12, 17);
3918 t
.set_alloc_hint(cid
, new_obj
,
3921 get_random_alloc_hints());
3923 in_flight_objects
.insert(new_obj
);
3924 if (!contents
.count(new_obj
))
3925 contents
[new_obj
] = Object();
3926 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
3927 int status
= store
->queue_transaction(ch
, std::move(t
));
3932 Mutex::Locker
locker(lock
);
3933 EnterExit
ee("stash");
3943 old_obj
= get_uniform_random_object();
3944 } while (--max
&& !contents
[old_obj
].data
.length());
3945 available_objects
.erase(old_obj
);
3946 ghobject_t new_obj
= old_obj
;
3947 new_obj
.generation
++;
3948 available_objects
.erase(new_obj
);
3950 ObjectStore::Transaction t
;
3951 t
.collection_move_rename(cid
, old_obj
, cid
, new_obj
);
3953 in_flight_objects
.insert(old_obj
);
3955 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
3956 contents
[new_obj
].data
= contents
[old_obj
].data
;
3957 contents
.erase(old_obj
);
3958 t
.register_on_applied(new C_SyntheticOnStash(this, old_obj
, new_obj
));
3959 int status
= store
->queue_transaction(ch
, std::move(t
));
3964 Mutex::Locker
locker(lock
);
3965 EnterExit
ee("clone");
3975 old_obj
= get_uniform_random_object();
3976 } while (--max
&& !contents
[old_obj
].data
.length());
3977 available_objects
.erase(old_obj
);
3978 ghobject_t new_obj
= object_gen
->create_object(rng
);
3979 // make the hash match
3980 new_obj
.hobj
.set_hash(old_obj
.hobj
.get_hash());
3981 available_objects
.erase(new_obj
);
3983 ObjectStore::Transaction t
;
3984 t
.clone(cid
, old_obj
, new_obj
);
3986 in_flight_objects
.insert(old_obj
);
3988 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
3989 contents
[new_obj
].data
= contents
[old_obj
].data
;
3991 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
3992 int status
= store
->queue_transaction(ch
, std::move(t
));
3997 Mutex::Locker
locker(lock
);
3998 EnterExit
ee("clone_range");
4008 old_obj
= get_uniform_random_object();
4009 } while (--max
&& !contents
[old_obj
].data
.length());
4010 bufferlist
&srcdata
= contents
[old_obj
].data
;
4011 if (srcdata
.length() == 0) {
4014 available_objects
.erase(old_obj
);
4015 ghobject_t new_obj
= get_uniform_random_object();
4016 available_objects
.erase(new_obj
);
4018 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4019 boost::uniform_int
<> u2(0, max_write_len
);
4020 uint64_t srcoff
= u1(*rng
);
4021 // make src and dst offsets match, since that's what the osd does
4022 uint64_t dstoff
= srcoff
; //u1(*rng);
4023 uint64_t len
= u2(*rng
);
4024 if (write_alignment
) {
4025 srcoff
= round_up_to(srcoff
, write_alignment
);
4026 dstoff
= round_up_to(dstoff
, write_alignment
);
4027 len
= round_up_to(len
, write_alignment
);
4030 if (srcoff
> srcdata
.length() - 1) {
4031 srcoff
= srcdata
.length() - 1;
4033 if (srcoff
+ len
> srcdata
.length()) {
4034 len
= srcdata
.length() - srcoff
;
4037 cout
<< __func__
<< " from " << srcoff
<< "~" << len
4038 << " (size " << srcdata
.length() << ") to "
4039 << dstoff
<< "~" << len
<< std::endl
;
4041 ObjectStore::Transaction t
;
4042 t
.clone_range(cid
, old_obj
, new_obj
, srcoff
, len
, dstoff
);
4044 in_flight_objects
.insert(old_obj
);
4047 if (srcoff
< srcdata
.length()) {
4048 if (srcoff
+ len
> srcdata
.length()) {
4049 bl
.substr_of(srcdata
, srcoff
, srcdata
.length() - srcoff
);
4051 bl
.substr_of(srcdata
, srcoff
, len
);
4055 bufferlist
& dstdata
= contents
[new_obj
].data
;
4056 if (dstdata
.length() <= dstoff
) {
4057 if (bl
.length() > 0) {
4058 dstdata
.append_zero(dstoff
- dstdata
.length());
4063 ceph_assert(dstdata
.length() > dstoff
);
4064 dstdata
.copy(0, dstoff
, value
);
4066 if (value
.length() < dstdata
.length())
4067 dstdata
.copy(value
.length(),
4068 dstdata
.length() - value
.length(), value
);
4069 value
.swap(dstdata
);
4072 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
4073 int status
= store
->queue_transaction(ch
, std::move(t
));
4079 Mutex::Locker
locker(lock
);
4080 EnterExit
ee("write");
4085 ghobject_t new_obj
= get_uniform_random_object();
4086 available_objects
.erase(new_obj
);
4087 ObjectStore::Transaction t
;
4089 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4090 boost::uniform_int
<> u2(0, max_write_len
);
4091 uint64_t offset
= u1(*rng
);
4092 uint64_t len
= u2(*rng
);
4094 if (write_alignment
) {
4095 offset
= round_up_to(offset
, write_alignment
);
4096 len
= round_up_to(len
, write_alignment
);
4099 filled_byte_array(bl
, len
);
4101 bufferlist
& data
= contents
[new_obj
].data
;
4102 if (data
.length() <= offset
) {
4104 data
.append_zero(offset
-data
.length());
4109 ceph_assert(data
.length() > offset
);
4110 data
.copy(0, offset
, value
);
4112 if (value
.length() < data
.length())
4113 data
.copy(value
.length(),
4114 data
.length()-value
.length(), value
);
4118 t
.write(cid
, new_obj
, offset
, len
, bl
);
4120 in_flight_objects
.insert(new_obj
);
4121 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4122 int status
= store
->queue_transaction(ch
, std::move(t
));
4127 Mutex::Locker
locker(lock
);
4128 EnterExit
ee("truncate");
4133 ghobject_t obj
= get_uniform_random_object();
4134 available_objects
.erase(obj
);
4135 ObjectStore::Transaction t
;
4137 boost::uniform_int
<> choose(0, max_object_len
);
4138 size_t len
= choose(*rng
);
4139 if (write_alignment
) {
4140 len
= round_up_to(len
, write_alignment
);
4143 t
.truncate(cid
, obj
, len
);
4145 in_flight_objects
.insert(obj
);
4146 bufferlist
& data
= contents
[obj
].data
;
4147 if (data
.length() <= len
) {
4148 data
.append_zero(len
- data
.length());
4151 data
.copy(0, len
, bl
);
4155 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4156 int status
= store
->queue_transaction(ch
, std::move(t
));
4161 Mutex::Locker
locker(lock
);
4162 EnterExit
ee("zero");
4167 ghobject_t new_obj
= get_uniform_random_object();
4168 available_objects
.erase(new_obj
);
4169 ObjectStore::Transaction t
;
4171 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4172 boost::uniform_int
<> u2(0, max_write_len
);
4173 uint64_t offset
= u1(*rng
);
4174 uint64_t len
= u2(*rng
);
4175 if (write_alignment
) {
4176 offset
= round_up_to(offset
, write_alignment
);
4177 len
= round_up_to(len
, write_alignment
);
4181 auto& data
= contents
[new_obj
].data
;
4182 if (data
.length() < offset
+ len
) {
4183 data
.append_zero(offset
+len
-data
.length());
4186 n
.substr_of(data
, 0, offset
);
4188 if (data
.length() > offset
+ len
)
4189 data
.copy(offset
+ len
, data
.length() - offset
- len
, n
);
4193 t
.zero(cid
, new_obj
, offset
, len
);
4195 in_flight_objects
.insert(new_obj
);
4196 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4197 int status
= store
->queue_transaction(ch
, std::move(t
));
4202 EnterExit
ee("read");
4203 boost::uniform_int
<> u1(0, max_object_len
/2);
4204 boost::uniform_int
<> u2(0, max_object_len
);
4205 uint64_t offset
= u1(*rng
);
4206 uint64_t len
= u2(*rng
);
4211 bufferlist expected
;
4214 Mutex::Locker
locker(lock
);
4215 EnterExit
ee("read locked");
4220 obj
= get_uniform_random_object();
4221 expected
= contents
[obj
].data
;
4223 bufferlist bl
, result
;
4224 if (0) cout
<< " obj " << obj
4225 << " size " << expected
.length()
4226 << " offset " << offset
4227 << " len " << len
<< std::endl
;
4228 r
= store
->read(ch
, obj
, offset
, len
, result
);
4229 if (offset
>= expected
.length()) {
4232 size_t max_len
= expected
.length() - offset
;
4235 ceph_assert(len
== result
.length());
4236 ASSERT_EQ(len
, result
.length());
4237 expected
.copy(offset
, len
, bl
);
4238 ASSERT_EQ(r
, (int)len
);
4239 ASSERT_TRUE(bl_eq(bl
, result
));
4244 Mutex::Locker
locker(lock
);
4245 EnterExit
ee("setattrs");
4250 ghobject_t obj
= get_uniform_random_object();
4251 available_objects
.erase(obj
);
4252 ObjectStore::Transaction t
;
4254 boost::uniform_int
<> u0(1, max_attr_size
);
4255 boost::uniform_int
<> u1(4, max_attr_name_len
);
4256 boost::uniform_int
<> u2(4, max_attr_value_len
);
4257 boost::uniform_int
<> u3(0, 100);
4258 uint64_t size
= u0(*rng
);
4260 map
<string
, bufferlist
> attrs
;
4262 for (map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4263 it
!= contents
[obj
].attrs
.end(); ++it
)
4264 keys
.insert(it
->first
);
4267 bufferlist name
, value
;
4268 uint64_t get_exist
= u3(*rng
);
4269 uint64_t value_len
= u2(*rng
);
4270 filled_byte_array(value
, value_len
);
4271 if (get_exist
< 50 && keys
.size()) {
4272 set
<string
>::iterator k
= keys
.begin();
4274 contents
[obj
].attrs
[*k
] = value
;
4277 name_len
= u1(*rng
);
4278 filled_byte_array(name
, name_len
);
4279 attrs
[name
.c_str()] = value
;
4280 contents
[obj
].attrs
[name
.c_str()] = value
;
4283 t
.setattrs(cid
, obj
, attrs
);
4285 in_flight_objects
.insert(obj
);
4286 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4287 int status
= store
->queue_transaction(ch
, std::move(t
));
4292 EnterExit
ee("getattrs");
4294 map
<string
, bufferlist
> expected
;
4296 Mutex::Locker
locker(lock
);
4297 EnterExit
ee("getattrs locked");
4304 obj
= get_uniform_random_object();
4307 } while (contents
[obj
].attrs
.empty());
4308 expected
= contents
[obj
].attrs
;
4310 map
<string
, bufferlist
> attrs
;
4311 int r
= store
->getattrs(ch
, obj
, attrs
);
4312 ASSERT_TRUE(r
== 0);
4313 ASSERT_TRUE(attrs
.size() == expected
.size());
4314 for (map
<string
, bufferlist
>::iterator it
= expected
.begin();
4315 it
!= expected
.end(); ++it
) {
4316 ASSERT_TRUE(bl_eq(attrs
[it
->first
], it
->second
));
4321 EnterExit
ee("getattr");
4325 map
<string
, bufferlist
> expected
;
4327 Mutex::Locker
locker(lock
);
4328 EnterExit
ee("getattr locked");
4335 obj
= get_uniform_random_object();
4338 } while (contents
[obj
].attrs
.empty());
4339 expected
= contents
[obj
].attrs
;
4341 boost::uniform_int
<> u(0, expected
.size()-1);
4343 map
<string
, bufferlist
>::iterator it
= expected
.begin();
4350 r
= store
->getattr(ch
, obj
, it
->first
, bl
);
4352 ASSERT_TRUE(bl_eq(it
->second
, bl
));
4356 Mutex::Locker
locker(lock
);
4357 EnterExit
ee("rmattr");
4365 obj
= get_uniform_random_object();
4368 } while (contents
[obj
].attrs
.empty());
4370 boost::uniform_int
<> u(0, contents
[obj
].attrs
.size()-1);
4372 map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4378 available_objects
.erase(obj
);
4379 ObjectStore::Transaction t
;
4380 t
.rmattr(cid
, obj
, it
->first
);
4382 contents
[obj
].attrs
.erase(it
->first
);
4384 in_flight_objects
.insert(obj
);
4385 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4386 int status
= store
->queue_transaction(ch
, std::move(t
));
4390 void fsck(bool deep
) {
4391 Mutex::Locker
locker(lock
);
4392 EnterExit
ee("fsck");
4397 int r
= store
->fsck(deep
);
4398 ceph_assert(r
== 0 || r
== -EOPNOTSUPP
);
4400 ch
= store
->open_collection(cid
);
4404 Mutex::Locker
locker(lock
);
4405 EnterExit
ee("scan");
4408 vector
<ghobject_t
> objects
;
4409 set
<ghobject_t
> objects_set
, objects_set2
;
4410 ghobject_t next
, current
;
4412 //cerr << "scanning..." << std::endl;
4413 int r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 100,
4416 ASSERT_TRUE(sorted(objects
));
4417 objects_set
.insert(objects
.begin(), objects
.end());
4419 if (next
.is_max()) break;
4422 if (objects_set
.size() != available_objects
.size()) {
4423 for (set
<ghobject_t
>::iterator p
= objects_set
.begin();
4424 p
!= objects_set
.end();
4426 if (available_objects
.count(*p
) == 0) {
4427 cerr
<< "+ " << *p
<< std::endl
;
4430 for (set
<ghobject_t
>::iterator p
= available_objects
.begin();
4431 p
!= available_objects
.end();
4433 if (objects_set
.count(*p
) == 0)
4434 cerr
<< "- " << *p
<< std::endl
;
4435 //cerr << " objects_set: " << objects_set << std::endl;
4436 //cerr << " available_set: " << available_objects << std::endl;
4437 ceph_abort_msg("badness");
4440 ASSERT_EQ(objects_set
.size(), available_objects
.size());
4441 for (set
<ghobject_t
>::iterator i
= objects_set
.begin();
4442 i
!= objects_set
.end();
4444 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
4447 int r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
4448 INT_MAX
, &objects
, 0);
4450 objects_set2
.insert(objects
.begin(), objects
.end());
4451 ASSERT_EQ(objects_set2
.size(), available_objects
.size());
4452 for (set
<ghobject_t
>::iterator i
= objects_set2
.begin();
4453 i
!= objects_set2
.end();
4455 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
4456 if (available_objects
.count(*i
) == 0) {
4457 cerr
<< "+ " << *i
<< std::endl
;
4463 EnterExit
ee("stat");
4467 Mutex::Locker
locker(lock
);
4468 EnterExit
ee("stat lock1");
4471 hoid
= get_uniform_random_object();
4472 in_flight_objects
.insert(hoid
);
4473 available_objects
.erase(hoid
);
4475 expected
= contents
[hoid
].data
.length();
4478 int r
= store
->stat(ch
, hoid
, &buf
);
4480 ceph_assert((uint64_t)buf
.st_size
== expected
);
4481 ASSERT_TRUE((uint64_t)buf
.st_size
== expected
);
4483 Mutex::Locker
locker(lock
);
4484 EnterExit
ee("stat lock2");
4487 in_flight_objects
.erase(hoid
);
4488 available_objects
.insert(hoid
);
4493 Mutex::Locker
locker(lock
);
4494 EnterExit
ee("unlink");
4497 ghobject_t to_remove
= get_uniform_random_object();
4498 ObjectStore::Transaction t
;
4499 t
.remove(cid
, to_remove
);
4501 available_objects
.erase(to_remove
);
4502 in_flight_objects
.insert(to_remove
);
4503 contents
.erase(to_remove
);
4504 t
.register_on_applied(new C_SyntheticOnReadable(this, to_remove
));
4505 int status
= store
->queue_transaction(ch
, std::move(t
));
4509 void print_internal_state() {
4510 Mutex::Locker
locker(lock
);
4511 cerr
<< "available_objects: " << available_objects
.size()
4512 << " in_flight_objects: " << in_flight_objects
.size()
4513 << " total objects: " << in_flight_objects
.size() + available_objects
.size()
4514 << " in_flight " << in_flight
<< std::endl
;
4519 void StoreTest::doSyntheticTest(
4521 uint64_t max_obj
, uint64_t max_wr
, uint64_t align
)
4523 MixedGenerator
gen(555);
4524 gen_type
rng(time(NULL
));
4525 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
4527 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
4528 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
4529 g_ceph_context
->_conf
.apply_changes(nullptr);
4531 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
,
4532 max_obj
, max_wr
, align
);
4534 for (int i
= 0; i
< num_ops
/10; ++i
) {
4535 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
4538 for (int i
= 0; i
< num_ops
; ++i
) {
4540 cerr
<< "Op " << i
<< std::endl
;
4541 test_obj
.print_internal_state();
4543 boost::uniform_int
<> true_false(0, 999);
4544 int val
= true_false(rng
);
4546 test_obj
.fsck(true);
4547 } else if (val
> 997) {
4548 test_obj
.fsck(false);
4549 } else if (val
> 970) {
4551 } else if (val
> 950) {
4553 } else if (val
> 850) {
4555 } else if (val
> 800) {
4557 } else if (val
> 550) {
4559 } else if (val
> 500) {
4561 } else if (val
> 450) {
4562 test_obj
.clone_range();
4563 } else if (val
> 300) {
4565 } else if (val
> 100) {
4568 test_obj
.truncate();
4571 test_obj
.wait_for_done();
4572 test_obj
.shutdown();
4575 TEST_P(StoreTest
, Synthetic
) {
4576 doSyntheticTest(10000, 400*1024, 40*1024, 0);
4579 TEST_P(StoreTestSpecificAUSize
, BlueFSExtenderTest
) {
4580 if(string(GetParam()) != "bluestore")
4583 SetVal(g_conf(), "bluestore_block_db_size", "0");
4584 SetVal(g_conf(), "bluestore_block_wal_size", "0");
4585 SetVal(g_conf(), "bluestore_bluefs_min", "12582912");
4586 SetVal(g_conf(), "bluestore_bluefs_min_free", "4194304");
4587 SetVal(g_conf(), "bluestore_bluefs_gift_ratio", "0");
4588 SetVal(g_conf(), "bluestore_bluefs_min_ratio", "0");
4589 SetVal(g_conf(), "bluestore_bluefs_balance_interval", "100000");
4590 SetVal(g_conf(), "bluestore_bluefs_db_compatibility", "false");
4592 g_conf().apply_changes(nullptr);
4594 StartDeferred(4096);
4596 doSyntheticTest(10000, 400*1024, 40*1024, 0);
4598 BlueStore
* bstore
= NULL
;
4599 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
4601 // verify downgrades are broken and repair that
4603 ASSERT_EQ(bstore
->fsck(false), 0);
4605 SetVal(g_conf(), "bluestore_bluefs_db_compatibility", "true");
4606 g_conf().apply_changes(nullptr);
4608 ASSERT_EQ(bstore
->fsck(false), 1);
4609 ASSERT_EQ(bstore
->repair(false), 0);
4610 ASSERT_EQ(bstore
->fsck(false), 0);
4614 #if defined(WITH_BLUESTORE)
4615 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixSharding
) {
4616 if (string(GetParam()) != "bluestore")
4619 const char *m
[][10] = {
4620 { "bluestore_min_alloc_size", "4096", 0 }, // must be the first!
4621 { "num_ops", "50000", 0 },
4622 { "max_write", "65536", 0 },
4623 { "max_size", "262144", 0 },
4624 { "alignment", "4096", 0 },
4625 { "bluestore_max_blob_size", "65536", 0 },
4626 { "bluestore_extent_map_shard_min_size", "60", 0 },
4627 { "bluestore_extent_map_shard_max_size", "300", 0 },
4628 { "bluestore_extent_map_shard_target_size", "150", 0 },
4629 { "bluestore_default_buffered_read", "true", 0 },
4630 { "bluestore_default_buffered_write", "true", 0 },
4633 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4636 TEST_P(StoreTestSpecificAUSize
, ZipperPatternSharded
) {
4637 if(string(GetParam()) != "bluestore")
4639 StartDeferred(4096);
4643 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
4644 auto ch
= store
->create_new_collection(cid
);
4646 ObjectStore::Transaction t
;
4647 t
.create_collection(cid
, 0);
4648 cerr
<< "Creating collection " << cid
<< std::endl
;
4649 r
= queue_transaction(store
, ch
, std::move(t
));
4657 for (int i
=0; i
<1000; ++i
) {
4658 ObjectStore::Transaction t
;
4659 t
.write(cid
, a
, i
*2*len
, len
, bl
, 0);
4660 r
= queue_transaction(store
, ch
, std::move(t
));
4663 for (int i
=0; i
<1000; ++i
) {
4664 ObjectStore::Transaction t
;
4665 t
.write(cid
, a
, i
*2*len
+ 1, len
, bl
, 0);
4666 r
= queue_transaction(store
, ch
, std::move(t
));
4670 ObjectStore::Transaction t
;
4672 t
.remove_collection(cid
);
4673 cerr
<< "Cleaning" << std::endl
;
4674 r
= queue_transaction(store
, ch
, std::move(t
));
4679 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumAlgorithm
) {
4680 if (string(GetParam()) != "bluestore")
4683 const char *m
[][10] = {
4684 { "bluestore_min_alloc_size", "65536", 0 }, // must be the first!
4685 { "max_write", "65536", 0 },
4686 { "max_size", "1048576", 0 },
4687 { "alignment", "16", 0 },
4688 { "bluestore_csum_type", "crc32c", "crc32c_16", "crc32c_8", "xxhash32",
4689 "xxhash64", "none", 0 },
4690 { "bluestore_default_buffered_write", "false", 0 },
4693 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4696 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumVsCompression
) {
4697 if (string(GetParam()) != "bluestore")
4700 const char *m
[][10] = {
4701 { "bluestore_min_alloc_size", "4096", "16384", 0 }, //to be the first!
4702 { "max_write", "131072", 0 },
4703 { "max_size", "262144", 0 },
4704 { "alignment", "512", 0 },
4705 { "bluestore_compression_mode", "force", 0},
4706 { "bluestore_compression_algorithm", "snappy", "zlib", 0 },
4707 { "bluestore_csum_type", "crc32c", 0 },
4708 { "bluestore_default_buffered_read", "true", "false", 0 },
4709 { "bluestore_default_buffered_write", "true", "false", 0 },
4710 { "bluestore_sync_submit_transaction", "false", 0 },
4713 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4716 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompression
) {
4717 if (string(GetParam()) != "bluestore")
4720 const char *m
[][10] = {
4721 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4722 { "max_write", "1048576", 0 },
4723 { "max_size", "4194304", 0 },
4724 { "alignment", "65536", 0 },
4725 { "bluestore_compression_mode", "force", "aggressive", "passive", "none", 0},
4726 { "bluestore_default_buffered_write", "false", 0 },
4727 { "bluestore_sync_submit_transaction", "true", 0 },
4730 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4733 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompressionAlgorithm
) {
4734 if (string(GetParam()) != "bluestore")
4737 const char *m
[][10] = {
4738 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4739 { "max_write", "1048576", 0 },
4740 { "max_size", "4194304", 0 },
4741 { "alignment", "65536", 0 },
4742 { "bluestore_compression_algorithm", "zlib", "snappy", 0 },
4743 { "bluestore_compression_mode", "force", 0 },
4744 { "bluestore_default_buffered_write", "false", 0 },
4747 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4750 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixNoCsum
) {
4751 if (string(GetParam()) != "bluestore")
4754 const char *m
[][10] = {
4755 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4756 { "max_write", "65536", 0 },
4757 { "max_size", "1048576", 0 },
4758 { "alignment", "512", 0 },
4759 { "bluestore_max_blob_size", "262144", 0 },
4760 { "bluestore_compression_mode", "force", "none", 0},
4761 { "bluestore_csum_type", "none", 0},
4762 { "bluestore_default_buffered_read", "true", "false", 0 },
4763 { "bluestore_default_buffered_write", "true", 0 },
4764 { "bluestore_sync_submit_transaction", "true", "false", 0 },
4767 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4770 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixPreferDeferred
) {
4771 if (string(GetParam()) != "bluestore")
4774 const char *m
[][10] = {
4775 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4776 { "max_write", "65536", 0 },
4777 { "max_size", "1048576", 0 },
4778 { "alignment", "512", 0 },
4779 { "bluestore_max_blob_size", "262144", 0 },
4780 { "bluestore_compression_mode", "force", "none", 0},
4781 { "bluestore_prefer_deferred_size", "32768", "0", 0},
4784 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4786 #endif // WITH_BLUESTORE
4788 TEST_P(StoreTest
, AttrSynthetic
) {
4789 MixedGenerator
gen(447);
4790 gen_type
rng(time(NULL
));
4791 coll_t
cid(spg_t(pg_t(0,447),shard_id_t::NO_SHARD
));
4793 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
, 40*1024, 4*1024, 0);
4795 for (int i
= 0; i
< 500; ++i
) {
4796 if (!(i
% 10)) cerr
<< "seeding object " << i
<< std::endl
;
4799 for (int i
= 0; i
< 1000; ++i
) {
4801 cerr
<< "Op " << i
<< std::endl
;
4802 test_obj
.print_internal_state();
4804 boost::uniform_int
<> true_false(0, 99);
4805 int val
= true_false(rng
);
4808 } else if (val
> 93) {
4810 } else if (val
> 75) {
4812 } else if (val
> 47) {
4813 test_obj
.setattrs();
4814 } else if (val
> 45) {
4816 } else if (val
> 37) {
4818 } else if (val
> 30) {
4819 test_obj
.getattrs();
4824 test_obj
.wait_for_done();
4825 test_obj
.shutdown();
4828 TEST_P(StoreTest
, HashCollisionTest
) {
4829 int64_t poolid
= 11;
4830 coll_t
cid(spg_t(pg_t(0,poolid
),shard_id_t::NO_SHARD
));
4832 auto ch
= store
->create_new_collection(cid
);
4834 ObjectStore::Transaction t
;
4835 t
.create_collection(cid
, 0);
4836 r
= queue_transaction(store
, ch
, std::move(t
));
4840 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
4841 set
<ghobject_t
> created
;
4842 for (int n
= 0; n
< 10; ++n
) {
4844 sprintf(nbuf
, "n%d", n
);
4845 for (int i
= 0; i
< 1000; ++i
) {
4847 sprintf(buf
, "%d", i
);
4849 cerr
<< "Object n" << n
<< " "<< i
<< std::endl
;
4851 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, 0, poolid
, string(nbuf
)));
4853 ObjectStore::Transaction t
;
4855 r
= queue_transaction(store
, ch
, std::move(t
));
4858 created
.insert(hoid
);
4861 vector
<ghobject_t
> objects
;
4862 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
, &objects
, 0);
4864 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
4865 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
4866 ASSERT_TRUE(listed
.size() == created
.size());
4869 ghobject_t current
, next
;
4871 r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 60,
4874 ASSERT_TRUE(sorted(objects
));
4875 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
4878 if (listed
.count(*i
))
4879 cerr
<< *i
<< " repeated" << std::endl
;
4882 if (objects
.size() < 50) {
4883 ASSERT_TRUE(next
.is_max());
4889 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
4890 ASSERT_TRUE(listed
.size() == created
.size());
4891 for (set
<ghobject_t
>::iterator i
= listed
.begin();
4894 ASSERT_TRUE(created
.count(*i
));
4897 for (set
<ghobject_t
>::iterator i
= created
.begin();
4900 ObjectStore::Transaction t
;
4902 r
= queue_transaction(store
, ch
, std::move(t
));
4905 ObjectStore::Transaction t
;
4906 t
.remove_collection(cid
);
4907 r
= queue_transaction(store
, ch
, std::move(t
));
4911 TEST_P(StoreTest
, ScrubTest
) {
4912 int64_t poolid
= 111;
4913 coll_t
cid(spg_t(pg_t(0, poolid
),shard_id_t(1)));
4915 auto ch
= store
->create_new_collection(cid
);
4917 ObjectStore::Transaction t
;
4918 t
.create_collection(cid
, 0);
4919 r
= queue_transaction(store
, ch
, std::move(t
));
4922 string base
= "aaaaa";
4923 set
<ghobject_t
> created
;
4924 for (int i
= 0; i
< 1000; ++i
) {
4926 sprintf(buf
, "%d", i
);
4928 cerr
<< "Object " << i
<< std::endl
;
4930 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, i
,
4932 ghobject_t::NO_GEN
, shard_id_t(1));
4934 ObjectStore::Transaction t
;
4936 r
= queue_transaction(store
, ch
, std::move(t
));
4939 created
.insert(hoid
);
4942 // Add same hobject_t but different generation
4944 ghobject_t
hoid1(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""),
4945 ghobject_t::NO_GEN
, shard_id_t(1));
4946 ghobject_t
hoid2(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)1, shard_id_t(1));
4947 ghobject_t
hoid3(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)2, shard_id_t(1));
4948 ObjectStore::Transaction t
;
4949 t
.touch(cid
, hoid1
);
4950 t
.touch(cid
, hoid2
);
4951 t
.touch(cid
, hoid3
);
4952 r
= queue_transaction(store
, ch
, std::move(t
));
4953 created
.insert(hoid1
);
4954 created
.insert(hoid2
);
4955 created
.insert(hoid3
);
4959 vector
<ghobject_t
> objects
;
4960 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
4961 INT_MAX
, &objects
, 0);
4963 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
4964 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
4965 ASSERT_TRUE(listed
.size() == created
.size());
4968 ghobject_t current
, next
;
4970 r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 60,
4973 ASSERT_TRUE(sorted(objects
));
4974 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
4975 i
!= objects
.end(); ++i
) {
4976 if (listed
.count(*i
))
4977 cerr
<< *i
<< " repeated" << std::endl
;
4980 if (objects
.size() < 50) {
4981 ASSERT_TRUE(next
.is_max());
4985 current
= next
.get_boundary();
4987 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
4988 ASSERT_TRUE(listed
.size() == created
.size());
4989 for (set
<ghobject_t
>::iterator i
= listed
.begin();
4992 ASSERT_TRUE(created
.count(*i
));
4995 for (set
<ghobject_t
>::iterator i
= created
.begin();
4998 ObjectStore::Transaction t
;
5000 r
= queue_transaction(store
, ch
, std::move(t
));
5003 ObjectStore::Transaction t
;
5004 t
.remove_collection(cid
);
5005 r
= queue_transaction(store
, ch
, std::move(t
));
5010 TEST_P(StoreTest
, OMapTest
) {
5012 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5013 auto ch
= store
->create_new_collection(cid
);
5016 ObjectStore::Transaction t
;
5017 t
.create_collection(cid
, 0);
5018 r
= queue_transaction(store
, ch
, std::move(t
));
5022 map
<string
, bufferlist
> attrs
;
5024 ObjectStore::Transaction t
;
5026 t
.omap_clear(cid
, hoid
);
5027 map
<string
, bufferlist
> start_set
;
5028 t
.omap_setkeys(cid
, hoid
, start_set
);
5029 r
= queue_transaction(store
, ch
, std::move(t
));
5033 for (int i
= 0; i
< 100; i
++) {
5035 std::cout
<< "On iteration " << i
<< std::endl
;
5037 ObjectStore::Transaction t
;
5039 map
<string
, bufferlist
> cur_attrs
;
5040 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5042 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5045 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5047 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5048 if (cur_attrs
.count(j
->first
) > 0) {
5049 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5052 ASSERT_EQ(correct
, true);
5054 ASSERT_EQ(attrs
.size(), cur_attrs
.size());
5057 snprintf(buf
, sizeof(buf
), "%d", i
);
5059 bufferptr
bp(buf
, strlen(buf
) + 1);
5061 map
<string
, bufferlist
> to_add
;
5062 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5063 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5064 t
.omap_setkeys(cid
, hoid
, to_add
);
5065 r
= queue_transaction(store
, ch
, std::move(t
));
5070 while (attrs
.size()) {
5072 std::cout
<< "removal: On iteration " << i
<< std::endl
;
5074 ObjectStore::Transaction t
;
5076 map
<string
, bufferlist
> cur_attrs
;
5077 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5079 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5082 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5084 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5085 if (cur_attrs
.count(j
->first
) > 0) {
5086 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5089 ASSERT_EQ(correct
, true);
5092 string to_remove
= attrs
.begin()->first
;
5093 set
<string
> keys_to_remove
;
5094 keys_to_remove
.insert(to_remove
);
5095 t
.omap_rmkeys(cid
, hoid
, keys_to_remove
);
5096 r
= queue_transaction(store
, ch
, std::move(t
));
5099 attrs
.erase(to_remove
);
5106 bl1
.append("omap_header");
5107 ObjectStore::Transaction t
;
5108 t
.omap_setheader(cid
, hoid
, bl1
);
5109 r
= queue_transaction(store
, ch
, std::move(t
));
5111 t
= ObjectStore::Transaction();
5114 bl2
.append("value");
5115 map
<string
, bufferlist
> to_add
;
5116 to_add
.insert(pair
<string
, bufferlist
>("key", bl2
));
5117 t
.omap_setkeys(cid
, hoid
, to_add
);
5118 r
= queue_transaction(store
, ch
, std::move(t
));
5122 map
<string
, bufferlist
> cur_attrs
;
5123 r
= store
->omap_get(ch
, hoid
, &bl3
, &cur_attrs
);
5125 ASSERT_EQ(cur_attrs
.size(), size_t(1));
5126 ASSERT_TRUE(bl_eq(bl1
, bl3
));
5129 r
= store
->omap_get_keys(ch
, hoid
, &keys
);
5131 ASSERT_EQ(keys
.size(), size_t(1));
5134 // test omap_clear, omap_rmkey_range
5137 map
<string
,bufferlist
> to_set
;
5138 for (int n
=0; n
<10; ++n
) {
5139 to_set
[stringify(n
)].append("foo");
5143 ObjectStore::Transaction t
;
5144 t
.remove(cid
, hoid
);
5146 t
.omap_setheader(cid
, hoid
, h
);
5147 t
.omap_setkeys(cid
, hoid
, to_set
);
5148 r
= queue_transaction(store
, ch
, std::move(t
));
5152 ObjectStore::Transaction t
;
5153 t
.omap_rmkeyrange(cid
, hoid
, "3", "7");
5154 r
= queue_transaction(store
, ch
, std::move(t
));
5159 map
<string
,bufferlist
> m
;
5160 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5161 ASSERT_EQ(6u, hdr
.length());
5162 ASSERT_TRUE(m
.count("2"));
5163 ASSERT_TRUE(!m
.count("3"));
5164 ASSERT_TRUE(!m
.count("6"));
5165 ASSERT_TRUE(m
.count("7"));
5166 ASSERT_TRUE(m
.count("8"));
5167 //cout << m << std::endl;
5168 ASSERT_EQ(6u, m
.size());
5171 ObjectStore::Transaction t
;
5172 t
.omap_clear(cid
, hoid
);
5173 r
= queue_transaction(store
, ch
, std::move(t
));
5178 map
<string
,bufferlist
> m
;
5179 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5180 ASSERT_EQ(0u, hdr
.length());
5181 ASSERT_EQ(0u, m
.size());
5185 ObjectStore::Transaction t
;
5186 t
.remove(cid
, hoid
);
5187 t
.remove_collection(cid
);
5188 r
= queue_transaction(store
, ch
, std::move(t
));
5192 TEST_P(StoreTest
, OMapIterator
) {
5194 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5196 auto ch
= store
->create_new_collection(cid
);
5199 ObjectStore::Transaction t
;
5200 t
.create_collection(cid
, 0);
5201 r
= queue_transaction(store
, ch
, std::move(t
));
5205 map
<string
, bufferlist
> attrs
;
5207 ObjectStore::Transaction t
;
5209 t
.omap_clear(cid
, hoid
);
5210 map
<string
, bufferlist
> start_set
;
5211 t
.omap_setkeys(cid
, hoid
, start_set
);
5212 r
= queue_transaction(store
, ch
, std::move(t
));
5215 ObjectMap::ObjectMapIterator iter
;
5218 for (int i
= 0; i
< 100; i
++) {
5220 std::cout
<< "On iteration " << i
<< std::endl
;
5224 // FileStore may deadlock two active iterators over the same data
5225 iter
= ObjectMap::ObjectMapIterator();
5227 iter
= store
->get_omap_iterator(ch
, hoid
);
5228 for (iter
->seek_to_first(), count
=0; iter
->valid(); iter
->next(), count
++) {
5229 string key
= iter
->key();
5230 bufferlist value
= iter
->value();
5231 correct
= attrs
.count(key
) && (string(value
.c_str()) == string(attrs
[key
].c_str()));
5233 if (attrs
.count(key
) > 0) {
5234 std::cout
<< "key " << key
<< "in omap , " << value
.c_str() << " : " << attrs
[key
].c_str() << std::endl
;
5237 std::cout
<< "key " << key
<< "should not exists in omap" << std::endl
;
5239 ASSERT_EQ(correct
, true);
5241 ASSERT_EQ((int)attrs
.size(), count
);
5243 // FileStore may deadlock an active iterator vs queue_transaction
5244 iter
= ObjectMap::ObjectMapIterator();
5247 snprintf(buf
, sizeof(buf
), "%d", i
);
5249 bufferptr
bp(buf
, strlen(buf
) + 1);
5251 map
<string
, bufferlist
> to_add
;
5252 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5253 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5254 ObjectStore::Transaction t
;
5255 t
.omap_setkeys(cid
, hoid
, to_add
);
5256 r
= queue_transaction(store
, ch
, std::move(t
));
5260 iter
= store
->get_omap_iterator(ch
, hoid
);
5262 string bound_key
= "key-5";
5263 iter
->lower_bound(bound_key
);
5264 correct
= bound_key
<= iter
->key();
5266 std::cout
<< "lower bound, bound key is " << bound_key
<< " < iter key is " << iter
->key() << std::endl
;
5268 ASSERT_EQ(correct
, true);
5270 iter
->upper_bound(bound_key
);
5271 correct
= iter
->key() > bound_key
;
5273 std::cout
<< "upper bound, bound key is " << bound_key
<< " >= iter key is " << iter
->key() << std::endl
;
5275 ASSERT_EQ(correct
, true);
5277 // FileStore may deadlock an active iterator vs queue_transaction
5278 iter
= ObjectMap::ObjectMapIterator();
5280 ObjectStore::Transaction t
;
5281 t
.remove(cid
, hoid
);
5282 t
.remove_collection(cid
);
5283 r
= queue_transaction(store
, ch
, std::move(t
));
5288 TEST_P(StoreTest
, XattrTest
) {
5290 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5292 for (unsigned i
= 0; i
< 10000; ++i
) {
5296 for (unsigned i
= 0; i
< 10; ++i
) {
5300 auto ch
= store
->create_new_collection(cid
);
5302 ObjectStore::Transaction t
;
5303 t
.create_collection(cid
, 0);
5305 r
= queue_transaction(store
, ch
, std::move(t
));
5309 map
<string
, bufferlist
> attrs
;
5311 ObjectStore::Transaction t
;
5312 t
.setattr(cid
, hoid
, "attr1", small
);
5313 attrs
["attr1"] = small
;
5314 t
.setattr(cid
, hoid
, "attr2", big
);
5315 attrs
["attr2"] = big
;
5316 t
.setattr(cid
, hoid
, "attr3", small
);
5317 attrs
["attr3"] = small
;
5318 t
.setattr(cid
, hoid
, "attr1", small
);
5319 attrs
["attr1"] = small
;
5320 t
.setattr(cid
, hoid
, "attr4", big
);
5321 attrs
["attr4"] = big
;
5322 t
.setattr(cid
, hoid
, "attr3", big
);
5323 attrs
["attr3"] = big
;
5324 r
= queue_transaction(store
, ch
, std::move(t
));
5328 map
<string
, bufferptr
> aset
;
5329 store
->getattrs(ch
, hoid
, aset
);
5330 ASSERT_EQ(aset
.size(), attrs
.size());
5331 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
5335 bl
.push_back(i
->second
);
5336 ASSERT_TRUE(attrs
[i
->first
] == bl
);
5340 ObjectStore::Transaction t
;
5341 t
.rmattr(cid
, hoid
, "attr2");
5342 attrs
.erase("attr2");
5343 r
= queue_transaction(store
, ch
, std::move(t
));
5348 store
->getattrs(ch
, hoid
, aset
);
5349 ASSERT_EQ(aset
.size(), attrs
.size());
5350 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
5354 bl
.push_back(i
->second
);
5355 ASSERT_TRUE(attrs
[i
->first
] == bl
);
5359 r
= store
->getattr(ch
, hoid
, "attr2", bp
);
5360 ASSERT_EQ(r
, -ENODATA
);
5362 r
= store
->getattr(ch
, hoid
, "attr3", bp
);
5366 ASSERT_TRUE(bl2
== attrs
["attr3"]);
5368 ObjectStore::Transaction t
;
5369 t
.remove(cid
, hoid
);
5370 t
.remove_collection(cid
);
5371 r
= queue_transaction(store
, ch
, std::move(t
));
5377 unsigned num_objects
,
5378 unsigned common_suffix_size
,
5381 coll_t
cid(spg_t(pg_t(0,52),shard_id_t::NO_SHARD
));
5382 coll_t
tid(spg_t(pg_t(1<<common_suffix_size
,52),shard_id_t::NO_SHARD
));
5383 auto ch
= store
->create_new_collection(cid
);
5384 auto tch
= store
->create_new_collection(tid
);
5387 ObjectStore::Transaction t
;
5388 t
.create_collection(cid
, common_suffix_size
);
5389 r
= queue_transaction(store
, ch
, std::move(t
));
5393 small
.append("small");
5395 ObjectStore::Transaction t
;
5396 for (uint32_t i
= 0; i
< (2 - (int)clones
)*num_objects
; ++i
) {
5397 stringstream objname
;
5398 objname
<< "obj" << i
;
5399 ghobject_t
a(hobject_t(
5403 i
<<common_suffix_size
,
5405 t
.write(cid
, a
, 0, small
.length(), small
,
5406 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
5408 objname
<< "-clone";
5409 ghobject_t
b(hobject_t(
5413 i
<<common_suffix_size
,
5418 r
= queue_transaction(store
, ch
, std::move(t
));
5420 t
= ObjectStore::Transaction();
5423 r
= queue_transaction(store
, ch
, std::move(t
));
5427 ObjectStore::Transaction t
;
5428 t
.create_collection(tid
, common_suffix_size
+ 1);
5429 t
.split_collection(cid
, common_suffix_size
+1, 1<<common_suffix_size
, tid
);
5430 r
= queue_transaction(store
, ch
, std::move(t
));
5436 vector
<ghobject_t
> objects
;
5437 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
5438 INT_MAX
, &objects
, 0);
5440 ASSERT_EQ(objects
.size(), num_objects
);
5441 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5444 ASSERT_EQ(!!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
5448 r
= store
->collection_list(tch
, ghobject_t(), ghobject_t::get_max(),
5449 INT_MAX
, &objects
, 0);
5451 ASSERT_EQ(objects
.size(), num_objects
);
5452 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5455 ASSERT_EQ(!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
5458 // merge them again!
5460 ObjectStore::Transaction t
;
5461 t
.merge_collection(tid
, cid
, common_suffix_size
);
5462 r
= queue_transaction(store
, ch
, std::move(t
));
5466 // check and clean up
5467 ObjectStore::Transaction t
;
5469 vector
<ghobject_t
> objects
;
5470 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
5471 INT_MAX
, &objects
, 0);
5473 ASSERT_EQ(objects
.size(), num_objects
* 2); // both halves
5475 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5481 r
= queue_transaction(store
, ch
, std::move(t
));
5483 t
= ObjectStore::Transaction();
5487 t
.remove_collection(cid
);
5488 r
= queue_transaction(store
, ch
, std::move(t
));
5492 ASSERT_TRUE(!store
->collection_exists(tid
));
5495 TEST_P(StoreTest
, ColSplitTest0
) {
5496 colsplittest(store
.get(), 10, 5, false);
5498 TEST_P(StoreTest
, ColSplitTest1
) {
5499 colsplittest(store
.get(), 10000, 11, false);
5501 TEST_P(StoreTest
, ColSplitTest1Clones
) {
5502 colsplittest(store
.get(), 10000, 11, true);
5504 TEST_P(StoreTest
, ColSplitTest2
) {
5505 colsplittest(store
.get(), 100, 7, false);
5507 TEST_P(StoreTest
, ColSplitTest2Clones
) {
5508 colsplittest(store
.get(), 100, 7, true);
5512 TEST_P(StoreTest
, ColSplitTest3
) {
5513 colsplittest(store
.get(), 100000, 25);
5517 void test_merge_skewed(ObjectStore
*store
,
5518 unsigned base
, unsigned bits
,
5519 unsigned anum
, unsigned bnum
)
5521 cout
<< __func__
<< " 0x" << std::hex
<< base
<< std::dec
5523 << " anum " << anum
<< " bnum " << bnum
<< std::endl
;
5525 make merge source pgs have radically different # of objects in them,
5526 which should trigger different splitting in filestore, and verify that
5527 post-merge all objects are accessible.
5530 coll_t
a(spg_t(pg_t(base
, 0), shard_id_t::NO_SHARD
));
5531 coll_t
b(spg_t(pg_t(base
| (1<<bits
), 0), shard_id_t::NO_SHARD
));
5533 auto cha
= store
->create_new_collection(a
);
5534 auto chb
= store
->create_new_collection(b
);
5536 ObjectStore::Transaction t
;
5537 t
.create_collection(a
, bits
+ 1);
5538 r
= queue_transaction(store
, cha
, std::move(t
));
5542 ObjectStore::Transaction t
;
5543 t
.create_collection(b
, bits
+ 1);
5544 r
= queue_transaction(store
, chb
, std::move(t
));
5549 small
.append("small");
5550 string suffix
= "ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooaaaaaaaaaa";
5551 set
<ghobject_t
> aobjects
, bobjects
;
5554 ObjectStore::Transaction t
;
5555 for (unsigned i
= 0; i
< 1000; ++i
) {
5556 string objname
= "a" + stringify(i
) + suffix
;
5557 ghobject_t
o(hobject_t(
5564 t
.write(a
, o
, 0, small
.length(), small
, 0);
5566 r
= queue_transaction(store
, cha
, std::move(t
));
5568 t
= ObjectStore::Transaction();
5571 r
= queue_transaction(store
, cha
, std::move(t
));
5576 ObjectStore::Transaction t
;
5577 for (unsigned i
= 0; i
< 10; ++i
) {
5578 string objname
= "b" + stringify(i
) + suffix
;
5579 ghobject_t
o(hobject_t(
5583 (i
<<(base
+1)) | base
| (1<<bits
),
5586 t
.write(b
, o
, 0, small
.length(), small
, 0);
5588 r
= queue_transaction(store
, chb
, std::move(t
));
5590 t
= ObjectStore::Transaction();
5593 r
= queue_transaction(store
, chb
, std::move(t
));
5599 ObjectStore::Transaction t
;
5600 t
.merge_collection(b
, a
, bits
);
5601 r
= queue_transaction(store
, cha
, std::move(t
));
5607 vector
<ghobject_t
> got
;
5608 store
->collection_list(cha
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5610 set
<ghobject_t
> gotset
;
5611 for (auto& o
: got
) {
5612 ASSERT_TRUE(aobjects
.count(o
) || bobjects
.count(o
));
5615 // check both listing and stat-ability (different code paths!)
5617 for (auto& o
: aobjects
) {
5618 ASSERT_TRUE(gotset
.count(o
));
5619 int r
= store
->stat(cha
, o
, &st
, false);
5622 for (auto& o
: bobjects
) {
5623 ASSERT_TRUE(gotset
.count(o
));
5624 int r
= store
->stat(cha
, o
, &st
, false);
5631 ObjectStore::Transaction t
;
5632 for (auto &o
: aobjects
) {
5635 r
= queue_transaction(store
, cha
, std::move(t
));
5639 ObjectStore::Transaction t
;
5640 for (auto &o
: bobjects
) {
5643 t
.remove_collection(a
);
5644 r
= queue_transaction(store
, cha
, std::move(t
));
5649 TEST_P(StoreTest
, MergeSkewed
) {
5650 if (string(GetParam()) != "filestore")
5653 // this is sufficient to exercise merges with different hashing levels
5654 test_merge_skewed(store
.get(), 0xf, 4, 10, 10000);
5655 test_merge_skewed(store
.get(), 0xf, 4, 10000, 10);
5658 // this covers a zillion variations that all boil down to the same thing
5659 for (unsigned base = 3; base < 0x1000; base *= 5) {
5662 for (bits = 0; t; t >>= 1) {
5665 for (unsigned b = bits; b < bits + 10; b += 3) {
5666 for (auto anum : { 10, 1000, 10000 }) {
5667 for (auto bnum : { 10, 1000, 10000 }) {
5671 test_merge_skewed(store.get(), base, b, anum, bnum);
5681 * This test tests adding two different groups
5682 * of objects, each with 1 common prefix and 1
5683 * different prefix. We then remove half
5684 * in order to verify that the merging correctly
5685 * stops at the common prefix subdir. See bug
5687 TEST_P(StoreTest
, TwoHash
) {
5690 auto ch
= store
->create_new_collection(cid
);
5692 ObjectStore::Transaction t
;
5693 t
.create_collection(cid
, 0);
5694 r
= queue_transaction(store
, ch
, std::move(t
));
5697 std::cout
<< "Making objects" << std::endl
;
5698 for (int i
= 0; i
< 360; ++i
) {
5699 ObjectStore::Transaction t
;
5703 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5706 o
.hobj
.set_hash((i
<< 16) | 0xB1);
5708 r
= queue_transaction(store
, ch
, std::move(t
));
5711 std::cout
<< "Removing half" << std::endl
;
5712 for (int i
= 1; i
< 8; ++i
) {
5713 ObjectStore::Transaction t
;
5716 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5718 r
= queue_transaction(store
, ch
, std::move(t
));
5721 std::cout
<< "Checking" << std::endl
;
5722 for (int i
= 1; i
< 8; ++i
) {
5723 ObjectStore::Transaction t
;
5725 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5727 bool exists
= store
->exists(ch
, o
);
5728 ASSERT_EQ(exists
, false);
5732 o
.hobj
.set_hash(0xA1);
5734 bool exists
= store
->exists(ch
, o
);
5735 ASSERT_EQ(exists
, true);
5737 std::cout
<< "Cleanup" << std::endl
;
5738 for (int i
= 0; i
< 360; ++i
) {
5739 ObjectStore::Transaction t
;
5741 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5744 o
.hobj
.set_hash((i
<< 16) | 0xB1);
5746 r
= queue_transaction(store
, ch
, std::move(t
));
5749 ObjectStore::Transaction t
;
5750 t
.remove_collection(cid
);
5751 r
= queue_transaction(store
, ch
, std::move(t
));
5755 TEST_P(StoreTest
, Rename
) {
5756 coll_t
cid(spg_t(pg_t(0, 2122),shard_id_t::NO_SHARD
));
5757 ghobject_t
srcoid(hobject_t("src_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5758 ghobject_t
dstoid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5762 auto ch
= store
->create_new_collection(cid
);
5765 ObjectStore::Transaction t
;
5766 t
.create_collection(cid
, 0);
5767 t
.write(cid
, srcoid
, 0, a
.length(), a
);
5768 r
= queue_transaction(store
, ch
, std::move(t
));
5771 ASSERT_TRUE(store
->exists(ch
, srcoid
));
5773 ObjectStore::Transaction t
;
5774 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
5775 t
.write(cid
, srcoid
, 0, b
.length(), b
);
5776 t
.setattr(cid
, srcoid
, "attr", b
);
5777 r
= queue_transaction(store
, ch
, std::move(t
));
5780 ASSERT_TRUE(store
->exists(ch
, srcoid
));
5781 ASSERT_TRUE(store
->exists(ch
, dstoid
));
5784 store
->read(ch
, srcoid
, 0, 3, bl
);
5785 ASSERT_TRUE(bl_eq(b
, bl
));
5786 store
->read(ch
, dstoid
, 0, 3, bl
);
5787 ASSERT_TRUE(bl_eq(a
, bl
));
5790 ObjectStore::Transaction t
;
5791 t
.remove(cid
, dstoid
);
5792 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
5793 r
= queue_transaction(store
, ch
, std::move(t
));
5796 ASSERT_TRUE(store
->exists(ch
, dstoid
));
5797 ASSERT_FALSE(store
->exists(ch
, srcoid
));
5800 store
->read(ch
, dstoid
, 0, 3, bl
);
5801 ASSERT_TRUE(bl_eq(b
, bl
));
5804 ObjectStore::Transaction t
;
5805 t
.remove(cid
, dstoid
);
5806 t
.remove_collection(cid
);
5807 r
= queue_transaction(store
, ch
, std::move(t
));
5812 TEST_P(StoreTest
, MoveRename
) {
5813 coll_t
cid(spg_t(pg_t(0, 212),shard_id_t::NO_SHARD
));
5814 ghobject_t
temp_oid(hobject_t("tmp_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5815 ghobject_t
oid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5816 auto ch
= store
->create_new_collection(cid
);
5819 ObjectStore::Transaction t
;
5820 t
.create_collection(cid
, 0);
5822 r
= queue_transaction(store
, ch
, std::move(t
));
5825 ASSERT_TRUE(store
->exists(ch
, oid
));
5826 bufferlist data
, attr
;
5827 map
<string
, bufferlist
> omap
;
5828 data
.append("data payload");
5829 attr
.append("attr value");
5830 omap
["omap_key"].append("omap value");
5832 ObjectStore::Transaction t
;
5833 t
.touch(cid
, temp_oid
);
5834 t
.write(cid
, temp_oid
, 0, data
.length(), data
);
5835 t
.setattr(cid
, temp_oid
, "attr", attr
);
5836 t
.omap_setkeys(cid
, temp_oid
, omap
);
5837 r
= queue_transaction(store
, ch
, std::move(t
));
5840 ASSERT_TRUE(store
->exists(ch
, temp_oid
));
5842 ObjectStore::Transaction t
;
5844 t
.collection_move_rename(cid
, temp_oid
, cid
, oid
);
5845 r
= queue_transaction(store
, ch
, std::move(t
));
5848 ASSERT_TRUE(store
->exists(ch
, oid
));
5849 ASSERT_FALSE(store
->exists(ch
, temp_oid
));
5852 r
= store
->read(ch
, oid
, 0, 1000, newdata
);
5854 ASSERT_TRUE(bl_eq(data
, newdata
));
5856 r
= store
->getattr(ch
, oid
, "attr", newattr
);
5858 ASSERT_TRUE(bl_eq(attr
, newattr
));
5860 keys
.insert("omap_key");
5861 map
<string
, bufferlist
> newomap
;
5862 r
= store
->omap_get_values(ch
, oid
, keys
, &newomap
);
5864 ASSERT_EQ(1u, newomap
.size());
5865 ASSERT_TRUE(newomap
.count("omap_key"));
5866 ASSERT_TRUE(bl_eq(omap
["omap_key"], newomap
["omap_key"]));
5869 ObjectStore::Transaction t
;
5871 t
.remove_collection(cid
);
5872 r
= queue_transaction(store
, ch
, std::move(t
));
5877 TEST_P(StoreTest
, BigRGWObjectName
) {
5878 coll_t
cid(spg_t(pg_t(0,12),shard_id_t::NO_SHARD
));
5881 "default.4106.50_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
5888 shard_id_t::NO_SHARD
);
5889 ghobject_t
oid2(oid
);
5890 oid2
.generation
= 17;
5891 ghobject_t
oidhead(oid
);
5892 oidhead
.generation
= ghobject_t::NO_GEN
;
5894 auto ch
= store
->create_new_collection(cid
);
5898 ObjectStore::Transaction t
;
5899 t
.create_collection(cid
, 0);
5900 t
.touch(cid
, oidhead
);
5901 t
.collection_move_rename(cid
, oidhead
, cid
, oid
);
5902 t
.touch(cid
, oidhead
);
5903 t
.collection_move_rename(cid
, oidhead
, cid
, oid2
);
5904 r
= queue_transaction(store
, ch
, std::move(t
));
5909 ObjectStore::Transaction t
;
5911 r
= queue_transaction(store
, ch
, std::move(t
));
5916 vector
<ghobject_t
> objects
;
5917 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
5918 INT_MAX
, &objects
, 0);
5920 ASSERT_EQ(objects
.size(), 1u);
5921 ASSERT_EQ(objects
[0], oid2
);
5924 ASSERT_FALSE(store
->exists(ch
, oid
));
5927 ObjectStore::Transaction t
;
5928 t
.remove(cid
, oid2
);
5929 t
.remove_collection(cid
);
5930 r
= queue_transaction(store
, ch
, std::move(t
));
5936 TEST_P(StoreTest
, SetAllocHint
) {
5938 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, 0, ""));
5939 auto ch
= store
->create_new_collection(cid
);
5942 ObjectStore::Transaction t
;
5943 t
.create_collection(cid
, 0);
5945 r
= queue_transaction(store
, ch
, std::move(t
));
5949 ObjectStore::Transaction t
;
5950 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
5951 r
= queue_transaction(store
, ch
, std::move(t
));
5955 ObjectStore::Transaction t
;
5956 t
.remove(cid
, hoid
);
5957 r
= queue_transaction(store
, ch
, std::move(t
));
5961 ObjectStore::Transaction t
;
5962 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
5963 r
= queue_transaction(store
, ch
, std::move(t
));
5967 ObjectStore::Transaction t
;
5968 t
.remove_collection(cid
);
5969 r
= queue_transaction(store
, ch
, std::move(t
));
5974 TEST_P(StoreTest
, TryMoveRename
) {
5976 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
5977 ghobject_t
hoid2(hobject_t("test_hint2", "", CEPH_NOSNAP
, 0, -1, ""));
5978 auto ch
= store
->create_new_collection(cid
);
5981 ObjectStore::Transaction t
;
5982 t
.create_collection(cid
, 0);
5983 r
= queue_transaction(store
, ch
, std::move(t
));
5987 ObjectStore::Transaction t
;
5988 t
.try_rename(cid
, hoid
, hoid2
);
5989 r
= queue_transaction(store
, ch
, std::move(t
));
5993 ObjectStore::Transaction t
;
5995 r
= queue_transaction(store
, ch
, std::move(t
));
5999 ObjectStore::Transaction t
;
6000 t
.try_rename(cid
, hoid
, hoid2
);
6001 r
= queue_transaction(store
, ch
, std::move(t
));
6005 ASSERT_EQ(store
->stat(ch
, hoid
, &st
), -ENOENT
);
6006 ASSERT_EQ(store
->stat(ch
, hoid2
, &st
), 0);
6009 #if defined(WITH_BLUESTORE)
6010 TEST_P(StoreTest
, BluestoreOnOffCSumTest
) {
6011 if (string(GetParam()) != "bluestore")
6013 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6014 g_conf().apply_changes(nullptr);
6018 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
6020 auto ch
= store
->open_collection(cid
);
6023 auto ch
= store
->create_new_collection(cid
);
6025 ObjectStore::Transaction t
;
6026 t
.create_collection(cid
, 0);
6027 cerr
<< "Creating collection " << cid
<< std::endl
;
6028 r
= queue_transaction(store
, ch
, std::move(t
));
6032 //write with csum enabled followed by read with csum disabled
6033 size_t block_size
= 64*1024;
6034 ObjectStore::Transaction t
;
6035 bufferlist bl
, orig
;
6036 bl
.append(std::string(block_size
, 'a'));
6038 t
.remove(cid
, hoid
);
6039 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6040 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6041 cerr
<< "Remove then create" << std::endl
;
6042 r
= queue_transaction(store
, ch
, std::move(t
));
6045 SetVal(g_conf(), "bluestore_csum_type", "none");
6046 g_conf().apply_changes(nullptr);
6049 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6050 ASSERT_EQ((int)block_size
, r
);
6051 ASSERT_TRUE(bl_eq(orig
, in
));
6055 //write with csum disabled followed by read with csum enabled
6057 size_t block_size
= 64*1024;
6058 ObjectStore::Transaction t
;
6059 bufferlist bl
, orig
;
6060 bl
.append(std::string(block_size
, 'a'));
6062 t
.remove(cid
, hoid
);
6063 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6064 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6065 cerr
<< "Remove then create" << std::endl
;
6066 r
= queue_transaction(store
, ch
, std::move(t
));
6069 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6070 g_conf().apply_changes(nullptr);
6073 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6074 ASSERT_EQ((int)block_size
, r
);
6075 ASSERT_TRUE(bl_eq(orig
, in
));
6078 //'mixed' non-overlapping writes to the same blob
6080 ObjectStore::Transaction t
;
6081 bufferlist bl
, orig
;
6082 size_t block_size
= 8000;
6083 bl
.append(std::string(block_size
, 'a'));
6085 t
.remove(cid
, hoid
);
6086 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6087 cerr
<< "Remove then create" << std::endl
;
6088 r
= queue_transaction(store
, ch
, std::move(t
));
6091 SetVal(g_conf(), "bluestore_csum_type", "none");
6092 g_conf().apply_changes(nullptr);
6094 ObjectStore::Transaction t2
;
6095 t2
.write(cid
, hoid
, block_size
*2, bl
.length(), bl
);
6096 cerr
<< "Append 'unprotected'" << std::endl
;
6097 r
= queue_transaction(store
, ch
, std::move(t2
));
6101 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6102 ASSERT_EQ((int)block_size
, r
);
6103 ASSERT_TRUE(bl_eq(orig
, in
));
6105 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6106 ASSERT_EQ((int)block_size
, r
);
6107 ASSERT_TRUE(bl_eq(orig
, in
));
6109 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6110 g_conf().apply_changes(nullptr);
6112 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6113 ASSERT_EQ((int)block_size
, r
);
6114 ASSERT_TRUE(bl_eq(orig
, in
));
6116 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6117 ASSERT_EQ((int)block_size
, r
);
6118 ASSERT_TRUE(bl_eq(orig
, in
));
6121 //partially blob overwrite under a different csum enablement mode
6123 ObjectStore::Transaction t
;
6124 bufferlist bl
, orig
, orig2
;
6125 size_t block_size0
= 0x10000;
6126 size_t block_size
= 9000;
6127 size_t block_size2
= 5000;
6128 bl
.append(std::string(block_size0
, 'a'));
6129 t
.remove(cid
, hoid
);
6130 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6131 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6132 cerr
<< "Remove then create" << std::endl
;
6133 r
= queue_transaction(store
, ch
, std::move(t
));
6136 SetVal(g_conf(), "bluestore_csum_type", "none");
6137 g_conf().apply_changes(nullptr);
6139 ObjectStore::Transaction t2
;
6141 bl
.append(std::string(block_size
, 'b'));
6142 t2
.write(cid
, hoid
, 0, bl
.length(), bl
);
6143 t2
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6144 cerr
<< "Overwrite with unprotected data" << std::endl
;
6145 r
= queue_transaction(store
, ch
, std::move(t2
));
6150 orig
.append( std::string(block_size0
- block_size
, 'a'));
6153 r
= store
->read(ch
, hoid
, 0, block_size0
, in
);
6154 ASSERT_EQ((int)block_size0
, r
);
6155 ASSERT_TRUE(bl_eq(orig
, in
));
6157 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6158 ASSERT_EQ((int)block_size
, r
);
6159 ASSERT_TRUE(bl_eq(orig2
, in
));
6161 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6162 g_conf().apply_changes(nullptr);
6164 ObjectStore::Transaction t3
;
6166 bl
.append(std::string(block_size2
, 'c'));
6167 t3
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6168 cerr
<< "Overwrite with protected data" << std::endl
;
6169 r
= queue_transaction(store
, ch
, std::move(t3
));
6174 orig
.append( std::string(block_size
- block_size2
, 'b'));
6175 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6176 ASSERT_EQ((int)block_size
, r
);
6177 ASSERT_TRUE(bl_eq(orig
, in
));
6181 ObjectStore::Transaction t
;
6182 t
.remove(cid
, hoid
);
6183 t
.remove_collection(cid
);
6184 cerr
<< "Cleaning" << std::endl
;
6185 r
= queue_transaction(store
, ch
, std::move(t
));
6191 INSTANTIATE_TEST_CASE_P(
6197 #if defined(WITH_BLUESTORE)
6202 // Note: instantiate all stores to preserve store numbering order only
6203 INSTANTIATE_TEST_CASE_P(
6205 StoreTestSpecificAUSize
,
6209 #if defined(WITH_BLUESTORE)
6216 // Google Test may not support value-parameterized tests with some
6217 // compilers. If we use conditional compilation to compile out all
6218 // code referring to the gtest_main library, MSVC linker will not link
6219 // that library at all and consequently complain about missing entry
6220 // point defined in that library (fatal error LNK1561: entry point
6221 // must be defined). This dummy test keeps gtest_main linked in.
6222 TEST(DummyTest
, ValueParameterizedTestsAreNotSupportedOnThisPlatform
) {}
6226 void doMany4KWritesTest(boost::scoped_ptr
<ObjectStore
>& store
,
6227 unsigned max_objects
,
6229 unsigned max_object_size
,
6230 unsigned max_write_size
,
6231 unsigned write_alignment
)
6233 MixedGenerator
gen(555);
6234 gen_type
rng(time(NULL
));
6235 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
6236 store_statfs_t res_stat
;
6238 SyntheticWorkloadState
test_obj(store
.get(),
6246 for (unsigned i
= 0; i
< max_objects
; ++i
) {
6247 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
6250 for (unsigned i
= 0; i
< max_ops
; ++i
) {
6252 cerr
<< "Op " << i
<< std::endl
;
6253 test_obj
.print_internal_state();
6257 test_obj
.wait_for_done();
6258 test_obj
.statfs(res_stat
);
6259 if (!(res_stat
.data_stored
<= max_object_size
) ||
6260 !(res_stat
.allocated
<= max_object_size
)) {
6261 // this will provide more insight on the mismatch and
6262 // helps to avoid any races during stats collection
6263 test_obj
.fsck(false);
6264 // retrieving stats once again and assert if still broken
6265 test_obj
.statfs(res_stat
);
6266 ASSERT_LE(res_stat
.data_stored
, max_object_size
);
6267 ASSERT_LE(res_stat
.allocated
, max_object_size
);
6269 test_obj
.shutdown();
6272 TEST_P(StoreTestSpecificAUSize
, Many4KWritesTest
) {
6273 if (string(GetParam()) != "bluestore")
6276 StartDeferred(0x10000);
6278 const unsigned max_object
= 4*1024*1024;
6279 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0);
6282 TEST_P(StoreTestSpecificAUSize
, Many4KWritesNoCSumTest
) {
6283 if (string(GetParam()) != "bluestore")
6285 StartDeferred(0x10000);
6286 SetVal(g_conf(), "bluestore_csum_type", "none");
6287 g_ceph_context
->_conf
.apply_changes(nullptr);
6288 const unsigned max_object
= 4*1024*1024;
6290 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0 );
6293 TEST_P(StoreTestSpecificAUSize
, TooManyBlobsTest
) {
6294 if (string(GetParam()) != "bluestore")
6296 StartDeferred(0x10000);
6297 const unsigned max_object
= 4*1024*1024;
6298 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0);
6301 #if defined(WITH_BLUESTORE)
6302 void get_mempool_stats(uint64_t* total_bytes
, uint64_t* total_items
)
6304 uint64_t onode_allocated
= mempool::bluestore_cache_onode::allocated_bytes();
6305 uint64_t other_allocated
= mempool::bluestore_cache_other::allocated_bytes();
6307 uint64_t onode_items
= mempool::bluestore_cache_onode::allocated_items();
6308 uint64_t other_items
= mempool::bluestore_cache_other::allocated_items();
6309 cout
<< "onode(" << onode_allocated
<< "/" << onode_items
6310 << ") other(" << other_allocated
<< "/" << other_items
6311 << ")" << std::endl
;
6312 *total_bytes
= onode_allocated
+ other_allocated
;
6313 *total_items
= onode_items
;
6316 TEST_P(StoreTestSpecificAUSize
, OnodeSizeTracking
) {
6318 if (string(GetParam()) != "bluestore")
6321 size_t block_size
= 4096;
6322 StartDeferred(block_size
);
6323 SetVal(g_conf(), "bluestore_compression_mode", "none");
6324 SetVal(g_conf(), "bluestore_csum_type", "none");
6325 SetVal(g_conf(), "bluestore_cache_size_hdd", "400000000");
6326 SetVal(g_conf(), "bluestore_cache_size_ssd", "400000000");
6327 g_conf().apply_changes(nullptr);
6331 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6332 size_t obj_size
= 4 * 1024 * 1024;
6333 uint64_t total_bytes
, total_bytes2
;
6334 uint64_t total_onodes
;
6335 get_mempool_stats(&total_bytes
, &total_onodes
);
6336 ASSERT_EQ(total_onodes
, 0u);
6338 auto ch
= store
->create_new_collection(cid
);
6340 ObjectStore::Transaction t
;
6341 t
.create_collection(cid
, 0);
6342 r
= queue_transaction(store
, ch
, std::move(t
));
6346 ObjectStore::Transaction t
;
6347 bufferlist bl
, orig
, orig2
;
6349 bl
.append(std::string(obj_size
, 'a'));
6350 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6351 r
= queue_transaction(store
, ch
, std::move(t
));
6354 get_mempool_stats(&total_bytes
, &total_onodes
);
6355 ASSERT_NE(total_bytes
, 0u);
6356 ASSERT_EQ(total_onodes
, 1u);
6359 ObjectStore::Transaction t
;
6360 t
.truncate(cid
, hoid
, 0);
6361 r
= queue_transaction(store
, ch
, std::move(t
));
6365 for(size_t i
= 0; i
< 1; ++i
) {
6367 bl
.append(std::string(block_size
* (i
+1), 'a'));
6368 for( size_t j
= 0; j
< obj_size
; j
+= bl
.length()) {
6369 ObjectStore::Transaction t
;
6370 t
.write(cid
, hoid
, j
, bl
.length(), bl
);
6371 r
= queue_transaction(store
, ch
, std::move(t
));
6374 get_mempool_stats(&total_bytes2
, &total_onodes
);
6375 ASSERT_NE(total_bytes2
, 0u);
6376 ASSERT_EQ(total_onodes
, 1u);
6379 cout
<<" mempool dump:\n";
6380 JSONFormatter
f(true);
6381 f
.open_object_section("transaction");
6389 for (size_t i
= 0; i
< obj_size
; i
+= 0x1000) {
6390 store
->read(ch
, hoid
, i
, 0x1000, bl
);
6393 get_mempool_stats(&total_bytes
, &total_onodes
);
6394 ASSERT_NE(total_bytes
, 0u);
6395 ASSERT_EQ(total_onodes
, 1u);
6398 cout
<<" mempool dump:\n";
6399 JSONFormatter
f(true);
6400 f
.open_object_section("transaction");
6407 ObjectStore::Transaction t
;
6408 t
.remove(cid
, hoid
);
6409 t
.remove_collection(cid
);
6410 cerr
<< "Cleaning" << std::endl
;
6411 r
= queue_transaction(store
, ch
, std::move(t
));
6416 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwrite
) {
6418 if (string(GetParam()) != "bluestore")
6421 size_t block_size
= 4096;
6422 StartDeferred(block_size
);
6423 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6424 g_conf().apply_changes(nullptr);
6428 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6430 const PerfCounters
* logger
= store
->get_perf_counters();
6432 auto ch
= store
->create_new_collection(cid
);
6434 ObjectStore::Transaction t
;
6435 t
.create_collection(cid
, 0);
6436 r
= queue_transaction(store
, ch
, std::move(t
));
6440 ObjectStore::Transaction t
;
6443 bl
.append(std::string(block_size
* 2, 'a'));
6444 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6445 r
= queue_transaction(store
, ch
, std::move(t
));
6449 // overwrite at the beginning
6450 ObjectStore::Transaction t
;
6453 bl
.append(std::string(block_size
, 'b'));
6454 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6455 r
= queue_transaction(store
, ch
, std::move(t
));
6460 ObjectStore::Transaction t
;
6463 bl
.append(std::string(block_size
* 2, 'c'));
6464 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6465 r
= queue_transaction(store
, ch
, std::move(t
));
6469 // append with a gap
6470 ObjectStore::Transaction t
;
6473 bl
.append(std::string(block_size
* 2, 'd'));
6474 t
.write(cid
, hoid
, block_size
* 5, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6475 r
= queue_transaction(store
, ch
, std::move(t
));
6479 // We need to issue a read to trigger cache stat update that refresh
6480 // perf counters. additionally we need to wait some time for mempool
6481 // thread to update stats.
6483 bufferlist bl
, expected
;
6484 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6485 ASSERT_EQ(r
, (int)block_size
);
6486 expected
.append(string(block_size
, 'b'));
6487 ASSERT_TRUE(bl_eq(expected
, bl
));
6488 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6489 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
6493 ObjectStore::Transaction t
;
6496 bl
.append(std::string(block_size
* 2, 'e'));
6498 // Currently we are unable to reuse blob when overwriting in a single step
6499 t
.write(cid
, hoid
, block_size
* 6, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6500 r
= queue_transaction(store
, ch
, std::move(t
));
6504 // We need to issue a read to trigger cache stat update that refresh
6505 // perf counters. additionally we need to wait some time for mempool
6506 // thread to update stats.
6508 bufferlist bl
, expected
;
6509 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6510 ASSERT_EQ(r
, (int)block_size
);
6511 expected
.append(string(block_size
, 'b'));
6512 ASSERT_TRUE(bl_eq(expected
, bl
));
6513 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6514 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
6518 ObjectStore::Transaction t
;
6521 bl
.append(std::string(block_size
, 'f'));
6523 t
.write(cid
, hoid
, block_size
* 4, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6524 r
= queue_transaction(store
, ch
, std::move(t
));
6528 // we need to wait some time for mempool
6529 // thread to update stats to be able to check blob/extent numbers from
6533 bufferlist bl
, expected
;
6534 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6535 ASSERT_EQ(r
, (int)block_size
);
6536 expected
.append(string(block_size
, 'b'));
6537 ASSERT_TRUE(bl_eq(expected
, bl
));
6541 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
6542 ASSERT_EQ(r
, (int)block_size
);
6543 expected
.append(string(block_size
, 'a'));
6544 ASSERT_TRUE(bl_eq(expected
, bl
));
6548 r
= store
->read(ch
, hoid
, block_size
* 2, block_size
* 2, bl
);
6549 ASSERT_EQ(r
, (int)block_size
* 2);
6550 expected
.append(string(block_size
* 2, 'c'));
6551 ASSERT_TRUE(bl_eq(expected
, bl
));
6555 r
= store
->read(ch
, hoid
, block_size
* 4, block_size
, bl
);
6556 ASSERT_EQ(r
, (int)block_size
);
6557 expected
.append(string(block_size
, 'f'));
6558 ASSERT_TRUE(bl_eq(expected
, bl
));
6562 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
, bl
);
6563 ASSERT_EQ(r
, (int)block_size
);
6564 expected
.append(string(block_size
, 'd'));
6565 ASSERT_TRUE(bl_eq(expected
, bl
));
6569 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
* 3, bl
);
6570 ASSERT_EQ(r
, (int)block_size
* 3);
6571 expected
.append(string(block_size
, 'd'));
6572 expected
.append(string(block_size
* 2, 'e'));
6573 ASSERT_TRUE(bl_eq(expected
, bl
));
6575 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6576 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
6580 ObjectStore::Transaction t
;
6581 t
.remove(cid
, hoid
);
6582 t
.remove_collection(cid
);
6583 cerr
<< "Cleaning" << std::endl
;
6584 r
= queue_transaction(store
, ch
, std::move(t
));
6589 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwriteReverse
) {
6591 if (string(GetParam()) != "bluestore")
6594 size_t block_size
= 4096;
6595 StartDeferred(block_size
);
6596 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6597 g_conf().apply_changes(nullptr);
6601 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6603 auto ch
= store
->create_new_collection(cid
);
6605 const PerfCounters
* logger
= store
->get_perf_counters();
6607 ObjectStore::Transaction t
;
6608 t
.create_collection(cid
, 0);
6609 r
= queue_transaction(store
, ch
, std::move(t
));
6613 ObjectStore::Transaction t
;
6616 bl
.append(std::string(block_size
* 2, 'a'));
6617 t
.write(cid
, hoid
, block_size
* 10, bl
.length(), bl
,
6618 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6619 r
= queue_transaction(store
, ch
, std::move(t
));
6624 ObjectStore::Transaction t
;
6627 bl
.append(std::string(block_size
, 'b'));
6628 t
.write(cid
, hoid
, block_size
* 9, bl
.length(), bl
,
6629 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6630 r
= queue_transaction(store
, ch
, std::move(t
));
6634 // We need to issue a read to trigger cache stat update that refresh
6635 // perf counters. additionally we need to wait some time for mempool
6636 // thread to update stats.
6638 bufferlist bl
, expected
;
6639 r
= store
->read(ch
, hoid
, block_size
* 9, block_size
* 2, bl
);
6640 ASSERT_EQ(r
, (int)block_size
* 2);
6641 expected
.append(string(block_size
, 'b'));
6642 expected
.append(string(block_size
, 'a'));
6643 ASSERT_TRUE(bl_eq(expected
, bl
));
6644 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6645 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
6650 // prepend existing with a gap
6651 ObjectStore::Transaction t
;
6654 bl
.append(std::string(block_size
, 'c'));
6655 t
.write(cid
, hoid
, block_size
* 7, bl
.length(), bl
,
6656 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6657 r
= queue_transaction(store
, ch
, std::move(t
));
6661 // We need to issue a read to trigger cache stat update that refresh
6662 // perf counters. additionally we need to wait some time for mempool
6663 // thread to update stats.
6665 bufferlist bl
, expected
;
6666 r
= store
->read(ch
, hoid
, block_size
* 7, block_size
* 3, bl
);
6667 ASSERT_EQ(r
, (int)block_size
* 3);
6668 expected
.append(string(block_size
, 'c'));
6669 expected
.append(string(block_size
, 0));
6670 expected
.append(string(block_size
, 'b'));
6671 ASSERT_TRUE(bl_eq(expected
, bl
));
6672 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6673 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
6677 // append after existing with a gap
6678 ObjectStore::Transaction t
;
6681 bl
.append(std::string(block_size
, 'd'));
6682 t
.write(cid
, hoid
, block_size
* 13, bl
.length(), bl
,
6683 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6684 r
= queue_transaction(store
, ch
, std::move(t
));
6688 // We need to issue a read to trigger cache stat update that refresh
6689 // perf counters. additionally we need to wait some time for mempool
6690 // thread to update stats.
6692 bufferlist bl
, expected
;
6693 r
= store
->read(ch
, hoid
, block_size
* 11, block_size
* 3, bl
);
6694 ASSERT_EQ(r
, (int)block_size
* 3);
6695 expected
.append(string(block_size
, 'a'));
6696 expected
.append(string(block_size
, 0));
6697 expected
.append(string(block_size
, 'd'));
6698 ASSERT_TRUE(bl_eq(expected
, bl
));
6699 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6700 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
6704 // append twice to the next max_blob slot
6705 ObjectStore::Transaction t
;
6708 bl
.append(std::string(block_size
, 'e'));
6709 t
.write(cid
, hoid
, block_size
* 17, bl
.length(), bl
,
6710 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6711 t
.write(cid
, hoid
, block_size
* 19, bl
.length(), bl
,
6712 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6713 r
= queue_transaction(store
, ch
, std::move(t
));
6717 // We need to issue a read to trigger cache stat update that refresh
6718 // perf counters. additionally we need to wait some time for mempool
6719 // thread to update stats.
6721 bufferlist bl
, expected
;
6722 r
= store
->read(ch
, hoid
, block_size
* 17, block_size
* 3, bl
);
6723 ASSERT_EQ(r
, (int)block_size
* 3);
6724 expected
.append(string(block_size
, 'e'));
6725 expected
.append(string(block_size
, 0));
6726 expected
.append(string(block_size
, 'e'));
6727 ASSERT_TRUE(bl_eq(expected
, bl
));
6728 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
6729 ASSERT_EQ(logger
->get(l_bluestore_extents
), 5u);
6732 // fill gaps at the second slot
6733 ObjectStore::Transaction t
;
6736 bl
.append(std::string(block_size
, 'f'));
6737 t
.write(cid
, hoid
, block_size
* 16, bl
.length(), bl
,
6738 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6739 t
.write(cid
, hoid
, block_size
* 18, bl
.length(), bl
,
6740 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6741 r
= queue_transaction(store
, ch
, std::move(t
));
6745 // We need to issue a read to trigger cache stat update that refresh
6746 // perf counters. additionally we need to wait some time for mempool
6747 // thread to update stats.
6749 bufferlist bl
, expected
;
6750 r
= store
->read(ch
, hoid
, block_size
* 16, block_size
* 4, bl
);
6751 ASSERT_EQ(r
, (int)block_size
* 4);
6752 expected
.append(string(block_size
, 'f'));
6753 expected
.append(string(block_size
, 'e'));
6754 expected
.append(string(block_size
, 'f'));
6755 expected
.append(string(block_size
, 'e'));
6756 ASSERT_TRUE(bl_eq(expected
, bl
));
6757 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
6758 ASSERT_EQ(logger
->get(l_bluestore_extents
), 4u);
6761 ObjectStore::Transaction t
;
6762 t
.remove(cid
, hoid
);
6763 t
.remove_collection(cid
);
6764 cerr
<< "Cleaning" << std::endl
;
6765 r
= queue_transaction(store
, ch
, std::move(t
));
6770 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnSmallOverwrite
) {
6772 if (string(GetParam()) != "bluestore")
6775 size_t block_size
= 4096;
6776 StartDeferred(block_size
);
6777 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6778 g_conf().apply_changes(nullptr);
6782 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6784 const PerfCounters
* logger
= store
->get_perf_counters();
6785 auto ch
= store
->create_new_collection(cid
);
6788 ObjectStore::Transaction t
;
6789 t
.create_collection(cid
, 0);
6790 r
= queue_transaction(store
, ch
, std::move(t
));
6794 ObjectStore::Transaction t
;
6797 bl
.append(std::string(block_size
, 'a'));
6798 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6799 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
,
6800 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6801 r
= queue_transaction(store
, ch
, std::move(t
));
6805 // write small into the gap
6806 ObjectStore::Transaction t
;
6809 bl
.append(std::string(3, 'b'));
6810 t
.write(cid
, hoid
, block_size
+ 1, bl
.length(), bl
,
6811 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6812 r
= queue_transaction(store
, ch
, std::move(t
));
6816 // We need to issue a read to trigger cache stat update that refresh
6817 // perf counters. additionally we need to wait some time for mempool
6818 // thread to update stats.
6820 bufferlist bl
, expected
;
6821 r
= store
->read(ch
, hoid
, 0, block_size
* 3, bl
);
6822 ASSERT_EQ(r
, (int)block_size
* 3);
6823 expected
.append(string(block_size
, 'a'));
6824 expected
.append(string(1, 0));
6825 expected
.append(string(3, 'b'));
6826 expected
.append(string(block_size
- 4, 0));
6827 expected
.append(string(block_size
, 'a'));
6828 ASSERT_TRUE(bl_eq(expected
, bl
));
6830 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6831 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
6834 ObjectStore::Transaction t
;
6835 t
.remove(cid
, hoid
);
6836 t
.remove_collection(cid
);
6837 cerr
<< "Cleaning" << std::endl
;
6838 r
= queue_transaction(store
, ch
, std::move(t
));
6843 // The test case to reproduce an issue when write happens
6844 // to a zero space between the extents sharing the same spanning blob
6845 // with unloaded shard map.
6846 // Second extent might be filled with zeros this way due to wrong result
6847 // returned by has_any_extents() call in do_write_small. The latter is caused
6848 // by incompletly loaded extent map.
6849 TEST_P(StoreTestSpecificAUSize
, SmallWriteOnShardedExtents
) {
6850 if (string(GetParam()) != "bluestore")
6853 size_t block_size
= 0x10000;
6854 StartDeferred(block_size
);
6856 SetVal(g_conf(), "bluestore_csum_type", "xxhash64");
6857 SetVal(g_conf(), "bluestore_max_blob_size", "524288"); // for sure
6859 g_conf().apply_changes(nullptr);
6863 ghobject_t
hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
6864 auto ch
= store
->create_new_collection(cid
);
6867 ObjectStore::Transaction t
;
6868 t
.create_collection(cid
, 0);
6869 r
= queue_transaction(store
, ch
, std::move(t
));
6873 //doing some tricks to have sharded extents/spanning objects
6874 ObjectStore::Transaction t
;
6877 bl
.append(std::string(0x80000, 'a'));
6878 t
.write(cid
, hoid1
, 0, bl
.length(), bl
, 0);
6879 t
.zero(cid
, hoid1
, 0x719e0, 0x75b0 );
6880 r
= queue_transaction(store
, ch
, std::move(t
));
6883 bl2
.append(std::string(0x70000, 'b'));
6884 t
.write(cid
, hoid1
, 0, bl2
.length(), bl2
, 0);
6885 t
.zero(cid
, hoid1
, 0, 0x50000);
6886 r
= queue_transaction(store
, ch
, std::move(t
));
6893 ch
= store
->open_collection(cid
);
6896 // do a write to zero space in between some extents sharing the same blob
6897 ObjectStore::Transaction t
;
6900 bl
.append(std::string(0x6520, 'c'));
6901 t
.write(cid
, hoid1
, 0x71c00, bl
.length(), bl
, 0);
6903 r
= queue_transaction(store
, ch
, std::move(t
));
6908 ObjectStore::Transaction t
;
6909 bufferlist bl
, expected
;
6911 r
= store
->read(ch
, hoid1
, 0x70000, 0x9c00, bl
);
6912 ASSERT_EQ(r
, (int)0x9c00);
6913 expected
.append(string(0x19e0, 'a'));
6914 expected
.append(string(0x220, 0));
6915 expected
.append(string(0x6520, 'c'));
6916 expected
.append(string(0xe70, 0));
6917 expected
.append(string(0xc70, 'a'));
6918 ASSERT_TRUE(bl_eq(expected
, bl
));
6924 ObjectStore::Transaction t
;
6925 t
.remove(cid
, hoid1
);
6926 t
.remove_collection(cid
);
6927 cerr
<< "Cleaning" << std::endl
;
6928 r
= queue_transaction(store
, ch
, std::move(t
));
6933 TEST_P(StoreTestSpecificAUSize
, ExcessiveFragmentation
) {
6934 if (string(GetParam()) != "bluestore")
6937 SetVal(g_conf(), "bluestore_block_size",
6938 stringify((uint64_t)2048 * 1024 * 1024).c_str());
6940 ASSERT_EQ(g_conf().get_val
<Option::size_t>("bluefs_alloc_size"),
6943 size_t block_size
= 0x10000;
6944 StartDeferred(block_size
);
6948 ghobject_t
hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
6949 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
6950 auto ch
= store
->create_new_collection(cid
);
6953 ObjectStore::Transaction t
;
6954 t
.create_collection(cid
, 0);
6955 r
= queue_transaction(store
, ch
, std::move(t
));
6959 // create 2x400MB objects in a way that their pextents are interleaved
6960 ObjectStore::Transaction t
;
6963 bl
.append(std::string(block_size
* 4, 'a')); // 256KB
6965 while(offs
< (uint64_t)400 * 1024 * 1024) {
6966 t
.write(cid
, hoid1
, offs
, bl
.length(), bl
, 0);
6967 t
.write(cid
, hoid2
, offs
, bl
.length(), bl
, 0);
6968 r
= queue_transaction(store
, ch
, std::move(t
));
6970 offs
+= bl
.length();
6971 if( (offs
% (100 * 1024 * 1024)) == 0) {
6972 std::cout
<<"written " << offs
<< std::endl
;
6976 std::cout
<<"written 800MB"<<std::endl
;
6978 // Partially overwrite objects with 100MB each leaving space
6979 // fragmented and occuping still unfragmented space at the end
6980 // So we'll have enough free space but it'll lack long enough (e.g. 1MB)
6981 // contiguous pextents.
6982 ObjectStore::Transaction t
;
6985 bl
.append(std::string(block_size
* 4, 'a'));
6987 while(offs
< 112 * 1024 * 1024) {
6988 t
.write(cid
, hoid1
, offs
, bl
.length(), bl
, 0);
6989 t
.write(cid
, hoid2
, offs
, bl
.length(), bl
, 0);
6990 r
= queue_transaction(store
, ch
, std::move(t
));
6992 // this will produce high fragmentation if original allocations
6994 offs
+= bl
.length();
6995 if( (offs
% (10 * 1024 * 1024)) == 0) {
6996 std::cout
<<"written " << offs
<< std::endl
;
7001 // remove one of the object producing much free space
7002 // and hence triggering bluefs rebalance.
7003 // Which should fail as there is no long enough pextents.
7004 ObjectStore::Transaction t
;
7005 t
.remove(cid
, hoid2
);
7006 r
= queue_transaction(store
, ch
, std::move(t
));
7011 (int)g_conf().get_val
<double>("bluestore_bluefs_balance_interval");
7012 std::cout
<<"sleeping... " << std::endl
;
7016 // touch another object to triggerrebalance
7017 ObjectStore::Transaction t
;
7018 t
.touch(cid
, hoid1
);
7019 r
= queue_transaction(store
, ch
, std::move(t
));
7023 ObjectStore::Transaction t
;
7024 t
.remove(cid
, hoid1
);
7025 t
.remove(cid
, hoid2
);
7026 t
.remove_collection(cid
);
7027 cerr
<< "Cleaning" << std::endl
;
7028 r
= queue_transaction(store
, ch
, std::move(t
));
7033 #endif //#if defined(WITH_BLUESTORE)
7035 TEST_P(StoreTest
, KVDBHistogramTest
) {
7036 if (string(GetParam()) != "bluestore")
7042 string
base("testobj.");
7044 bufferptr
ap(0x1000);
7045 memset(ap
.c_str(), 'a', 0x1000);
7047 auto ch
= store
->create_new_collection(cid
);
7049 ObjectStore::Transaction t
;
7050 t
.create_collection(cid
, 0);
7051 r
= queue_transaction(store
, ch
, std::move(t
));
7054 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
7055 ObjectStore::Transaction t
;
7057 snprintf(buf
, sizeof(buf
), "%d", i
);
7058 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
7059 t
.write(cid
, hoid
, 0, 0x1000, a
);
7060 r
= queue_transaction(store
, ch
, std::move(t
));
7064 Formatter
*f
= Formatter::create("store_test", "json-pretty", "json-pretty");
7065 store
->generate_db_histogram(f
);
7070 TEST_P(StoreTest
, KVDBStatsTest
) {
7071 if (string(GetParam()) != "bluestore")
7074 SetVal(g_conf(), "rocksdb_perf", "true");
7075 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
7076 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
7077 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
7078 g_ceph_context
->_conf
.apply_changes(nullptr);
7079 int r
= store
->umount();
7081 r
= store
->mount(); //to force rocksdb stats
7086 string
base("testobj.");
7088 bufferptr
ap(0x1000);
7089 memset(ap
.c_str(), 'a', 0x1000);
7091 auto ch
= store
->create_new_collection(cid
);
7093 ObjectStore::Transaction t
;
7094 t
.create_collection(cid
, 0);
7095 r
= queue_transaction(store
, ch
, std::move(t
));
7098 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
7099 ObjectStore::Transaction t
;
7101 snprintf(buf
, sizeof(buf
), "%d", i
);
7102 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
7103 t
.write(cid
, hoid
, 0, 0x1000, a
);
7104 r
= queue_transaction(store
, ch
, std::move(t
));
7108 Formatter
*f
= Formatter::create("store_test", "json-pretty", "json-pretty");
7109 store
->get_db_statistics(f
);
7114 #if defined(WITH_BLUESTORE)
7115 TEST_P(StoreTestSpecificAUSize
, garbageCollection
) {
7118 int buf_len
= 256 * 1024;
7119 int overlap_offset
= 64 * 1024;
7120 int write_offset
= buf_len
;
7121 if (string(GetParam()) != "bluestore")
7124 #define WRITE_AT(offset, _length) {\
7125 ObjectStore::Transaction t;\
7126 if ((uint64_t)_length != bl.length()) { \
7127 buffer::ptr p(bl.c_str(), _length);\
7129 bl_tmp.push_back(p);\
7130 t.write(cid, hoid, offset, bl_tmp.length(), bl_tmp);\
7132 t.write(cid, hoid, offset, bl.length(), bl);\
7134 r = queue_transaction(store, ch, std::move(t));\
7138 StartDeferred(65536);
7140 SetVal(g_conf(), "bluestore_compression_max_blob_size", "524288");
7141 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
7142 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
7143 SetVal(g_conf(), "bluestore_compression_mode", "force");
7144 g_conf().apply_changes(nullptr);
7146 auto ch
= store
->create_new_collection(cid
);
7148 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
7151 r
= store
->read(ch
, hoid
, 0, 5, in
);
7152 ASSERT_EQ(-ENOENT
, r
);
7155 ObjectStore::Transaction t
;
7156 t
.create_collection(cid
, 0);
7157 cerr
<< "Creating collection " << cid
<< std::endl
;
7158 r
= queue_transaction(store
, ch
, std::move(t
));
7163 data
.resize(buf_len
);
7167 bool exists
= store
->exists(ch
, hoid
);
7168 ASSERT_TRUE(!exists
);
7170 ObjectStore::Transaction t
;
7172 cerr
<< "Creating object " << hoid
<< std::endl
;
7173 r
= queue_transaction(store
, ch
, std::move(t
));
7176 exists
= store
->exists(ch
, hoid
);
7177 ASSERT_EQ(true, exists
);
7181 for(size_t i
= 0; i
< data
.size(); i
++)
7187 struct store_statfs_t statfs
;
7188 WRITE_AT(0, buf_len
);
7189 int r
= store
->statfs(&statfs
);
7191 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7194 struct store_statfs_t statfs
;
7195 WRITE_AT(write_offset
- 2 * overlap_offset
, buf_len
);
7196 int r
= store
->statfs(&statfs
);
7198 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7199 const PerfCounters
* counters
= store
->get_perf_counters();
7200 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0u);
7204 struct store_statfs_t statfs
;
7205 WRITE_AT(write_offset
- overlap_offset
, buf_len
);
7206 int r
= store
->statfs(&statfs
);
7208 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7209 const PerfCounters
* counters
= store
->get_perf_counters();
7210 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x10000u
);
7213 struct store_statfs_t statfs
;
7214 WRITE_AT(write_offset
- 3 * overlap_offset
, buf_len
);
7215 int r
= store
->statfs(&statfs
);
7217 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7218 const PerfCounters
* counters
= store
->get_perf_counters();
7219 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
7222 struct store_statfs_t statfs
;
7223 WRITE_AT(write_offset
+ 1, overlap_offset
-1);
7224 int r
= store
->statfs(&statfs
);
7226 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7227 const PerfCounters
* counters
= store
->get_perf_counters();
7228 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
7231 struct store_statfs_t statfs
;
7232 WRITE_AT(write_offset
+ 1, overlap_offset
);
7233 int r
= store
->statfs(&statfs
);
7235 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7236 const PerfCounters
* counters
= store
->get_perf_counters();
7237 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x3ffffu
);
7240 struct store_statfs_t statfs
;
7241 WRITE_AT(0, buf_len
-1);
7242 int r
= store
->statfs(&statfs
);
7244 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7245 const PerfCounters
* counters
= store
->get_perf_counters();
7246 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
7248 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "1"); //forbid GC when saving = 0
7250 struct store_statfs_t statfs
;
7251 WRITE_AT(1, overlap_offset
-2);
7252 WRITE_AT(overlap_offset
* 2 + 1, overlap_offset
-2);
7253 int r
= store
->statfs(&statfs
);
7255 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7256 const PerfCounters
* counters
= store
->get_perf_counters();
7257 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
7260 struct store_statfs_t statfs
;
7261 WRITE_AT(overlap_offset
+ 1, overlap_offset
-2);
7262 int r
= store
->statfs(&statfs
);
7264 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x0);
7265 const PerfCounters
* counters
= store
->get_perf_counters();
7266 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40007u
);
7269 ObjectStore::Transaction t
;
7270 t
.remove(cid
, hoid
);
7271 cerr
<< "Cleaning" << std::endl
;
7272 r
= queue_transaction(store
, ch
, std::move(t
));
7278 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice
) {
7279 if (string(GetParam()) != "bluestore")
7282 SetVal(g_conf(), "bluestore_block_size",
7283 stringify(0x280005000).c_str()); //10 Gb + 4K
7284 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7285 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7286 StartDeferred(0x4000);
7288 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7293 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice2
) {
7294 if (string(GetParam()) != "bluestore")
7297 SetVal(g_conf(), "bluestore_block_size",
7298 stringify(0x280005000).c_str()); //10 Gb + 20K
7299 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7300 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7301 StartDeferred(0x1000);
7303 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7308 ghobject_t
make_object(const char* name
, int64_t pool
) {
7309 sobject_t soid
{name
, CEPH_NOSNAP
};
7310 uint32_t hash
= std::hash
<sobject_t
>{}(soid
);
7311 return ghobject_t
{hobject_t
{soid
, "", hash
, pool
, ""}};
7315 TEST_P(StoreTestSpecificAUSize
, BluestoreRepairTest
) {
7316 if (string(GetParam()) != "bluestore")
7318 const size_t offs_base
= 65536 / 2;
7320 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7321 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7322 SetVal(g_conf(), "bluestore_max_blob_size",
7323 stringify(2 * offs_base
).c_str());
7324 SetVal(g_conf(), "bluestore_extent_map_shard_max_size", "12000");
7325 SetVal(g_conf(), "bluestore_no_per_pool_stats_tolerance", "enforce");
7327 StartDeferred(0x10000);
7329 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
7331 // fill the store with some data
7332 const uint64_t pool
= 555;
7333 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
7334 auto ch
= store
->create_new_collection(cid
);
7336 ghobject_t hoid
= make_object("Object 1", pool
);
7337 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
7338 ghobject_t hoid2
= make_object("Object 2", pool
);
7339 ghobject_t hoid_cloned
= hoid2
;
7340 hoid_cloned
.hobj
.snap
= 1;
7341 ghobject_t hoid3
= make_object("Object 3", pool
);
7342 ghobject_t hoid3_cloned
= hoid3
;
7343 hoid3_cloned
.hobj
.snap
= 1;
7345 bl
.append("1234512345");
7347 const size_t repeats
= 16;
7349 auto ch
= store
->create_new_collection(cid
);
7350 cerr
<< "create collection + write" << std::endl
;
7351 ObjectStore::Transaction t
;
7352 t
.create_collection(cid
, 0);
7353 for( auto i
= 0ul; i
< repeats
; ++i
) {
7354 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
7355 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
7357 for( auto i
= 0ul; i
< repeats
; ++i
) {
7358 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
7360 t
.clone(cid
, hoid2
, hoid_cloned
);
7362 r
= queue_transaction(store
, ch
, std::move(t
));
7367 //////////// leaked pextent fix ////////////
7368 cerr
<< "fix leaked pextents" << std::endl
;
7369 ASSERT_EQ(bstore
->fsck(false), 0);
7370 ASSERT_EQ(bstore
->repair(false), 0);
7372 bstore
->inject_leaked(0x30000);
7374 ASSERT_EQ(bstore
->fsck(false), 1);
7375 ASSERT_EQ(bstore
->repair(false), 0);
7376 ASSERT_EQ(bstore
->fsck(false), 0);
7378 //////////// false free fix ////////////
7379 cerr
<< "fix false free pextents" << std::endl
;
7381 bstore
->inject_false_free(cid
, hoid
);
7383 ASSERT_EQ(bstore
->fsck(false), 2);
7384 ASSERT_EQ(bstore
->repair(false), 0);
7385 ASSERT_EQ(bstore
->fsck(false), 0);
7387 //////////// verify invalid statfs ///////////
7388 cerr
<< "fix invalid statfs" << std::endl
;
7389 store_statfs_t statfs0
, statfs
;
7391 ASSERT_EQ(bstore
->statfs(&statfs0
), 0);
7393 statfs
.allocated
+= 0x10000;
7394 statfs
.data_stored
+= 0x10000;
7395 ASSERT_FALSE(statfs0
== statfs
);
7396 bstore
->inject_statfs("bluestore_statfs", statfs
);
7399 ASSERT_EQ(bstore
->fsck(false), 1);
7400 ASSERT_EQ(bstore
->repair(false), 0);
7401 ASSERT_EQ(bstore
->fsck(false), 0);
7402 ASSERT_EQ(bstore
->mount(), 0);
7403 ASSERT_EQ(bstore
->statfs(&statfs
), 0);
7404 // adjust free space to success in comparison
7405 statfs0
.available
= statfs
.available
;
7406 ASSERT_EQ(statfs0
, statfs
);
7408 ///////// undecodable shared blob key / stray shared blob records ///////
7409 cerr
<< "undecodable shared blob key" << std::endl
;
7410 bstore
->inject_broken_shared_blob_key("undec1",
7412 bstore
->inject_broken_shared_blob_key("undecodable key 2",
7414 bstore
->inject_broken_shared_blob_key("undecodable key 3",
7417 ASSERT_EQ(bstore
->fsck(false), 3);
7418 ASSERT_EQ(bstore
->repair(false), 0);
7419 ASSERT_EQ(bstore
->fsck(false), 0);
7421 cerr
<< "misreferencing" << std::endl
;
7423 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, 0);
7424 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, (offs_base
* repeats
) / 2);
7425 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, offs_base
* (repeats
-1) );
7428 ASSERT_EQ(bstore
->fsck(false), 6);
7429 ASSERT_EQ(bstore
->repair(false), 0);
7431 ASSERT_EQ(bstore
->fsck(true), 0);
7433 // reproducing issues #21040 & 20983
7434 SetVal(g_conf(), "bluestore_debug_inject_bug21040", "true");
7435 g_ceph_context
->_conf
.apply_changes(nullptr);
7438 cerr
<< "repro bug #21040" << std::endl
;
7440 auto ch
= store
->open_collection(cid
);
7442 ObjectStore::Transaction t
;
7443 bl
.append("0123456789012345");
7444 t
.write(cid
, hoid3
, offs_base
, bl
.length(), bl
);
7447 t
.write(cid
, hoid3
, 0, bl
.length(), bl
);
7449 r
= queue_transaction(store
, ch
, std::move(t
));
7453 ObjectStore::Transaction t
;
7454 t
.clone(cid
, hoid3
, hoid3_cloned
);
7455 r
= queue_transaction(store
, ch
, std::move(t
));
7460 ASSERT_EQ(bstore
->fsck(false), 3);
7461 ASSERT_LE(bstore
->repair(false), 0);
7462 ASSERT_EQ(bstore
->fsck(false), 0);
7465 // enable per-pool stats collection hence causing fsck to fail
7466 cerr
<< "per-pool statfs" << std::endl
;
7467 SetVal(g_conf(), "bluestore_no_per_pool_stats_tolerance", "until_fsck");
7468 g_ceph_context
->_conf
.apply_changes(nullptr);
7470 ASSERT_EQ(bstore
->fsck(false), 2);
7471 ASSERT_EQ(bstore
->repair(false), 0);
7472 ASSERT_EQ(bstore
->fsck(false), 0);
7474 cerr
<< "Completing" << std::endl
;
7479 TEST_P(StoreTest
, BluestoreStatistics
) {
7480 if (string(GetParam()) != "bluestore")
7483 SetVal(g_conf(), "rocksdb_perf", "true");
7484 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
7485 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
7486 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
7489 SetVal(g_conf(), "bluestore_cache_size_ssd", "0");
7490 SetVal(g_conf(), "bluestore_cache_size_hdd", "0");
7491 SetVal(g_conf(), "bluestore_cache_size", "0");
7492 g_ceph_context
->_conf
.apply_changes(nullptr);
7494 int r
= store
->umount();
7499 BlueStore
* bstore
= NULL
;
7500 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
7503 ghobject_t
hoid(hobject_t("test_db_statistics", "", CEPH_NOSNAP
, 0, 0, ""));
7504 auto ch
= bstore
->create_new_collection(cid
);
7506 bl
.append("0123456789abcdefghi");
7508 ObjectStore::Transaction t
;
7509 t
.create_collection(cid
, 0);
7511 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7512 cerr
<< "Write object" << std::endl
;
7513 r
= queue_transaction(bstore
, ch
, std::move(t
));
7517 bufferlist readback
;
7518 r
= store
->read(ch
, hoid
, 0, bl
.length(), readback
);
7519 ASSERT_EQ(static_cast<int>(bl
.length()), r
);
7520 ASSERT_TRUE(bl_eq(bl
, readback
));
7522 Formatter
*f
= Formatter::create("store_test", "json-pretty", "json-pretty");
7523 EXPECT_NO_THROW(store
->get_db_statistics(f
));
7528 TEST_P(StoreTestSpecificAUSize
, BluestoreTinyDevFailure
) {
7529 if (string(GetParam()) != "bluestore")
7531 // This caused superblock overwrite by bluefs, see
7532 // https://tracker.ceph.com/issues/24480
7533 SetVal(g_conf(), "bluestore_block_size",
7534 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7535 SetVal(g_conf(), "bluestore_block_db_size", "0");
7536 SetVal(g_conf(), "bluestore_block_db_create", "false");
7537 SetVal(g_conf(), "bluestore_bluefs_min",
7538 stringify(1024 * 1024 * 1024).c_str());
7539 StartDeferred(0x1000);
7541 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7545 TEST_P(StoreTestSpecificAUSize
, BluestoreTinyDevFailure2
) {
7546 if (string(GetParam()) != "bluestore")
7549 // This caused assert in allocator as initial bluefs extent as slow device
7550 // overlaped with superblock
7551 // https://tracker.ceph.com/issues/24480
7552 SetVal(g_conf(), "bluestore_block_size",
7553 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7554 SetVal(g_conf(), "bluestore_block_db_size",
7555 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7556 SetVal(g_conf(), "bluestore_block_db_create", "true");
7557 SetVal(g_conf(), "bluestore_bluefs_min",
7558 stringify(1024 * 1024 * 1024).c_str());
7559 StartDeferred(0x1000);
7561 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7565 TEST_P(StoreTest
, SpuriousReadErrorTest
) {
7566 if (string(GetParam()) != "bluestore")
7570 auto logger
= store
->get_perf_counters();
7572 auto ch
= store
->create_new_collection(cid
);
7573 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
7575 ObjectStore::Transaction t
;
7576 t
.create_collection(cid
, 0);
7577 cerr
<< "Creating collection " << cid
<< std::endl
;
7578 r
= queue_transaction(store
, ch
, std::move(t
));
7581 bufferlist test_data
;
7582 bufferptr
ap(0x2000);
7583 memset(ap
.c_str(), 'a', 0x2000);
7584 test_data
.append(ap
);
7586 ObjectStore::Transaction t
;
7587 t
.write(cid
, hoid
, 0, 0x2000, test_data
);
7588 r
= queue_transaction(store
, ch
, std::move(t
));
7590 // force cache clear
7591 EXPECT_EQ(store
->umount(), 0);
7592 EXPECT_EQ(store
->mount(), 0);
7595 cerr
<< "Injecting CRC error with no retry, expecting EIO" << std::endl
;
7596 SetVal(g_conf(), "bluestore_retry_disk_reads", "0");
7597 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "1");
7598 g_ceph_context
->_conf
.apply_changes(nullptr);
7601 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7603 ASSERT_EQ(logger
->get(l_bluestore_read_eio
), 1u);
7604 ASSERT_EQ(logger
->get(l_bluestore_reads_with_retries
), 0u);
7607 cerr
<< "Injecting CRC error with retries, expecting success after several retries" << std::endl
;
7608 SetVal(g_conf(), "bluestore_retry_disk_reads", "255");
7609 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "0.8");
7611 * Probabilistic test: 25 reads, each has a 80% chance of failing with 255 retries
7612 * Probability of at least one retried read: 1 - (0.2 ** 25) = 100% - 3e-18
7613 * Probability of a random test failure: 1 - ((1 - (0.8 ** 255)) ** 25) ~= 5e-24
7615 g_ceph_context
->_conf
.apply_changes(nullptr);
7617 for (int i
= 0; i
< 25; ++i
) {
7619 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7620 ASSERT_EQ(0x2000, r
);
7621 ASSERT_TRUE(bl_eq(test_data
, in
));
7623 ASSERT_GE(logger
->get(l_bluestore_reads_with_retries
), 1u);
7627 TEST_P(StoreTest
, allocateBlueFSTest
) {
7628 if (string(GetParam()) != "bluestore")
7631 BlueStore
* bstore
= NULL
;
7632 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
7634 struct store_statfs_t statfs
;
7635 store
->statfs(&statfs
);
7637 uint64_t to_alloc
= g_conf().get_val
<Option::size_t>("bluefs_alloc_size");
7639 int r
= bstore
->allocate_bluefs_freespace(to_alloc
, to_alloc
, nullptr);
7641 r
= bstore
->allocate_bluefs_freespace(statfs
.total
, statfs
.total
, nullptr);
7642 ASSERT_EQ(r
, -ENOSPC
);
7643 r
= bstore
->allocate_bluefs_freespace(to_alloc
* 16, to_alloc
* 16, nullptr);
7646 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7651 TEST_P(StoreTest
, mergeRegionTest
) {
7652 if (string(GetParam()) != "bluestore")
7655 SetVal(g_conf(), "bluestore_fsck_on_mount", "true");
7656 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
7657 SetVal(g_conf(), "bdev_debug_inflight_ios", "true");
7658 g_ceph_context
->_conf
.apply_changes(nullptr);
7660 uint32_t chunk_size
= g_ceph_context
->_conf
->bdev_block_size
;
7663 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
7664 auto ch
= store
->create_new_collection(cid
);
7666 ObjectStore::Transaction t
;
7667 t
.create_collection(cid
, 0);
7668 r
= queue_transaction(store
, ch
, std::move(t
));
7672 ObjectStore::Transaction t
;
7674 cerr
<< "Creating object " << hoid
<< std::endl
;
7675 r
= queue_transaction(store
, ch
, std::move(t
));
7679 bl5
.append("abcde");
7680 uint64_t offset
= 0;
7682 ObjectStore::Transaction t
;
7683 t
.write(cid
, hoid
, offset
, 5, bl5
);
7684 t
.write(cid
, hoid
, 0xa + offset
, 5, bl5
);
7685 t
.write(cid
, hoid
, 0x14 + offset
, 5, bl5
);
7686 r
= queue_transaction(store
, ch
, std::move(t
));
7689 { // 2. adjacent regions
7690 ObjectStore::Transaction t
;
7691 offset
= chunk_size
;
7692 t
.write(cid
, hoid
, offset
, 5, bl5
);
7693 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
7694 r
= queue_transaction(store
, ch
, std::move(t
));
7698 ObjectStore::Transaction t
;
7699 offset
= chunk_size
* 2;
7700 t
.write(cid
, hoid
, offset
, 5, bl5
);
7701 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, 5, bl5
);
7702 r
= queue_transaction(store
, ch
, std::move(t
));
7706 ObjectStore::Transaction t
;
7708 blc2
.append_zero(chunk_size
+ 2);
7710 offset
= chunk_size
* 3;
7711 t
.write(cid
, hoid
, offset
, chunk_size
+ 2, blc2
);
7712 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
7713 r
= queue_transaction(store
, ch
, std::move(t
));
7717 ObjectStore::Transaction t
;
7718 uint64_t final_len
= 0;
7719 offset
= chunk_size
* 10;
7721 bl2c2
.append_zero(chunk_size
* 2);
7722 t
.write(cid
, hoid
, offset
+ chunk_size
* 3 - 3, chunk_size
* 2, bl2c2
);
7723 bl2c2
.append_zero(2);
7724 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, chunk_size
* 2 + 2, bl2c2
);
7725 r
= queue_transaction(store
, ch
, std::move(t
));
7728 final_len
= (offset
+ chunk_size
* 3 - 3) + (chunk_size
* 2);
7730 r
= store
->read(ch
, hoid
, 0, final_len
, bl
);
7731 ASSERT_EQ(final_len
, static_cast<uint64_t>(r
));
7734 #endif // WITH_BLUESTORE
7736 int main(int argc
, char **argv
) {
7737 vector
<const char*> args
;
7738 argv_to_vec(argc
, (const char **)argv
, args
);
7740 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
7741 CODE_ENVIRONMENT_UTILITY
,
7742 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
7743 common_init_finish(g_ceph_context
);
7745 // make sure we can adjust any config settings
7746 g_ceph_context
->_conf
._clear_safe_to_start_threads();
7748 g_ceph_context
->_conf
.set_val_or_die("osd_journal_size", "400");
7749 g_ceph_context
->_conf
.set_val_or_die("filestore_index_retry_probability", "0.5");
7750 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_timeout", "1000");
7751 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_suicide_timeout", "10000");
7752 //g_ceph_context->_conf.set_val_or_die("filestore_fiemap", "true");
7753 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mkfs", "false");
7754 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mount", "false");
7755 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_umount", "false");
7756 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_misc", "true");
7757 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_small_allocations", "4");
7758 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_freelist", "true");
7759 g_ceph_context
->_conf
.set_val_or_die("bluestore_clone_cow", "true");
7760 g_ceph_context
->_conf
.set_val_or_die("bluestore_max_alloc_size", "196608");
7762 // set small cache sizes so we see trimming during Synthetic tests
7763 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_hdd", "4000000");
7764 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_ssd", "4000000");
7766 // very short *_max prealloc so that we fall back to async submits
7767 g_ceph_context
->_conf
.set_val_or_die("bluestore_blobid_prealloc", "10");
7768 g_ceph_context
->_conf
.set_val_or_die("bluestore_nid_prealloc", "10");
7769 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_randomize_serial_transaction",
7772 g_ceph_context
->_conf
.set_val_or_die("bdev_debug_aio", "true");
7774 // specify device size
7775 g_ceph_context
->_conf
.set_val_or_die("bluestore_block_size",
7776 stringify(DEF_STORE_TEST_BLOCKDEV_SIZE
));
7778 g_ceph_context
->_conf
.set_val_or_die(
7779 "enable_experimental_unrecoverable_data_corrupting_features", "*");
7780 g_ceph_context
->_conf
.apply_changes(nullptr);
7782 ::testing::InitGoogleTest(&argc
, argv
);
7783 return RUN_ALL_TESTS();
7788 * compile-command: "cd ../.. ; make ceph_test_objectstore &&
7789 * ./ceph_test_objectstore \
7790 * --gtest_filter=*.collect_metadata* --log-to-stderr=true --debug-filestore=20