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"
31 #include "os/bluestore/BlueFS.h"
33 #include "include/Context.h"
34 #include "common/ceph_argparse.h"
35 #include "common/admin_socket.h"
36 #include "global/global_init.h"
37 #include "common/ceph_mutex.h"
38 #include "common/Cond.h"
39 #include "common/errno.h"
40 #include "include/stringify.h"
41 #include "include/coredumpctl.h"
43 #include "include/unordered_map.h"
44 #include "store_test_fixture.h"
46 using namespace std::placeholders
;
48 typedef boost::mt11213b gen_type
;
50 const uint64_t DEF_STORE_TEST_BLOCKDEV_SIZE
= 10240000000;
51 #define dout_context g_ceph_context
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 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
1324 // just a big number to disble gc
1325 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "100000");
1326 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
1327 g_conf().apply_changes(nullptr);
1331 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
1332 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
1337 ghobject_t hoid2
= hoid
;
1338 hoid2
.hobj
.snap
= 1;
1340 auto ch
= store
->open_collection(cid
);
1343 auto ch
= store
->create_new_collection(cid
);
1345 ObjectStore::Transaction t
;
1346 t
.create_collection(cid
, 0);
1347 cerr
<< "Creating collection " << cid
<< std::endl
;
1348 r
= queue_transaction(store
, ch
, std::move(t
));
1352 bool exists
= store
->exists(ch
, hoid
);
1353 ASSERT_TRUE(!exists
);
1355 ObjectStore::Transaction t
;
1357 cerr
<< "Creating object " << hoid
<< std::endl
;
1358 r
= queue_transaction(store
, ch
, std::move(t
));
1361 exists
= store
->exists(ch
, hoid
);
1362 ASSERT_EQ(true, exists
);
1365 struct store_statfs_t statfs
;
1366 int r
= store
->statfs(&statfs
);
1368 ASSERT_EQ( 0u, statfs
.allocated
);
1369 ASSERT_EQ( 0u, statfs
.data_stored
);
1370 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
1371 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
1373 struct store_statfs_t statfs_pool
;
1375 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1377 ASSERT_EQ( 0u, statfs_pool
.allocated
);
1378 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
1382 EXPECT_EQ(store
->umount(), 0);
1383 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1384 EXPECT_EQ(store
->mount(), 0);
1385 ch
= store
->open_collection(cid
);
1388 ObjectStore::Transaction t
;
1391 t
.write(cid
, hoid
, 0, 5, bl
);
1392 cerr
<< "Append 5 bytes" << std::endl
;
1393 r
= queue_transaction(store
, ch
, std::move(t
));
1396 struct store_statfs_t statfs
;
1397 int r
= store
->statfs(&statfs
);
1399 ASSERT_EQ(5, statfs
.data_stored
);
1400 ASSERT_EQ(0x10000, statfs
.allocated
);
1401 ASSERT_EQ(0, statfs
.data_compressed
);
1402 ASSERT_EQ(0, statfs
.data_compressed_original
);
1403 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1405 struct store_statfs_t statfs_pool
;
1407 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1409 ASSERT_EQ(5, statfs_pool
.data_stored
);
1410 ASSERT_EQ(0x10000, statfs_pool
.allocated
);
1411 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1412 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1413 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1415 // accessing unknown pool
1416 r
= store
->pool_statfs(poolid
+ 1, &statfs_pool
, &per_pool_omap
);
1418 ASSERT_EQ(0, statfs_pool
.data_stored
);
1419 ASSERT_EQ(0, statfs_pool
.allocated
);
1420 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1421 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1422 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1426 EXPECT_EQ(store
->umount(), 0);
1427 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1428 EXPECT_EQ(store
->mount(), 0);
1429 ch
= store
->open_collection(cid
);
1432 ObjectStore::Transaction t
;
1433 std::string
s(0x30000, 'a');
1436 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1437 cerr
<< "Append 0x30000 compressible bytes" << std::endl
;
1438 r
= queue_transaction(store
, ch
, std::move(t
));
1441 struct store_statfs_t statfs
;
1442 int r
= store
->statfs(&statfs
);
1444 ASSERT_EQ(0x30005, statfs
.data_stored
);
1445 ASSERT_EQ(0x30000, statfs
.allocated
);
1446 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1447 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1448 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1450 struct store_statfs_t statfs_pool
;
1452 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1454 ASSERT_EQ(0x30005, statfs_pool
.data_stored
);
1455 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1456 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1457 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1458 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1461 EXPECT_EQ(store
->umount(), 0);
1462 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1463 EXPECT_EQ(store
->mount(), 0);
1464 ch
= store
->open_collection(cid
);
1467 ObjectStore::Transaction t
;
1468 t
.zero(cid
, hoid
, 1, 3);
1469 t
.zero(cid
, hoid
, 0x20000, 9);
1470 cerr
<< "Punch hole at 1~3, 0x20000~9" << std::endl
;
1471 r
= queue_transaction(store
, ch
, std::move(t
));
1474 struct store_statfs_t statfs
;
1475 int r
= store
->statfs(&statfs
);
1477 ASSERT_EQ(0x30005 - 3 - 9, statfs
.data_stored
);
1478 ASSERT_EQ(0x30000, statfs
.allocated
);
1479 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1480 ASSERT_EQ(0x20000 - 9, statfs
.data_compressed_original
);
1481 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1483 struct store_statfs_t statfs_pool
;
1485 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1487 ASSERT_EQ(0x30005 - 3 - 9, statfs_pool
.data_stored
);
1488 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1489 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1490 ASSERT_EQ(0x20000 - 9, statfs_pool
.data_compressed_original
);
1491 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1494 EXPECT_EQ(store
->umount(), 0);
1495 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1496 EXPECT_EQ(store
->mount(), 0);
1497 ch
= store
->open_collection(cid
);
1500 ObjectStore::Transaction t
;
1501 std::string
s(0x1000, 'b');
1504 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
1505 t
.write(cid
, hoid
, 0x10001, bl
.length(), bl
);
1506 cerr
<< "Overwrite first and second(compressible) extents" << std::endl
;
1507 r
= queue_transaction(store
, ch
, std::move(t
));
1510 struct store_statfs_t statfs
;
1511 int r
= store
->statfs(&statfs
);
1513 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs
.data_stored
);
1514 ASSERT_EQ(0x40000, statfs
.allocated
);
1515 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1516 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs
.data_compressed_original
);
1517 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1519 struct store_statfs_t statfs_pool
;
1521 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1523 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs_pool
.data_stored
);
1524 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1525 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1526 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs_pool
.data_compressed_original
);
1527 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1530 EXPECT_EQ(store
->umount(), 0);
1531 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1532 EXPECT_EQ(store
->mount(), 0);
1533 ch
= store
->open_collection(cid
);
1536 ObjectStore::Transaction t
;
1537 std::string
s(0x10000, 'c');
1540 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1541 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
1542 t
.write(cid
, hoid
, 0x30000, bl
.length(), bl
);
1543 cerr
<< "Overwrite compressed extent with 3 uncompressible ones" << std::endl
;
1544 r
= queue_transaction(store
, ch
, std::move(t
));
1547 struct store_statfs_t statfs
;
1548 int r
= store
->statfs(&statfs
);
1550 ASSERT_EQ(0x30000 + 0x1001, statfs
.data_stored
);
1551 ASSERT_EQ(0x40000, statfs
.allocated
);
1552 ASSERT_LE(statfs
.data_compressed
, 0);
1553 ASSERT_EQ(0, statfs
.data_compressed_original
);
1554 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1556 struct store_statfs_t statfs_pool
;
1558 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1560 ASSERT_EQ(0x30000 + 0x1001, statfs_pool
.data_stored
);
1561 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1562 ASSERT_LE(statfs_pool
.data_compressed
, 0);
1563 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1564 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1567 EXPECT_EQ(store
->umount(), 0);
1568 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1569 EXPECT_EQ(store
->mount(), 0);
1570 ch
= store
->open_collection(cid
);
1573 ObjectStore::Transaction t
;
1574 t
.zero(cid
, hoid
, 0, 0x40000);
1575 cerr
<< "Zero object" << std::endl
;
1576 r
= queue_transaction(store
, ch
, std::move(t
));
1578 struct store_statfs_t statfs
;
1579 int r
= store
->statfs(&statfs
);
1581 ASSERT_EQ(0u, statfs
.allocated
);
1582 ASSERT_EQ(0u, statfs
.data_stored
);
1583 ASSERT_EQ(0u, statfs
.data_compressed_original
);
1584 ASSERT_EQ(0u, statfs
.data_compressed
);
1585 ASSERT_EQ(0u, statfs
.data_compressed_allocated
);
1587 struct store_statfs_t statfs_pool
;
1589 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1591 ASSERT_EQ(0u, statfs_pool
.allocated
);
1592 ASSERT_EQ(0u, statfs_pool
.data_stored
);
1593 ASSERT_EQ(0u, statfs_pool
.data_compressed_original
);
1594 ASSERT_EQ(0u, statfs_pool
.data_compressed
);
1595 ASSERT_EQ(0u, statfs_pool
.data_compressed_allocated
);
1598 EXPECT_EQ(store
->umount(), 0);
1599 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1600 EXPECT_EQ(store
->mount(), 0);
1601 ch
= store
->open_collection(cid
);
1604 ObjectStore::Transaction t
;
1605 std::string
s(0x10000, 'c');
1610 bl
.append(s
.substr(0, 0x10000-2));
1611 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1612 cerr
<< "Yet another compressible write" << std::endl
;
1613 r
= queue_transaction(store
, ch
, std::move(t
));
1615 struct store_statfs_t statfs
;
1616 r
= store
->statfs(&statfs
);
1618 ASSERT_EQ(0x40000 - 2, statfs
.data_stored
);
1619 ASSERT_EQ(0x30000, statfs
.allocated
);
1620 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1621 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1622 ASSERT_EQ(0x10000, statfs
.data_compressed_allocated
);
1624 struct store_statfs_t statfs_pool
;
1626 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1628 ASSERT_EQ(0x40000 - 2, statfs_pool
.data_stored
);
1629 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1630 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1631 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1632 ASSERT_EQ(0x10000, statfs_pool
.data_compressed_allocated
);
1635 EXPECT_EQ(store
->umount(), 0);
1636 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1637 EXPECT_EQ(store
->mount(), 0);
1638 ch
= store
->open_collection(cid
);
1641 struct store_statfs_t statfs
;
1642 r
= store
->statfs(&statfs
);
1645 struct store_statfs_t statfs_pool
;
1647 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1650 ObjectStore::Transaction t
;
1651 t
.clone(cid
, hoid
, hoid2
);
1652 cerr
<< "Clone compressed objecte" << std::endl
;
1653 r
= queue_transaction(store
, ch
, std::move(t
));
1655 struct store_statfs_t statfs2
;
1656 r
= store
->statfs(&statfs2
);
1658 ASSERT_GT(statfs2
.data_stored
, statfs
.data_stored
);
1659 ASSERT_EQ(statfs2
.allocated
, statfs
.allocated
);
1660 ASSERT_GT(statfs2
.data_compressed
, statfs
.data_compressed
);
1661 ASSERT_GT(statfs2
.data_compressed_original
, statfs
.data_compressed_original
);
1662 ASSERT_EQ(statfs2
.data_compressed_allocated
, statfs
.data_compressed_allocated
);
1664 struct store_statfs_t statfs2_pool
;
1665 r
= store
->pool_statfs(poolid
, &statfs2_pool
, &per_pool_omap
);
1667 ASSERT_GT(statfs2_pool
.data_stored
, statfs_pool
.data_stored
);
1668 ASSERT_EQ(statfs2_pool
.allocated
, statfs_pool
.allocated
);
1669 ASSERT_GT(statfs2_pool
.data_compressed
, statfs_pool
.data_compressed
);
1670 ASSERT_GT(statfs2_pool
.data_compressed_original
,
1671 statfs_pool
.data_compressed_original
);
1672 ASSERT_EQ(statfs2_pool
.data_compressed_allocated
,
1673 statfs_pool
.data_compressed_allocated
);
1678 auto poolid2
= poolid
+ 1;
1679 coll_t cid2
= coll_t(spg_t(pg_t(20, poolid2
), shard_id_t::NO_SHARD
));
1680 ghobject_t
hoid(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
1685 auto ch
= store
->create_new_collection(cid2
);
1689 struct store_statfs_t statfs1_pool
;
1691 int r
= store
->pool_statfs(poolid
, &statfs1_pool
, &per_pool_omap
);
1694 cerr
<< "Creating second collection " << cid2
<< std::endl
;
1695 ObjectStore::Transaction t
;
1696 t
.create_collection(cid2
, 0);
1697 r
= queue_transaction(store
, ch
, std::move(t
));
1700 t
= ObjectStore::Transaction();
1703 t
.write(cid2
, hoid
, 0, 5, bl
);
1704 r
= queue_transaction(store
, ch
, std::move(t
));
1707 struct store_statfs_t statfs2_pool
;
1708 r
= store
->pool_statfs(poolid2
, &statfs2_pool
, &per_pool_omap
);
1710 ASSERT_EQ(5, statfs2_pool
.data_stored
);
1711 ASSERT_EQ(0x10000, statfs2_pool
.allocated
);
1712 ASSERT_EQ(0, statfs2_pool
.data_compressed
);
1713 ASSERT_EQ(0, statfs2_pool
.data_compressed_original
);
1714 ASSERT_EQ(0, statfs2_pool
.data_compressed_allocated
);
1716 struct store_statfs_t statfs1_pool_again
;
1717 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
, &per_pool_omap
);
1719 // adjust 'available' since it has changed
1720 statfs1_pool_again
.available
= statfs1_pool
.available
;
1721 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
1723 t
= ObjectStore::Transaction();
1724 t
.remove(cid2
, hoid
);
1725 t
.remove_collection(cid2
);
1726 cerr
<< "Cleaning" << std::endl
;
1727 r
= queue_transaction(store
, ch
, std::move(t
));
1733 // verify ops on temporary object
1735 auto poolid3
= poolid
+ 2;
1736 coll_t cid3
= coll_t(spg_t(pg_t(20, poolid3
), shard_id_t::NO_SHARD
));
1737 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
),
1742 ghobject_t hoid3_temp
;
1743 hoid3_temp
.hobj
= hoid3
.hobj
.make_temp_hobject("Object 3 temp");
1744 auto ch3
= store
->create_new_collection(cid3
);
1746 struct store_statfs_t statfs1_pool
;
1748 int r
= store
->pool_statfs(poolid
, &statfs1_pool
, &per_pool_omap
);
1751 cerr
<< "Creating third collection " << cid3
<< std::endl
;
1752 ObjectStore::Transaction t
;
1753 t
.create_collection(cid3
, 0);
1754 r
= queue_transaction(store
, ch3
, std::move(t
));
1757 t
= ObjectStore::Transaction();
1760 t
.write(cid3
, hoid3_temp
, 0, 5, bl
);
1761 r
= queue_transaction(store
, ch3
, std::move(t
));
1764 struct store_statfs_t statfs3_pool
;
1765 r
= store
->pool_statfs(poolid3
, &statfs3_pool
, &per_pool_omap
);
1767 ASSERT_EQ(5, statfs3_pool
.data_stored
);
1768 ASSERT_EQ(0x10000, statfs3_pool
.allocated
);
1769 ASSERT_EQ(0, statfs3_pool
.data_compressed
);
1770 ASSERT_EQ(0, statfs3_pool
.data_compressed_original
);
1771 ASSERT_EQ(0, statfs3_pool
.data_compressed_allocated
);
1773 struct store_statfs_t statfs1_pool_again
;
1774 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
, &per_pool_omap
);
1776 // adjust 'available' since it has changed
1777 statfs1_pool_again
.available
= statfs1_pool
.available
;
1778 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
1783 EXPECT_EQ(store
->umount(), 0);
1784 EXPECT_EQ(store
->mount(), 0);
1785 ch
= store
->open_collection(cid
);
1786 ch3
= store
->open_collection(cid3
);
1788 t
= ObjectStore::Transaction();
1789 t
.collection_move_rename(
1792 r
= queue_transaction(store
, ch3
, std::move(t
));
1795 struct store_statfs_t statfs3_pool_again
;
1796 r
= store
->pool_statfs(poolid3
, &statfs3_pool_again
, &per_pool_omap
);
1798 ASSERT_EQ(statfs3_pool_again
, statfs3_pool
);
1803 EXPECT_EQ(store
->umount(), 0);
1804 EXPECT_EQ(store
->mount(), 0);
1805 ch
= store
->open_collection(cid
);
1806 ch3
= store
->open_collection(cid3
);
1808 t
= ObjectStore::Transaction();
1809 t
.remove(cid3
, hoid3
);
1810 t
.remove_collection(cid3
);
1811 cerr
<< "Cleaning" << std::endl
;
1812 r
= queue_transaction(store
, ch3
, std::move(t
));
1818 ObjectStore::Transaction t
;
1819 t
.remove(cid
, hoid
);
1820 t
.remove(cid
, hoid2
);
1821 t
.remove_collection(cid
);
1822 cerr
<< "Cleaning" << std::endl
;
1823 r
= queue_transaction(store
, ch
, std::move(t
));
1826 struct store_statfs_t statfs
;
1827 r
= store
->statfs(&statfs
);
1829 ASSERT_EQ( 0u, statfs
.allocated
);
1830 ASSERT_EQ( 0u, statfs
.data_stored
);
1831 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
1832 ASSERT_EQ( 0u, statfs
.data_compressed
);
1833 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
1835 struct store_statfs_t statfs_pool
;
1837 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1839 ASSERT_EQ( 0u, statfs_pool
.allocated
);
1840 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
1841 ASSERT_EQ( 0u, statfs_pool
.data_compressed_original
);
1842 ASSERT_EQ( 0u, statfs_pool
.data_compressed
);
1843 ASSERT_EQ( 0u, statfs_pool
.data_compressed_allocated
);
1847 TEST_P(StoreTestSpecificAUSize
, BluestoreFragmentedBlobTest
) {
1848 if(string(GetParam()) != "bluestore")
1850 StartDeferred(0x10000);
1854 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1855 auto ch
= store
->create_new_collection(cid
);
1857 ObjectStore::Transaction t
;
1858 t
.create_collection(cid
, 0);
1859 cerr
<< "Creating collection " << cid
<< std::endl
;
1860 r
= queue_transaction(store
, ch
, std::move(t
));
1864 bool exists
= store
->exists(ch
, hoid
);
1865 ASSERT_TRUE(!exists
);
1867 ObjectStore::Transaction t
;
1869 cerr
<< "Creating object " << hoid
<< std::endl
;
1870 r
= queue_transaction(store
, ch
, std::move(t
));
1873 exists
= store
->exists(ch
, hoid
);
1874 ASSERT_EQ(true, exists
);
1877 struct store_statfs_t statfs
;
1878 int r
= store
->statfs(&statfs
);
1880 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
1881 ASSERT_EQ(0u, statfs
.allocated
);
1882 ASSERT_EQ(0u, statfs
.data_stored
);
1883 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
1886 data
.resize(0x10000 * 3);
1888 ObjectStore::Transaction t
;
1889 for(size_t i
= 0;i
< data
.size(); i
++)
1890 data
[i
] = i
/ 256 + 1;
1891 bufferlist bl
, newdata
;
1893 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1894 t
.zero(cid
, hoid
, 0x10000, 0x10000);
1895 cerr
<< "Append 3*0x10000 bytes and punch a hole 0x10000~10000" << std::endl
;
1896 r
= queue_transaction(store
, ch
, std::move(t
));
1899 struct store_statfs_t statfs
;
1900 int r
= store
->statfs(&statfs
);
1902 ASSERT_EQ(0x20000, statfs
.data_stored
);
1903 ASSERT_EQ(0x20000, statfs
.allocated
);
1905 r
= store
->read(ch
, hoid
, 0, data
.size(), newdata
);
1906 ASSERT_EQ(r
, (int)data
.size());
1908 bufferlist expected
;
1909 expected
.append(data
.substr(0, 0x10000));
1910 expected
.append(string(0x10000, 0));
1911 expected
.append(data
.substr(0x20000, 0x10000));
1912 ASSERT_TRUE(bl_eq(expected
, newdata
));
1916 r
= store
->read(ch
, hoid
, 1, data
.size()-2, newdata
);
1917 ASSERT_EQ(r
, (int)data
.size()-2);
1919 bufferlist expected
;
1920 expected
.append(data
.substr(1, 0x10000-1));
1921 expected
.append(string(0x10000, 0));
1922 expected
.append(data
.substr(0x20000, 0x10000 - 1));
1923 ASSERT_TRUE(bl_eq(expected
, newdata
));
1929 EXPECT_EQ(store
->umount(), 0);
1930 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1931 EXPECT_EQ(store
->mount(), 0);
1932 ch
= store
->open_collection(cid
);
1935 ObjectStore::Transaction t
;
1936 std::string
data2(3, 'b');
1937 bufferlist bl
, newdata
;
1939 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
1940 cerr
<< "Write 3 bytes after the hole" << std::endl
;
1941 r
= queue_transaction(store
, ch
, std::move(t
));
1944 struct store_statfs_t statfs
;
1945 int r
= store
->statfs(&statfs
);
1947 ASSERT_EQ(0x20000, statfs
.allocated
);
1948 ASSERT_EQ(0x20000, statfs
.data_stored
);
1950 r
= store
->read(ch
, hoid
, 0x20000-1, 21, newdata
);
1951 ASSERT_EQ(r
, (int)21);
1953 bufferlist expected
;
1954 expected
.append(string(0x1, 0));
1955 expected
.append(string(data2
));
1956 expected
.append(data
.substr(0x20003, 21-4));
1957 ASSERT_TRUE(bl_eq(expected
, newdata
));
1963 EXPECT_EQ(store
->umount(), 0);
1964 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1965 EXPECT_EQ(store
->mount(), 0);
1966 ch
= store
->open_collection(cid
);
1969 ObjectStore::Transaction t
;
1970 std::string
data2(3, 'a');
1971 bufferlist bl
, newdata
;
1973 t
.write(cid
, hoid
, 0x10000+1, bl
.length(), bl
);
1974 cerr
<< "Write 3 bytes to the hole" << std::endl
;
1975 r
= queue_transaction(store
, ch
, std::move(t
));
1978 struct store_statfs_t statfs
;
1979 int r
= store
->statfs(&statfs
);
1981 ASSERT_EQ(0x30000, statfs
.allocated
);
1982 ASSERT_EQ(0x20003, statfs
.data_stored
);
1984 r
= store
->read(ch
, hoid
, 0x10000-1, 0x10000+22, newdata
);
1985 ASSERT_EQ(r
, (int)0x10000+22);
1987 bufferlist expected
;
1988 expected
.append(data
.substr(0x10000-1, 1));
1989 expected
.append(string(0x1, 0));
1990 expected
.append(data2
);
1991 expected
.append(string(0x10000-4, 0));
1992 expected
.append(string(0x3, 'b'));
1993 expected
.append(data
.substr(0x20004, 21-3));
1994 ASSERT_TRUE(bl_eq(expected
, newdata
));
1999 ObjectStore::Transaction t
;
2000 bufferlist bl
, newdata
;
2001 bl
.append(string(0x30000, 'c'));
2002 t
.write(cid
, hoid
, 0, 0x30000, bl
);
2003 t
.zero(cid
, hoid
, 0, 0x10000);
2004 t
.zero(cid
, hoid
, 0x20000, 0x10000);
2005 cerr
<< "Rewrite an object and create two holes at the beginning and the end" << std::endl
;
2006 r
= queue_transaction(store
, ch
, std::move(t
));
2009 struct store_statfs_t statfs
;
2010 int r
= store
->statfs(&statfs
);
2012 ASSERT_EQ(0x10000, statfs
.allocated
);
2013 ASSERT_EQ(0x10000, statfs
.data_stored
);
2015 r
= store
->read(ch
, hoid
, 0, 0x30000, newdata
);
2016 ASSERT_EQ(r
, (int)0x30000);
2018 bufferlist expected
;
2019 expected
.append(string(0x10000, 0));
2020 expected
.append(string(0x10000, 'c'));
2021 expected
.append(string(0x10000, 0));
2022 ASSERT_TRUE(bl_eq(expected
, newdata
));
2029 EXPECT_EQ(store
->umount(), 0);
2030 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2031 EXPECT_EQ(store
->mount(), 0);
2032 ch
= store
->open_collection(cid
);
2035 ObjectStore::Transaction t
;
2036 t
.remove(cid
, hoid
);
2037 t
.remove_collection(cid
);
2038 cerr
<< "Cleaning" << std::endl
;
2039 r
= queue_transaction(store
, ch
, std::move(t
));
2042 struct store_statfs_t statfs
;
2043 r
= store
->statfs(&statfs
);
2045 ASSERT_EQ( 0u, statfs
.allocated
);
2046 ASSERT_EQ( 0u, statfs
.data_stored
);
2047 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
2048 ASSERT_EQ( 0u, statfs
.data_compressed
);
2049 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
2054 TEST_P(StoreTest
, ManySmallWrite
) {
2057 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2058 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2059 auto ch
= store
->create_new_collection(cid
);
2061 ObjectStore::Transaction t
;
2062 t
.create_collection(cid
, 0);
2063 cerr
<< "Creating collection " << cid
<< std::endl
;
2064 r
= queue_transaction(store
, ch
, std::move(t
));
2071 for (int i
=0; i
<100; ++i
) {
2072 ObjectStore::Transaction t
;
2073 t
.write(cid
, a
, i
*4096, 4096, bl
, 0);
2074 r
= queue_transaction(store
, ch
, std::move(t
));
2077 for (int i
=0; i
<100; ++i
) {
2078 ObjectStore::Transaction t
;
2079 t
.write(cid
, b
, (rand() % 1024)*4096, 4096, bl
, 0);
2080 r
= queue_transaction(store
, ch
, std::move(t
));
2084 ObjectStore::Transaction t
;
2087 t
.remove_collection(cid
);
2088 cerr
<< "Cleaning" << std::endl
;
2089 r
= queue_transaction(store
, ch
, std::move(t
));
2094 TEST_P(StoreTest
, MultiSmallWriteSameBlock
) {
2097 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2098 auto ch
= store
->create_new_collection(cid
);
2100 ObjectStore::Transaction t
;
2101 t
.create_collection(cid
, 0);
2102 cerr
<< "Creating collection " << cid
<< std::endl
;
2103 r
= queue_transaction(store
, ch
, std::move(t
));
2109 // touch same block in both same transaction, tls, and pipelined txns
2111 ObjectStore::Transaction t
, u
;
2112 t
.write(cid
, a
, 0, 5, bl
, 0);
2113 t
.write(cid
, a
, 5, 5, bl
, 0);
2114 t
.write(cid
, a
, 4094, 5, bl
, 0);
2115 t
.write(cid
, a
, 9000, 5, bl
, 0);
2116 u
.write(cid
, a
, 10, 5, bl
, 0);
2117 u
.write(cid
, a
, 7000, 5, bl
, 0);
2118 t
.register_on_commit(&c
);
2119 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2120 store
->queue_transactions(ch
, v
);
2123 ObjectStore::Transaction t
, u
;
2124 t
.write(cid
, a
, 40, 5, bl
, 0);
2125 t
.write(cid
, a
, 45, 5, bl
, 0);
2126 t
.write(cid
, a
, 4094, 5, bl
, 0);
2127 t
.write(cid
, a
, 6000, 5, bl
, 0);
2128 u
.write(cid
, a
, 610, 5, bl
, 0);
2129 u
.write(cid
, a
, 11000, 5, bl
, 0);
2130 t
.register_on_commit(&d
);
2131 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2132 store
->queue_transactions(ch
, v
);
2138 r
= store
->read(ch
, a
, 0, 16000, bl2
);
2142 ObjectStore::Transaction t
;
2144 t
.remove_collection(cid
);
2145 cerr
<< "Cleaning" << std::endl
;
2146 r
= queue_transaction(store
, ch
, std::move(t
));
2151 TEST_P(StoreTest
, SmallSkipFront
) {
2154 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2155 auto ch
= store
->create_new_collection(cid
);
2157 ObjectStore::Transaction t
;
2158 t
.create_collection(cid
, 0);
2159 cerr
<< "Creating collection " << cid
<< std::endl
;
2160 r
= queue_transaction(store
, ch
, std::move(t
));
2164 ObjectStore::Transaction t
;
2166 t
.truncate(cid
, a
, 3000);
2167 r
= queue_transaction(store
, ch
, std::move(t
));
2173 memset(bp
.c_str(), 1, 4096);
2175 ObjectStore::Transaction t
;
2176 t
.write(cid
, a
, 4096, 4096, bl
);
2177 r
= queue_transaction(store
, ch
, std::move(t
));
2182 ASSERT_EQ(8192, store
->read(ch
, a
, 0, 8192, bl
));
2183 for (unsigned i
=0; i
<4096; ++i
)
2184 ASSERT_EQ(0, bl
[i
]);
2185 for (unsigned i
=4096; i
<8192; ++i
)
2186 ASSERT_EQ(1, bl
[i
]);
2189 ObjectStore::Transaction t
;
2191 t
.remove_collection(cid
);
2192 cerr
<< "Cleaning" << std::endl
;
2193 r
= queue_transaction(store
, ch
, std::move(t
));
2198 TEST_P(StoreTest
, AppendDeferredVsTailCache
) {
2201 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2202 auto ch
= store
->create_new_collection(cid
);
2204 ObjectStore::Transaction t
;
2205 t
.create_collection(cid
, 0);
2206 cerr
<< "Creating collection " << cid
<< std::endl
;
2207 r
= store
->queue_transaction(ch
, std::move(t
));
2210 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2211 unsigned size
= min_alloc
/ 3;
2212 bufferptr
bpa(size
);
2213 memset(bpa
.c_str(), 1, bpa
.length());
2217 ObjectStore::Transaction t
;
2218 t
.write(cid
, a
, 0, bla
.length(), bla
, 0);
2219 r
= store
->queue_transaction(ch
, std::move(t
));
2223 // force cached tail to clear ...
2226 int r
= store
->umount();
2230 ch
= store
->open_collection(cid
);
2233 bufferptr
bpb(size
);
2234 memset(bpb
.c_str(), 2, bpb
.length());
2238 ObjectStore::Transaction t
;
2239 t
.write(cid
, a
, bla
.length(), blb
.length(), blb
, 0);
2240 r
= store
->queue_transaction(ch
, std::move(t
));
2243 bufferptr
bpc(size
);
2244 memset(bpc
.c_str(), 3, bpc
.length());
2248 ObjectStore::Transaction t
;
2249 t
.write(cid
, a
, bla
.length() + blb
.length(), blc
.length(), blc
, 0);
2250 r
= store
->queue_transaction(ch
, std::move(t
));
2259 ASSERT_EQ((int)final
.length(),
2260 store
->read(ch
, a
, 0, final
.length(), actual
));
2261 ASSERT_TRUE(bl_eq(final
, actual
));
2264 ObjectStore::Transaction t
;
2266 t
.remove_collection(cid
);
2267 cerr
<< "Cleaning" << std::endl
;
2268 r
= store
->queue_transaction(ch
, std::move(t
));
2273 TEST_P(StoreTest
, AppendZeroTrailingSharedBlock
) {
2276 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2279 auto ch
= store
->create_new_collection(cid
);
2281 ObjectStore::Transaction t
;
2282 t
.create_collection(cid
, 0);
2283 cerr
<< "Creating collection " << cid
<< std::endl
;
2284 r
= store
->queue_transaction(ch
, std::move(t
));
2287 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2288 unsigned size
= min_alloc
/ 3;
2289 bufferptr
bpa(size
);
2290 memset(bpa
.c_str(), 1, bpa
.length());
2293 // make sure there is some trailing gunk in the last block
2297 bt
.append("BADBADBADBAD");
2298 ObjectStore::Transaction t
;
2299 t
.write(cid
, a
, 0, bt
.length(), bt
, 0);
2300 r
= store
->queue_transaction(ch
, std::move(t
));
2304 ObjectStore::Transaction t
;
2305 t
.truncate(cid
, a
, size
);
2306 r
= store
->queue_transaction(ch
, std::move(t
));
2312 ObjectStore::Transaction t
;
2314 r
= store
->queue_transaction(ch
, std::move(t
));
2318 // append with implicit zeroing
2319 bufferptr
bpb(size
);
2320 memset(bpb
.c_str(), 2, bpb
.length());
2324 ObjectStore::Transaction t
;
2325 t
.write(cid
, a
, min_alloc
* 3, blb
.length(), blb
, 0);
2326 r
= store
->queue_transaction(ch
, std::move(t
));
2332 zeros
.append_zero(min_alloc
* 3 - size
);
2333 final
.append(zeros
);
2337 ASSERT_EQ((int)final
.length(),
2338 store
->read(ch
, a
, 0, final
.length(), actual
));
2339 final
.hexdump(cout
);
2340 actual
.hexdump(cout
);
2341 ASSERT_TRUE(bl_eq(final
, actual
));
2344 ObjectStore::Transaction t
;
2347 t
.remove_collection(cid
);
2348 cerr
<< "Cleaning" << std::endl
;
2349 r
= store
->queue_transaction(ch
, std::move(t
));
2354 TEST_P(StoreTest
, SmallSequentialUnaligned
) {
2357 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2358 auto ch
= store
->create_new_collection(cid
);
2360 ObjectStore::Transaction t
;
2361 t
.create_collection(cid
, 0);
2362 cerr
<< "Creating collection " << cid
<< std::endl
;
2363 r
= queue_transaction(store
, ch
, std::move(t
));
2371 for (int i
=0; i
<1000; ++i
) {
2372 ObjectStore::Transaction t
;
2373 t
.write(cid
, a
, i
*len
, len
, bl
, 0);
2374 r
= queue_transaction(store
, ch
, std::move(t
));
2378 ObjectStore::Transaction t
;
2380 t
.remove_collection(cid
);
2381 cerr
<< "Cleaning" << std::endl
;
2382 r
= queue_transaction(store
, ch
, std::move(t
));
2387 TEST_P(StoreTest
, ManyBigWrite
) {
2390 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2391 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2392 auto ch
= store
->create_new_collection(cid
);
2394 ObjectStore::Transaction t
;
2395 t
.create_collection(cid
, 0);
2396 cerr
<< "Creating collection " << cid
<< std::endl
;
2397 r
= queue_transaction(store
, ch
, std::move(t
));
2401 bufferptr
bp(4 * 1048576);
2404 for (int i
=0; i
<10; ++i
) {
2405 ObjectStore::Transaction t
;
2406 t
.write(cid
, a
, i
*4*1048586, 4*1048576, bl
, 0);
2407 r
= queue_transaction(store
, ch
, std::move(t
));
2411 for (int i
=0; i
<10; ++i
) {
2412 ObjectStore::Transaction t
;
2413 t
.write(cid
, b
, (rand() % 256)*4*1048576, 4*1048576, bl
, 0);
2414 r
= queue_transaction(store
, ch
, std::move(t
));
2418 for (int i
=0; i
<10; ++i
) {
2419 ObjectStore::Transaction t
;
2420 t
.write(cid
, b
, (rand() % (256*4096))*1024, 4*1048576, bl
, 0);
2421 r
= queue_transaction(store
, ch
, std::move(t
));
2425 for (int i
=0; i
<10; ++i
) {
2426 ObjectStore::Transaction t
;
2427 t
.zero(cid
, b
, (rand() % (256*4096))*1024, 16*1048576);
2428 r
= queue_transaction(store
, ch
, std::move(t
));
2432 ObjectStore::Transaction t
;
2435 t
.remove_collection(cid
);
2436 cerr
<< "Cleaning" << std::endl
;
2437 r
= queue_transaction(store
, ch
, std::move(t
));
2442 TEST_P(StoreTest
, BigWriteBigZero
) {
2445 ghobject_t
a(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2446 auto ch
= store
->create_new_collection(cid
);
2448 ObjectStore::Transaction t
;
2449 t
.create_collection(cid
, 0);
2450 r
= queue_transaction(store
, ch
, std::move(t
));
2454 bufferptr
bp(1048576);
2455 memset(bp
.c_str(), 'b', bp
.length());
2459 memset(sp
.c_str(), 's', sp
.length());
2462 ObjectStore::Transaction t
;
2463 t
.write(cid
, a
, 0, bl
.length(), bl
);
2464 r
= queue_transaction(store
, ch
, std::move(t
));
2468 ObjectStore::Transaction t
;
2469 t
.zero(cid
, a
, bl
.length() / 4, bl
.length() / 2);
2470 r
= queue_transaction(store
, ch
, std::move(t
));
2474 ObjectStore::Transaction t
;
2475 t
.write(cid
, a
, bl
.length() / 2, s
.length(), s
);
2476 r
= queue_transaction(store
, ch
, std::move(t
));
2480 ObjectStore::Transaction t
;
2482 t
.remove_collection(cid
);
2483 r
= queue_transaction(store
, ch
, std::move(t
));
2488 TEST_P(StoreTest
, MiscFragmentTests
) {
2491 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2492 auto ch
= store
->create_new_collection(cid
);
2494 ObjectStore::Transaction t
;
2495 t
.create_collection(cid
, 0);
2496 cerr
<< "Creating collection " << cid
<< std::endl
;
2497 r
= queue_transaction(store
, ch
, std::move(t
));
2501 bufferptr
bp(524288);
2505 ObjectStore::Transaction t
;
2506 t
.write(cid
, a
, 0, 524288, bl
, 0);
2507 r
= queue_transaction(store
, ch
, std::move(t
));
2511 ObjectStore::Transaction t
;
2512 t
.write(cid
, a
, 1048576, 524288, bl
, 0);
2513 r
= queue_transaction(store
, ch
, std::move(t
));
2518 int r
= store
->read(ch
, a
, 524288 + 131072, 1024, inbl
);
2520 ASSERT_EQ(inbl
.length(), 1024u);
2521 ASSERT_TRUE(inbl
.is_zero());
2524 ObjectStore::Transaction t
;
2525 t
.write(cid
, a
, 1048576 - 4096, 524288, bl
, 0);
2526 r
= queue_transaction(store
, ch
, std::move(t
));
2530 ObjectStore::Transaction t
;
2532 t
.remove_collection(cid
);
2533 cerr
<< "Cleaning" << std::endl
;
2534 r
= queue_transaction(store
, ch
, std::move(t
));
2540 TEST_P(StoreTest
, ZeroVsObjectSize
) {
2544 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2545 auto ch
= store
->create_new_collection(cid
);
2547 ObjectStore::Transaction t
;
2548 t
.create_collection(cid
, 0);
2549 cerr
<< "Creating collection " << cid
<< std::endl
;
2550 r
= queue_transaction(store
, ch
, std::move(t
));
2556 ObjectStore::Transaction t
;
2557 t
.write(cid
, hoid
, 0, 5, a
);
2558 r
= queue_transaction(store
, ch
, std::move(t
));
2561 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2562 ASSERT_EQ(5, stat
.st_size
);
2564 ObjectStore::Transaction t
;
2565 t
.zero(cid
, hoid
, 1, 2);
2566 r
= queue_transaction(store
, ch
, std::move(t
));
2569 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2570 ASSERT_EQ(5, stat
.st_size
);
2572 ObjectStore::Transaction t
;
2573 t
.zero(cid
, hoid
, 3, 200);
2574 r
= queue_transaction(store
, ch
, std::move(t
));
2577 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2578 ASSERT_EQ(203, stat
.st_size
);
2580 ObjectStore::Transaction t
;
2581 t
.zero(cid
, hoid
, 100000, 200);
2582 r
= queue_transaction(store
, ch
, std::move(t
));
2585 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2586 ASSERT_EQ(100200, stat
.st_size
);
2589 TEST_P(StoreTest
, ZeroLengthWrite
) {
2592 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2593 auto ch
= store
->create_new_collection(cid
);
2595 ObjectStore::Transaction t
;
2596 t
.create_collection(cid
, 0);
2598 r
= queue_transaction(store
, ch
, std::move(t
));
2602 ObjectStore::Transaction t
;
2604 t
.write(cid
, hoid
, 1048576, 0, empty
);
2605 r
= queue_transaction(store
, ch
, std::move(t
));
2609 r
= store
->stat(ch
, hoid
, &stat
);
2611 ASSERT_EQ(0, stat
.st_size
);
2614 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2618 TEST_P(StoreTest
, ZeroLengthZero
) {
2621 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2622 auto ch
= store
->create_new_collection(cid
);
2624 ObjectStore::Transaction t
;
2625 t
.create_collection(cid
, 0);
2627 r
= queue_transaction(store
, ch
, std::move(t
));
2631 ObjectStore::Transaction t
;
2632 t
.zero(cid
, hoid
, 1048576, 0);
2633 r
= queue_transaction(store
, ch
, std::move(t
));
2637 r
= store
->stat(ch
, hoid
, &stat
);
2639 ASSERT_EQ(0, stat
.st_size
);
2642 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2646 TEST_P(StoreTest
, SimpleAttrTest
) {
2649 ghobject_t
hoid(hobject_t(sobject_t("attr object 1", CEPH_NOSNAP
)));
2650 bufferlist val
, val2
;
2651 val
.append("value");
2652 val
.append("value2");
2654 auto ch
= store
->open_collection(cid
);
2657 auto ch
= store
->create_new_collection(cid
);
2659 ObjectStore::Transaction t
;
2660 t
.create_collection(cid
, 0);
2661 r
= queue_transaction(store
, ch
, std::move(t
));
2666 int r
= store
->collection_empty(ch
, &empty
);
2672 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2673 ASSERT_EQ(-ENOENT
, r
);
2676 ObjectStore::Transaction t
;
2678 t
.setattr(cid
, hoid
, "foo", val
);
2679 t
.setattr(cid
, hoid
, "bar", val2
);
2680 r
= queue_transaction(store
, ch
, std::move(t
));
2685 int r
= store
->collection_empty(ch
, &empty
);
2687 ASSERT_TRUE(!empty
);
2691 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2692 ASSERT_EQ(-ENODATA
, r
);
2694 r
= store
->getattr(ch
, hoid
, "foo", bp
);
2698 ASSERT_TRUE(bl_eq(val
, bl
));
2700 map
<string
,bufferptr
> bm
;
2701 r
= store
->getattrs(ch
, hoid
, bm
);
2706 ObjectStore::Transaction t
;
2707 t
.remove(cid
, hoid
);
2708 t
.remove_collection(cid
);
2709 r
= queue_transaction(store
, ch
, std::move(t
));
2714 TEST_P(StoreTest
, SimpleListTest
) {
2716 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2717 auto ch
= store
->create_new_collection(cid
);
2719 ObjectStore::Transaction t
;
2720 t
.create_collection(cid
, 0);
2721 cerr
<< "Creating collection " << cid
<< std::endl
;
2722 r
= queue_transaction(store
, ch
, std::move(t
));
2725 set
<ghobject_t
> all
;
2727 ObjectStore::Transaction t
;
2728 for (int i
=0; i
<200; ++i
) {
2729 string
name("object_");
2730 name
+= stringify(i
);
2731 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
2732 ghobject_t::NO_GEN
, shard_id_t(1));
2736 cerr
<< "Creating object " << hoid
<< std::endl
;
2738 r
= queue_transaction(store
, ch
, std::move(t
));
2742 set
<ghobject_t
> saw
;
2743 vector
<ghobject_t
> objects
;
2744 ghobject_t next
, current
;
2745 while (!next
.is_max()) {
2746 int r
= store
->collection_list(ch
, current
, ghobject_t::get_max(),
2750 ASSERT_TRUE(sorted(objects
));
2751 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
2752 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
2754 if (saw
.count(*p
)) {
2755 cout
<< "got DUP " << *p
<< std::endl
;
2757 //cout << "got new " << *p << std::endl;
2764 ASSERT_EQ(saw
.size(), all
.size());
2765 ASSERT_EQ(saw
, all
);
2768 ObjectStore::Transaction t
;
2769 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
2771 t
.remove_collection(cid
);
2772 cerr
<< "Cleaning" << std::endl
;
2773 r
= queue_transaction(store
, ch
, std::move(t
));
2778 TEST_P(StoreTest
, ListEndTest
) {
2780 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2781 auto ch
= store
->create_new_collection(cid
);
2783 ObjectStore::Transaction t
;
2784 t
.create_collection(cid
, 0);
2785 cerr
<< "Creating collection " << cid
<< std::endl
;
2786 r
= queue_transaction(store
, ch
, std::move(t
));
2789 set
<ghobject_t
> all
;
2791 ObjectStore::Transaction t
;
2792 for (int i
=0; i
<200; ++i
) {
2793 string
name("object_");
2794 name
+= stringify(i
);
2795 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
2796 ghobject_t::NO_GEN
, shard_id_t(1));
2800 cerr
<< "Creating object " << hoid
<< std::endl
;
2802 r
= queue_transaction(store
, ch
, std::move(t
));
2806 ghobject_t
end(hobject_t(sobject_t("object_100", CEPH_NOSNAP
)),
2807 ghobject_t::NO_GEN
, shard_id_t(1));
2809 vector
<ghobject_t
> objects
;
2811 int r
= store
->collection_list(ch
, ghobject_t(), end
, 500,
2814 for (auto &p
: objects
) {
2819 ObjectStore::Transaction t
;
2820 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
2822 t
.remove_collection(cid
);
2823 cerr
<< "Cleaning" << std::endl
;
2824 r
= queue_transaction(store
, ch
, std::move(t
));
2829 TEST_P(StoreTest
, Sort
) {
2831 hobject_t
a(sobject_t("a", CEPH_NOSNAP
));
2844 ghobject_t
a(hobject_t(sobject_t("a", CEPH_NOSNAP
)));
2845 ghobject_t
b(hobject_t(sobject_t("b", CEPH_NOSNAP
)));
2857 TEST_P(StoreTest
, MultipoolListTest
) {
2860 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
2861 auto ch
= store
->create_new_collection(cid
);
2863 ObjectStore::Transaction t
;
2864 t
.create_collection(cid
, 0);
2865 cerr
<< "Creating collection " << cid
<< std::endl
;
2866 r
= queue_transaction(store
, ch
, std::move(t
));
2869 set
<ghobject_t
> all
, saw
;
2871 ObjectStore::Transaction t
;
2872 for (int i
=0; i
<200; ++i
) {
2873 string
name("object_");
2874 name
+= stringify(i
);
2875 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)));
2877 hoid
.hobj
.pool
= -2 - poolid
;
2879 hoid
.hobj
.pool
= poolid
;
2882 cerr
<< "Creating object " << hoid
<< std::endl
;
2884 r
= queue_transaction(store
, ch
, std::move(t
));
2888 vector
<ghobject_t
> objects
;
2889 ghobject_t next
, current
;
2890 while (!next
.is_max()) {
2891 int r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 50,
2894 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
2895 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
2902 ASSERT_EQ(saw
, all
);
2905 ObjectStore::Transaction t
;
2906 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
2908 t
.remove_collection(cid
);
2909 cerr
<< "Cleaning" << std::endl
;
2910 r
= queue_transaction(store
, ch
, std::move(t
));
2915 TEST_P(StoreTest
, SimpleCloneTest
) {
2918 auto ch
= store
->create_new_collection(cid
);
2920 ObjectStore::Transaction t
;
2921 t
.create_collection(cid
, 0);
2922 cerr
<< "Creating collection " << cid
<< std::endl
;
2923 r
= queue_transaction(store
, ch
, std::move(t
));
2926 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
2927 "key", 123, -1, ""));
2928 bufferlist small
, large
, xlarge
, newdata
, attr
;
2929 small
.append("small");
2930 large
.append("large");
2931 xlarge
.append("xlarge");
2933 ObjectStore::Transaction t
;
2935 t
.setattr(cid
, hoid
, "attr1", small
);
2936 t
.setattr(cid
, hoid
, "attr2", large
);
2937 t
.setattr(cid
, hoid
, "attr3", xlarge
);
2938 t
.write(cid
, hoid
, 0, small
.length(), small
);
2939 t
.write(cid
, hoid
, 10, small
.length(), small
);
2940 cerr
<< "Creating object and set attr " << hoid
<< std::endl
;
2941 r
= queue_transaction(store
, ch
, std::move(t
));
2945 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
2946 "key", 123, -1, ""));
2947 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
)));
2949 ObjectStore::Transaction t
;
2950 t
.clone(cid
, hoid
, hoid2
);
2951 t
.setattr(cid
, hoid2
, "attr2", small
);
2952 t
.rmattr(cid
, hoid2
, "attr1");
2953 t
.write(cid
, hoid
, 10, large
.length(), large
);
2954 t
.setattr(cid
, hoid
, "attr1", large
);
2955 t
.setattr(cid
, hoid
, "attr2", small
);
2956 cerr
<< "Clone object and rm attr" << std::endl
;
2957 r
= queue_transaction(store
, ch
, std::move(t
));
2960 r
= store
->read(ch
, hoid
, 10, 5, newdata
);
2962 ASSERT_TRUE(bl_eq(large
, newdata
));
2965 r
= store
->read(ch
, hoid
, 0, 5, newdata
);
2967 ASSERT_TRUE(bl_eq(small
, newdata
));
2970 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
2972 ASSERT_TRUE(bl_eq(small
, newdata
));
2974 r
= store
->getattr(ch
, hoid2
, "attr2", attr
);
2976 ASSERT_TRUE(bl_eq(small
, attr
));
2979 r
= store
->getattr(ch
, hoid2
, "attr3", attr
);
2981 ASSERT_TRUE(bl_eq(xlarge
, attr
));
2984 r
= store
->getattr(ch
, hoid
, "attr1", attr
);
2986 ASSERT_TRUE(bl_eq(large
, attr
));
2989 ObjectStore::Transaction t
;
2990 t
.remove(cid
, hoid
);
2991 t
.remove(cid
, hoid2
);
2992 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
2997 memset(p
.c_str(), 1, p
.length());
3001 ObjectStore::Transaction t
;
3002 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3003 t
.clone(cid
, hoid
, hoid2
);
3005 memset(a
.c_str(), 2, a
.length());
3009 t
.write(cid
, hoid
, pl
.length(), a
.length(), al
);
3010 r
= queue_transaction(store
, ch
, std::move(t
));
3013 ASSERT_EQ((int)final
.length(),
3014 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3015 ASSERT_TRUE(bl_eq(rl
, final
));
3018 ObjectStore::Transaction t
;
3019 t
.remove(cid
, hoid
);
3020 t
.remove(cid
, hoid2
);
3021 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3026 memset(p
.c_str(), 111, p
.length());
3030 ObjectStore::Transaction t
;
3031 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3032 t
.clone(cid
, hoid
, hoid2
);
3037 memset(a
.c_str(), 112, a
.length());
3041 t
.write(cid
, hoid
, pl
.length() + z
.length(), a
.length(), al
);
3042 r
= queue_transaction(store
, ch
, std::move(t
));
3045 ASSERT_EQ((int)final
.length(),
3046 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3047 ASSERT_TRUE(bl_eq(rl
, final
));
3050 ObjectStore::Transaction t
;
3051 t
.remove(cid
, hoid
);
3052 t
.remove(cid
, hoid2
);
3053 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3058 memset(p
.c_str(), 5, p
.length());
3062 ObjectStore::Transaction t
;
3063 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3064 t
.clone(cid
, hoid
, hoid2
);
3069 memset(a
.c_str(), 6, a
.length());
3073 t
.write(cid
, hoid
, 17000, a
.length(), al
);
3074 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3076 ASSERT_EQ((int)final
.length(),
3077 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3078 /*cout << "expected:\n";
3079 final.hexdump(cout);
3082 ASSERT_TRUE(bl_eq(rl
, final
));
3085 ObjectStore::Transaction t
;
3086 t
.remove(cid
, hoid
);
3087 t
.remove(cid
, hoid2
);
3088 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3091 bufferptr
p(1048576);
3092 memset(p
.c_str(), 3, p
.length());
3095 ObjectStore::Transaction t
;
3096 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3097 t
.clone(cid
, hoid
, hoid2
);
3099 memset(a
.c_str(), 4, a
.length());
3102 t
.write(cid
, hoid
, a
.length(), a
.length(), al
);
3103 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3106 final
.substr_of(pl
, 0, al
.length());
3109 end
.substr_of(pl
, al
.length()*2, pl
.length() - al
.length()*2);
3111 ASSERT_EQ((int)final
.length(),
3112 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3113 /*cout << "expected:\n";
3114 final.hexdump(cout);
3117 ASSERT_TRUE(bl_eq(rl
, final
));
3120 ObjectStore::Transaction t
;
3121 t
.remove(cid
, hoid
);
3122 t
.remove(cid
, hoid2
);
3123 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3127 memset(p
.c_str(), 7, p
.length());
3130 ObjectStore::Transaction t
;
3131 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3132 t
.clone(cid
, hoid
, hoid2
);
3134 memset(a
.c_str(), 8, a
.length());
3137 t
.write(cid
, hoid
, 32768, a
.length(), al
);
3138 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3141 final
.substr_of(pl
, 0, 32768);
3144 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3146 ASSERT_EQ((int)final
.length(),
3147 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3148 /*cout << "expected:\n";
3149 final.hexdump(cout);
3152 ASSERT_TRUE(bl_eq(rl
, final
));
3155 ObjectStore::Transaction t
;
3156 t
.remove(cid
, hoid
);
3157 t
.remove(cid
, hoid2
);
3158 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3162 memset(p
.c_str(), 9, p
.length());
3165 ObjectStore::Transaction t
;
3166 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3167 t
.clone(cid
, hoid
, hoid2
);
3169 memset(a
.c_str(), 10, a
.length());
3172 t
.write(cid
, hoid
, 33768, a
.length(), al
);
3173 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3176 final
.substr_of(pl
, 0, 33768);
3179 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3181 ASSERT_EQ((int)final
.length(),
3182 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3183 /*cout << "expected:\n";
3184 final.hexdump(cout);
3187 ASSERT_TRUE(bl_eq(rl
, final
));
3190 //Unfortunately we need a workaround for filestore since EXPECT_DEATH
3191 // macro has potential issues when using /in multithread environments.
3192 //It works well for all stores but filestore for now.
3193 //A fix setting gtest_death_test_style = "threadsafe" doesn't help as well -
3194 // test app clone asserts on store folder presence.
3196 if (string(GetParam()) != "filestore") {
3197 //verify if non-empty collection is properly handled after store reload
3199 r
= store
->umount();
3203 ch
= store
->open_collection(cid
);
3205 ObjectStore::Transaction t
;
3206 t
.remove_collection(cid
);
3207 cerr
<< "Invalid rm coll" << std::endl
;
3208 PrCtl unset_dumpable
;
3209 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3212 ObjectStore::Transaction t
;
3213 t
.touch(cid
, hoid3
); //new record in db
3214 r
= queue_transaction(store
, ch
, std::move(t
));
3217 //See comment above for "filestore" check explanation.
3218 if (string(GetParam()) != "filestore") {
3219 ObjectStore::Transaction t
;
3220 //verify if non-empty collection is properly handled when there are some pending removes and live records in db
3221 cerr
<< "Invalid rm coll again" << std::endl
;
3223 r
= store
->umount();
3227 ch
= store
->open_collection(cid
);
3229 t
.remove(cid
, hoid
);
3230 t
.remove(cid
, hoid2
);
3231 t
.remove_collection(cid
);
3232 PrCtl unset_dumpable
;
3233 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3236 ObjectStore::Transaction t
;
3237 t
.remove(cid
, hoid
);
3238 t
.remove(cid
, hoid2
);
3239 t
.remove(cid
, hoid3
);
3240 t
.remove_collection(cid
);
3241 cerr
<< "Cleaning" << std::endl
;
3242 r
= queue_transaction(store
, ch
, std::move(t
));
3247 TEST_P(StoreTest
, OmapSimple
) {
3250 auto ch
= store
->create_new_collection(cid
);
3252 ObjectStore::Transaction t
;
3253 t
.create_collection(cid
, 0);
3254 cerr
<< "Creating collection " << cid
<< std::endl
;
3255 r
= queue_transaction(store
, ch
, std::move(t
));
3258 ghobject_t
hoid(hobject_t(sobject_t("omap_obj", CEPH_NOSNAP
),
3259 "key", 123, -1, ""));
3261 small
.append("small");
3262 map
<string
,bufferlist
> km
;
3264 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3266 header
.append("this is a header");
3268 ObjectStore::Transaction t
;
3270 t
.omap_setkeys(cid
, hoid
, km
);
3271 t
.omap_setheader(cid
, hoid
, header
);
3272 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3273 r
= queue_transaction(store
, ch
, std::move(t
));
3279 map
<string
,bufferlist
> r
;
3280 store
->omap_get(ch
, hoid
, &h
, &r
);
3281 ASSERT_TRUE(bl_eq(header
, h
));
3282 ASSERT_EQ(r
.size(), km
.size());
3283 cout
<< "r: " << r
<< std::endl
;
3285 // test iterator with seek_to_first
3287 map
<string
,bufferlist
> r
;
3288 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3289 for (iter
->seek_to_first(); iter
->valid(); iter
->next()) {
3290 r
[iter
->key()] = iter
->value();
3292 cout
<< "r: " << r
<< std::endl
;
3293 ASSERT_EQ(r
.size(), km
.size());
3295 // test iterator with initial lower_bound
3297 map
<string
,bufferlist
> r
;
3298 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3299 for (iter
->lower_bound(string()); iter
->valid(); iter
->next()) {
3300 r
[iter
->key()] = iter
->value();
3302 cout
<< "r: " << r
<< std::endl
;
3303 ASSERT_EQ(r
.size(), km
.size());
3306 ObjectStore::Transaction t
;
3307 t
.remove(cid
, hoid
);
3308 t
.remove_collection(cid
);
3309 cerr
<< "Cleaning" << std::endl
;
3310 r
= queue_transaction(store
, ch
, std::move(t
));
3315 TEST_P(StoreTest
, OmapCloneTest
) {
3318 auto ch
= store
->create_new_collection(cid
);
3320 ObjectStore::Transaction t
;
3321 t
.create_collection(cid
, 0);
3322 cerr
<< "Creating collection " << cid
<< std::endl
;
3323 r
= queue_transaction(store
, ch
, std::move(t
));
3326 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
3327 "key", 123, -1, ""));
3329 small
.append("small");
3330 map
<string
,bufferlist
> km
;
3332 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3334 header
.append("this is a header");
3336 ObjectStore::Transaction t
;
3338 t
.omap_setkeys(cid
, hoid
, km
);
3339 t
.omap_setheader(cid
, hoid
, header
);
3340 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3341 r
= queue_transaction(store
, ch
, std::move(t
));
3344 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
3345 "key", 123, -1, ""));
3347 ObjectStore::Transaction t
;
3348 t
.clone(cid
, hoid
, hoid2
);
3349 cerr
<< "Clone object" << std::endl
;
3350 r
= queue_transaction(store
, ch
, std::move(t
));
3354 map
<string
,bufferlist
> r
;
3356 store
->omap_get(ch
, hoid2
, &h
, &r
);
3357 ASSERT_TRUE(bl_eq(header
, h
));
3358 ASSERT_EQ(r
.size(), km
.size());
3361 ObjectStore::Transaction t
;
3362 t
.remove(cid
, hoid
);
3363 t
.remove(cid
, hoid2
);
3364 t
.remove_collection(cid
);
3365 cerr
<< "Cleaning" << std::endl
;
3366 r
= queue_transaction(store
, ch
, std::move(t
));
3371 TEST_P(StoreTest
, SimpleCloneRangeTest
) {
3374 auto ch
= store
->create_new_collection(cid
);
3376 ObjectStore::Transaction t
;
3377 t
.create_collection(cid
, 0);
3378 cerr
<< "Creating collection " << cid
<< std::endl
;
3379 r
= queue_transaction(store
, ch
, std::move(t
));
3382 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3383 hoid
.hobj
.pool
= -1;
3384 bufferlist small
, newdata
;
3385 small
.append("small");
3387 ObjectStore::Transaction t
;
3388 t
.write(cid
, hoid
, 10, 5, small
);
3389 cerr
<< "Creating object and write bl " << hoid
<< std::endl
;
3390 r
= queue_transaction(store
, ch
, std::move(t
));
3393 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
3394 hoid2
.hobj
.pool
= -1;
3396 ObjectStore::Transaction t
;
3397 t
.clone_range(cid
, hoid
, hoid2
, 10, 5, 10);
3398 cerr
<< "Clone range object" << std::endl
;
3399 r
= queue_transaction(store
, ch
, std::move(t
));
3401 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
3403 ASSERT_TRUE(bl_eq(small
, newdata
));
3406 ObjectStore::Transaction t
;
3407 t
.truncate(cid
, hoid
, 1024*1024);
3408 t
.clone_range(cid
, hoid
, hoid2
, 0, 1024*1024, 0);
3409 cerr
<< "Clone range object" << std::endl
;
3410 r
= queue_transaction(store
, ch
, std::move(t
));
3412 struct stat stat
, stat2
;
3413 r
= store
->stat(ch
, hoid
, &stat
);
3414 r
= store
->stat(ch
, hoid2
, &stat2
);
3415 ASSERT_EQ(stat
.st_size
, stat2
.st_size
);
3416 ASSERT_EQ(1024*1024, stat2
.st_size
);
3419 ObjectStore::Transaction t
;
3420 t
.remove(cid
, hoid
);
3421 t
.remove(cid
, hoid2
);
3422 t
.remove_collection(cid
);
3423 cerr
<< "Cleaning" << std::endl
;
3424 r
= queue_transaction(store
, ch
, std::move(t
));
3430 TEST_P(StoreTest
, SimpleObjectLongnameTest
) {
3433 auto ch
= store
->create_new_collection(cid
);
3435 ObjectStore::Transaction t
;
3436 t
.create_collection(cid
, 0);
3437 cerr
<< "Creating collection " << cid
<< std::endl
;
3438 r
= queue_transaction(store
, ch
, std::move(t
));
3441 ghobject_t
hoid(hobject_t(sobject_t("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaObjectaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1", CEPH_NOSNAP
)));
3443 ObjectStore::Transaction t
;
3445 cerr
<< "Creating object " << hoid
<< std::endl
;
3446 r
= queue_transaction(store
, ch
, std::move(t
));
3450 ObjectStore::Transaction t
;
3451 t
.remove(cid
, hoid
);
3452 t
.remove_collection(cid
);
3453 cerr
<< "Cleaning" << std::endl
;
3454 r
= queue_transaction(store
, ch
, std::move(t
));
3459 ghobject_t
generate_long_name(unsigned i
)
3462 name
<< "object id " << i
<< " ";
3463 for (unsigned j
= 0; j
< 500; ++j
) name
<< 'a';
3464 ghobject_t
hoid(hobject_t(sobject_t(name
.str(), CEPH_NOSNAP
)));
3465 hoid
.hobj
.set_hash(i
% 2);
3469 TEST_P(StoreTest
, LongnameSplitTest
) {
3472 auto ch
= store
->create_new_collection(cid
);
3474 ObjectStore::Transaction t
;
3475 t
.create_collection(cid
, 0);
3476 cerr
<< "Creating collection " << cid
<< std::endl
;
3477 r
= queue_transaction(store
, ch
, std::move(t
));
3480 for (unsigned i
= 0; i
< 320; ++i
) {
3481 ObjectStore::Transaction t
;
3482 ghobject_t hoid
= generate_long_name(i
);
3484 cerr
<< "Creating object " << hoid
<< std::endl
;
3485 r
= queue_transaction(store
, ch
, std::move(t
));
3489 ghobject_t test_obj
= generate_long_name(319);
3490 ghobject_t test_obj_2
= test_obj
;
3491 test_obj_2
.generation
= 0;
3493 ObjectStore::Transaction t
;
3494 // should cause a split
3495 t
.collection_move_rename(
3498 r
= queue_transaction(store
, ch
, std::move(t
));
3502 for (unsigned i
= 0; i
< 319; ++i
) {
3503 ObjectStore::Transaction t
;
3504 ghobject_t hoid
= generate_long_name(i
);
3505 t
.remove(cid
, hoid
);
3506 cerr
<< "Removing object " << hoid
<< std::endl
;
3507 r
= queue_transaction(store
, ch
, std::move(t
));
3511 ObjectStore::Transaction t
;
3512 t
.remove(cid
, test_obj_2
);
3513 t
.remove_collection(cid
);
3514 cerr
<< "Cleaning" << std::endl
;
3515 r
= queue_transaction(store
, ch
, std::move(t
));
3521 TEST_P(StoreTest
, ManyObjectTest
) {
3522 int NUM_OBJS
= 2000;
3526 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
3527 set
<ghobject_t
> created
;
3528 auto ch
= store
->create_new_collection(cid
);
3530 ObjectStore::Transaction t
;
3531 t
.create_collection(cid
, 0);
3532 r
= queue_transaction(store
, ch
, std::move(t
));
3535 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
3537 cerr
<< "Object " << i
<< std::endl
;
3539 ObjectStore::Transaction t
;
3541 snprintf(buf
, sizeof(buf
), "%d", i
);
3542 ghobject_t
hoid(hobject_t(sobject_t(string(buf
) + base
, CEPH_NOSNAP
)));
3544 created
.insert(hoid
);
3545 r
= queue_transaction(store
, ch
, std::move(t
));
3549 for (set
<ghobject_t
>::iterator i
= created
.begin();
3553 ASSERT_TRUE(!store
->stat(ch
, *i
, &buf
));
3556 set
<ghobject_t
> listed
, listed2
;
3557 vector
<ghobject_t
> objects
;
3558 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
, &objects
, 0);
3561 cerr
<< "objects.size() is " << objects
.size() << std::endl
;
3562 for (vector
<ghobject_t
> ::iterator i
= objects
.begin();
3566 ASSERT_TRUE(created
.count(*i
));
3568 ASSERT_TRUE(listed
.size() == created
.size());
3570 ghobject_t start
, next
;
3572 r
= store
->collection_list(
3574 ghobject_t::get_max(),
3575 ghobject_t::get_max(),
3581 ASSERT_TRUE(objects
.empty());
3585 ghobject_t start2
, next2
;
3587 r
= store
->collection_list(ch
, start
, ghobject_t::get_max(),
3591 ASSERT_TRUE(sorted(objects
));
3593 listed
.insert(objects
.begin(), objects
.end());
3594 if (objects
.size() < 50) {
3595 ASSERT_TRUE(next
.is_max());
3602 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
3603 ASSERT_TRUE(listed
.size() == created
.size());
3604 if (listed2
.size()) {
3605 ASSERT_EQ(listed
.size(), listed2
.size());
3607 for (set
<ghobject_t
>::iterator i
= listed
.begin();
3610 ASSERT_TRUE(created
.count(*i
));
3613 for (set
<ghobject_t
>::iterator i
= created
.begin();
3616 ObjectStore::Transaction t
;
3618 r
= queue_transaction(store
, ch
, std::move(t
));
3621 cerr
<< "cleaning up" << std::endl
;
3623 ObjectStore::Transaction t
;
3624 t
.remove_collection(cid
);
3625 r
= queue_transaction(store
, ch
, std::move(t
));
3631 class ObjectGenerator
{
3633 virtual ghobject_t
create_object(gen_type
*gen
) = 0;
3634 virtual ~ObjectGenerator() {}
3637 class MixedGenerator
: public ObjectGenerator
{
3641 explicit MixedGenerator(int64_t p
) : seq(0), poolid(p
) {}
3642 ghobject_t
create_object(gen_type
*gen
) override
{
3644 snprintf(buf
, sizeof(buf
), "OBJ_%u", seq
);
3647 for (unsigned i
= 0; i
< 300; ++i
) {
3648 name
.push_back('a');
3654 name
, string(), rand() & 2 ? CEPH_NOSNAP
: rand(),
3655 (((seq
/ 1024) % 2) * 0xF00 ) +
3661 class SyntheticWorkloadState
{
3664 map
<string
, bufferlist
> attrs
;
3667 static const unsigned max_in_flight
= 16;
3668 static const unsigned max_objects
= 3000;
3669 static const unsigned max_attr_size
= 5;
3670 static const unsigned max_attr_name_len
= 100;
3671 static const unsigned max_attr_value_len
= 1024 * 64;
3673 unsigned write_alignment
;
3674 unsigned max_object_len
, max_write_len
;
3676 map
<ghobject_t
, Object
> contents
;
3677 set
<ghobject_t
> available_objects
;
3678 set
<ghobject_t
> in_flight_objects
;
3679 ObjectGenerator
*object_gen
;
3682 ObjectStore::CollectionHandle ch
;
3684 ceph::mutex lock
= ceph::make_mutex("State lock");
3685 ceph::condition_variable cond
;
3689 explicit EnterExit(const char *m
) : msg(m
) {
3690 //cout << pthread_self() << " enter " << msg << std::endl;
3693 //cout << pthread_self() << " exit " << msg << std::endl;
3697 class C_SyntheticOnReadable
: public Context
{
3699 SyntheticWorkloadState
*state
;
3701 C_SyntheticOnReadable(SyntheticWorkloadState
*state
, ghobject_t hoid
)
3702 : state(state
), hoid(hoid
) {}
3704 void finish(int r
) override
{
3705 std::lock_guard locker
{state
->lock
};
3706 EnterExit
ee("onreadable finish");
3707 ASSERT_TRUE(state
->in_flight_objects
.count(hoid
));
3709 state
->in_flight_objects
.erase(hoid
);
3710 if (state
->contents
.count(hoid
))
3711 state
->available_objects
.insert(hoid
);
3712 --(state
->in_flight
);
3713 state
->cond
.notify_all();
3716 r
= state
->store
->read(state
->ch
, hoid
, 0, state
->contents
[hoid
].data
.length(), r2
);
3717 ceph_assert(bl_eq(state
->contents
[hoid
].data
, r2
));
3718 state
->cond
.notify_all();
3722 class C_SyntheticOnStash
: public Context
{
3724 SyntheticWorkloadState
*state
;
3725 ghobject_t oid
, noid
;
3727 C_SyntheticOnStash(SyntheticWorkloadState
*state
,
3728 ghobject_t oid
, ghobject_t noid
)
3729 : state(state
), oid(oid
), noid(noid
) {}
3731 void finish(int r
) override
{
3732 std::lock_guard locker
{state
->lock
};
3733 EnterExit
ee("stash finish");
3734 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
3736 state
->in_flight_objects
.erase(oid
);
3737 if (state
->contents
.count(noid
))
3738 state
->available_objects
.insert(noid
);
3739 --(state
->in_flight
);
3741 r
= state
->store
->read(
3743 state
->contents
[noid
].data
.length(), r2
);
3744 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
3745 state
->cond
.notify_all();
3749 class C_SyntheticOnClone
: public Context
{
3751 SyntheticWorkloadState
*state
;
3752 ghobject_t oid
, noid
;
3754 C_SyntheticOnClone(SyntheticWorkloadState
*state
,
3755 ghobject_t oid
, ghobject_t noid
)
3756 : state(state
), oid(oid
), noid(noid
) {}
3758 void finish(int r
) override
{
3759 std::lock_guard locker
{state
->lock
};
3760 EnterExit
ee("clone finish");
3761 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
3763 state
->in_flight_objects
.erase(oid
);
3764 if (state
->contents
.count(oid
))
3765 state
->available_objects
.insert(oid
);
3766 if (state
->contents
.count(noid
))
3767 state
->available_objects
.insert(noid
);
3768 --(state
->in_flight
);
3770 r
= state
->store
->read(state
->ch
, noid
, 0, state
->contents
[noid
].data
.length(), r2
);
3771 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
3772 state
->cond
.notify_all();
3776 static void filled_byte_array(bufferlist
& bl
, size_t size
)
3778 static const char alphanum
[] = "0123456789"
3779 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3780 "abcdefghijklmnopqrstuvwxyz";
3785 for (unsigned int i
= 0; i
< size
- 1; i
++) {
3786 // severely limit entropy so we can compress...
3787 bp
[i
] = alphanum
[rand() % 10]; //(sizeof(alphanum) - 1)];
3789 bp
[size
- 1] = '\0';
3794 SyntheticWorkloadState(ObjectStore
*store
,
3795 ObjectGenerator
*gen
,
3801 : cid(cid
), write_alignment(alignment
), max_object_len(max_size
),
3802 max_write_len(max_write
), in_flight(0), object_gen(gen
),
3803 rng(rng
), store(store
) {}
3806 ObjectStore::Transaction t
;
3807 ch
= store
->create_new_collection(cid
);
3808 t
.create_collection(cid
, 0);
3809 return queue_transaction(store
, ch
, std::move(t
));
3813 vector
<ghobject_t
> objects
;
3814 int r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
3816 ceph_assert(r
>= 0);
3817 if (objects
.empty())
3819 ObjectStore::Transaction t
;
3820 for (vector
<ghobject_t
>::iterator p
= objects
.begin();
3821 p
!= objects
.end(); ++p
) {
3824 queue_transaction(store
, ch
, std::move(t
));
3826 ObjectStore::Transaction t
;
3827 t
.remove_collection(cid
);
3828 queue_transaction(store
, ch
, std::move(t
));
3830 void statfs(store_statfs_t
& stat
) {
3831 store
->statfs(&stat
);
3834 ghobject_t
get_uniform_random_object(std::unique_lock
<ceph::mutex
>& locker
) {
3835 cond
.wait(locker
, [this] {
3836 return in_flight
< max_in_flight
&& !available_objects
.empty();
3838 boost::uniform_int
<> choose(0, available_objects
.size() - 1);
3839 int index
= choose(*rng
);
3840 set
<ghobject_t
>::iterator i
= available_objects
.begin();
3841 for ( ; index
> 0; --index
, ++i
) ;
3842 ghobject_t ret
= *i
;
3846 void wait_for_ready(std::unique_lock
<ceph::mutex
>& locker
) {
3847 cond
.wait(locker
, [this] { return in_flight
< max_in_flight
; });
3850 void wait_for_done() {
3851 std::unique_lock locker
{lock
};
3852 cond
.wait(locker
, [this] { return in_flight
== 0; });
3856 return (available_objects
.size() + in_flight_objects
.size()) < max_objects
;
3860 return (available_objects
.size() + in_flight_objects
.size()) > 0;
3863 unsigned get_random_alloc_hints() {
3866 boost::uniform_int
<> u(0, 3);
3869 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE
;
3872 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE
;
3877 boost::uniform_int
<> u(0, 3);
3880 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
;
3883 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ
;
3888 // append_only, immutable
3889 boost::uniform_int
<> u(0, 4);
3893 boost::uniform_int
<> u(0, 3);
3896 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED
;
3899 f
|= CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED
;
3904 boost::uniform_int
<> u(0, 3);
3907 f
|= CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE
;
3910 f
|= CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE
;
3918 std::unique_lock locker
{lock
};
3919 EnterExit
ee("touch");
3922 wait_for_ready(locker
);
3923 ghobject_t new_obj
= object_gen
->create_object(rng
);
3924 available_objects
.erase(new_obj
);
3925 ObjectStore::Transaction t
;
3926 t
.touch(cid
, new_obj
);
3927 boost::uniform_int
<> u(17, 22);
3928 boost::uniform_int
<> v(12, 17);
3929 t
.set_alloc_hint(cid
, new_obj
,
3932 get_random_alloc_hints());
3934 in_flight_objects
.insert(new_obj
);
3935 if (!contents
.count(new_obj
))
3936 contents
[new_obj
] = Object();
3937 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
3938 int status
= store
->queue_transaction(ch
, std::move(t
));
3943 std::unique_lock locker
{lock
};
3944 EnterExit
ee("stash");
3949 wait_for_ready(locker
);
3954 old_obj
= get_uniform_random_object(locker
);
3955 } while (--max
&& !contents
[old_obj
].data
.length());
3956 available_objects
.erase(old_obj
);
3957 ghobject_t new_obj
= old_obj
;
3958 new_obj
.generation
++;
3959 available_objects
.erase(new_obj
);
3961 ObjectStore::Transaction t
;
3962 t
.collection_move_rename(cid
, old_obj
, cid
, new_obj
);
3964 in_flight_objects
.insert(old_obj
);
3966 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
3967 contents
[new_obj
].data
= contents
[old_obj
].data
;
3968 contents
.erase(old_obj
);
3969 t
.register_on_applied(new C_SyntheticOnStash(this, old_obj
, new_obj
));
3970 int status
= store
->queue_transaction(ch
, std::move(t
));
3975 std::unique_lock locker
{lock
};
3976 EnterExit
ee("clone");
3981 wait_for_ready(locker
);
3986 old_obj
= get_uniform_random_object(locker
);
3987 } while (--max
&& !contents
[old_obj
].data
.length());
3988 available_objects
.erase(old_obj
);
3989 ghobject_t new_obj
= object_gen
->create_object(rng
);
3990 // make the hash match
3991 new_obj
.hobj
.set_hash(old_obj
.hobj
.get_hash());
3992 available_objects
.erase(new_obj
);
3994 ObjectStore::Transaction t
;
3995 t
.clone(cid
, old_obj
, new_obj
);
3997 in_flight_objects
.insert(old_obj
);
3999 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
4000 contents
[new_obj
].data
= contents
[old_obj
].data
;
4002 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
4003 int status
= store
->queue_transaction(ch
, std::move(t
));
4008 std::unique_lock locker
{lock
};
4009 EnterExit
ee("clone_range");
4014 wait_for_ready(locker
);
4019 old_obj
= get_uniform_random_object(locker
);
4020 } while (--max
&& !contents
[old_obj
].data
.length());
4021 bufferlist
&srcdata
= contents
[old_obj
].data
;
4022 if (srcdata
.length() == 0) {
4025 available_objects
.erase(old_obj
);
4026 ghobject_t new_obj
= get_uniform_random_object(locker
);
4027 available_objects
.erase(new_obj
);
4029 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4030 boost::uniform_int
<> u2(0, max_write_len
);
4031 uint64_t srcoff
= u1(*rng
);
4032 // make src and dst offsets match, since that's what the osd does
4033 uint64_t dstoff
= srcoff
; //u1(*rng);
4034 uint64_t len
= u2(*rng
);
4035 if (write_alignment
) {
4036 srcoff
= round_up_to(srcoff
, write_alignment
);
4037 dstoff
= round_up_to(dstoff
, write_alignment
);
4038 len
= round_up_to(len
, write_alignment
);
4041 if (srcoff
> srcdata
.length() - 1) {
4042 srcoff
= srcdata
.length() - 1;
4044 if (srcoff
+ len
> srcdata
.length()) {
4045 len
= srcdata
.length() - srcoff
;
4048 cout
<< __func__
<< " from " << srcoff
<< "~" << len
4049 << " (size " << srcdata
.length() << ") to "
4050 << dstoff
<< "~" << len
<< std::endl
;
4052 ObjectStore::Transaction t
;
4053 t
.clone_range(cid
, old_obj
, new_obj
, srcoff
, len
, dstoff
);
4055 in_flight_objects
.insert(old_obj
);
4058 if (srcoff
< srcdata
.length()) {
4059 if (srcoff
+ len
> srcdata
.length()) {
4060 bl
.substr_of(srcdata
, srcoff
, srcdata
.length() - srcoff
);
4062 bl
.substr_of(srcdata
, srcoff
, len
);
4066 bufferlist
& dstdata
= contents
[new_obj
].data
;
4067 if (dstdata
.length() <= dstoff
) {
4068 if (bl
.length() > 0) {
4069 dstdata
.append_zero(dstoff
- dstdata
.length());
4074 ceph_assert(dstdata
.length() > dstoff
);
4075 dstdata
.cbegin().copy(dstoff
, value
);
4077 if (value
.length() < dstdata
.length())
4078 dstdata
.cbegin(value
.length()).copy(
4079 dstdata
.length() - value
.length(), value
);
4080 value
.swap(dstdata
);
4083 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
4084 int status
= store
->queue_transaction(ch
, std::move(t
));
4090 std::unique_lock locker
{lock
};
4091 EnterExit
ee("write");
4094 wait_for_ready(locker
);
4096 ghobject_t new_obj
= get_uniform_random_object(locker
);
4097 available_objects
.erase(new_obj
);
4098 ObjectStore::Transaction t
;
4100 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4101 boost::uniform_int
<> u2(0, max_write_len
);
4102 uint64_t offset
= u1(*rng
);
4103 uint64_t len
= u2(*rng
);
4105 if (write_alignment
) {
4106 offset
= round_up_to(offset
, write_alignment
);
4107 len
= round_up_to(len
, write_alignment
);
4110 filled_byte_array(bl
, len
);
4112 bufferlist
& data
= contents
[new_obj
].data
;
4113 if (data
.length() <= offset
) {
4115 data
.append_zero(offset
-data
.length());
4120 ceph_assert(data
.length() > offset
);
4121 data
.cbegin().copy(offset
, value
);
4123 if (value
.length() < data
.length())
4124 data
.cbegin(value
.length()).copy(
4125 data
.length()-value
.length(), value
);
4129 t
.write(cid
, new_obj
, offset
, len
, bl
);
4131 in_flight_objects
.insert(new_obj
);
4132 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4133 int status
= store
->queue_transaction(ch
, std::move(t
));
4138 std::unique_lock locker
{lock
};
4139 EnterExit
ee("truncate");
4142 wait_for_ready(locker
);
4144 ghobject_t obj
= get_uniform_random_object(locker
);
4145 available_objects
.erase(obj
);
4146 ObjectStore::Transaction t
;
4148 boost::uniform_int
<> choose(0, max_object_len
);
4149 size_t len
= choose(*rng
);
4150 if (write_alignment
) {
4151 len
= round_up_to(len
, write_alignment
);
4154 t
.truncate(cid
, obj
, len
);
4156 in_flight_objects
.insert(obj
);
4157 bufferlist
& data
= contents
[obj
].data
;
4158 if (data
.length() <= len
) {
4159 data
.append_zero(len
- data
.length());
4162 data
.cbegin().copy(len
, bl
);
4166 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4167 int status
= store
->queue_transaction(ch
, std::move(t
));
4172 std::unique_lock locker
{lock
};
4173 EnterExit
ee("zero");
4176 wait_for_ready(locker
);
4178 ghobject_t new_obj
= get_uniform_random_object(locker
);
4179 available_objects
.erase(new_obj
);
4180 ObjectStore::Transaction t
;
4182 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4183 boost::uniform_int
<> u2(0, max_write_len
);
4184 uint64_t offset
= u1(*rng
);
4185 uint64_t len
= u2(*rng
);
4186 if (write_alignment
) {
4187 offset
= round_up_to(offset
, write_alignment
);
4188 len
= round_up_to(len
, write_alignment
);
4192 auto& data
= contents
[new_obj
].data
;
4193 if (data
.length() < offset
+ len
) {
4194 data
.append_zero(offset
+len
-data
.length());
4197 n
.substr_of(data
, 0, offset
);
4199 if (data
.length() > offset
+ len
)
4200 data
.cbegin(offset
+ len
).copy(data
.length() - offset
- len
, n
);
4204 t
.zero(cid
, new_obj
, offset
, len
);
4206 in_flight_objects
.insert(new_obj
);
4207 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4208 int status
= store
->queue_transaction(ch
, std::move(t
));
4213 EnterExit
ee("read");
4214 boost::uniform_int
<> u1(0, max_object_len
/2);
4215 boost::uniform_int
<> u2(0, max_object_len
);
4216 uint64_t offset
= u1(*rng
);
4217 uint64_t len
= u2(*rng
);
4222 bufferlist expected
;
4225 std::unique_lock locker
{lock
};
4226 EnterExit
ee("read locked");
4229 wait_for_ready(locker
);
4231 obj
= get_uniform_random_object(locker
);
4232 expected
= contents
[obj
].data
;
4234 bufferlist bl
, result
;
4235 if (0) cout
<< " obj " << obj
4236 << " size " << expected
.length()
4237 << " offset " << offset
4238 << " len " << len
<< std::endl
;
4239 r
= store
->read(ch
, obj
, offset
, len
, result
);
4240 if (offset
>= expected
.length()) {
4243 size_t max_len
= expected
.length() - offset
;
4246 ceph_assert(len
== result
.length());
4247 ASSERT_EQ(len
, result
.length());
4248 expected
.cbegin(offset
).copy(len
, bl
);
4249 ASSERT_EQ(r
, (int)len
);
4250 ASSERT_TRUE(bl_eq(bl
, result
));
4255 std::unique_lock locker
{lock
};
4256 EnterExit
ee("setattrs");
4259 wait_for_ready(locker
);
4261 ghobject_t obj
= get_uniform_random_object(locker
);
4262 available_objects
.erase(obj
);
4263 ObjectStore::Transaction t
;
4265 boost::uniform_int
<> u0(1, max_attr_size
);
4266 boost::uniform_int
<> u1(4, max_attr_name_len
);
4267 boost::uniform_int
<> u2(4, max_attr_value_len
);
4268 boost::uniform_int
<> u3(0, 100);
4269 uint64_t size
= u0(*rng
);
4271 map
<string
, bufferlist
> attrs
;
4273 for (map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4274 it
!= contents
[obj
].attrs
.end(); ++it
)
4275 keys
.insert(it
->first
);
4278 bufferlist name
, value
;
4279 uint64_t get_exist
= u3(*rng
);
4280 uint64_t value_len
= u2(*rng
);
4281 filled_byte_array(value
, value_len
);
4282 if (get_exist
< 50 && keys
.size()) {
4283 set
<string
>::iterator k
= keys
.begin();
4285 contents
[obj
].attrs
[*k
] = value
;
4288 name_len
= u1(*rng
);
4289 filled_byte_array(name
, name_len
);
4290 attrs
[name
.c_str()] = value
;
4291 contents
[obj
].attrs
[name
.c_str()] = value
;
4294 t
.setattrs(cid
, obj
, attrs
);
4296 in_flight_objects
.insert(obj
);
4297 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4298 int status
= store
->queue_transaction(ch
, std::move(t
));
4303 EnterExit
ee("getattrs");
4305 map
<string
, bufferlist
> expected
;
4307 std::unique_lock locker
{lock
};
4308 EnterExit
ee("getattrs locked");
4311 wait_for_ready(locker
);
4315 obj
= get_uniform_random_object(locker
);
4318 } while (contents
[obj
].attrs
.empty());
4319 expected
= contents
[obj
].attrs
;
4321 map
<string
, bufferlist
> attrs
;
4322 int r
= store
->getattrs(ch
, obj
, attrs
);
4323 ASSERT_TRUE(r
== 0);
4324 ASSERT_TRUE(attrs
.size() == expected
.size());
4325 for (map
<string
, bufferlist
>::iterator it
= expected
.begin();
4326 it
!= expected
.end(); ++it
) {
4327 ASSERT_TRUE(bl_eq(attrs
[it
->first
], it
->second
));
4332 EnterExit
ee("getattr");
4336 map
<string
, bufferlist
> expected
;
4338 std::unique_lock locker
{lock
};
4339 EnterExit
ee("getattr locked");
4342 wait_for_ready(locker
);
4346 obj
= get_uniform_random_object(locker
);
4349 } while (contents
[obj
].attrs
.empty());
4350 expected
= contents
[obj
].attrs
;
4352 boost::uniform_int
<> u(0, expected
.size()-1);
4354 map
<string
, bufferlist
>::iterator it
= expected
.begin();
4361 r
= store
->getattr(ch
, obj
, it
->first
, bl
);
4363 ASSERT_TRUE(bl_eq(it
->second
, bl
));
4367 std::unique_lock locker
{lock
};
4368 EnterExit
ee("rmattr");
4371 wait_for_ready(locker
);
4376 obj
= get_uniform_random_object(locker
);
4379 } while (contents
[obj
].attrs
.empty());
4381 boost::uniform_int
<> u(0, contents
[obj
].attrs
.size()-1);
4383 map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4389 available_objects
.erase(obj
);
4390 ObjectStore::Transaction t
;
4391 t
.rmattr(cid
, obj
, it
->first
);
4393 contents
[obj
].attrs
.erase(it
->first
);
4395 in_flight_objects
.insert(obj
);
4396 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4397 int status
= store
->queue_transaction(ch
, std::move(t
));
4401 void fsck(bool deep
) {
4402 std::unique_lock locker
{lock
};
4403 EnterExit
ee("fsck");
4404 cond
.wait(locker
, [this] { return in_flight
== 0; });
4407 int r
= store
->fsck(deep
);
4408 ceph_assert(r
== 0 || r
== -EOPNOTSUPP
);
4410 ch
= store
->open_collection(cid
);
4414 std::unique_lock locker
{lock
};
4415 EnterExit
ee("scan");
4416 cond
.wait(locker
, [this] { return in_flight
== 0; });
4417 vector
<ghobject_t
> objects
;
4418 set
<ghobject_t
> objects_set
, objects_set2
;
4419 ghobject_t next
, current
;
4421 //cerr << "scanning..." << std::endl;
4422 int r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 100,
4425 ASSERT_TRUE(sorted(objects
));
4426 objects_set
.insert(objects
.begin(), objects
.end());
4428 if (next
.is_max()) break;
4431 if (objects_set
.size() != available_objects
.size()) {
4432 for (set
<ghobject_t
>::iterator p
= objects_set
.begin();
4433 p
!= objects_set
.end();
4435 if (available_objects
.count(*p
) == 0) {
4436 cerr
<< "+ " << *p
<< std::endl
;
4439 for (set
<ghobject_t
>::iterator p
= available_objects
.begin();
4440 p
!= available_objects
.end();
4442 if (objects_set
.count(*p
) == 0)
4443 cerr
<< "- " << *p
<< std::endl
;
4444 //cerr << " objects_set: " << objects_set << std::endl;
4445 //cerr << " available_set: " << available_objects << std::endl;
4446 ceph_abort_msg("badness");
4449 ASSERT_EQ(objects_set
.size(), available_objects
.size());
4450 for (set
<ghobject_t
>::iterator i
= objects_set
.begin();
4451 i
!= objects_set
.end();
4453 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
4456 int r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
4457 INT_MAX
, &objects
, 0);
4459 objects_set2
.insert(objects
.begin(), objects
.end());
4460 ASSERT_EQ(objects_set2
.size(), available_objects
.size());
4461 for (set
<ghobject_t
>::iterator i
= objects_set2
.begin();
4462 i
!= objects_set2
.end();
4464 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
4465 if (available_objects
.count(*i
) == 0) {
4466 cerr
<< "+ " << *i
<< std::endl
;
4472 EnterExit
ee("stat");
4476 std::unique_lock locker
{lock
};
4477 EnterExit
ee("stat lock1");
4480 hoid
= get_uniform_random_object(locker
);
4481 in_flight_objects
.insert(hoid
);
4482 available_objects
.erase(hoid
);
4484 expected
= contents
[hoid
].data
.length();
4487 int r
= store
->stat(ch
, hoid
, &buf
);
4489 ceph_assert((uint64_t)buf
.st_size
== expected
);
4490 ASSERT_TRUE((uint64_t)buf
.st_size
== expected
);
4492 std::lock_guard locker
{lock
};
4493 EnterExit
ee("stat lock2");
4496 in_flight_objects
.erase(hoid
);
4497 available_objects
.insert(hoid
);
4502 std::unique_lock locker
{lock
};
4503 EnterExit
ee("unlink");
4506 ghobject_t to_remove
= get_uniform_random_object(locker
);
4507 ObjectStore::Transaction t
;
4508 t
.remove(cid
, to_remove
);
4510 available_objects
.erase(to_remove
);
4511 in_flight_objects
.insert(to_remove
);
4512 contents
.erase(to_remove
);
4513 t
.register_on_applied(new C_SyntheticOnReadable(this, to_remove
));
4514 int status
= store
->queue_transaction(ch
, std::move(t
));
4518 void print_internal_state() {
4519 std::lock_guard locker
{lock
};
4520 cerr
<< "available_objects: " << available_objects
.size()
4521 << " in_flight_objects: " << in_flight_objects
.size()
4522 << " total objects: " << in_flight_objects
.size() + available_objects
.size()
4523 << " in_flight " << in_flight
<< std::endl
;
4528 void StoreTest::doSyntheticTest(
4530 uint64_t max_obj
, uint64_t max_wr
, uint64_t align
)
4532 MixedGenerator
gen(555);
4533 gen_type
rng(time(NULL
));
4534 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
4536 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
4537 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
4538 g_ceph_context
->_conf
.apply_changes(nullptr);
4540 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
,
4541 max_obj
, max_wr
, align
);
4543 for (int i
= 0; i
< num_ops
/10; ++i
) {
4544 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
4547 for (int i
= 0; i
< num_ops
; ++i
) {
4549 cerr
<< "Op " << i
<< std::endl
;
4550 test_obj
.print_internal_state();
4552 boost::uniform_int
<> true_false(0, 999);
4553 int val
= true_false(rng
);
4555 test_obj
.fsck(true);
4556 } else if (val
> 997) {
4557 test_obj
.fsck(false);
4558 } else if (val
> 970) {
4560 } else if (val
> 950) {
4562 } else if (val
> 850) {
4564 } else if (val
> 800) {
4566 } else if (val
> 550) {
4568 } else if (val
> 500) {
4570 } else if (val
> 450) {
4571 test_obj
.clone_range();
4572 } else if (val
> 300) {
4574 } else if (val
> 100) {
4577 test_obj
.truncate();
4580 test_obj
.wait_for_done();
4581 test_obj
.shutdown();
4584 TEST_P(StoreTest
, Synthetic
) {
4585 doSyntheticTest(10000, 400*1024, 40*1024, 0);
4588 #if defined(WITH_BLUESTORE)
4589 TEST_P(StoreTestSpecificAUSize
, BlueFSExtenderTest
) {
4590 if(string(GetParam()) != "bluestore")
4593 SetVal(g_conf(), "bluestore_block_db_size", "0");
4594 SetVal(g_conf(), "bluestore_block_wal_size", "0");
4595 SetVal(g_conf(), "bluestore_bluefs_min", "12582912");
4596 SetVal(g_conf(), "bluestore_bluefs_min_free", "4194304");
4597 SetVal(g_conf(), "bluestore_bluefs_gift_ratio", "0");
4598 SetVal(g_conf(), "bluestore_bluefs_min_ratio", "0");
4599 SetVal(g_conf(), "bluestore_bluefs_balance_interval", "100000");
4600 SetVal(g_conf(), "bluestore_bluefs_db_compatibility", "false");
4602 g_conf().apply_changes(nullptr);
4604 StartDeferred(4096);
4606 doSyntheticTest(10000, 400*1024, 40*1024, 0);
4608 BlueStore
* bstore
= NULL
;
4609 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
4611 // verify downgrades are broken and repair that
4613 ASSERT_EQ(bstore
->fsck(false), 0);
4615 SetVal(g_conf(), "bluestore_bluefs_db_compatibility", "true");
4616 g_conf().apply_changes(nullptr);
4618 ASSERT_EQ(bstore
->fsck(false), 1);
4619 ASSERT_EQ(bstore
->repair(false), 0);
4620 ASSERT_EQ(bstore
->fsck(false), 0);
4624 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixSharding
) {
4625 if (string(GetParam()) != "bluestore")
4628 const char *m
[][10] = {
4629 { "bluestore_min_alloc_size", "4096", 0 }, // must be the first!
4630 { "num_ops", "50000", 0 },
4631 { "max_write", "65536", 0 },
4632 { "max_size", "262144", 0 },
4633 { "alignment", "4096", 0 },
4634 { "bluestore_max_blob_size", "65536", 0 },
4635 { "bluestore_extent_map_shard_min_size", "60", 0 },
4636 { "bluestore_extent_map_shard_max_size", "300", 0 },
4637 { "bluestore_extent_map_shard_target_size", "150", 0 },
4638 { "bluestore_default_buffered_read", "true", 0 },
4639 { "bluestore_default_buffered_write", "true", 0 },
4642 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4645 TEST_P(StoreTestSpecificAUSize
, ZipperPatternSharded
) {
4646 if(string(GetParam()) != "bluestore")
4648 StartDeferred(4096);
4652 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
4653 auto ch
= store
->create_new_collection(cid
);
4655 ObjectStore::Transaction t
;
4656 t
.create_collection(cid
, 0);
4657 cerr
<< "Creating collection " << cid
<< std::endl
;
4658 r
= queue_transaction(store
, ch
, std::move(t
));
4666 for (int i
=0; i
<1000; ++i
) {
4667 ObjectStore::Transaction t
;
4668 t
.write(cid
, a
, i
*2*len
, len
, bl
, 0);
4669 r
= queue_transaction(store
, ch
, std::move(t
));
4672 for (int i
=0; i
<1000; ++i
) {
4673 ObjectStore::Transaction t
;
4674 t
.write(cid
, a
, i
*2*len
+ 1, len
, bl
, 0);
4675 r
= queue_transaction(store
, ch
, std::move(t
));
4679 ObjectStore::Transaction t
;
4681 t
.remove_collection(cid
);
4682 cerr
<< "Cleaning" << std::endl
;
4683 r
= queue_transaction(store
, ch
, std::move(t
));
4688 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumAlgorithm
) {
4689 if (string(GetParam()) != "bluestore")
4692 const char *m
[][10] = {
4693 { "bluestore_min_alloc_size", "65536", 0 }, // must be the first!
4694 { "max_write", "65536", 0 },
4695 { "max_size", "1048576", 0 },
4696 { "alignment", "16", 0 },
4697 { "bluestore_csum_type", "crc32c", "crc32c_16", "crc32c_8", "xxhash32",
4698 "xxhash64", "none", 0 },
4699 { "bluestore_default_buffered_write", "false", 0 },
4702 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4705 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumVsCompression
) {
4706 if (string(GetParam()) != "bluestore")
4709 const char *m
[][10] = {
4710 { "bluestore_min_alloc_size", "4096", "16384", 0 }, //to be the first!
4711 { "max_write", "131072", 0 },
4712 { "max_size", "262144", 0 },
4713 { "alignment", "512", 0 },
4714 { "bluestore_compression_mode", "force", 0},
4715 { "bluestore_compression_algorithm", "snappy", "zlib", 0 },
4716 { "bluestore_csum_type", "crc32c", 0 },
4717 { "bluestore_default_buffered_read", "true", "false", 0 },
4718 { "bluestore_default_buffered_write", "true", "false", 0 },
4719 { "bluestore_sync_submit_transaction", "false", 0 },
4722 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4725 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompression
) {
4726 if (string(GetParam()) != "bluestore")
4729 const char *m
[][10] = {
4730 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4731 { "max_write", "1048576", 0 },
4732 { "max_size", "4194304", 0 },
4733 { "alignment", "65536", 0 },
4734 { "bluestore_compression_mode", "force", "aggressive", "passive", "none", 0},
4735 { "bluestore_default_buffered_write", "false", 0 },
4736 { "bluestore_sync_submit_transaction", "true", 0 },
4739 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4742 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompressionAlgorithm
) {
4743 if (string(GetParam()) != "bluestore")
4746 const char *m
[][10] = {
4747 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4748 { "max_write", "1048576", 0 },
4749 { "max_size", "4194304", 0 },
4750 { "alignment", "65536", 0 },
4751 { "bluestore_compression_algorithm", "zlib", "snappy", 0 },
4752 { "bluestore_compression_mode", "force", 0 },
4753 { "bluestore_default_buffered_write", "false", 0 },
4756 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4759 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixNoCsum
) {
4760 if (string(GetParam()) != "bluestore")
4763 const char *m
[][10] = {
4764 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4765 { "max_write", "65536", 0 },
4766 { "max_size", "1048576", 0 },
4767 { "alignment", "512", 0 },
4768 { "bluestore_max_blob_size", "262144", 0 },
4769 { "bluestore_compression_mode", "force", "none", 0},
4770 { "bluestore_csum_type", "none", 0},
4771 { "bluestore_default_buffered_read", "true", "false", 0 },
4772 { "bluestore_default_buffered_write", "true", 0 },
4773 { "bluestore_sync_submit_transaction", "true", "false", 0 },
4776 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4779 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixPreferDeferred
) {
4780 if (string(GetParam()) != "bluestore")
4783 const char *m
[][10] = {
4784 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4785 { "max_write", "65536", 0 },
4786 { "max_size", "1048576", 0 },
4787 { "alignment", "512", 0 },
4788 { "bluestore_max_blob_size", "262144", 0 },
4789 { "bluestore_compression_mode", "force", "none", 0},
4790 { "bluestore_prefer_deferred_size", "32768", "0", 0},
4793 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4795 #endif // WITH_BLUESTORE
4797 TEST_P(StoreTest
, AttrSynthetic
) {
4798 MixedGenerator
gen(447);
4799 gen_type
rng(time(NULL
));
4800 coll_t
cid(spg_t(pg_t(0,447),shard_id_t::NO_SHARD
));
4802 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
, 40*1024, 4*1024, 0);
4804 for (int i
= 0; i
< 500; ++i
) {
4805 if (!(i
% 10)) cerr
<< "seeding object " << i
<< std::endl
;
4808 for (int i
= 0; i
< 1000; ++i
) {
4810 cerr
<< "Op " << i
<< std::endl
;
4811 test_obj
.print_internal_state();
4813 boost::uniform_int
<> true_false(0, 99);
4814 int val
= true_false(rng
);
4817 } else if (val
> 93) {
4819 } else if (val
> 75) {
4821 } else if (val
> 47) {
4822 test_obj
.setattrs();
4823 } else if (val
> 45) {
4825 } else if (val
> 37) {
4827 } else if (val
> 30) {
4828 test_obj
.getattrs();
4833 test_obj
.wait_for_done();
4834 test_obj
.shutdown();
4837 TEST_P(StoreTest
, HashCollisionTest
) {
4838 int64_t poolid
= 11;
4839 coll_t
cid(spg_t(pg_t(0,poolid
),shard_id_t::NO_SHARD
));
4841 auto ch
= store
->create_new_collection(cid
);
4843 ObjectStore::Transaction t
;
4844 t
.create_collection(cid
, 0);
4845 r
= queue_transaction(store
, ch
, std::move(t
));
4849 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
4850 set
<ghobject_t
> created
;
4851 for (int n
= 0; n
< 10; ++n
) {
4853 sprintf(nbuf
, "n%d", n
);
4854 for (int i
= 0; i
< 1000; ++i
) {
4856 sprintf(buf
, "%d", i
);
4858 cerr
<< "Object n" << n
<< " "<< i
<< std::endl
;
4860 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, 0, poolid
, string(nbuf
)));
4862 ObjectStore::Transaction t
;
4864 r
= queue_transaction(store
, ch
, std::move(t
));
4867 created
.insert(hoid
);
4870 vector
<ghobject_t
> objects
;
4871 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
, &objects
, 0);
4873 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
4874 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
4875 ASSERT_TRUE(listed
.size() == created
.size());
4878 ghobject_t current
, next
;
4880 r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 60,
4883 ASSERT_TRUE(sorted(objects
));
4884 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
4887 if (listed
.count(*i
))
4888 cerr
<< *i
<< " repeated" << std::endl
;
4891 if (objects
.size() < 50) {
4892 ASSERT_TRUE(next
.is_max());
4898 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
4899 ASSERT_TRUE(listed
.size() == created
.size());
4900 for (set
<ghobject_t
>::iterator i
= listed
.begin();
4903 ASSERT_TRUE(created
.count(*i
));
4906 for (set
<ghobject_t
>::iterator i
= created
.begin();
4909 ObjectStore::Transaction t
;
4911 r
= queue_transaction(store
, ch
, std::move(t
));
4914 ObjectStore::Transaction t
;
4915 t
.remove_collection(cid
);
4916 r
= queue_transaction(store
, ch
, std::move(t
));
4920 TEST_P(StoreTest
, ScrubTest
) {
4921 int64_t poolid
= 111;
4922 coll_t
cid(spg_t(pg_t(0, poolid
),shard_id_t(1)));
4924 auto ch
= store
->create_new_collection(cid
);
4926 ObjectStore::Transaction t
;
4927 t
.create_collection(cid
, 0);
4928 r
= queue_transaction(store
, ch
, std::move(t
));
4931 string base
= "aaaaa";
4932 set
<ghobject_t
> created
;
4933 for (int i
= 0; i
< 1000; ++i
) {
4935 sprintf(buf
, "%d", i
);
4937 cerr
<< "Object " << i
<< std::endl
;
4939 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, i
,
4941 ghobject_t::NO_GEN
, shard_id_t(1));
4943 ObjectStore::Transaction t
;
4945 r
= queue_transaction(store
, ch
, std::move(t
));
4948 created
.insert(hoid
);
4951 // Add same hobject_t but different generation
4953 ghobject_t
hoid1(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""),
4954 ghobject_t::NO_GEN
, shard_id_t(1));
4955 ghobject_t
hoid2(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)1, shard_id_t(1));
4956 ghobject_t
hoid3(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)2, shard_id_t(1));
4957 ObjectStore::Transaction t
;
4958 t
.touch(cid
, hoid1
);
4959 t
.touch(cid
, hoid2
);
4960 t
.touch(cid
, hoid3
);
4961 r
= queue_transaction(store
, ch
, std::move(t
));
4962 created
.insert(hoid1
);
4963 created
.insert(hoid2
);
4964 created
.insert(hoid3
);
4968 vector
<ghobject_t
> objects
;
4969 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
4970 INT_MAX
, &objects
, 0);
4972 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
4973 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
4974 ASSERT_TRUE(listed
.size() == created
.size());
4977 ghobject_t current
, next
;
4979 r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 60,
4982 ASSERT_TRUE(sorted(objects
));
4983 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
4984 i
!= objects
.end(); ++i
) {
4985 if (listed
.count(*i
))
4986 cerr
<< *i
<< " repeated" << std::endl
;
4989 if (objects
.size() < 50) {
4990 ASSERT_TRUE(next
.is_max());
4994 current
= next
.get_boundary();
4996 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
4997 ASSERT_TRUE(listed
.size() == created
.size());
4998 for (set
<ghobject_t
>::iterator i
= listed
.begin();
5001 ASSERT_TRUE(created
.count(*i
));
5004 for (set
<ghobject_t
>::iterator i
= created
.begin();
5007 ObjectStore::Transaction t
;
5009 r
= queue_transaction(store
, ch
, std::move(t
));
5012 ObjectStore::Transaction t
;
5013 t
.remove_collection(cid
);
5014 r
= queue_transaction(store
, ch
, std::move(t
));
5019 TEST_P(StoreTest
, OMapTest
) {
5021 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5022 auto ch
= store
->create_new_collection(cid
);
5025 ObjectStore::Transaction t
;
5026 t
.create_collection(cid
, 0);
5027 r
= queue_transaction(store
, ch
, std::move(t
));
5031 map
<string
, bufferlist
> attrs
;
5033 ObjectStore::Transaction t
;
5035 t
.omap_clear(cid
, hoid
);
5036 map
<string
, bufferlist
> start_set
;
5037 t
.omap_setkeys(cid
, hoid
, start_set
);
5038 r
= queue_transaction(store
, ch
, std::move(t
));
5042 for (int i
= 0; i
< 100; i
++) {
5044 std::cout
<< "On iteration " << i
<< std::endl
;
5046 ObjectStore::Transaction t
;
5048 map
<string
, bufferlist
> cur_attrs
;
5049 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5051 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5054 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5056 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5057 if (cur_attrs
.count(j
->first
) > 0) {
5058 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5061 ASSERT_EQ(correct
, true);
5063 ASSERT_EQ(attrs
.size(), cur_attrs
.size());
5066 snprintf(buf
, sizeof(buf
), "%d", i
);
5068 bufferptr
bp(buf
, strlen(buf
) + 1);
5070 map
<string
, bufferlist
> to_add
;
5071 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5072 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5073 t
.omap_setkeys(cid
, hoid
, to_add
);
5074 r
= queue_transaction(store
, ch
, std::move(t
));
5079 while (attrs
.size()) {
5081 std::cout
<< "removal: On iteration " << i
<< std::endl
;
5083 ObjectStore::Transaction t
;
5085 map
<string
, bufferlist
> cur_attrs
;
5086 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5088 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5091 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5093 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5094 if (cur_attrs
.count(j
->first
) > 0) {
5095 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5098 ASSERT_EQ(correct
, true);
5101 string to_remove
= attrs
.begin()->first
;
5102 t
.omap_rmkey(cid
, hoid
, to_remove
);
5103 r
= queue_transaction(store
, ch
, std::move(t
));
5106 attrs
.erase(to_remove
);
5113 bl1
.append("omap_header");
5114 ObjectStore::Transaction t
;
5115 t
.omap_setheader(cid
, hoid
, bl1
);
5116 r
= queue_transaction(store
, ch
, std::move(t
));
5118 t
= ObjectStore::Transaction();
5121 bl2
.append("value");
5122 map
<string
, bufferlist
> to_add
;
5123 to_add
.insert(pair
<string
, bufferlist
>("key", bl2
));
5124 t
.omap_setkeys(cid
, hoid
, to_add
);
5125 r
= queue_transaction(store
, ch
, std::move(t
));
5129 map
<string
, bufferlist
> cur_attrs
;
5130 r
= store
->omap_get(ch
, hoid
, &bl3
, &cur_attrs
);
5132 ASSERT_EQ(cur_attrs
.size(), size_t(1));
5133 ASSERT_TRUE(bl_eq(bl1
, bl3
));
5136 r
= store
->omap_get_keys(ch
, hoid
, &keys
);
5138 ASSERT_EQ(keys
.size(), size_t(1));
5141 // test omap_clear, omap_rmkey_range
5144 map
<string
,bufferlist
> to_set
;
5145 for (int n
=0; n
<10; ++n
) {
5146 to_set
[stringify(n
)].append("foo");
5150 ObjectStore::Transaction t
;
5151 t
.remove(cid
, hoid
);
5153 t
.omap_setheader(cid
, hoid
, h
);
5154 t
.omap_setkeys(cid
, hoid
, to_set
);
5155 r
= queue_transaction(store
, ch
, std::move(t
));
5159 ObjectStore::Transaction t
;
5160 t
.omap_rmkeyrange(cid
, hoid
, "3", "7");
5161 r
= queue_transaction(store
, ch
, std::move(t
));
5166 map
<string
,bufferlist
> m
;
5167 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5168 ASSERT_EQ(6u, hdr
.length());
5169 ASSERT_TRUE(m
.count("2"));
5170 ASSERT_TRUE(!m
.count("3"));
5171 ASSERT_TRUE(!m
.count("6"));
5172 ASSERT_TRUE(m
.count("7"));
5173 ASSERT_TRUE(m
.count("8"));
5174 //cout << m << std::endl;
5175 ASSERT_EQ(6u, m
.size());
5178 ObjectStore::Transaction t
;
5179 t
.omap_clear(cid
, hoid
);
5180 r
= queue_transaction(store
, ch
, std::move(t
));
5185 map
<string
,bufferlist
> m
;
5186 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5187 ASSERT_EQ(0u, hdr
.length());
5188 ASSERT_EQ(0u, m
.size());
5192 ObjectStore::Transaction t
;
5193 t
.remove(cid
, hoid
);
5194 t
.remove_collection(cid
);
5195 r
= queue_transaction(store
, ch
, std::move(t
));
5199 TEST_P(StoreTest
, OMapIterator
) {
5201 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5203 auto ch
= store
->create_new_collection(cid
);
5206 ObjectStore::Transaction t
;
5207 t
.create_collection(cid
, 0);
5208 r
= queue_transaction(store
, ch
, std::move(t
));
5212 map
<string
, bufferlist
> attrs
;
5214 ObjectStore::Transaction t
;
5216 t
.omap_clear(cid
, hoid
);
5217 map
<string
, bufferlist
> start_set
;
5218 t
.omap_setkeys(cid
, hoid
, start_set
);
5219 r
= queue_transaction(store
, ch
, std::move(t
));
5222 ObjectMap::ObjectMapIterator iter
;
5225 for (int i
= 0; i
< 100; i
++) {
5227 std::cout
<< "On iteration " << i
<< std::endl
;
5231 // FileStore may deadlock two active iterators over the same data
5232 iter
= ObjectMap::ObjectMapIterator();
5234 iter
= store
->get_omap_iterator(ch
, hoid
);
5235 for (iter
->seek_to_first(), count
=0; iter
->valid(); iter
->next(), count
++) {
5236 string key
= iter
->key();
5237 bufferlist value
= iter
->value();
5238 correct
= attrs
.count(key
) && (string(value
.c_str()) == string(attrs
[key
].c_str()));
5240 if (attrs
.count(key
) > 0) {
5241 std::cout
<< "key " << key
<< "in omap , " << value
.c_str() << " : " << attrs
[key
].c_str() << std::endl
;
5244 std::cout
<< "key " << key
<< "should not exists in omap" << std::endl
;
5246 ASSERT_EQ(correct
, true);
5248 ASSERT_EQ((int)attrs
.size(), count
);
5250 // FileStore may deadlock an active iterator vs queue_transaction
5251 iter
= ObjectMap::ObjectMapIterator();
5254 snprintf(buf
, sizeof(buf
), "%d", i
);
5256 bufferptr
bp(buf
, strlen(buf
) + 1);
5258 map
<string
, bufferlist
> to_add
;
5259 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5260 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5261 ObjectStore::Transaction t
;
5262 t
.omap_setkeys(cid
, hoid
, to_add
);
5263 r
= queue_transaction(store
, ch
, std::move(t
));
5267 iter
= store
->get_omap_iterator(ch
, hoid
);
5269 string bound_key
= "key-5";
5270 iter
->lower_bound(bound_key
);
5271 correct
= bound_key
<= iter
->key();
5273 std::cout
<< "lower bound, bound key is " << bound_key
<< " < iter key is " << iter
->key() << std::endl
;
5275 ASSERT_EQ(correct
, true);
5277 iter
->upper_bound(bound_key
);
5278 correct
= iter
->key() > bound_key
;
5280 std::cout
<< "upper bound, bound key is " << bound_key
<< " >= iter key is " << iter
->key() << std::endl
;
5282 ASSERT_EQ(correct
, true);
5284 // FileStore may deadlock an active iterator vs queue_transaction
5285 iter
= ObjectMap::ObjectMapIterator();
5287 ObjectStore::Transaction t
;
5288 t
.remove(cid
, hoid
);
5289 t
.remove_collection(cid
);
5290 r
= queue_transaction(store
, ch
, std::move(t
));
5295 TEST_P(StoreTest
, XattrTest
) {
5297 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5299 for (unsigned i
= 0; i
< 10000; ++i
) {
5303 for (unsigned i
= 0; i
< 10; ++i
) {
5307 auto ch
= store
->create_new_collection(cid
);
5309 ObjectStore::Transaction t
;
5310 t
.create_collection(cid
, 0);
5312 r
= queue_transaction(store
, ch
, std::move(t
));
5316 map
<string
, bufferlist
> attrs
;
5318 ObjectStore::Transaction t
;
5319 t
.setattr(cid
, hoid
, "attr1", small
);
5320 attrs
["attr1"] = small
;
5321 t
.setattr(cid
, hoid
, "attr2", big
);
5322 attrs
["attr2"] = big
;
5323 t
.setattr(cid
, hoid
, "attr3", small
);
5324 attrs
["attr3"] = small
;
5325 t
.setattr(cid
, hoid
, "attr1", small
);
5326 attrs
["attr1"] = small
;
5327 t
.setattr(cid
, hoid
, "attr4", big
);
5328 attrs
["attr4"] = big
;
5329 t
.setattr(cid
, hoid
, "attr3", big
);
5330 attrs
["attr3"] = big
;
5331 r
= queue_transaction(store
, ch
, std::move(t
));
5335 map
<string
, bufferptr
> aset
;
5336 store
->getattrs(ch
, hoid
, aset
);
5337 ASSERT_EQ(aset
.size(), attrs
.size());
5338 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
5342 bl
.push_back(i
->second
);
5343 ASSERT_TRUE(attrs
[i
->first
] == bl
);
5347 ObjectStore::Transaction t
;
5348 t
.rmattr(cid
, hoid
, "attr2");
5349 attrs
.erase("attr2");
5350 r
= queue_transaction(store
, ch
, std::move(t
));
5355 store
->getattrs(ch
, hoid
, aset
);
5356 ASSERT_EQ(aset
.size(), attrs
.size());
5357 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
5361 bl
.push_back(i
->second
);
5362 ASSERT_TRUE(attrs
[i
->first
] == bl
);
5366 r
= store
->getattr(ch
, hoid
, "attr2", bp
);
5367 ASSERT_EQ(r
, -ENODATA
);
5369 r
= store
->getattr(ch
, hoid
, "attr3", bp
);
5373 ASSERT_TRUE(bl2
== attrs
["attr3"]);
5375 ObjectStore::Transaction t
;
5376 t
.remove(cid
, hoid
);
5377 t
.remove_collection(cid
);
5378 r
= queue_transaction(store
, ch
, std::move(t
));
5384 unsigned num_objects
,
5385 unsigned common_suffix_size
,
5388 coll_t
cid(spg_t(pg_t(0,52),shard_id_t::NO_SHARD
));
5389 coll_t
tid(spg_t(pg_t(1<<common_suffix_size
,52),shard_id_t::NO_SHARD
));
5390 auto ch
= store
->create_new_collection(cid
);
5391 auto tch
= store
->create_new_collection(tid
);
5394 ObjectStore::Transaction t
;
5395 t
.create_collection(cid
, common_suffix_size
);
5396 r
= queue_transaction(store
, ch
, std::move(t
));
5400 small
.append("small");
5402 ObjectStore::Transaction t
;
5403 for (uint32_t i
= 0; i
< (2 - (int)clones
)*num_objects
; ++i
) {
5404 stringstream objname
;
5405 objname
<< "obj" << i
;
5406 ghobject_t
a(hobject_t(
5410 i
<<common_suffix_size
,
5412 t
.write(cid
, a
, 0, small
.length(), small
,
5413 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
5415 objname
<< "-clone";
5416 ghobject_t
b(hobject_t(
5420 i
<<common_suffix_size
,
5425 r
= queue_transaction(store
, ch
, std::move(t
));
5427 t
= ObjectStore::Transaction();
5430 r
= queue_transaction(store
, ch
, std::move(t
));
5434 ObjectStore::Transaction t
;
5435 t
.create_collection(tid
, common_suffix_size
+ 1);
5436 t
.split_collection(cid
, common_suffix_size
+1, 1<<common_suffix_size
, tid
);
5437 r
= queue_transaction(store
, ch
, std::move(t
));
5443 vector
<ghobject_t
> objects
;
5444 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
5445 INT_MAX
, &objects
, 0);
5447 ASSERT_EQ(objects
.size(), num_objects
);
5448 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5451 ASSERT_EQ(!!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
5455 r
= store
->collection_list(tch
, ghobject_t(), ghobject_t::get_max(),
5456 INT_MAX
, &objects
, 0);
5458 ASSERT_EQ(objects
.size(), num_objects
);
5459 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5462 ASSERT_EQ(!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
5465 // merge them again!
5467 ObjectStore::Transaction t
;
5468 t
.merge_collection(tid
, cid
, common_suffix_size
);
5469 r
= queue_transaction(store
, ch
, std::move(t
));
5473 // check and clean up
5474 ObjectStore::Transaction t
;
5476 vector
<ghobject_t
> objects
;
5477 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
5478 INT_MAX
, &objects
, 0);
5480 ASSERT_EQ(objects
.size(), num_objects
* 2); // both halves
5482 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5488 r
= queue_transaction(store
, ch
, std::move(t
));
5490 t
= ObjectStore::Transaction();
5494 t
.remove_collection(cid
);
5495 r
= queue_transaction(store
, ch
, std::move(t
));
5499 ASSERT_TRUE(!store
->collection_exists(tid
));
5502 TEST_P(StoreTest
, ColSplitTest0
) {
5503 colsplittest(store
.get(), 10, 5, false);
5505 TEST_P(StoreTest
, ColSplitTest1
) {
5506 colsplittest(store
.get(), 10000, 11, false);
5508 TEST_P(StoreTest
, ColSplitTest1Clones
) {
5509 colsplittest(store
.get(), 10000, 11, true);
5511 TEST_P(StoreTest
, ColSplitTest2
) {
5512 colsplittest(store
.get(), 100, 7, false);
5514 TEST_P(StoreTest
, ColSplitTest2Clones
) {
5515 colsplittest(store
.get(), 100, 7, true);
5519 TEST_P(StoreTest
, ColSplitTest3
) {
5520 colsplittest(store
.get(), 100000, 25);
5524 void test_merge_skewed(ObjectStore
*store
,
5525 unsigned base
, unsigned bits
,
5526 unsigned anum
, unsigned bnum
)
5528 cout
<< __func__
<< " 0x" << std::hex
<< base
<< std::dec
5530 << " anum " << anum
<< " bnum " << bnum
<< std::endl
;
5532 make merge source pgs have radically different # of objects in them,
5533 which should trigger different splitting in filestore, and verify that
5534 post-merge all objects are accessible.
5537 coll_t
a(spg_t(pg_t(base
, 0), shard_id_t::NO_SHARD
));
5538 coll_t
b(spg_t(pg_t(base
| (1<<bits
), 0), shard_id_t::NO_SHARD
));
5540 auto cha
= store
->create_new_collection(a
);
5541 auto chb
= store
->create_new_collection(b
);
5543 ObjectStore::Transaction t
;
5544 t
.create_collection(a
, bits
+ 1);
5545 r
= queue_transaction(store
, cha
, std::move(t
));
5549 ObjectStore::Transaction t
;
5550 t
.create_collection(b
, bits
+ 1);
5551 r
= queue_transaction(store
, chb
, std::move(t
));
5556 small
.append("small");
5557 string suffix
= "ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooaaaaaaaaaa";
5558 set
<ghobject_t
> aobjects
, bobjects
;
5561 ObjectStore::Transaction t
;
5562 for (unsigned i
= 0; i
< 1000; ++i
) {
5563 string objname
= "a" + stringify(i
) + suffix
;
5564 ghobject_t
o(hobject_t(
5571 t
.write(a
, o
, 0, small
.length(), small
, 0);
5573 r
= queue_transaction(store
, cha
, std::move(t
));
5575 t
= ObjectStore::Transaction();
5578 r
= queue_transaction(store
, cha
, std::move(t
));
5583 ObjectStore::Transaction t
;
5584 for (unsigned i
= 0; i
< 10; ++i
) {
5585 string objname
= "b" + stringify(i
) + suffix
;
5586 ghobject_t
o(hobject_t(
5590 (i
<<(base
+1)) | base
| (1<<bits
),
5593 t
.write(b
, o
, 0, small
.length(), small
, 0);
5595 r
= queue_transaction(store
, chb
, std::move(t
));
5597 t
= ObjectStore::Transaction();
5600 r
= queue_transaction(store
, chb
, std::move(t
));
5606 ObjectStore::Transaction t
;
5607 t
.merge_collection(b
, a
, bits
);
5608 r
= queue_transaction(store
, cha
, std::move(t
));
5614 vector
<ghobject_t
> got
;
5615 store
->collection_list(cha
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5617 set
<ghobject_t
> gotset
;
5618 for (auto& o
: got
) {
5619 ASSERT_TRUE(aobjects
.count(o
) || bobjects
.count(o
));
5622 // check both listing and stat-ability (different code paths!)
5624 for (auto& o
: aobjects
) {
5625 ASSERT_TRUE(gotset
.count(o
));
5626 int r
= store
->stat(cha
, o
, &st
, false);
5629 for (auto& o
: bobjects
) {
5630 ASSERT_TRUE(gotset
.count(o
));
5631 int r
= store
->stat(cha
, o
, &st
, false);
5638 ObjectStore::Transaction t
;
5639 for (auto &o
: aobjects
) {
5642 r
= queue_transaction(store
, cha
, std::move(t
));
5646 ObjectStore::Transaction t
;
5647 for (auto &o
: bobjects
) {
5650 t
.remove_collection(a
);
5651 r
= queue_transaction(store
, cha
, std::move(t
));
5656 TEST_P(StoreTest
, MergeSkewed
) {
5657 if (string(GetParam()) != "filestore")
5660 // this is sufficient to exercise merges with different hashing levels
5661 test_merge_skewed(store
.get(), 0xf, 4, 10, 10000);
5662 test_merge_skewed(store
.get(), 0xf, 4, 10000, 10);
5665 // this covers a zillion variations that all boil down to the same thing
5666 for (unsigned base = 3; base < 0x1000; base *= 5) {
5669 for (bits = 0; t; t >>= 1) {
5672 for (unsigned b = bits; b < bits + 10; b += 3) {
5673 for (auto anum : { 10, 1000, 10000 }) {
5674 for (auto bnum : { 10, 1000, 10000 }) {
5678 test_merge_skewed(store.get(), base, b, anum, bnum);
5688 * This test tests adding two different groups
5689 * of objects, each with 1 common prefix and 1
5690 * different prefix. We then remove half
5691 * in order to verify that the merging correctly
5692 * stops at the common prefix subdir. See bug
5694 TEST_P(StoreTest
, TwoHash
) {
5697 auto ch
= store
->create_new_collection(cid
);
5699 ObjectStore::Transaction t
;
5700 t
.create_collection(cid
, 0);
5701 r
= queue_transaction(store
, ch
, std::move(t
));
5704 std::cout
<< "Making objects" << std::endl
;
5705 for (int i
= 0; i
< 360; ++i
) {
5706 ObjectStore::Transaction t
;
5710 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5713 o
.hobj
.set_hash((i
<< 16) | 0xB1);
5715 r
= queue_transaction(store
, ch
, std::move(t
));
5718 std::cout
<< "Removing half" << std::endl
;
5719 for (int i
= 1; i
< 8; ++i
) {
5720 ObjectStore::Transaction t
;
5723 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5725 r
= queue_transaction(store
, ch
, std::move(t
));
5728 std::cout
<< "Checking" << std::endl
;
5729 for (int i
= 1; i
< 8; ++i
) {
5730 ObjectStore::Transaction t
;
5732 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5734 bool exists
= store
->exists(ch
, o
);
5735 ASSERT_EQ(exists
, false);
5739 o
.hobj
.set_hash(0xA1);
5741 bool exists
= store
->exists(ch
, o
);
5742 ASSERT_EQ(exists
, true);
5744 std::cout
<< "Cleanup" << std::endl
;
5745 for (int i
= 0; i
< 360; ++i
) {
5746 ObjectStore::Transaction t
;
5748 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5751 o
.hobj
.set_hash((i
<< 16) | 0xB1);
5753 r
= queue_transaction(store
, ch
, std::move(t
));
5756 ObjectStore::Transaction t
;
5757 t
.remove_collection(cid
);
5758 r
= queue_transaction(store
, ch
, std::move(t
));
5762 TEST_P(StoreTest
, Rename
) {
5763 coll_t
cid(spg_t(pg_t(0, 2122),shard_id_t::NO_SHARD
));
5764 ghobject_t
srcoid(hobject_t("src_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5765 ghobject_t
dstoid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5769 auto ch
= store
->create_new_collection(cid
);
5772 ObjectStore::Transaction t
;
5773 t
.create_collection(cid
, 0);
5774 t
.write(cid
, srcoid
, 0, a
.length(), a
);
5775 r
= queue_transaction(store
, ch
, std::move(t
));
5778 ASSERT_TRUE(store
->exists(ch
, srcoid
));
5780 ObjectStore::Transaction t
;
5781 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
5782 t
.write(cid
, srcoid
, 0, b
.length(), b
);
5783 t
.setattr(cid
, srcoid
, "attr", b
);
5784 r
= queue_transaction(store
, ch
, std::move(t
));
5787 ASSERT_TRUE(store
->exists(ch
, srcoid
));
5788 ASSERT_TRUE(store
->exists(ch
, dstoid
));
5791 store
->read(ch
, srcoid
, 0, 3, bl
);
5792 ASSERT_TRUE(bl_eq(b
, bl
));
5793 store
->read(ch
, dstoid
, 0, 3, bl
);
5794 ASSERT_TRUE(bl_eq(a
, bl
));
5797 ObjectStore::Transaction t
;
5798 t
.remove(cid
, dstoid
);
5799 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
5800 r
= queue_transaction(store
, ch
, std::move(t
));
5803 ASSERT_TRUE(store
->exists(ch
, dstoid
));
5804 ASSERT_FALSE(store
->exists(ch
, srcoid
));
5807 store
->read(ch
, dstoid
, 0, 3, bl
);
5808 ASSERT_TRUE(bl_eq(b
, bl
));
5811 ObjectStore::Transaction t
;
5812 t
.remove(cid
, dstoid
);
5813 t
.remove_collection(cid
);
5814 r
= queue_transaction(store
, ch
, std::move(t
));
5819 TEST_P(StoreTest
, MoveRename
) {
5820 coll_t
cid(spg_t(pg_t(0, 212),shard_id_t::NO_SHARD
));
5821 ghobject_t
temp_oid(hobject_t("tmp_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5822 ghobject_t
oid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5823 auto ch
= store
->create_new_collection(cid
);
5826 ObjectStore::Transaction t
;
5827 t
.create_collection(cid
, 0);
5829 r
= queue_transaction(store
, ch
, std::move(t
));
5832 ASSERT_TRUE(store
->exists(ch
, oid
));
5833 bufferlist data
, attr
;
5834 map
<string
, bufferlist
> omap
;
5835 data
.append("data payload");
5836 attr
.append("attr value");
5837 omap
["omap_key"].append("omap value");
5839 ObjectStore::Transaction t
;
5840 t
.touch(cid
, temp_oid
);
5841 t
.write(cid
, temp_oid
, 0, data
.length(), data
);
5842 t
.setattr(cid
, temp_oid
, "attr", attr
);
5843 t
.omap_setkeys(cid
, temp_oid
, omap
);
5844 r
= queue_transaction(store
, ch
, std::move(t
));
5847 ASSERT_TRUE(store
->exists(ch
, temp_oid
));
5849 ObjectStore::Transaction t
;
5851 t
.collection_move_rename(cid
, temp_oid
, cid
, oid
);
5852 r
= queue_transaction(store
, ch
, std::move(t
));
5855 ASSERT_TRUE(store
->exists(ch
, oid
));
5856 ASSERT_FALSE(store
->exists(ch
, temp_oid
));
5859 r
= store
->read(ch
, oid
, 0, 1000, newdata
);
5861 ASSERT_TRUE(bl_eq(data
, newdata
));
5863 r
= store
->getattr(ch
, oid
, "attr", newattr
);
5865 ASSERT_TRUE(bl_eq(attr
, newattr
));
5867 keys
.insert("omap_key");
5868 map
<string
, bufferlist
> newomap
;
5869 r
= store
->omap_get_values(ch
, oid
, keys
, &newomap
);
5871 ASSERT_EQ(1u, newomap
.size());
5872 ASSERT_TRUE(newomap
.count("omap_key"));
5873 ASSERT_TRUE(bl_eq(omap
["omap_key"], newomap
["omap_key"]));
5876 ObjectStore::Transaction t
;
5878 t
.remove_collection(cid
);
5879 r
= queue_transaction(store
, ch
, std::move(t
));
5884 TEST_P(StoreTest
, BigRGWObjectName
) {
5885 coll_t
cid(spg_t(pg_t(0,12),shard_id_t::NO_SHARD
));
5888 "default.4106.50_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
5895 shard_id_t::NO_SHARD
);
5896 ghobject_t
oid2(oid
);
5897 oid2
.generation
= 17;
5898 ghobject_t
oidhead(oid
);
5899 oidhead
.generation
= ghobject_t::NO_GEN
;
5901 auto ch
= store
->create_new_collection(cid
);
5905 ObjectStore::Transaction t
;
5906 t
.create_collection(cid
, 0);
5907 t
.touch(cid
, oidhead
);
5908 t
.collection_move_rename(cid
, oidhead
, cid
, oid
);
5909 t
.touch(cid
, oidhead
);
5910 t
.collection_move_rename(cid
, oidhead
, cid
, oid2
);
5911 r
= queue_transaction(store
, ch
, std::move(t
));
5916 ObjectStore::Transaction t
;
5918 r
= queue_transaction(store
, ch
, std::move(t
));
5923 vector
<ghobject_t
> objects
;
5924 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
5925 INT_MAX
, &objects
, 0);
5927 ASSERT_EQ(objects
.size(), 1u);
5928 ASSERT_EQ(objects
[0], oid2
);
5931 ASSERT_FALSE(store
->exists(ch
, oid
));
5934 ObjectStore::Transaction t
;
5935 t
.remove(cid
, oid2
);
5936 t
.remove_collection(cid
);
5937 r
= queue_transaction(store
, ch
, std::move(t
));
5943 TEST_P(StoreTest
, SetAllocHint
) {
5945 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, 0, ""));
5946 auto ch
= store
->create_new_collection(cid
);
5949 ObjectStore::Transaction t
;
5950 t
.create_collection(cid
, 0);
5952 r
= queue_transaction(store
, ch
, std::move(t
));
5956 ObjectStore::Transaction t
;
5957 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
5958 r
= queue_transaction(store
, ch
, std::move(t
));
5962 ObjectStore::Transaction t
;
5963 t
.remove(cid
, hoid
);
5964 r
= queue_transaction(store
, ch
, std::move(t
));
5968 ObjectStore::Transaction t
;
5969 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
5970 r
= queue_transaction(store
, ch
, std::move(t
));
5974 ObjectStore::Transaction t
;
5975 t
.remove_collection(cid
);
5976 r
= queue_transaction(store
, ch
, std::move(t
));
5981 TEST_P(StoreTest
, TryMoveRename
) {
5983 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
5984 ghobject_t
hoid2(hobject_t("test_hint2", "", CEPH_NOSNAP
, 0, -1, ""));
5985 auto ch
= store
->create_new_collection(cid
);
5988 ObjectStore::Transaction t
;
5989 t
.create_collection(cid
, 0);
5990 r
= queue_transaction(store
, ch
, std::move(t
));
5994 ObjectStore::Transaction t
;
5995 t
.try_rename(cid
, hoid
, hoid2
);
5996 r
= queue_transaction(store
, ch
, std::move(t
));
6000 ObjectStore::Transaction t
;
6002 r
= queue_transaction(store
, ch
, std::move(t
));
6006 ObjectStore::Transaction t
;
6007 t
.try_rename(cid
, hoid
, hoid2
);
6008 r
= queue_transaction(store
, ch
, std::move(t
));
6012 ASSERT_EQ(store
->stat(ch
, hoid
, &st
), -ENOENT
);
6013 ASSERT_EQ(store
->stat(ch
, hoid2
, &st
), 0);
6016 #if defined(WITH_BLUESTORE)
6017 TEST_P(StoreTest
, BluestoreOnOffCSumTest
) {
6018 if (string(GetParam()) != "bluestore")
6020 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6021 g_conf().apply_changes(nullptr);
6025 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
6027 auto ch
= store
->open_collection(cid
);
6030 auto ch
= store
->create_new_collection(cid
);
6032 ObjectStore::Transaction t
;
6033 t
.create_collection(cid
, 0);
6034 cerr
<< "Creating collection " << cid
<< std::endl
;
6035 r
= queue_transaction(store
, ch
, std::move(t
));
6039 //write with csum enabled followed by read with csum disabled
6040 size_t block_size
= 64*1024;
6041 ObjectStore::Transaction t
;
6042 bufferlist bl
, orig
;
6043 bl
.append(std::string(block_size
, 'a'));
6045 t
.remove(cid
, hoid
);
6046 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6047 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6048 cerr
<< "Remove then create" << std::endl
;
6049 r
= queue_transaction(store
, ch
, std::move(t
));
6052 SetVal(g_conf(), "bluestore_csum_type", "none");
6053 g_conf().apply_changes(nullptr);
6056 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6057 ASSERT_EQ((int)block_size
, r
);
6058 ASSERT_TRUE(bl_eq(orig
, in
));
6062 //write with csum disabled followed by read with csum enabled
6064 size_t block_size
= 64*1024;
6065 ObjectStore::Transaction t
;
6066 bufferlist bl
, orig
;
6067 bl
.append(std::string(block_size
, 'a'));
6069 t
.remove(cid
, hoid
);
6070 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6071 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6072 cerr
<< "Remove then create" << std::endl
;
6073 r
= queue_transaction(store
, ch
, std::move(t
));
6076 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6077 g_conf().apply_changes(nullptr);
6080 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6081 ASSERT_EQ((int)block_size
, r
);
6082 ASSERT_TRUE(bl_eq(orig
, in
));
6085 //'mixed' non-overlapping writes to the same blob
6087 ObjectStore::Transaction t
;
6088 bufferlist bl
, orig
;
6089 size_t block_size
= 8000;
6090 bl
.append(std::string(block_size
, 'a'));
6092 t
.remove(cid
, hoid
);
6093 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6094 cerr
<< "Remove then create" << std::endl
;
6095 r
= queue_transaction(store
, ch
, std::move(t
));
6098 SetVal(g_conf(), "bluestore_csum_type", "none");
6099 g_conf().apply_changes(nullptr);
6101 ObjectStore::Transaction t2
;
6102 t2
.write(cid
, hoid
, block_size
*2, bl
.length(), bl
);
6103 cerr
<< "Append 'unprotected'" << std::endl
;
6104 r
= queue_transaction(store
, ch
, std::move(t2
));
6108 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6109 ASSERT_EQ((int)block_size
, r
);
6110 ASSERT_TRUE(bl_eq(orig
, in
));
6112 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6113 ASSERT_EQ((int)block_size
, r
);
6114 ASSERT_TRUE(bl_eq(orig
, in
));
6116 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6117 g_conf().apply_changes(nullptr);
6119 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6120 ASSERT_EQ((int)block_size
, r
);
6121 ASSERT_TRUE(bl_eq(orig
, in
));
6123 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6124 ASSERT_EQ((int)block_size
, r
);
6125 ASSERT_TRUE(bl_eq(orig
, in
));
6128 //partially blob overwrite under a different csum enablement mode
6130 ObjectStore::Transaction t
;
6131 bufferlist bl
, orig
, orig2
;
6132 size_t block_size0
= 0x10000;
6133 size_t block_size
= 9000;
6134 size_t block_size2
= 5000;
6135 bl
.append(std::string(block_size0
, 'a'));
6136 t
.remove(cid
, hoid
);
6137 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6138 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6139 cerr
<< "Remove then create" << std::endl
;
6140 r
= queue_transaction(store
, ch
, std::move(t
));
6143 SetVal(g_conf(), "bluestore_csum_type", "none");
6144 g_conf().apply_changes(nullptr);
6146 ObjectStore::Transaction t2
;
6148 bl
.append(std::string(block_size
, 'b'));
6149 t2
.write(cid
, hoid
, 0, bl
.length(), bl
);
6150 t2
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6151 cerr
<< "Overwrite with unprotected data" << std::endl
;
6152 r
= queue_transaction(store
, ch
, std::move(t2
));
6157 orig
.append( std::string(block_size0
- block_size
, 'a'));
6160 r
= store
->read(ch
, hoid
, 0, block_size0
, in
);
6161 ASSERT_EQ((int)block_size0
, r
);
6162 ASSERT_TRUE(bl_eq(orig
, in
));
6164 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6165 ASSERT_EQ((int)block_size
, r
);
6166 ASSERT_TRUE(bl_eq(orig2
, in
));
6168 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6169 g_conf().apply_changes(nullptr);
6171 ObjectStore::Transaction t3
;
6173 bl
.append(std::string(block_size2
, 'c'));
6174 t3
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6175 cerr
<< "Overwrite with protected data" << std::endl
;
6176 r
= queue_transaction(store
, ch
, std::move(t3
));
6181 orig
.append( std::string(block_size
- block_size2
, 'b'));
6182 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6183 ASSERT_EQ((int)block_size
, r
);
6184 ASSERT_TRUE(bl_eq(orig
, in
));
6188 ObjectStore::Transaction t
;
6189 t
.remove(cid
, hoid
);
6190 t
.remove_collection(cid
);
6191 cerr
<< "Cleaning" << std::endl
;
6192 r
= queue_transaction(store
, ch
, std::move(t
));
6198 INSTANTIATE_TEST_SUITE_P(
6204 #if defined(WITH_BLUESTORE)
6209 // Note: instantiate all stores to preserve store numbering order only
6210 INSTANTIATE_TEST_SUITE_P(
6212 StoreTestSpecificAUSize
,
6216 #if defined(WITH_BLUESTORE)
6221 void doMany4KWritesTest(boost::scoped_ptr
<ObjectStore
>& store
,
6222 unsigned max_objects
,
6224 unsigned max_object_size
,
6225 unsigned max_write_size
,
6226 unsigned write_alignment
)
6228 MixedGenerator
gen(555);
6229 gen_type
rng(time(NULL
));
6230 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
6231 store_statfs_t res_stat
;
6233 SyntheticWorkloadState
test_obj(store
.get(),
6241 for (unsigned i
= 0; i
< max_objects
; ++i
) {
6242 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
6245 for (unsigned i
= 0; i
< max_ops
; ++i
) {
6247 cerr
<< "Op " << i
<< std::endl
;
6248 test_obj
.print_internal_state();
6252 test_obj
.wait_for_done();
6253 test_obj
.statfs(res_stat
);
6254 if (!(res_stat
.data_stored
<= max_object_size
) ||
6255 !(res_stat
.allocated
<= max_object_size
)) {
6256 // this will provide more insight on the mismatch and
6257 // helps to avoid any races during stats collection
6258 test_obj
.fsck(false);
6259 // retrieving stats once again and assert if still broken
6260 test_obj
.statfs(res_stat
);
6261 ASSERT_LE(res_stat
.data_stored
, max_object_size
);
6262 ASSERT_LE(res_stat
.allocated
, max_object_size
);
6264 test_obj
.shutdown();
6267 TEST_P(StoreTestSpecificAUSize
, Many4KWritesTest
) {
6268 if (string(GetParam()) != "bluestore")
6271 StartDeferred(0x10000);
6273 const unsigned max_object
= 4*1024*1024;
6274 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0);
6277 TEST_P(StoreTestSpecificAUSize
, Many4KWritesNoCSumTest
) {
6278 if (string(GetParam()) != "bluestore")
6280 StartDeferred(0x10000);
6281 SetVal(g_conf(), "bluestore_csum_type", "none");
6282 g_ceph_context
->_conf
.apply_changes(nullptr);
6283 const unsigned max_object
= 4*1024*1024;
6285 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0 );
6288 TEST_P(StoreTestSpecificAUSize
, TooManyBlobsTest
) {
6289 if (string(GetParam()) != "bluestore")
6291 StartDeferred(0x10000);
6292 const unsigned max_object
= 4*1024*1024;
6293 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0);
6296 #if defined(WITH_BLUESTORE)
6297 void get_mempool_stats(uint64_t* total_bytes
, uint64_t* total_items
)
6299 uint64_t onode_allocated
= mempool::bluestore_cache_onode::allocated_bytes();
6300 uint64_t other_allocated
= mempool::bluestore_cache_other::allocated_bytes();
6302 uint64_t onode_items
= mempool::bluestore_cache_onode::allocated_items();
6303 uint64_t other_items
= mempool::bluestore_cache_other::allocated_items();
6304 cout
<< "onode(" << onode_allocated
<< "/" << onode_items
6305 << ") other(" << other_allocated
<< "/" << other_items
6306 << ")" << std::endl
;
6307 *total_bytes
= onode_allocated
+ other_allocated
;
6308 *total_items
= onode_items
;
6311 TEST_P(StoreTestSpecificAUSize
, OnodeSizeTracking
) {
6313 if (string(GetParam()) != "bluestore")
6316 size_t block_size
= 4096;
6317 StartDeferred(block_size
);
6318 SetVal(g_conf(), "bluestore_compression_mode", "none");
6319 SetVal(g_conf(), "bluestore_csum_type", "none");
6320 SetVal(g_conf(), "bluestore_cache_size_hdd", "400000000");
6321 SetVal(g_conf(), "bluestore_cache_size_ssd", "400000000");
6322 g_conf().apply_changes(nullptr);
6326 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6327 size_t obj_size
= 4 * 1024 * 1024;
6328 uint64_t total_bytes
, total_bytes2
;
6329 uint64_t total_onodes
;
6330 get_mempool_stats(&total_bytes
, &total_onodes
);
6331 ASSERT_EQ(total_onodes
, 0u);
6333 auto ch
= store
->create_new_collection(cid
);
6335 ObjectStore::Transaction t
;
6336 t
.create_collection(cid
, 0);
6337 r
= queue_transaction(store
, ch
, std::move(t
));
6341 ObjectStore::Transaction t
;
6342 bufferlist bl
, orig
, orig2
;
6344 bl
.append(std::string(obj_size
, 'a'));
6345 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6346 r
= queue_transaction(store
, ch
, std::move(t
));
6349 get_mempool_stats(&total_bytes
, &total_onodes
);
6350 ASSERT_NE(total_bytes
, 0u);
6351 ASSERT_EQ(total_onodes
, 1u);
6354 ObjectStore::Transaction t
;
6355 t
.truncate(cid
, hoid
, 0);
6356 r
= queue_transaction(store
, ch
, std::move(t
));
6360 for(size_t i
= 0; i
< 1; ++i
) {
6362 bl
.append(std::string(block_size
* (i
+1), 'a'));
6363 for( size_t j
= 0; j
< obj_size
; j
+= bl
.length()) {
6364 ObjectStore::Transaction t
;
6365 t
.write(cid
, hoid
, j
, bl
.length(), bl
);
6366 r
= queue_transaction(store
, ch
, std::move(t
));
6369 get_mempool_stats(&total_bytes2
, &total_onodes
);
6370 ASSERT_NE(total_bytes2
, 0u);
6371 ASSERT_EQ(total_onodes
, 1u);
6374 cout
<<" mempool dump:\n";
6375 JSONFormatter
f(true);
6376 f
.open_object_section("transaction");
6384 for (size_t i
= 0; i
< obj_size
; i
+= 0x1000) {
6385 store
->read(ch
, hoid
, i
, 0x1000, bl
);
6388 get_mempool_stats(&total_bytes
, &total_onodes
);
6389 ASSERT_NE(total_bytes
, 0u);
6390 ASSERT_EQ(total_onodes
, 1u);
6393 cout
<<" mempool dump:\n";
6394 JSONFormatter
f(true);
6395 f
.open_object_section("transaction");
6402 ObjectStore::Transaction t
;
6403 t
.remove(cid
, hoid
);
6404 t
.remove_collection(cid
);
6405 cerr
<< "Cleaning" << std::endl
;
6406 r
= queue_transaction(store
, ch
, std::move(t
));
6411 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwrite
) {
6413 if (string(GetParam()) != "bluestore")
6416 size_t block_size
= 4096;
6417 StartDeferred(block_size
);
6418 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6419 g_conf().apply_changes(nullptr);
6423 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6425 const PerfCounters
* logger
= store
->get_perf_counters();
6427 auto ch
= store
->create_new_collection(cid
);
6429 ObjectStore::Transaction t
;
6430 t
.create_collection(cid
, 0);
6431 r
= queue_transaction(store
, ch
, std::move(t
));
6435 ObjectStore::Transaction t
;
6438 bl
.append(std::string(block_size
* 2, 'a'));
6439 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6440 r
= queue_transaction(store
, ch
, std::move(t
));
6444 // overwrite at the beginning
6445 ObjectStore::Transaction t
;
6448 bl
.append(std::string(block_size
, 'b'));
6449 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6450 r
= queue_transaction(store
, ch
, std::move(t
));
6455 ObjectStore::Transaction t
;
6458 bl
.append(std::string(block_size
* 2, 'c'));
6459 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6460 r
= queue_transaction(store
, ch
, std::move(t
));
6464 // append with a gap
6465 ObjectStore::Transaction t
;
6468 bl
.append(std::string(block_size
* 2, 'd'));
6469 t
.write(cid
, hoid
, block_size
* 5, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6470 r
= queue_transaction(store
, ch
, std::move(t
));
6474 // We need to issue a read to trigger cache stat update that refresh
6475 // perf counters. additionally we need to wait some time for mempool
6476 // thread to update stats.
6478 bufferlist bl
, expected
;
6479 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6480 ASSERT_EQ(r
, (int)block_size
);
6481 expected
.append(string(block_size
, 'b'));
6482 ASSERT_TRUE(bl_eq(expected
, bl
));
6483 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6484 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
6488 ObjectStore::Transaction t
;
6491 bl
.append(std::string(block_size
* 2, 'e'));
6493 // Currently we are unable to reuse blob when overwriting in a single step
6494 t
.write(cid
, hoid
, block_size
* 6, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6495 r
= queue_transaction(store
, ch
, std::move(t
));
6499 // We need to issue a read to trigger cache stat update that refresh
6500 // perf counters. additionally we need to wait some time for mempool
6501 // thread to update stats.
6503 bufferlist bl
, expected
;
6504 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6505 ASSERT_EQ(r
, (int)block_size
);
6506 expected
.append(string(block_size
, 'b'));
6507 ASSERT_TRUE(bl_eq(expected
, bl
));
6508 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6509 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
6513 ObjectStore::Transaction t
;
6516 bl
.append(std::string(block_size
, 'f'));
6518 t
.write(cid
, hoid
, block_size
* 4, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6519 r
= queue_transaction(store
, ch
, std::move(t
));
6523 // we need to wait some time for mempool
6524 // thread to update stats to be able to check blob/extent numbers from
6528 bufferlist bl
, expected
;
6529 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6530 ASSERT_EQ(r
, (int)block_size
);
6531 expected
.append(string(block_size
, 'b'));
6532 ASSERT_TRUE(bl_eq(expected
, bl
));
6536 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
6537 ASSERT_EQ(r
, (int)block_size
);
6538 expected
.append(string(block_size
, 'a'));
6539 ASSERT_TRUE(bl_eq(expected
, bl
));
6543 r
= store
->read(ch
, hoid
, block_size
* 2, block_size
* 2, bl
);
6544 ASSERT_EQ(r
, (int)block_size
* 2);
6545 expected
.append(string(block_size
* 2, 'c'));
6546 ASSERT_TRUE(bl_eq(expected
, bl
));
6550 r
= store
->read(ch
, hoid
, block_size
* 4, block_size
, bl
);
6551 ASSERT_EQ(r
, (int)block_size
);
6552 expected
.append(string(block_size
, 'f'));
6553 ASSERT_TRUE(bl_eq(expected
, bl
));
6557 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
, bl
);
6558 ASSERT_EQ(r
, (int)block_size
);
6559 expected
.append(string(block_size
, 'd'));
6560 ASSERT_TRUE(bl_eq(expected
, bl
));
6564 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
* 3, bl
);
6565 ASSERT_EQ(r
, (int)block_size
* 3);
6566 expected
.append(string(block_size
, 'd'));
6567 expected
.append(string(block_size
* 2, 'e'));
6568 ASSERT_TRUE(bl_eq(expected
, bl
));
6570 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6571 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
6575 ObjectStore::Transaction t
;
6576 t
.remove(cid
, hoid
);
6577 t
.remove_collection(cid
);
6578 cerr
<< "Cleaning" << std::endl
;
6579 r
= queue_transaction(store
, ch
, std::move(t
));
6584 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwriteReverse
) {
6586 if (string(GetParam()) != "bluestore")
6589 size_t block_size
= 4096;
6590 StartDeferred(block_size
);
6591 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6592 g_conf().apply_changes(nullptr);
6596 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6598 auto ch
= store
->create_new_collection(cid
);
6600 const PerfCounters
* logger
= store
->get_perf_counters();
6602 ObjectStore::Transaction t
;
6603 t
.create_collection(cid
, 0);
6604 r
= queue_transaction(store
, ch
, std::move(t
));
6608 ObjectStore::Transaction t
;
6611 bl
.append(std::string(block_size
* 2, 'a'));
6612 t
.write(cid
, hoid
, block_size
* 10, bl
.length(), bl
,
6613 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6614 r
= queue_transaction(store
, ch
, std::move(t
));
6619 ObjectStore::Transaction t
;
6622 bl
.append(std::string(block_size
, 'b'));
6623 t
.write(cid
, hoid
, block_size
* 9, bl
.length(), bl
,
6624 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6625 r
= queue_transaction(store
, ch
, std::move(t
));
6629 // We need to issue a read to trigger cache stat update that refresh
6630 // perf counters. additionally we need to wait some time for mempool
6631 // thread to update stats.
6633 bufferlist bl
, expected
;
6634 r
= store
->read(ch
, hoid
, block_size
* 9, block_size
* 2, bl
);
6635 ASSERT_EQ(r
, (int)block_size
* 2);
6636 expected
.append(string(block_size
, 'b'));
6637 expected
.append(string(block_size
, 'a'));
6638 ASSERT_TRUE(bl_eq(expected
, bl
));
6639 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6640 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
6645 // prepend existing with a gap
6646 ObjectStore::Transaction t
;
6649 bl
.append(std::string(block_size
, 'c'));
6650 t
.write(cid
, hoid
, block_size
* 7, bl
.length(), bl
,
6651 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6652 r
= queue_transaction(store
, ch
, std::move(t
));
6656 // We need to issue a read to trigger cache stat update that refresh
6657 // perf counters. additionally we need to wait some time for mempool
6658 // thread to update stats.
6660 bufferlist bl
, expected
;
6661 r
= store
->read(ch
, hoid
, block_size
* 7, block_size
* 3, bl
);
6662 ASSERT_EQ(r
, (int)block_size
* 3);
6663 expected
.append(string(block_size
, 'c'));
6664 expected
.append(string(block_size
, 0));
6665 expected
.append(string(block_size
, 'b'));
6666 ASSERT_TRUE(bl_eq(expected
, bl
));
6667 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6668 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
6672 // append after existing with a gap
6673 ObjectStore::Transaction t
;
6676 bl
.append(std::string(block_size
, 'd'));
6677 t
.write(cid
, hoid
, block_size
* 13, bl
.length(), bl
,
6678 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6679 r
= queue_transaction(store
, ch
, std::move(t
));
6683 // We need to issue a read to trigger cache stat update that refresh
6684 // perf counters. additionally we need to wait some time for mempool
6685 // thread to update stats.
6687 bufferlist bl
, expected
;
6688 r
= store
->read(ch
, hoid
, block_size
* 11, block_size
* 3, bl
);
6689 ASSERT_EQ(r
, (int)block_size
* 3);
6690 expected
.append(string(block_size
, 'a'));
6691 expected
.append(string(block_size
, 0));
6692 expected
.append(string(block_size
, 'd'));
6693 ASSERT_TRUE(bl_eq(expected
, bl
));
6694 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6695 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
6699 // append twice to the next max_blob slot
6700 ObjectStore::Transaction t
;
6703 bl
.append(std::string(block_size
, 'e'));
6704 t
.write(cid
, hoid
, block_size
* 17, bl
.length(), bl
,
6705 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6706 t
.write(cid
, hoid
, block_size
* 19, bl
.length(), bl
,
6707 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6708 r
= queue_transaction(store
, ch
, std::move(t
));
6712 // We need to issue a read to trigger cache stat update that refresh
6713 // perf counters. additionally we need to wait some time for mempool
6714 // thread to update stats.
6716 bufferlist bl
, expected
;
6717 r
= store
->read(ch
, hoid
, block_size
* 17, block_size
* 3, bl
);
6718 ASSERT_EQ(r
, (int)block_size
* 3);
6719 expected
.append(string(block_size
, 'e'));
6720 expected
.append(string(block_size
, 0));
6721 expected
.append(string(block_size
, 'e'));
6722 ASSERT_TRUE(bl_eq(expected
, bl
));
6723 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
6724 ASSERT_EQ(logger
->get(l_bluestore_extents
), 5u);
6727 // fill gaps at the second slot
6728 ObjectStore::Transaction t
;
6731 bl
.append(std::string(block_size
, 'f'));
6732 t
.write(cid
, hoid
, block_size
* 16, bl
.length(), bl
,
6733 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6734 t
.write(cid
, hoid
, block_size
* 18, bl
.length(), bl
,
6735 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6736 r
= queue_transaction(store
, ch
, std::move(t
));
6740 // We need to issue a read to trigger cache stat update that refresh
6741 // perf counters. additionally we need to wait some time for mempool
6742 // thread to update stats.
6744 bufferlist bl
, expected
;
6745 r
= store
->read(ch
, hoid
, block_size
* 16, block_size
* 4, bl
);
6746 ASSERT_EQ(r
, (int)block_size
* 4);
6747 expected
.append(string(block_size
, 'f'));
6748 expected
.append(string(block_size
, 'e'));
6749 expected
.append(string(block_size
, 'f'));
6750 expected
.append(string(block_size
, 'e'));
6751 ASSERT_TRUE(bl_eq(expected
, bl
));
6752 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
6753 ASSERT_EQ(logger
->get(l_bluestore_extents
), 4u);
6756 ObjectStore::Transaction t
;
6757 t
.remove(cid
, hoid
);
6758 t
.remove_collection(cid
);
6759 cerr
<< "Cleaning" << std::endl
;
6760 r
= queue_transaction(store
, ch
, std::move(t
));
6765 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnSmallOverwrite
) {
6767 if (string(GetParam()) != "bluestore")
6770 size_t block_size
= 4096;
6771 StartDeferred(block_size
);
6772 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6773 g_conf().apply_changes(nullptr);
6777 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6779 const PerfCounters
* logger
= store
->get_perf_counters();
6780 auto ch
= store
->create_new_collection(cid
);
6783 ObjectStore::Transaction t
;
6784 t
.create_collection(cid
, 0);
6785 r
= queue_transaction(store
, ch
, std::move(t
));
6789 ObjectStore::Transaction t
;
6792 bl
.append(std::string(block_size
, 'a'));
6793 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6794 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
,
6795 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6796 r
= queue_transaction(store
, ch
, std::move(t
));
6800 // write small into the gap
6801 ObjectStore::Transaction t
;
6804 bl
.append(std::string(3, 'b'));
6805 t
.write(cid
, hoid
, block_size
+ 1, bl
.length(), bl
,
6806 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6807 r
= queue_transaction(store
, ch
, std::move(t
));
6811 // We need to issue a read to trigger cache stat update that refresh
6812 // perf counters. additionally we need to wait some time for mempool
6813 // thread to update stats.
6815 bufferlist bl
, expected
;
6816 r
= store
->read(ch
, hoid
, 0, block_size
* 3, bl
);
6817 ASSERT_EQ(r
, (int)block_size
* 3);
6818 expected
.append(string(block_size
, 'a'));
6819 expected
.append(string(1, 0));
6820 expected
.append(string(3, 'b'));
6821 expected
.append(string(block_size
- 4, 0));
6822 expected
.append(string(block_size
, 'a'));
6823 ASSERT_TRUE(bl_eq(expected
, bl
));
6825 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6826 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
6829 ObjectStore::Transaction t
;
6830 t
.remove(cid
, hoid
);
6831 t
.remove_collection(cid
);
6832 cerr
<< "Cleaning" << std::endl
;
6833 r
= queue_transaction(store
, ch
, std::move(t
));
6838 // The test case to reproduce an issue when write happens
6839 // to a zero space between the extents sharing the same spanning blob
6840 // with unloaded shard map.
6841 // Second extent might be filled with zeros this way due to wrong result
6842 // returned by has_any_extents() call in do_write_small. The latter is caused
6843 // by incompletly loaded extent map.
6844 TEST_P(StoreTestSpecificAUSize
, SmallWriteOnShardedExtents
) {
6845 if (string(GetParam()) != "bluestore")
6848 size_t block_size
= 0x10000;
6849 StartDeferred(block_size
);
6851 SetVal(g_conf(), "bluestore_csum_type", "xxhash64");
6852 SetVal(g_conf(), "bluestore_max_blob_size", "524288"); // for sure
6854 g_conf().apply_changes(nullptr);
6858 ghobject_t
hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
6859 auto ch
= store
->create_new_collection(cid
);
6862 ObjectStore::Transaction t
;
6863 t
.create_collection(cid
, 0);
6864 r
= queue_transaction(store
, ch
, std::move(t
));
6868 //doing some tricks to have sharded extents/spanning objects
6869 ObjectStore::Transaction t
;
6872 bl
.append(std::string(0x80000, 'a'));
6873 t
.write(cid
, hoid1
, 0, bl
.length(), bl
, 0);
6874 t
.zero(cid
, hoid1
, 0x719e0, 0x75b0 );
6875 r
= queue_transaction(store
, ch
, std::move(t
));
6878 bl2
.append(std::string(0x70000, 'b'));
6879 t
.write(cid
, hoid1
, 0, bl2
.length(), bl2
, 0);
6880 t
.zero(cid
, hoid1
, 0, 0x50000);
6881 r
= queue_transaction(store
, ch
, std::move(t
));
6888 ch
= store
->open_collection(cid
);
6891 // do a write to zero space in between some extents sharing the same blob
6892 ObjectStore::Transaction t
;
6895 bl
.append(std::string(0x6520, 'c'));
6896 t
.write(cid
, hoid1
, 0x71c00, bl
.length(), bl
, 0);
6898 r
= queue_transaction(store
, ch
, std::move(t
));
6903 ObjectStore::Transaction t
;
6904 bufferlist bl
, expected
;
6906 r
= store
->read(ch
, hoid1
, 0x70000, 0x9c00, bl
);
6907 ASSERT_EQ(r
, (int)0x9c00);
6908 expected
.append(string(0x19e0, 'a'));
6909 expected
.append(string(0x220, 0));
6910 expected
.append(string(0x6520, 'c'));
6911 expected
.append(string(0xe70, 0));
6912 expected
.append(string(0xc70, 'a'));
6913 ASSERT_TRUE(bl_eq(expected
, bl
));
6919 ObjectStore::Transaction t
;
6920 t
.remove(cid
, hoid1
);
6921 t
.remove_collection(cid
);
6922 cerr
<< "Cleaning" << std::endl
;
6923 r
= queue_transaction(store
, ch
, std::move(t
));
6928 TEST_P(StoreTestSpecificAUSize
, ExcessiveFragmentation
) {
6929 if (string(GetParam()) != "bluestore")
6932 SetVal(g_conf(), "bluestore_block_size",
6933 stringify((uint64_t)2048 * 1024 * 1024).c_str());
6935 ASSERT_EQ(g_conf().get_val
<Option::size_t>("bluefs_alloc_size"),
6938 size_t block_size
= 0x10000;
6939 StartDeferred(block_size
);
6943 ghobject_t
hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
6944 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
6945 auto ch
= store
->create_new_collection(cid
);
6948 ObjectStore::Transaction t
;
6949 t
.create_collection(cid
, 0);
6950 r
= queue_transaction(store
, ch
, std::move(t
));
6954 // create 2x400MB objects in a way that their pextents are interleaved
6955 ObjectStore::Transaction t
;
6958 bl
.append(std::string(block_size
* 4, 'a')); // 256KB
6960 while(offs
< (uint64_t)400 * 1024 * 1024) {
6961 t
.write(cid
, hoid1
, offs
, bl
.length(), bl
, 0);
6962 t
.write(cid
, hoid2
, offs
, bl
.length(), bl
, 0);
6963 r
= queue_transaction(store
, ch
, std::move(t
));
6965 offs
+= bl
.length();
6966 if( (offs
% (100 * 1024 * 1024)) == 0) {
6967 std::cout
<<"written " << offs
<< std::endl
;
6971 std::cout
<<"written 800MB"<<std::endl
;
6973 // Partially overwrite objects with 100MB each leaving space
6974 // fragmented and occuping still unfragmented space at the end
6975 // So we'll have enough free space but it'll lack long enough (e.g. 1MB)
6976 // contiguous pextents.
6977 ObjectStore::Transaction t
;
6980 bl
.append(std::string(block_size
* 4, 'a'));
6982 while(offs
< 112 * 1024 * 1024) {
6983 t
.write(cid
, hoid1
, offs
, bl
.length(), bl
, 0);
6984 t
.write(cid
, hoid2
, offs
, bl
.length(), bl
, 0);
6985 r
= queue_transaction(store
, ch
, std::move(t
));
6987 // this will produce high fragmentation if original allocations
6989 offs
+= bl
.length();
6990 if( (offs
% (10 * 1024 * 1024)) == 0) {
6991 std::cout
<<"written " << offs
<< std::endl
;
6996 // remove one of the object producing much free space
6997 // and hence triggering bluefs rebalance.
6998 // Which should fail as there is no long enough pextents.
6999 ObjectStore::Transaction t
;
7000 t
.remove(cid
, hoid2
);
7001 r
= queue_transaction(store
, ch
, std::move(t
));
7006 (int)g_conf().get_val
<double>("bluestore_bluefs_balance_interval");
7007 std::cout
<<"sleeping... " << std::endl
;
7011 // touch another object to triggerrebalance
7012 ObjectStore::Transaction t
;
7013 t
.touch(cid
, hoid1
);
7014 r
= queue_transaction(store
, ch
, std::move(t
));
7018 ObjectStore::Transaction t
;
7019 t
.remove(cid
, hoid1
);
7020 t
.remove(cid
, hoid2
);
7021 t
.remove_collection(cid
);
7022 cerr
<< "Cleaning" << std::endl
;
7023 r
= queue_transaction(store
, ch
, std::move(t
));
7028 #endif //#if defined(WITH_BLUESTORE)
7030 TEST_P(StoreTest
, KVDBHistogramTest
) {
7031 if (string(GetParam()) != "bluestore")
7037 string
base("testobj.");
7039 bufferptr
ap(0x1000);
7040 memset(ap
.c_str(), 'a', 0x1000);
7042 auto ch
= store
->create_new_collection(cid
);
7044 ObjectStore::Transaction t
;
7045 t
.create_collection(cid
, 0);
7046 r
= queue_transaction(store
, ch
, std::move(t
));
7049 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
7050 ObjectStore::Transaction t
;
7052 snprintf(buf
, sizeof(buf
), "%d", i
);
7053 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
7054 t
.write(cid
, hoid
, 0, 0x1000, a
);
7055 r
= queue_transaction(store
, ch
, std::move(t
));
7059 Formatter
*f
= Formatter::create("store_test", "json-pretty", "json-pretty");
7060 store
->generate_db_histogram(f
);
7065 TEST_P(StoreTest
, KVDBStatsTest
) {
7066 if (string(GetParam()) != "bluestore")
7069 SetVal(g_conf(), "rocksdb_perf", "true");
7070 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
7071 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
7072 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
7073 g_ceph_context
->_conf
.apply_changes(nullptr);
7074 int r
= store
->umount();
7076 r
= store
->mount(); //to force rocksdb stats
7081 string
base("testobj.");
7083 bufferptr
ap(0x1000);
7084 memset(ap
.c_str(), 'a', 0x1000);
7086 auto ch
= store
->create_new_collection(cid
);
7088 ObjectStore::Transaction t
;
7089 t
.create_collection(cid
, 0);
7090 r
= queue_transaction(store
, ch
, std::move(t
));
7093 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
7094 ObjectStore::Transaction t
;
7096 snprintf(buf
, sizeof(buf
), "%d", i
);
7097 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
7098 t
.write(cid
, hoid
, 0, 0x1000, a
);
7099 r
= queue_transaction(store
, ch
, std::move(t
));
7103 Formatter
*f
= Formatter::create("store_test", "json-pretty", "json-pretty");
7104 store
->get_db_statistics(f
);
7109 #if defined(WITH_BLUESTORE)
7110 TEST_P(StoreTestSpecificAUSize
, garbageCollection
) {
7113 int buf_len
= 256 * 1024;
7114 int overlap_offset
= 64 * 1024;
7115 int write_offset
= buf_len
;
7116 if (string(GetParam()) != "bluestore")
7119 #define WRITE_AT(offset, _length) {\
7120 ObjectStore::Transaction t;\
7121 if ((uint64_t)_length != bl.length()) { \
7122 buffer::ptr p(bl.c_str(), _length);\
7124 bl_tmp.push_back(p);\
7125 t.write(cid, hoid, offset, bl_tmp.length(), bl_tmp);\
7127 t.write(cid, hoid, offset, bl.length(), bl);\
7129 r = queue_transaction(store, ch, std::move(t));\
7133 StartDeferred(65536);
7135 SetVal(g_conf(), "bluestore_compression_max_blob_size", "524288");
7136 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
7137 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
7138 SetVal(g_conf(), "bluestore_compression_mode", "force");
7139 g_conf().apply_changes(nullptr);
7141 auto ch
= store
->create_new_collection(cid
);
7143 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
7146 r
= store
->read(ch
, hoid
, 0, 5, in
);
7147 ASSERT_EQ(-ENOENT
, r
);
7150 ObjectStore::Transaction t
;
7151 t
.create_collection(cid
, 0);
7152 cerr
<< "Creating collection " << cid
<< std::endl
;
7153 r
= queue_transaction(store
, ch
, std::move(t
));
7158 data
.resize(buf_len
);
7162 bool exists
= store
->exists(ch
, hoid
);
7163 ASSERT_TRUE(!exists
);
7165 ObjectStore::Transaction t
;
7167 cerr
<< "Creating object " << hoid
<< std::endl
;
7168 r
= queue_transaction(store
, ch
, std::move(t
));
7171 exists
= store
->exists(ch
, hoid
);
7172 ASSERT_EQ(true, exists
);
7176 for(size_t i
= 0; i
< data
.size(); i
++)
7182 struct store_statfs_t statfs
;
7183 WRITE_AT(0, buf_len
);
7184 int r
= store
->statfs(&statfs
);
7186 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7189 struct store_statfs_t statfs
;
7190 WRITE_AT(write_offset
- 2 * overlap_offset
, buf_len
);
7191 int r
= store
->statfs(&statfs
);
7193 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7194 const PerfCounters
* counters
= store
->get_perf_counters();
7195 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0u);
7199 struct store_statfs_t statfs
;
7200 WRITE_AT(write_offset
- overlap_offset
, buf_len
);
7201 int r
= store
->statfs(&statfs
);
7203 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7204 const PerfCounters
* counters
= store
->get_perf_counters();
7205 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x10000u
);
7208 struct store_statfs_t statfs
;
7209 WRITE_AT(write_offset
- 3 * overlap_offset
, buf_len
);
7210 int r
= store
->statfs(&statfs
);
7212 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7213 const PerfCounters
* counters
= store
->get_perf_counters();
7214 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
7217 struct store_statfs_t statfs
;
7218 WRITE_AT(write_offset
+ 1, overlap_offset
-1);
7219 int r
= store
->statfs(&statfs
);
7221 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7222 const PerfCounters
* counters
= store
->get_perf_counters();
7223 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
7226 struct store_statfs_t statfs
;
7227 WRITE_AT(write_offset
+ 1, overlap_offset
);
7228 int r
= store
->statfs(&statfs
);
7230 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7231 const PerfCounters
* counters
= store
->get_perf_counters();
7232 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x3ffffu
);
7235 struct store_statfs_t statfs
;
7236 WRITE_AT(0, buf_len
-1);
7237 int r
= store
->statfs(&statfs
);
7239 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7240 const PerfCounters
* counters
= store
->get_perf_counters();
7241 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
7243 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "1"); //forbid GC when saving = 0
7245 struct store_statfs_t statfs
;
7246 WRITE_AT(1, overlap_offset
-2);
7247 WRITE_AT(overlap_offset
* 2 + 1, overlap_offset
-2);
7248 int r
= store
->statfs(&statfs
);
7250 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7251 const PerfCounters
* counters
= store
->get_perf_counters();
7252 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
7255 struct store_statfs_t statfs
;
7256 WRITE_AT(overlap_offset
+ 1, overlap_offset
-2);
7257 int r
= store
->statfs(&statfs
);
7259 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x0);
7260 const PerfCounters
* counters
= store
->get_perf_counters();
7261 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40007u
);
7264 ObjectStore::Transaction t
;
7265 t
.remove(cid
, hoid
);
7266 cerr
<< "Cleaning" << std::endl
;
7267 r
= queue_transaction(store
, ch
, std::move(t
));
7273 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice
) {
7274 if (string(GetParam()) != "bluestore")
7277 SetVal(g_conf(), "bluestore_block_size",
7278 stringify(0x280005000).c_str()); //10 Gb + 4K
7279 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7280 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7281 StartDeferred(0x4000);
7283 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7288 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice2
) {
7289 if (string(GetParam()) != "bluestore")
7292 SetVal(g_conf(), "bluestore_block_size",
7293 stringify(0x280005000).c_str()); //10 Gb + 20K
7294 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7295 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7296 StartDeferred(0x1000);
7298 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7303 ghobject_t
make_object(const char* name
, int64_t pool
) {
7304 sobject_t soid
{name
, CEPH_NOSNAP
};
7305 uint32_t hash
= std::hash
<sobject_t
>{}(soid
);
7306 return ghobject_t
{hobject_t
{soid
, "", hash
, pool
, ""}};
7310 TEST_P(StoreTestSpecificAUSize
, BluestoreRepairTest
) {
7311 if (string(GetParam()) != "bluestore")
7313 const size_t offs_base
= 65536 / 2;
7315 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7316 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7317 SetVal(g_conf(), "bluestore_max_blob_size",
7318 stringify(2 * offs_base
).c_str());
7319 SetVal(g_conf(), "bluestore_extent_map_shard_max_size", "12000");
7320 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "false");
7322 StartDeferred(0x10000);
7324 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
7326 // fill the store with some data
7327 const uint64_t pool
= 555;
7328 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
7329 auto ch
= store
->create_new_collection(cid
);
7331 ghobject_t hoid
= make_object("Object 1", pool
);
7332 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
7333 ghobject_t hoid2
= make_object("Object 2", pool
);
7334 ghobject_t hoid_cloned
= hoid2
;
7335 hoid_cloned
.hobj
.snap
= 1;
7336 ghobject_t hoid3
= make_object("Object 3", pool
);
7337 ghobject_t hoid3_cloned
= hoid3
;
7338 hoid3_cloned
.hobj
.snap
= 1;
7340 bl
.append("1234512345");
7342 const size_t repeats
= 16;
7344 auto ch
= store
->create_new_collection(cid
);
7345 cerr
<< "create collection + write" << std::endl
;
7346 ObjectStore::Transaction t
;
7347 t
.create_collection(cid
, 0);
7348 for( auto i
= 0ul; i
< repeats
; ++i
) {
7349 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
7350 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
7352 for( auto i
= 0ul; i
< repeats
; ++i
) {
7353 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
7355 t
.clone(cid
, hoid2
, hoid_cloned
);
7357 r
= queue_transaction(store
, ch
, std::move(t
));
7362 //////////// leaked pextent fix ////////////
7363 cerr
<< "fix leaked pextents" << std::endl
;
7364 ASSERT_EQ(bstore
->fsck(false), 0);
7365 ASSERT_EQ(bstore
->repair(false), 0);
7367 bstore
->inject_leaked(0x30000);
7369 ASSERT_EQ(bstore
->fsck(false), 1);
7370 ASSERT_EQ(bstore
->repair(false), 0);
7371 ASSERT_EQ(bstore
->fsck(false), 0);
7373 //////////// false free fix ////////////
7374 cerr
<< "fix false free pextents" << std::endl
;
7376 bstore
->inject_false_free(cid
, hoid
);
7378 ASSERT_EQ(bstore
->fsck(false), 2);
7379 ASSERT_EQ(bstore
->repair(false), 0);
7380 ASSERT_EQ(bstore
->fsck(false), 0);
7382 //////////// verify invalid statfs ///////////
7383 cerr
<< "fix invalid statfs" << std::endl
;
7384 store_statfs_t statfs0
, statfs
;
7386 ASSERT_EQ(bstore
->statfs(&statfs0
), 0);
7388 statfs
.allocated
+= 0x10000;
7389 statfs
.data_stored
+= 0x10000;
7390 ASSERT_FALSE(statfs0
== statfs
);
7391 bstore
->inject_statfs("bluestore_statfs", statfs
);
7394 ASSERT_EQ(bstore
->fsck(false), 2);
7395 ASSERT_EQ(bstore
->repair(false), 0);
7396 ASSERT_EQ(bstore
->fsck(false), 0);
7397 ASSERT_EQ(bstore
->mount(), 0);
7398 ASSERT_EQ(bstore
->statfs(&statfs
), 0);
7399 // adjust free space to success in comparison
7400 statfs0
.available
= statfs
.available
;
7401 ASSERT_EQ(statfs0
, statfs
);
7403 ///////// undecodable shared blob key / stray shared blob records ///////
7404 cerr
<< "undecodable shared blob key" << std::endl
;
7405 bstore
->inject_broken_shared_blob_key("undec1",
7407 bstore
->inject_broken_shared_blob_key("undecodable key 2",
7409 bstore
->inject_broken_shared_blob_key("undecodable key 3",
7412 ASSERT_EQ(bstore
->fsck(false), 3);
7413 ASSERT_EQ(bstore
->repair(false), 0);
7414 ASSERT_EQ(bstore
->fsck(false), 0);
7416 cerr
<< "misreferencing" << std::endl
;
7418 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, 0);
7419 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, (offs_base
* repeats
) / 2);
7420 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, offs_base
* (repeats
-1) );
7423 ASSERT_EQ(bstore
->fsck(false), 6);
7424 ASSERT_EQ(bstore
->repair(false), 0);
7426 ASSERT_EQ(bstore
->fsck(true), 0);
7428 // reproducing issues #21040 & 20983
7429 SetVal(g_conf(), "bluestore_debug_inject_bug21040", "true");
7430 g_ceph_context
->_conf
.apply_changes(nullptr);
7433 cerr
<< "repro bug #21040" << std::endl
;
7435 auto ch
= store
->open_collection(cid
);
7437 ObjectStore::Transaction t
;
7438 bl
.append("0123456789012345");
7439 t
.write(cid
, hoid3
, offs_base
, bl
.length(), bl
);
7442 t
.write(cid
, hoid3
, 0, bl
.length(), bl
);
7444 r
= queue_transaction(store
, ch
, std::move(t
));
7448 ObjectStore::Transaction t
;
7449 t
.clone(cid
, hoid3
, hoid3_cloned
);
7450 r
= queue_transaction(store
, ch
, std::move(t
));
7455 ASSERT_EQ(bstore
->fsck(false), 3);
7456 ASSERT_LE(bstore
->repair(false), 0);
7457 ASSERT_EQ(bstore
->fsck(false), 0);
7460 cerr
<< "Completing" << std::endl
;
7465 TEST_P(StoreTest
, BluestoreRepairGlobalStats
)
7467 if (string(GetParam()) != "bluestore")
7469 const size_t offs_base
= 65536 / 2;
7471 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
7473 // start with global stats
7474 bstore
->inject_global_statfs({});
7476 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
7479 // fill the store with some data
7480 const uint64_t pool
= 555;
7481 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
7482 auto ch
= store
->create_new_collection(cid
);
7484 ghobject_t hoid
= make_object("Object 1", pool
);
7485 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
7486 ghobject_t hoid2
= make_object("Object 2", pool
);
7487 ghobject_t hoid_cloned
= hoid2
;
7488 hoid_cloned
.hobj
.snap
= 1;
7489 ghobject_t hoid3
= make_object("Object 3", pool
);
7490 ghobject_t hoid3_cloned
= hoid3
;
7491 hoid3_cloned
.hobj
.snap
= 1;
7493 bl
.append("1234512345");
7495 const size_t repeats
= 16;
7497 auto ch
= store
->create_new_collection(cid
);
7498 cerr
<< "create collection + write" << std::endl
;
7499 ObjectStore::Transaction t
;
7500 t
.create_collection(cid
, 0);
7501 for( auto i
= 0ul; i
< repeats
; ++i
) {
7502 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
7503 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
7505 for( auto i
= 0ul; i
< repeats
; ++i
) {
7506 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
7508 t
.clone(cid
, hoid2
, hoid_cloned
);
7510 r
= queue_transaction(store
, ch
, std::move(t
));
7516 // enable per-pool stats collection hence causing fsck to fail
7517 cerr
<< "per-pool statfs" << std::endl
;
7518 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
7519 g_ceph_context
->_conf
.apply_changes(nullptr);
7521 ASSERT_EQ(bstore
->fsck(false), 1);
7522 ASSERT_EQ(bstore
->repair(false), 0);
7523 ASSERT_EQ(bstore
->fsck(false), 0);
7528 TEST_P(StoreTest
, BluestoreRepairGlobalStatsFixOnMount
)
7530 if (string(GetParam()) != "bluestore")
7532 const size_t offs_base
= 65536 / 2;
7534 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
7536 // start with global stats
7537 bstore
->inject_global_statfs({});
7539 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
7542 // fill the store with some data
7543 const uint64_t pool
= 555;
7544 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
7545 auto ch
= store
->create_new_collection(cid
);
7547 ghobject_t hoid
= make_object("Object 1", pool
);
7548 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
7549 ghobject_t hoid2
= make_object("Object 2", pool
);
7550 ghobject_t hoid_cloned
= hoid2
;
7551 hoid_cloned
.hobj
.snap
= 1;
7552 ghobject_t hoid3
= make_object("Object 3", pool
);
7553 ghobject_t hoid3_cloned
= hoid3
;
7554 hoid3_cloned
.hobj
.snap
= 1;
7556 bl
.append("1234512345");
7558 const size_t repeats
= 16;
7560 auto ch
= store
->create_new_collection(cid
);
7561 cerr
<< "create collection + write" << std::endl
;
7562 ObjectStore::Transaction t
;
7563 t
.create_collection(cid
, 0);
7564 for( auto i
= 0ul; i
< repeats
; ++i
) {
7565 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
7566 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
7568 for( auto i
= 0ul; i
< repeats
; ++i
) {
7569 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
7571 t
.clone(cid
, hoid2
, hoid_cloned
);
7573 r
= queue_transaction(store
, ch
, std::move(t
));
7579 // enable per-pool stats collection hence causing fsck to fail
7580 cerr
<< "per-pool statfs" << std::endl
;
7581 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
7582 g_ceph_context
->_conf
.apply_changes(nullptr);
7584 ASSERT_EQ(bstore
->fsck(false), 1);
7586 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
7589 ASSERT_EQ(bstore
->fsck(false), 0);
7594 TEST_P(StoreTest
, BluestoreStatistics
) {
7595 if (string(GetParam()) != "bluestore")
7598 SetVal(g_conf(), "rocksdb_perf", "true");
7599 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
7600 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
7601 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
7604 SetVal(g_conf(), "bluestore_cache_size_ssd", "0");
7605 SetVal(g_conf(), "bluestore_cache_size_hdd", "0");
7606 SetVal(g_conf(), "bluestore_cache_size", "0");
7607 g_ceph_context
->_conf
.apply_changes(nullptr);
7609 int r
= store
->umount();
7614 BlueStore
* bstore
= NULL
;
7615 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
7618 ghobject_t
hoid(hobject_t("test_db_statistics", "", CEPH_NOSNAP
, 0, 0, ""));
7619 auto ch
= bstore
->create_new_collection(cid
);
7621 bl
.append("0123456789abcdefghi");
7623 ObjectStore::Transaction t
;
7624 t
.create_collection(cid
, 0);
7626 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7627 cerr
<< "Write object" << std::endl
;
7628 r
= queue_transaction(bstore
, ch
, std::move(t
));
7632 bufferlist readback
;
7633 r
= store
->read(ch
, hoid
, 0, bl
.length(), readback
);
7634 ASSERT_EQ(static_cast<int>(bl
.length()), r
);
7635 ASSERT_TRUE(bl_eq(bl
, readback
));
7637 Formatter
*f
= Formatter::create("store_test", "json-pretty", "json-pretty");
7638 EXPECT_NO_THROW(store
->get_db_statistics(f
));
7643 TEST_P(StoreTest
, BluestorePerPoolOmapFixOnMount
)
7645 if (string(GetParam()) != "bluestore")
7648 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
7649 const uint64_t pool
= 555;
7650 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
7651 ghobject_t oid
= make_object("Object 1", pool
);
7652 ghobject_t oid2
= make_object("Object 2", pool
);
7653 // fill the store with some data
7654 auto ch
= store
->create_new_collection(cid
);
7655 map
<string
, bufferlist
> omap
;
7659 omap
["omap_key"].append("omap value");
7660 ObjectStore::Transaction t
;
7661 t
.create_collection(cid
, 0);
7663 t
.omap_setheader(cid
, oid
, h
);
7665 t
.omap_setheader(cid
, oid2
, h
);
7666 int r
= queue_transaction(store
, ch
, std::move(t
));
7670 // inject legacy omaps
7671 bstore
->inject_legacy_omap();
7672 bstore
->inject_legacy_omap(cid
, oid
);
7673 bstore
->inject_legacy_omap(cid
, oid2
);
7677 // check we injected an issue
7678 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
7679 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
7680 g_ceph_context
->_conf
.apply_changes(nullptr);
7681 ASSERT_EQ(bstore
->fsck(false), 3);
7683 // set autofix and mount
7684 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
7685 g_ceph_context
->_conf
.apply_changes(nullptr);
7689 // check we fixed it..
7690 ASSERT_EQ(bstore
->fsck(false), 0);
7694 // Now repro https://tracker.ceph.com/issues/43824
7696 // inject legacy omaps again
7697 bstore
->inject_legacy_omap();
7698 bstore
->inject_legacy_omap(cid
, oid
);
7699 bstore
->inject_legacy_omap(cid
, oid2
);
7702 // check we injected an issue
7703 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
7704 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
7705 g_ceph_context
->_conf
.apply_changes(nullptr);
7707 ch
= store
->open_collection(cid
);
7710 // write to onode which will partiall revert per-pool
7711 // omap repair done on mount due to #43824.
7712 // And object removal will leave stray per-pool omap recs
7714 ObjectStore::Transaction t
;
7717 //this triggers onode rec update and hence legacy omap
7718 t
.write(cid
, oid
, 0, bl
.length(), bl
);
7719 t
.remove(cid
, oid2
); // this will trigger stray per-pool omap
7720 int r
= queue_transaction(store
, ch
, std::move(t
));
7724 // check omap's been fixed.
7725 ASSERT_EQ(bstore
->fsck(false), 0); // this will fail without fix for #43824
7730 TEST_P(StoreTestSpecificAUSize
, BluestoreTinyDevFailure
) {
7731 if (string(GetParam()) != "bluestore")
7733 // This caused superblock overwrite by bluefs, see
7734 // https://tracker.ceph.com/issues/24480
7735 SetVal(g_conf(), "bluestore_block_size",
7736 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7737 SetVal(g_conf(), "bluestore_block_db_size", "0");
7738 SetVal(g_conf(), "bluestore_block_db_create", "false");
7739 SetVal(g_conf(), "bluestore_bluefs_min",
7740 stringify(1024 * 1024 * 1024).c_str());
7741 StartDeferred(0x1000);
7743 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7747 TEST_P(StoreTestSpecificAUSize
, BluestoreTinyDevFailure2
) {
7748 if (string(GetParam()) != "bluestore")
7751 // This caused assert in allocator as initial bluefs extent as slow device
7752 // overlaped with superblock
7753 // https://tracker.ceph.com/issues/24480
7754 SetVal(g_conf(), "bluestore_block_size",
7755 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7756 SetVal(g_conf(), "bluestore_block_db_size",
7757 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7758 SetVal(g_conf(), "bluestore_block_db_create", "true");
7759 SetVal(g_conf(), "bluestore_bluefs_min",
7760 stringify(1024 * 1024 * 1024).c_str());
7761 StartDeferred(0x1000);
7763 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7767 TEST_P(StoreTest
, SpuriousReadErrorTest
) {
7768 if (string(GetParam()) != "bluestore")
7772 auto logger
= store
->get_perf_counters();
7774 auto ch
= store
->create_new_collection(cid
);
7775 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
7777 ObjectStore::Transaction t
;
7778 t
.create_collection(cid
, 0);
7779 cerr
<< "Creating collection " << cid
<< std::endl
;
7780 r
= queue_transaction(store
, ch
, std::move(t
));
7783 bufferlist test_data
;
7784 bufferptr
ap(0x2000);
7785 memset(ap
.c_str(), 'a', 0x2000);
7786 test_data
.append(ap
);
7788 ObjectStore::Transaction t
;
7789 t
.write(cid
, hoid
, 0, 0x2000, test_data
);
7790 r
= queue_transaction(store
, ch
, std::move(t
));
7792 // force cache clear
7793 EXPECT_EQ(store
->umount(), 0);
7794 EXPECT_EQ(store
->mount(), 0);
7797 cerr
<< "Injecting CRC error with no retry, expecting EIO" << std::endl
;
7798 SetVal(g_conf(), "bluestore_retry_disk_reads", "0");
7799 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "1");
7800 g_ceph_context
->_conf
.apply_changes(nullptr);
7803 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7805 ASSERT_EQ(logger
->get(l_bluestore_read_eio
), 1u);
7806 ASSERT_EQ(logger
->get(l_bluestore_reads_with_retries
), 0u);
7809 cerr
<< "Injecting CRC error with retries, expecting success after several retries" << std::endl
;
7810 SetVal(g_conf(), "bluestore_retry_disk_reads", "255");
7811 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "0.8");
7813 * Probabilistic test: 25 reads, each has a 80% chance of failing with 255 retries
7814 * Probability of at least one retried read: 1 - (0.2 ** 25) = 100% - 3e-18
7815 * Probability of a random test failure: 1 - ((1 - (0.8 ** 255)) ** 25) ~= 5e-24
7817 g_ceph_context
->_conf
.apply_changes(nullptr);
7819 for (int i
= 0; i
< 25; ++i
) {
7821 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7822 ASSERT_EQ(0x2000, r
);
7823 ASSERT_TRUE(bl_eq(test_data
, in
));
7825 ASSERT_GE(logger
->get(l_bluestore_reads_with_retries
), 1u);
7829 TEST_P(StoreTest
, allocateBlueFSTest
) {
7830 if (string(GetParam()) != "bluestore")
7833 BlueStore
* bstore
= NULL
;
7834 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
7836 struct store_statfs_t statfs
;
7837 store
->statfs(&statfs
);
7839 uint64_t to_alloc
= g_conf().get_val
<Option::size_t>("bluefs_alloc_size");
7841 int r
= bstore
->allocate_bluefs_freespace(to_alloc
, to_alloc
, nullptr);
7843 r
= bstore
->allocate_bluefs_freespace(statfs
.total
, statfs
.total
, nullptr);
7844 ASSERT_EQ(r
, -ENOSPC
);
7845 r
= bstore
->allocate_bluefs_freespace(to_alloc
* 16, to_alloc
* 16, nullptr);
7848 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7853 TEST_P(StoreTest
, mergeRegionTest
) {
7854 if (string(GetParam()) != "bluestore")
7857 SetVal(g_conf(), "bluestore_fsck_on_mount", "true");
7858 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
7859 SetVal(g_conf(), "bdev_debug_inflight_ios", "true");
7860 g_ceph_context
->_conf
.apply_changes(nullptr);
7862 uint32_t chunk_size
= g_ceph_context
->_conf
->bdev_block_size
;
7865 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
7866 auto ch
= store
->create_new_collection(cid
);
7868 ObjectStore::Transaction t
;
7869 t
.create_collection(cid
, 0);
7870 r
= queue_transaction(store
, ch
, std::move(t
));
7874 ObjectStore::Transaction t
;
7876 cerr
<< "Creating object " << hoid
<< std::endl
;
7877 r
= queue_transaction(store
, ch
, std::move(t
));
7881 bl5
.append("abcde");
7882 uint64_t offset
= 0;
7884 ObjectStore::Transaction t
;
7885 t
.write(cid
, hoid
, offset
, 5, bl5
);
7886 t
.write(cid
, hoid
, 0xa + offset
, 5, bl5
);
7887 t
.write(cid
, hoid
, 0x14 + offset
, 5, bl5
);
7888 r
= queue_transaction(store
, ch
, std::move(t
));
7891 { // 2. adjacent regions
7892 ObjectStore::Transaction t
;
7893 offset
= chunk_size
;
7894 t
.write(cid
, hoid
, offset
, 5, bl5
);
7895 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
7896 r
= queue_transaction(store
, ch
, std::move(t
));
7900 ObjectStore::Transaction t
;
7901 offset
= chunk_size
* 2;
7902 t
.write(cid
, hoid
, offset
, 5, bl5
);
7903 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, 5, bl5
);
7904 r
= queue_transaction(store
, ch
, std::move(t
));
7908 ObjectStore::Transaction t
;
7910 blc2
.append_zero(chunk_size
+ 2);
7912 offset
= chunk_size
* 3;
7913 t
.write(cid
, hoid
, offset
, chunk_size
+ 2, blc2
);
7914 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
7915 r
= queue_transaction(store
, ch
, std::move(t
));
7919 ObjectStore::Transaction t
;
7920 uint64_t final_len
= 0;
7921 offset
= chunk_size
* 10;
7923 bl2c2
.append_zero(chunk_size
* 2);
7924 t
.write(cid
, hoid
, offset
+ chunk_size
* 3 - 3, chunk_size
* 2, bl2c2
);
7925 bl2c2
.append_zero(2);
7926 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, chunk_size
* 2 + 2, bl2c2
);
7927 r
= queue_transaction(store
, ch
, std::move(t
));
7930 final_len
= (offset
+ chunk_size
* 3 - 3) + (chunk_size
* 2);
7932 r
= store
->read(ch
, hoid
, 0, final_len
, bl
);
7933 ASSERT_EQ(final_len
, static_cast<uint64_t>(r
));
7937 TEST_P(StoreTestSpecificAUSize
, BluestoreEnforceHWSettingsHdd
) {
7938 if (string(GetParam()) != "bluestore")
7941 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
7942 StartDeferred(0x1000);
7946 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
7947 auto ch
= store
->create_new_collection(cid
);
7949 ObjectStore::Transaction t
;
7950 t
.create_collection(cid
, 0);
7951 cerr
<< "Creating collection " << cid
<< std::endl
;
7952 r
= queue_transaction(store
, ch
, std::move(t
));
7956 ObjectStore::Transaction t
;
7957 bufferlist bl
, orig
;
7958 string
s(g_ceph_context
->_conf
->bluestore_max_blob_size_hdd
, '0');
7960 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7961 cerr
<< "write" << std::endl
;
7962 r
= queue_transaction(store
, ch
, std::move(t
));
7965 const PerfCounters
* logger
= store
->get_perf_counters();
7966 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 1u);
7970 TEST_P(StoreTestSpecificAUSize
, BluestoreEnforceHWSettingsSsd
) {
7971 if (string(GetParam()) != "bluestore")
7974 SetVal(g_conf(), "bluestore_debug_enforce_settings", "ssd");
7975 StartDeferred(0x1000);
7979 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
7980 auto ch
= store
->create_new_collection(cid
);
7982 ObjectStore::Transaction t
;
7983 t
.create_collection(cid
, 0);
7984 cerr
<< "Creating collection " << cid
<< std::endl
;
7985 r
= queue_transaction(store
, ch
, std::move(t
));
7989 ObjectStore::Transaction t
;
7990 bufferlist bl
, orig
;
7991 string
s(g_ceph_context
->_conf
->bluestore_max_blob_size_ssd
* 8, '0');
7993 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7994 cerr
<< "write" << std::endl
;
7995 r
= queue_transaction(store
, ch
, std::move(t
));
7998 const PerfCounters
* logger
= store
->get_perf_counters();
7999 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 8u);
8003 TEST_P(StoreTestSpecificAUSize
, ReproNoBlobMultiTest
) {
8005 if(string(GetParam()) != "bluestore")
8008 SetVal(g_conf(), "bluestore_block_db_create", "true");
8009 SetVal(g_conf(), "bluestore_block_db_size", "4294967296");
8010 SetVal(g_conf(), "bluestore_block_size", "12884901888");
8011 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
8013 g_conf().apply_changes(nullptr);
8015 StartDeferred(65536);
8019 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
8020 ghobject_t hoid2
= hoid
;
8021 hoid2
.hobj
.snap
= 1;
8023 auto ch
= store
->create_new_collection(cid
);
8025 ObjectStore::Transaction t
;
8026 t
.create_collection(cid
, 0);
8027 cerr
<< "Creating collection " << cid
<< std::endl
;
8028 r
= queue_transaction(store
, ch
, std::move(t
));
8032 bool exists
= store
->exists(ch
, hoid
);
8033 ASSERT_TRUE(!exists
);
8035 ObjectStore::Transaction t
;
8037 cerr
<< "Creating object " << hoid
<< std::endl
;
8038 r
= queue_transaction(store
, ch
, std::move(t
));
8041 exists
= store
->exists(ch
, hoid
);
8042 ASSERT_EQ(true, exists
);
8047 const int size
= 0x100;
8049 memset(ap
.c_str(), 'a', size
);
8052 uint64_t blob_size
= 524288;
8054 for (i
= 0; i
<= 512; i
++) {
8055 offs
= 0 + i
* size
;
8056 ObjectStore::Transaction t
;
8057 ghobject_t hoid2
= hoid
;
8058 hoid2
.hobj
.snap
= i
+ 1;
8059 while (offs
< 128 * 1024 * 1024) {
8061 t
.write(cid
, hoid
, offs
, ap
.length(), bl
);
8063 total
+= ap
.length();
8065 t
.clone(cid
, hoid
, hoid2
);
8066 r
= queue_transaction(store
, ch
, std::move(t
));
8069 cerr
<< "Total written = " << total
<< std::endl
;
8072 cerr
<< "Finalizing" << std::endl
;
8073 const PerfCounters
* logger
= store
->get_perf_counters();
8074 ASSERT_GE(logger
->get(l_bluestore_gc_merged
), 1024*1024*1024);
8078 void doManySetAttr(ObjectStore
* store
,
8079 std::function
<void(ObjectStore
*)> do_check_fn
)
8081 MixedGenerator
gen(447);
8082 gen_type
rng(time(NULL
));
8083 coll_t
cid(spg_t(pg_t(0, 447), shard_id_t::NO_SHARD
));
8085 SyntheticWorkloadState
test_obj(store
, &gen
, &rng
, cid
, 40 * 1024, 4 * 1024, 0);
8087 for (int i
= 0; i
< 1500; ++i
) {
8088 if (!(i
% 10)) cerr
<< "seeding object " << i
<< std::endl
;
8091 for (int i
= 0; i
< 10000; ++i
) {
8093 cerr
<< "Op " << i
<< std::endl
;
8094 test_obj
.print_internal_state();
8096 boost::uniform_int
<> true_false(0, 99);
8097 test_obj
.setattrs();
8099 test_obj
.wait_for_done();
8101 AdminSocket
* admin_socket
= g_ceph_context
->get_admin_socket();
8102 ceph_assert(admin_socket
);
8104 ceph::bufferlist in
, out
;
8107 bool b
= admin_socket
->execute_command(
8108 { "{\"prefix\": \"bluestore bluefs stats\"}" },
8111 cerr
<< "failure querying " << std::endl
;
8113 std::cout
<< std::string(out
.c_str(), out
.length()) << std::endl
;
8115 test_obj
.shutdown();
8118 TEST_P(StoreTestSpecificAUSize
, SpilloverTest
) {
8119 if (string(GetParam()) != "bluestore")
8122 SetVal(g_conf(), "bluestore_block_db_create", "true");
8123 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
8124 SetVal(g_conf(), "bluestore_volume_selection_policy", "rocksdb_original");
8126 g_conf().apply_changes(nullptr);
8128 StartDeferred(65536);
8129 doManySetAttr(store
.get(),
8130 [&](ObjectStore
* _store
) {
8132 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
8133 ceph_assert(bstore
);
8134 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
8135 //experimentally it was discovered that this case results in 400+MB spillover
8136 //using lower 300MB threshold just to be safe enough
8137 ASSERT_GE(logger
->get(l_bluefs_slow_used_bytes
), 300 * 1024 * 1024);
8143 TEST_P(StoreTestSpecificAUSize
, SpilloverFixedTest
) {
8144 if (string(GetParam()) != "bluestore")
8147 SetVal(g_conf(), "bluestore_block_db_create", "true");
8148 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
8149 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
8150 SetVal(g_conf(), "bluestore_volume_selection_reserved", "1"); // just use non-zero to enable
8152 g_conf().apply_changes(nullptr);
8154 StartDeferred(65536);
8155 doManySetAttr(store
.get(),
8156 [&](ObjectStore
* _store
) {
8158 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
8159 ceph_assert(bstore
);
8160 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
8161 ASSERT_EQ(0, logger
->get(l_bluefs_slow_used_bytes
));
8166 TEST_P(StoreTestSpecificAUSize
, SpilloverFixed2Test
) {
8167 if (string(GetParam()) != "bluestore")
8170 SetVal(g_conf(), "bluestore_block_db_create", "true");
8171 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
8172 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
8173 //default 2.0 factor results in too high threshold, using less value
8174 // that results in less but still present spillover.
8175 SetVal(g_conf(), "bluestore_volume_selection_reserved_factor", "0.5");
8177 g_conf().apply_changes(nullptr);
8179 StartDeferred(65536);
8180 doManySetAttr(store
.get(),
8181 [&](ObjectStore
* _store
) {
8183 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
8184 ceph_assert(bstore
);
8185 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
8186 ASSERT_LE(logger
->get(l_bluefs_slow_used_bytes
), 300 * 1024 * 1024); // see SpilloverTest for 300MB choice rationale
8191 #endif // WITH_BLUESTORE
8193 int main(int argc
, char **argv
) {
8194 vector
<const char*> args
;
8195 argv_to_vec(argc
, (const char **)argv
, args
);
8197 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
8198 CODE_ENVIRONMENT_UTILITY
,
8199 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
8200 common_init_finish(g_ceph_context
);
8202 // make sure we can adjust any config settings
8203 g_ceph_context
->_conf
._clear_safe_to_start_threads();
8205 g_ceph_context
->_conf
.set_val_or_die("osd_journal_size", "400");
8206 g_ceph_context
->_conf
.set_val_or_die("filestore_index_retry_probability", "0.5");
8207 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_timeout", "1000");
8208 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_suicide_timeout", "10000");
8209 //g_ceph_context->_conf.set_val_or_die("filestore_fiemap", "true");
8210 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mkfs", "false");
8211 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mount", "false");
8212 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_umount", "false");
8213 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_misc", "true");
8214 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_small_allocations", "4");
8215 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_freelist", "true");
8216 g_ceph_context
->_conf
.set_val_or_die("bluestore_clone_cow", "true");
8217 g_ceph_context
->_conf
.set_val_or_die("bluestore_max_alloc_size", "196608");
8219 // set small cache sizes so we see trimming during Synthetic tests
8220 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_hdd", "4000000");
8221 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_ssd", "4000000");
8223 // very short *_max prealloc so that we fall back to async submits
8224 g_ceph_context
->_conf
.set_val_or_die("bluestore_blobid_prealloc", "10");
8225 g_ceph_context
->_conf
.set_val_or_die("bluestore_nid_prealloc", "10");
8226 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_randomize_serial_transaction",
8229 g_ceph_context
->_conf
.set_val_or_die("bdev_debug_aio", "true");
8231 // specify device size
8232 g_ceph_context
->_conf
.set_val_or_die("bluestore_block_size",
8233 stringify(DEF_STORE_TEST_BLOCKDEV_SIZE
));
8235 g_ceph_context
->_conf
.set_val_or_die(
8236 "enable_experimental_unrecoverable_data_corrupting_features", "*");
8237 g_ceph_context
->_conf
.apply_changes(nullptr);
8239 ::testing::InitGoogleTest(&argc
, argv
);
8240 return RUN_ALL_TESTS();
8245 * compile-command: "cd ../.. ; make ceph_test_objectstore &&
8246 * ./ceph_test_objectstore \
8247 * --gtest_filter=*.collect_metadata* --log-to-stderr=true --debug-filestore=20