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
, ReproBug41901Test
) {
1319 if(string(GetParam()) != "bluestore")
1321 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
1322 g_conf().apply_changes(nullptr);
1323 StartDeferred(65536);
1327 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1328 const PerfCounters
* logger
= store
->get_perf_counters();
1329 auto ch
= store
->create_new_collection(cid
);
1331 ObjectStore::Transaction t
;
1332 t
.create_collection(cid
, 0);
1333 cerr
<< "Creating collection " << cid
<< std::endl
;
1334 r
= queue_transaction(store
, ch
, std::move(t
));
1338 bool exists
= store
->exists(ch
, hoid
);
1339 ASSERT_TRUE(!exists
);
1341 ObjectStore::Transaction t
;
1343 cerr
<< "Creating object " << hoid
<< std::endl
;
1344 r
= queue_transaction(store
, ch
, std::move(t
));
1347 exists
= store
->exists(ch
, hoid
);
1348 ASSERT_EQ(true, exists
);
1351 ObjectStore::Transaction t
;
1352 bufferlist bl
, orig
;
1353 string
s(4096, 'a');
1355 t
.write(cid
, hoid
, 0x11000, bl
.length(), bl
);
1356 cerr
<< "write1" << std::endl
;
1357 r
= queue_transaction(store
, ch
, std::move(t
));
1361 ObjectStore::Transaction t
;
1362 bufferlist bl
, orig
;
1363 string
s(4096 * 3, 'a');
1365 t
.write(cid
, hoid
, 0x15000, bl
.length(), bl
);
1366 cerr
<< "write2" << std::endl
;
1367 r
= queue_transaction(store
, ch
, std::move(t
));
1370 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 2u);
1371 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 1u);
1374 ObjectStore::Transaction t
;
1375 bufferlist bl
, orig
;
1376 string
s(4096 * 2, 'a');
1378 t
.write(cid
, hoid
, 0xe000, bl
.length(), bl
);
1379 cerr
<< "write3" << std::endl
;
1380 r
= queue_transaction(store
, ch
, std::move(t
));
1383 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 3u);
1384 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 2u);
1388 ObjectStore::Transaction t
;
1389 bufferlist bl
, orig
;
1390 string
s(4096, 'a');
1392 t
.write(cid
, hoid
, 0xf000, bl
.length(), bl
);
1393 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1394 cerr
<< "write3" << std::endl
;
1395 r
= queue_transaction(store
, ch
, std::move(t
));
1398 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 5u);
1399 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 2u);
1401 ObjectStore::Transaction t
;
1402 t
.remove(cid
, hoid
);
1403 t
.remove_collection(cid
);
1404 cerr
<< "Cleaning" << std::endl
;
1405 r
= queue_transaction(store
, ch
, std::move(t
));
1411 TEST_P(StoreTestSpecificAUSize
, BluestoreStatFSTest
) {
1412 if(string(GetParam()) != "bluestore")
1414 StartDeferred(65536);
1415 SetVal(g_conf(), "bluestore_compression_mode", "force");
1416 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
1417 // just a big number to disble gc
1418 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "100000");
1419 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
1420 g_conf().apply_changes(nullptr);
1424 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
1425 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
1430 ghobject_t hoid2
= hoid
;
1431 hoid2
.hobj
.snap
= 1;
1433 auto ch
= store
->open_collection(cid
);
1436 auto ch
= store
->create_new_collection(cid
);
1438 ObjectStore::Transaction t
;
1439 t
.create_collection(cid
, 0);
1440 cerr
<< "Creating collection " << cid
<< std::endl
;
1441 r
= queue_transaction(store
, ch
, std::move(t
));
1445 bool exists
= store
->exists(ch
, hoid
);
1446 ASSERT_TRUE(!exists
);
1448 ObjectStore::Transaction t
;
1450 cerr
<< "Creating object " << hoid
<< std::endl
;
1451 r
= queue_transaction(store
, ch
, std::move(t
));
1454 exists
= store
->exists(ch
, hoid
);
1455 ASSERT_EQ(true, exists
);
1458 struct store_statfs_t statfs
;
1459 int r
= store
->statfs(&statfs
);
1461 ASSERT_EQ( 0u, statfs
.allocated
);
1462 ASSERT_EQ( 0u, statfs
.data_stored
);
1463 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
1464 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
1466 struct store_statfs_t statfs_pool
;
1468 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1470 ASSERT_EQ( 0u, statfs_pool
.allocated
);
1471 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
1475 EXPECT_EQ(store
->umount(), 0);
1476 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1477 EXPECT_EQ(store
->mount(), 0);
1478 ch
= store
->open_collection(cid
);
1481 ObjectStore::Transaction t
;
1484 t
.write(cid
, hoid
, 0, 5, bl
);
1485 cerr
<< "Append 5 bytes" << std::endl
;
1486 r
= queue_transaction(store
, ch
, std::move(t
));
1489 struct store_statfs_t statfs
;
1490 int r
= store
->statfs(&statfs
);
1492 ASSERT_EQ(5, statfs
.data_stored
);
1493 ASSERT_EQ(0x10000, statfs
.allocated
);
1494 ASSERT_EQ(0, statfs
.data_compressed
);
1495 ASSERT_EQ(0, statfs
.data_compressed_original
);
1496 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1498 struct store_statfs_t statfs_pool
;
1500 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1502 ASSERT_EQ(5, statfs_pool
.data_stored
);
1503 ASSERT_EQ(0x10000, statfs_pool
.allocated
);
1504 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1505 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1506 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1508 // accessing unknown pool
1509 r
= store
->pool_statfs(poolid
+ 1, &statfs_pool
, &per_pool_omap
);
1511 ASSERT_EQ(0, statfs_pool
.data_stored
);
1512 ASSERT_EQ(0, statfs_pool
.allocated
);
1513 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1514 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1515 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1519 EXPECT_EQ(store
->umount(), 0);
1520 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1521 EXPECT_EQ(store
->mount(), 0);
1522 ch
= store
->open_collection(cid
);
1525 ObjectStore::Transaction t
;
1526 std::string
s(0x30000, 'a');
1529 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1530 cerr
<< "Append 0x30000 compressible bytes" << std::endl
;
1531 r
= queue_transaction(store
, ch
, std::move(t
));
1534 struct store_statfs_t statfs
;
1535 int r
= store
->statfs(&statfs
);
1537 ASSERT_EQ(0x30005, statfs
.data_stored
);
1538 ASSERT_EQ(0x30000, statfs
.allocated
);
1539 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1540 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1541 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1543 struct store_statfs_t statfs_pool
;
1545 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1547 ASSERT_EQ(0x30005, statfs_pool
.data_stored
);
1548 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1549 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1550 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1551 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1554 EXPECT_EQ(store
->umount(), 0);
1555 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1556 EXPECT_EQ(store
->mount(), 0);
1557 ch
= store
->open_collection(cid
);
1560 ObjectStore::Transaction t
;
1561 t
.zero(cid
, hoid
, 1, 3);
1562 t
.zero(cid
, hoid
, 0x20000, 9);
1563 cerr
<< "Punch hole at 1~3, 0x20000~9" << std::endl
;
1564 r
= queue_transaction(store
, ch
, std::move(t
));
1567 struct store_statfs_t statfs
;
1568 int r
= store
->statfs(&statfs
);
1570 ASSERT_EQ(0x30005 - 3 - 9, statfs
.data_stored
);
1571 ASSERT_EQ(0x30000, statfs
.allocated
);
1572 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1573 ASSERT_EQ(0x20000 - 9, statfs
.data_compressed_original
);
1574 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1576 struct store_statfs_t statfs_pool
;
1578 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1580 ASSERT_EQ(0x30005 - 3 - 9, statfs_pool
.data_stored
);
1581 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1582 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1583 ASSERT_EQ(0x20000 - 9, statfs_pool
.data_compressed_original
);
1584 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1587 EXPECT_EQ(store
->umount(), 0);
1588 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1589 EXPECT_EQ(store
->mount(), 0);
1590 ch
= store
->open_collection(cid
);
1593 ObjectStore::Transaction t
;
1594 std::string
s(0x1000, 'b');
1597 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
1598 t
.write(cid
, hoid
, 0x10001, bl
.length(), bl
);
1599 cerr
<< "Overwrite first and second(compressible) extents" << std::endl
;
1600 r
= queue_transaction(store
, ch
, std::move(t
));
1603 struct store_statfs_t statfs
;
1604 int r
= store
->statfs(&statfs
);
1606 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs
.data_stored
);
1607 ASSERT_EQ(0x40000, statfs
.allocated
);
1608 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1609 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs
.data_compressed_original
);
1610 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1612 struct store_statfs_t statfs_pool
;
1614 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1616 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs_pool
.data_stored
);
1617 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1618 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1619 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs_pool
.data_compressed_original
);
1620 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1623 EXPECT_EQ(store
->umount(), 0);
1624 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1625 EXPECT_EQ(store
->mount(), 0);
1626 ch
= store
->open_collection(cid
);
1629 ObjectStore::Transaction t
;
1630 std::string
s(0x10000, 'c');
1633 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1634 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
1635 t
.write(cid
, hoid
, 0x30000, bl
.length(), bl
);
1636 cerr
<< "Overwrite compressed extent with 3 uncompressible ones" << std::endl
;
1637 r
= queue_transaction(store
, ch
, std::move(t
));
1640 struct store_statfs_t statfs
;
1641 int r
= store
->statfs(&statfs
);
1643 ASSERT_EQ(0x30000 + 0x1001, statfs
.data_stored
);
1644 ASSERT_EQ(0x40000, statfs
.allocated
);
1645 ASSERT_LE(statfs
.data_compressed
, 0);
1646 ASSERT_EQ(0, statfs
.data_compressed_original
);
1647 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1649 struct store_statfs_t statfs_pool
;
1651 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1653 ASSERT_EQ(0x30000 + 0x1001, statfs_pool
.data_stored
);
1654 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1655 ASSERT_LE(statfs_pool
.data_compressed
, 0);
1656 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1657 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1660 EXPECT_EQ(store
->umount(), 0);
1661 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1662 EXPECT_EQ(store
->mount(), 0);
1663 ch
= store
->open_collection(cid
);
1666 ObjectStore::Transaction t
;
1667 t
.zero(cid
, hoid
, 0, 0x40000);
1668 cerr
<< "Zero object" << std::endl
;
1669 r
= queue_transaction(store
, ch
, std::move(t
));
1671 struct store_statfs_t statfs
;
1672 int r
= store
->statfs(&statfs
);
1674 ASSERT_EQ(0u, statfs
.allocated
);
1675 ASSERT_EQ(0u, statfs
.data_stored
);
1676 ASSERT_EQ(0u, statfs
.data_compressed_original
);
1677 ASSERT_EQ(0u, statfs
.data_compressed
);
1678 ASSERT_EQ(0u, statfs
.data_compressed_allocated
);
1680 struct store_statfs_t statfs_pool
;
1682 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1684 ASSERT_EQ(0u, statfs_pool
.allocated
);
1685 ASSERT_EQ(0u, statfs_pool
.data_stored
);
1686 ASSERT_EQ(0u, statfs_pool
.data_compressed_original
);
1687 ASSERT_EQ(0u, statfs_pool
.data_compressed
);
1688 ASSERT_EQ(0u, statfs_pool
.data_compressed_allocated
);
1691 EXPECT_EQ(store
->umount(), 0);
1692 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1693 EXPECT_EQ(store
->mount(), 0);
1694 ch
= store
->open_collection(cid
);
1697 ObjectStore::Transaction t
;
1698 std::string
s(0x10000, 'c');
1703 bl
.append(s
.substr(0, 0x10000-2));
1704 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1705 cerr
<< "Yet another compressible write" << std::endl
;
1706 r
= queue_transaction(store
, ch
, std::move(t
));
1708 struct store_statfs_t statfs
;
1709 r
= store
->statfs(&statfs
);
1711 ASSERT_EQ(0x40000 - 2, statfs
.data_stored
);
1712 ASSERT_EQ(0x30000, statfs
.allocated
);
1713 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1714 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1715 ASSERT_EQ(0x10000, statfs
.data_compressed_allocated
);
1717 struct store_statfs_t statfs_pool
;
1719 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1721 ASSERT_EQ(0x40000 - 2, statfs_pool
.data_stored
);
1722 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1723 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1724 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1725 ASSERT_EQ(0x10000, statfs_pool
.data_compressed_allocated
);
1728 EXPECT_EQ(store
->umount(), 0);
1729 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1730 EXPECT_EQ(store
->mount(), 0);
1731 ch
= store
->open_collection(cid
);
1734 struct store_statfs_t statfs
;
1735 r
= store
->statfs(&statfs
);
1738 struct store_statfs_t statfs_pool
;
1740 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1743 ObjectStore::Transaction t
;
1744 t
.clone(cid
, hoid
, hoid2
);
1745 cerr
<< "Clone compressed objecte" << std::endl
;
1746 r
= queue_transaction(store
, ch
, std::move(t
));
1748 struct store_statfs_t statfs2
;
1749 r
= store
->statfs(&statfs2
);
1751 ASSERT_GT(statfs2
.data_stored
, statfs
.data_stored
);
1752 ASSERT_EQ(statfs2
.allocated
, statfs
.allocated
);
1753 ASSERT_GT(statfs2
.data_compressed
, statfs
.data_compressed
);
1754 ASSERT_GT(statfs2
.data_compressed_original
, statfs
.data_compressed_original
);
1755 ASSERT_EQ(statfs2
.data_compressed_allocated
, statfs
.data_compressed_allocated
);
1757 struct store_statfs_t statfs2_pool
;
1758 r
= store
->pool_statfs(poolid
, &statfs2_pool
, &per_pool_omap
);
1760 ASSERT_GT(statfs2_pool
.data_stored
, statfs_pool
.data_stored
);
1761 ASSERT_EQ(statfs2_pool
.allocated
, statfs_pool
.allocated
);
1762 ASSERT_GT(statfs2_pool
.data_compressed
, statfs_pool
.data_compressed
);
1763 ASSERT_GT(statfs2_pool
.data_compressed_original
,
1764 statfs_pool
.data_compressed_original
);
1765 ASSERT_EQ(statfs2_pool
.data_compressed_allocated
,
1766 statfs_pool
.data_compressed_allocated
);
1771 auto poolid2
= poolid
+ 1;
1772 coll_t cid2
= coll_t(spg_t(pg_t(20, poolid2
), shard_id_t::NO_SHARD
));
1773 ghobject_t
hoid(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
1778 auto ch
= store
->create_new_collection(cid2
);
1782 struct store_statfs_t statfs1_pool
;
1784 int r
= store
->pool_statfs(poolid
, &statfs1_pool
, &per_pool_omap
);
1787 cerr
<< "Creating second collection " << cid2
<< std::endl
;
1788 ObjectStore::Transaction t
;
1789 t
.create_collection(cid2
, 0);
1790 r
= queue_transaction(store
, ch
, std::move(t
));
1793 t
= ObjectStore::Transaction();
1796 t
.write(cid2
, hoid
, 0, 5, bl
);
1797 r
= queue_transaction(store
, ch
, std::move(t
));
1800 struct store_statfs_t statfs2_pool
;
1801 r
= store
->pool_statfs(poolid2
, &statfs2_pool
, &per_pool_omap
);
1803 ASSERT_EQ(5, statfs2_pool
.data_stored
);
1804 ASSERT_EQ(0x10000, statfs2_pool
.allocated
);
1805 ASSERT_EQ(0, statfs2_pool
.data_compressed
);
1806 ASSERT_EQ(0, statfs2_pool
.data_compressed_original
);
1807 ASSERT_EQ(0, statfs2_pool
.data_compressed_allocated
);
1809 struct store_statfs_t statfs1_pool_again
;
1810 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
, &per_pool_omap
);
1812 // adjust 'available' since it has changed
1813 statfs1_pool_again
.available
= statfs1_pool
.available
;
1814 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
1816 t
= ObjectStore::Transaction();
1817 t
.remove(cid2
, hoid
);
1818 t
.remove_collection(cid2
);
1819 cerr
<< "Cleaning" << std::endl
;
1820 r
= queue_transaction(store
, ch
, std::move(t
));
1826 // verify ops on temporary object
1828 auto poolid3
= poolid
+ 2;
1829 coll_t cid3
= coll_t(spg_t(pg_t(20, poolid3
), shard_id_t::NO_SHARD
));
1830 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
),
1835 ghobject_t hoid3_temp
;
1836 hoid3_temp
.hobj
= hoid3
.hobj
.make_temp_hobject("Object 3 temp");
1837 auto ch3
= store
->create_new_collection(cid3
);
1839 struct store_statfs_t statfs1_pool
;
1841 int r
= store
->pool_statfs(poolid
, &statfs1_pool
, &per_pool_omap
);
1844 cerr
<< "Creating third collection " << cid3
<< std::endl
;
1845 ObjectStore::Transaction t
;
1846 t
.create_collection(cid3
, 0);
1847 r
= queue_transaction(store
, ch3
, std::move(t
));
1850 t
= ObjectStore::Transaction();
1853 t
.write(cid3
, hoid3_temp
, 0, 5, bl
);
1854 r
= queue_transaction(store
, ch3
, std::move(t
));
1857 struct store_statfs_t statfs3_pool
;
1858 r
= store
->pool_statfs(poolid3
, &statfs3_pool
, &per_pool_omap
);
1860 ASSERT_EQ(5, statfs3_pool
.data_stored
);
1861 ASSERT_EQ(0x10000, statfs3_pool
.allocated
);
1862 ASSERT_EQ(0, statfs3_pool
.data_compressed
);
1863 ASSERT_EQ(0, statfs3_pool
.data_compressed_original
);
1864 ASSERT_EQ(0, statfs3_pool
.data_compressed_allocated
);
1866 struct store_statfs_t statfs1_pool_again
;
1867 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
, &per_pool_omap
);
1869 // adjust 'available' since it has changed
1870 statfs1_pool_again
.available
= statfs1_pool
.available
;
1871 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
1876 EXPECT_EQ(store
->umount(), 0);
1877 EXPECT_EQ(store
->mount(), 0);
1878 ch
= store
->open_collection(cid
);
1879 ch3
= store
->open_collection(cid3
);
1881 t
= ObjectStore::Transaction();
1882 t
.collection_move_rename(
1885 r
= queue_transaction(store
, ch3
, std::move(t
));
1888 struct store_statfs_t statfs3_pool_again
;
1889 r
= store
->pool_statfs(poolid3
, &statfs3_pool_again
, &per_pool_omap
);
1891 ASSERT_EQ(statfs3_pool_again
, statfs3_pool
);
1896 EXPECT_EQ(store
->umount(), 0);
1897 EXPECT_EQ(store
->mount(), 0);
1898 ch
= store
->open_collection(cid
);
1899 ch3
= store
->open_collection(cid3
);
1901 t
= ObjectStore::Transaction();
1902 t
.remove(cid3
, hoid3
);
1903 t
.remove_collection(cid3
);
1904 cerr
<< "Cleaning" << std::endl
;
1905 r
= queue_transaction(store
, ch3
, std::move(t
));
1911 ObjectStore::Transaction t
;
1912 t
.remove(cid
, hoid
);
1913 t
.remove(cid
, hoid2
);
1914 t
.remove_collection(cid
);
1915 cerr
<< "Cleaning" << std::endl
;
1916 r
= queue_transaction(store
, ch
, std::move(t
));
1919 struct store_statfs_t statfs
;
1920 r
= store
->statfs(&statfs
);
1922 ASSERT_EQ( 0u, statfs
.allocated
);
1923 ASSERT_EQ( 0u, statfs
.data_stored
);
1924 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
1925 ASSERT_EQ( 0u, statfs
.data_compressed
);
1926 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
1928 struct store_statfs_t statfs_pool
;
1930 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1932 ASSERT_EQ( 0u, statfs_pool
.allocated
);
1933 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
1934 ASSERT_EQ( 0u, statfs_pool
.data_compressed_original
);
1935 ASSERT_EQ( 0u, statfs_pool
.data_compressed
);
1936 ASSERT_EQ( 0u, statfs_pool
.data_compressed_allocated
);
1940 TEST_P(StoreTestSpecificAUSize
, BluestoreFragmentedBlobTest
) {
1941 if(string(GetParam()) != "bluestore")
1943 StartDeferred(0x10000);
1947 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1948 auto ch
= store
->create_new_collection(cid
);
1950 ObjectStore::Transaction t
;
1951 t
.create_collection(cid
, 0);
1952 cerr
<< "Creating collection " << cid
<< std::endl
;
1953 r
= queue_transaction(store
, ch
, std::move(t
));
1957 bool exists
= store
->exists(ch
, hoid
);
1958 ASSERT_TRUE(!exists
);
1960 ObjectStore::Transaction t
;
1962 cerr
<< "Creating object " << hoid
<< std::endl
;
1963 r
= queue_transaction(store
, ch
, std::move(t
));
1966 exists
= store
->exists(ch
, hoid
);
1967 ASSERT_EQ(true, exists
);
1970 struct store_statfs_t statfs
;
1971 int r
= store
->statfs(&statfs
);
1973 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
1974 ASSERT_EQ(0u, statfs
.allocated
);
1975 ASSERT_EQ(0u, statfs
.data_stored
);
1976 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
1979 data
.resize(0x10000 * 3);
1981 ObjectStore::Transaction t
;
1982 for(size_t i
= 0;i
< data
.size(); i
++)
1983 data
[i
] = i
/ 256 + 1;
1984 bufferlist bl
, newdata
;
1986 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1987 t
.zero(cid
, hoid
, 0x10000, 0x10000);
1988 cerr
<< "Append 3*0x10000 bytes and punch a hole 0x10000~10000" << std::endl
;
1989 r
= queue_transaction(store
, ch
, std::move(t
));
1992 struct store_statfs_t statfs
;
1993 int r
= store
->statfs(&statfs
);
1995 ASSERT_EQ(0x20000, statfs
.data_stored
);
1996 ASSERT_EQ(0x20000, statfs
.allocated
);
1998 r
= store
->read(ch
, hoid
, 0, data
.size(), newdata
);
1999 ASSERT_EQ(r
, (int)data
.size());
2001 bufferlist expected
;
2002 expected
.append(data
.substr(0, 0x10000));
2003 expected
.append(string(0x10000, 0));
2004 expected
.append(data
.substr(0x20000, 0x10000));
2005 ASSERT_TRUE(bl_eq(expected
, newdata
));
2009 r
= store
->read(ch
, hoid
, 1, data
.size()-2, newdata
);
2010 ASSERT_EQ(r
, (int)data
.size()-2);
2012 bufferlist expected
;
2013 expected
.append(data
.substr(1, 0x10000-1));
2014 expected
.append(string(0x10000, 0));
2015 expected
.append(data
.substr(0x20000, 0x10000 - 1));
2016 ASSERT_TRUE(bl_eq(expected
, newdata
));
2022 EXPECT_EQ(store
->umount(), 0);
2023 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2024 EXPECT_EQ(store
->mount(), 0);
2025 ch
= store
->open_collection(cid
);
2028 ObjectStore::Transaction t
;
2029 std::string
data2(3, 'b');
2030 bufferlist bl
, newdata
;
2032 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
2033 cerr
<< "Write 3 bytes after the hole" << std::endl
;
2034 r
= queue_transaction(store
, ch
, std::move(t
));
2037 struct store_statfs_t statfs
;
2038 int r
= store
->statfs(&statfs
);
2040 ASSERT_EQ(0x20000, statfs
.allocated
);
2041 ASSERT_EQ(0x20000, statfs
.data_stored
);
2043 r
= store
->read(ch
, hoid
, 0x20000-1, 21, newdata
);
2044 ASSERT_EQ(r
, (int)21);
2046 bufferlist expected
;
2047 expected
.append(string(0x1, 0));
2048 expected
.append(string(data2
));
2049 expected
.append(data
.substr(0x20003, 21-4));
2050 ASSERT_TRUE(bl_eq(expected
, newdata
));
2056 EXPECT_EQ(store
->umount(), 0);
2057 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2058 EXPECT_EQ(store
->mount(), 0);
2059 ch
= store
->open_collection(cid
);
2062 ObjectStore::Transaction t
;
2063 std::string
data2(3, 'a');
2064 bufferlist bl
, newdata
;
2066 t
.write(cid
, hoid
, 0x10000+1, bl
.length(), bl
);
2067 cerr
<< "Write 3 bytes to the hole" << std::endl
;
2068 r
= queue_transaction(store
, ch
, std::move(t
));
2071 struct store_statfs_t statfs
;
2072 int r
= store
->statfs(&statfs
);
2074 ASSERT_EQ(0x30000, statfs
.allocated
);
2075 ASSERT_EQ(0x20003, statfs
.data_stored
);
2077 r
= store
->read(ch
, hoid
, 0x10000-1, 0x10000+22, newdata
);
2078 ASSERT_EQ(r
, (int)0x10000+22);
2080 bufferlist expected
;
2081 expected
.append(data
.substr(0x10000-1, 1));
2082 expected
.append(string(0x1, 0));
2083 expected
.append(data2
);
2084 expected
.append(string(0x10000-4, 0));
2085 expected
.append(string(0x3, 'b'));
2086 expected
.append(data
.substr(0x20004, 21-3));
2087 ASSERT_TRUE(bl_eq(expected
, newdata
));
2092 ObjectStore::Transaction t
;
2093 bufferlist bl
, newdata
;
2094 bl
.append(string(0x30000, 'c'));
2095 t
.write(cid
, hoid
, 0, 0x30000, bl
);
2096 t
.zero(cid
, hoid
, 0, 0x10000);
2097 t
.zero(cid
, hoid
, 0x20000, 0x10000);
2098 cerr
<< "Rewrite an object and create two holes at the beginning and the end" << std::endl
;
2099 r
= queue_transaction(store
, ch
, std::move(t
));
2102 struct store_statfs_t statfs
;
2103 int r
= store
->statfs(&statfs
);
2105 ASSERT_EQ(0x10000, statfs
.allocated
);
2106 ASSERT_EQ(0x10000, statfs
.data_stored
);
2108 r
= store
->read(ch
, hoid
, 0, 0x30000, newdata
);
2109 ASSERT_EQ(r
, (int)0x30000);
2111 bufferlist expected
;
2112 expected
.append(string(0x10000, 0));
2113 expected
.append(string(0x10000, 'c'));
2114 expected
.append(string(0x10000, 0));
2115 ASSERT_TRUE(bl_eq(expected
, newdata
));
2122 EXPECT_EQ(store
->umount(), 0);
2123 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2124 EXPECT_EQ(store
->mount(), 0);
2125 ch
= store
->open_collection(cid
);
2128 ObjectStore::Transaction t
;
2129 t
.remove(cid
, hoid
);
2130 t
.remove_collection(cid
);
2131 cerr
<< "Cleaning" << std::endl
;
2132 r
= queue_transaction(store
, ch
, std::move(t
));
2135 struct store_statfs_t statfs
;
2136 r
= store
->statfs(&statfs
);
2138 ASSERT_EQ( 0u, statfs
.allocated
);
2139 ASSERT_EQ( 0u, statfs
.data_stored
);
2140 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
2141 ASSERT_EQ( 0u, statfs
.data_compressed
);
2142 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
2147 TEST_P(StoreTest
, ManySmallWrite
) {
2150 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2151 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2152 auto ch
= store
->create_new_collection(cid
);
2154 ObjectStore::Transaction t
;
2155 t
.create_collection(cid
, 0);
2156 cerr
<< "Creating collection " << cid
<< std::endl
;
2157 r
= queue_transaction(store
, ch
, std::move(t
));
2164 for (int i
=0; i
<100; ++i
) {
2165 ObjectStore::Transaction t
;
2166 t
.write(cid
, a
, i
*4096, 4096, bl
, 0);
2167 r
= queue_transaction(store
, ch
, std::move(t
));
2170 for (int i
=0; i
<100; ++i
) {
2171 ObjectStore::Transaction t
;
2172 t
.write(cid
, b
, (rand() % 1024)*4096, 4096, bl
, 0);
2173 r
= queue_transaction(store
, ch
, std::move(t
));
2177 ObjectStore::Transaction t
;
2180 t
.remove_collection(cid
);
2181 cerr
<< "Cleaning" << std::endl
;
2182 r
= queue_transaction(store
, ch
, std::move(t
));
2187 TEST_P(StoreTest
, MultiSmallWriteSameBlock
) {
2190 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2191 auto ch
= store
->create_new_collection(cid
);
2193 ObjectStore::Transaction t
;
2194 t
.create_collection(cid
, 0);
2195 cerr
<< "Creating collection " << cid
<< std::endl
;
2196 r
= queue_transaction(store
, ch
, std::move(t
));
2202 // touch same block in both same transaction, tls, and pipelined txns
2204 ObjectStore::Transaction t
, u
;
2205 t
.write(cid
, a
, 0, 5, bl
, 0);
2206 t
.write(cid
, a
, 5, 5, bl
, 0);
2207 t
.write(cid
, a
, 4094, 5, bl
, 0);
2208 t
.write(cid
, a
, 9000, 5, bl
, 0);
2209 u
.write(cid
, a
, 10, 5, bl
, 0);
2210 u
.write(cid
, a
, 7000, 5, bl
, 0);
2211 t
.register_on_commit(&c
);
2212 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2213 store
->queue_transactions(ch
, v
);
2216 ObjectStore::Transaction t
, u
;
2217 t
.write(cid
, a
, 40, 5, bl
, 0);
2218 t
.write(cid
, a
, 45, 5, bl
, 0);
2219 t
.write(cid
, a
, 4094, 5, bl
, 0);
2220 t
.write(cid
, a
, 6000, 5, bl
, 0);
2221 u
.write(cid
, a
, 610, 5, bl
, 0);
2222 u
.write(cid
, a
, 11000, 5, bl
, 0);
2223 t
.register_on_commit(&d
);
2224 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2225 store
->queue_transactions(ch
, v
);
2231 r
= store
->read(ch
, a
, 0, 16000, bl2
);
2235 ObjectStore::Transaction t
;
2237 t
.remove_collection(cid
);
2238 cerr
<< "Cleaning" << std::endl
;
2239 r
= queue_transaction(store
, ch
, std::move(t
));
2244 TEST_P(StoreTest
, SmallSkipFront
) {
2247 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2248 auto ch
= store
->create_new_collection(cid
);
2250 ObjectStore::Transaction t
;
2251 t
.create_collection(cid
, 0);
2252 cerr
<< "Creating collection " << cid
<< std::endl
;
2253 r
= queue_transaction(store
, ch
, std::move(t
));
2257 ObjectStore::Transaction t
;
2259 t
.truncate(cid
, a
, 3000);
2260 r
= queue_transaction(store
, ch
, std::move(t
));
2266 memset(bp
.c_str(), 1, 4096);
2268 ObjectStore::Transaction t
;
2269 t
.write(cid
, a
, 4096, 4096, bl
);
2270 r
= queue_transaction(store
, ch
, std::move(t
));
2275 ASSERT_EQ(8192, store
->read(ch
, a
, 0, 8192, bl
));
2276 for (unsigned i
=0; i
<4096; ++i
)
2277 ASSERT_EQ(0, bl
[i
]);
2278 for (unsigned i
=4096; i
<8192; ++i
)
2279 ASSERT_EQ(1, bl
[i
]);
2282 ObjectStore::Transaction t
;
2284 t
.remove_collection(cid
);
2285 cerr
<< "Cleaning" << std::endl
;
2286 r
= queue_transaction(store
, ch
, std::move(t
));
2291 TEST_P(StoreTest
, AppendDeferredVsTailCache
) {
2294 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2295 auto ch
= store
->create_new_collection(cid
);
2297 ObjectStore::Transaction t
;
2298 t
.create_collection(cid
, 0);
2299 cerr
<< "Creating collection " << cid
<< std::endl
;
2300 r
= store
->queue_transaction(ch
, std::move(t
));
2303 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2304 unsigned size
= min_alloc
/ 3;
2305 bufferptr
bpa(size
);
2306 memset(bpa
.c_str(), 1, bpa
.length());
2310 ObjectStore::Transaction t
;
2311 t
.write(cid
, a
, 0, bla
.length(), bla
, 0);
2312 r
= store
->queue_transaction(ch
, std::move(t
));
2316 // force cached tail to clear ...
2319 int r
= store
->umount();
2323 ch
= store
->open_collection(cid
);
2326 bufferptr
bpb(size
);
2327 memset(bpb
.c_str(), 2, bpb
.length());
2331 ObjectStore::Transaction t
;
2332 t
.write(cid
, a
, bla
.length(), blb
.length(), blb
, 0);
2333 r
= store
->queue_transaction(ch
, std::move(t
));
2336 bufferptr
bpc(size
);
2337 memset(bpc
.c_str(), 3, bpc
.length());
2341 ObjectStore::Transaction t
;
2342 t
.write(cid
, a
, bla
.length() + blb
.length(), blc
.length(), blc
, 0);
2343 r
= store
->queue_transaction(ch
, std::move(t
));
2352 ASSERT_EQ((int)final
.length(),
2353 store
->read(ch
, a
, 0, final
.length(), actual
));
2354 ASSERT_TRUE(bl_eq(final
, actual
));
2357 ObjectStore::Transaction t
;
2359 t
.remove_collection(cid
);
2360 cerr
<< "Cleaning" << std::endl
;
2361 r
= store
->queue_transaction(ch
, std::move(t
));
2366 TEST_P(StoreTest
, AppendZeroTrailingSharedBlock
) {
2369 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2372 auto ch
= store
->create_new_collection(cid
);
2374 ObjectStore::Transaction t
;
2375 t
.create_collection(cid
, 0);
2376 cerr
<< "Creating collection " << cid
<< std::endl
;
2377 r
= store
->queue_transaction(ch
, std::move(t
));
2380 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2381 unsigned size
= min_alloc
/ 3;
2382 bufferptr
bpa(size
);
2383 memset(bpa
.c_str(), 1, bpa
.length());
2386 // make sure there is some trailing gunk in the last block
2390 bt
.append("BADBADBADBAD");
2391 ObjectStore::Transaction t
;
2392 t
.write(cid
, a
, 0, bt
.length(), bt
, 0);
2393 r
= store
->queue_transaction(ch
, std::move(t
));
2397 ObjectStore::Transaction t
;
2398 t
.truncate(cid
, a
, size
);
2399 r
= store
->queue_transaction(ch
, std::move(t
));
2405 ObjectStore::Transaction t
;
2407 r
= store
->queue_transaction(ch
, std::move(t
));
2411 // append with implicit zeroing
2412 bufferptr
bpb(size
);
2413 memset(bpb
.c_str(), 2, bpb
.length());
2417 ObjectStore::Transaction t
;
2418 t
.write(cid
, a
, min_alloc
* 3, blb
.length(), blb
, 0);
2419 r
= store
->queue_transaction(ch
, std::move(t
));
2425 zeros
.append_zero(min_alloc
* 3 - size
);
2426 final
.append(zeros
);
2430 ASSERT_EQ((int)final
.length(),
2431 store
->read(ch
, a
, 0, final
.length(), actual
));
2432 final
.hexdump(cout
);
2433 actual
.hexdump(cout
);
2434 ASSERT_TRUE(bl_eq(final
, actual
));
2437 ObjectStore::Transaction t
;
2440 t
.remove_collection(cid
);
2441 cerr
<< "Cleaning" << std::endl
;
2442 r
= store
->queue_transaction(ch
, std::move(t
));
2447 TEST_P(StoreTest
, SmallSequentialUnaligned
) {
2450 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2451 auto ch
= store
->create_new_collection(cid
);
2453 ObjectStore::Transaction t
;
2454 t
.create_collection(cid
, 0);
2455 cerr
<< "Creating collection " << cid
<< std::endl
;
2456 r
= queue_transaction(store
, ch
, std::move(t
));
2464 for (int i
=0; i
<1000; ++i
) {
2465 ObjectStore::Transaction t
;
2466 t
.write(cid
, a
, i
*len
, len
, bl
, 0);
2467 r
= queue_transaction(store
, ch
, std::move(t
));
2471 ObjectStore::Transaction t
;
2473 t
.remove_collection(cid
);
2474 cerr
<< "Cleaning" << std::endl
;
2475 r
= queue_transaction(store
, ch
, std::move(t
));
2480 TEST_P(StoreTest
, ManyBigWrite
) {
2483 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2484 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2485 auto ch
= store
->create_new_collection(cid
);
2487 ObjectStore::Transaction t
;
2488 t
.create_collection(cid
, 0);
2489 cerr
<< "Creating collection " << cid
<< std::endl
;
2490 r
= queue_transaction(store
, ch
, std::move(t
));
2494 bufferptr
bp(4 * 1048576);
2497 for (int i
=0; i
<10; ++i
) {
2498 ObjectStore::Transaction t
;
2499 t
.write(cid
, a
, i
*4*1048586, 4*1048576, bl
, 0);
2500 r
= queue_transaction(store
, ch
, std::move(t
));
2504 for (int i
=0; i
<10; ++i
) {
2505 ObjectStore::Transaction t
;
2506 t
.write(cid
, b
, (rand() % 256)*4*1048576, 4*1048576, bl
, 0);
2507 r
= queue_transaction(store
, ch
, std::move(t
));
2511 for (int i
=0; i
<10; ++i
) {
2512 ObjectStore::Transaction t
;
2513 t
.write(cid
, b
, (rand() % (256*4096))*1024, 4*1048576, bl
, 0);
2514 r
= queue_transaction(store
, ch
, std::move(t
));
2518 for (int i
=0; i
<10; ++i
) {
2519 ObjectStore::Transaction t
;
2520 t
.zero(cid
, b
, (rand() % (256*4096))*1024, 16*1048576);
2521 r
= queue_transaction(store
, ch
, std::move(t
));
2525 ObjectStore::Transaction t
;
2528 t
.remove_collection(cid
);
2529 cerr
<< "Cleaning" << std::endl
;
2530 r
= queue_transaction(store
, ch
, std::move(t
));
2535 TEST_P(StoreTest
, BigWriteBigZero
) {
2538 ghobject_t
a(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2539 auto ch
= store
->create_new_collection(cid
);
2541 ObjectStore::Transaction t
;
2542 t
.create_collection(cid
, 0);
2543 r
= queue_transaction(store
, ch
, std::move(t
));
2547 bufferptr
bp(1048576);
2548 memset(bp
.c_str(), 'b', bp
.length());
2552 memset(sp
.c_str(), 's', sp
.length());
2555 ObjectStore::Transaction t
;
2556 t
.write(cid
, a
, 0, bl
.length(), bl
);
2557 r
= queue_transaction(store
, ch
, std::move(t
));
2561 ObjectStore::Transaction t
;
2562 t
.zero(cid
, a
, bl
.length() / 4, bl
.length() / 2);
2563 r
= queue_transaction(store
, ch
, std::move(t
));
2567 ObjectStore::Transaction t
;
2568 t
.write(cid
, a
, bl
.length() / 2, s
.length(), s
);
2569 r
= queue_transaction(store
, ch
, std::move(t
));
2573 ObjectStore::Transaction t
;
2575 t
.remove_collection(cid
);
2576 r
= queue_transaction(store
, ch
, std::move(t
));
2581 TEST_P(StoreTest
, MiscFragmentTests
) {
2584 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2585 auto ch
= store
->create_new_collection(cid
);
2587 ObjectStore::Transaction t
;
2588 t
.create_collection(cid
, 0);
2589 cerr
<< "Creating collection " << cid
<< std::endl
;
2590 r
= queue_transaction(store
, ch
, std::move(t
));
2594 bufferptr
bp(524288);
2598 ObjectStore::Transaction t
;
2599 t
.write(cid
, a
, 0, 524288, bl
, 0);
2600 r
= queue_transaction(store
, ch
, std::move(t
));
2604 ObjectStore::Transaction t
;
2605 t
.write(cid
, a
, 1048576, 524288, bl
, 0);
2606 r
= queue_transaction(store
, ch
, std::move(t
));
2611 int r
= store
->read(ch
, a
, 524288 + 131072, 1024, inbl
);
2613 ASSERT_EQ(inbl
.length(), 1024u);
2614 ASSERT_TRUE(inbl
.is_zero());
2617 ObjectStore::Transaction t
;
2618 t
.write(cid
, a
, 1048576 - 4096, 524288, bl
, 0);
2619 r
= queue_transaction(store
, ch
, std::move(t
));
2623 ObjectStore::Transaction t
;
2625 t
.remove_collection(cid
);
2626 cerr
<< "Cleaning" << std::endl
;
2627 r
= queue_transaction(store
, ch
, std::move(t
));
2633 TEST_P(StoreTest
, ZeroVsObjectSize
) {
2637 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2638 auto ch
= store
->create_new_collection(cid
);
2640 ObjectStore::Transaction t
;
2641 t
.create_collection(cid
, 0);
2642 cerr
<< "Creating collection " << cid
<< std::endl
;
2643 r
= queue_transaction(store
, ch
, std::move(t
));
2649 ObjectStore::Transaction t
;
2650 t
.write(cid
, hoid
, 0, 5, a
);
2651 r
= queue_transaction(store
, ch
, std::move(t
));
2654 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2655 ASSERT_EQ(5, stat
.st_size
);
2657 ObjectStore::Transaction t
;
2658 t
.zero(cid
, hoid
, 1, 2);
2659 r
= queue_transaction(store
, ch
, std::move(t
));
2662 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2663 ASSERT_EQ(5, stat
.st_size
);
2665 ObjectStore::Transaction t
;
2666 t
.zero(cid
, hoid
, 3, 200);
2667 r
= queue_transaction(store
, ch
, std::move(t
));
2670 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2671 ASSERT_EQ(203, stat
.st_size
);
2673 ObjectStore::Transaction t
;
2674 t
.zero(cid
, hoid
, 100000, 200);
2675 r
= queue_transaction(store
, ch
, std::move(t
));
2678 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2679 ASSERT_EQ(100200, stat
.st_size
);
2682 TEST_P(StoreTest
, ZeroLengthWrite
) {
2685 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2686 auto ch
= store
->create_new_collection(cid
);
2688 ObjectStore::Transaction t
;
2689 t
.create_collection(cid
, 0);
2691 r
= queue_transaction(store
, ch
, std::move(t
));
2695 ObjectStore::Transaction t
;
2697 t
.write(cid
, hoid
, 1048576, 0, empty
);
2698 r
= queue_transaction(store
, ch
, std::move(t
));
2702 r
= store
->stat(ch
, hoid
, &stat
);
2704 ASSERT_EQ(0, stat
.st_size
);
2707 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2711 TEST_P(StoreTest
, ZeroLengthZero
) {
2714 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2715 auto ch
= store
->create_new_collection(cid
);
2717 ObjectStore::Transaction t
;
2718 t
.create_collection(cid
, 0);
2720 r
= queue_transaction(store
, ch
, std::move(t
));
2724 ObjectStore::Transaction t
;
2725 t
.zero(cid
, hoid
, 1048576, 0);
2726 r
= queue_transaction(store
, ch
, std::move(t
));
2730 r
= store
->stat(ch
, hoid
, &stat
);
2732 ASSERT_EQ(0, stat
.st_size
);
2735 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2739 TEST_P(StoreTest
, SimpleAttrTest
) {
2742 ghobject_t
hoid(hobject_t(sobject_t("attr object 1", CEPH_NOSNAP
)));
2743 bufferlist val
, val2
;
2744 val
.append("value");
2745 val
.append("value2");
2747 auto ch
= store
->open_collection(cid
);
2750 auto ch
= store
->create_new_collection(cid
);
2752 ObjectStore::Transaction t
;
2753 t
.create_collection(cid
, 0);
2754 r
= queue_transaction(store
, ch
, std::move(t
));
2759 int r
= store
->collection_empty(ch
, &empty
);
2765 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2766 ASSERT_EQ(-ENOENT
, r
);
2769 ObjectStore::Transaction t
;
2771 t
.setattr(cid
, hoid
, "foo", val
);
2772 t
.setattr(cid
, hoid
, "bar", val2
);
2773 r
= queue_transaction(store
, ch
, std::move(t
));
2778 int r
= store
->collection_empty(ch
, &empty
);
2780 ASSERT_TRUE(!empty
);
2784 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2785 ASSERT_EQ(-ENODATA
, r
);
2787 r
= store
->getattr(ch
, hoid
, "foo", bp
);
2791 ASSERT_TRUE(bl_eq(val
, bl
));
2793 map
<string
,bufferptr
> bm
;
2794 r
= store
->getattrs(ch
, hoid
, bm
);
2799 ObjectStore::Transaction t
;
2800 t
.remove(cid
, hoid
);
2801 t
.remove_collection(cid
);
2802 r
= queue_transaction(store
, ch
, std::move(t
));
2807 TEST_P(StoreTest
, SimpleListTest
) {
2809 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2810 auto ch
= store
->create_new_collection(cid
);
2812 ObjectStore::Transaction t
;
2813 t
.create_collection(cid
, 0);
2814 cerr
<< "Creating collection " << cid
<< std::endl
;
2815 r
= queue_transaction(store
, ch
, std::move(t
));
2818 set
<ghobject_t
> all
;
2820 ObjectStore::Transaction t
;
2821 for (int i
=0; i
<200; ++i
) {
2822 string
name("object_");
2823 name
+= stringify(i
);
2824 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
2825 ghobject_t::NO_GEN
, shard_id_t(1));
2829 cerr
<< "Creating object " << hoid
<< std::endl
;
2831 r
= queue_transaction(store
, ch
, std::move(t
));
2835 set
<ghobject_t
> saw
;
2836 vector
<ghobject_t
> objects
;
2837 ghobject_t next
, current
;
2838 while (!next
.is_max()) {
2839 int r
= store
->collection_list(ch
, current
, ghobject_t::get_max(),
2843 ASSERT_TRUE(sorted(objects
));
2844 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
2845 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
2847 if (saw
.count(*p
)) {
2848 cout
<< "got DUP " << *p
<< std::endl
;
2850 //cout << "got new " << *p << std::endl;
2857 ASSERT_EQ(saw
.size(), all
.size());
2858 ASSERT_EQ(saw
, all
);
2861 ObjectStore::Transaction t
;
2862 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
2864 t
.remove_collection(cid
);
2865 cerr
<< "Cleaning" << std::endl
;
2866 r
= queue_transaction(store
, ch
, std::move(t
));
2871 TEST_P(StoreTest
, ListEndTest
) {
2873 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2874 auto ch
= store
->create_new_collection(cid
);
2876 ObjectStore::Transaction t
;
2877 t
.create_collection(cid
, 0);
2878 cerr
<< "Creating collection " << cid
<< std::endl
;
2879 r
= queue_transaction(store
, ch
, std::move(t
));
2882 set
<ghobject_t
> all
;
2884 ObjectStore::Transaction t
;
2885 for (int i
=0; i
<200; ++i
) {
2886 string
name("object_");
2887 name
+= stringify(i
);
2888 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
2889 ghobject_t::NO_GEN
, shard_id_t(1));
2893 cerr
<< "Creating object " << hoid
<< std::endl
;
2895 r
= queue_transaction(store
, ch
, std::move(t
));
2899 ghobject_t
end(hobject_t(sobject_t("object_100", CEPH_NOSNAP
)),
2900 ghobject_t::NO_GEN
, shard_id_t(1));
2902 vector
<ghobject_t
> objects
;
2904 int r
= store
->collection_list(ch
, ghobject_t(), end
, 500,
2907 for (auto &p
: objects
) {
2912 ObjectStore::Transaction t
;
2913 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
2915 t
.remove_collection(cid
);
2916 cerr
<< "Cleaning" << std::endl
;
2917 r
= queue_transaction(store
, ch
, std::move(t
));
2922 TEST_P(StoreTest
, Sort
) {
2924 hobject_t
a(sobject_t("a", CEPH_NOSNAP
));
2937 ghobject_t
a(hobject_t(sobject_t("a", CEPH_NOSNAP
)));
2938 ghobject_t
b(hobject_t(sobject_t("b", CEPH_NOSNAP
)));
2950 TEST_P(StoreTest
, MultipoolListTest
) {
2953 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
2954 auto ch
= store
->create_new_collection(cid
);
2956 ObjectStore::Transaction t
;
2957 t
.create_collection(cid
, 0);
2958 cerr
<< "Creating collection " << cid
<< std::endl
;
2959 r
= queue_transaction(store
, ch
, std::move(t
));
2962 set
<ghobject_t
> all
, saw
;
2964 ObjectStore::Transaction t
;
2965 for (int i
=0; i
<200; ++i
) {
2966 string
name("object_");
2967 name
+= stringify(i
);
2968 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)));
2970 hoid
.hobj
.pool
= -2 - poolid
;
2972 hoid
.hobj
.pool
= poolid
;
2975 cerr
<< "Creating object " << hoid
<< std::endl
;
2977 r
= queue_transaction(store
, ch
, std::move(t
));
2981 vector
<ghobject_t
> objects
;
2982 ghobject_t next
, current
;
2983 while (!next
.is_max()) {
2984 int r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 50,
2987 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
2988 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
2995 ASSERT_EQ(saw
, all
);
2998 ObjectStore::Transaction t
;
2999 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
3001 t
.remove_collection(cid
);
3002 cerr
<< "Cleaning" << std::endl
;
3003 r
= queue_transaction(store
, ch
, std::move(t
));
3008 TEST_P(StoreTest
, SimpleCloneTest
) {
3011 auto ch
= store
->create_new_collection(cid
);
3013 ObjectStore::Transaction t
;
3014 t
.create_collection(cid
, 0);
3015 cerr
<< "Creating collection " << cid
<< std::endl
;
3016 r
= queue_transaction(store
, ch
, std::move(t
));
3019 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
3020 "key", 123, -1, ""));
3021 bufferlist small
, large
, xlarge
, newdata
, attr
;
3022 small
.append("small");
3023 large
.append("large");
3024 xlarge
.append("xlarge");
3026 ObjectStore::Transaction t
;
3028 t
.setattr(cid
, hoid
, "attr1", small
);
3029 t
.setattr(cid
, hoid
, "attr2", large
);
3030 t
.setattr(cid
, hoid
, "attr3", xlarge
);
3031 t
.write(cid
, hoid
, 0, small
.length(), small
);
3032 t
.write(cid
, hoid
, 10, small
.length(), small
);
3033 cerr
<< "Creating object and set attr " << hoid
<< std::endl
;
3034 r
= queue_transaction(store
, ch
, std::move(t
));
3038 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
3039 "key", 123, -1, ""));
3040 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
)));
3042 ObjectStore::Transaction t
;
3043 t
.clone(cid
, hoid
, hoid2
);
3044 t
.setattr(cid
, hoid2
, "attr2", small
);
3045 t
.rmattr(cid
, hoid2
, "attr1");
3046 t
.write(cid
, hoid
, 10, large
.length(), large
);
3047 t
.setattr(cid
, hoid
, "attr1", large
);
3048 t
.setattr(cid
, hoid
, "attr2", small
);
3049 cerr
<< "Clone object and rm attr" << std::endl
;
3050 r
= queue_transaction(store
, ch
, std::move(t
));
3053 r
= store
->read(ch
, hoid
, 10, 5, newdata
);
3055 ASSERT_TRUE(bl_eq(large
, newdata
));
3058 r
= store
->read(ch
, hoid
, 0, 5, newdata
);
3060 ASSERT_TRUE(bl_eq(small
, newdata
));
3063 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
3065 ASSERT_TRUE(bl_eq(small
, newdata
));
3067 r
= store
->getattr(ch
, hoid2
, "attr2", attr
);
3069 ASSERT_TRUE(bl_eq(small
, attr
));
3072 r
= store
->getattr(ch
, hoid2
, "attr3", attr
);
3074 ASSERT_TRUE(bl_eq(xlarge
, attr
));
3077 r
= store
->getattr(ch
, hoid
, "attr1", attr
);
3079 ASSERT_TRUE(bl_eq(large
, attr
));
3082 ObjectStore::Transaction t
;
3083 t
.remove(cid
, hoid
);
3084 t
.remove(cid
, hoid2
);
3085 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3090 memset(p
.c_str(), 1, p
.length());
3094 ObjectStore::Transaction t
;
3095 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3096 t
.clone(cid
, hoid
, hoid2
);
3098 memset(a
.c_str(), 2, a
.length());
3102 t
.write(cid
, hoid
, pl
.length(), a
.length(), al
);
3103 r
= queue_transaction(store
, ch
, std::move(t
));
3106 ASSERT_EQ((int)final
.length(),
3107 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3108 ASSERT_TRUE(bl_eq(rl
, final
));
3111 ObjectStore::Transaction t
;
3112 t
.remove(cid
, hoid
);
3113 t
.remove(cid
, hoid2
);
3114 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3119 memset(p
.c_str(), 111, p
.length());
3123 ObjectStore::Transaction t
;
3124 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3125 t
.clone(cid
, hoid
, hoid2
);
3130 memset(a
.c_str(), 112, a
.length());
3134 t
.write(cid
, hoid
, pl
.length() + z
.length(), a
.length(), al
);
3135 r
= queue_transaction(store
, ch
, std::move(t
));
3138 ASSERT_EQ((int)final
.length(),
3139 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3140 ASSERT_TRUE(bl_eq(rl
, final
));
3143 ObjectStore::Transaction t
;
3144 t
.remove(cid
, hoid
);
3145 t
.remove(cid
, hoid2
);
3146 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3151 memset(p
.c_str(), 5, p
.length());
3155 ObjectStore::Transaction t
;
3156 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3157 t
.clone(cid
, hoid
, hoid2
);
3162 memset(a
.c_str(), 6, a
.length());
3166 t
.write(cid
, hoid
, 17000, a
.length(), al
);
3167 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3169 ASSERT_EQ((int)final
.length(),
3170 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3171 /*cout << "expected:\n";
3172 final.hexdump(cout);
3175 ASSERT_TRUE(bl_eq(rl
, final
));
3178 ObjectStore::Transaction t
;
3179 t
.remove(cid
, hoid
);
3180 t
.remove(cid
, hoid2
);
3181 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3184 bufferptr
p(1048576);
3185 memset(p
.c_str(), 3, p
.length());
3188 ObjectStore::Transaction t
;
3189 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3190 t
.clone(cid
, hoid
, hoid2
);
3192 memset(a
.c_str(), 4, a
.length());
3195 t
.write(cid
, hoid
, a
.length(), a
.length(), al
);
3196 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3199 final
.substr_of(pl
, 0, al
.length());
3202 end
.substr_of(pl
, al
.length()*2, pl
.length() - al
.length()*2);
3204 ASSERT_EQ((int)final
.length(),
3205 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3206 /*cout << "expected:\n";
3207 final.hexdump(cout);
3210 ASSERT_TRUE(bl_eq(rl
, final
));
3213 ObjectStore::Transaction t
;
3214 t
.remove(cid
, hoid
);
3215 t
.remove(cid
, hoid2
);
3216 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3220 memset(p
.c_str(), 7, p
.length());
3223 ObjectStore::Transaction t
;
3224 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3225 t
.clone(cid
, hoid
, hoid2
);
3227 memset(a
.c_str(), 8, a
.length());
3230 t
.write(cid
, hoid
, 32768, a
.length(), al
);
3231 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3234 final
.substr_of(pl
, 0, 32768);
3237 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3239 ASSERT_EQ((int)final
.length(),
3240 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3241 /*cout << "expected:\n";
3242 final.hexdump(cout);
3245 ASSERT_TRUE(bl_eq(rl
, final
));
3248 ObjectStore::Transaction t
;
3249 t
.remove(cid
, hoid
);
3250 t
.remove(cid
, hoid2
);
3251 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3255 memset(p
.c_str(), 9, p
.length());
3258 ObjectStore::Transaction t
;
3259 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3260 t
.clone(cid
, hoid
, hoid2
);
3262 memset(a
.c_str(), 10, a
.length());
3265 t
.write(cid
, hoid
, 33768, a
.length(), al
);
3266 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3269 final
.substr_of(pl
, 0, 33768);
3272 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3274 ASSERT_EQ((int)final
.length(),
3275 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3276 /*cout << "expected:\n";
3277 final.hexdump(cout);
3280 ASSERT_TRUE(bl_eq(rl
, final
));
3283 //Unfortunately we need a workaround for filestore since EXPECT_DEATH
3284 // macro has potential issues when using /in multithread environments.
3285 //It works well for all stores but filestore for now.
3286 //A fix setting gtest_death_test_style = "threadsafe" doesn't help as well -
3287 // test app clone asserts on store folder presence.
3289 if (string(GetParam()) != "filestore") {
3290 //verify if non-empty collection is properly handled after store reload
3292 r
= store
->umount();
3296 ch
= store
->open_collection(cid
);
3298 ObjectStore::Transaction t
;
3299 t
.remove_collection(cid
);
3300 cerr
<< "Invalid rm coll" << std::endl
;
3301 PrCtl unset_dumpable
;
3302 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3305 ObjectStore::Transaction t
;
3306 t
.touch(cid
, hoid3
); //new record in db
3307 r
= queue_transaction(store
, ch
, std::move(t
));
3310 //See comment above for "filestore" check explanation.
3311 if (string(GetParam()) != "filestore") {
3312 ObjectStore::Transaction t
;
3313 //verify if non-empty collection is properly handled when there are some pending removes and live records in db
3314 cerr
<< "Invalid rm coll again" << std::endl
;
3316 r
= store
->umount();
3320 ch
= store
->open_collection(cid
);
3322 t
.remove(cid
, hoid
);
3323 t
.remove(cid
, hoid2
);
3324 t
.remove_collection(cid
);
3325 PrCtl unset_dumpable
;
3326 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3329 ObjectStore::Transaction t
;
3330 t
.remove(cid
, hoid
);
3331 t
.remove(cid
, hoid2
);
3332 t
.remove(cid
, hoid3
);
3333 t
.remove_collection(cid
);
3334 cerr
<< "Cleaning" << std::endl
;
3335 r
= queue_transaction(store
, ch
, std::move(t
));
3340 TEST_P(StoreTest
, OmapSimple
) {
3343 auto ch
= store
->create_new_collection(cid
);
3345 ObjectStore::Transaction t
;
3346 t
.create_collection(cid
, 0);
3347 cerr
<< "Creating collection " << cid
<< std::endl
;
3348 r
= queue_transaction(store
, ch
, std::move(t
));
3351 ghobject_t
hoid(hobject_t(sobject_t("omap_obj", CEPH_NOSNAP
),
3352 "key", 123, -1, ""));
3354 small
.append("small");
3355 map
<string
,bufferlist
> km
;
3357 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3359 header
.append("this is a header");
3361 ObjectStore::Transaction t
;
3363 t
.omap_setkeys(cid
, hoid
, km
);
3364 t
.omap_setheader(cid
, hoid
, header
);
3365 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3366 r
= queue_transaction(store
, ch
, std::move(t
));
3372 map
<string
,bufferlist
> r
;
3373 store
->omap_get(ch
, hoid
, &h
, &r
);
3374 ASSERT_TRUE(bl_eq(header
, h
));
3375 ASSERT_EQ(r
.size(), km
.size());
3376 cout
<< "r: " << r
<< std::endl
;
3378 // test iterator with seek_to_first
3380 map
<string
,bufferlist
> r
;
3381 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3382 for (iter
->seek_to_first(); iter
->valid(); iter
->next()) {
3383 r
[iter
->key()] = iter
->value();
3385 cout
<< "r: " << r
<< std::endl
;
3386 ASSERT_EQ(r
.size(), km
.size());
3388 // test iterator with initial lower_bound
3390 map
<string
,bufferlist
> r
;
3391 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3392 for (iter
->lower_bound(string()); iter
->valid(); iter
->next()) {
3393 r
[iter
->key()] = iter
->value();
3395 cout
<< "r: " << r
<< std::endl
;
3396 ASSERT_EQ(r
.size(), km
.size());
3399 ObjectStore::Transaction t
;
3400 t
.remove(cid
, hoid
);
3401 t
.remove_collection(cid
);
3402 cerr
<< "Cleaning" << std::endl
;
3403 r
= queue_transaction(store
, ch
, std::move(t
));
3408 TEST_P(StoreTest
, OmapCloneTest
) {
3411 auto ch
= store
->create_new_collection(cid
);
3413 ObjectStore::Transaction t
;
3414 t
.create_collection(cid
, 0);
3415 cerr
<< "Creating collection " << cid
<< std::endl
;
3416 r
= queue_transaction(store
, ch
, std::move(t
));
3419 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
3420 "key", 123, -1, ""));
3422 small
.append("small");
3423 map
<string
,bufferlist
> km
;
3425 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3427 header
.append("this is a header");
3429 ObjectStore::Transaction t
;
3431 t
.omap_setkeys(cid
, hoid
, km
);
3432 t
.omap_setheader(cid
, hoid
, header
);
3433 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3434 r
= queue_transaction(store
, ch
, std::move(t
));
3437 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
3438 "key", 123, -1, ""));
3440 ObjectStore::Transaction t
;
3441 t
.clone(cid
, hoid
, hoid2
);
3442 cerr
<< "Clone object" << std::endl
;
3443 r
= queue_transaction(store
, ch
, std::move(t
));
3447 map
<string
,bufferlist
> r
;
3449 store
->omap_get(ch
, hoid2
, &h
, &r
);
3450 ASSERT_TRUE(bl_eq(header
, h
));
3451 ASSERT_EQ(r
.size(), km
.size());
3454 ObjectStore::Transaction t
;
3455 t
.remove(cid
, hoid
);
3456 t
.remove(cid
, hoid2
);
3457 t
.remove_collection(cid
);
3458 cerr
<< "Cleaning" << std::endl
;
3459 r
= queue_transaction(store
, ch
, std::move(t
));
3464 TEST_P(StoreTest
, SimpleCloneRangeTest
) {
3467 auto ch
= store
->create_new_collection(cid
);
3469 ObjectStore::Transaction t
;
3470 t
.create_collection(cid
, 0);
3471 cerr
<< "Creating collection " << cid
<< std::endl
;
3472 r
= queue_transaction(store
, ch
, std::move(t
));
3475 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3476 hoid
.hobj
.pool
= -1;
3477 bufferlist small
, newdata
;
3478 small
.append("small");
3480 ObjectStore::Transaction t
;
3481 t
.write(cid
, hoid
, 10, 5, small
);
3482 cerr
<< "Creating object and write bl " << hoid
<< std::endl
;
3483 r
= queue_transaction(store
, ch
, std::move(t
));
3486 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
3487 hoid2
.hobj
.pool
= -1;
3489 ObjectStore::Transaction t
;
3490 t
.clone_range(cid
, hoid
, hoid2
, 10, 5, 10);
3491 cerr
<< "Clone range object" << std::endl
;
3492 r
= queue_transaction(store
, ch
, std::move(t
));
3494 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
3496 ASSERT_TRUE(bl_eq(small
, newdata
));
3499 ObjectStore::Transaction t
;
3500 t
.truncate(cid
, hoid
, 1024*1024);
3501 t
.clone_range(cid
, hoid
, hoid2
, 0, 1024*1024, 0);
3502 cerr
<< "Clone range object" << std::endl
;
3503 r
= queue_transaction(store
, ch
, std::move(t
));
3505 struct stat stat
, stat2
;
3506 r
= store
->stat(ch
, hoid
, &stat
);
3507 r
= store
->stat(ch
, hoid2
, &stat2
);
3508 ASSERT_EQ(stat
.st_size
, stat2
.st_size
);
3509 ASSERT_EQ(1024*1024, stat2
.st_size
);
3512 ObjectStore::Transaction t
;
3513 t
.remove(cid
, hoid
);
3514 t
.remove(cid
, hoid2
);
3515 t
.remove_collection(cid
);
3516 cerr
<< "Cleaning" << std::endl
;
3517 r
= queue_transaction(store
, ch
, std::move(t
));
3523 TEST_P(StoreTest
, SimpleObjectLongnameTest
) {
3526 auto ch
= store
->create_new_collection(cid
);
3528 ObjectStore::Transaction t
;
3529 t
.create_collection(cid
, 0);
3530 cerr
<< "Creating collection " << cid
<< std::endl
;
3531 r
= queue_transaction(store
, ch
, std::move(t
));
3534 ghobject_t
hoid(hobject_t(sobject_t("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaObjectaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1", CEPH_NOSNAP
)));
3536 ObjectStore::Transaction t
;
3538 cerr
<< "Creating object " << hoid
<< std::endl
;
3539 r
= queue_transaction(store
, ch
, std::move(t
));
3543 ObjectStore::Transaction t
;
3544 t
.remove(cid
, hoid
);
3545 t
.remove_collection(cid
);
3546 cerr
<< "Cleaning" << std::endl
;
3547 r
= queue_transaction(store
, ch
, std::move(t
));
3552 ghobject_t
generate_long_name(unsigned i
)
3555 name
<< "object id " << i
<< " ";
3556 for (unsigned j
= 0; j
< 500; ++j
) name
<< 'a';
3557 ghobject_t
hoid(hobject_t(sobject_t(name
.str(), CEPH_NOSNAP
)));
3558 hoid
.hobj
.set_hash(i
% 2);
3562 TEST_P(StoreTest
, LongnameSplitTest
) {
3565 auto ch
= store
->create_new_collection(cid
);
3567 ObjectStore::Transaction t
;
3568 t
.create_collection(cid
, 0);
3569 cerr
<< "Creating collection " << cid
<< std::endl
;
3570 r
= queue_transaction(store
, ch
, std::move(t
));
3573 for (unsigned i
= 0; i
< 320; ++i
) {
3574 ObjectStore::Transaction t
;
3575 ghobject_t hoid
= generate_long_name(i
);
3577 cerr
<< "Creating object " << hoid
<< std::endl
;
3578 r
= queue_transaction(store
, ch
, std::move(t
));
3582 ghobject_t test_obj
= generate_long_name(319);
3583 ghobject_t test_obj_2
= test_obj
;
3584 test_obj_2
.generation
= 0;
3586 ObjectStore::Transaction t
;
3587 // should cause a split
3588 t
.collection_move_rename(
3591 r
= queue_transaction(store
, ch
, std::move(t
));
3595 for (unsigned i
= 0; i
< 319; ++i
) {
3596 ObjectStore::Transaction t
;
3597 ghobject_t hoid
= generate_long_name(i
);
3598 t
.remove(cid
, hoid
);
3599 cerr
<< "Removing object " << hoid
<< std::endl
;
3600 r
= queue_transaction(store
, ch
, std::move(t
));
3604 ObjectStore::Transaction t
;
3605 t
.remove(cid
, test_obj_2
);
3606 t
.remove_collection(cid
);
3607 cerr
<< "Cleaning" << std::endl
;
3608 r
= queue_transaction(store
, ch
, std::move(t
));
3614 TEST_P(StoreTest
, ManyObjectTest
) {
3615 int NUM_OBJS
= 2000;
3619 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
3620 set
<ghobject_t
> created
;
3621 auto ch
= store
->create_new_collection(cid
);
3623 ObjectStore::Transaction t
;
3624 t
.create_collection(cid
, 0);
3625 r
= queue_transaction(store
, ch
, std::move(t
));
3628 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
3630 cerr
<< "Object " << i
<< std::endl
;
3632 ObjectStore::Transaction t
;
3634 snprintf(buf
, sizeof(buf
), "%d", i
);
3635 ghobject_t
hoid(hobject_t(sobject_t(string(buf
) + base
, CEPH_NOSNAP
)));
3637 created
.insert(hoid
);
3638 r
= queue_transaction(store
, ch
, std::move(t
));
3642 for (set
<ghobject_t
>::iterator i
= created
.begin();
3646 ASSERT_TRUE(!store
->stat(ch
, *i
, &buf
));
3649 set
<ghobject_t
> listed
, listed2
;
3650 vector
<ghobject_t
> objects
;
3651 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
, &objects
, 0);
3654 cerr
<< "objects.size() is " << objects
.size() << std::endl
;
3655 for (vector
<ghobject_t
> ::iterator i
= objects
.begin();
3659 ASSERT_TRUE(created
.count(*i
));
3661 ASSERT_TRUE(listed
.size() == created
.size());
3663 ghobject_t start
, next
;
3665 r
= store
->collection_list(
3667 ghobject_t::get_max(),
3668 ghobject_t::get_max(),
3674 ASSERT_TRUE(objects
.empty());
3678 ghobject_t start2
, next2
;
3680 r
= store
->collection_list(ch
, start
, ghobject_t::get_max(),
3684 ASSERT_TRUE(sorted(objects
));
3686 listed
.insert(objects
.begin(), objects
.end());
3687 if (objects
.size() < 50) {
3688 ASSERT_TRUE(next
.is_max());
3695 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
3696 ASSERT_TRUE(listed
.size() == created
.size());
3697 if (listed2
.size()) {
3698 ASSERT_EQ(listed
.size(), listed2
.size());
3700 for (set
<ghobject_t
>::iterator i
= listed
.begin();
3703 ASSERT_TRUE(created
.count(*i
));
3706 for (set
<ghobject_t
>::iterator i
= created
.begin();
3709 ObjectStore::Transaction t
;
3711 r
= queue_transaction(store
, ch
, std::move(t
));
3714 cerr
<< "cleaning up" << std::endl
;
3716 ObjectStore::Transaction t
;
3717 t
.remove_collection(cid
);
3718 r
= queue_transaction(store
, ch
, std::move(t
));
3724 class ObjectGenerator
{
3726 virtual ghobject_t
create_object(gen_type
*gen
) = 0;
3727 virtual ~ObjectGenerator() {}
3730 class MixedGenerator
: public ObjectGenerator
{
3734 explicit MixedGenerator(int64_t p
) : seq(0), poolid(p
) {}
3735 ghobject_t
create_object(gen_type
*gen
) override
{
3737 snprintf(buf
, sizeof(buf
), "OBJ_%u", seq
);
3740 for (unsigned i
= 0; i
< 300; ++i
) {
3741 name
.push_back('a');
3747 name
, string(), rand() & 2 ? CEPH_NOSNAP
: rand(),
3748 (((seq
/ 1024) % 2) * 0xF00 ) +
3754 class SyntheticWorkloadState
{
3757 map
<string
, bufferlist
> attrs
;
3760 static const unsigned max_in_flight
= 16;
3761 static const unsigned max_objects
= 3000;
3762 static const unsigned max_attr_size
= 5;
3763 static const unsigned max_attr_name_len
= 100;
3764 static const unsigned max_attr_value_len
= 1024 * 64;
3766 unsigned write_alignment
;
3767 unsigned max_object_len
, max_write_len
;
3769 map
<ghobject_t
, Object
> contents
;
3770 set
<ghobject_t
> available_objects
;
3771 set
<ghobject_t
> in_flight_objects
;
3772 ObjectGenerator
*object_gen
;
3775 ObjectStore::CollectionHandle ch
;
3777 ceph::mutex lock
= ceph::make_mutex("State lock");
3778 ceph::condition_variable cond
;
3782 explicit EnterExit(const char *m
) : msg(m
) {
3783 //cout << pthread_self() << " enter " << msg << std::endl;
3786 //cout << pthread_self() << " exit " << msg << std::endl;
3790 class C_SyntheticOnReadable
: public Context
{
3792 SyntheticWorkloadState
*state
;
3794 C_SyntheticOnReadable(SyntheticWorkloadState
*state
, ghobject_t hoid
)
3795 : state(state
), hoid(hoid
) {}
3797 void finish(int r
) override
{
3798 std::lock_guard locker
{state
->lock
};
3799 EnterExit
ee("onreadable finish");
3800 ASSERT_TRUE(state
->in_flight_objects
.count(hoid
));
3802 state
->in_flight_objects
.erase(hoid
);
3803 if (state
->contents
.count(hoid
))
3804 state
->available_objects
.insert(hoid
);
3805 --(state
->in_flight
);
3806 state
->cond
.notify_all();
3809 r
= state
->store
->read(state
->ch
, hoid
, 0, state
->contents
[hoid
].data
.length(), r2
);
3810 ceph_assert(bl_eq(state
->contents
[hoid
].data
, r2
));
3811 state
->cond
.notify_all();
3815 class C_SyntheticOnStash
: public Context
{
3817 SyntheticWorkloadState
*state
;
3818 ghobject_t oid
, noid
;
3820 C_SyntheticOnStash(SyntheticWorkloadState
*state
,
3821 ghobject_t oid
, ghobject_t noid
)
3822 : state(state
), oid(oid
), noid(noid
) {}
3824 void finish(int r
) override
{
3825 std::lock_guard locker
{state
->lock
};
3826 EnterExit
ee("stash finish");
3827 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
3829 state
->in_flight_objects
.erase(oid
);
3830 if (state
->contents
.count(noid
))
3831 state
->available_objects
.insert(noid
);
3832 --(state
->in_flight
);
3834 r
= state
->store
->read(
3836 state
->contents
[noid
].data
.length(), r2
);
3837 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
3838 state
->cond
.notify_all();
3842 class C_SyntheticOnClone
: public Context
{
3844 SyntheticWorkloadState
*state
;
3845 ghobject_t oid
, noid
;
3847 C_SyntheticOnClone(SyntheticWorkloadState
*state
,
3848 ghobject_t oid
, ghobject_t noid
)
3849 : state(state
), oid(oid
), noid(noid
) {}
3851 void finish(int r
) override
{
3852 std::lock_guard locker
{state
->lock
};
3853 EnterExit
ee("clone finish");
3854 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
3856 state
->in_flight_objects
.erase(oid
);
3857 if (state
->contents
.count(oid
))
3858 state
->available_objects
.insert(oid
);
3859 if (state
->contents
.count(noid
))
3860 state
->available_objects
.insert(noid
);
3861 --(state
->in_flight
);
3863 r
= state
->store
->read(state
->ch
, noid
, 0, state
->contents
[noid
].data
.length(), r2
);
3864 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
3865 state
->cond
.notify_all();
3869 static void filled_byte_array(bufferlist
& bl
, size_t size
)
3871 static const char alphanum
[] = "0123456789"
3872 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3873 "abcdefghijklmnopqrstuvwxyz";
3878 for (unsigned int i
= 0; i
< size
- 1; i
++) {
3879 // severely limit entropy so we can compress...
3880 bp
[i
] = alphanum
[rand() % 10]; //(sizeof(alphanum) - 1)];
3882 bp
[size
- 1] = '\0';
3887 SyntheticWorkloadState(ObjectStore
*store
,
3888 ObjectGenerator
*gen
,
3894 : cid(cid
), write_alignment(alignment
), max_object_len(max_size
),
3895 max_write_len(max_write
), in_flight(0), object_gen(gen
),
3896 rng(rng
), store(store
) {}
3899 ObjectStore::Transaction t
;
3900 ch
= store
->create_new_collection(cid
);
3901 t
.create_collection(cid
, 0);
3902 return queue_transaction(store
, ch
, std::move(t
));
3906 vector
<ghobject_t
> objects
;
3907 int r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
3909 ceph_assert(r
>= 0);
3910 if (objects
.empty())
3912 ObjectStore::Transaction t
;
3913 for (vector
<ghobject_t
>::iterator p
= objects
.begin();
3914 p
!= objects
.end(); ++p
) {
3917 queue_transaction(store
, ch
, std::move(t
));
3919 ObjectStore::Transaction t
;
3920 t
.remove_collection(cid
);
3921 queue_transaction(store
, ch
, std::move(t
));
3923 void statfs(store_statfs_t
& stat
) {
3924 store
->statfs(&stat
);
3927 ghobject_t
get_uniform_random_object(std::unique_lock
<ceph::mutex
>& locker
) {
3928 cond
.wait(locker
, [this] {
3929 return in_flight
< max_in_flight
&& !available_objects
.empty();
3931 boost::uniform_int
<> choose(0, available_objects
.size() - 1);
3932 int index
= choose(*rng
);
3933 set
<ghobject_t
>::iterator i
= available_objects
.begin();
3934 for ( ; index
> 0; --index
, ++i
) ;
3935 ghobject_t ret
= *i
;
3939 void wait_for_ready(std::unique_lock
<ceph::mutex
>& locker
) {
3940 cond
.wait(locker
, [this] { return in_flight
< max_in_flight
; });
3943 void wait_for_done() {
3944 std::unique_lock locker
{lock
};
3945 cond
.wait(locker
, [this] { return in_flight
== 0; });
3949 return (available_objects
.size() + in_flight_objects
.size()) < max_objects
;
3953 return (available_objects
.size() + in_flight_objects
.size()) > 0;
3956 unsigned get_random_alloc_hints() {
3959 boost::uniform_int
<> u(0, 3);
3962 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE
;
3965 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE
;
3970 boost::uniform_int
<> u(0, 3);
3973 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
;
3976 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ
;
3981 // append_only, immutable
3982 boost::uniform_int
<> u(0, 4);
3986 boost::uniform_int
<> u(0, 3);
3989 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED
;
3992 f
|= CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED
;
3997 boost::uniform_int
<> u(0, 3);
4000 f
|= CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE
;
4003 f
|= CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE
;
4011 std::unique_lock locker
{lock
};
4012 EnterExit
ee("touch");
4015 wait_for_ready(locker
);
4016 ghobject_t new_obj
= object_gen
->create_object(rng
);
4017 available_objects
.erase(new_obj
);
4018 ObjectStore::Transaction t
;
4019 t
.touch(cid
, new_obj
);
4020 boost::uniform_int
<> u(17, 22);
4021 boost::uniform_int
<> v(12, 17);
4022 t
.set_alloc_hint(cid
, new_obj
,
4025 get_random_alloc_hints());
4027 in_flight_objects
.insert(new_obj
);
4028 if (!contents
.count(new_obj
))
4029 contents
[new_obj
] = Object();
4030 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4031 int status
= store
->queue_transaction(ch
, std::move(t
));
4036 std::unique_lock locker
{lock
};
4037 EnterExit
ee("stash");
4042 wait_for_ready(locker
);
4047 old_obj
= get_uniform_random_object(locker
);
4048 } while (--max
&& !contents
[old_obj
].data
.length());
4049 available_objects
.erase(old_obj
);
4050 ghobject_t new_obj
= old_obj
;
4051 new_obj
.generation
++;
4052 available_objects
.erase(new_obj
);
4054 ObjectStore::Transaction t
;
4055 t
.collection_move_rename(cid
, old_obj
, cid
, new_obj
);
4057 in_flight_objects
.insert(old_obj
);
4059 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
4060 contents
[new_obj
].data
= contents
[old_obj
].data
;
4061 contents
.erase(old_obj
);
4062 t
.register_on_applied(new C_SyntheticOnStash(this, old_obj
, new_obj
));
4063 int status
= store
->queue_transaction(ch
, std::move(t
));
4068 std::unique_lock locker
{lock
};
4069 EnterExit
ee("clone");
4074 wait_for_ready(locker
);
4079 old_obj
= get_uniform_random_object(locker
);
4080 } while (--max
&& !contents
[old_obj
].data
.length());
4081 available_objects
.erase(old_obj
);
4082 ghobject_t new_obj
= object_gen
->create_object(rng
);
4083 // make the hash match
4084 new_obj
.hobj
.set_hash(old_obj
.hobj
.get_hash());
4085 available_objects
.erase(new_obj
);
4087 ObjectStore::Transaction t
;
4088 t
.clone(cid
, old_obj
, new_obj
);
4090 in_flight_objects
.insert(old_obj
);
4092 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
4093 contents
[new_obj
].data
= contents
[old_obj
].data
;
4095 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
4096 int status
= store
->queue_transaction(ch
, std::move(t
));
4101 std::unique_lock locker
{lock
};
4102 EnterExit
ee("clone_range");
4107 wait_for_ready(locker
);
4112 old_obj
= get_uniform_random_object(locker
);
4113 } while (--max
&& !contents
[old_obj
].data
.length());
4114 bufferlist
&srcdata
= contents
[old_obj
].data
;
4115 if (srcdata
.length() == 0) {
4118 available_objects
.erase(old_obj
);
4119 ghobject_t new_obj
= get_uniform_random_object(locker
);
4120 available_objects
.erase(new_obj
);
4122 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4123 boost::uniform_int
<> u2(0, max_write_len
);
4124 uint64_t srcoff
= u1(*rng
);
4125 // make src and dst offsets match, since that's what the osd does
4126 uint64_t dstoff
= srcoff
; //u1(*rng);
4127 uint64_t len
= u2(*rng
);
4128 if (write_alignment
) {
4129 srcoff
= round_up_to(srcoff
, write_alignment
);
4130 dstoff
= round_up_to(dstoff
, write_alignment
);
4131 len
= round_up_to(len
, write_alignment
);
4134 if (srcoff
> srcdata
.length() - 1) {
4135 srcoff
= srcdata
.length() - 1;
4137 if (srcoff
+ len
> srcdata
.length()) {
4138 len
= srcdata
.length() - srcoff
;
4141 cout
<< __func__
<< " from " << srcoff
<< "~" << len
4142 << " (size " << srcdata
.length() << ") to "
4143 << dstoff
<< "~" << len
<< std::endl
;
4145 ObjectStore::Transaction t
;
4146 t
.clone_range(cid
, old_obj
, new_obj
, srcoff
, len
, dstoff
);
4148 in_flight_objects
.insert(old_obj
);
4151 if (srcoff
< srcdata
.length()) {
4152 if (srcoff
+ len
> srcdata
.length()) {
4153 bl
.substr_of(srcdata
, srcoff
, srcdata
.length() - srcoff
);
4155 bl
.substr_of(srcdata
, srcoff
, len
);
4159 bufferlist
& dstdata
= contents
[new_obj
].data
;
4160 if (dstdata
.length() <= dstoff
) {
4161 if (bl
.length() > 0) {
4162 dstdata
.append_zero(dstoff
- dstdata
.length());
4167 ceph_assert(dstdata
.length() > dstoff
);
4168 dstdata
.cbegin().copy(dstoff
, value
);
4170 if (value
.length() < dstdata
.length())
4171 dstdata
.cbegin(value
.length()).copy(
4172 dstdata
.length() - value
.length(), value
);
4173 value
.swap(dstdata
);
4176 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
4177 int status
= store
->queue_transaction(ch
, std::move(t
));
4183 std::unique_lock locker
{lock
};
4184 EnterExit
ee("write");
4187 wait_for_ready(locker
);
4189 ghobject_t new_obj
= get_uniform_random_object(locker
);
4190 available_objects
.erase(new_obj
);
4191 ObjectStore::Transaction t
;
4193 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4194 boost::uniform_int
<> u2(0, max_write_len
);
4195 uint64_t offset
= u1(*rng
);
4196 uint64_t len
= u2(*rng
);
4198 if (write_alignment
) {
4199 offset
= round_up_to(offset
, write_alignment
);
4200 len
= round_up_to(len
, write_alignment
);
4203 filled_byte_array(bl
, len
);
4205 bufferlist
& data
= contents
[new_obj
].data
;
4206 if (data
.length() <= offset
) {
4208 data
.append_zero(offset
-data
.length());
4213 ceph_assert(data
.length() > offset
);
4214 data
.cbegin().copy(offset
, value
);
4216 if (value
.length() < data
.length())
4217 data
.cbegin(value
.length()).copy(
4218 data
.length()-value
.length(), value
);
4222 t
.write(cid
, new_obj
, offset
, len
, bl
);
4224 in_flight_objects
.insert(new_obj
);
4225 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4226 int status
= store
->queue_transaction(ch
, std::move(t
));
4231 std::unique_lock locker
{lock
};
4232 EnterExit
ee("truncate");
4235 wait_for_ready(locker
);
4237 ghobject_t obj
= get_uniform_random_object(locker
);
4238 available_objects
.erase(obj
);
4239 ObjectStore::Transaction t
;
4241 boost::uniform_int
<> choose(0, max_object_len
);
4242 size_t len
= choose(*rng
);
4243 if (write_alignment
) {
4244 len
= round_up_to(len
, write_alignment
);
4247 t
.truncate(cid
, obj
, len
);
4249 in_flight_objects
.insert(obj
);
4250 bufferlist
& data
= contents
[obj
].data
;
4251 if (data
.length() <= len
) {
4252 data
.append_zero(len
- data
.length());
4255 data
.cbegin().copy(len
, bl
);
4259 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4260 int status
= store
->queue_transaction(ch
, std::move(t
));
4265 std::unique_lock locker
{lock
};
4266 EnterExit
ee("zero");
4269 wait_for_ready(locker
);
4271 ghobject_t new_obj
= get_uniform_random_object(locker
);
4272 available_objects
.erase(new_obj
);
4273 ObjectStore::Transaction t
;
4275 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4276 boost::uniform_int
<> u2(0, max_write_len
);
4277 uint64_t offset
= u1(*rng
);
4278 uint64_t len
= u2(*rng
);
4279 if (write_alignment
) {
4280 offset
= round_up_to(offset
, write_alignment
);
4281 len
= round_up_to(len
, write_alignment
);
4285 auto& data
= contents
[new_obj
].data
;
4286 if (data
.length() < offset
+ len
) {
4287 data
.append_zero(offset
+len
-data
.length());
4290 n
.substr_of(data
, 0, offset
);
4292 if (data
.length() > offset
+ len
)
4293 data
.cbegin(offset
+ len
).copy(data
.length() - offset
- len
, n
);
4297 t
.zero(cid
, new_obj
, offset
, len
);
4299 in_flight_objects
.insert(new_obj
);
4300 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4301 int status
= store
->queue_transaction(ch
, std::move(t
));
4306 EnterExit
ee("read");
4307 boost::uniform_int
<> u1(0, max_object_len
/2);
4308 boost::uniform_int
<> u2(0, max_object_len
);
4309 uint64_t offset
= u1(*rng
);
4310 uint64_t len
= u2(*rng
);
4315 bufferlist expected
;
4318 std::unique_lock locker
{lock
};
4319 EnterExit
ee("read locked");
4322 wait_for_ready(locker
);
4324 obj
= get_uniform_random_object(locker
);
4325 expected
= contents
[obj
].data
;
4327 bufferlist bl
, result
;
4328 if (0) cout
<< " obj " << obj
4329 << " size " << expected
.length()
4330 << " offset " << offset
4331 << " len " << len
<< std::endl
;
4332 r
= store
->read(ch
, obj
, offset
, len
, result
);
4333 if (offset
>= expected
.length()) {
4336 size_t max_len
= expected
.length() - offset
;
4339 ceph_assert(len
== result
.length());
4340 ASSERT_EQ(len
, result
.length());
4341 expected
.cbegin(offset
).copy(len
, bl
);
4342 ASSERT_EQ(r
, (int)len
);
4343 ASSERT_TRUE(bl_eq(bl
, result
));
4348 std::unique_lock locker
{lock
};
4349 EnterExit
ee("setattrs");
4352 wait_for_ready(locker
);
4354 ghobject_t obj
= get_uniform_random_object(locker
);
4355 available_objects
.erase(obj
);
4356 ObjectStore::Transaction t
;
4358 boost::uniform_int
<> u0(1, max_attr_size
);
4359 boost::uniform_int
<> u1(4, max_attr_name_len
);
4360 boost::uniform_int
<> u2(4, max_attr_value_len
);
4361 boost::uniform_int
<> u3(0, 100);
4362 uint64_t size
= u0(*rng
);
4364 map
<string
, bufferlist
> attrs
;
4366 for (map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4367 it
!= contents
[obj
].attrs
.end(); ++it
)
4368 keys
.insert(it
->first
);
4371 bufferlist name
, value
;
4372 uint64_t get_exist
= u3(*rng
);
4373 uint64_t value_len
= u2(*rng
);
4374 filled_byte_array(value
, value_len
);
4375 if (get_exist
< 50 && keys
.size()) {
4376 set
<string
>::iterator k
= keys
.begin();
4378 contents
[obj
].attrs
[*k
] = value
;
4381 name_len
= u1(*rng
);
4382 filled_byte_array(name
, name_len
);
4383 attrs
[name
.c_str()] = value
;
4384 contents
[obj
].attrs
[name
.c_str()] = value
;
4387 t
.setattrs(cid
, obj
, attrs
);
4389 in_flight_objects
.insert(obj
);
4390 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4391 int status
= store
->queue_transaction(ch
, std::move(t
));
4396 EnterExit
ee("getattrs");
4398 map
<string
, bufferlist
> expected
;
4400 std::unique_lock locker
{lock
};
4401 EnterExit
ee("getattrs locked");
4404 wait_for_ready(locker
);
4408 obj
= get_uniform_random_object(locker
);
4411 } while (contents
[obj
].attrs
.empty());
4412 expected
= contents
[obj
].attrs
;
4414 map
<string
, bufferlist
> attrs
;
4415 int r
= store
->getattrs(ch
, obj
, attrs
);
4416 ASSERT_TRUE(r
== 0);
4417 ASSERT_TRUE(attrs
.size() == expected
.size());
4418 for (map
<string
, bufferlist
>::iterator it
= expected
.begin();
4419 it
!= expected
.end(); ++it
) {
4420 ASSERT_TRUE(bl_eq(attrs
[it
->first
], it
->second
));
4425 EnterExit
ee("getattr");
4429 map
<string
, bufferlist
> expected
;
4431 std::unique_lock locker
{lock
};
4432 EnterExit
ee("getattr locked");
4435 wait_for_ready(locker
);
4439 obj
= get_uniform_random_object(locker
);
4442 } while (contents
[obj
].attrs
.empty());
4443 expected
= contents
[obj
].attrs
;
4445 boost::uniform_int
<> u(0, expected
.size()-1);
4447 map
<string
, bufferlist
>::iterator it
= expected
.begin();
4454 r
= store
->getattr(ch
, obj
, it
->first
, bl
);
4456 ASSERT_TRUE(bl_eq(it
->second
, bl
));
4460 std::unique_lock locker
{lock
};
4461 EnterExit
ee("rmattr");
4464 wait_for_ready(locker
);
4469 obj
= get_uniform_random_object(locker
);
4472 } while (contents
[obj
].attrs
.empty());
4474 boost::uniform_int
<> u(0, contents
[obj
].attrs
.size()-1);
4476 map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4482 available_objects
.erase(obj
);
4483 ObjectStore::Transaction t
;
4484 t
.rmattr(cid
, obj
, it
->first
);
4486 contents
[obj
].attrs
.erase(it
->first
);
4488 in_flight_objects
.insert(obj
);
4489 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4490 int status
= store
->queue_transaction(ch
, std::move(t
));
4494 void fsck(bool deep
) {
4495 std::unique_lock locker
{lock
};
4496 EnterExit
ee("fsck");
4497 cond
.wait(locker
, [this] { return in_flight
== 0; });
4500 int r
= store
->fsck(deep
);
4501 ceph_assert(r
== 0 || r
== -EOPNOTSUPP
);
4503 ch
= store
->open_collection(cid
);
4507 std::unique_lock locker
{lock
};
4508 EnterExit
ee("scan");
4509 cond
.wait(locker
, [this] { return in_flight
== 0; });
4510 vector
<ghobject_t
> objects
;
4511 set
<ghobject_t
> objects_set
, objects_set2
;
4512 ghobject_t next
, current
;
4514 //cerr << "scanning..." << std::endl;
4515 int r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 100,
4518 ASSERT_TRUE(sorted(objects
));
4519 objects_set
.insert(objects
.begin(), objects
.end());
4521 if (next
.is_max()) break;
4524 if (objects_set
.size() != available_objects
.size()) {
4525 for (set
<ghobject_t
>::iterator p
= objects_set
.begin();
4526 p
!= objects_set
.end();
4528 if (available_objects
.count(*p
) == 0) {
4529 cerr
<< "+ " << *p
<< std::endl
;
4532 for (set
<ghobject_t
>::iterator p
= available_objects
.begin();
4533 p
!= available_objects
.end();
4535 if (objects_set
.count(*p
) == 0)
4536 cerr
<< "- " << *p
<< std::endl
;
4537 //cerr << " objects_set: " << objects_set << std::endl;
4538 //cerr << " available_set: " << available_objects << std::endl;
4539 ceph_abort_msg("badness");
4542 ASSERT_EQ(objects_set
.size(), available_objects
.size());
4543 for (set
<ghobject_t
>::iterator i
= objects_set
.begin();
4544 i
!= objects_set
.end();
4546 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
4549 int r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
4550 INT_MAX
, &objects
, 0);
4552 objects_set2
.insert(objects
.begin(), objects
.end());
4553 ASSERT_EQ(objects_set2
.size(), available_objects
.size());
4554 for (set
<ghobject_t
>::iterator i
= objects_set2
.begin();
4555 i
!= objects_set2
.end();
4557 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
4558 if (available_objects
.count(*i
) == 0) {
4559 cerr
<< "+ " << *i
<< std::endl
;
4565 EnterExit
ee("stat");
4569 std::unique_lock locker
{lock
};
4570 EnterExit
ee("stat lock1");
4573 hoid
= get_uniform_random_object(locker
);
4574 in_flight_objects
.insert(hoid
);
4575 available_objects
.erase(hoid
);
4577 expected
= contents
[hoid
].data
.length();
4580 int r
= store
->stat(ch
, hoid
, &buf
);
4582 ceph_assert((uint64_t)buf
.st_size
== expected
);
4583 ASSERT_TRUE((uint64_t)buf
.st_size
== expected
);
4585 std::lock_guard locker
{lock
};
4586 EnterExit
ee("stat lock2");
4589 in_flight_objects
.erase(hoid
);
4590 available_objects
.insert(hoid
);
4595 std::unique_lock locker
{lock
};
4596 EnterExit
ee("unlink");
4599 ghobject_t to_remove
= get_uniform_random_object(locker
);
4600 ObjectStore::Transaction t
;
4601 t
.remove(cid
, to_remove
);
4603 available_objects
.erase(to_remove
);
4604 in_flight_objects
.insert(to_remove
);
4605 contents
.erase(to_remove
);
4606 t
.register_on_applied(new C_SyntheticOnReadable(this, to_remove
));
4607 int status
= store
->queue_transaction(ch
, std::move(t
));
4611 void print_internal_state() {
4612 std::lock_guard locker
{lock
};
4613 cerr
<< "available_objects: " << available_objects
.size()
4614 << " in_flight_objects: " << in_flight_objects
.size()
4615 << " total objects: " << in_flight_objects
.size() + available_objects
.size()
4616 << " in_flight " << in_flight
<< std::endl
;
4621 void StoreTest::doSyntheticTest(
4623 uint64_t max_obj
, uint64_t max_wr
, uint64_t align
)
4625 MixedGenerator
gen(555);
4626 gen_type
rng(time(NULL
));
4627 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
4629 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
4630 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
4631 g_ceph_context
->_conf
.apply_changes(nullptr);
4633 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
,
4634 max_obj
, max_wr
, align
);
4636 for (int i
= 0; i
< num_ops
/10; ++i
) {
4637 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
4640 for (int i
= 0; i
< num_ops
; ++i
) {
4642 cerr
<< "Op " << i
<< std::endl
;
4643 test_obj
.print_internal_state();
4645 boost::uniform_int
<> true_false(0, 999);
4646 int val
= true_false(rng
);
4648 test_obj
.fsck(true);
4649 } else if (val
> 997) {
4650 test_obj
.fsck(false);
4651 } else if (val
> 970) {
4653 } else if (val
> 950) {
4655 } else if (val
> 850) {
4657 } else if (val
> 800) {
4659 } else if (val
> 550) {
4661 } else if (val
> 500) {
4663 } else if (val
> 450) {
4664 test_obj
.clone_range();
4665 } else if (val
> 300) {
4667 } else if (val
> 100) {
4670 test_obj
.truncate();
4673 test_obj
.wait_for_done();
4674 test_obj
.shutdown();
4677 TEST_P(StoreTest
, Synthetic
) {
4678 doSyntheticTest(10000, 400*1024, 40*1024, 0);
4681 #if defined(WITH_BLUESTORE)
4682 TEST_P(StoreTestSpecificAUSize
, BlueFSExtenderTest
) {
4683 if(string(GetParam()) != "bluestore")
4686 SetVal(g_conf(), "bluestore_block_db_size", "0");
4687 SetVal(g_conf(), "bluestore_block_wal_size", "0");
4688 SetVal(g_conf(), "bluestore_bluefs_min", "12582912");
4689 SetVal(g_conf(), "bluestore_bluefs_min_free", "4194304");
4690 SetVal(g_conf(), "bluestore_bluefs_gift_ratio", "0");
4691 SetVal(g_conf(), "bluestore_bluefs_min_ratio", "0");
4692 SetVal(g_conf(), "bluestore_bluefs_balance_interval", "100000");
4693 SetVal(g_conf(), "bluestore_bluefs_db_compatibility", "false");
4695 g_conf().apply_changes(nullptr);
4697 StartDeferred(4096);
4699 doSyntheticTest(10000, 400*1024, 40*1024, 0);
4701 BlueStore
* bstore
= NULL
;
4702 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
4704 // verify downgrades are broken and repair that
4706 ASSERT_EQ(bstore
->fsck(false), 0);
4708 SetVal(g_conf(), "bluestore_bluefs_db_compatibility", "true");
4709 g_conf().apply_changes(nullptr);
4711 ASSERT_EQ(bstore
->fsck(false), 1);
4712 ASSERT_EQ(bstore
->repair(false), 0);
4713 ASSERT_EQ(bstore
->fsck(false), 0);
4717 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixSharding
) {
4718 if (string(GetParam()) != "bluestore")
4721 const char *m
[][10] = {
4722 { "bluestore_min_alloc_size", "4096", 0 }, // must be the first!
4723 { "num_ops", "50000", 0 },
4724 { "max_write", "65536", 0 },
4725 { "max_size", "262144", 0 },
4726 { "alignment", "4096", 0 },
4727 { "bluestore_max_blob_size", "65536", 0 },
4728 { "bluestore_extent_map_shard_min_size", "60", 0 },
4729 { "bluestore_extent_map_shard_max_size", "300", 0 },
4730 { "bluestore_extent_map_shard_target_size", "150", 0 },
4731 { "bluestore_default_buffered_read", "true", 0 },
4732 { "bluestore_default_buffered_write", "true", 0 },
4735 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4738 TEST_P(StoreTestSpecificAUSize
, ZipperPatternSharded
) {
4739 if(string(GetParam()) != "bluestore")
4741 StartDeferred(4096);
4745 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
4746 auto ch
= store
->create_new_collection(cid
);
4748 ObjectStore::Transaction t
;
4749 t
.create_collection(cid
, 0);
4750 cerr
<< "Creating collection " << cid
<< std::endl
;
4751 r
= queue_transaction(store
, ch
, std::move(t
));
4759 for (int i
=0; i
<1000; ++i
) {
4760 ObjectStore::Transaction t
;
4761 t
.write(cid
, a
, i
*2*len
, len
, bl
, 0);
4762 r
= queue_transaction(store
, ch
, std::move(t
));
4765 for (int i
=0; i
<1000; ++i
) {
4766 ObjectStore::Transaction t
;
4767 t
.write(cid
, a
, i
*2*len
+ 1, len
, bl
, 0);
4768 r
= queue_transaction(store
, ch
, std::move(t
));
4772 ObjectStore::Transaction t
;
4774 t
.remove_collection(cid
);
4775 cerr
<< "Cleaning" << std::endl
;
4776 r
= queue_transaction(store
, ch
, std::move(t
));
4781 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumAlgorithm
) {
4782 if (string(GetParam()) != "bluestore")
4785 const char *m
[][10] = {
4786 { "bluestore_min_alloc_size", "65536", 0 }, // must be the first!
4787 { "max_write", "65536", 0 },
4788 { "max_size", "1048576", 0 },
4789 { "alignment", "16", 0 },
4790 { "bluestore_csum_type", "crc32c", "crc32c_16", "crc32c_8", "xxhash32",
4791 "xxhash64", "none", 0 },
4792 { "bluestore_default_buffered_write", "false", 0 },
4795 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4798 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumVsCompression
) {
4799 if (string(GetParam()) != "bluestore")
4802 const char *m
[][10] = {
4803 { "bluestore_min_alloc_size", "4096", "16384", 0 }, //to be the first!
4804 { "max_write", "131072", 0 },
4805 { "max_size", "262144", 0 },
4806 { "alignment", "512", 0 },
4807 { "bluestore_compression_mode", "force", 0},
4808 { "bluestore_compression_algorithm", "snappy", "zlib", 0 },
4809 { "bluestore_csum_type", "crc32c", 0 },
4810 { "bluestore_default_buffered_read", "true", "false", 0 },
4811 { "bluestore_default_buffered_write", "true", "false", 0 },
4812 { "bluestore_sync_submit_transaction", "false", 0 },
4815 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4818 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompression
) {
4819 if (string(GetParam()) != "bluestore")
4822 const char *m
[][10] = {
4823 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4824 { "max_write", "1048576", 0 },
4825 { "max_size", "4194304", 0 },
4826 { "alignment", "65536", 0 },
4827 { "bluestore_compression_mode", "force", "aggressive", "passive", "none", 0},
4828 { "bluestore_default_buffered_write", "false", 0 },
4829 { "bluestore_sync_submit_transaction", "true", 0 },
4832 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4835 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompressionAlgorithm
) {
4836 if (string(GetParam()) != "bluestore")
4839 const char *m
[][10] = {
4840 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4841 { "max_write", "1048576", 0 },
4842 { "max_size", "4194304", 0 },
4843 { "alignment", "65536", 0 },
4844 { "bluestore_compression_algorithm", "zlib", "snappy", 0 },
4845 { "bluestore_compression_mode", "force", 0 },
4846 { "bluestore_default_buffered_write", "false", 0 },
4849 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4852 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixNoCsum
) {
4853 if (string(GetParam()) != "bluestore")
4856 const char *m
[][10] = {
4857 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4858 { "max_write", "65536", 0 },
4859 { "max_size", "1048576", 0 },
4860 { "alignment", "512", 0 },
4861 { "bluestore_max_blob_size", "262144", 0 },
4862 { "bluestore_compression_mode", "force", "none", 0},
4863 { "bluestore_csum_type", "none", 0},
4864 { "bluestore_default_buffered_read", "true", "false", 0 },
4865 { "bluestore_default_buffered_write", "true", 0 },
4866 { "bluestore_sync_submit_transaction", "true", "false", 0 },
4869 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4872 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixPreferDeferred
) {
4873 if (string(GetParam()) != "bluestore")
4876 const char *m
[][10] = {
4877 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4878 { "max_write", "65536", 0 },
4879 { "max_size", "1048576", 0 },
4880 { "alignment", "512", 0 },
4881 { "bluestore_max_blob_size", "262144", 0 },
4882 { "bluestore_compression_mode", "force", "none", 0},
4883 { "bluestore_prefer_deferred_size", "32768", "0", 0},
4886 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4888 #endif // WITH_BLUESTORE
4890 TEST_P(StoreTest
, AttrSynthetic
) {
4891 MixedGenerator
gen(447);
4892 gen_type
rng(time(NULL
));
4893 coll_t
cid(spg_t(pg_t(0,447),shard_id_t::NO_SHARD
));
4895 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
, 40*1024, 4*1024, 0);
4897 for (int i
= 0; i
< 500; ++i
) {
4898 if (!(i
% 10)) cerr
<< "seeding object " << i
<< std::endl
;
4901 for (int i
= 0; i
< 1000; ++i
) {
4903 cerr
<< "Op " << i
<< std::endl
;
4904 test_obj
.print_internal_state();
4906 boost::uniform_int
<> true_false(0, 99);
4907 int val
= true_false(rng
);
4910 } else if (val
> 93) {
4912 } else if (val
> 75) {
4914 } else if (val
> 47) {
4915 test_obj
.setattrs();
4916 } else if (val
> 45) {
4918 } else if (val
> 37) {
4920 } else if (val
> 30) {
4921 test_obj
.getattrs();
4926 test_obj
.wait_for_done();
4927 test_obj
.shutdown();
4930 TEST_P(StoreTest
, HashCollisionTest
) {
4931 int64_t poolid
= 11;
4932 coll_t
cid(spg_t(pg_t(0,poolid
),shard_id_t::NO_SHARD
));
4934 auto ch
= store
->create_new_collection(cid
);
4936 ObjectStore::Transaction t
;
4937 t
.create_collection(cid
, 0);
4938 r
= queue_transaction(store
, ch
, std::move(t
));
4942 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
4943 set
<ghobject_t
> created
;
4944 for (int n
= 0; n
< 10; ++n
) {
4946 sprintf(nbuf
, "n%d", n
);
4947 for (int i
= 0; i
< 1000; ++i
) {
4949 sprintf(buf
, "%d", i
);
4951 cerr
<< "Object n" << n
<< " "<< i
<< std::endl
;
4953 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, 0, poolid
, string(nbuf
)));
4955 ObjectStore::Transaction t
;
4957 r
= queue_transaction(store
, ch
, std::move(t
));
4960 created
.insert(hoid
);
4963 vector
<ghobject_t
> objects
;
4964 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
, &objects
, 0);
4966 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
4967 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
4968 ASSERT_TRUE(listed
.size() == created
.size());
4971 ghobject_t current
, next
;
4973 r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 60,
4976 ASSERT_TRUE(sorted(objects
));
4977 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
4980 if (listed
.count(*i
))
4981 cerr
<< *i
<< " repeated" << std::endl
;
4984 if (objects
.size() < 50) {
4985 ASSERT_TRUE(next
.is_max());
4991 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
4992 ASSERT_TRUE(listed
.size() == created
.size());
4993 for (set
<ghobject_t
>::iterator i
= listed
.begin();
4996 ASSERT_TRUE(created
.count(*i
));
4999 for (set
<ghobject_t
>::iterator i
= created
.begin();
5002 ObjectStore::Transaction t
;
5004 r
= queue_transaction(store
, ch
, std::move(t
));
5007 ObjectStore::Transaction t
;
5008 t
.remove_collection(cid
);
5009 r
= queue_transaction(store
, ch
, std::move(t
));
5013 TEST_P(StoreTest
, ScrubTest
) {
5014 int64_t poolid
= 111;
5015 coll_t
cid(spg_t(pg_t(0, poolid
),shard_id_t(1)));
5017 auto ch
= store
->create_new_collection(cid
);
5019 ObjectStore::Transaction t
;
5020 t
.create_collection(cid
, 0);
5021 r
= queue_transaction(store
, ch
, std::move(t
));
5024 string base
= "aaaaa";
5025 set
<ghobject_t
> created
;
5026 for (int i
= 0; i
< 1000; ++i
) {
5028 sprintf(buf
, "%d", i
);
5030 cerr
<< "Object " << i
<< std::endl
;
5032 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, i
,
5034 ghobject_t::NO_GEN
, shard_id_t(1));
5036 ObjectStore::Transaction t
;
5038 r
= queue_transaction(store
, ch
, std::move(t
));
5041 created
.insert(hoid
);
5044 // Add same hobject_t but different generation
5046 ghobject_t
hoid1(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""),
5047 ghobject_t::NO_GEN
, shard_id_t(1));
5048 ghobject_t
hoid2(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)1, shard_id_t(1));
5049 ghobject_t
hoid3(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)2, shard_id_t(1));
5050 ObjectStore::Transaction t
;
5051 t
.touch(cid
, hoid1
);
5052 t
.touch(cid
, hoid2
);
5053 t
.touch(cid
, hoid3
);
5054 r
= queue_transaction(store
, ch
, std::move(t
));
5055 created
.insert(hoid1
);
5056 created
.insert(hoid2
);
5057 created
.insert(hoid3
);
5061 vector
<ghobject_t
> objects
;
5062 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
5063 INT_MAX
, &objects
, 0);
5065 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
5066 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
5067 ASSERT_TRUE(listed
.size() == created
.size());
5070 ghobject_t current
, next
;
5072 r
= store
->collection_list(ch
, current
, ghobject_t::get_max(), 60,
5075 ASSERT_TRUE(sorted(objects
));
5076 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5077 i
!= objects
.end(); ++i
) {
5078 if (listed
.count(*i
))
5079 cerr
<< *i
<< " repeated" << std::endl
;
5082 if (objects
.size() < 50) {
5083 ASSERT_TRUE(next
.is_max());
5087 current
= next
.get_boundary();
5089 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
5090 ASSERT_TRUE(listed
.size() == created
.size());
5091 for (set
<ghobject_t
>::iterator i
= listed
.begin();
5094 ASSERT_TRUE(created
.count(*i
));
5097 for (set
<ghobject_t
>::iterator i
= created
.begin();
5100 ObjectStore::Transaction t
;
5102 r
= queue_transaction(store
, ch
, std::move(t
));
5105 ObjectStore::Transaction t
;
5106 t
.remove_collection(cid
);
5107 r
= queue_transaction(store
, ch
, std::move(t
));
5112 TEST_P(StoreTest
, OMapTest
) {
5114 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5115 auto ch
= store
->create_new_collection(cid
);
5118 ObjectStore::Transaction t
;
5119 t
.create_collection(cid
, 0);
5120 r
= queue_transaction(store
, ch
, std::move(t
));
5124 map
<string
, bufferlist
> attrs
;
5126 ObjectStore::Transaction t
;
5128 t
.omap_clear(cid
, hoid
);
5129 map
<string
, bufferlist
> start_set
;
5130 t
.omap_setkeys(cid
, hoid
, start_set
);
5131 r
= queue_transaction(store
, ch
, std::move(t
));
5135 for (int i
= 0; i
< 100; i
++) {
5137 std::cout
<< "On iteration " << i
<< std::endl
;
5139 ObjectStore::Transaction t
;
5141 map
<string
, bufferlist
> cur_attrs
;
5142 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5144 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5147 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5149 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5150 if (cur_attrs
.count(j
->first
) > 0) {
5151 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5154 ASSERT_EQ(correct
, true);
5156 ASSERT_EQ(attrs
.size(), cur_attrs
.size());
5159 snprintf(buf
, sizeof(buf
), "%d", i
);
5161 bufferptr
bp(buf
, strlen(buf
) + 1);
5163 map
<string
, bufferlist
> to_add
;
5164 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5165 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5166 t
.omap_setkeys(cid
, hoid
, to_add
);
5167 r
= queue_transaction(store
, ch
, std::move(t
));
5172 while (attrs
.size()) {
5174 std::cout
<< "removal: On iteration " << i
<< std::endl
;
5176 ObjectStore::Transaction t
;
5178 map
<string
, bufferlist
> cur_attrs
;
5179 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5181 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5184 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5186 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5187 if (cur_attrs
.count(j
->first
) > 0) {
5188 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5191 ASSERT_EQ(correct
, true);
5194 string to_remove
= attrs
.begin()->first
;
5195 t
.omap_rmkey(cid
, hoid
, to_remove
);
5196 r
= queue_transaction(store
, ch
, std::move(t
));
5199 attrs
.erase(to_remove
);
5206 bl1
.append("omap_header");
5207 ObjectStore::Transaction t
;
5208 t
.omap_setheader(cid
, hoid
, bl1
);
5209 r
= queue_transaction(store
, ch
, std::move(t
));
5211 t
= ObjectStore::Transaction();
5214 bl2
.append("value");
5215 map
<string
, bufferlist
> to_add
;
5216 to_add
.insert(pair
<string
, bufferlist
>("key", bl2
));
5217 t
.omap_setkeys(cid
, hoid
, to_add
);
5218 r
= queue_transaction(store
, ch
, std::move(t
));
5222 map
<string
, bufferlist
> cur_attrs
;
5223 r
= store
->omap_get(ch
, hoid
, &bl3
, &cur_attrs
);
5225 ASSERT_EQ(cur_attrs
.size(), size_t(1));
5226 ASSERT_TRUE(bl_eq(bl1
, bl3
));
5229 r
= store
->omap_get_keys(ch
, hoid
, &keys
);
5231 ASSERT_EQ(keys
.size(), size_t(1));
5234 // test omap_clear, omap_rmkey_range
5237 map
<string
,bufferlist
> to_set
;
5238 for (int n
=0; n
<10; ++n
) {
5239 to_set
[stringify(n
)].append("foo");
5243 ObjectStore::Transaction t
;
5244 t
.remove(cid
, hoid
);
5246 t
.omap_setheader(cid
, hoid
, h
);
5247 t
.omap_setkeys(cid
, hoid
, to_set
);
5248 r
= queue_transaction(store
, ch
, std::move(t
));
5252 ObjectStore::Transaction t
;
5253 t
.omap_rmkeyrange(cid
, hoid
, "3", "7");
5254 r
= queue_transaction(store
, ch
, std::move(t
));
5259 map
<string
,bufferlist
> m
;
5260 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5261 ASSERT_EQ(6u, hdr
.length());
5262 ASSERT_TRUE(m
.count("2"));
5263 ASSERT_TRUE(!m
.count("3"));
5264 ASSERT_TRUE(!m
.count("6"));
5265 ASSERT_TRUE(m
.count("7"));
5266 ASSERT_TRUE(m
.count("8"));
5267 //cout << m << std::endl;
5268 ASSERT_EQ(6u, m
.size());
5271 ObjectStore::Transaction t
;
5272 t
.omap_clear(cid
, hoid
);
5273 r
= queue_transaction(store
, ch
, std::move(t
));
5278 map
<string
,bufferlist
> m
;
5279 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5280 ASSERT_EQ(0u, hdr
.length());
5281 ASSERT_EQ(0u, m
.size());
5285 ObjectStore::Transaction t
;
5286 t
.remove(cid
, hoid
);
5287 t
.remove_collection(cid
);
5288 r
= queue_transaction(store
, ch
, std::move(t
));
5292 TEST_P(StoreTest
, OMapIterator
) {
5294 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5296 auto ch
= store
->create_new_collection(cid
);
5299 ObjectStore::Transaction t
;
5300 t
.create_collection(cid
, 0);
5301 r
= queue_transaction(store
, ch
, std::move(t
));
5305 map
<string
, bufferlist
> attrs
;
5307 ObjectStore::Transaction t
;
5309 t
.omap_clear(cid
, hoid
);
5310 map
<string
, bufferlist
> start_set
;
5311 t
.omap_setkeys(cid
, hoid
, start_set
);
5312 r
= queue_transaction(store
, ch
, std::move(t
));
5315 ObjectMap::ObjectMapIterator iter
;
5318 for (int i
= 0; i
< 100; i
++) {
5320 std::cout
<< "On iteration " << i
<< std::endl
;
5324 // FileStore may deadlock two active iterators over the same data
5325 iter
= ObjectMap::ObjectMapIterator();
5327 iter
= store
->get_omap_iterator(ch
, hoid
);
5328 for (iter
->seek_to_first(), count
=0; iter
->valid(); iter
->next(), count
++) {
5329 string key
= iter
->key();
5330 bufferlist value
= iter
->value();
5331 correct
= attrs
.count(key
) && (string(value
.c_str()) == string(attrs
[key
].c_str()));
5333 if (attrs
.count(key
) > 0) {
5334 std::cout
<< "key " << key
<< "in omap , " << value
.c_str() << " : " << attrs
[key
].c_str() << std::endl
;
5337 std::cout
<< "key " << key
<< "should not exists in omap" << std::endl
;
5339 ASSERT_EQ(correct
, true);
5341 ASSERT_EQ((int)attrs
.size(), count
);
5343 // FileStore may deadlock an active iterator vs queue_transaction
5344 iter
= ObjectMap::ObjectMapIterator();
5347 snprintf(buf
, sizeof(buf
), "%d", i
);
5349 bufferptr
bp(buf
, strlen(buf
) + 1);
5351 map
<string
, bufferlist
> to_add
;
5352 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5353 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5354 ObjectStore::Transaction t
;
5355 t
.omap_setkeys(cid
, hoid
, to_add
);
5356 r
= queue_transaction(store
, ch
, std::move(t
));
5360 iter
= store
->get_omap_iterator(ch
, hoid
);
5362 string bound_key
= "key-5";
5363 iter
->lower_bound(bound_key
);
5364 correct
= bound_key
<= iter
->key();
5366 std::cout
<< "lower bound, bound key is " << bound_key
<< " < iter key is " << iter
->key() << std::endl
;
5368 ASSERT_EQ(correct
, true);
5370 iter
->upper_bound(bound_key
);
5371 correct
= iter
->key() > bound_key
;
5373 std::cout
<< "upper bound, bound key is " << bound_key
<< " >= iter key is " << iter
->key() << std::endl
;
5375 ASSERT_EQ(correct
, true);
5377 // FileStore may deadlock an active iterator vs queue_transaction
5378 iter
= ObjectMap::ObjectMapIterator();
5380 ObjectStore::Transaction t
;
5381 t
.remove(cid
, hoid
);
5382 t
.remove_collection(cid
);
5383 r
= queue_transaction(store
, ch
, std::move(t
));
5388 TEST_P(StoreTest
, XattrTest
) {
5390 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5392 for (unsigned i
= 0; i
< 10000; ++i
) {
5396 for (unsigned i
= 0; i
< 10; ++i
) {
5400 auto ch
= store
->create_new_collection(cid
);
5402 ObjectStore::Transaction t
;
5403 t
.create_collection(cid
, 0);
5405 r
= queue_transaction(store
, ch
, std::move(t
));
5409 map
<string
, bufferlist
> attrs
;
5411 ObjectStore::Transaction t
;
5412 t
.setattr(cid
, hoid
, "attr1", small
);
5413 attrs
["attr1"] = small
;
5414 t
.setattr(cid
, hoid
, "attr2", big
);
5415 attrs
["attr2"] = big
;
5416 t
.setattr(cid
, hoid
, "attr3", small
);
5417 attrs
["attr3"] = small
;
5418 t
.setattr(cid
, hoid
, "attr1", small
);
5419 attrs
["attr1"] = small
;
5420 t
.setattr(cid
, hoid
, "attr4", big
);
5421 attrs
["attr4"] = big
;
5422 t
.setattr(cid
, hoid
, "attr3", big
);
5423 attrs
["attr3"] = big
;
5424 r
= queue_transaction(store
, ch
, std::move(t
));
5428 map
<string
, bufferptr
> aset
;
5429 store
->getattrs(ch
, hoid
, aset
);
5430 ASSERT_EQ(aset
.size(), attrs
.size());
5431 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
5435 bl
.push_back(i
->second
);
5436 ASSERT_TRUE(attrs
[i
->first
] == bl
);
5440 ObjectStore::Transaction t
;
5441 t
.rmattr(cid
, hoid
, "attr2");
5442 attrs
.erase("attr2");
5443 r
= queue_transaction(store
, ch
, std::move(t
));
5448 store
->getattrs(ch
, hoid
, aset
);
5449 ASSERT_EQ(aset
.size(), attrs
.size());
5450 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
5454 bl
.push_back(i
->second
);
5455 ASSERT_TRUE(attrs
[i
->first
] == bl
);
5459 r
= store
->getattr(ch
, hoid
, "attr2", bp
);
5460 ASSERT_EQ(r
, -ENODATA
);
5462 r
= store
->getattr(ch
, hoid
, "attr3", bp
);
5466 ASSERT_TRUE(bl2
== attrs
["attr3"]);
5468 ObjectStore::Transaction t
;
5469 t
.remove(cid
, hoid
);
5470 t
.remove_collection(cid
);
5471 r
= queue_transaction(store
, ch
, std::move(t
));
5477 unsigned num_objects
,
5478 unsigned common_suffix_size
,
5481 coll_t
cid(spg_t(pg_t(0,52),shard_id_t::NO_SHARD
));
5482 coll_t
tid(spg_t(pg_t(1<<common_suffix_size
,52),shard_id_t::NO_SHARD
));
5483 auto ch
= store
->create_new_collection(cid
);
5484 auto tch
= store
->create_new_collection(tid
);
5487 ObjectStore::Transaction t
;
5488 t
.create_collection(cid
, common_suffix_size
);
5489 r
= queue_transaction(store
, ch
, std::move(t
));
5493 small
.append("small");
5495 ObjectStore::Transaction t
;
5496 for (uint32_t i
= 0; i
< (2 - (int)clones
)*num_objects
; ++i
) {
5497 stringstream objname
;
5498 objname
<< "obj" << i
;
5499 ghobject_t
a(hobject_t(
5503 i
<<common_suffix_size
,
5505 t
.write(cid
, a
, 0, small
.length(), small
,
5506 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
5508 objname
<< "-clone";
5509 ghobject_t
b(hobject_t(
5513 i
<<common_suffix_size
,
5518 r
= queue_transaction(store
, ch
, std::move(t
));
5520 t
= ObjectStore::Transaction();
5523 r
= queue_transaction(store
, ch
, std::move(t
));
5527 ObjectStore::Transaction t
;
5528 t
.create_collection(tid
, common_suffix_size
+ 1);
5529 t
.split_collection(cid
, common_suffix_size
+1, 1<<common_suffix_size
, tid
);
5530 r
= queue_transaction(store
, ch
, std::move(t
));
5536 vector
<ghobject_t
> objects
;
5537 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
5538 INT_MAX
, &objects
, 0);
5540 ASSERT_EQ(objects
.size(), num_objects
);
5541 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5544 ASSERT_EQ(!!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
5548 r
= store
->collection_list(tch
, ghobject_t(), ghobject_t::get_max(),
5549 INT_MAX
, &objects
, 0);
5551 ASSERT_EQ(objects
.size(), num_objects
);
5552 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5555 ASSERT_EQ(!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
5558 // merge them again!
5560 ObjectStore::Transaction t
;
5561 t
.merge_collection(tid
, cid
, common_suffix_size
);
5562 r
= queue_transaction(store
, ch
, std::move(t
));
5566 // check and clean up
5567 ObjectStore::Transaction t
;
5569 vector
<ghobject_t
> objects
;
5570 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
5571 INT_MAX
, &objects
, 0);
5573 ASSERT_EQ(objects
.size(), num_objects
* 2); // both halves
5575 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5581 r
= queue_transaction(store
, ch
, std::move(t
));
5583 t
= ObjectStore::Transaction();
5587 t
.remove_collection(cid
);
5588 r
= queue_transaction(store
, ch
, std::move(t
));
5592 ASSERT_TRUE(!store
->collection_exists(tid
));
5595 TEST_P(StoreTest
, ColSplitTest0
) {
5596 colsplittest(store
.get(), 10, 5, false);
5598 TEST_P(StoreTest
, ColSplitTest1
) {
5599 colsplittest(store
.get(), 10000, 11, false);
5601 TEST_P(StoreTest
, ColSplitTest1Clones
) {
5602 colsplittest(store
.get(), 10000, 11, true);
5604 TEST_P(StoreTest
, ColSplitTest2
) {
5605 colsplittest(store
.get(), 100, 7, false);
5607 TEST_P(StoreTest
, ColSplitTest2Clones
) {
5608 colsplittest(store
.get(), 100, 7, true);
5612 TEST_P(StoreTest
, ColSplitTest3
) {
5613 colsplittest(store
.get(), 100000, 25);
5617 void test_merge_skewed(ObjectStore
*store
,
5618 unsigned base
, unsigned bits
,
5619 unsigned anum
, unsigned bnum
)
5621 cout
<< __func__
<< " 0x" << std::hex
<< base
<< std::dec
5623 << " anum " << anum
<< " bnum " << bnum
<< std::endl
;
5625 make merge source pgs have radically different # of objects in them,
5626 which should trigger different splitting in filestore, and verify that
5627 post-merge all objects are accessible.
5630 coll_t
a(spg_t(pg_t(base
, 0), shard_id_t::NO_SHARD
));
5631 coll_t
b(spg_t(pg_t(base
| (1<<bits
), 0), shard_id_t::NO_SHARD
));
5633 auto cha
= store
->create_new_collection(a
);
5634 auto chb
= store
->create_new_collection(b
);
5636 ObjectStore::Transaction t
;
5637 t
.create_collection(a
, bits
+ 1);
5638 r
= queue_transaction(store
, cha
, std::move(t
));
5642 ObjectStore::Transaction t
;
5643 t
.create_collection(b
, bits
+ 1);
5644 r
= queue_transaction(store
, chb
, std::move(t
));
5649 small
.append("small");
5650 string suffix
= "ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooaaaaaaaaaa";
5651 set
<ghobject_t
> aobjects
, bobjects
;
5654 ObjectStore::Transaction t
;
5655 for (unsigned i
= 0; i
< 1000; ++i
) {
5656 string objname
= "a" + stringify(i
) + suffix
;
5657 ghobject_t
o(hobject_t(
5664 t
.write(a
, o
, 0, small
.length(), small
, 0);
5666 r
= queue_transaction(store
, cha
, std::move(t
));
5668 t
= ObjectStore::Transaction();
5671 r
= queue_transaction(store
, cha
, std::move(t
));
5676 ObjectStore::Transaction t
;
5677 for (unsigned i
= 0; i
< 10; ++i
) {
5678 string objname
= "b" + stringify(i
) + suffix
;
5679 ghobject_t
o(hobject_t(
5683 (i
<<(base
+1)) | base
| (1<<bits
),
5686 t
.write(b
, o
, 0, small
.length(), small
, 0);
5688 r
= queue_transaction(store
, chb
, std::move(t
));
5690 t
= ObjectStore::Transaction();
5693 r
= queue_transaction(store
, chb
, std::move(t
));
5699 ObjectStore::Transaction t
;
5700 t
.merge_collection(b
, a
, bits
);
5701 r
= queue_transaction(store
, cha
, std::move(t
));
5707 vector
<ghobject_t
> got
;
5708 store
->collection_list(cha
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5710 set
<ghobject_t
> gotset
;
5711 for (auto& o
: got
) {
5712 ASSERT_TRUE(aobjects
.count(o
) || bobjects
.count(o
));
5715 // check both listing and stat-ability (different code paths!)
5717 for (auto& o
: aobjects
) {
5718 ASSERT_TRUE(gotset
.count(o
));
5719 int r
= store
->stat(cha
, o
, &st
, false);
5722 for (auto& o
: bobjects
) {
5723 ASSERT_TRUE(gotset
.count(o
));
5724 int r
= store
->stat(cha
, o
, &st
, false);
5731 ObjectStore::Transaction t
;
5732 for (auto &o
: aobjects
) {
5735 r
= queue_transaction(store
, cha
, std::move(t
));
5739 ObjectStore::Transaction t
;
5740 for (auto &o
: bobjects
) {
5743 t
.remove_collection(a
);
5744 r
= queue_transaction(store
, cha
, std::move(t
));
5749 TEST_P(StoreTest
, MergeSkewed
) {
5750 if (string(GetParam()) != "filestore")
5753 // this is sufficient to exercise merges with different hashing levels
5754 test_merge_skewed(store
.get(), 0xf, 4, 10, 10000);
5755 test_merge_skewed(store
.get(), 0xf, 4, 10000, 10);
5758 // this covers a zillion variations that all boil down to the same thing
5759 for (unsigned base = 3; base < 0x1000; base *= 5) {
5762 for (bits = 0; t; t >>= 1) {
5765 for (unsigned b = bits; b < bits + 10; b += 3) {
5766 for (auto anum : { 10, 1000, 10000 }) {
5767 for (auto bnum : { 10, 1000, 10000 }) {
5771 test_merge_skewed(store.get(), base, b, anum, bnum);
5781 * This test tests adding two different groups
5782 * of objects, each with 1 common prefix and 1
5783 * different prefix. We then remove half
5784 * in order to verify that the merging correctly
5785 * stops at the common prefix subdir. See bug
5787 TEST_P(StoreTest
, TwoHash
) {
5790 auto ch
= store
->create_new_collection(cid
);
5792 ObjectStore::Transaction t
;
5793 t
.create_collection(cid
, 0);
5794 r
= queue_transaction(store
, ch
, std::move(t
));
5797 std::cout
<< "Making objects" << std::endl
;
5798 for (int i
= 0; i
< 360; ++i
) {
5799 ObjectStore::Transaction t
;
5803 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5806 o
.hobj
.set_hash((i
<< 16) | 0xB1);
5808 r
= queue_transaction(store
, ch
, std::move(t
));
5811 std::cout
<< "Removing half" << std::endl
;
5812 for (int i
= 1; i
< 8; ++i
) {
5813 ObjectStore::Transaction t
;
5816 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5818 r
= queue_transaction(store
, ch
, std::move(t
));
5821 std::cout
<< "Checking" << std::endl
;
5822 for (int i
= 1; i
< 8; ++i
) {
5823 ObjectStore::Transaction t
;
5825 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5827 bool exists
= store
->exists(ch
, o
);
5828 ASSERT_EQ(exists
, false);
5832 o
.hobj
.set_hash(0xA1);
5834 bool exists
= store
->exists(ch
, o
);
5835 ASSERT_EQ(exists
, true);
5837 std::cout
<< "Cleanup" << std::endl
;
5838 for (int i
= 0; i
< 360; ++i
) {
5839 ObjectStore::Transaction t
;
5841 o
.hobj
.set_hash((i
<< 16) | 0xA1);
5844 o
.hobj
.set_hash((i
<< 16) | 0xB1);
5846 r
= queue_transaction(store
, ch
, std::move(t
));
5849 ObjectStore::Transaction t
;
5850 t
.remove_collection(cid
);
5851 r
= queue_transaction(store
, ch
, std::move(t
));
5855 TEST_P(StoreTest
, Rename
) {
5856 coll_t
cid(spg_t(pg_t(0, 2122),shard_id_t::NO_SHARD
));
5857 ghobject_t
srcoid(hobject_t("src_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5858 ghobject_t
dstoid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5862 auto ch
= store
->create_new_collection(cid
);
5865 ObjectStore::Transaction t
;
5866 t
.create_collection(cid
, 0);
5867 t
.write(cid
, srcoid
, 0, a
.length(), a
);
5868 r
= queue_transaction(store
, ch
, std::move(t
));
5871 ASSERT_TRUE(store
->exists(ch
, srcoid
));
5873 ObjectStore::Transaction t
;
5874 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
5875 t
.write(cid
, srcoid
, 0, b
.length(), b
);
5876 t
.setattr(cid
, srcoid
, "attr", b
);
5877 r
= queue_transaction(store
, ch
, std::move(t
));
5880 ASSERT_TRUE(store
->exists(ch
, srcoid
));
5881 ASSERT_TRUE(store
->exists(ch
, dstoid
));
5884 store
->read(ch
, srcoid
, 0, 3, bl
);
5885 ASSERT_TRUE(bl_eq(b
, bl
));
5886 store
->read(ch
, dstoid
, 0, 3, bl
);
5887 ASSERT_TRUE(bl_eq(a
, bl
));
5890 ObjectStore::Transaction t
;
5891 t
.remove(cid
, dstoid
);
5892 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
5893 r
= queue_transaction(store
, ch
, std::move(t
));
5896 ASSERT_TRUE(store
->exists(ch
, dstoid
));
5897 ASSERT_FALSE(store
->exists(ch
, srcoid
));
5900 store
->read(ch
, dstoid
, 0, 3, bl
);
5901 ASSERT_TRUE(bl_eq(b
, bl
));
5904 ObjectStore::Transaction t
;
5905 t
.remove(cid
, dstoid
);
5906 t
.remove_collection(cid
);
5907 r
= queue_transaction(store
, ch
, std::move(t
));
5912 TEST_P(StoreTest
, MoveRename
) {
5913 coll_t
cid(spg_t(pg_t(0, 212),shard_id_t::NO_SHARD
));
5914 ghobject_t
temp_oid(hobject_t("tmp_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5915 ghobject_t
oid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
5916 auto ch
= store
->create_new_collection(cid
);
5919 ObjectStore::Transaction t
;
5920 t
.create_collection(cid
, 0);
5922 r
= queue_transaction(store
, ch
, std::move(t
));
5925 ASSERT_TRUE(store
->exists(ch
, oid
));
5926 bufferlist data
, attr
;
5927 map
<string
, bufferlist
> omap
;
5928 data
.append("data payload");
5929 attr
.append("attr value");
5930 omap
["omap_key"].append("omap value");
5932 ObjectStore::Transaction t
;
5933 t
.touch(cid
, temp_oid
);
5934 t
.write(cid
, temp_oid
, 0, data
.length(), data
);
5935 t
.setattr(cid
, temp_oid
, "attr", attr
);
5936 t
.omap_setkeys(cid
, temp_oid
, omap
);
5937 r
= queue_transaction(store
, ch
, std::move(t
));
5940 ASSERT_TRUE(store
->exists(ch
, temp_oid
));
5942 ObjectStore::Transaction t
;
5944 t
.collection_move_rename(cid
, temp_oid
, cid
, oid
);
5945 r
= queue_transaction(store
, ch
, std::move(t
));
5948 ASSERT_TRUE(store
->exists(ch
, oid
));
5949 ASSERT_FALSE(store
->exists(ch
, temp_oid
));
5952 r
= store
->read(ch
, oid
, 0, 1000, newdata
);
5954 ASSERT_TRUE(bl_eq(data
, newdata
));
5956 r
= store
->getattr(ch
, oid
, "attr", newattr
);
5958 ASSERT_TRUE(bl_eq(attr
, newattr
));
5960 keys
.insert("omap_key");
5961 map
<string
, bufferlist
> newomap
;
5962 r
= store
->omap_get_values(ch
, oid
, keys
, &newomap
);
5964 ASSERT_EQ(1u, newomap
.size());
5965 ASSERT_TRUE(newomap
.count("omap_key"));
5966 ASSERT_TRUE(bl_eq(omap
["omap_key"], newomap
["omap_key"]));
5969 ObjectStore::Transaction t
;
5971 t
.remove_collection(cid
);
5972 r
= queue_transaction(store
, ch
, std::move(t
));
5977 TEST_P(StoreTest
, BigRGWObjectName
) {
5978 coll_t
cid(spg_t(pg_t(0,12),shard_id_t::NO_SHARD
));
5981 "default.4106.50_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
5988 shard_id_t::NO_SHARD
);
5989 ghobject_t
oid2(oid
);
5990 oid2
.generation
= 17;
5991 ghobject_t
oidhead(oid
);
5992 oidhead
.generation
= ghobject_t::NO_GEN
;
5994 auto ch
= store
->create_new_collection(cid
);
5998 ObjectStore::Transaction t
;
5999 t
.create_collection(cid
, 0);
6000 t
.touch(cid
, oidhead
);
6001 t
.collection_move_rename(cid
, oidhead
, cid
, oid
);
6002 t
.touch(cid
, oidhead
);
6003 t
.collection_move_rename(cid
, oidhead
, cid
, oid2
);
6004 r
= queue_transaction(store
, ch
, std::move(t
));
6009 ObjectStore::Transaction t
;
6011 r
= queue_transaction(store
, ch
, std::move(t
));
6016 vector
<ghobject_t
> objects
;
6017 r
= store
->collection_list(ch
, ghobject_t(), ghobject_t::get_max(),
6018 INT_MAX
, &objects
, 0);
6020 ASSERT_EQ(objects
.size(), 1u);
6021 ASSERT_EQ(objects
[0], oid2
);
6024 ASSERT_FALSE(store
->exists(ch
, oid
));
6027 ObjectStore::Transaction t
;
6028 t
.remove(cid
, oid2
);
6029 t
.remove_collection(cid
);
6030 r
= queue_transaction(store
, ch
, std::move(t
));
6036 TEST_P(StoreTest
, SetAllocHint
) {
6038 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, 0, ""));
6039 auto ch
= store
->create_new_collection(cid
);
6042 ObjectStore::Transaction t
;
6043 t
.create_collection(cid
, 0);
6045 r
= queue_transaction(store
, ch
, std::move(t
));
6049 ObjectStore::Transaction t
;
6050 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
6051 r
= queue_transaction(store
, ch
, std::move(t
));
6055 ObjectStore::Transaction t
;
6056 t
.remove(cid
, hoid
);
6057 r
= queue_transaction(store
, ch
, std::move(t
));
6061 ObjectStore::Transaction t
;
6062 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
6063 r
= queue_transaction(store
, ch
, std::move(t
));
6067 ObjectStore::Transaction t
;
6068 t
.remove_collection(cid
);
6069 r
= queue_transaction(store
, ch
, std::move(t
));
6074 TEST_P(StoreTest
, TryMoveRename
) {
6076 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6077 ghobject_t
hoid2(hobject_t("test_hint2", "", CEPH_NOSNAP
, 0, -1, ""));
6078 auto ch
= store
->create_new_collection(cid
);
6081 ObjectStore::Transaction t
;
6082 t
.create_collection(cid
, 0);
6083 r
= queue_transaction(store
, ch
, std::move(t
));
6087 ObjectStore::Transaction t
;
6088 t
.try_rename(cid
, hoid
, hoid2
);
6089 r
= queue_transaction(store
, ch
, std::move(t
));
6093 ObjectStore::Transaction t
;
6095 r
= queue_transaction(store
, ch
, std::move(t
));
6099 ObjectStore::Transaction t
;
6100 t
.try_rename(cid
, hoid
, hoid2
);
6101 r
= queue_transaction(store
, ch
, std::move(t
));
6105 ASSERT_EQ(store
->stat(ch
, hoid
, &st
), -ENOENT
);
6106 ASSERT_EQ(store
->stat(ch
, hoid2
, &st
), 0);
6109 #if defined(WITH_BLUESTORE)
6110 TEST_P(StoreTest
, BluestoreOnOffCSumTest
) {
6111 if (string(GetParam()) != "bluestore")
6113 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6114 g_conf().apply_changes(nullptr);
6118 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
6120 auto ch
= store
->open_collection(cid
);
6123 auto ch
= store
->create_new_collection(cid
);
6125 ObjectStore::Transaction t
;
6126 t
.create_collection(cid
, 0);
6127 cerr
<< "Creating collection " << cid
<< std::endl
;
6128 r
= queue_transaction(store
, ch
, std::move(t
));
6132 //write with csum enabled followed by read with csum disabled
6133 size_t block_size
= 64*1024;
6134 ObjectStore::Transaction t
;
6135 bufferlist bl
, orig
;
6136 bl
.append(std::string(block_size
, 'a'));
6138 t
.remove(cid
, hoid
);
6139 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6140 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6141 cerr
<< "Remove then create" << std::endl
;
6142 r
= queue_transaction(store
, ch
, std::move(t
));
6145 SetVal(g_conf(), "bluestore_csum_type", "none");
6146 g_conf().apply_changes(nullptr);
6149 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6150 ASSERT_EQ((int)block_size
, r
);
6151 ASSERT_TRUE(bl_eq(orig
, in
));
6155 //write with csum disabled followed by read with csum enabled
6157 size_t block_size
= 64*1024;
6158 ObjectStore::Transaction t
;
6159 bufferlist bl
, orig
;
6160 bl
.append(std::string(block_size
, 'a'));
6162 t
.remove(cid
, hoid
);
6163 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6164 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6165 cerr
<< "Remove then create" << std::endl
;
6166 r
= queue_transaction(store
, ch
, std::move(t
));
6169 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6170 g_conf().apply_changes(nullptr);
6173 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6174 ASSERT_EQ((int)block_size
, r
);
6175 ASSERT_TRUE(bl_eq(orig
, in
));
6178 //'mixed' non-overlapping writes to the same blob
6180 ObjectStore::Transaction t
;
6181 bufferlist bl
, orig
;
6182 size_t block_size
= 8000;
6183 bl
.append(std::string(block_size
, 'a'));
6185 t
.remove(cid
, hoid
);
6186 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6187 cerr
<< "Remove then create" << std::endl
;
6188 r
= queue_transaction(store
, ch
, std::move(t
));
6191 SetVal(g_conf(), "bluestore_csum_type", "none");
6192 g_conf().apply_changes(nullptr);
6194 ObjectStore::Transaction t2
;
6195 t2
.write(cid
, hoid
, block_size
*2, bl
.length(), bl
);
6196 cerr
<< "Append 'unprotected'" << std::endl
;
6197 r
= queue_transaction(store
, ch
, std::move(t2
));
6201 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6202 ASSERT_EQ((int)block_size
, r
);
6203 ASSERT_TRUE(bl_eq(orig
, in
));
6205 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6206 ASSERT_EQ((int)block_size
, r
);
6207 ASSERT_TRUE(bl_eq(orig
, in
));
6209 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6210 g_conf().apply_changes(nullptr);
6212 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6213 ASSERT_EQ((int)block_size
, r
);
6214 ASSERT_TRUE(bl_eq(orig
, in
));
6216 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6217 ASSERT_EQ((int)block_size
, r
);
6218 ASSERT_TRUE(bl_eq(orig
, in
));
6221 //partially blob overwrite under a different csum enablement mode
6223 ObjectStore::Transaction t
;
6224 bufferlist bl
, orig
, orig2
;
6225 size_t block_size0
= 0x10000;
6226 size_t block_size
= 9000;
6227 size_t block_size2
= 5000;
6228 bl
.append(std::string(block_size0
, 'a'));
6229 t
.remove(cid
, hoid
);
6230 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6231 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6232 cerr
<< "Remove then create" << std::endl
;
6233 r
= queue_transaction(store
, ch
, std::move(t
));
6236 SetVal(g_conf(), "bluestore_csum_type", "none");
6237 g_conf().apply_changes(nullptr);
6239 ObjectStore::Transaction t2
;
6241 bl
.append(std::string(block_size
, 'b'));
6242 t2
.write(cid
, hoid
, 0, bl
.length(), bl
);
6243 t2
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6244 cerr
<< "Overwrite with unprotected data" << std::endl
;
6245 r
= queue_transaction(store
, ch
, std::move(t2
));
6250 orig
.append( std::string(block_size0
- block_size
, 'a'));
6253 r
= store
->read(ch
, hoid
, 0, block_size0
, in
);
6254 ASSERT_EQ((int)block_size0
, r
);
6255 ASSERT_TRUE(bl_eq(orig
, in
));
6257 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6258 ASSERT_EQ((int)block_size
, r
);
6259 ASSERT_TRUE(bl_eq(orig2
, in
));
6261 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6262 g_conf().apply_changes(nullptr);
6264 ObjectStore::Transaction t3
;
6266 bl
.append(std::string(block_size2
, 'c'));
6267 t3
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6268 cerr
<< "Overwrite with protected data" << std::endl
;
6269 r
= queue_transaction(store
, ch
, std::move(t3
));
6274 orig
.append( std::string(block_size
- block_size2
, 'b'));
6275 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6276 ASSERT_EQ((int)block_size
, r
);
6277 ASSERT_TRUE(bl_eq(orig
, in
));
6281 ObjectStore::Transaction t
;
6282 t
.remove(cid
, hoid
);
6283 t
.remove_collection(cid
);
6284 cerr
<< "Cleaning" << std::endl
;
6285 r
= queue_transaction(store
, ch
, std::move(t
));
6291 INSTANTIATE_TEST_SUITE_P(
6297 #if defined(WITH_BLUESTORE)
6302 // Note: instantiate all stores to preserve store numbering order only
6303 INSTANTIATE_TEST_SUITE_P(
6305 StoreTestSpecificAUSize
,
6309 #if defined(WITH_BLUESTORE)
6314 void doMany4KWritesTest(boost::scoped_ptr
<ObjectStore
>& store
,
6315 unsigned max_objects
,
6317 unsigned max_object_size
,
6318 unsigned max_write_size
,
6319 unsigned write_alignment
)
6321 MixedGenerator
gen(555);
6322 gen_type
rng(time(NULL
));
6323 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
6324 store_statfs_t res_stat
;
6326 SyntheticWorkloadState
test_obj(store
.get(),
6334 for (unsigned i
= 0; i
< max_objects
; ++i
) {
6335 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
6338 for (unsigned i
= 0; i
< max_ops
; ++i
) {
6340 cerr
<< "Op " << i
<< std::endl
;
6341 test_obj
.print_internal_state();
6345 test_obj
.wait_for_done();
6346 test_obj
.statfs(res_stat
);
6347 if (!(res_stat
.data_stored
<= max_object_size
) ||
6348 !(res_stat
.allocated
<= max_object_size
)) {
6349 // this will provide more insight on the mismatch and
6350 // helps to avoid any races during stats collection
6351 test_obj
.fsck(false);
6352 // retrieving stats once again and assert if still broken
6353 test_obj
.statfs(res_stat
);
6354 ASSERT_LE(res_stat
.data_stored
, max_object_size
);
6355 ASSERT_LE(res_stat
.allocated
, max_object_size
);
6357 test_obj
.shutdown();
6360 TEST_P(StoreTestSpecificAUSize
, Many4KWritesTest
) {
6361 if (string(GetParam()) != "bluestore")
6364 StartDeferred(0x10000);
6366 const unsigned max_object
= 4*1024*1024;
6367 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0);
6370 TEST_P(StoreTestSpecificAUSize
, Many4KWritesNoCSumTest
) {
6371 if (string(GetParam()) != "bluestore")
6373 StartDeferred(0x10000);
6374 SetVal(g_conf(), "bluestore_csum_type", "none");
6375 g_ceph_context
->_conf
.apply_changes(nullptr);
6376 const unsigned max_object
= 4*1024*1024;
6378 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0 );
6381 TEST_P(StoreTestSpecificAUSize
, TooManyBlobsTest
) {
6382 if (string(GetParam()) != "bluestore")
6384 StartDeferred(0x10000);
6385 const unsigned max_object
= 4*1024*1024;
6386 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0);
6389 #if defined(WITH_BLUESTORE)
6390 void get_mempool_stats(uint64_t* total_bytes
, uint64_t* total_items
)
6392 uint64_t onode_allocated
= mempool::bluestore_cache_onode::allocated_bytes();
6393 uint64_t other_allocated
= mempool::bluestore_cache_other::allocated_bytes();
6395 uint64_t onode_items
= mempool::bluestore_cache_onode::allocated_items();
6396 uint64_t other_items
= mempool::bluestore_cache_other::allocated_items();
6397 cout
<< "onode(" << onode_allocated
<< "/" << onode_items
6398 << ") other(" << other_allocated
<< "/" << other_items
6399 << ")" << std::endl
;
6400 *total_bytes
= onode_allocated
+ other_allocated
;
6401 *total_items
= onode_items
;
6404 TEST_P(StoreTestSpecificAUSize
, OnodeSizeTracking
) {
6406 if (string(GetParam()) != "bluestore")
6409 size_t block_size
= 4096;
6410 StartDeferred(block_size
);
6411 SetVal(g_conf(), "bluestore_compression_mode", "none");
6412 SetVal(g_conf(), "bluestore_csum_type", "none");
6413 SetVal(g_conf(), "bluestore_cache_size_hdd", "400000000");
6414 SetVal(g_conf(), "bluestore_cache_size_ssd", "400000000");
6415 g_conf().apply_changes(nullptr);
6419 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6420 size_t obj_size
= 4 * 1024 * 1024;
6421 uint64_t total_bytes
, total_bytes2
;
6422 uint64_t total_onodes
;
6423 get_mempool_stats(&total_bytes
, &total_onodes
);
6424 ASSERT_EQ(total_onodes
, 0u);
6426 auto ch
= store
->create_new_collection(cid
);
6428 ObjectStore::Transaction t
;
6429 t
.create_collection(cid
, 0);
6430 r
= queue_transaction(store
, ch
, std::move(t
));
6434 ObjectStore::Transaction t
;
6435 bufferlist bl
, orig
, orig2
;
6437 bl
.append(std::string(obj_size
, 'a'));
6438 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6439 r
= queue_transaction(store
, ch
, std::move(t
));
6442 get_mempool_stats(&total_bytes
, &total_onodes
);
6443 ASSERT_NE(total_bytes
, 0u);
6444 ASSERT_EQ(total_onodes
, 1u);
6447 ObjectStore::Transaction t
;
6448 t
.truncate(cid
, hoid
, 0);
6449 r
= queue_transaction(store
, ch
, std::move(t
));
6453 for(size_t i
= 0; i
< 1; ++i
) {
6455 bl
.append(std::string(block_size
* (i
+1), 'a'));
6456 for( size_t j
= 0; j
< obj_size
; j
+= bl
.length()) {
6457 ObjectStore::Transaction t
;
6458 t
.write(cid
, hoid
, j
, bl
.length(), bl
);
6459 r
= queue_transaction(store
, ch
, std::move(t
));
6462 get_mempool_stats(&total_bytes2
, &total_onodes
);
6463 ASSERT_NE(total_bytes2
, 0u);
6464 ASSERT_EQ(total_onodes
, 1u);
6467 cout
<<" mempool dump:\n";
6468 JSONFormatter
f(true);
6469 f
.open_object_section("transaction");
6477 for (size_t i
= 0; i
< obj_size
; i
+= 0x1000) {
6478 store
->read(ch
, hoid
, i
, 0x1000, bl
);
6481 get_mempool_stats(&total_bytes
, &total_onodes
);
6482 ASSERT_NE(total_bytes
, 0u);
6483 ASSERT_EQ(total_onodes
, 1u);
6486 cout
<<" mempool dump:\n";
6487 JSONFormatter
f(true);
6488 f
.open_object_section("transaction");
6495 ObjectStore::Transaction t
;
6496 t
.remove(cid
, hoid
);
6497 t
.remove_collection(cid
);
6498 cerr
<< "Cleaning" << std::endl
;
6499 r
= queue_transaction(store
, ch
, std::move(t
));
6504 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwrite
) {
6506 if (string(GetParam()) != "bluestore")
6509 size_t block_size
= 4096;
6510 StartDeferred(block_size
);
6511 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6512 g_conf().apply_changes(nullptr);
6516 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6518 const PerfCounters
* logger
= store
->get_perf_counters();
6520 auto ch
= store
->create_new_collection(cid
);
6522 ObjectStore::Transaction t
;
6523 t
.create_collection(cid
, 0);
6524 r
= queue_transaction(store
, ch
, std::move(t
));
6528 ObjectStore::Transaction t
;
6531 bl
.append(std::string(block_size
* 2, 'a'));
6532 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6533 r
= queue_transaction(store
, ch
, std::move(t
));
6537 // overwrite at the beginning
6538 ObjectStore::Transaction t
;
6541 bl
.append(std::string(block_size
, 'b'));
6542 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6543 r
= queue_transaction(store
, ch
, std::move(t
));
6548 ObjectStore::Transaction t
;
6551 bl
.append(std::string(block_size
* 2, 'c'));
6552 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6553 r
= queue_transaction(store
, ch
, std::move(t
));
6557 // append with a gap
6558 ObjectStore::Transaction t
;
6561 bl
.append(std::string(block_size
* 2, 'd'));
6562 t
.write(cid
, hoid
, block_size
* 5, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6563 r
= queue_transaction(store
, ch
, std::move(t
));
6567 // We need to issue a read to trigger cache stat update that refresh
6568 // perf counters. additionally we need to wait some time for mempool
6569 // thread to update stats.
6571 bufferlist bl
, expected
;
6572 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6573 ASSERT_EQ(r
, (int)block_size
);
6574 expected
.append(string(block_size
, 'b'));
6575 ASSERT_TRUE(bl_eq(expected
, bl
));
6576 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6577 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
6581 ObjectStore::Transaction t
;
6584 bl
.append(std::string(block_size
* 2, 'e'));
6586 // Currently we are unable to reuse blob when overwriting in a single step
6587 t
.write(cid
, hoid
, block_size
* 6, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6588 r
= queue_transaction(store
, ch
, std::move(t
));
6592 // We need to issue a read to trigger cache stat update that refresh
6593 // perf counters. additionally we need to wait some time for mempool
6594 // thread to update stats.
6596 bufferlist bl
, expected
;
6597 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6598 ASSERT_EQ(r
, (int)block_size
);
6599 expected
.append(string(block_size
, 'b'));
6600 ASSERT_TRUE(bl_eq(expected
, bl
));
6601 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6602 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
6606 ObjectStore::Transaction t
;
6609 bl
.append(std::string(block_size
, 'f'));
6611 t
.write(cid
, hoid
, block_size
* 4, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6612 r
= queue_transaction(store
, ch
, std::move(t
));
6616 // we need to wait some time for mempool
6617 // thread to update stats to be able to check blob/extent numbers from
6621 bufferlist bl
, expected
;
6622 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6623 ASSERT_EQ(r
, (int)block_size
);
6624 expected
.append(string(block_size
, 'b'));
6625 ASSERT_TRUE(bl_eq(expected
, bl
));
6629 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
6630 ASSERT_EQ(r
, (int)block_size
);
6631 expected
.append(string(block_size
, 'a'));
6632 ASSERT_TRUE(bl_eq(expected
, bl
));
6636 r
= store
->read(ch
, hoid
, block_size
* 2, block_size
* 2, bl
);
6637 ASSERT_EQ(r
, (int)block_size
* 2);
6638 expected
.append(string(block_size
* 2, 'c'));
6639 ASSERT_TRUE(bl_eq(expected
, bl
));
6643 r
= store
->read(ch
, hoid
, block_size
* 4, block_size
, bl
);
6644 ASSERT_EQ(r
, (int)block_size
);
6645 expected
.append(string(block_size
, 'f'));
6646 ASSERT_TRUE(bl_eq(expected
, bl
));
6650 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
, bl
);
6651 ASSERT_EQ(r
, (int)block_size
);
6652 expected
.append(string(block_size
, 'd'));
6653 ASSERT_TRUE(bl_eq(expected
, bl
));
6657 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
* 3, bl
);
6658 ASSERT_EQ(r
, (int)block_size
* 3);
6659 expected
.append(string(block_size
, 'd'));
6660 expected
.append(string(block_size
* 2, 'e'));
6661 ASSERT_TRUE(bl_eq(expected
, bl
));
6663 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6664 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
6668 ObjectStore::Transaction t
;
6669 t
.remove(cid
, hoid
);
6670 t
.remove_collection(cid
);
6671 cerr
<< "Cleaning" << std::endl
;
6672 r
= queue_transaction(store
, ch
, std::move(t
));
6677 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwriteReverse
) {
6679 if (string(GetParam()) != "bluestore")
6682 size_t block_size
= 4096;
6683 StartDeferred(block_size
);
6684 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6685 g_conf().apply_changes(nullptr);
6689 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6691 auto ch
= store
->create_new_collection(cid
);
6693 const PerfCounters
* logger
= store
->get_perf_counters();
6695 ObjectStore::Transaction t
;
6696 t
.create_collection(cid
, 0);
6697 r
= queue_transaction(store
, ch
, std::move(t
));
6701 ObjectStore::Transaction t
;
6704 bl
.append(std::string(block_size
* 2, 'a'));
6705 t
.write(cid
, hoid
, block_size
* 10, bl
.length(), bl
,
6706 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6707 r
= queue_transaction(store
, ch
, std::move(t
));
6712 ObjectStore::Transaction t
;
6715 bl
.append(std::string(block_size
, 'b'));
6716 t
.write(cid
, hoid
, block_size
* 9, bl
.length(), bl
,
6717 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6718 r
= queue_transaction(store
, ch
, std::move(t
));
6722 // We need to issue a read to trigger cache stat update that refresh
6723 // perf counters. additionally we need to wait some time for mempool
6724 // thread to update stats.
6726 bufferlist bl
, expected
;
6727 r
= store
->read(ch
, hoid
, block_size
* 9, block_size
* 2, bl
);
6728 ASSERT_EQ(r
, (int)block_size
* 2);
6729 expected
.append(string(block_size
, 'b'));
6730 expected
.append(string(block_size
, 'a'));
6731 ASSERT_TRUE(bl_eq(expected
, bl
));
6732 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6733 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
6738 // prepend existing with a gap
6739 ObjectStore::Transaction t
;
6742 bl
.append(std::string(block_size
, 'c'));
6743 t
.write(cid
, hoid
, block_size
* 7, bl
.length(), bl
,
6744 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6745 r
= queue_transaction(store
, ch
, std::move(t
));
6749 // We need to issue a read to trigger cache stat update that refresh
6750 // perf counters. additionally we need to wait some time for mempool
6751 // thread to update stats.
6753 bufferlist bl
, expected
;
6754 r
= store
->read(ch
, hoid
, block_size
* 7, block_size
* 3, bl
);
6755 ASSERT_EQ(r
, (int)block_size
* 3);
6756 expected
.append(string(block_size
, 'c'));
6757 expected
.append(string(block_size
, 0));
6758 expected
.append(string(block_size
, 'b'));
6759 ASSERT_TRUE(bl_eq(expected
, bl
));
6760 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6761 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
6765 // append after existing with a gap
6766 ObjectStore::Transaction t
;
6769 bl
.append(std::string(block_size
, 'd'));
6770 t
.write(cid
, hoid
, block_size
* 13, bl
.length(), bl
,
6771 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6772 r
= queue_transaction(store
, ch
, std::move(t
));
6776 // We need to issue a read to trigger cache stat update that refresh
6777 // perf counters. additionally we need to wait some time for mempool
6778 // thread to update stats.
6780 bufferlist bl
, expected
;
6781 r
= store
->read(ch
, hoid
, block_size
* 11, block_size
* 3, bl
);
6782 ASSERT_EQ(r
, (int)block_size
* 3);
6783 expected
.append(string(block_size
, 'a'));
6784 expected
.append(string(block_size
, 0));
6785 expected
.append(string(block_size
, 'd'));
6786 ASSERT_TRUE(bl_eq(expected
, bl
));
6787 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6788 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
6792 // append twice to the next max_blob slot
6793 ObjectStore::Transaction t
;
6796 bl
.append(std::string(block_size
, 'e'));
6797 t
.write(cid
, hoid
, block_size
* 17, bl
.length(), bl
,
6798 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6799 t
.write(cid
, hoid
, block_size
* 19, bl
.length(), bl
,
6800 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6801 r
= queue_transaction(store
, ch
, std::move(t
));
6805 // We need to issue a read to trigger cache stat update that refresh
6806 // perf counters. additionally we need to wait some time for mempool
6807 // thread to update stats.
6809 bufferlist bl
, expected
;
6810 r
= store
->read(ch
, hoid
, block_size
* 17, block_size
* 3, bl
);
6811 ASSERT_EQ(r
, (int)block_size
* 3);
6812 expected
.append(string(block_size
, 'e'));
6813 expected
.append(string(block_size
, 0));
6814 expected
.append(string(block_size
, 'e'));
6815 ASSERT_TRUE(bl_eq(expected
, bl
));
6816 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
6817 ASSERT_EQ(logger
->get(l_bluestore_extents
), 5u);
6820 // fill gaps at the second slot
6821 ObjectStore::Transaction t
;
6824 bl
.append(std::string(block_size
, 'f'));
6825 t
.write(cid
, hoid
, block_size
* 16, bl
.length(), bl
,
6826 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6827 t
.write(cid
, hoid
, block_size
* 18, bl
.length(), bl
,
6828 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6829 r
= queue_transaction(store
, ch
, std::move(t
));
6833 // We need to issue a read to trigger cache stat update that refresh
6834 // perf counters. additionally we need to wait some time for mempool
6835 // thread to update stats.
6837 bufferlist bl
, expected
;
6838 r
= store
->read(ch
, hoid
, block_size
* 16, block_size
* 4, bl
);
6839 ASSERT_EQ(r
, (int)block_size
* 4);
6840 expected
.append(string(block_size
, 'f'));
6841 expected
.append(string(block_size
, 'e'));
6842 expected
.append(string(block_size
, 'f'));
6843 expected
.append(string(block_size
, 'e'));
6844 ASSERT_TRUE(bl_eq(expected
, bl
));
6845 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
6846 ASSERT_EQ(logger
->get(l_bluestore_extents
), 4u);
6849 ObjectStore::Transaction t
;
6850 t
.remove(cid
, hoid
);
6851 t
.remove_collection(cid
);
6852 cerr
<< "Cleaning" << std::endl
;
6853 r
= queue_transaction(store
, ch
, std::move(t
));
6858 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnSmallOverwrite
) {
6860 if (string(GetParam()) != "bluestore")
6863 size_t block_size
= 4096;
6864 StartDeferred(block_size
);
6865 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6866 g_conf().apply_changes(nullptr);
6870 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6872 const PerfCounters
* logger
= store
->get_perf_counters();
6873 auto ch
= store
->create_new_collection(cid
);
6876 ObjectStore::Transaction t
;
6877 t
.create_collection(cid
, 0);
6878 r
= queue_transaction(store
, ch
, std::move(t
));
6882 ObjectStore::Transaction t
;
6885 bl
.append(std::string(block_size
, 'a'));
6886 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6887 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
,
6888 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6889 r
= queue_transaction(store
, ch
, std::move(t
));
6893 // write small into the gap
6894 ObjectStore::Transaction t
;
6897 bl
.append(std::string(3, 'b'));
6898 t
.write(cid
, hoid
, block_size
+ 1, bl
.length(), bl
,
6899 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6900 r
= queue_transaction(store
, ch
, std::move(t
));
6904 // We need to issue a read to trigger cache stat update that refresh
6905 // perf counters. additionally we need to wait some time for mempool
6906 // thread to update stats.
6908 bufferlist bl
, expected
;
6909 r
= store
->read(ch
, hoid
, 0, block_size
* 3, bl
);
6910 ASSERT_EQ(r
, (int)block_size
* 3);
6911 expected
.append(string(block_size
, 'a'));
6912 expected
.append(string(1, 0));
6913 expected
.append(string(3, 'b'));
6914 expected
.append(string(block_size
- 4, 0));
6915 expected
.append(string(block_size
, 'a'));
6916 ASSERT_TRUE(bl_eq(expected
, bl
));
6918 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6919 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
6922 ObjectStore::Transaction t
;
6923 t
.remove(cid
, hoid
);
6924 t
.remove_collection(cid
);
6925 cerr
<< "Cleaning" << std::endl
;
6926 r
= queue_transaction(store
, ch
, std::move(t
));
6931 // The test case to reproduce an issue when write happens
6932 // to a zero space between the extents sharing the same spanning blob
6933 // with unloaded shard map.
6934 // Second extent might be filled with zeros this way due to wrong result
6935 // returned by has_any_extents() call in do_write_small. The latter is caused
6936 // by incompletly loaded extent map.
6937 TEST_P(StoreTestSpecificAUSize
, SmallWriteOnShardedExtents
) {
6938 if (string(GetParam()) != "bluestore")
6941 size_t block_size
= 0x10000;
6942 StartDeferred(block_size
);
6944 SetVal(g_conf(), "bluestore_csum_type", "xxhash64");
6945 SetVal(g_conf(), "bluestore_max_blob_size", "524288"); // for sure
6947 g_conf().apply_changes(nullptr);
6951 ghobject_t
hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
6952 auto ch
= store
->create_new_collection(cid
);
6955 ObjectStore::Transaction t
;
6956 t
.create_collection(cid
, 0);
6957 r
= queue_transaction(store
, ch
, std::move(t
));
6961 //doing some tricks to have sharded extents/spanning objects
6962 ObjectStore::Transaction t
;
6965 bl
.append(std::string(0x80000, 'a'));
6966 t
.write(cid
, hoid1
, 0, bl
.length(), bl
, 0);
6967 t
.zero(cid
, hoid1
, 0x719e0, 0x75b0 );
6968 r
= queue_transaction(store
, ch
, std::move(t
));
6971 bl2
.append(std::string(0x70000, 'b'));
6972 t
.write(cid
, hoid1
, 0, bl2
.length(), bl2
, 0);
6973 t
.zero(cid
, hoid1
, 0, 0x50000);
6974 r
= queue_transaction(store
, ch
, std::move(t
));
6981 ch
= store
->open_collection(cid
);
6984 // do a write to zero space in between some extents sharing the same blob
6985 ObjectStore::Transaction t
;
6988 bl
.append(std::string(0x6520, 'c'));
6989 t
.write(cid
, hoid1
, 0x71c00, bl
.length(), bl
, 0);
6991 r
= queue_transaction(store
, ch
, std::move(t
));
6996 ObjectStore::Transaction t
;
6997 bufferlist bl
, expected
;
6999 r
= store
->read(ch
, hoid1
, 0x70000, 0x9c00, bl
);
7000 ASSERT_EQ(r
, (int)0x9c00);
7001 expected
.append(string(0x19e0, 'a'));
7002 expected
.append(string(0x220, 0));
7003 expected
.append(string(0x6520, 'c'));
7004 expected
.append(string(0xe70, 0));
7005 expected
.append(string(0xc70, 'a'));
7006 ASSERT_TRUE(bl_eq(expected
, bl
));
7012 ObjectStore::Transaction t
;
7013 t
.remove(cid
, hoid1
);
7014 t
.remove_collection(cid
);
7015 cerr
<< "Cleaning" << std::endl
;
7016 r
= queue_transaction(store
, ch
, std::move(t
));
7021 TEST_P(StoreTestSpecificAUSize
, ExcessiveFragmentation
) {
7022 if (string(GetParam()) != "bluestore")
7025 SetVal(g_conf(), "bluestore_block_size",
7026 stringify((uint64_t)2048 * 1024 * 1024).c_str());
7028 ASSERT_EQ(g_conf().get_val
<Option::size_t>("bluefs_alloc_size"),
7031 size_t block_size
= 0x10000;
7032 StartDeferred(block_size
);
7036 ghobject_t
hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
7037 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
7038 auto ch
= store
->create_new_collection(cid
);
7041 ObjectStore::Transaction t
;
7042 t
.create_collection(cid
, 0);
7043 r
= queue_transaction(store
, ch
, std::move(t
));
7047 // create 2x400MB objects in a way that their pextents are interleaved
7048 ObjectStore::Transaction t
;
7051 bl
.append(std::string(block_size
* 4, 'a')); // 256KB
7053 while(offs
< (uint64_t)400 * 1024 * 1024) {
7054 t
.write(cid
, hoid1
, offs
, bl
.length(), bl
, 0);
7055 t
.write(cid
, hoid2
, offs
, bl
.length(), bl
, 0);
7056 r
= queue_transaction(store
, ch
, std::move(t
));
7058 offs
+= bl
.length();
7059 if( (offs
% (100 * 1024 * 1024)) == 0) {
7060 std::cout
<<"written " << offs
<< std::endl
;
7064 std::cout
<<"written 800MB"<<std::endl
;
7066 // Partially overwrite objects with 100MB each leaving space
7067 // fragmented and occuping still unfragmented space at the end
7068 // So we'll have enough free space but it'll lack long enough (e.g. 1MB)
7069 // contiguous pextents.
7070 ObjectStore::Transaction t
;
7073 bl
.append(std::string(block_size
* 4, 'a'));
7075 while(offs
< 112 * 1024 * 1024) {
7076 t
.write(cid
, hoid1
, offs
, bl
.length(), bl
, 0);
7077 t
.write(cid
, hoid2
, offs
, bl
.length(), bl
, 0);
7078 r
= queue_transaction(store
, ch
, std::move(t
));
7080 // this will produce high fragmentation if original allocations
7082 offs
+= bl
.length();
7083 if( (offs
% (10 * 1024 * 1024)) == 0) {
7084 std::cout
<<"written " << offs
<< std::endl
;
7089 // remove one of the object producing much free space
7090 // and hence triggering bluefs rebalance.
7091 // Which should fail as there is no long enough pextents.
7092 ObjectStore::Transaction t
;
7093 t
.remove(cid
, hoid2
);
7094 r
= queue_transaction(store
, ch
, std::move(t
));
7099 (int)g_conf().get_val
<double>("bluestore_bluefs_balance_interval");
7100 std::cout
<<"sleeping... " << std::endl
;
7104 // touch another object to triggerrebalance
7105 ObjectStore::Transaction t
;
7106 t
.touch(cid
, hoid1
);
7107 r
= queue_transaction(store
, ch
, std::move(t
));
7111 ObjectStore::Transaction t
;
7112 t
.remove(cid
, hoid1
);
7113 t
.remove(cid
, hoid2
);
7114 t
.remove_collection(cid
);
7115 cerr
<< "Cleaning" << std::endl
;
7116 r
= queue_transaction(store
, ch
, std::move(t
));
7121 #endif //#if defined(WITH_BLUESTORE)
7123 TEST_P(StoreTest
, KVDBHistogramTest
) {
7124 if (string(GetParam()) != "bluestore")
7130 string
base("testobj.");
7132 bufferptr
ap(0x1000);
7133 memset(ap
.c_str(), 'a', 0x1000);
7135 auto ch
= store
->create_new_collection(cid
);
7137 ObjectStore::Transaction t
;
7138 t
.create_collection(cid
, 0);
7139 r
= queue_transaction(store
, ch
, std::move(t
));
7142 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
7143 ObjectStore::Transaction t
;
7145 snprintf(buf
, sizeof(buf
), "%d", i
);
7146 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
7147 t
.write(cid
, hoid
, 0, 0x1000, a
);
7148 r
= queue_transaction(store
, ch
, std::move(t
));
7152 Formatter
*f
= Formatter::create("store_test", "json-pretty", "json-pretty");
7153 store
->generate_db_histogram(f
);
7158 TEST_P(StoreTest
, KVDBStatsTest
) {
7159 if (string(GetParam()) != "bluestore")
7162 SetVal(g_conf(), "rocksdb_perf", "true");
7163 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
7164 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
7165 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
7166 g_ceph_context
->_conf
.apply_changes(nullptr);
7167 int r
= store
->umount();
7169 r
= store
->mount(); //to force rocksdb stats
7174 string
base("testobj.");
7176 bufferptr
ap(0x1000);
7177 memset(ap
.c_str(), 'a', 0x1000);
7179 auto ch
= store
->create_new_collection(cid
);
7181 ObjectStore::Transaction t
;
7182 t
.create_collection(cid
, 0);
7183 r
= queue_transaction(store
, ch
, std::move(t
));
7186 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
7187 ObjectStore::Transaction t
;
7189 snprintf(buf
, sizeof(buf
), "%d", i
);
7190 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
7191 t
.write(cid
, hoid
, 0, 0x1000, a
);
7192 r
= queue_transaction(store
, ch
, std::move(t
));
7196 Formatter
*f
= Formatter::create("store_test", "json-pretty", "json-pretty");
7197 store
->get_db_statistics(f
);
7202 #if defined(WITH_BLUESTORE)
7203 TEST_P(StoreTestSpecificAUSize
, garbageCollection
) {
7206 int buf_len
= 256 * 1024;
7207 int overlap_offset
= 64 * 1024;
7208 int write_offset
= buf_len
;
7209 if (string(GetParam()) != "bluestore")
7212 #define WRITE_AT(offset, _length) {\
7213 ObjectStore::Transaction t;\
7214 if ((uint64_t)_length != bl.length()) { \
7215 buffer::ptr p(bl.c_str(), _length);\
7217 bl_tmp.push_back(p);\
7218 t.write(cid, hoid, offset, bl_tmp.length(), bl_tmp);\
7220 t.write(cid, hoid, offset, bl.length(), bl);\
7222 r = queue_transaction(store, ch, std::move(t));\
7226 StartDeferred(65536);
7228 SetVal(g_conf(), "bluestore_compression_max_blob_size", "524288");
7229 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
7230 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
7231 SetVal(g_conf(), "bluestore_compression_mode", "force");
7232 g_conf().apply_changes(nullptr);
7234 auto ch
= store
->create_new_collection(cid
);
7236 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
7239 r
= store
->read(ch
, hoid
, 0, 5, in
);
7240 ASSERT_EQ(-ENOENT
, r
);
7243 ObjectStore::Transaction t
;
7244 t
.create_collection(cid
, 0);
7245 cerr
<< "Creating collection " << cid
<< std::endl
;
7246 r
= queue_transaction(store
, ch
, std::move(t
));
7251 data
.resize(buf_len
);
7255 bool exists
= store
->exists(ch
, hoid
);
7256 ASSERT_TRUE(!exists
);
7258 ObjectStore::Transaction t
;
7260 cerr
<< "Creating object " << hoid
<< std::endl
;
7261 r
= queue_transaction(store
, ch
, std::move(t
));
7264 exists
= store
->exists(ch
, hoid
);
7265 ASSERT_EQ(true, exists
);
7269 for(size_t i
= 0; i
< data
.size(); i
++)
7275 struct store_statfs_t statfs
;
7276 WRITE_AT(0, buf_len
);
7277 int r
= store
->statfs(&statfs
);
7279 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7282 struct store_statfs_t statfs
;
7283 WRITE_AT(write_offset
- 2 * overlap_offset
, buf_len
);
7284 int r
= store
->statfs(&statfs
);
7286 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7287 const PerfCounters
* counters
= store
->get_perf_counters();
7288 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0u);
7292 struct store_statfs_t statfs
;
7293 WRITE_AT(write_offset
- overlap_offset
, buf_len
);
7294 int r
= store
->statfs(&statfs
);
7296 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7297 const PerfCounters
* counters
= store
->get_perf_counters();
7298 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x10000u
);
7301 struct store_statfs_t statfs
;
7302 WRITE_AT(write_offset
- 3 * overlap_offset
, buf_len
);
7303 int r
= store
->statfs(&statfs
);
7305 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7306 const PerfCounters
* counters
= store
->get_perf_counters();
7307 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
7310 struct store_statfs_t statfs
;
7311 WRITE_AT(write_offset
+ 1, overlap_offset
-1);
7312 int r
= store
->statfs(&statfs
);
7314 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
7315 const PerfCounters
* counters
= store
->get_perf_counters();
7316 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
7319 struct store_statfs_t statfs
;
7320 WRITE_AT(write_offset
+ 1, overlap_offset
);
7321 int r
= store
->statfs(&statfs
);
7323 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7324 const PerfCounters
* counters
= store
->get_perf_counters();
7325 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x3ffffu
);
7328 struct store_statfs_t statfs
;
7329 WRITE_AT(0, buf_len
-1);
7330 int r
= store
->statfs(&statfs
);
7332 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7333 const PerfCounters
* counters
= store
->get_perf_counters();
7334 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
7336 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "1"); //forbid GC when saving = 0
7338 struct store_statfs_t statfs
;
7339 WRITE_AT(1, overlap_offset
-2);
7340 WRITE_AT(overlap_offset
* 2 + 1, overlap_offset
-2);
7341 int r
= store
->statfs(&statfs
);
7343 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
7344 const PerfCounters
* counters
= store
->get_perf_counters();
7345 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
7348 struct store_statfs_t statfs
;
7349 WRITE_AT(overlap_offset
+ 1, overlap_offset
-2);
7350 int r
= store
->statfs(&statfs
);
7352 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x0);
7353 const PerfCounters
* counters
= store
->get_perf_counters();
7354 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40007u
);
7357 ObjectStore::Transaction t
;
7358 t
.remove(cid
, hoid
);
7359 cerr
<< "Cleaning" << std::endl
;
7360 r
= queue_transaction(store
, ch
, std::move(t
));
7366 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice
) {
7367 if (string(GetParam()) != "bluestore")
7370 SetVal(g_conf(), "bluestore_block_size",
7371 stringify(0x280005000).c_str()); //10 Gb + 4K
7372 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7373 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7374 StartDeferred(0x4000);
7376 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7381 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice2
) {
7382 if (string(GetParam()) != "bluestore")
7385 SetVal(g_conf(), "bluestore_block_size",
7386 stringify(0x280005000).c_str()); //10 Gb + 20K
7387 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7388 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7389 StartDeferred(0x1000);
7391 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7396 ghobject_t
make_object(const char* name
, int64_t pool
) {
7397 sobject_t soid
{name
, CEPH_NOSNAP
};
7398 uint32_t hash
= std::hash
<sobject_t
>{}(soid
);
7399 return ghobject_t
{hobject_t
{soid
, "", hash
, pool
, ""}};
7403 TEST_P(StoreTestSpecificAUSize
, BluestoreRepairTest
) {
7404 if (string(GetParam()) != "bluestore")
7406 const size_t offs_base
= 65536 / 2;
7408 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
7409 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
7410 SetVal(g_conf(), "bluestore_max_blob_size",
7411 stringify(2 * offs_base
).c_str());
7412 SetVal(g_conf(), "bluestore_extent_map_shard_max_size", "12000");
7413 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "false");
7415 StartDeferred(0x10000);
7417 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
7419 // fill the store with some data
7420 const uint64_t pool
= 555;
7421 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
7422 auto ch
= store
->create_new_collection(cid
);
7424 ghobject_t hoid
= make_object("Object 1", pool
);
7425 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
7426 ghobject_t hoid2
= make_object("Object 2", pool
);
7427 ghobject_t hoid_cloned
= hoid2
;
7428 hoid_cloned
.hobj
.snap
= 1;
7429 ghobject_t hoid3
= make_object("Object 3", pool
);
7430 ghobject_t hoid3_cloned
= hoid3
;
7431 hoid3_cloned
.hobj
.snap
= 1;
7433 bl
.append("1234512345");
7435 const size_t repeats
= 16;
7437 auto ch
= store
->create_new_collection(cid
);
7438 cerr
<< "create collection + write" << std::endl
;
7439 ObjectStore::Transaction t
;
7440 t
.create_collection(cid
, 0);
7441 for( auto i
= 0ul; i
< repeats
; ++i
) {
7442 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
7443 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
7445 for( auto i
= 0ul; i
< repeats
; ++i
) {
7446 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
7448 t
.clone(cid
, hoid2
, hoid_cloned
);
7450 r
= queue_transaction(store
, ch
, std::move(t
));
7455 //////////// leaked pextent fix ////////////
7456 cerr
<< "fix leaked pextents" << std::endl
;
7457 ASSERT_EQ(bstore
->fsck(false), 0);
7458 ASSERT_EQ(bstore
->repair(false), 0);
7460 bstore
->inject_leaked(0x30000);
7462 ASSERT_EQ(bstore
->fsck(false), 1);
7463 ASSERT_EQ(bstore
->repair(false), 0);
7464 ASSERT_EQ(bstore
->fsck(false), 0);
7466 //////////// false free fix ////////////
7467 cerr
<< "fix false free pextents" << std::endl
;
7469 bstore
->inject_false_free(cid
, hoid
);
7471 ASSERT_EQ(bstore
->fsck(false), 2);
7472 ASSERT_EQ(bstore
->repair(false), 0);
7473 ASSERT_EQ(bstore
->fsck(false), 0);
7475 //////////// verify invalid statfs ///////////
7476 cerr
<< "fix invalid statfs" << std::endl
;
7477 store_statfs_t statfs0
, statfs
;
7479 ASSERT_EQ(bstore
->statfs(&statfs0
), 0);
7481 statfs
.allocated
+= 0x10000;
7482 statfs
.data_stored
+= 0x10000;
7483 ASSERT_FALSE(statfs0
== statfs
);
7484 bstore
->inject_statfs("bluestore_statfs", statfs
);
7487 ASSERT_EQ(bstore
->fsck(false), 2);
7488 ASSERT_EQ(bstore
->repair(false), 0);
7489 ASSERT_EQ(bstore
->fsck(false), 0);
7490 ASSERT_EQ(bstore
->mount(), 0);
7491 ASSERT_EQ(bstore
->statfs(&statfs
), 0);
7492 // adjust free space to success in comparison
7493 statfs0
.available
= statfs
.available
;
7494 ASSERT_EQ(statfs0
, statfs
);
7496 ///////// undecodable shared blob key / stray shared blob records ///////
7497 cerr
<< "undecodable shared blob key" << std::endl
;
7498 bstore
->inject_broken_shared_blob_key("undec1",
7500 bstore
->inject_broken_shared_blob_key("undecodable key 2",
7502 bstore
->inject_broken_shared_blob_key("undecodable key 3",
7505 ASSERT_EQ(bstore
->fsck(false), 3);
7506 ASSERT_EQ(bstore
->repair(false), 0);
7507 ASSERT_EQ(bstore
->fsck(false), 0);
7509 cerr
<< "misreferencing" << std::endl
;
7511 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, 0);
7512 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, (offs_base
* repeats
) / 2);
7513 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, offs_base
* (repeats
-1) );
7516 ASSERT_EQ(bstore
->fsck(false), 6);
7517 ASSERT_EQ(bstore
->repair(false), 0);
7519 ASSERT_EQ(bstore
->fsck(true), 0);
7521 // reproducing issues #21040 & 20983
7522 SetVal(g_conf(), "bluestore_debug_inject_bug21040", "true");
7523 g_ceph_context
->_conf
.apply_changes(nullptr);
7526 cerr
<< "repro bug #21040" << std::endl
;
7528 auto ch
= store
->open_collection(cid
);
7530 ObjectStore::Transaction t
;
7531 bl
.append("0123456789012345");
7532 t
.write(cid
, hoid3
, offs_base
, bl
.length(), bl
);
7535 t
.write(cid
, hoid3
, 0, bl
.length(), bl
);
7537 r
= queue_transaction(store
, ch
, std::move(t
));
7541 ObjectStore::Transaction t
;
7542 t
.clone(cid
, hoid3
, hoid3_cloned
);
7543 r
= queue_transaction(store
, ch
, std::move(t
));
7548 ASSERT_EQ(bstore
->fsck(false), 3);
7549 ASSERT_LE(bstore
->repair(false), 0);
7550 ASSERT_EQ(bstore
->fsck(false), 0);
7553 cerr
<< "Completing" << std::endl
;
7558 TEST_P(StoreTest
, BluestoreRepairGlobalStats
)
7560 if (string(GetParam()) != "bluestore")
7562 const size_t offs_base
= 65536 / 2;
7564 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
7566 // start with global stats
7567 bstore
->inject_global_statfs({});
7569 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
7572 // fill the store with some data
7573 const uint64_t pool
= 555;
7574 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
7575 auto ch
= store
->create_new_collection(cid
);
7577 ghobject_t hoid
= make_object("Object 1", pool
);
7578 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
7579 ghobject_t hoid2
= make_object("Object 2", pool
);
7580 ghobject_t hoid_cloned
= hoid2
;
7581 hoid_cloned
.hobj
.snap
= 1;
7582 ghobject_t hoid3
= make_object("Object 3", pool
);
7583 ghobject_t hoid3_cloned
= hoid3
;
7584 hoid3_cloned
.hobj
.snap
= 1;
7586 bl
.append("1234512345");
7588 const size_t repeats
= 16;
7590 auto ch
= store
->create_new_collection(cid
);
7591 cerr
<< "create collection + write" << std::endl
;
7592 ObjectStore::Transaction t
;
7593 t
.create_collection(cid
, 0);
7594 for( auto i
= 0ul; i
< repeats
; ++i
) {
7595 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
7596 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
7598 for( auto i
= 0ul; i
< repeats
; ++i
) {
7599 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
7601 t
.clone(cid
, hoid2
, hoid_cloned
);
7603 r
= queue_transaction(store
, ch
, std::move(t
));
7609 // enable per-pool stats collection hence causing fsck to fail
7610 cerr
<< "per-pool statfs" << std::endl
;
7611 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
7612 g_ceph_context
->_conf
.apply_changes(nullptr);
7614 ASSERT_EQ(bstore
->fsck(false), 1);
7615 ASSERT_EQ(bstore
->repair(false), 0);
7616 ASSERT_EQ(bstore
->fsck(false), 0);
7621 TEST_P(StoreTest
, BluestoreRepairGlobalStatsFixOnMount
)
7623 if (string(GetParam()) != "bluestore")
7625 const size_t offs_base
= 65536 / 2;
7627 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
7629 // start with global stats
7630 bstore
->inject_global_statfs({});
7632 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
7635 // fill the store with some data
7636 const uint64_t pool
= 555;
7637 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
7638 auto ch
= store
->create_new_collection(cid
);
7640 ghobject_t hoid
= make_object("Object 1", pool
);
7641 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
7642 ghobject_t hoid2
= make_object("Object 2", pool
);
7643 ghobject_t hoid_cloned
= hoid2
;
7644 hoid_cloned
.hobj
.snap
= 1;
7645 ghobject_t hoid3
= make_object("Object 3", pool
);
7646 ghobject_t hoid3_cloned
= hoid3
;
7647 hoid3_cloned
.hobj
.snap
= 1;
7649 bl
.append("1234512345");
7651 const size_t repeats
= 16;
7653 auto ch
= store
->create_new_collection(cid
);
7654 cerr
<< "create collection + write" << std::endl
;
7655 ObjectStore::Transaction t
;
7656 t
.create_collection(cid
, 0);
7657 for( auto i
= 0ul; i
< repeats
; ++i
) {
7658 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
7659 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
7661 for( auto i
= 0ul; i
< repeats
; ++i
) {
7662 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
7664 t
.clone(cid
, hoid2
, hoid_cloned
);
7666 r
= queue_transaction(store
, ch
, std::move(t
));
7672 // enable per-pool stats collection hence causing fsck to fail
7673 cerr
<< "per-pool statfs" << std::endl
;
7674 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
7675 g_ceph_context
->_conf
.apply_changes(nullptr);
7677 ASSERT_EQ(bstore
->fsck(false), 1);
7679 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
7682 ASSERT_EQ(bstore
->fsck(false), 0);
7687 TEST_P(StoreTest
, BluestoreStatistics
) {
7688 if (string(GetParam()) != "bluestore")
7691 SetVal(g_conf(), "rocksdb_perf", "true");
7692 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
7693 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
7694 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
7697 SetVal(g_conf(), "bluestore_cache_size_ssd", "0");
7698 SetVal(g_conf(), "bluestore_cache_size_hdd", "0");
7699 SetVal(g_conf(), "bluestore_cache_size", "0");
7700 g_ceph_context
->_conf
.apply_changes(nullptr);
7702 int r
= store
->umount();
7707 BlueStore
* bstore
= NULL
;
7708 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
7711 ghobject_t
hoid(hobject_t("test_db_statistics", "", CEPH_NOSNAP
, 0, 0, ""));
7712 auto ch
= bstore
->create_new_collection(cid
);
7714 bl
.append("0123456789abcdefghi");
7716 ObjectStore::Transaction t
;
7717 t
.create_collection(cid
, 0);
7719 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7720 cerr
<< "Write object" << std::endl
;
7721 r
= queue_transaction(bstore
, ch
, std::move(t
));
7725 bufferlist readback
;
7726 r
= store
->read(ch
, hoid
, 0, bl
.length(), readback
);
7727 ASSERT_EQ(static_cast<int>(bl
.length()), r
);
7728 ASSERT_TRUE(bl_eq(bl
, readback
));
7730 Formatter
*f
= Formatter::create("store_test", "json-pretty", "json-pretty");
7731 EXPECT_NO_THROW(store
->get_db_statistics(f
));
7736 TEST_P(StoreTest
, BluestorePerPoolOmapFixOnMount
)
7738 if (string(GetParam()) != "bluestore")
7741 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
7742 const uint64_t pool
= 555;
7743 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
7744 ghobject_t oid
= make_object("Object 1", pool
);
7745 ghobject_t oid2
= make_object("Object 2", pool
);
7746 // fill the store with some data
7747 auto ch
= store
->create_new_collection(cid
);
7748 map
<string
, bufferlist
> omap
;
7752 omap
["omap_key"].append("omap value");
7753 ObjectStore::Transaction t
;
7754 t
.create_collection(cid
, 0);
7756 t
.omap_setheader(cid
, oid
, h
);
7758 t
.omap_setheader(cid
, oid2
, h
);
7759 int r
= queue_transaction(store
, ch
, std::move(t
));
7763 // inject legacy omaps
7764 bstore
->inject_legacy_omap();
7765 bstore
->inject_legacy_omap(cid
, oid
);
7766 bstore
->inject_legacy_omap(cid
, oid2
);
7770 // check we injected an issue
7771 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
7772 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
7773 g_ceph_context
->_conf
.apply_changes(nullptr);
7774 ASSERT_EQ(bstore
->fsck(false), 3);
7776 // set autofix and mount
7777 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
7778 g_ceph_context
->_conf
.apply_changes(nullptr);
7782 // check we fixed it..
7783 ASSERT_EQ(bstore
->fsck(false), 0);
7787 // Now repro https://tracker.ceph.com/issues/43824
7789 // inject legacy omaps again
7790 bstore
->inject_legacy_omap();
7791 bstore
->inject_legacy_omap(cid
, oid
);
7792 bstore
->inject_legacy_omap(cid
, oid2
);
7795 // check we injected an issue
7796 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
7797 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
7798 g_ceph_context
->_conf
.apply_changes(nullptr);
7800 ch
= store
->open_collection(cid
);
7803 // write to onode which will partiall revert per-pool
7804 // omap repair done on mount due to #43824.
7805 // And object removal will leave stray per-pool omap recs
7807 ObjectStore::Transaction t
;
7810 //this triggers onode rec update and hence legacy omap
7811 t
.write(cid
, oid
, 0, bl
.length(), bl
);
7812 t
.remove(cid
, oid2
); // this will trigger stray per-pool omap
7813 int r
= queue_transaction(store
, ch
, std::move(t
));
7817 // check omap's been fixed.
7818 ASSERT_EQ(bstore
->fsck(false), 0); // this will fail without fix for #43824
7823 TEST_P(StoreTestSpecificAUSize
, BluestoreTinyDevFailure
) {
7824 if (string(GetParam()) != "bluestore")
7826 // This caused superblock overwrite by bluefs, see
7827 // https://tracker.ceph.com/issues/24480
7828 SetVal(g_conf(), "bluestore_block_size",
7829 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7830 SetVal(g_conf(), "bluestore_block_db_size", "0");
7831 SetVal(g_conf(), "bluestore_block_db_create", "false");
7832 SetVal(g_conf(), "bluestore_bluefs_min",
7833 stringify(1024 * 1024 * 1024).c_str());
7834 StartDeferred(0x1000);
7836 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7840 TEST_P(StoreTestSpecificAUSize
, BluestoreTinyDevFailure2
) {
7841 if (string(GetParam()) != "bluestore")
7844 // This caused assert in allocator as initial bluefs extent as slow device
7845 // overlaped with superblock
7846 // https://tracker.ceph.com/issues/24480
7847 SetVal(g_conf(), "bluestore_block_size",
7848 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7849 SetVal(g_conf(), "bluestore_block_db_size",
7850 stringify(1024 * 1024 * 1024).c_str()); //1 Gb
7851 SetVal(g_conf(), "bluestore_block_db_create", "true");
7852 SetVal(g_conf(), "bluestore_bluefs_min",
7853 stringify(1024 * 1024 * 1024).c_str());
7854 StartDeferred(0x1000);
7856 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7860 TEST_P(StoreTest
, SpuriousReadErrorTest
) {
7861 if (string(GetParam()) != "bluestore")
7865 auto logger
= store
->get_perf_counters();
7867 auto ch
= store
->create_new_collection(cid
);
7868 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
7870 ObjectStore::Transaction t
;
7871 t
.create_collection(cid
, 0);
7872 cerr
<< "Creating collection " << cid
<< std::endl
;
7873 r
= queue_transaction(store
, ch
, std::move(t
));
7876 bufferlist test_data
;
7877 bufferptr
ap(0x2000);
7878 memset(ap
.c_str(), 'a', 0x2000);
7879 test_data
.append(ap
);
7881 ObjectStore::Transaction t
;
7882 t
.write(cid
, hoid
, 0, 0x2000, test_data
);
7883 r
= queue_transaction(store
, ch
, std::move(t
));
7885 // force cache clear
7886 EXPECT_EQ(store
->umount(), 0);
7887 EXPECT_EQ(store
->mount(), 0);
7890 cerr
<< "Injecting CRC error with no retry, expecting EIO" << std::endl
;
7891 SetVal(g_conf(), "bluestore_retry_disk_reads", "0");
7892 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "1");
7893 g_ceph_context
->_conf
.apply_changes(nullptr);
7896 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7898 ASSERT_EQ(logger
->get(l_bluestore_read_eio
), 1u);
7899 ASSERT_EQ(logger
->get(l_bluestore_reads_with_retries
), 0u);
7902 cerr
<< "Injecting CRC error with retries, expecting success after several retries" << std::endl
;
7903 SetVal(g_conf(), "bluestore_retry_disk_reads", "255");
7904 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "0.8");
7906 * Probabilistic test: 25 reads, each has a 80% chance of failing with 255 retries
7907 * Probability of at least one retried read: 1 - (0.2 ** 25) = 100% - 3e-18
7908 * Probability of a random test failure: 1 - ((1 - (0.8 ** 255)) ** 25) ~= 5e-24
7910 g_ceph_context
->_conf
.apply_changes(nullptr);
7912 for (int i
= 0; i
< 25; ++i
) {
7914 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7915 ASSERT_EQ(0x2000, r
);
7916 ASSERT_TRUE(bl_eq(test_data
, in
));
7918 ASSERT_GE(logger
->get(l_bluestore_reads_with_retries
), 1u);
7922 TEST_P(StoreTest
, allocateBlueFSTest
) {
7923 if (string(GetParam()) != "bluestore")
7926 BlueStore
* bstore
= NULL
;
7927 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
7929 struct store_statfs_t statfs
;
7930 store
->statfs(&statfs
);
7932 uint64_t to_alloc
= g_conf().get_val
<Option::size_t>("bluefs_alloc_size");
7934 int r
= bstore
->allocate_bluefs_freespace(to_alloc
, to_alloc
, nullptr);
7936 r
= bstore
->allocate_bluefs_freespace(statfs
.total
, statfs
.total
, nullptr);
7937 ASSERT_EQ(r
, -ENOSPC
);
7938 r
= bstore
->allocate_bluefs_freespace(to_alloc
* 16, to_alloc
* 16, nullptr);
7941 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
7946 TEST_P(StoreTest
, mergeRegionTest
) {
7947 if (string(GetParam()) != "bluestore")
7950 SetVal(g_conf(), "bluestore_fsck_on_mount", "true");
7951 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
7952 SetVal(g_conf(), "bdev_debug_inflight_ios", "true");
7953 g_ceph_context
->_conf
.apply_changes(nullptr);
7955 uint32_t chunk_size
= g_ceph_context
->_conf
->bdev_block_size
;
7958 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
7959 auto ch
= store
->create_new_collection(cid
);
7961 ObjectStore::Transaction t
;
7962 t
.create_collection(cid
, 0);
7963 r
= queue_transaction(store
, ch
, std::move(t
));
7967 ObjectStore::Transaction t
;
7969 cerr
<< "Creating object " << hoid
<< std::endl
;
7970 r
= queue_transaction(store
, ch
, std::move(t
));
7974 bl5
.append("abcde");
7975 uint64_t offset
= 0;
7977 ObjectStore::Transaction t
;
7978 t
.write(cid
, hoid
, offset
, 5, bl5
);
7979 t
.write(cid
, hoid
, 0xa + offset
, 5, bl5
);
7980 t
.write(cid
, hoid
, 0x14 + offset
, 5, bl5
);
7981 r
= queue_transaction(store
, ch
, std::move(t
));
7984 { // 2. adjacent regions
7985 ObjectStore::Transaction t
;
7986 offset
= chunk_size
;
7987 t
.write(cid
, hoid
, offset
, 5, bl5
);
7988 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
7989 r
= queue_transaction(store
, ch
, std::move(t
));
7993 ObjectStore::Transaction t
;
7994 offset
= chunk_size
* 2;
7995 t
.write(cid
, hoid
, offset
, 5, bl5
);
7996 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, 5, bl5
);
7997 r
= queue_transaction(store
, ch
, std::move(t
));
8001 ObjectStore::Transaction t
;
8003 blc2
.append_zero(chunk_size
+ 2);
8005 offset
= chunk_size
* 3;
8006 t
.write(cid
, hoid
, offset
, chunk_size
+ 2, blc2
);
8007 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
8008 r
= queue_transaction(store
, ch
, std::move(t
));
8012 ObjectStore::Transaction t
;
8013 uint64_t final_len
= 0;
8014 offset
= chunk_size
* 10;
8016 bl2c2
.append_zero(chunk_size
* 2);
8017 t
.write(cid
, hoid
, offset
+ chunk_size
* 3 - 3, chunk_size
* 2, bl2c2
);
8018 bl2c2
.append_zero(2);
8019 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, chunk_size
* 2 + 2, bl2c2
);
8020 r
= queue_transaction(store
, ch
, std::move(t
));
8023 final_len
= (offset
+ chunk_size
* 3 - 3) + (chunk_size
* 2);
8025 r
= store
->read(ch
, hoid
, 0, final_len
, bl
);
8026 ASSERT_EQ(final_len
, static_cast<uint64_t>(r
));
8030 TEST_P(StoreTestSpecificAUSize
, BluestoreEnforceHWSettingsHdd
) {
8031 if (string(GetParam()) != "bluestore")
8034 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
8035 StartDeferred(0x1000);
8039 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
8040 auto ch
= store
->create_new_collection(cid
);
8042 ObjectStore::Transaction t
;
8043 t
.create_collection(cid
, 0);
8044 cerr
<< "Creating collection " << cid
<< std::endl
;
8045 r
= queue_transaction(store
, ch
, std::move(t
));
8049 ObjectStore::Transaction t
;
8050 bufferlist bl
, orig
;
8051 string
s(g_ceph_context
->_conf
->bluestore_max_blob_size_hdd
, '0');
8053 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
8054 cerr
<< "write" << std::endl
;
8055 r
= queue_transaction(store
, ch
, std::move(t
));
8058 const PerfCounters
* logger
= store
->get_perf_counters();
8059 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 1u);
8063 TEST_P(StoreTestSpecificAUSize
, BluestoreEnforceHWSettingsSsd
) {
8064 if (string(GetParam()) != "bluestore")
8067 SetVal(g_conf(), "bluestore_debug_enforce_settings", "ssd");
8068 StartDeferred(0x1000);
8072 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
8073 auto ch
= store
->create_new_collection(cid
);
8075 ObjectStore::Transaction t
;
8076 t
.create_collection(cid
, 0);
8077 cerr
<< "Creating collection " << cid
<< std::endl
;
8078 r
= queue_transaction(store
, ch
, std::move(t
));
8082 ObjectStore::Transaction t
;
8083 bufferlist bl
, orig
;
8084 string
s(g_ceph_context
->_conf
->bluestore_max_blob_size_ssd
* 8, '0');
8086 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
8087 cerr
<< "write" << std::endl
;
8088 r
= queue_transaction(store
, ch
, std::move(t
));
8091 const PerfCounters
* logger
= store
->get_perf_counters();
8092 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 8u);
8096 TEST_P(StoreTestSpecificAUSize
, ReproNoBlobMultiTest
) {
8098 if(string(GetParam()) != "bluestore")
8101 SetVal(g_conf(), "bluestore_block_db_create", "true");
8102 SetVal(g_conf(), "bluestore_block_db_size", "4294967296");
8103 SetVal(g_conf(), "bluestore_block_size", "12884901888");
8104 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
8106 g_conf().apply_changes(nullptr);
8108 StartDeferred(65536);
8112 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
8113 ghobject_t hoid2
= hoid
;
8114 hoid2
.hobj
.snap
= 1;
8116 auto ch
= store
->create_new_collection(cid
);
8118 ObjectStore::Transaction t
;
8119 t
.create_collection(cid
, 0);
8120 cerr
<< "Creating collection " << cid
<< std::endl
;
8121 r
= queue_transaction(store
, ch
, std::move(t
));
8125 bool exists
= store
->exists(ch
, hoid
);
8126 ASSERT_TRUE(!exists
);
8128 ObjectStore::Transaction t
;
8130 cerr
<< "Creating object " << hoid
<< std::endl
;
8131 r
= queue_transaction(store
, ch
, std::move(t
));
8134 exists
= store
->exists(ch
, hoid
);
8135 ASSERT_EQ(true, exists
);
8140 const int size
= 0x100;
8142 memset(ap
.c_str(), 'a', size
);
8145 uint64_t blob_size
= 524288;
8147 for (i
= 0; i
<= 512; i
++) {
8148 offs
= 0 + i
* size
;
8149 ObjectStore::Transaction t
;
8150 ghobject_t hoid2
= hoid
;
8151 hoid2
.hobj
.snap
= i
+ 1;
8152 while (offs
< 128 * 1024 * 1024) {
8154 t
.write(cid
, hoid
, offs
, ap
.length(), bl
);
8156 total
+= ap
.length();
8158 t
.clone(cid
, hoid
, hoid2
);
8159 r
= queue_transaction(store
, ch
, std::move(t
));
8162 cerr
<< "Total written = " << total
<< std::endl
;
8165 cerr
<< "Finalizing" << std::endl
;
8166 const PerfCounters
* logger
= store
->get_perf_counters();
8167 ASSERT_GE(logger
->get(l_bluestore_gc_merged
), 1024*1024*1024);
8171 void doManySetAttr(ObjectStore
* store
,
8172 std::function
<void(ObjectStore
*)> do_check_fn
)
8174 MixedGenerator
gen(447);
8175 gen_type
rng(time(NULL
));
8176 coll_t
cid(spg_t(pg_t(0, 447), shard_id_t::NO_SHARD
));
8178 SyntheticWorkloadState
test_obj(store
, &gen
, &rng
, cid
, 40 * 1024, 4 * 1024, 0);
8180 for (int i
= 0; i
< 1500; ++i
) {
8181 if (!(i
% 10)) cerr
<< "seeding object " << i
<< std::endl
;
8184 for (int i
= 0; i
< 10000; ++i
) {
8186 cerr
<< "Op " << i
<< std::endl
;
8187 test_obj
.print_internal_state();
8189 boost::uniform_int
<> true_false(0, 99);
8190 test_obj
.setattrs();
8192 test_obj
.wait_for_done();
8194 AdminSocket
* admin_socket
= g_ceph_context
->get_admin_socket();
8195 ceph_assert(admin_socket
);
8197 ceph::bufferlist in
, out
;
8200 bool b
= admin_socket
->execute_command(
8201 { "{\"prefix\": \"bluestore bluefs stats\"}" },
8204 cerr
<< "failure querying " << std::endl
;
8206 std::cout
<< std::string(out
.c_str(), out
.length()) << std::endl
;
8208 test_obj
.shutdown();
8211 TEST_P(StoreTestSpecificAUSize
, SpilloverTest
) {
8212 if (string(GetParam()) != "bluestore")
8215 SetVal(g_conf(), "bluestore_block_db_create", "true");
8216 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
8217 SetVal(g_conf(), "bluestore_volume_selection_policy", "rocksdb_original");
8219 g_conf().apply_changes(nullptr);
8221 StartDeferred(65536);
8222 doManySetAttr(store
.get(),
8223 [&](ObjectStore
* _store
) {
8225 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
8226 ceph_assert(bstore
);
8227 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
8228 //experimentally it was discovered that this case results in 400+MB spillover
8229 //using lower 300MB threshold just to be safe enough
8230 ASSERT_GE(logger
->get(l_bluefs_slow_used_bytes
), 300 * 1024 * 1024);
8236 TEST_P(StoreTestSpecificAUSize
, SpilloverFixedTest
) {
8237 if (string(GetParam()) != "bluestore")
8240 SetVal(g_conf(), "bluestore_block_db_create", "true");
8241 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
8242 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
8243 SetVal(g_conf(), "bluestore_volume_selection_reserved", "1"); // just use non-zero to enable
8245 g_conf().apply_changes(nullptr);
8247 StartDeferred(65536);
8248 doManySetAttr(store
.get(),
8249 [&](ObjectStore
* _store
) {
8251 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
8252 ceph_assert(bstore
);
8253 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
8254 ASSERT_EQ(0, logger
->get(l_bluefs_slow_used_bytes
));
8259 TEST_P(StoreTestSpecificAUSize
, SpilloverFixed2Test
) {
8260 if (string(GetParam()) != "bluestore")
8263 SetVal(g_conf(), "bluestore_block_db_create", "true");
8264 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
8265 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
8266 //default 2.0 factor results in too high threshold, using less value
8267 // that results in less but still present spillover.
8268 SetVal(g_conf(), "bluestore_volume_selection_reserved_factor", "0.5");
8270 g_conf().apply_changes(nullptr);
8272 StartDeferred(65536);
8273 doManySetAttr(store
.get(),
8274 [&](ObjectStore
* _store
) {
8276 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
8277 ceph_assert(bstore
);
8278 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
8279 ASSERT_LE(logger
->get(l_bluefs_slow_used_bytes
), 300 * 1024 * 1024); // see SpilloverTest for 300MB choice rationale
8284 #endif // WITH_BLUESTORE
8286 int main(int argc
, char **argv
) {
8287 vector
<const char*> args
;
8288 argv_to_vec(argc
, (const char **)argv
, args
);
8290 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
8291 CODE_ENVIRONMENT_UTILITY
,
8292 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
8293 common_init_finish(g_ceph_context
);
8295 // make sure we can adjust any config settings
8296 g_ceph_context
->_conf
._clear_safe_to_start_threads();
8298 g_ceph_context
->_conf
.set_val_or_die("osd_journal_size", "400");
8299 g_ceph_context
->_conf
.set_val_or_die("filestore_index_retry_probability", "0.5");
8300 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_timeout", "1000");
8301 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_suicide_timeout", "10000");
8302 //g_ceph_context->_conf.set_val_or_die("filestore_fiemap", "true");
8303 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mkfs", "false");
8304 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mount", "false");
8305 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_umount", "false");
8306 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_misc", "true");
8307 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_small_allocations", "4");
8308 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_freelist", "true");
8309 g_ceph_context
->_conf
.set_val_or_die("bluestore_clone_cow", "true");
8310 g_ceph_context
->_conf
.set_val_or_die("bluestore_max_alloc_size", "196608");
8312 // set small cache sizes so we see trimming during Synthetic tests
8313 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_hdd", "4000000");
8314 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_ssd", "4000000");
8316 // very short *_max prealloc so that we fall back to async submits
8317 g_ceph_context
->_conf
.set_val_or_die("bluestore_blobid_prealloc", "10");
8318 g_ceph_context
->_conf
.set_val_or_die("bluestore_nid_prealloc", "10");
8319 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_randomize_serial_transaction",
8322 g_ceph_context
->_conf
.set_val_or_die("bdev_debug_aio", "true");
8324 // specify device size
8325 g_ceph_context
->_conf
.set_val_or_die("bluestore_block_size",
8326 stringify(DEF_STORE_TEST_BLOCKDEV_SIZE
));
8328 g_ceph_context
->_conf
.set_val_or_die(
8329 "enable_experimental_unrecoverable_data_corrupting_features", "*");
8330 g_ceph_context
->_conf
.apply_changes(nullptr);
8332 ::testing::InitGoogleTest(&argc
, argv
);
8333 return RUN_ALL_TESTS();
8338 * compile-command: "cd ../.. ; make ceph_test_objectstore &&
8339 * ./ceph_test_objectstore \
8340 * --gtest_filter=*.collect_metadata* --log-to-stderr=true --debug-filestore=20