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
));
104 template <typename T
>
105 int collection_list(T
&store
, ObjectStore::CollectionHandle
&c
,
106 const ghobject_t
& start
, const ghobject_t
& end
, int max
,
107 vector
<ghobject_t
> *ls
, ghobject_t
*pnext
,
108 bool disable_legacy
= false) {
109 if (disable_legacy
|| rand() % 2) {
110 return store
->collection_list(c
, start
, end
, max
, ls
, pnext
);
112 return store
->collection_list_legacy(c
, start
, end
, max
, ls
, pnext
);
116 bool sorted(const vector
<ghobject_t
> &in
) {
118 for (vector
<ghobject_t
>::const_iterator i
= in
.begin();
122 cout
<< start
<< " should follow " << *i
<< std::endl
;
130 class StoreTest
: public StoreTestFixture
,
131 public ::testing::WithParamInterface
<const char*> {
134 : StoreTestFixture(GetParam())
136 void doCompressionTest();
137 void doSyntheticTest(
139 uint64_t max_obj
, uint64_t max_wr
, uint64_t align
);
142 class StoreTestDeferredSetup
: public StoreTest
{
143 void SetUp() override
{
148 void DeferredSetup() {
155 class StoreTestSpecificAUSize
: public StoreTestDeferredSetup
{
163 uint64_t align
)> MatrixTest
;
165 void StartDeferred(size_t min_alloc_size
) {
166 SetVal(g_conf(), "bluestore_min_alloc_size", stringify(min_alloc_size
).c_str());
171 // bluestore matrix testing
172 uint64_t max_write
= 40 * 1024;
173 uint64_t max_size
= 400 * 1024;
174 uint64_t alignment
= 0;
175 uint64_t num_ops
= 10000;
178 string
matrix_get(const char *k
) {
179 if (string(k
) == "max_write") {
180 return stringify(max_write
);
181 } else if (string(k
) == "max_size") {
182 return stringify(max_size
);
183 } else if (string(k
) == "alignment") {
184 return stringify(alignment
);
185 } else if (string(k
) == "num_ops") {
186 return stringify(num_ops
);
189 g_conf().get_val(k
, &buf
, -1);
196 void matrix_set(const char *k
, const char *v
) {
197 if (string(k
) == "max_write") {
198 max_write
= atoll(v
);
199 } else if (string(k
) == "max_size") {
201 } else if (string(k
) == "alignment") {
202 alignment
= atoll(v
);
203 } else if (string(k
) == "num_ops") {
206 SetVal(g_conf(), k
, v
);
210 void do_matrix_choose(const char *matrix
[][10],
211 int i
, int pos
, int num
,
215 for (count
= 0; matrix
[i
][count
+1]; ++count
) ;
216 for (int j
= 1; matrix
[i
][j
]; ++j
) {
217 matrix_set(matrix
[i
][0], matrix
[i
][j
]);
218 do_matrix_choose(matrix
,
225 cout
<< "---------------------- " << (pos
+ 1) << " / " << num
226 << " ----------------------" << std::endl
;
227 for (unsigned k
=0; matrix
[k
][0]; ++k
) {
228 cout
<< " " << matrix
[k
][0] << " = " << matrix_get(matrix
[k
][0])
231 g_ceph_context
->_conf
.apply_changes(nullptr);
232 fn(num_ops
, max_size
, max_write
, alignment
);
236 void do_matrix(const char *matrix
[][10],
239 if (strcmp(matrix
[0][0], "bluestore_min_alloc_size") == 0) {
241 for (count
= 0; matrix
[0][count
+1]; ++count
) ;
242 for (size_t j
= 1; matrix
[0][j
]; ++j
) {
246 StartDeferred(strtoll(matrix
[0][j
], NULL
, 10));
247 do_matrix_choose(matrix
, 1, j
- 1, count
, fn
);
251 do_matrix_choose(matrix
, 0, 0, 1, fn
);
257 TEST_P(StoreTest
, collect_metadata
) {
258 map
<string
,string
> pm
;
259 store
->collect_metadata(&pm
);
260 if (GetParam() == string("filestore")) {
261 ASSERT_NE(pm
.count("filestore_backend"), 0u);
262 ASSERT_NE(pm
.count("filestore_f_type"), 0u);
263 ASSERT_NE(pm
.count("backend_filestore_partition_path"), 0u);
264 ASSERT_NE(pm
.count("backend_filestore_dev_node"), 0u);
268 TEST_P(StoreTest
, Trivial
) {
271 TEST_P(StoreTest
, TrivialRemount
) {
272 int r
= store
->umount();
278 TEST_P(StoreTest
, SimpleRemount
) {
280 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
281 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
283 bl
.append("1234512345");
285 auto ch
= store
->create_new_collection(cid
);
287 cerr
<< "create collection + write" << std::endl
;
288 ObjectStore::Transaction t
;
289 t
.create_collection(cid
, 0);
290 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
291 r
= queue_transaction(store
, ch
, std::move(t
));
299 ch
= store
->open_collection(cid
);
301 ObjectStore::Transaction t
;
302 t
.write(cid
, hoid2
, 0, bl
.length(), bl
);
303 r
= queue_transaction(store
, ch
, std::move(t
));
307 ObjectStore::Transaction t
;
309 t
.remove(cid
, hoid2
);
310 t
.remove_collection(cid
);
311 cerr
<< "remove collection" << std::endl
;
312 r
= queue_transaction(store
, ch
, std::move(t
));
320 ch
= store
->create_new_collection(cid
);
322 ObjectStore::Transaction t
;
323 t
.create_collection(cid
, 0);
324 r
= queue_transaction(store
, ch
, std::move(t
));
326 bool exists
= store
->exists(ch
, hoid
);
327 ASSERT_TRUE(!exists
);
330 ObjectStore::Transaction t
;
331 t
.remove_collection(cid
);
332 cerr
<< "remove collection" << std::endl
;
333 r
= queue_transaction(store
, ch
, std::move(t
));
338 TEST_P(StoreTest
, IORemount
) {
341 bl
.append("1234512345");
343 auto ch
= store
->create_new_collection(cid
);
345 cerr
<< "create collection + objects" << std::endl
;
346 ObjectStore::Transaction t
;
347 t
.create_collection(cid
, 0);
348 for (int n
=1; n
<=100; ++n
) {
349 ghobject_t
hoid(hobject_t(sobject_t("Object " + stringify(n
), CEPH_NOSNAP
)));
350 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
352 r
= queue_transaction(store
, ch
, std::move(t
));
357 cout
<< "overwrites" << std::endl
;
358 for (int n
=1; n
<=100; ++n
) {
359 ObjectStore::Transaction t
;
360 ghobject_t
hoid(hobject_t(sobject_t("Object " + stringify(n
), CEPH_NOSNAP
)));
361 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
362 r
= queue_transaction(store
, ch
, std::move(t
));
372 ObjectStore::Transaction t
;
373 for (int n
=1; n
<=100; ++n
) {
374 ghobject_t
hoid(hobject_t(sobject_t("Object " + stringify(n
), CEPH_NOSNAP
)));
377 t
.remove_collection(cid
);
378 auto ch
= store
->open_collection(cid
);
379 r
= queue_transaction(store
, ch
, std::move(t
));
384 TEST_P(StoreTest
, UnprintableCharsName
) {
386 string name
= "funnychars_";
387 for (unsigned i
= 0; i
< 256; ++i
) {
390 ghobject_t
oid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)));
392 auto ch
= store
->create_new_collection(cid
);
394 cerr
<< "create collection + object" << std::endl
;
395 ObjectStore::Transaction t
;
396 t
.create_collection(cid
, 0);
398 r
= queue_transaction(store
, ch
, std::move(t
));
407 cout
<< "removing" << std::endl
;
408 ObjectStore::Transaction t
;
410 t
.remove_collection(cid
);
411 auto ch
= store
->open_collection(cid
);
412 r
= queue_transaction(store
, ch
, std::move(t
));
417 TEST_P(StoreTest
, FiemapEmpty
) {
420 ghobject_t
oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP
)));
421 auto ch
= store
->create_new_collection(cid
);
423 ObjectStore::Transaction t
;
424 t
.create_collection(cid
, 0);
426 t
.truncate(cid
, oid
, 100000);
427 r
= queue_transaction(store
, ch
, std::move(t
));
432 store
->fiemap(ch
, oid
, 0, 100000, bl
);
433 map
<uint64_t,uint64_t> m
, e
;
434 auto p
= bl
.cbegin();
436 cout
<< " got " << m
<< std::endl
;
438 EXPECT_TRUE(m
== e
|| m
.empty());
441 ObjectStore::Transaction t
;
443 t
.remove_collection(cid
);
444 cerr
<< "remove collection" << std::endl
;
445 r
= queue_transaction(store
, ch
, std::move(t
));
450 TEST_P(StoreTest
, FiemapHoles
) {
451 const uint64_t MAX_EXTENTS
= 4000;
452 const uint64_t SKIP_STEP
= 65536;
455 ghobject_t
oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP
)));
458 auto ch
= store
->create_new_collection(cid
);
460 ObjectStore::Transaction t
;
461 t
.create_collection(cid
, 0);
463 for (uint64_t i
= 0; i
< MAX_EXTENTS
; i
++)
464 t
.write(cid
, oid
, SKIP_STEP
* i
, 3, bl
);
465 r
= queue_transaction(store
, ch
, std::move(t
));
469 //fiemap test from 0 to SKIP_STEP * (MAX_EXTENTS - 1) + 3
471 store
->fiemap(ch
, oid
, 0, SKIP_STEP
* (MAX_EXTENTS
- 1) + 3, bl
);
472 map
<uint64_t,uint64_t> m
, e
;
473 auto p
= bl
.cbegin();
475 cout
<< " got " << m
<< std::endl
;
476 ASSERT_TRUE(!m
.empty());
478 auto last
= m
.crbegin();
480 ASSERT_EQ(0u, last
->first
);
481 } else if (m
.size() == MAX_EXTENTS
) {
482 for (uint64_t i
= 0; i
< MAX_EXTENTS
; i
++) {
483 ASSERT_TRUE(m
.count(SKIP_STEP
* i
));
486 ASSERT_GT(last
->first
+ last
->second
, SKIP_STEP
* (MAX_EXTENTS
- 1));
489 // fiemap test from SKIP_STEP to SKIP_STEP * (MAX_EXTENTS - 2) + 3
491 store
->fiemap(ch
, oid
, SKIP_STEP
, SKIP_STEP
* (MAX_EXTENTS
- 2) + 3, bl
);
492 map
<uint64_t,uint64_t> m
, e
;
493 auto p
= bl
.cbegin();
495 cout
<< " got " << m
<< std::endl
;
496 ASSERT_TRUE(!m
.empty());
497 // kstore always returns [0, object_size] regardless of offset and length
498 // FIXME: if fiemap logic in kstore is refined
499 if (string(GetParam()) != "kstore") {
500 ASSERT_GE(m
[SKIP_STEP
], 3u);
501 auto last
= m
.crbegin();
503 ASSERT_EQ(SKIP_STEP
, last
->first
);
504 } else if (m
.size() == MAX_EXTENTS
- 2) {
505 for (uint64_t i
= 1; i
< MAX_EXTENTS
- 1; i
++) {
506 ASSERT_TRUE(m
.count(SKIP_STEP
*i
));
509 ASSERT_GT(last
->first
+ last
->second
, SKIP_STEP
* (MAX_EXTENTS
- 1));
513 ObjectStore::Transaction t
;
515 t
.remove_collection(cid
);
516 cerr
<< "remove collection" << std::endl
;
517 r
= queue_transaction(store
, ch
, std::move(t
));
522 TEST_P(StoreTest
, SimpleMetaColTest
) {
526 auto ch
= store
->create_new_collection(cid
);
527 ObjectStore::Transaction t
;
528 t
.create_collection(cid
, 0);
529 cerr
<< "create collection" << std::endl
;
530 r
= queue_transaction(store
, ch
, std::move(t
));
534 ObjectStore::Transaction t
;
535 t
.remove_collection(cid
);
536 cerr
<< "remove collection" << std::endl
;
537 auto ch
= store
->open_collection(cid
);
538 r
= queue_transaction(store
, ch
, std::move(t
));
542 auto ch
= store
->create_new_collection(cid
);
543 ObjectStore::Transaction t
;
544 t
.create_collection(cid
, 0);
545 cerr
<< "add collection" << std::endl
;
546 r
= queue_transaction(store
, ch
, std::move(t
));
550 ObjectStore::Transaction t
;
551 t
.remove_collection(cid
);
552 cerr
<< "remove collection" << std::endl
;
553 auto ch
= store
->open_collection(cid
);
554 r
= queue_transaction(store
, ch
, std::move(t
));
559 TEST_P(StoreTest
, SimplePGColTest
) {
560 coll_t
cid(spg_t(pg_t(1,2), shard_id_t::NO_SHARD
));
563 ObjectStore::Transaction t
;
564 auto ch
= store
->create_new_collection(cid
);
565 t
.create_collection(cid
, 4);
566 cerr
<< "create collection" << std::endl
;
567 r
= queue_transaction(store
, ch
, std::move(t
));
571 ObjectStore::Transaction t
;
572 t
.remove_collection(cid
);
573 cerr
<< "remove collection" << std::endl
;
574 auto ch
= store
->open_collection(cid
);
575 r
= queue_transaction(store
, ch
, std::move(t
));
579 ObjectStore::Transaction t
;
580 t
.create_collection(cid
, 4);
581 cerr
<< "add collection" << std::endl
;
582 auto ch
= store
->create_new_collection(cid
);
583 r
= queue_transaction(store
, ch
, std::move(t
));
587 ObjectStore::Transaction t
;
588 t
.remove_collection(cid
);
589 cerr
<< "remove collection" << std::endl
;
590 auto ch
= store
->open_collection(cid
);
591 r
= queue_transaction(store
, ch
, std::move(t
));
596 TEST_P(StoreTest
, SimpleColPreHashTest
) {
597 // Firstly we will need to revert the value making sure
598 // collection hint actually works
599 int merge_threshold
= g_ceph_context
->_conf
->filestore_merge_threshold
;
600 std::ostringstream oss
;
601 if (merge_threshold
> 0) {
602 oss
<< "-" << merge_threshold
;
603 SetVal(g_conf(), "filestore_merge_threshold", oss
.str().c_str());
606 uint32_t pg_num
= 128;
608 boost::uniform_int
<> pg_id_range(0, pg_num
);
609 gen_type
rng(time(NULL
));
610 int pg_id
= pg_id_range(rng
);
612 int objs_per_folder
= abs(merge_threshold
) * 16 * g_ceph_context
->_conf
->filestore_split_multiple
;
613 boost::uniform_int
<> folders_range(5, 256);
614 uint64_t expected_num_objs
= (uint64_t)objs_per_folder
* (uint64_t)folders_range(rng
);
616 coll_t
cid(spg_t(pg_t(pg_id
, 15), shard_id_t::NO_SHARD
));
618 auto ch
= store
->create_new_collection(cid
);
620 // Create a collection along with a hint
621 ObjectStore::Transaction t
;
622 t
.create_collection(cid
, 5);
623 cerr
<< "create collection" << std::endl
;
625 encode(pg_num
, hint
);
626 encode(expected_num_objs
, hint
);
627 t
.collection_hint(cid
, ObjectStore::Transaction::COLL_HINT_EXPECTED_NUM_OBJECTS
, hint
);
628 cerr
<< "collection hint" << std::endl
;
629 r
= queue_transaction(store
, ch
, std::move(t
));
633 // Remove the collection
634 ObjectStore::Transaction t
;
635 t
.remove_collection(cid
);
636 cerr
<< "remove collection" << std::endl
;
637 r
= queue_transaction(store
, ch
, std::move(t
));
642 TEST_P(StoreTest
, SmallBlockWrites
) {
645 auto ch
= store
->create_new_collection(cid
);
646 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
648 ObjectStore::Transaction t
;
649 t
.create_collection(cid
, 0);
650 cerr
<< "Creating collection " << cid
<< std::endl
;
651 r
= queue_transaction(store
, ch
, std::move(t
));
655 bufferptr
ap(0x1000);
656 memset(ap
.c_str(), 'a', 0x1000);
659 bufferptr
bp(0x1000);
660 memset(bp
.c_str(), 'b', 0x1000);
663 bufferptr
cp(0x1000);
664 memset(cp
.c_str(), 'c', 0x1000);
666 bufferptr
zp(0x1000);
671 ObjectStore::Transaction t
;
672 t
.write(cid
, hoid
, 0, 0x1000, a
);
673 r
= queue_transaction(store
, ch
, std::move(t
));
677 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
678 ASSERT_EQ(0x1000, r
);
680 ASSERT_TRUE(bl_eq(exp
, in
));
683 ObjectStore::Transaction t
;
684 t
.write(cid
, hoid
, 0x1000, 0x1000, b
);
685 r
= queue_transaction(store
, ch
, std::move(t
));
689 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
690 ASSERT_EQ(0x2000, r
);
693 ASSERT_TRUE(bl_eq(exp
, in
));
696 ObjectStore::Transaction t
;
697 t
.write(cid
, hoid
, 0x3000, 0x1000, c
);
698 r
= queue_transaction(store
, ch
, std::move(t
));
702 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
703 ASSERT_EQ(0x4000, r
);
708 ASSERT_TRUE(bl_eq(exp
, in
));
711 ObjectStore::Transaction t
;
712 t
.write(cid
, hoid
, 0x2000, 0x1000, a
);
713 r
= queue_transaction(store
, ch
, std::move(t
));
717 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
718 ASSERT_EQ(0x4000, r
);
723 ASSERT_TRUE(bl_eq(exp
, in
));
726 ObjectStore::Transaction t
;
727 t
.write(cid
, hoid
, 0, 0x1000, c
);
728 r
= queue_transaction(store
, ch
, std::move(t
));
733 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
734 ASSERT_EQ(0x4000, r
);
739 ASSERT_TRUE(bl_eq(exp
, in
));
742 ObjectStore::Transaction t
;
744 t
.remove_collection(cid
);
745 cerr
<< "Cleaning" << std::endl
;
746 r
= queue_transaction(store
, ch
, std::move(t
));
751 TEST_P(StoreTest
, BufferCacheReadTest
) {
754 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
756 auto ch
= store
->open_collection(cid
);
759 auto ch
= store
->create_new_collection(cid
);
761 ObjectStore::Transaction t
;
762 t
.create_collection(cid
, 0);
763 cerr
<< "Creating collection " << cid
<< std::endl
;
764 r
= queue_transaction(store
, ch
, std::move(t
));
768 bool exists
= store
->exists(ch
, hoid
);
769 ASSERT_TRUE(!exists
);
771 ObjectStore::Transaction t
;
773 cerr
<< "Creating object " << hoid
<< std::endl
;
774 r
= queue_transaction(store
, ch
, std::move(t
));
777 exists
= store
->exists(ch
, hoid
);
778 ASSERT_EQ(true, exists
);
781 ObjectStore::Transaction t
;
782 bufferlist bl
, newdata
;
784 t
.write(cid
, hoid
, 0, 5, bl
);
785 t
.write(cid
, hoid
, 10, 5, bl
);
786 cerr
<< "TwinWrite" << std::endl
;
787 r
= queue_transaction(store
, ch
, std::move(t
));
790 r
= store
->read(ch
, hoid
, 0, 15, newdata
);
795 expected
.append_zero(5);
797 ASSERT_TRUE(bl_eq(expected
, newdata
));
800 //overwrite over the same extents
802 ObjectStore::Transaction t
;
803 bufferlist bl
, newdata
;
805 t
.write(cid
, hoid
, 0, 5, bl
);
806 t
.write(cid
, hoid
, 10, 5, bl
);
807 cerr
<< "TwinWrite" << std::endl
;
808 r
= queue_transaction(store
, ch
, std::move(t
));
811 r
= store
->read(ch
, hoid
, 0, 15, newdata
);
816 expected
.append_zero(5);
818 ASSERT_TRUE(bl_eq(expected
, newdata
));
821 //additional write to an unused region of some blob
823 ObjectStore::Transaction t
;
824 bufferlist bl2
, newdata
;
825 bl2
.append("1234567890");
827 t
.write(cid
, hoid
, 20, bl2
.length(), bl2
);
828 cerr
<< "Append" << std::endl
;
829 r
= queue_transaction(store
, ch
, std::move(t
));
832 r
= store
->read(ch
, hoid
, 0, 30, newdata
);
836 expected
.append("edcba");
837 expected
.append_zero(5);
838 expected
.append("edcba");
839 expected
.append_zero(5);
840 expected
.append(bl2
);
842 ASSERT_TRUE(bl_eq(expected
, newdata
));
845 //additional write to an unused region of some blob and partial owerite over existing extents
847 ObjectStore::Transaction t
;
848 bufferlist bl
, bl2
, bl3
, newdata
;
850 bl2
.append("1234567890");
853 t
.write(cid
, hoid
, 30, bl2
.length(), bl2
);
854 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
855 t
.write(cid
, hoid
, 13, bl3
.length(), bl3
);
856 cerr
<< "TripleWrite" << std::endl
;
857 r
= queue_transaction(store
, ch
, std::move(t
));
860 r
= store
->read(ch
, hoid
, 0, 40, newdata
);
864 expected
.append("eDCBa");
865 expected
.append_zero(5);
866 expected
.append("edcBA");
867 expected
.append_zero(5);
868 expected
.append(bl2
);
869 expected
.append(bl2
);
871 ASSERT_TRUE(bl_eq(expected
, newdata
));
876 void StoreTest::doCompressionTest()
880 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
882 auto ch
= store
->open_collection(cid
);
885 auto ch
= store
->create_new_collection(cid
);
887 ObjectStore::Transaction t
;
888 t
.create_collection(cid
, 0);
889 cerr
<< "Creating collection " << cid
<< std::endl
;
890 r
= queue_transaction(store
, ch
, std::move(t
));
894 bool exists
= store
->exists(ch
, hoid
);
895 ASSERT_TRUE(!exists
);
897 ObjectStore::Transaction t
;
899 cerr
<< "Creating object " << hoid
<< std::endl
;
900 r
= queue_transaction(store
, ch
, std::move(t
));
903 exists
= store
->exists(ch
, hoid
);
904 ASSERT_EQ(true, exists
);
907 data
.resize(0x10000 * 4);
908 for(size_t i
= 0;i
< data
.size(); i
++)
911 ObjectStore::Transaction t
;
912 bufferlist bl
, newdata
;
914 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
915 cerr
<< "CompressibleData (4xAU) Write" << std::endl
;
916 r
= queue_transaction(store
, ch
, std::move(t
));
919 r
= store
->read(ch
, hoid
, 0, data
.size() , newdata
);
921 ASSERT_EQ(r
, (int)data
.size());
924 expected
.append(data
);
925 ASSERT_TRUE(bl_eq(expected
, newdata
));
928 r
= store
->read(ch
, hoid
, 0, 711 , newdata
);
932 expected
.append(data
.substr(0,711));
933 ASSERT_TRUE(bl_eq(expected
, newdata
));
936 r
= store
->read(ch
, hoid
, 0xf00f, data
.size(), newdata
);
937 ASSERT_EQ(r
, int(data
.size() - 0xf00f) );
940 expected
.append(data
.substr(0xf00f));
941 ASSERT_TRUE(bl_eq(expected
, newdata
));
944 struct store_statfs_t statfs
;
945 int r
= store
->statfs(&statfs
);
947 ASSERT_EQ(statfs
.data_stored
, (unsigned)data
.size());
948 ASSERT_LE(statfs
.data_compressed
, (unsigned)data
.size());
949 ASSERT_EQ(statfs
.data_compressed_original
, (unsigned)data
.size());
950 ASSERT_LE(statfs
.data_compressed_allocated
, (unsigned)data
.size());
954 data2
.resize(0x10000 * 4 - 0x9000);
955 for(size_t i
= 0;i
< data2
.size(); i
++)
956 data2
[i
] = (i
+1) / 256;
958 ObjectStore::Transaction t
;
959 bufferlist bl
, newdata
;
961 t
.write(cid
, hoid
, 0x8000, bl
.length(), bl
);
962 cerr
<< "CompressibleData partial overwrite" << std::endl
;
963 r
= queue_transaction(store
, ch
, std::move(t
));
966 r
= store
->read(ch
, hoid
, 0, 0x10000, newdata
);
967 ASSERT_EQ(r
, (int)0x10000);
970 expected
.append(data
.substr(0, 0x8000));
971 expected
.append(data2
.substr(0, 0x8000));
972 ASSERT_TRUE(bl_eq(expected
, newdata
));
975 r
= store
->read(ch
, hoid
, 0x9000, 711 , newdata
);
979 expected
.append(data2
.substr(0x1000,711));
980 ASSERT_TRUE(bl_eq(expected
, newdata
));
983 r
= store
->read(ch
, hoid
, 0x0, 0x40000, newdata
);
984 ASSERT_EQ(r
, int(0x40000) );
987 expected
.append(data
.substr(0, 0x8000));
988 expected
.append(data2
.substr(0, 0x37000));
989 expected
.append(data
.substr(0x3f000, 0x1000));
990 ASSERT_TRUE(bl_eq(expected
, newdata
));
993 data2
.resize(0x3f000);
994 for(size_t i
= 0;i
< data2
.size(); i
++)
995 data2
[i
] = (i
+2) / 256;
997 ObjectStore::Transaction t
;
998 bufferlist bl
, newdata
;
1000 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1001 cerr
<< "CompressibleData partial overwrite, two extents overlapped, single one to be removed" << std::endl
;
1002 r
= queue_transaction(store
, ch
, std::move(t
));
1005 r
= store
->read(ch
, hoid
, 0, 0x3e000 - 1, newdata
);
1006 ASSERT_EQ(r
, (int)0x3e000 - 1);
1008 bufferlist expected
;
1009 expected
.append(data2
.substr(0, 0x3e000 - 1));
1010 ASSERT_TRUE(bl_eq(expected
, newdata
));
1013 r
= store
->read(ch
, hoid
, 0x3e000-1, 0x2001, newdata
);
1014 ASSERT_EQ(r
, 0x2001);
1016 bufferlist expected
;
1017 expected
.append(data2
.substr(0x3e000-1, 0x1001));
1018 expected
.append(data
.substr(0x3f000, 0x1000));
1019 ASSERT_TRUE(bl_eq(expected
, newdata
));
1022 r
= store
->read(ch
, hoid
, 0x0, 0x40000, newdata
);
1023 ASSERT_EQ(r
, int(0x40000) );
1025 bufferlist expected
;
1026 expected
.append(data2
.substr(0, 0x3f000));
1027 expected
.append(data
.substr(0x3f000, 0x1000));
1028 ASSERT_TRUE(bl_eq(expected
, newdata
));
1031 data
.resize(0x1001);
1032 for(size_t i
= 0;i
< data
.size(); i
++)
1033 data
[i
] = (i
+3) / 256;
1035 ObjectStore::Transaction t
;
1036 bufferlist bl
, newdata
;
1038 t
.write(cid
, hoid
, 0x3f000-1, bl
.length(), bl
);
1039 cerr
<< "Small chunk partial overwrite, two extents overlapped, single one to be removed" << std::endl
;
1040 r
= queue_transaction(store
, ch
, std::move(t
));
1043 r
= store
->read(ch
, hoid
, 0x3e000, 0x2000, newdata
);
1044 ASSERT_EQ(r
, (int)0x2000);
1046 bufferlist expected
;
1047 expected
.append(data2
.substr(0x3e000, 0x1000 - 1));
1048 expected
.append(data
.substr(0, 0x1001));
1049 ASSERT_TRUE(bl_eq(expected
, newdata
));
1053 ObjectStore::Transaction t
;
1054 t
.remove(cid
, hoid
);
1055 cerr
<< "Cleaning object" << std::endl
;
1056 r
= queue_transaction(store
, ch
, std::move(t
));
1061 EXPECT_EQ(store
->umount(), 0);
1062 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1063 EXPECT_EQ(store
->mount(), 0);
1064 ch
= store
->open_collection(cid
);
1065 auto settingsBookmark
= BookmarkSettings();
1066 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
1067 g_ceph_context
->_conf
.apply_changes(nullptr);
1069 data
.resize(0x10000*6);
1071 for(size_t i
= 0;i
< data
.size(); i
++)
1073 ObjectStore::Transaction t
;
1074 bufferlist bl
, newdata
;
1076 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1077 cerr
<< "CompressibleData large blob" << std::endl
;
1078 r
= queue_transaction(store
, ch
, std::move(t
));
1083 EXPECT_EQ(store
->umount(), 0);
1084 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1085 EXPECT_EQ(store
->mount(), 0);
1086 ch
= store
->open_collection(cid
);
1088 ObjectStore::Transaction t
;
1089 t
.remove(cid
, hoid
);
1090 t
.remove_collection(cid
);
1091 cerr
<< "Cleaning" << std::endl
;
1092 r
= queue_transaction(store
, ch
, std::move(t
));
1097 TEST_P(StoreTest
, CompressionTest
) {
1098 if (string(GetParam()) != "bluestore")
1101 SetVal(g_conf(), "bluestore_compression_algorithm", "snappy");
1102 SetVal(g_conf(), "bluestore_compression_mode", "force");
1103 g_ceph_context
->_conf
.apply_changes(nullptr);
1104 doCompressionTest();
1106 SetVal(g_conf(), "bluestore_compression_algorithm", "zlib");
1107 SetVal(g_conf(), "bluestore_compression_mode", "aggressive");
1108 g_ceph_context
->_conf
.apply_changes(nullptr);
1109 doCompressionTest();
1112 TEST_P(StoreTest
, SimpleObjectTest
) {
1115 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1117 auto ch
= store
->open_collection(cid
);
1120 auto ch
= store
->create_new_collection(cid
);
1122 ObjectStore::Transaction t
;
1123 t
.create_collection(cid
, 0);
1124 cerr
<< "Creating collection " << cid
<< std::endl
;
1125 r
= queue_transaction(store
, ch
, std::move(t
));
1129 bool exists
= store
->exists(ch
, hoid
);
1130 ASSERT_TRUE(!exists
);
1132 ObjectStore::Transaction t
;
1134 cerr
<< "Creating object " << hoid
<< std::endl
;
1135 r
= queue_transaction(store
, ch
, std::move(t
));
1138 exists
= store
->exists(ch
, hoid
);
1139 ASSERT_EQ(true, exists
);
1142 ObjectStore::Transaction t
;
1143 t
.remove(cid
, hoid
);
1145 cerr
<< "Remove then create" << std::endl
;
1146 r
= queue_transaction(store
, ch
, std::move(t
));
1150 ObjectStore::Transaction t
;
1151 bufferlist bl
, orig
;
1154 t
.remove(cid
, hoid
);
1155 t
.write(cid
, hoid
, 0, 5, bl
);
1156 cerr
<< "Remove then create" << std::endl
;
1157 r
= queue_transaction(store
, ch
, std::move(t
));
1161 r
= store
->read(ch
, hoid
, 0, 5, in
);
1163 ASSERT_TRUE(bl_eq(orig
, in
));
1166 ObjectStore::Transaction t
;
1171 t
.write(cid
, hoid
, 5, 5, bl
);
1172 cerr
<< "Append" << std::endl
;
1173 r
= queue_transaction(store
, ch
, std::move(t
));
1177 r
= store
->read(ch
, hoid
, 0, 10, in
);
1179 ASSERT_TRUE(bl_eq(exp
, in
));
1182 ObjectStore::Transaction t
;
1184 bl
.append("abcdeabcde");
1186 t
.write(cid
, hoid
, 0, 10, bl
);
1187 cerr
<< "Full overwrite" << std::endl
;
1188 r
= queue_transaction(store
, ch
, std::move(t
));
1192 r
= store
->read(ch
, hoid
, 0, 10, in
);
1194 ASSERT_TRUE(bl_eq(exp
, in
));
1197 ObjectStore::Transaction t
;
1200 t
.write(cid
, hoid
, 3, 5, bl
);
1201 cerr
<< "Partial overwrite" << std::endl
;
1202 r
= queue_transaction(store
, ch
, std::move(t
));
1206 exp
.append("abcabcdede");
1207 r
= store
->read(ch
, hoid
, 0, 10, in
);
1210 ASSERT_TRUE(bl_eq(exp
, in
));
1214 ObjectStore::Transaction t
;
1217 t
.truncate(cid
, hoid
, 0);
1218 t
.write(cid
, hoid
, 5, 5, bl
);
1219 cerr
<< "Truncate + hole" << std::endl
;
1220 r
= queue_transaction(store
, ch
, std::move(t
));
1224 ObjectStore::Transaction t
;
1227 t
.write(cid
, hoid
, 0, 5, bl
);
1228 cerr
<< "Reverse fill-in" << std::endl
;
1229 r
= queue_transaction(store
, ch
, std::move(t
));
1234 exp
.append("abcdefghij");
1235 r
= store
->read(ch
, hoid
, 0, 10, in
);
1238 ASSERT_TRUE(bl_eq(exp
, in
));
1241 ObjectStore::Transaction t
;
1243 bl
.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1244 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1245 cerr
<< "larger overwrite" << std::endl
;
1246 r
= queue_transaction(store
, ch
, std::move(t
));
1250 r
= store
->read(ch
, hoid
, 0, bl
.length(), in
);
1251 ASSERT_EQ((int)bl
.length(), r
);
1253 ASSERT_TRUE(bl_eq(bl
, in
));
1257 bl
.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1259 //test: offset=len=0 mean read all data
1261 r
= store
->read(ch
, hoid
, 0, 0, in
);
1262 ASSERT_EQ((int)bl
.length(), r
);
1264 ASSERT_TRUE(bl_eq(bl
, in
));
1267 //verifying unaligned csums
1268 std::string
s1("1"), s2(0x1000, '2'), s3("00");
1270 ObjectStore::Transaction t
;
1274 t
.truncate(cid
, hoid
, 0);
1275 t
.write(cid
, hoid
, 0x1000-1, bl
.length(), bl
);
1276 cerr
<< "Write unaligned csum, stage 1" << std::endl
;
1277 r
= queue_transaction(store
, ch
, std::move(t
));
1281 bufferlist in
, exp1
, exp2
, exp3
;
1285 r
= store
->read(ch
, hoid
, 0x1000-1, 1, in
);
1287 ASSERT_TRUE(bl_eq(exp1
, in
));
1289 r
= store
->read(ch
, hoid
, 0x1000, 0x1000, in
);
1290 ASSERT_EQ(0x1000, r
);
1291 ASSERT_TRUE(bl_eq(exp2
, in
));
1294 ObjectStore::Transaction t
;
1297 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
1298 cerr
<< "Write unaligned csum, stage 2" << std::endl
;
1299 r
= queue_transaction(store
, ch
, std::move(t
));
1303 r
= store
->read(ch
, hoid
, 1, 2, in
);
1305 ASSERT_TRUE(bl_eq(exp3
, in
));
1307 r
= store
->read(ch
, hoid
, 0x1000-1, 1, in
);
1309 ASSERT_TRUE(bl_eq(exp1
, in
));
1311 r
= store
->read(ch
, hoid
, 0x1000, 0x1000, in
);
1312 ASSERT_EQ(0x1000, r
);
1313 ASSERT_TRUE(bl_eq(exp2
, in
));
1318 ObjectStore::Transaction t
;
1319 t
.remove(cid
, hoid
);
1320 t
.remove_collection(cid
);
1321 cerr
<< "Cleaning" << std::endl
;
1322 r
= queue_transaction(store
, ch
, std::move(t
));
1327 #if defined(WITH_BLUESTORE)
1329 TEST_P(StoreTestSpecificAUSize
, ReproBug41901Test
) {
1330 if(string(GetParam()) != "bluestore")
1333 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
1334 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
1335 g_conf().apply_changes(nullptr);
1336 StartDeferred(65536);
1340 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1341 const PerfCounters
* logger
= store
->get_perf_counters();
1342 auto ch
= store
->create_new_collection(cid
);
1344 ObjectStore::Transaction t
;
1345 t
.create_collection(cid
, 0);
1346 cerr
<< "Creating collection " << cid
<< std::endl
;
1347 r
= queue_transaction(store
, ch
, std::move(t
));
1351 bool exists
= store
->exists(ch
, hoid
);
1352 ASSERT_TRUE(!exists
);
1354 ObjectStore::Transaction t
;
1356 cerr
<< "Creating object " << hoid
<< std::endl
;
1357 r
= queue_transaction(store
, ch
, std::move(t
));
1360 exists
= store
->exists(ch
, hoid
);
1361 ASSERT_EQ(true, exists
);
1364 ObjectStore::Transaction t
;
1365 bufferlist bl
, orig
;
1366 string
s(4096, 'a');
1368 t
.write(cid
, hoid
, 0x11000, bl
.length(), bl
);
1369 cerr
<< "write1" << std::endl
;
1370 r
= queue_transaction(store
, ch
, std::move(t
));
1374 ObjectStore::Transaction t
;
1375 bufferlist bl
, orig
;
1376 string
s(4096 * 3, 'a');
1378 t
.write(cid
, hoid
, 0x15000, bl
.length(), bl
);
1379 cerr
<< "write2" << std::endl
;
1380 r
= queue_transaction(store
, ch
, std::move(t
));
1383 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 2u);
1384 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 1u);
1387 ObjectStore::Transaction t
;
1388 bufferlist bl
, orig
;
1389 string
s(4096 * 2, 'a');
1391 t
.write(cid
, hoid
, 0xe000, bl
.length(), bl
);
1392 cerr
<< "write3" << std::endl
;
1393 r
= queue_transaction(store
, ch
, std::move(t
));
1396 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 3u);
1397 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 2u);
1401 ObjectStore::Transaction t
;
1402 bufferlist bl
, orig
;
1403 string
s(4096, 'a');
1405 t
.write(cid
, hoid
, 0xf000, bl
.length(), bl
);
1406 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1407 cerr
<< "write3" << std::endl
;
1408 r
= queue_transaction(store
, ch
, std::move(t
));
1411 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 5u);
1412 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 2u);
1414 ObjectStore::Transaction t
;
1415 t
.remove(cid
, hoid
);
1416 t
.remove_collection(cid
);
1417 cerr
<< "Cleaning" << std::endl
;
1418 r
= queue_transaction(store
, ch
, std::move(t
));
1424 TEST_P(StoreTestSpecificAUSize
, BluestoreStatFSTest
) {
1425 if(string(GetParam()) != "bluestore")
1427 SetVal(g_conf(), "bluestore_block_db_path", "");
1428 StartDeferred(65536);
1429 SetVal(g_conf(), "bluestore_compression_mode", "force");
1430 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
1431 // just a big number to disble gc
1432 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "100000");
1433 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
1434 g_conf().apply_changes(nullptr);
1438 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
1439 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
1444 ghobject_t hoid2
= hoid
;
1445 hoid2
.hobj
.snap
= 1;
1447 auto ch
= store
->open_collection(cid
);
1450 auto ch
= store
->create_new_collection(cid
);
1452 ObjectStore::Transaction t
;
1453 t
.create_collection(cid
, 0);
1454 cerr
<< "Creating collection " << cid
<< std::endl
;
1455 r
= queue_transaction(store
, ch
, std::move(t
));
1459 bool exists
= store
->exists(ch
, hoid
);
1460 ASSERT_TRUE(!exists
);
1462 ObjectStore::Transaction t
;
1464 cerr
<< "Creating object " << hoid
<< std::endl
;
1465 r
= queue_transaction(store
, ch
, std::move(t
));
1468 exists
= store
->exists(ch
, hoid
);
1469 ASSERT_EQ(true, exists
);
1472 struct store_statfs_t statfs
;
1473 int r
= store
->statfs(&statfs
);
1475 ASSERT_EQ( 0u, statfs
.allocated
);
1476 ASSERT_EQ( 0u, statfs
.data_stored
);
1477 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
1478 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
1480 struct store_statfs_t statfs_pool
;
1482 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1484 ASSERT_EQ( 0u, statfs_pool
.allocated
);
1485 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
1489 EXPECT_EQ(store
->umount(), 0);
1490 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1491 EXPECT_EQ(store
->mount(), 0);
1492 ch
= store
->open_collection(cid
);
1495 ObjectStore::Transaction t
;
1498 t
.write(cid
, hoid
, 0, 5, bl
);
1499 cerr
<< "Append 5 bytes" << std::endl
;
1500 r
= queue_transaction(store
, ch
, std::move(t
));
1503 struct store_statfs_t statfs
;
1504 int r
= store
->statfs(&statfs
);
1506 ASSERT_EQ(5, statfs
.data_stored
);
1507 ASSERT_EQ(0x10000, statfs
.allocated
);
1508 ASSERT_EQ(0, statfs
.data_compressed
);
1509 ASSERT_EQ(0, statfs
.data_compressed_original
);
1510 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1512 struct store_statfs_t statfs_pool
;
1514 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1516 ASSERT_EQ(5, statfs_pool
.data_stored
);
1517 ASSERT_EQ(0x10000, statfs_pool
.allocated
);
1518 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1519 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1520 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1522 // accessing unknown pool
1523 r
= store
->pool_statfs(poolid
+ 1, &statfs_pool
, &per_pool_omap
);
1525 ASSERT_EQ(0, statfs_pool
.data_stored
);
1526 ASSERT_EQ(0, statfs_pool
.allocated
);
1527 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1528 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1529 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1533 EXPECT_EQ(store
->umount(), 0);
1534 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1535 EXPECT_EQ(store
->mount(), 0);
1536 ch
= store
->open_collection(cid
);
1539 ObjectStore::Transaction t
;
1540 std::string
s(0x30000, 'a');
1543 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1544 cerr
<< "Append 0x30000 compressible bytes" << std::endl
;
1545 r
= queue_transaction(store
, ch
, std::move(t
));
1548 struct store_statfs_t statfs
;
1549 int r
= store
->statfs(&statfs
);
1551 ASSERT_EQ(0x30005, statfs
.data_stored
);
1552 ASSERT_EQ(0x30000, statfs
.allocated
);
1553 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1554 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1555 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1557 struct store_statfs_t statfs_pool
;
1559 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1561 ASSERT_EQ(0x30005, statfs_pool
.data_stored
);
1562 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1563 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1564 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1565 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1568 EXPECT_EQ(store
->umount(), 0);
1569 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1570 EXPECT_EQ(store
->mount(), 0);
1571 ch
= store
->open_collection(cid
);
1574 ObjectStore::Transaction t
;
1575 t
.zero(cid
, hoid
, 1, 3);
1576 t
.zero(cid
, hoid
, 0x20000, 9);
1577 cerr
<< "Punch hole at 1~3, 0x20000~9" << std::endl
;
1578 r
= queue_transaction(store
, ch
, std::move(t
));
1581 struct store_statfs_t statfs
;
1582 int r
= store
->statfs(&statfs
);
1584 ASSERT_EQ(0x30005 - 3 - 9, statfs
.data_stored
);
1585 ASSERT_EQ(0x30000, statfs
.allocated
);
1586 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1587 ASSERT_EQ(0x20000 - 9, statfs
.data_compressed_original
);
1588 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1590 struct store_statfs_t statfs_pool
;
1592 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1594 ASSERT_EQ(0x30005 - 3 - 9, statfs_pool
.data_stored
);
1595 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1596 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1597 ASSERT_EQ(0x20000 - 9, statfs_pool
.data_compressed_original
);
1598 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1601 EXPECT_EQ(store
->umount(), 0);
1602 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1603 EXPECT_EQ(store
->mount(), 0);
1604 ch
= store
->open_collection(cid
);
1607 ObjectStore::Transaction t
;
1608 std::string
s(0x1000, 'b');
1611 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
1612 t
.write(cid
, hoid
, 0x10001, bl
.length(), bl
);
1613 cerr
<< "Overwrite first and second(compressible) extents" << std::endl
;
1614 r
= queue_transaction(store
, ch
, std::move(t
));
1617 struct store_statfs_t statfs
;
1618 int r
= store
->statfs(&statfs
);
1620 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs
.data_stored
);
1621 ASSERT_EQ(0x40000, statfs
.allocated
);
1622 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1623 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs
.data_compressed_original
);
1624 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1626 struct store_statfs_t statfs_pool
;
1628 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1630 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs_pool
.data_stored
);
1631 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1632 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1633 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs_pool
.data_compressed_original
);
1634 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1637 EXPECT_EQ(store
->umount(), 0);
1638 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1639 EXPECT_EQ(store
->mount(), 0);
1640 ch
= store
->open_collection(cid
);
1643 ObjectStore::Transaction t
;
1644 std::string
s(0x10000, 'c');
1647 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1648 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
1649 t
.write(cid
, hoid
, 0x30000, bl
.length(), bl
);
1650 cerr
<< "Overwrite compressed extent with 3 uncompressible ones" << std::endl
;
1651 r
= queue_transaction(store
, ch
, std::move(t
));
1654 struct store_statfs_t statfs
;
1655 int r
= store
->statfs(&statfs
);
1657 ASSERT_EQ(0x30000 + 0x1001, statfs
.data_stored
);
1658 ASSERT_EQ(0x40000, statfs
.allocated
);
1659 ASSERT_LE(statfs
.data_compressed
, 0);
1660 ASSERT_EQ(0, statfs
.data_compressed_original
);
1661 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1663 struct store_statfs_t statfs_pool
;
1665 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1667 ASSERT_EQ(0x30000 + 0x1001, statfs_pool
.data_stored
);
1668 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1669 ASSERT_LE(statfs_pool
.data_compressed
, 0);
1670 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1671 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1674 EXPECT_EQ(store
->umount(), 0);
1675 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1676 EXPECT_EQ(store
->mount(), 0);
1677 ch
= store
->open_collection(cid
);
1680 ObjectStore::Transaction t
;
1681 t
.zero(cid
, hoid
, 0, 0x40000);
1682 cerr
<< "Zero object" << std::endl
;
1683 r
= queue_transaction(store
, ch
, std::move(t
));
1685 struct store_statfs_t statfs
;
1686 int r
= store
->statfs(&statfs
);
1688 ASSERT_EQ(0u, statfs
.allocated
);
1689 ASSERT_EQ(0u, statfs
.data_stored
);
1690 ASSERT_EQ(0u, statfs
.data_compressed_original
);
1691 ASSERT_EQ(0u, statfs
.data_compressed
);
1692 ASSERT_EQ(0u, statfs
.data_compressed_allocated
);
1694 struct store_statfs_t statfs_pool
;
1696 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1698 ASSERT_EQ(0u, statfs_pool
.allocated
);
1699 ASSERT_EQ(0u, statfs_pool
.data_stored
);
1700 ASSERT_EQ(0u, statfs_pool
.data_compressed_original
);
1701 ASSERT_EQ(0u, statfs_pool
.data_compressed
);
1702 ASSERT_EQ(0u, statfs_pool
.data_compressed_allocated
);
1705 EXPECT_EQ(store
->umount(), 0);
1706 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1707 EXPECT_EQ(store
->mount(), 0);
1708 ch
= store
->open_collection(cid
);
1711 ObjectStore::Transaction t
;
1712 std::string
s(0x10000, 'c');
1717 bl
.append(s
.substr(0, 0x10000-2));
1718 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1719 cerr
<< "Yet another compressible write" << std::endl
;
1720 r
= queue_transaction(store
, ch
, std::move(t
));
1722 struct store_statfs_t statfs
;
1723 r
= store
->statfs(&statfs
);
1725 ASSERT_EQ(0x40000 - 2, statfs
.data_stored
);
1726 ASSERT_EQ(0x30000, statfs
.allocated
);
1727 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1728 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1729 ASSERT_EQ(0x10000, statfs
.data_compressed_allocated
);
1731 struct store_statfs_t statfs_pool
;
1733 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1735 ASSERT_EQ(0x40000 - 2, statfs_pool
.data_stored
);
1736 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1737 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1738 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1739 ASSERT_EQ(0x10000, statfs_pool
.data_compressed_allocated
);
1742 EXPECT_EQ(store
->umount(), 0);
1743 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1744 EXPECT_EQ(store
->mount(), 0);
1745 ch
= store
->open_collection(cid
);
1748 struct store_statfs_t statfs
;
1749 r
= store
->statfs(&statfs
);
1752 struct store_statfs_t statfs_pool
;
1754 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1757 ObjectStore::Transaction t
;
1758 t
.clone(cid
, hoid
, hoid2
);
1759 cerr
<< "Clone compressed objecte" << std::endl
;
1760 r
= queue_transaction(store
, ch
, std::move(t
));
1762 struct store_statfs_t statfs2
;
1763 r
= store
->statfs(&statfs2
);
1765 ASSERT_GT(statfs2
.data_stored
, statfs
.data_stored
);
1766 ASSERT_EQ(statfs2
.allocated
, statfs
.allocated
);
1767 ASSERT_GT(statfs2
.data_compressed
, statfs
.data_compressed
);
1768 ASSERT_GT(statfs2
.data_compressed_original
, statfs
.data_compressed_original
);
1769 ASSERT_EQ(statfs2
.data_compressed_allocated
, statfs
.data_compressed_allocated
);
1771 struct store_statfs_t statfs2_pool
;
1772 r
= store
->pool_statfs(poolid
, &statfs2_pool
, &per_pool_omap
);
1774 ASSERT_GT(statfs2_pool
.data_stored
, statfs_pool
.data_stored
);
1775 ASSERT_EQ(statfs2_pool
.allocated
, statfs_pool
.allocated
);
1776 ASSERT_GT(statfs2_pool
.data_compressed
, statfs_pool
.data_compressed
);
1777 ASSERT_GT(statfs2_pool
.data_compressed_original
,
1778 statfs_pool
.data_compressed_original
);
1779 ASSERT_EQ(statfs2_pool
.data_compressed_allocated
,
1780 statfs_pool
.data_compressed_allocated
);
1785 auto poolid2
= poolid
+ 1;
1786 coll_t cid2
= coll_t(spg_t(pg_t(20, poolid2
), shard_id_t::NO_SHARD
));
1787 ghobject_t
hoid(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
1792 auto ch
= store
->create_new_collection(cid2
);
1796 struct store_statfs_t statfs1_pool
;
1798 int r
= store
->pool_statfs(poolid
, &statfs1_pool
, &per_pool_omap
);
1801 cerr
<< "Creating second collection " << cid2
<< std::endl
;
1802 ObjectStore::Transaction t
;
1803 t
.create_collection(cid2
, 0);
1804 r
= queue_transaction(store
, ch
, std::move(t
));
1807 t
= ObjectStore::Transaction();
1810 t
.write(cid2
, hoid
, 0, 5, bl
);
1811 r
= queue_transaction(store
, ch
, std::move(t
));
1814 struct store_statfs_t statfs2_pool
;
1815 r
= store
->pool_statfs(poolid2
, &statfs2_pool
, &per_pool_omap
);
1817 ASSERT_EQ(5, statfs2_pool
.data_stored
);
1818 ASSERT_EQ(0x10000, statfs2_pool
.allocated
);
1819 ASSERT_EQ(0, statfs2_pool
.data_compressed
);
1820 ASSERT_EQ(0, statfs2_pool
.data_compressed_original
);
1821 ASSERT_EQ(0, statfs2_pool
.data_compressed_allocated
);
1823 struct store_statfs_t statfs1_pool_again
;
1824 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
, &per_pool_omap
);
1826 // adjust 'available' since it has changed
1827 statfs1_pool_again
.available
= statfs1_pool
.available
;
1828 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
1830 t
= ObjectStore::Transaction();
1831 t
.remove(cid2
, hoid
);
1832 t
.remove_collection(cid2
);
1833 cerr
<< "Cleaning" << std::endl
;
1834 r
= queue_transaction(store
, ch
, std::move(t
));
1840 // verify ops on temporary object
1842 auto poolid3
= poolid
+ 2;
1843 coll_t cid3
= coll_t(spg_t(pg_t(20, poolid3
), shard_id_t::NO_SHARD
));
1844 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
),
1849 ghobject_t hoid3_temp
;
1850 hoid3_temp
.hobj
= hoid3
.hobj
.make_temp_hobject("Object 3 temp");
1851 auto ch3
= store
->create_new_collection(cid3
);
1853 struct store_statfs_t statfs1_pool
;
1855 int r
= store
->pool_statfs(poolid
, &statfs1_pool
, &per_pool_omap
);
1858 cerr
<< "Creating third collection " << cid3
<< std::endl
;
1859 ObjectStore::Transaction t
;
1860 t
.create_collection(cid3
, 0);
1861 r
= queue_transaction(store
, ch3
, std::move(t
));
1864 t
= ObjectStore::Transaction();
1867 t
.write(cid3
, hoid3_temp
, 0, 5, bl
);
1868 r
= queue_transaction(store
, ch3
, std::move(t
));
1871 struct store_statfs_t statfs3_pool
;
1872 r
= store
->pool_statfs(poolid3
, &statfs3_pool
, &per_pool_omap
);
1874 ASSERT_EQ(5, statfs3_pool
.data_stored
);
1875 ASSERT_EQ(0x10000, statfs3_pool
.allocated
);
1876 ASSERT_EQ(0, statfs3_pool
.data_compressed
);
1877 ASSERT_EQ(0, statfs3_pool
.data_compressed_original
);
1878 ASSERT_EQ(0, statfs3_pool
.data_compressed_allocated
);
1880 struct store_statfs_t statfs1_pool_again
;
1881 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
, &per_pool_omap
);
1883 // adjust 'available' since it has changed
1884 statfs1_pool_again
.available
= statfs1_pool
.available
;
1885 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
1890 EXPECT_EQ(store
->umount(), 0);
1891 EXPECT_EQ(store
->mount(), 0);
1892 ch
= store
->open_collection(cid
);
1893 ch3
= store
->open_collection(cid3
);
1895 t
= ObjectStore::Transaction();
1896 t
.collection_move_rename(
1899 r
= queue_transaction(store
, ch3
, std::move(t
));
1902 struct store_statfs_t statfs3_pool_again
;
1903 r
= store
->pool_statfs(poolid3
, &statfs3_pool_again
, &per_pool_omap
);
1905 ASSERT_EQ(statfs3_pool_again
, statfs3_pool
);
1910 EXPECT_EQ(store
->umount(), 0);
1911 EXPECT_EQ(store
->mount(), 0);
1912 ch
= store
->open_collection(cid
);
1913 ch3
= store
->open_collection(cid3
);
1915 t
= ObjectStore::Transaction();
1916 t
.remove(cid3
, hoid3
);
1917 t
.remove_collection(cid3
);
1918 cerr
<< "Cleaning" << std::endl
;
1919 r
= queue_transaction(store
, ch3
, std::move(t
));
1925 ObjectStore::Transaction t
;
1926 t
.remove(cid
, hoid
);
1927 t
.remove(cid
, hoid2
);
1928 t
.remove_collection(cid
);
1929 cerr
<< "Cleaning" << std::endl
;
1930 r
= queue_transaction(store
, ch
, std::move(t
));
1933 struct store_statfs_t statfs
;
1934 r
= store
->statfs(&statfs
);
1936 ASSERT_EQ( 0u, statfs
.allocated
);
1937 ASSERT_EQ( 0u, statfs
.data_stored
);
1938 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
1939 ASSERT_EQ( 0u, statfs
.data_compressed
);
1940 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
1942 struct store_statfs_t statfs_pool
;
1944 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1946 ASSERT_EQ( 0u, statfs_pool
.allocated
);
1947 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
1948 ASSERT_EQ( 0u, statfs_pool
.data_compressed_original
);
1949 ASSERT_EQ( 0u, statfs_pool
.data_compressed
);
1950 ASSERT_EQ( 0u, statfs_pool
.data_compressed_allocated
);
1954 TEST_P(StoreTestSpecificAUSize
, BluestoreFragmentedBlobTest
) {
1955 if(string(GetParam()) != "bluestore")
1957 SetVal(g_conf(), "bluestore_block_db_path", "");
1958 StartDeferred(0x10000);
1962 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1963 auto ch
= store
->create_new_collection(cid
);
1965 ObjectStore::Transaction t
;
1966 t
.create_collection(cid
, 0);
1967 cerr
<< "Creating collection " << cid
<< std::endl
;
1968 r
= queue_transaction(store
, ch
, std::move(t
));
1972 bool exists
= store
->exists(ch
, hoid
);
1973 ASSERT_TRUE(!exists
);
1975 ObjectStore::Transaction t
;
1977 cerr
<< "Creating object " << hoid
<< std::endl
;
1978 r
= queue_transaction(store
, ch
, std::move(t
));
1981 exists
= store
->exists(ch
, hoid
);
1982 ASSERT_EQ(true, exists
);
1985 struct store_statfs_t statfs
;
1986 int r
= store
->statfs(&statfs
);
1988 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
1989 ASSERT_EQ(0u, statfs
.allocated
);
1990 ASSERT_EQ(0u, statfs
.data_stored
);
1991 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
1994 data
.resize(0x10000 * 3);
1996 ObjectStore::Transaction t
;
1997 for(size_t i
= 0;i
< data
.size(); i
++)
1998 data
[i
] = i
/ 256 + 1;
1999 bufferlist bl
, newdata
;
2001 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
2002 t
.zero(cid
, hoid
, 0x10000, 0x10000);
2003 cerr
<< "Append 3*0x10000 bytes and punch a hole 0x10000~10000" << std::endl
;
2004 r
= queue_transaction(store
, ch
, std::move(t
));
2007 struct store_statfs_t statfs
;
2008 int r
= store
->statfs(&statfs
);
2010 ASSERT_EQ(0x20000, statfs
.data_stored
);
2011 ASSERT_EQ(0x20000, statfs
.allocated
);
2013 r
= store
->read(ch
, hoid
, 0, data
.size(), newdata
);
2014 ASSERT_EQ(r
, (int)data
.size());
2016 bufferlist expected
;
2017 expected
.append(data
.substr(0, 0x10000));
2018 expected
.append(string(0x10000, 0));
2019 expected
.append(data
.substr(0x20000, 0x10000));
2020 ASSERT_TRUE(bl_eq(expected
, newdata
));
2024 r
= store
->read(ch
, hoid
, 1, data
.size()-2, newdata
);
2025 ASSERT_EQ(r
, (int)data
.size()-2);
2027 bufferlist expected
;
2028 expected
.append(data
.substr(1, 0x10000-1));
2029 expected
.append(string(0x10000, 0));
2030 expected
.append(data
.substr(0x20000, 0x10000 - 1));
2031 ASSERT_TRUE(bl_eq(expected
, newdata
));
2037 EXPECT_EQ(store
->umount(), 0);
2038 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2039 EXPECT_EQ(store
->mount(), 0);
2040 ch
= store
->open_collection(cid
);
2043 ObjectStore::Transaction t
;
2044 std::string
data2(3, 'b');
2045 bufferlist bl
, newdata
;
2047 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
2048 cerr
<< "Write 3 bytes after the hole" << std::endl
;
2049 r
= queue_transaction(store
, ch
, std::move(t
));
2052 struct store_statfs_t statfs
;
2053 int r
= store
->statfs(&statfs
);
2055 ASSERT_EQ(0x20000, statfs
.allocated
);
2056 ASSERT_EQ(0x20000, statfs
.data_stored
);
2058 r
= store
->read(ch
, hoid
, 0x20000-1, 21, newdata
);
2059 ASSERT_EQ(r
, (int)21);
2061 bufferlist expected
;
2062 expected
.append(string(0x1, 0));
2063 expected
.append(string(data2
));
2064 expected
.append(data
.substr(0x20003, 21-4));
2065 ASSERT_TRUE(bl_eq(expected
, newdata
));
2071 EXPECT_EQ(store
->umount(), 0);
2072 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2073 EXPECT_EQ(store
->mount(), 0);
2074 ch
= store
->open_collection(cid
);
2077 ObjectStore::Transaction t
;
2078 std::string
data2(3, 'a');
2079 bufferlist bl
, newdata
;
2081 t
.write(cid
, hoid
, 0x10000+1, bl
.length(), bl
);
2082 cerr
<< "Write 3 bytes to the hole" << std::endl
;
2083 r
= queue_transaction(store
, ch
, std::move(t
));
2086 struct store_statfs_t statfs
;
2087 int r
= store
->statfs(&statfs
);
2089 ASSERT_EQ(0x30000, statfs
.allocated
);
2090 ASSERT_EQ(0x20003, statfs
.data_stored
);
2092 r
= store
->read(ch
, hoid
, 0x10000-1, 0x10000+22, newdata
);
2093 ASSERT_EQ(r
, (int)0x10000+22);
2095 bufferlist expected
;
2096 expected
.append(data
.substr(0x10000-1, 1));
2097 expected
.append(string(0x1, 0));
2098 expected
.append(data2
);
2099 expected
.append(string(0x10000-4, 0));
2100 expected
.append(string(0x3, 'b'));
2101 expected
.append(data
.substr(0x20004, 21-3));
2102 ASSERT_TRUE(bl_eq(expected
, newdata
));
2107 ObjectStore::Transaction t
;
2108 bufferlist bl
, newdata
;
2109 bl
.append(string(0x30000, 'c'));
2110 t
.write(cid
, hoid
, 0, 0x30000, bl
);
2111 t
.zero(cid
, hoid
, 0, 0x10000);
2112 t
.zero(cid
, hoid
, 0x20000, 0x10000);
2113 cerr
<< "Rewrite an object and create two holes at the beginning and the end" << std::endl
;
2114 r
= queue_transaction(store
, ch
, std::move(t
));
2117 struct store_statfs_t statfs
;
2118 int r
= store
->statfs(&statfs
);
2120 ASSERT_EQ(0x10000, statfs
.allocated
);
2121 ASSERT_EQ(0x10000, statfs
.data_stored
);
2123 r
= store
->read(ch
, hoid
, 0, 0x30000, newdata
);
2124 ASSERT_EQ(r
, (int)0x30000);
2126 bufferlist expected
;
2127 expected
.append(string(0x10000, 0));
2128 expected
.append(string(0x10000, 'c'));
2129 expected
.append(string(0x10000, 0));
2130 ASSERT_TRUE(bl_eq(expected
, newdata
));
2137 EXPECT_EQ(store
->umount(), 0);
2138 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2139 EXPECT_EQ(store
->mount(), 0);
2140 ch
= store
->open_collection(cid
);
2143 ObjectStore::Transaction t
;
2144 t
.remove(cid
, hoid
);
2145 t
.remove_collection(cid
);
2146 cerr
<< "Cleaning" << std::endl
;
2147 r
= queue_transaction(store
, ch
, std::move(t
));
2150 struct store_statfs_t statfs
;
2151 r
= store
->statfs(&statfs
);
2153 ASSERT_EQ( 0u, statfs
.allocated
);
2154 ASSERT_EQ( 0u, statfs
.data_stored
);
2155 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
2156 ASSERT_EQ( 0u, statfs
.data_compressed
);
2157 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
2162 TEST_P(StoreTest
, ManySmallWrite
) {
2165 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2166 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2167 auto ch
= store
->create_new_collection(cid
);
2169 ObjectStore::Transaction t
;
2170 t
.create_collection(cid
, 0);
2171 cerr
<< "Creating collection " << cid
<< std::endl
;
2172 r
= queue_transaction(store
, ch
, std::move(t
));
2179 for (int i
=0; i
<100; ++i
) {
2180 ObjectStore::Transaction t
;
2181 t
.write(cid
, a
, i
*4096, 4096, bl
, 0);
2182 r
= queue_transaction(store
, ch
, std::move(t
));
2185 for (int i
=0; i
<100; ++i
) {
2186 ObjectStore::Transaction t
;
2187 t
.write(cid
, b
, (rand() % 1024)*4096, 4096, bl
, 0);
2188 r
= queue_transaction(store
, ch
, std::move(t
));
2192 ObjectStore::Transaction t
;
2195 t
.remove_collection(cid
);
2196 cerr
<< "Cleaning" << std::endl
;
2197 r
= queue_transaction(store
, ch
, std::move(t
));
2202 TEST_P(StoreTest
, MultiSmallWriteSameBlock
) {
2205 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2206 auto ch
= store
->create_new_collection(cid
);
2208 ObjectStore::Transaction t
;
2209 t
.create_collection(cid
, 0);
2210 cerr
<< "Creating collection " << cid
<< std::endl
;
2211 r
= queue_transaction(store
, ch
, std::move(t
));
2217 // touch same block in both same transaction, tls, and pipelined txns
2219 ObjectStore::Transaction t
, u
;
2220 t
.write(cid
, a
, 0, 5, bl
, 0);
2221 t
.write(cid
, a
, 5, 5, bl
, 0);
2222 t
.write(cid
, a
, 4094, 5, bl
, 0);
2223 t
.write(cid
, a
, 9000, 5, bl
, 0);
2224 u
.write(cid
, a
, 10, 5, bl
, 0);
2225 u
.write(cid
, a
, 7000, 5, bl
, 0);
2226 t
.register_on_commit(&c
);
2227 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2228 store
->queue_transactions(ch
, v
);
2231 ObjectStore::Transaction t
, u
;
2232 t
.write(cid
, a
, 40, 5, bl
, 0);
2233 t
.write(cid
, a
, 45, 5, bl
, 0);
2234 t
.write(cid
, a
, 4094, 5, bl
, 0);
2235 t
.write(cid
, a
, 6000, 5, bl
, 0);
2236 u
.write(cid
, a
, 610, 5, bl
, 0);
2237 u
.write(cid
, a
, 11000, 5, bl
, 0);
2238 t
.register_on_commit(&d
);
2239 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2240 store
->queue_transactions(ch
, v
);
2246 r
= store
->read(ch
, a
, 0, 16000, bl2
);
2250 ObjectStore::Transaction t
;
2252 t
.remove_collection(cid
);
2253 cerr
<< "Cleaning" << std::endl
;
2254 r
= queue_transaction(store
, ch
, std::move(t
));
2259 TEST_P(StoreTest
, SmallSkipFront
) {
2262 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2263 auto ch
= store
->create_new_collection(cid
);
2265 ObjectStore::Transaction t
;
2266 t
.create_collection(cid
, 0);
2267 cerr
<< "Creating collection " << cid
<< std::endl
;
2268 r
= queue_transaction(store
, ch
, std::move(t
));
2272 ObjectStore::Transaction t
;
2274 t
.truncate(cid
, a
, 3000);
2275 r
= queue_transaction(store
, ch
, std::move(t
));
2281 memset(bp
.c_str(), 1, 4096);
2283 ObjectStore::Transaction t
;
2284 t
.write(cid
, a
, 4096, 4096, bl
);
2285 r
= queue_transaction(store
, ch
, std::move(t
));
2290 ASSERT_EQ(8192, store
->read(ch
, a
, 0, 8192, bl
));
2291 for (unsigned i
=0; i
<4096; ++i
)
2292 ASSERT_EQ(0, bl
[i
]);
2293 for (unsigned i
=4096; i
<8192; ++i
)
2294 ASSERT_EQ(1, bl
[i
]);
2297 ObjectStore::Transaction t
;
2299 t
.remove_collection(cid
);
2300 cerr
<< "Cleaning" << std::endl
;
2301 r
= queue_transaction(store
, ch
, std::move(t
));
2306 TEST_P(StoreTest
, AppendDeferredVsTailCache
) {
2309 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2310 auto ch
= store
->create_new_collection(cid
);
2312 ObjectStore::Transaction t
;
2313 t
.create_collection(cid
, 0);
2314 cerr
<< "Creating collection " << cid
<< std::endl
;
2315 r
= store
->queue_transaction(ch
, std::move(t
));
2318 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2319 unsigned size
= min_alloc
/ 3;
2320 bufferptr
bpa(size
);
2321 memset(bpa
.c_str(), 1, bpa
.length());
2325 ObjectStore::Transaction t
;
2326 t
.write(cid
, a
, 0, bla
.length(), bla
, 0);
2327 r
= store
->queue_transaction(ch
, std::move(t
));
2331 // force cached tail to clear ...
2334 int r
= store
->umount();
2338 ch
= store
->open_collection(cid
);
2341 bufferptr
bpb(size
);
2342 memset(bpb
.c_str(), 2, bpb
.length());
2346 ObjectStore::Transaction t
;
2347 t
.write(cid
, a
, bla
.length(), blb
.length(), blb
, 0);
2348 r
= store
->queue_transaction(ch
, std::move(t
));
2351 bufferptr
bpc(size
);
2352 memset(bpc
.c_str(), 3, bpc
.length());
2356 ObjectStore::Transaction t
;
2357 t
.write(cid
, a
, bla
.length() + blb
.length(), blc
.length(), blc
, 0);
2358 r
= store
->queue_transaction(ch
, std::move(t
));
2367 ASSERT_EQ((int)final
.length(),
2368 store
->read(ch
, a
, 0, final
.length(), actual
));
2369 ASSERT_TRUE(bl_eq(final
, actual
));
2372 ObjectStore::Transaction t
;
2374 t
.remove_collection(cid
);
2375 cerr
<< "Cleaning" << std::endl
;
2376 r
= store
->queue_transaction(ch
, std::move(t
));
2381 TEST_P(StoreTest
, AppendZeroTrailingSharedBlock
) {
2384 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2387 auto ch
= store
->create_new_collection(cid
);
2389 ObjectStore::Transaction t
;
2390 t
.create_collection(cid
, 0);
2391 cerr
<< "Creating collection " << cid
<< std::endl
;
2392 r
= store
->queue_transaction(ch
, std::move(t
));
2395 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2396 unsigned size
= min_alloc
/ 3;
2397 bufferptr
bpa(size
);
2398 memset(bpa
.c_str(), 1, bpa
.length());
2401 // make sure there is some trailing gunk in the last block
2405 bt
.append("BADBADBADBAD");
2406 ObjectStore::Transaction t
;
2407 t
.write(cid
, a
, 0, bt
.length(), bt
, 0);
2408 r
= store
->queue_transaction(ch
, std::move(t
));
2412 ObjectStore::Transaction t
;
2413 t
.truncate(cid
, a
, size
);
2414 r
= store
->queue_transaction(ch
, std::move(t
));
2420 ObjectStore::Transaction t
;
2422 r
= store
->queue_transaction(ch
, std::move(t
));
2426 // append with implicit zeroing
2427 bufferptr
bpb(size
);
2428 memset(bpb
.c_str(), 2, bpb
.length());
2432 ObjectStore::Transaction t
;
2433 t
.write(cid
, a
, min_alloc
* 3, blb
.length(), blb
, 0);
2434 r
= store
->queue_transaction(ch
, std::move(t
));
2440 zeros
.append_zero(min_alloc
* 3 - size
);
2441 final
.append(zeros
);
2445 ASSERT_EQ((int)final
.length(),
2446 store
->read(ch
, a
, 0, final
.length(), actual
));
2447 final
.hexdump(cout
);
2448 actual
.hexdump(cout
);
2449 ASSERT_TRUE(bl_eq(final
, actual
));
2452 ObjectStore::Transaction t
;
2455 t
.remove_collection(cid
);
2456 cerr
<< "Cleaning" << std::endl
;
2457 r
= store
->queue_transaction(ch
, std::move(t
));
2462 TEST_P(StoreTest
, SmallSequentialUnaligned
) {
2465 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2466 auto ch
= store
->create_new_collection(cid
);
2468 ObjectStore::Transaction t
;
2469 t
.create_collection(cid
, 0);
2470 cerr
<< "Creating collection " << cid
<< std::endl
;
2471 r
= queue_transaction(store
, ch
, std::move(t
));
2479 for (int i
=0; i
<1000; ++i
) {
2480 ObjectStore::Transaction t
;
2481 t
.write(cid
, a
, i
*len
, len
, bl
, 0);
2482 r
= queue_transaction(store
, ch
, std::move(t
));
2486 ObjectStore::Transaction t
;
2488 t
.remove_collection(cid
);
2489 cerr
<< "Cleaning" << std::endl
;
2490 r
= queue_transaction(store
, ch
, std::move(t
));
2495 TEST_P(StoreTest
, ManyBigWrite
) {
2498 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2499 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2500 auto ch
= store
->create_new_collection(cid
);
2502 ObjectStore::Transaction t
;
2503 t
.create_collection(cid
, 0);
2504 cerr
<< "Creating collection " << cid
<< std::endl
;
2505 r
= queue_transaction(store
, ch
, std::move(t
));
2509 bufferptr
bp(4 * 1048576);
2512 for (int i
=0; i
<10; ++i
) {
2513 ObjectStore::Transaction t
;
2514 t
.write(cid
, a
, i
*4*1048586, 4*1048576, bl
, 0);
2515 r
= queue_transaction(store
, ch
, std::move(t
));
2519 for (int i
=0; i
<10; ++i
) {
2520 ObjectStore::Transaction t
;
2521 t
.write(cid
, b
, (rand() % 256)*4*1048576, 4*1048576, bl
, 0);
2522 r
= queue_transaction(store
, ch
, std::move(t
));
2526 for (int i
=0; i
<10; ++i
) {
2527 ObjectStore::Transaction t
;
2528 t
.write(cid
, b
, (rand() % (256*4096))*1024, 4*1048576, bl
, 0);
2529 r
= queue_transaction(store
, ch
, std::move(t
));
2533 for (int i
=0; i
<10; ++i
) {
2534 ObjectStore::Transaction t
;
2535 t
.zero(cid
, b
, (rand() % (256*4096))*1024, 16*1048576);
2536 r
= queue_transaction(store
, ch
, std::move(t
));
2540 ObjectStore::Transaction t
;
2543 t
.remove_collection(cid
);
2544 cerr
<< "Cleaning" << std::endl
;
2545 r
= queue_transaction(store
, ch
, std::move(t
));
2550 TEST_P(StoreTest
, BigWriteBigZero
) {
2553 ghobject_t
a(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2554 auto ch
= store
->create_new_collection(cid
);
2556 ObjectStore::Transaction t
;
2557 t
.create_collection(cid
, 0);
2558 r
= queue_transaction(store
, ch
, std::move(t
));
2562 bufferptr
bp(1048576);
2563 memset(bp
.c_str(), 'b', bp
.length());
2567 memset(sp
.c_str(), 's', sp
.length());
2570 ObjectStore::Transaction t
;
2571 t
.write(cid
, a
, 0, bl
.length(), bl
);
2572 r
= queue_transaction(store
, ch
, std::move(t
));
2576 ObjectStore::Transaction t
;
2577 t
.zero(cid
, a
, bl
.length() / 4, bl
.length() / 2);
2578 r
= queue_transaction(store
, ch
, std::move(t
));
2582 ObjectStore::Transaction t
;
2583 t
.write(cid
, a
, bl
.length() / 2, s
.length(), s
);
2584 r
= queue_transaction(store
, ch
, std::move(t
));
2588 ObjectStore::Transaction t
;
2590 t
.remove_collection(cid
);
2591 r
= queue_transaction(store
, ch
, std::move(t
));
2596 TEST_P(StoreTest
, MiscFragmentTests
) {
2599 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2600 auto ch
= store
->create_new_collection(cid
);
2602 ObjectStore::Transaction t
;
2603 t
.create_collection(cid
, 0);
2604 cerr
<< "Creating collection " << cid
<< std::endl
;
2605 r
= queue_transaction(store
, ch
, std::move(t
));
2609 bufferptr
bp(524288);
2613 ObjectStore::Transaction t
;
2614 t
.write(cid
, a
, 0, 524288, bl
, 0);
2615 r
= queue_transaction(store
, ch
, std::move(t
));
2619 ObjectStore::Transaction t
;
2620 t
.write(cid
, a
, 1048576, 524288, bl
, 0);
2621 r
= queue_transaction(store
, ch
, std::move(t
));
2626 int r
= store
->read(ch
, a
, 524288 + 131072, 1024, inbl
);
2628 ASSERT_EQ(inbl
.length(), 1024u);
2629 ASSERT_TRUE(inbl
.is_zero());
2632 ObjectStore::Transaction t
;
2633 t
.write(cid
, a
, 1048576 - 4096, 524288, bl
, 0);
2634 r
= queue_transaction(store
, ch
, std::move(t
));
2638 ObjectStore::Transaction t
;
2640 t
.remove_collection(cid
);
2641 cerr
<< "Cleaning" << std::endl
;
2642 r
= queue_transaction(store
, ch
, std::move(t
));
2648 TEST_P(StoreTest
, ZeroVsObjectSize
) {
2652 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2653 auto ch
= store
->create_new_collection(cid
);
2655 ObjectStore::Transaction t
;
2656 t
.create_collection(cid
, 0);
2657 cerr
<< "Creating collection " << cid
<< std::endl
;
2658 r
= queue_transaction(store
, ch
, std::move(t
));
2664 ObjectStore::Transaction t
;
2665 t
.write(cid
, hoid
, 0, 5, a
);
2666 r
= queue_transaction(store
, ch
, std::move(t
));
2669 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2670 ASSERT_EQ(5, stat
.st_size
);
2672 ObjectStore::Transaction t
;
2673 t
.zero(cid
, hoid
, 1, 2);
2674 r
= queue_transaction(store
, ch
, std::move(t
));
2677 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2678 ASSERT_EQ(5, stat
.st_size
);
2680 ObjectStore::Transaction t
;
2681 t
.zero(cid
, hoid
, 3, 200);
2682 r
= queue_transaction(store
, ch
, std::move(t
));
2685 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2686 ASSERT_EQ(203, stat
.st_size
);
2688 ObjectStore::Transaction t
;
2689 t
.zero(cid
, hoid
, 100000, 200);
2690 r
= queue_transaction(store
, ch
, std::move(t
));
2693 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2694 ASSERT_EQ(100200, stat
.st_size
);
2697 TEST_P(StoreTest
, ZeroLengthWrite
) {
2700 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2701 auto ch
= store
->create_new_collection(cid
);
2703 ObjectStore::Transaction t
;
2704 t
.create_collection(cid
, 0);
2706 r
= queue_transaction(store
, ch
, std::move(t
));
2710 ObjectStore::Transaction t
;
2712 t
.write(cid
, hoid
, 1048576, 0, empty
);
2713 r
= queue_transaction(store
, ch
, std::move(t
));
2717 r
= store
->stat(ch
, hoid
, &stat
);
2719 ASSERT_EQ(0, stat
.st_size
);
2722 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2726 TEST_P(StoreTest
, ZeroLengthZero
) {
2729 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2730 auto ch
= store
->create_new_collection(cid
);
2732 ObjectStore::Transaction t
;
2733 t
.create_collection(cid
, 0);
2735 r
= queue_transaction(store
, ch
, std::move(t
));
2739 ObjectStore::Transaction t
;
2740 t
.zero(cid
, hoid
, 1048576, 0);
2741 r
= queue_transaction(store
, ch
, std::move(t
));
2745 r
= store
->stat(ch
, hoid
, &stat
);
2747 ASSERT_EQ(0, stat
.st_size
);
2750 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2754 TEST_P(StoreTest
, SimpleAttrTest
) {
2757 ghobject_t
hoid(hobject_t(sobject_t("attr object 1", CEPH_NOSNAP
)));
2758 bufferlist val
, val2
;
2759 val
.append("value");
2760 val
.append("value2");
2762 auto ch
= store
->open_collection(cid
);
2765 auto ch
= store
->create_new_collection(cid
);
2767 ObjectStore::Transaction t
;
2768 t
.create_collection(cid
, 0);
2769 r
= queue_transaction(store
, ch
, std::move(t
));
2774 int r
= store
->collection_empty(ch
, &empty
);
2780 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2781 ASSERT_EQ(-ENOENT
, r
);
2784 ObjectStore::Transaction t
;
2786 t
.setattr(cid
, hoid
, "foo", val
);
2787 t
.setattr(cid
, hoid
, "bar", val2
);
2788 r
= queue_transaction(store
, ch
, std::move(t
));
2793 int r
= store
->collection_empty(ch
, &empty
);
2795 ASSERT_TRUE(!empty
);
2799 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2800 ASSERT_EQ(-ENODATA
, r
);
2802 r
= store
->getattr(ch
, hoid
, "foo", bp
);
2806 ASSERT_TRUE(bl_eq(val
, bl
));
2808 map
<string
,bufferptr
> bm
;
2809 r
= store
->getattrs(ch
, hoid
, bm
);
2814 ObjectStore::Transaction t
;
2815 t
.remove(cid
, hoid
);
2816 t
.remove_collection(cid
);
2817 r
= queue_transaction(store
, ch
, std::move(t
));
2822 TEST_P(StoreTest
, SimpleListTest
) {
2824 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2825 auto ch
= store
->create_new_collection(cid
);
2827 ObjectStore::Transaction t
;
2828 t
.create_collection(cid
, 0);
2829 cerr
<< "Creating collection " << cid
<< std::endl
;
2830 r
= queue_transaction(store
, ch
, std::move(t
));
2833 set
<ghobject_t
> all
;
2835 ObjectStore::Transaction t
;
2836 for (int i
=0; i
<200; ++i
) {
2837 string
name("object_");
2838 name
+= stringify(i
);
2839 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
2840 ghobject_t::NO_GEN
, shard_id_t(1));
2844 cerr
<< "Creating object " << hoid
<< std::endl
;
2846 r
= queue_transaction(store
, ch
, std::move(t
));
2850 set
<ghobject_t
> saw
;
2851 vector
<ghobject_t
> objects
;
2852 ghobject_t next
, current
;
2853 while (!next
.is_max()) {
2854 int r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 50,
2857 ASSERT_TRUE(sorted(objects
));
2858 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
2859 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
2861 if (saw
.count(*p
)) {
2862 cout
<< "got DUP " << *p
<< std::endl
;
2864 //cout << "got new " << *p << std::endl;
2871 ASSERT_EQ(saw
.size(), all
.size());
2872 ASSERT_EQ(saw
, all
);
2875 ObjectStore::Transaction t
;
2876 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
2878 t
.remove_collection(cid
);
2879 cerr
<< "Cleaning" << std::endl
;
2880 r
= queue_transaction(store
, ch
, std::move(t
));
2885 TEST_P(StoreTest
, ListEndTest
) {
2887 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2888 auto ch
= store
->create_new_collection(cid
);
2890 ObjectStore::Transaction t
;
2891 t
.create_collection(cid
, 0);
2892 cerr
<< "Creating collection " << cid
<< std::endl
;
2893 r
= queue_transaction(store
, ch
, std::move(t
));
2896 set
<ghobject_t
> all
;
2898 ObjectStore::Transaction t
;
2899 for (int i
=0; i
<200; ++i
) {
2900 string
name("object_");
2901 name
+= stringify(i
);
2902 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
2903 ghobject_t::NO_GEN
, shard_id_t(1));
2907 cerr
<< "Creating object " << hoid
<< std::endl
;
2909 r
= queue_transaction(store
, ch
, std::move(t
));
2913 ghobject_t
end(hobject_t(sobject_t("object_100", CEPH_NOSNAP
)),
2914 ghobject_t::NO_GEN
, shard_id_t(1));
2916 vector
<ghobject_t
> objects
;
2918 int r
= collection_list(store
, ch
, ghobject_t(), end
, 500, &objects
, &next
);
2920 for (auto &p
: objects
) {
2925 ObjectStore::Transaction t
;
2926 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
2928 t
.remove_collection(cid
);
2929 cerr
<< "Cleaning" << std::endl
;
2930 r
= queue_transaction(store
, ch
, std::move(t
));
2935 TEST_P(StoreTest
, Sort
) {
2937 hobject_t
a(sobject_t("a", CEPH_NOSNAP
));
2950 ghobject_t
a(hobject_t(sobject_t("a", CEPH_NOSNAP
)));
2951 ghobject_t
b(hobject_t(sobject_t("b", CEPH_NOSNAP
)));
2963 TEST_P(StoreTest
, MultipoolListTest
) {
2966 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
2967 auto ch
= store
->create_new_collection(cid
);
2969 ObjectStore::Transaction t
;
2970 t
.create_collection(cid
, 0);
2971 cerr
<< "Creating collection " << cid
<< std::endl
;
2972 r
= queue_transaction(store
, ch
, std::move(t
));
2975 set
<ghobject_t
> all
, saw
;
2977 ObjectStore::Transaction t
;
2978 for (int i
=0; i
<200; ++i
) {
2979 string
name("object_");
2980 name
+= stringify(i
);
2981 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)));
2983 hoid
.hobj
.pool
= -2 - poolid
;
2985 hoid
.hobj
.pool
= poolid
;
2988 cerr
<< "Creating object " << hoid
<< std::endl
;
2990 r
= queue_transaction(store
, ch
, std::move(t
));
2994 vector
<ghobject_t
> objects
;
2995 ghobject_t next
, current
;
2996 while (!next
.is_max()) {
2997 int r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 50,
3000 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
3001 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
3008 ASSERT_EQ(saw
, all
);
3011 ObjectStore::Transaction t
;
3012 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
3014 t
.remove_collection(cid
);
3015 cerr
<< "Cleaning" << std::endl
;
3016 r
= queue_transaction(store
, ch
, std::move(t
));
3021 TEST_P(StoreTest
, SimpleCloneTest
) {
3025 SetDeathTestStyle("threadsafe");
3027 auto ch
= store
->create_new_collection(cid
);
3029 ObjectStore::Transaction t
;
3030 t
.create_collection(cid
, 0);
3031 cerr
<< "Creating collection " << cid
<< std::endl
;
3032 r
= queue_transaction(store
, ch
, std::move(t
));
3035 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
3036 "key", 123, -1, ""));
3037 bufferlist small
, large
, xlarge
, newdata
, attr
;
3038 small
.append("small");
3039 large
.append("large");
3040 xlarge
.append("xlarge");
3042 ObjectStore::Transaction t
;
3044 t
.setattr(cid
, hoid
, "attr1", small
);
3045 t
.setattr(cid
, hoid
, "attr2", large
);
3046 t
.setattr(cid
, hoid
, "attr3", xlarge
);
3047 t
.write(cid
, hoid
, 0, small
.length(), small
);
3048 t
.write(cid
, hoid
, 10, small
.length(), small
);
3049 cerr
<< "Creating object and set attr " << hoid
<< std::endl
;
3050 r
= queue_transaction(store
, ch
, std::move(t
));
3054 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
3055 "key", 123, -1, ""));
3056 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
)));
3058 ObjectStore::Transaction t
;
3059 t
.clone(cid
, hoid
, hoid2
);
3060 t
.setattr(cid
, hoid2
, "attr2", small
);
3061 t
.rmattr(cid
, hoid2
, "attr1");
3062 t
.write(cid
, hoid
, 10, large
.length(), large
);
3063 t
.setattr(cid
, hoid
, "attr1", large
);
3064 t
.setattr(cid
, hoid
, "attr2", small
);
3065 cerr
<< "Clone object and rm attr" << std::endl
;
3066 r
= queue_transaction(store
, ch
, std::move(t
));
3069 r
= store
->read(ch
, hoid
, 10, 5, newdata
);
3071 ASSERT_TRUE(bl_eq(large
, newdata
));
3074 r
= store
->read(ch
, hoid
, 0, 5, newdata
);
3076 ASSERT_TRUE(bl_eq(small
, newdata
));
3079 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
3081 ASSERT_TRUE(bl_eq(small
, newdata
));
3083 r
= store
->getattr(ch
, hoid2
, "attr2", attr
);
3085 ASSERT_TRUE(bl_eq(small
, attr
));
3088 r
= store
->getattr(ch
, hoid2
, "attr3", attr
);
3090 ASSERT_TRUE(bl_eq(xlarge
, attr
));
3093 r
= store
->getattr(ch
, hoid
, "attr1", attr
);
3095 ASSERT_TRUE(bl_eq(large
, attr
));
3098 ObjectStore::Transaction t
;
3099 t
.remove(cid
, hoid
);
3100 t
.remove(cid
, hoid2
);
3101 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3106 memset(p
.c_str(), 1, p
.length());
3110 ObjectStore::Transaction t
;
3111 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3112 t
.clone(cid
, hoid
, hoid2
);
3114 memset(a
.c_str(), 2, a
.length());
3118 t
.write(cid
, hoid
, pl
.length(), a
.length(), al
);
3119 r
= queue_transaction(store
, ch
, std::move(t
));
3122 ASSERT_EQ((int)final
.length(),
3123 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3124 ASSERT_TRUE(bl_eq(rl
, final
));
3127 ObjectStore::Transaction t
;
3128 t
.remove(cid
, hoid
);
3129 t
.remove(cid
, hoid2
);
3130 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3135 memset(p
.c_str(), 111, p
.length());
3139 ObjectStore::Transaction t
;
3140 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3141 t
.clone(cid
, hoid
, hoid2
);
3146 memset(a
.c_str(), 112, a
.length());
3150 t
.write(cid
, hoid
, pl
.length() + z
.length(), a
.length(), al
);
3151 r
= queue_transaction(store
, ch
, std::move(t
));
3154 ASSERT_EQ((int)final
.length(),
3155 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3156 ASSERT_TRUE(bl_eq(rl
, final
));
3159 ObjectStore::Transaction t
;
3160 t
.remove(cid
, hoid
);
3161 t
.remove(cid
, hoid2
);
3162 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3167 memset(p
.c_str(), 5, p
.length());
3171 ObjectStore::Transaction t
;
3172 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3173 t
.clone(cid
, hoid
, hoid2
);
3178 memset(a
.c_str(), 6, a
.length());
3182 t
.write(cid
, hoid
, 17000, a
.length(), al
);
3183 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3185 ASSERT_EQ((int)final
.length(),
3186 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3187 /*cout << "expected:\n";
3188 final.hexdump(cout);
3191 ASSERT_TRUE(bl_eq(rl
, final
));
3194 ObjectStore::Transaction t
;
3195 t
.remove(cid
, hoid
);
3196 t
.remove(cid
, hoid2
);
3197 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3200 bufferptr
p(1048576);
3201 memset(p
.c_str(), 3, p
.length());
3204 ObjectStore::Transaction t
;
3205 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3206 t
.clone(cid
, hoid
, hoid2
);
3208 memset(a
.c_str(), 4, a
.length());
3211 t
.write(cid
, hoid
, a
.length(), a
.length(), al
);
3212 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3215 final
.substr_of(pl
, 0, al
.length());
3218 end
.substr_of(pl
, al
.length()*2, pl
.length() - al
.length()*2);
3220 ASSERT_EQ((int)final
.length(),
3221 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3222 /*cout << "expected:\n";
3223 final.hexdump(cout);
3226 ASSERT_TRUE(bl_eq(rl
, final
));
3229 ObjectStore::Transaction t
;
3230 t
.remove(cid
, hoid
);
3231 t
.remove(cid
, hoid2
);
3232 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3236 memset(p
.c_str(), 7, p
.length());
3239 ObjectStore::Transaction t
;
3240 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3241 t
.clone(cid
, hoid
, hoid2
);
3243 memset(a
.c_str(), 8, a
.length());
3246 t
.write(cid
, hoid
, 32768, a
.length(), al
);
3247 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3250 final
.substr_of(pl
, 0, 32768);
3253 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3255 ASSERT_EQ((int)final
.length(),
3256 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3257 /*cout << "expected:\n";
3258 final.hexdump(cout);
3261 ASSERT_TRUE(bl_eq(rl
, final
));
3264 ObjectStore::Transaction t
;
3265 t
.remove(cid
, hoid
);
3266 t
.remove(cid
, hoid2
);
3267 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3271 memset(p
.c_str(), 9, p
.length());
3274 ObjectStore::Transaction t
;
3275 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3276 t
.clone(cid
, hoid
, hoid2
);
3278 memset(a
.c_str(), 10, a
.length());
3281 t
.write(cid
, hoid
, 33768, a
.length(), al
);
3282 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3285 final
.substr_of(pl
, 0, 33768);
3288 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3290 ASSERT_EQ((int)final
.length(),
3291 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3292 /*cout << "expected:\n";
3293 final.hexdump(cout);
3296 ASSERT_TRUE(bl_eq(rl
, final
));
3300 //verify if non-empty collection is properly handled after store reload
3302 r
= store
->umount();
3306 ch
= store
->open_collection(cid
);
3308 ObjectStore::Transaction t
;
3309 t
.remove_collection(cid
);
3310 cerr
<< "Invalid rm coll" << std::endl
;
3311 PrCtl unset_dumpable
;
3312 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3315 ObjectStore::Transaction t
;
3316 t
.touch(cid
, hoid3
); //new record in db
3317 r
= queue_transaction(store
, ch
, std::move(t
));
3321 ObjectStore::Transaction t
;
3322 //verify if non-empty collection is properly handled when there are some pending removes and live records in db
3323 cerr
<< "Invalid rm coll again" << std::endl
;
3325 r
= store
->umount();
3329 ch
= store
->open_collection(cid
);
3331 t
.remove(cid
, hoid
);
3332 t
.remove(cid
, hoid2
);
3333 t
.remove_collection(cid
);
3334 PrCtl unset_dumpable
;
3335 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3338 ObjectStore::Transaction t
;
3339 t
.remove(cid
, hoid
);
3340 t
.remove(cid
, hoid2
);
3341 t
.remove(cid
, hoid3
);
3342 t
.remove_collection(cid
);
3343 cerr
<< "Cleaning" << std::endl
;
3344 r
= queue_transaction(store
, ch
, std::move(t
));
3349 TEST_P(StoreTest
, OmapSimple
) {
3352 auto ch
= store
->create_new_collection(cid
);
3354 ObjectStore::Transaction t
;
3355 t
.create_collection(cid
, 0);
3356 cerr
<< "Creating collection " << cid
<< std::endl
;
3357 r
= queue_transaction(store
, ch
, std::move(t
));
3360 ghobject_t
hoid(hobject_t(sobject_t("omap_obj", CEPH_NOSNAP
),
3361 "key", 123, -1, ""));
3363 small
.append("small");
3364 map
<string
,bufferlist
> km
;
3366 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3368 header
.append("this is a header");
3370 ObjectStore::Transaction t
;
3372 t
.omap_setkeys(cid
, hoid
, km
);
3373 t
.omap_setheader(cid
, hoid
, header
);
3374 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3375 r
= queue_transaction(store
, ch
, std::move(t
));
3381 map
<string
,bufferlist
> r
;
3382 store
->omap_get(ch
, hoid
, &h
, &r
);
3383 ASSERT_TRUE(bl_eq(header
, h
));
3384 ASSERT_EQ(r
.size(), km
.size());
3385 cout
<< "r: " << r
<< std::endl
;
3387 // test iterator with seek_to_first
3389 map
<string
,bufferlist
> r
;
3390 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3391 for (iter
->seek_to_first(); iter
->valid(); iter
->next()) {
3392 r
[iter
->key()] = iter
->value();
3394 cout
<< "r: " << r
<< std::endl
;
3395 ASSERT_EQ(r
.size(), km
.size());
3397 // test iterator with initial lower_bound
3399 map
<string
,bufferlist
> r
;
3400 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3401 for (iter
->lower_bound(string()); iter
->valid(); iter
->next()) {
3402 r
[iter
->key()] = iter
->value();
3404 cout
<< "r: " << r
<< std::endl
;
3405 ASSERT_EQ(r
.size(), km
.size());
3408 ObjectStore::Transaction t
;
3409 t
.remove(cid
, hoid
);
3410 t
.remove_collection(cid
);
3411 cerr
<< "Cleaning" << std::endl
;
3412 r
= queue_transaction(store
, ch
, std::move(t
));
3417 TEST_P(StoreTest
, OmapCloneTest
) {
3420 auto ch
= store
->create_new_collection(cid
);
3422 ObjectStore::Transaction t
;
3423 t
.create_collection(cid
, 0);
3424 cerr
<< "Creating collection " << cid
<< std::endl
;
3425 r
= queue_transaction(store
, ch
, std::move(t
));
3428 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
3429 "key", 123, -1, ""));
3431 small
.append("small");
3432 map
<string
,bufferlist
> km
;
3434 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3436 header
.append("this is a header");
3438 ObjectStore::Transaction t
;
3440 t
.omap_setkeys(cid
, hoid
, km
);
3441 t
.omap_setheader(cid
, hoid
, header
);
3442 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3443 r
= queue_transaction(store
, ch
, std::move(t
));
3446 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
3447 "key", 123, -1, ""));
3449 ObjectStore::Transaction t
;
3450 t
.clone(cid
, hoid
, hoid2
);
3451 cerr
<< "Clone object" << std::endl
;
3452 r
= queue_transaction(store
, ch
, std::move(t
));
3456 map
<string
,bufferlist
> r
;
3458 store
->omap_get(ch
, hoid2
, &h
, &r
);
3459 ASSERT_TRUE(bl_eq(header
, h
));
3460 ASSERT_EQ(r
.size(), km
.size());
3463 ObjectStore::Transaction t
;
3464 t
.remove(cid
, hoid
);
3465 t
.remove(cid
, hoid2
);
3466 t
.remove_collection(cid
);
3467 cerr
<< "Cleaning" << std::endl
;
3468 r
= queue_transaction(store
, ch
, std::move(t
));
3473 TEST_P(StoreTest
, SimpleCloneRangeTest
) {
3476 auto ch
= store
->create_new_collection(cid
);
3478 ObjectStore::Transaction t
;
3479 t
.create_collection(cid
, 0);
3480 cerr
<< "Creating collection " << cid
<< std::endl
;
3481 r
= queue_transaction(store
, ch
, std::move(t
));
3484 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3485 hoid
.hobj
.pool
= -1;
3486 bufferlist small
, newdata
;
3487 small
.append("small");
3489 ObjectStore::Transaction t
;
3490 t
.write(cid
, hoid
, 10, 5, small
);
3491 cerr
<< "Creating object and write bl " << hoid
<< std::endl
;
3492 r
= queue_transaction(store
, ch
, std::move(t
));
3495 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
3496 hoid2
.hobj
.pool
= -1;
3498 ObjectStore::Transaction t
;
3499 t
.clone_range(cid
, hoid
, hoid2
, 10, 5, 10);
3500 cerr
<< "Clone range object" << std::endl
;
3501 r
= queue_transaction(store
, ch
, std::move(t
));
3503 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
3505 ASSERT_TRUE(bl_eq(small
, newdata
));
3508 ObjectStore::Transaction t
;
3509 t
.truncate(cid
, hoid
, 1024*1024);
3510 t
.clone_range(cid
, hoid
, hoid2
, 0, 1024*1024, 0);
3511 cerr
<< "Clone range object" << std::endl
;
3512 r
= queue_transaction(store
, ch
, std::move(t
));
3514 struct stat stat
, stat2
;
3515 r
= store
->stat(ch
, hoid
, &stat
);
3516 r
= store
->stat(ch
, hoid2
, &stat2
);
3517 ASSERT_EQ(stat
.st_size
, stat2
.st_size
);
3518 ASSERT_EQ(1024*1024, stat2
.st_size
);
3521 ObjectStore::Transaction t
;
3522 t
.remove(cid
, hoid
);
3523 t
.remove(cid
, hoid2
);
3524 r
= queue_transaction(store
, ch
, std::move(t
));
3529 #if defined(WITH_BLUESTORE)
3530 TEST_P(StoreTest
, BlueStoreUnshareBlobTest
) {
3531 if (string(GetParam()) != "bluestore")
3535 auto ch
= store
->create_new_collection(cid
);
3537 ObjectStore::Transaction t
;
3538 t
.create_collection(cid
, 0);
3539 cerr
<< "Creating collection " << cid
<< std::endl
;
3540 r
= queue_transaction(store
, ch
, std::move(t
));
3543 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3544 hoid
.hobj
.pool
= -1;
3545 ghobject_t
hoid2(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3546 hoid2
.hobj
.pool
= -1;
3547 hoid2
.generation
= 2;
3549 // check if blob is unshared properly
3550 bufferlist data
, newdata
;
3551 data
.append(string(8192, 'a'));
3553 ObjectStore::Transaction t
;
3554 t
.write(cid
, hoid
, 0, data
.length(), data
);
3555 cerr
<< "Creating object and write 8K " << hoid
<< std::endl
;
3556 r
= queue_transaction(store
, ch
, std::move(t
));
3559 ObjectStore::Transaction t2
;
3560 t2
.clone_range(cid
, hoid
, hoid2
, 0, 4096, 0);
3561 cerr
<< "Clone range object" << std::endl
;
3562 r
= queue_transaction(store
, ch
, std::move(t2
));
3566 data
.append(string(4096, 'b'));
3568 ObjectStore::Transaction t3
;
3569 t3
.write(cid
, hoid
, 0, data
.length(), data
);
3570 cerr
<< "Writing 4k to source object " << hoid
<< std::endl
;
3571 r
= queue_transaction(store
, ch
, std::move(t3
));
3575 // this trims hoid one out of onode cache
3576 EXPECT_EQ(store
->umount(), 0);
3577 EXPECT_EQ(store
->mount(), 0);
3578 ch
= store
->open_collection(cid
);
3581 ObjectStore::Transaction t4
;
3582 t4
.remove(cid
, hoid2
);
3583 cerr
<< "Deleting dest object" << hoid2
<< std::endl
;
3584 r
= queue_transaction(store
, ch
, std::move(t4
));
3588 r
= store
->read(ch
, hoid
, 0, 0x2000, resdata
);
3589 ASSERT_EQ(r
, 0x2000);
3592 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
3593 auto* kv
= bstore
->get_kv();
3595 // to be inline with BlueStore.cc
3596 const string PREFIX_SHARED_BLOB
= "X";
3599 auto it
= kv
->get_iterator(PREFIX_SHARED_BLOB
);
3601 for (it
->lower_bound(string()); it
->valid(); it
->next()) {
3608 ObjectStore::Transaction t
;
3609 t
.remove(cid
, hoid
);
3610 t
.remove_collection(cid
);
3611 cerr
<< "Cleaning" << std::endl
;
3612 r
= queue_transaction(store
, ch
, std::move(t
));
3617 TEST_P(StoreTest
, BlueStoreUnshareBlobBugTest
) {
3618 if (string(GetParam()) != "bluestore")
3622 auto ch
= store
->create_new_collection(cid
);
3624 ObjectStore::Transaction t
;
3625 t
.create_collection(cid
, 0);
3626 cerr
<< "Creating collection " << cid
<< std::endl
;
3627 r
= queue_transaction(store
, ch
, std::move(t
));
3630 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3631 hoid
.hobj
.pool
= -1;
3632 ghobject_t
hoid2(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3633 hoid2
.hobj
.pool
= -1;
3634 hoid2
.generation
= 2;
3636 // check if blob is unshared properly
3637 bufferlist data
, newdata
;
3638 data
.append(string(8192, 'a'));
3640 ObjectStore::Transaction t
;
3641 t
.write(cid
, hoid
, 0, data
.length(), data
);
3642 cerr
<< "Creating object and write 8K " << hoid
<< std::endl
;
3643 r
= queue_transaction(store
, ch
, std::move(t
));
3646 ObjectStore::Transaction t2
;
3647 t2
.clone_range(cid
, hoid
, hoid2
, 0, 4096, 0);
3648 cerr
<< "Clone range object" << std::endl
;
3649 r
= queue_transaction(store
, ch
, std::move(t2
));
3653 data
.append(string(4096, 'b'));
3655 ObjectStore::Transaction t3
;
3656 t3
.write(cid
, hoid
, 0, data
.length(), data
);
3657 cerr
<< "Writing 4k to source object " << hoid
<< std::endl
;
3658 r
= queue_transaction(store
, ch
, std::move(t3
));
3662 // this trims hoid one out of onode cache
3663 EXPECT_EQ(store
->umount(), 0);
3664 EXPECT_EQ(store
->mount(), 0);
3665 ch
= store
->open_collection(cid
);
3668 ObjectStore::Transaction t4
;
3669 t4
.write(cid
, hoid2
, 0, data
.length(), data
);
3670 cerr
<< "Writing 4k to second object " << hoid2
<< std::endl
;
3671 r
= queue_transaction(store
, ch
, std::move(t4
));
3675 r
= store
->read(ch
, hoid
, 0, 0x2000, resdata
);
3676 ASSERT_EQ(r
, 0x2000);
3679 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
3680 auto* kv
= bstore
->get_kv();
3682 // to be inline with BlueStore.cc
3683 const string PREFIX_SHARED_BLOB
= "X";
3686 auto it
= kv
->get_iterator(PREFIX_SHARED_BLOB
);
3688 for (it
->lower_bound(string()); it
->valid(); it
->next()) {
3691 // This shows a bug in unsharing a blob,
3692 // after writing to 0x0~1000 to hoid2 share blob at hoid should be
3693 //unshared but it doesn't in the current implementation
3698 ObjectStore::Transaction t
;
3699 t
.remove(cid
, hoid
);
3700 t
.remove(cid
, hoid2
);
3701 t
.remove_collection(cid
);
3702 cerr
<< "Cleaning" << std::endl
;
3703 r
= queue_transaction(store
, ch
, std::move(t
));
3709 TEST_P(StoreTest
, SimpleObjectLongnameTest
) {
3712 auto ch
= store
->create_new_collection(cid
);
3714 ObjectStore::Transaction t
;
3715 t
.create_collection(cid
, 0);
3716 cerr
<< "Creating collection " << cid
<< std::endl
;
3717 r
= queue_transaction(store
, ch
, std::move(t
));
3720 ghobject_t
hoid(hobject_t(sobject_t("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaObjectaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1", CEPH_NOSNAP
)));
3722 ObjectStore::Transaction t
;
3724 cerr
<< "Creating object " << hoid
<< std::endl
;
3725 r
= queue_transaction(store
, ch
, std::move(t
));
3729 ObjectStore::Transaction t
;
3730 t
.remove(cid
, hoid
);
3731 t
.remove_collection(cid
);
3732 cerr
<< "Cleaning" << std::endl
;
3733 r
= queue_transaction(store
, ch
, std::move(t
));
3738 ghobject_t
generate_long_name(unsigned i
)
3741 name
<< "object id " << i
<< " ";
3742 for (unsigned j
= 0; j
< 500; ++j
) name
<< 'a';
3743 ghobject_t
hoid(hobject_t(sobject_t(name
.str(), CEPH_NOSNAP
)));
3744 hoid
.hobj
.set_hash(i
% 2);
3748 TEST_P(StoreTest
, LongnameSplitTest
) {
3751 auto ch
= store
->create_new_collection(cid
);
3753 ObjectStore::Transaction t
;
3754 t
.create_collection(cid
, 0);
3755 cerr
<< "Creating collection " << cid
<< std::endl
;
3756 r
= queue_transaction(store
, ch
, std::move(t
));
3759 for (unsigned i
= 0; i
< 320; ++i
) {
3760 ObjectStore::Transaction t
;
3761 ghobject_t hoid
= generate_long_name(i
);
3763 cerr
<< "Creating object " << hoid
<< std::endl
;
3764 r
= queue_transaction(store
, ch
, std::move(t
));
3768 ghobject_t test_obj
= generate_long_name(319);
3769 ghobject_t test_obj_2
= test_obj
;
3770 test_obj_2
.generation
= 0;
3772 ObjectStore::Transaction t
;
3773 // should cause a split
3774 t
.collection_move_rename(
3777 r
= queue_transaction(store
, ch
, std::move(t
));
3781 for (unsigned i
= 0; i
< 319; ++i
) {
3782 ObjectStore::Transaction t
;
3783 ghobject_t hoid
= generate_long_name(i
);
3784 t
.remove(cid
, hoid
);
3785 cerr
<< "Removing object " << hoid
<< std::endl
;
3786 r
= queue_transaction(store
, ch
, std::move(t
));
3790 ObjectStore::Transaction t
;
3791 t
.remove(cid
, test_obj_2
);
3792 t
.remove_collection(cid
);
3793 cerr
<< "Cleaning" << std::endl
;
3794 r
= queue_transaction(store
, ch
, std::move(t
));
3800 TEST_P(StoreTest
, ManyObjectTest
) {
3801 int NUM_OBJS
= 2000;
3805 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
3806 set
<ghobject_t
> created
;
3807 auto ch
= store
->create_new_collection(cid
);
3809 ObjectStore::Transaction t
;
3810 t
.create_collection(cid
, 0);
3811 r
= queue_transaction(store
, ch
, std::move(t
));
3814 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
3816 cerr
<< "Object " << i
<< std::endl
;
3818 ObjectStore::Transaction t
;
3820 snprintf(buf
, sizeof(buf
), "%d", i
);
3821 ghobject_t
hoid(hobject_t(sobject_t(string(buf
) + base
, CEPH_NOSNAP
)));
3823 created
.insert(hoid
);
3824 r
= queue_transaction(store
, ch
, std::move(t
));
3828 for (set
<ghobject_t
>::iterator i
= created
.begin();
3832 ASSERT_TRUE(!store
->stat(ch
, *i
, &buf
));
3835 set
<ghobject_t
> listed
, listed2
;
3836 vector
<ghobject_t
> objects
;
3837 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
3841 cerr
<< "objects.size() is " << objects
.size() << std::endl
;
3842 for (vector
<ghobject_t
> ::iterator i
= objects
.begin();
3846 ASSERT_TRUE(created
.count(*i
));
3848 ASSERT_TRUE(listed
.size() == created
.size());
3850 ghobject_t start
, next
;
3852 r
= collection_list(
3855 ghobject_t::get_max(),
3856 ghobject_t::get_max(),
3862 ASSERT_TRUE(objects
.empty());
3866 ghobject_t start2
, next2
;
3868 r
= collection_list(store
, ch
, start
, ghobject_t::get_max(), 50, &objects
,
3870 ASSERT_TRUE(sorted(objects
));
3872 listed
.insert(objects
.begin(), objects
.end());
3873 if (objects
.size() < 50) {
3874 ASSERT_TRUE(next
.is_max());
3881 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
3882 ASSERT_TRUE(listed
.size() == created
.size());
3883 if (listed2
.size()) {
3884 ASSERT_EQ(listed
.size(), listed2
.size());
3886 for (set
<ghobject_t
>::iterator i
= listed
.begin();
3889 ASSERT_TRUE(created
.count(*i
));
3892 for (set
<ghobject_t
>::iterator i
= created
.begin();
3895 ObjectStore::Transaction t
;
3897 r
= queue_transaction(store
, ch
, std::move(t
));
3900 cerr
<< "cleaning up" << std::endl
;
3902 ObjectStore::Transaction t
;
3903 t
.remove_collection(cid
);
3904 r
= queue_transaction(store
, ch
, std::move(t
));
3910 class ObjectGenerator
{
3912 virtual ghobject_t
create_object(gen_type
*gen
) = 0;
3913 virtual ~ObjectGenerator() {}
3916 class MixedGenerator
: public ObjectGenerator
{
3920 explicit MixedGenerator(int64_t p
) : seq(0), poolid(p
) {}
3921 ghobject_t
create_object(gen_type
*gen
) override
{
3923 snprintf(buf
, sizeof(buf
), "OBJ_%u", seq
);
3926 for (unsigned i
= 0; i
< 300; ++i
) {
3927 name
.push_back('a');
3933 name
, string(), rand() & 2 ? CEPH_NOSNAP
: rand(),
3934 (((seq
/ 1024) % 2) * 0xF00 ) +
3940 class SyntheticWorkloadState
{
3943 map
<string
, bufferlist
> attrs
;
3946 static const unsigned max_in_flight
= 16;
3947 static const unsigned max_objects
= 3000;
3948 static const unsigned max_attr_size
= 5;
3949 static const unsigned max_attr_name_len
= 100;
3950 static const unsigned max_attr_value_len
= 1024 * 64;
3952 unsigned write_alignment
;
3953 unsigned max_object_len
, max_write_len
;
3955 map
<ghobject_t
, Object
> contents
;
3956 set
<ghobject_t
> available_objects
;
3957 set
<ghobject_t
>::iterator next_available_object
;
3958 set
<ghobject_t
> in_flight_objects
;
3959 ObjectGenerator
*object_gen
;
3962 ObjectStore::CollectionHandle ch
;
3964 ceph::mutex lock
= ceph::make_mutex("State lock");
3965 ceph::condition_variable cond
;
3969 explicit EnterExit(const char *m
) : msg(m
) {
3970 //cout << pthread_self() << " enter " << msg << std::endl;
3973 //cout << pthread_self() << " exit " << msg << std::endl;
3977 class C_SyntheticOnReadable
: public Context
{
3979 SyntheticWorkloadState
*state
;
3981 C_SyntheticOnReadable(SyntheticWorkloadState
*state
, ghobject_t hoid
)
3982 : state(state
), hoid(hoid
) {}
3984 void finish(int r
) override
{
3985 std::lock_guard locker
{state
->lock
};
3986 EnterExit
ee("onreadable finish");
3987 ASSERT_TRUE(state
->in_flight_objects
.count(hoid
));
3989 state
->in_flight_objects
.erase(hoid
);
3990 if (state
->contents
.count(hoid
))
3991 state
->available_objects
.insert(hoid
);
3992 --(state
->in_flight
);
3993 state
->cond
.notify_all();
3996 r
= state
->store
->read(state
->ch
, hoid
, 0, state
->contents
[hoid
].data
.length(), r2
);
3997 ceph_assert(bl_eq(state
->contents
[hoid
].data
, r2
));
3998 state
->cond
.notify_all();
4002 class C_SyntheticOnStash
: public Context
{
4004 SyntheticWorkloadState
*state
;
4005 ghobject_t oid
, noid
;
4007 C_SyntheticOnStash(SyntheticWorkloadState
*state
,
4008 ghobject_t oid
, ghobject_t noid
)
4009 : state(state
), oid(oid
), noid(noid
) {}
4011 void finish(int r
) override
{
4012 std::lock_guard locker
{state
->lock
};
4013 EnterExit
ee("stash finish");
4014 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
4016 state
->in_flight_objects
.erase(oid
);
4017 if (state
->contents
.count(noid
))
4018 state
->available_objects
.insert(noid
);
4019 --(state
->in_flight
);
4021 r
= state
->store
->read(
4023 state
->contents
[noid
].data
.length(), r2
);
4024 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
4025 state
->cond
.notify_all();
4029 class C_SyntheticOnClone
: public Context
{
4031 SyntheticWorkloadState
*state
;
4032 ghobject_t oid
, noid
;
4034 C_SyntheticOnClone(SyntheticWorkloadState
*state
,
4035 ghobject_t oid
, ghobject_t noid
)
4036 : state(state
), oid(oid
), noid(noid
) {}
4038 void finish(int r
) override
{
4039 std::lock_guard locker
{state
->lock
};
4040 EnterExit
ee("clone finish");
4041 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
4043 state
->in_flight_objects
.erase(oid
);
4044 if (state
->contents
.count(oid
))
4045 state
->available_objects
.insert(oid
);
4046 if (state
->contents
.count(noid
))
4047 state
->available_objects
.insert(noid
);
4048 --(state
->in_flight
);
4050 r
= state
->store
->read(state
->ch
, noid
, 0, state
->contents
[noid
].data
.length(), r2
);
4051 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
4052 state
->cond
.notify_all();
4056 static void filled_byte_array(bufferlist
& bl
, size_t size
)
4058 static const char alphanum
[] = "0123456789"
4059 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
4060 "abcdefghijklmnopqrstuvwxyz";
4065 for (unsigned int i
= 0; i
< size
- 1; i
++) {
4066 // severely limit entropy so we can compress...
4067 bp
[i
] = alphanum
[rand() % 10]; //(sizeof(alphanum) - 1)];
4069 bp
[size
- 1] = '\0';
4074 SyntheticWorkloadState(ObjectStore
*store
,
4075 ObjectGenerator
*gen
,
4081 : cid(cid
), write_alignment(alignment
), max_object_len(max_size
),
4082 max_write_len(max_write
), in_flight(0),
4083 next_available_object(available_objects
.end()),
4084 object_gen(gen
), rng(rng
), store(store
) {}
4087 ObjectStore::Transaction t
;
4088 ch
= store
->create_new_collection(cid
);
4089 t
.create_collection(cid
, 0);
4090 return queue_transaction(store
, ch
, std::move(t
));
4095 vector
<ghobject_t
> objects
;
4096 int r
= collection_list(store
, ch
, next
, ghobject_t::get_max(), 10,
4098 ceph_assert(r
>= 0);
4099 if (objects
.size() == 0)
4101 ObjectStore::Transaction t
;
4102 std::map
<std::string
, ceph::buffer::list
> attrset
;
4103 for (vector
<ghobject_t
>::iterator p
= objects
.begin();
4104 p
!= objects
.end(); ++p
) {
4107 queue_transaction(store
, ch
, std::move(t
));
4109 ObjectStore::Transaction t
;
4110 t
.remove_collection(cid
);
4111 queue_transaction(store
, ch
, std::move(t
));
4113 void statfs(store_statfs_t
& stat
) {
4114 store
->statfs(&stat
);
4117 ghobject_t
get_uniform_random_object(std::unique_lock
<ceph::mutex
>& locker
) {
4118 cond
.wait(locker
, [this] {
4119 return in_flight
< max_in_flight
&& !available_objects
.empty();
4121 boost::uniform_int
<> choose(0, available_objects
.size() - 1);
4122 int index
= choose(*rng
);
4123 set
<ghobject_t
>::iterator i
= available_objects
.begin();
4124 for ( ; index
> 0; --index
, ++i
) ;
4125 ghobject_t ret
= *i
;
4129 ghobject_t
get_next_object(std::unique_lock
<ceph::mutex
>& locker
) {
4130 cond
.wait(locker
, [this] {
4131 return in_flight
< max_in_flight
&& !available_objects
.empty();
4134 if (next_available_object
== available_objects
.end()) {
4135 next_available_object
= available_objects
.begin();
4138 ghobject_t ret
= *next_available_object
;
4139 ++next_available_object
;
4143 void wait_for_ready(std::unique_lock
<ceph::mutex
>& locker
) {
4144 cond
.wait(locker
, [this] { return in_flight
< max_in_flight
; });
4147 void wait_for_done() {
4148 std::unique_lock locker
{lock
};
4149 cond
.wait(locker
, [this] { return in_flight
== 0; });
4153 return (available_objects
.size() + in_flight_objects
.size()) < max_objects
;
4157 return (available_objects
.size() + in_flight_objects
.size()) > 0;
4160 unsigned get_random_alloc_hints() {
4163 boost::uniform_int
<> u(0, 3);
4166 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE
;
4169 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE
;
4174 boost::uniform_int
<> u(0, 3);
4177 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
;
4180 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ
;
4185 // append_only, immutable
4186 boost::uniform_int
<> u(0, 4);
4190 boost::uniform_int
<> u(0, 3);
4193 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED
;
4196 f
|= CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED
;
4201 boost::uniform_int
<> u(0, 3);
4204 f
|= CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE
;
4207 f
|= CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE
;
4215 std::unique_lock locker
{lock
};
4216 EnterExit
ee("touch");
4219 wait_for_ready(locker
);
4220 ghobject_t new_obj
= object_gen
->create_object(rng
);
4221 available_objects
.erase(new_obj
);
4222 ObjectStore::Transaction t
;
4223 t
.touch(cid
, new_obj
);
4224 boost::uniform_int
<> u(17, 22);
4225 boost::uniform_int
<> v(12, 17);
4226 t
.set_alloc_hint(cid
, new_obj
,
4229 get_random_alloc_hints());
4231 in_flight_objects
.insert(new_obj
);
4232 if (!contents
.count(new_obj
))
4233 contents
[new_obj
] = Object();
4234 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4235 int status
= store
->queue_transaction(ch
, std::move(t
));
4240 std::unique_lock locker
{lock
};
4241 EnterExit
ee("stash");
4246 wait_for_ready(locker
);
4251 old_obj
= get_uniform_random_object(locker
);
4252 } while (--max
&& !contents
[old_obj
].data
.length());
4253 available_objects
.erase(old_obj
);
4254 ghobject_t new_obj
= old_obj
;
4255 new_obj
.generation
++;
4256 available_objects
.erase(new_obj
);
4258 ObjectStore::Transaction t
;
4259 t
.collection_move_rename(cid
, old_obj
, cid
, new_obj
);
4261 in_flight_objects
.insert(old_obj
);
4263 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
4264 contents
[new_obj
].data
= contents
[old_obj
].data
;
4265 contents
.erase(old_obj
);
4266 t
.register_on_applied(new C_SyntheticOnStash(this, old_obj
, new_obj
));
4267 int status
= store
->queue_transaction(ch
, std::move(t
));
4272 std::unique_lock locker
{lock
};
4273 EnterExit
ee("clone");
4278 wait_for_ready(locker
);
4283 old_obj
= get_uniform_random_object(locker
);
4284 } while (--max
&& !contents
[old_obj
].data
.length());
4285 available_objects
.erase(old_obj
);
4286 ghobject_t new_obj
= object_gen
->create_object(rng
);
4287 // make the hash match
4288 new_obj
.hobj
.set_hash(old_obj
.hobj
.get_hash());
4289 available_objects
.erase(new_obj
);
4291 ObjectStore::Transaction t
;
4292 t
.clone(cid
, old_obj
, new_obj
);
4294 in_flight_objects
.insert(old_obj
);
4296 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
4297 contents
[new_obj
].data
= contents
[old_obj
].data
;
4299 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
4300 int status
= store
->queue_transaction(ch
, std::move(t
));
4305 std::unique_lock locker
{lock
};
4306 EnterExit
ee("clone_range");
4311 wait_for_ready(locker
);
4316 old_obj
= get_uniform_random_object(locker
);
4317 } while (--max
&& !contents
[old_obj
].data
.length());
4318 bufferlist
&srcdata
= contents
[old_obj
].data
;
4319 if (srcdata
.length() == 0) {
4322 available_objects
.erase(old_obj
);
4323 ghobject_t new_obj
= get_uniform_random_object(locker
);
4324 available_objects
.erase(new_obj
);
4326 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4327 boost::uniform_int
<> u2(0, max_write_len
);
4328 uint64_t srcoff
= u1(*rng
);
4329 // make src and dst offsets match, since that's what the osd does
4330 uint64_t dstoff
= srcoff
; //u1(*rng);
4331 uint64_t len
= u2(*rng
);
4332 if (write_alignment
) {
4333 srcoff
= round_up_to(srcoff
, write_alignment
);
4334 dstoff
= round_up_to(dstoff
, write_alignment
);
4335 len
= round_up_to(len
, write_alignment
);
4338 if (srcoff
> srcdata
.length() - 1) {
4339 srcoff
= srcdata
.length() - 1;
4341 if (srcoff
+ len
> srcdata
.length()) {
4342 len
= srcdata
.length() - srcoff
;
4345 cout
<< __func__
<< " from " << srcoff
<< "~" << len
4346 << " (size " << srcdata
.length() << ") to "
4347 << dstoff
<< "~" << len
<< std::endl
;
4349 ObjectStore::Transaction t
;
4350 t
.clone_range(cid
, old_obj
, new_obj
, srcoff
, len
, dstoff
);
4352 in_flight_objects
.insert(old_obj
);
4355 if (srcoff
< srcdata
.length()) {
4356 if (srcoff
+ len
> srcdata
.length()) {
4357 bl
.substr_of(srcdata
, srcoff
, srcdata
.length() - srcoff
);
4359 bl
.substr_of(srcdata
, srcoff
, len
);
4363 bufferlist
& dstdata
= contents
[new_obj
].data
;
4364 if (dstdata
.length() <= dstoff
) {
4365 if (bl
.length() > 0) {
4366 dstdata
.append_zero(dstoff
- dstdata
.length());
4371 ceph_assert(dstdata
.length() > dstoff
);
4372 dstdata
.cbegin().copy(dstoff
, value
);
4374 if (value
.length() < dstdata
.length())
4375 dstdata
.cbegin(value
.length()).copy(
4376 dstdata
.length() - value
.length(), value
);
4377 value
.swap(dstdata
);
4380 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
4381 int status
= store
->queue_transaction(ch
, std::move(t
));
4387 std::unique_lock locker
{lock
};
4388 EnterExit
ee("write");
4391 wait_for_ready(locker
);
4393 ghobject_t new_obj
= get_uniform_random_object(locker
);
4394 available_objects
.erase(new_obj
);
4395 ObjectStore::Transaction t
;
4397 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4398 boost::uniform_int
<> u2(0, max_write_len
);
4399 uint64_t offset
= u1(*rng
);
4400 uint64_t len
= u2(*rng
);
4402 if (write_alignment
) {
4403 offset
= round_up_to(offset
, write_alignment
);
4404 len
= round_up_to(len
, write_alignment
);
4407 filled_byte_array(bl
, len
);
4409 bufferlist
& data
= contents
[new_obj
].data
;
4410 if (data
.length() <= offset
) {
4412 data
.append_zero(offset
-data
.length());
4417 ceph_assert(data
.length() > offset
);
4418 data
.cbegin().copy(offset
, value
);
4420 if (value
.length() < data
.length())
4421 data
.cbegin(value
.length()).copy(
4422 data
.length()-value
.length(), value
);
4426 t
.write(cid
, new_obj
, offset
, len
, bl
);
4428 in_flight_objects
.insert(new_obj
);
4429 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4430 int status
= store
->queue_transaction(ch
, std::move(t
));
4435 std::unique_lock locker
{lock
};
4436 EnterExit
ee("truncate");
4439 wait_for_ready(locker
);
4441 ghobject_t obj
= get_uniform_random_object(locker
);
4442 available_objects
.erase(obj
);
4443 ObjectStore::Transaction t
;
4445 boost::uniform_int
<> choose(0, max_object_len
);
4446 size_t len
= choose(*rng
);
4447 if (write_alignment
) {
4448 len
= round_up_to(len
, write_alignment
);
4451 t
.truncate(cid
, obj
, len
);
4453 in_flight_objects
.insert(obj
);
4454 bufferlist
& data
= contents
[obj
].data
;
4455 if (data
.length() <= len
) {
4456 data
.append_zero(len
- data
.length());
4459 data
.cbegin().copy(len
, bl
);
4463 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4464 int status
= store
->queue_transaction(ch
, std::move(t
));
4469 std::unique_lock locker
{lock
};
4470 EnterExit
ee("zero");
4473 wait_for_ready(locker
);
4475 ghobject_t new_obj
= get_uniform_random_object(locker
);
4476 available_objects
.erase(new_obj
);
4477 ObjectStore::Transaction t
;
4479 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4480 boost::uniform_int
<> u2(0, max_write_len
);
4481 uint64_t offset
= u1(*rng
);
4482 uint64_t len
= u2(*rng
);
4483 if (write_alignment
) {
4484 offset
= round_up_to(offset
, write_alignment
);
4485 len
= round_up_to(len
, write_alignment
);
4489 auto& data
= contents
[new_obj
].data
;
4490 if (data
.length() < offset
+ len
) {
4491 data
.append_zero(offset
+len
-data
.length());
4494 n
.substr_of(data
, 0, offset
);
4496 if (data
.length() > offset
+ len
)
4497 data
.cbegin(offset
+ len
).copy(data
.length() - offset
- len
, n
);
4501 t
.zero(cid
, new_obj
, offset
, len
);
4503 in_flight_objects
.insert(new_obj
);
4504 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4505 int status
= store
->queue_transaction(ch
, std::move(t
));
4510 EnterExit
ee("read");
4511 boost::uniform_int
<> u1(0, max_object_len
/2);
4512 boost::uniform_int
<> u2(0, max_object_len
);
4513 uint64_t offset
= u1(*rng
);
4514 uint64_t len
= u2(*rng
);
4519 bufferlist expected
;
4522 std::unique_lock locker
{lock
};
4523 EnterExit
ee("read locked");
4526 wait_for_ready(locker
);
4528 obj
= get_uniform_random_object(locker
);
4529 expected
= contents
[obj
].data
;
4531 bufferlist bl
, result
;
4532 if (0) cout
<< " obj " << obj
4533 << " size " << expected
.length()
4534 << " offset " << offset
4535 << " len " << len
<< std::endl
;
4536 r
= store
->read(ch
, obj
, offset
, len
, result
);
4537 if (offset
>= expected
.length()) {
4540 size_t max_len
= expected
.length() - offset
;
4543 ceph_assert(len
== result
.length());
4544 ASSERT_EQ(len
, result
.length());
4545 expected
.cbegin(offset
).copy(len
, bl
);
4546 ASSERT_EQ(r
, (int)len
);
4547 ASSERT_TRUE(bl_eq(bl
, result
));
4552 std::unique_lock locker
{lock
};
4553 EnterExit
ee("setattrs");
4556 wait_for_ready(locker
);
4558 ghobject_t obj
= get_uniform_random_object(locker
);
4559 available_objects
.erase(obj
);
4560 ObjectStore::Transaction t
;
4562 boost::uniform_int
<> u0(1, max_attr_size
);
4563 boost::uniform_int
<> u1(4, max_attr_name_len
);
4564 boost::uniform_int
<> u2(4, max_attr_value_len
);
4565 boost::uniform_int
<> u3(0, 100);
4566 uint64_t size
= u0(*rng
);
4568 map
<string
, bufferlist
> attrs
;
4570 for (map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4571 it
!= contents
[obj
].attrs
.end(); ++it
)
4572 keys
.insert(it
->first
);
4575 bufferlist name
, value
;
4576 uint64_t get_exist
= u3(*rng
);
4577 uint64_t value_len
= u2(*rng
);
4578 filled_byte_array(value
, value_len
);
4579 if (get_exist
< 50 && keys
.size()) {
4580 set
<string
>::iterator k
= keys
.begin();
4582 contents
[obj
].attrs
[*k
] = value
;
4585 name_len
= u1(*rng
);
4586 filled_byte_array(name
, name_len
);
4587 attrs
[name
.c_str()] = value
;
4588 contents
[obj
].attrs
[name
.c_str()] = value
;
4591 t
.setattrs(cid
, obj
, attrs
);
4593 in_flight_objects
.insert(obj
);
4594 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4595 int status
= store
->queue_transaction(ch
, std::move(t
));
4599 int set_fixed_attrs(size_t entries
, size_t key_size
, size_t val_size
) {
4600 std::unique_lock locker
{ lock
};
4601 EnterExit
ee("setattrs");
4604 wait_for_ready(locker
);
4606 ghobject_t obj
= get_next_object(locker
);
4607 available_objects
.erase(obj
);
4608 ObjectStore::Transaction t
;
4610 map
<string
, bufferlist
> attrs
;
4614 bufferlist name
, value
;
4615 filled_byte_array(value
, val_size
);
4616 filled_byte_array(name
, key_size
);
4617 attrs
[name
.c_str()] = value
;
4618 contents
[obj
].attrs
[name
.c_str()] = value
;
4620 t
.setattrs(cid
, obj
, attrs
);
4622 in_flight_objects
.insert(obj
);
4623 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4624 int status
= store
->queue_transaction(ch
, std::move(t
));
4629 EnterExit
ee("getattrs");
4631 map
<string
, bufferlist
> expected
;
4633 std::unique_lock locker
{lock
};
4634 EnterExit
ee("getattrs locked");
4637 wait_for_ready(locker
);
4641 obj
= get_uniform_random_object(locker
);
4644 } while (contents
[obj
].attrs
.empty());
4645 expected
= contents
[obj
].attrs
;
4647 map
<string
, bufferlist
> attrs
;
4648 int r
= store
->getattrs(ch
, obj
, attrs
);
4649 ASSERT_TRUE(r
== 0);
4650 ASSERT_TRUE(attrs
.size() == expected
.size());
4651 for (map
<string
, bufferlist
>::iterator it
= expected
.begin();
4652 it
!= expected
.end(); ++it
) {
4653 ASSERT_TRUE(bl_eq(attrs
[it
->first
], it
->second
));
4658 EnterExit
ee("getattr");
4662 map
<string
, bufferlist
> expected
;
4664 std::unique_lock locker
{lock
};
4665 EnterExit
ee("getattr locked");
4668 wait_for_ready(locker
);
4672 obj
= get_uniform_random_object(locker
);
4675 } while (contents
[obj
].attrs
.empty());
4676 expected
= contents
[obj
].attrs
;
4678 boost::uniform_int
<> u(0, expected
.size()-1);
4680 map
<string
, bufferlist
>::iterator it
= expected
.begin();
4687 r
= store
->getattr(ch
, obj
, it
->first
, bl
);
4689 ASSERT_TRUE(bl_eq(it
->second
, bl
));
4693 std::unique_lock locker
{lock
};
4694 EnterExit
ee("rmattr");
4697 wait_for_ready(locker
);
4702 obj
= get_uniform_random_object(locker
);
4705 } while (contents
[obj
].attrs
.empty());
4707 boost::uniform_int
<> u(0, contents
[obj
].attrs
.size()-1);
4709 map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4715 available_objects
.erase(obj
);
4716 ObjectStore::Transaction t
;
4717 t
.rmattr(cid
, obj
, it
->first
);
4719 contents
[obj
].attrs
.erase(it
->first
);
4721 in_flight_objects
.insert(obj
);
4722 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4723 int status
= store
->queue_transaction(ch
, std::move(t
));
4727 void fsck(bool deep
) {
4728 std::unique_lock locker
{lock
};
4729 EnterExit
ee("fsck");
4730 cond
.wait(locker
, [this] { return in_flight
== 0; });
4733 int r
= store
->fsck(deep
);
4734 ceph_assert(r
== 0 || r
== -EOPNOTSUPP
);
4736 ch
= store
->open_collection(cid
);
4740 std::unique_lock locker
{lock
};
4741 EnterExit
ee("scan");
4742 cond
.wait(locker
, [this] { return in_flight
== 0; });
4743 vector
<ghobject_t
> objects
;
4744 set
<ghobject_t
> objects_set
, objects_set2
;
4745 ghobject_t next
, current
;
4747 //cerr << "scanning..." << std::endl;
4748 int r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 100,
4751 ASSERT_TRUE(sorted(objects
));
4752 objects_set
.insert(objects
.begin(), objects
.end());
4754 if (next
.is_max()) break;
4757 if (objects_set
.size() != available_objects
.size()) {
4758 for (set
<ghobject_t
>::iterator p
= objects_set
.begin();
4759 p
!= objects_set
.end();
4761 if (available_objects
.count(*p
) == 0) {
4762 cerr
<< "+ " << *p
<< std::endl
;
4765 for (set
<ghobject_t
>::iterator p
= available_objects
.begin();
4766 p
!= available_objects
.end();
4768 if (objects_set
.count(*p
) == 0)
4769 cerr
<< "- " << *p
<< std::endl
;
4770 //cerr << " objects_set: " << objects_set << std::endl;
4771 //cerr << " available_set: " << available_objects << std::endl;
4772 ceph_abort_msg("badness");
4775 ASSERT_EQ(objects_set
.size(), available_objects
.size());
4776 for (set
<ghobject_t
>::iterator i
= objects_set
.begin();
4777 i
!= objects_set
.end();
4779 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
4782 int r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(),
4783 INT_MAX
, &objects
, 0);
4785 objects_set2
.insert(objects
.begin(), objects
.end());
4786 ASSERT_EQ(objects_set2
.size(), available_objects
.size());
4787 for (set
<ghobject_t
>::iterator i
= objects_set2
.begin();
4788 i
!= objects_set2
.end();
4790 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
4791 if (available_objects
.count(*i
) == 0) {
4792 cerr
<< "+ " << *i
<< std::endl
;
4798 EnterExit
ee("stat");
4802 std::unique_lock locker
{lock
};
4803 EnterExit
ee("stat lock1");
4806 hoid
= get_uniform_random_object(locker
);
4807 in_flight_objects
.insert(hoid
);
4808 available_objects
.erase(hoid
);
4810 expected
= contents
[hoid
].data
.length();
4813 int r
= store
->stat(ch
, hoid
, &buf
);
4815 ceph_assert((uint64_t)buf
.st_size
== expected
);
4816 ASSERT_TRUE((uint64_t)buf
.st_size
== expected
);
4818 std::lock_guard locker
{lock
};
4819 EnterExit
ee("stat lock2");
4822 in_flight_objects
.erase(hoid
);
4823 available_objects
.insert(hoid
);
4828 std::unique_lock locker
{lock
};
4829 EnterExit
ee("unlink");
4832 ghobject_t to_remove
= get_uniform_random_object(locker
);
4833 ObjectStore::Transaction t
;
4834 t
.remove(cid
, to_remove
);
4836 available_objects
.erase(to_remove
);
4837 in_flight_objects
.insert(to_remove
);
4838 contents
.erase(to_remove
);
4839 t
.register_on_applied(new C_SyntheticOnReadable(this, to_remove
));
4840 int status
= store
->queue_transaction(ch
, std::move(t
));
4844 void print_internal_state() {
4845 std::lock_guard locker
{lock
};
4846 cerr
<< "available_objects: " << available_objects
.size()
4847 << " in_flight_objects: " << in_flight_objects
.size()
4848 << " total objects: " << in_flight_objects
.size() + available_objects
.size()
4849 << " in_flight " << in_flight
<< std::endl
;
4854 void StoreTest::doSyntheticTest(
4856 uint64_t max_obj
, uint64_t max_wr
, uint64_t align
)
4858 MixedGenerator
gen(555);
4859 gen_type
rng(time(NULL
));
4860 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
4862 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
4863 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
4864 g_ceph_context
->_conf
.apply_changes(nullptr);
4866 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
,
4867 max_obj
, max_wr
, align
);
4869 for (int i
= 0; i
< num_ops
/10; ++i
) {
4870 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
4873 for (int i
= 0; i
< num_ops
; ++i
) {
4875 cerr
<< "Op " << i
<< std::endl
;
4876 test_obj
.print_internal_state();
4878 boost::uniform_int
<> true_false(0, 999);
4879 int val
= true_false(rng
);
4881 test_obj
.fsck(true);
4882 } else if (val
> 997) {
4883 test_obj
.fsck(false);
4884 } else if (val
> 970) {
4886 } else if (val
> 950) {
4888 } else if (val
> 850) {
4890 } else if (val
> 800) {
4892 } else if (val
> 550) {
4894 } else if (val
> 500) {
4896 } else if (val
> 450) {
4897 test_obj
.clone_range();
4898 } else if (val
> 300) {
4900 } else if (val
> 100) {
4903 test_obj
.truncate();
4906 test_obj
.wait_for_done();
4907 test_obj
.shutdown();
4910 TEST_P(StoreTest
, Synthetic
) {
4911 doSyntheticTest(10000, 400*1024, 40*1024, 0);
4914 #if defined(WITH_BLUESTORE)
4915 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixSharding
) {
4916 if (string(GetParam()) != "bluestore")
4919 const char *m
[][10] = {
4920 { "bluestore_min_alloc_size", "4096", 0 }, // must be the first!
4921 { "num_ops", "50000", 0 },
4922 { "max_write", "65536", 0 },
4923 { "max_size", "262144", 0 },
4924 { "alignment", "4096", 0 },
4925 { "bluestore_max_blob_size", "65536", 0 },
4926 { "bluestore_extent_map_shard_min_size", "60", 0 },
4927 { "bluestore_extent_map_shard_max_size", "300", 0 },
4928 { "bluestore_extent_map_shard_target_size", "150", 0 },
4929 { "bluestore_default_buffered_read", "true", 0 },
4930 { "bluestore_default_buffered_write", "true", 0 },
4933 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4936 TEST_P(StoreTestSpecificAUSize
, ZipperPatternSharded
) {
4937 if(string(GetParam()) != "bluestore")
4939 StartDeferred(4096);
4943 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
4944 auto ch
= store
->create_new_collection(cid
);
4946 ObjectStore::Transaction t
;
4947 t
.create_collection(cid
, 0);
4948 cerr
<< "Creating collection " << cid
<< std::endl
;
4949 r
= queue_transaction(store
, ch
, std::move(t
));
4957 for (int i
=0; i
<1000; ++i
) {
4958 ObjectStore::Transaction t
;
4959 t
.write(cid
, a
, i
*2*len
, len
, bl
, 0);
4960 r
= queue_transaction(store
, ch
, std::move(t
));
4963 for (int i
=0; i
<1000; ++i
) {
4964 ObjectStore::Transaction t
;
4965 t
.write(cid
, a
, i
*2*len
+ 1, len
, bl
, 0);
4966 r
= queue_transaction(store
, ch
, std::move(t
));
4970 ObjectStore::Transaction t
;
4972 t
.remove_collection(cid
);
4973 cerr
<< "Cleaning" << std::endl
;
4974 r
= queue_transaction(store
, ch
, std::move(t
));
4979 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumAlgorithm
) {
4980 if (string(GetParam()) != "bluestore")
4983 const char *m
[][10] = {
4984 { "bluestore_min_alloc_size", "65536", 0 }, // must be the first!
4985 { "max_write", "65536", 0 },
4986 { "max_size", "1048576", 0 },
4987 { "alignment", "16", 0 },
4988 { "bluestore_csum_type", "crc32c", "crc32c_16", "crc32c_8", "xxhash32",
4989 "xxhash64", "none", 0 },
4990 { "bluestore_default_buffered_write", "false", 0 },
4993 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
4996 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumVsCompression
) {
4997 if (string(GetParam()) != "bluestore")
5000 const char *m
[][10] = {
5001 { "bluestore_min_alloc_size", "4096", "16384", 0 }, //to be the first!
5002 { "max_write", "131072", 0 },
5003 { "max_size", "262144", 0 },
5004 { "alignment", "512", 0 },
5005 { "bluestore_compression_mode", "force", 0},
5006 { "bluestore_compression_algorithm", "snappy", "zlib", 0 },
5007 { "bluestore_csum_type", "crc32c", 0 },
5008 { "bluestore_default_buffered_read", "true", "false", 0 },
5009 { "bluestore_default_buffered_write", "true", "false", 0 },
5010 { "bluestore_sync_submit_transaction", "false", 0 },
5013 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5016 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompression
) {
5017 if (string(GetParam()) != "bluestore")
5020 const char *m
[][10] = {
5021 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5022 { "max_write", "1048576", 0 },
5023 { "max_size", "4194304", 0 },
5024 { "alignment", "65536", 0 },
5025 { "bluestore_compression_mode", "force", "aggressive", "passive", "none", 0},
5026 { "bluestore_default_buffered_write", "false", 0 },
5027 { "bluestore_sync_submit_transaction", "true", 0 },
5030 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5033 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompressionAlgorithm
) {
5034 if (string(GetParam()) != "bluestore")
5037 const char *m
[][10] = {
5038 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5039 { "max_write", "1048576", 0 },
5040 { "max_size", "4194304", 0 },
5041 { "alignment", "65536", 0 },
5042 { "bluestore_compression_algorithm", "zlib", "snappy", 0 },
5043 { "bluestore_compression_mode", "force", 0 },
5044 { "bluestore_default_buffered_write", "false", 0 },
5047 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5050 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixNoCsum
) {
5051 if (string(GetParam()) != "bluestore")
5054 const char *m
[][10] = {
5055 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5056 { "max_write", "65536", 0 },
5057 { "max_size", "1048576", 0 },
5058 { "alignment", "512", 0 },
5059 { "bluestore_max_blob_size", "262144", 0 },
5060 { "bluestore_compression_mode", "force", "none", 0},
5061 { "bluestore_csum_type", "none", 0},
5062 { "bluestore_default_buffered_read", "true", "false", 0 },
5063 { "bluestore_default_buffered_write", "true", 0 },
5064 { "bluestore_sync_submit_transaction", "true", "false", 0 },
5067 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5070 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixPreferDeferred
) {
5071 if (string(GetParam()) != "bluestore")
5074 const char *m
[][10] = {
5075 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5076 { "max_write", "65536", 0 },
5077 { "max_size", "1048576", 0 },
5078 { "alignment", "512", 0 },
5079 { "bluestore_max_blob_size", "262144", 0 },
5080 { "bluestore_compression_mode", "force", "none", 0},
5081 { "bluestore_prefer_deferred_size", "32768", "0", 0},
5084 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5086 #endif // WITH_BLUESTORE
5088 TEST_P(StoreTest
, AttrSynthetic
) {
5089 MixedGenerator
gen(447);
5090 gen_type
rng(time(NULL
));
5091 coll_t
cid(spg_t(pg_t(0,447),shard_id_t::NO_SHARD
));
5093 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
, 40*1024, 4*1024, 0);
5095 for (int i
= 0; i
< 500; ++i
) {
5096 if (!(i
% 10)) cerr
<< "seeding object " << i
<< std::endl
;
5099 for (int i
= 0; i
< 1000; ++i
) {
5101 cerr
<< "Op " << i
<< std::endl
;
5102 test_obj
.print_internal_state();
5104 boost::uniform_int
<> true_false(0, 99);
5105 int val
= true_false(rng
);
5108 } else if (val
> 93) {
5110 } else if (val
> 75) {
5112 } else if (val
> 47) {
5113 test_obj
.setattrs();
5114 } else if (val
> 45) {
5116 } else if (val
> 37) {
5118 } else if (val
> 30) {
5119 test_obj
.getattrs();
5124 test_obj
.wait_for_done();
5125 test_obj
.shutdown();
5128 TEST_P(StoreTest
, HashCollisionTest
) {
5129 int64_t poolid
= 11;
5130 coll_t
cid(spg_t(pg_t(0,poolid
),shard_id_t::NO_SHARD
));
5132 auto ch
= store
->create_new_collection(cid
);
5134 ObjectStore::Transaction t
;
5135 t
.create_collection(cid
, 0);
5136 r
= queue_transaction(store
, ch
, std::move(t
));
5140 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
5141 set
<ghobject_t
> created
;
5142 for (int n
= 0; n
< 10; ++n
) {
5144 sprintf(nbuf
, "n%d", n
);
5145 for (int i
= 0; i
< 1000; ++i
) {
5147 sprintf(buf
, "%d", i
);
5149 cerr
<< "Object n" << n
<< " "<< i
<< std::endl
;
5151 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, 0, poolid
, string(nbuf
)));
5153 ObjectStore::Transaction t
;
5155 r
= queue_transaction(store
, ch
, std::move(t
));
5158 created
.insert(hoid
);
5161 vector
<ghobject_t
> objects
;
5162 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5165 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
5166 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
5167 ASSERT_TRUE(listed
.size() == created
.size());
5170 ghobject_t current
, next
;
5172 r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 60, &objects
,
5175 ASSERT_TRUE(sorted(objects
));
5176 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5179 if (listed
.count(*i
))
5180 cerr
<< *i
<< " repeated" << std::endl
;
5183 if (objects
.size() < 50) {
5184 ASSERT_TRUE(next
.is_max());
5190 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
5191 ASSERT_TRUE(listed
.size() == created
.size());
5192 for (set
<ghobject_t
>::iterator i
= listed
.begin();
5195 ASSERT_TRUE(created
.count(*i
));
5198 for (set
<ghobject_t
>::iterator i
= created
.begin();
5201 ObjectStore::Transaction t
;
5203 r
= queue_transaction(store
, ch
, std::move(t
));
5206 ObjectStore::Transaction t
;
5207 t
.remove_collection(cid
);
5208 r
= queue_transaction(store
, ch
, std::move(t
));
5212 TEST_P(StoreTest
, HashCollisionSorting
) {
5213 bool disable_legacy
= (string(GetParam()) == "bluestore");
5215 char buf121664318_1
[] = {18, -119, -121, -111, 0};
5216 char buf121664318_2
[] = {19, 127, -121, 32, 0};
5217 char buf121664318_3
[] = {19, -118, 15, 19, 0};
5218 char buf121664318_4
[] = {28, 27, -116, -113, 0};
5219 char buf121664318_5
[] = {28, 27, -115, -124, 0};
5221 char buf121666222_1
[] = {18, -119, -120, -111, 0};
5222 char buf121666222_2
[] = {19, 127, -120, 32, 0};
5223 char buf121666222_3
[] = {19, -118, 15, 30, 0};
5224 char buf121666222_4
[] = {29, 17, -126, -113, 0};
5225 char buf121666222_5
[] = {29, 17, -125, -124, 0};
5227 std::map
<uint32_t, std::vector
<std::string
>> object_names
= {
5228 {121664318, {{buf121664318_1
},
5233 {121666222, {{buf121666222_1
},
5237 {buf121666222_5
}}}};
5239 int64_t poolid
= 111;
5240 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
5241 auto ch
= store
->create_new_collection(cid
);
5243 ObjectStore::Transaction t
;
5244 t
.create_collection(cid
, 0);
5245 int r
= queue_transaction(store
, ch
, std::move(t
));
5249 std::set
<ghobject_t
> created
;
5250 for (auto &[hash
, names
] : object_names
) {
5251 for (auto &name
: names
) {
5252 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
),
5257 ASSERT_EQ(hash
, hoid
.hobj
.get_hash());
5258 ObjectStore::Transaction t
;
5260 int r
= queue_transaction(store
, ch
, std::move(t
));
5262 created
.insert(hoid
);
5266 vector
<ghobject_t
> objects
;
5267 int r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(),
5268 INT_MAX
, &objects
, 0, disable_legacy
);
5270 ASSERT_EQ(created
.size(), objects
.size());
5271 auto it
= objects
.begin();
5272 for (auto &hoid
: created
) {
5273 ASSERT_EQ(hoid
, *it
);
5277 for (auto i
= created
.begin(); i
!= created
.end(); i
++) {
5279 for (j
++; j
!= created
.end(); j
++) {
5280 std::set
<ghobject_t
> created_sub(i
, j
);
5283 r
= collection_list(store
, ch
, *i
, ghobject_t::get_max(),
5284 created_sub
.size(), &objects
, &next
, disable_legacy
);
5286 ASSERT_EQ(created_sub
.size(), objects
.size());
5287 it
= objects
.begin();
5288 for (auto &hoid
: created_sub
) {
5289 ASSERT_EQ(hoid
, *it
);
5292 if (j
== created
.end()) {
5293 ASSERT_TRUE(next
.is_max());
5295 ASSERT_EQ(*j
, next
);
5300 for (auto i
= created
.begin(); i
!= created
.end(); i
++) {
5302 for (j
++; j
!= created
.end(); j
++) {
5303 std::set
<ghobject_t
> created_sub(i
, j
);
5306 r
= collection_list(store
, ch
, *i
, *j
, INT_MAX
, &objects
, &next
,
5309 ASSERT_EQ(created_sub
.size(), objects
.size());
5310 it
= objects
.begin();
5311 for (auto &hoid
: created_sub
) {
5312 ASSERT_EQ(hoid
, *it
);
5315 if (j
== created
.end()) {
5316 ASSERT_TRUE(next
.is_max());
5318 ASSERT_EQ(*j
, next
);
5324 TEST_P(StoreTest
, ScrubTest
) {
5325 int64_t poolid
= 111;
5326 coll_t
cid(spg_t(pg_t(0, poolid
),shard_id_t(1)));
5328 auto ch
= store
->create_new_collection(cid
);
5330 ObjectStore::Transaction t
;
5331 t
.create_collection(cid
, 0);
5332 r
= queue_transaction(store
, ch
, std::move(t
));
5335 string base
= "aaaaa";
5336 set
<ghobject_t
> created
;
5337 for (int i
= 0; i
< 1000; ++i
) {
5339 sprintf(buf
, "%d", i
);
5341 cerr
<< "Object " << i
<< std::endl
;
5343 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, i
,
5345 ghobject_t::NO_GEN
, shard_id_t(1));
5347 ObjectStore::Transaction t
;
5349 r
= queue_transaction(store
, ch
, std::move(t
));
5352 created
.insert(hoid
);
5355 // Add same hobject_t but different generation
5357 ghobject_t
hoid1(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""),
5358 ghobject_t::NO_GEN
, shard_id_t(1));
5359 ghobject_t
hoid2(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)1, shard_id_t(1));
5360 ghobject_t
hoid3(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)2, shard_id_t(1));
5361 ObjectStore::Transaction t
;
5362 t
.touch(cid
, hoid1
);
5363 t
.touch(cid
, hoid2
);
5364 t
.touch(cid
, hoid3
);
5365 r
= queue_transaction(store
, ch
, std::move(t
));
5366 created
.insert(hoid1
);
5367 created
.insert(hoid2
);
5368 created
.insert(hoid3
);
5372 vector
<ghobject_t
> objects
;
5373 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5376 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
5377 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
5378 ASSERT_TRUE(listed
.size() == created
.size());
5381 ghobject_t current
, next
;
5383 r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 60, &objects
,
5386 ASSERT_TRUE(sorted(objects
));
5387 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5388 i
!= objects
.end(); ++i
) {
5389 if (listed
.count(*i
))
5390 cerr
<< *i
<< " repeated" << std::endl
;
5393 if (objects
.size() < 50) {
5394 ASSERT_TRUE(next
.is_max());
5398 current
= next
.get_boundary();
5400 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
5401 ASSERT_TRUE(listed
.size() == created
.size());
5402 for (set
<ghobject_t
>::iterator i
= listed
.begin();
5405 ASSERT_TRUE(created
.count(*i
));
5408 for (set
<ghobject_t
>::iterator i
= created
.begin();
5411 ObjectStore::Transaction t
;
5413 r
= queue_transaction(store
, ch
, std::move(t
));
5416 ObjectStore::Transaction t
;
5417 t
.remove_collection(cid
);
5418 r
= queue_transaction(store
, ch
, std::move(t
));
5423 TEST_P(StoreTest
, OMapTest
) {
5425 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5426 auto ch
= store
->create_new_collection(cid
);
5429 ObjectStore::Transaction t
;
5430 t
.create_collection(cid
, 0);
5431 r
= queue_transaction(store
, ch
, std::move(t
));
5435 map
<string
, bufferlist
> attrs
;
5437 ObjectStore::Transaction t
;
5439 t
.omap_clear(cid
, hoid
);
5440 map
<string
, bufferlist
> start_set
;
5441 t
.omap_setkeys(cid
, hoid
, start_set
);
5442 r
= queue_transaction(store
, ch
, std::move(t
));
5446 for (int i
= 0; i
< 100; i
++) {
5448 std::cout
<< "On iteration " << i
<< std::endl
;
5450 ObjectStore::Transaction t
;
5452 map
<string
, bufferlist
> cur_attrs
;
5453 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5455 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5458 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5460 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5461 if (cur_attrs
.count(j
->first
) > 0) {
5462 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5465 ASSERT_EQ(correct
, true);
5467 ASSERT_EQ(attrs
.size(), cur_attrs
.size());
5470 snprintf(buf
, sizeof(buf
), "%d", i
);
5472 bufferptr
bp(buf
, strlen(buf
) + 1);
5474 map
<string
, bufferlist
> to_add
;
5475 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5476 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5477 t
.omap_setkeys(cid
, hoid
, to_add
);
5478 r
= queue_transaction(store
, ch
, std::move(t
));
5483 while (attrs
.size()) {
5485 std::cout
<< "removal: On iteration " << i
<< std::endl
;
5487 ObjectStore::Transaction t
;
5489 map
<string
, bufferlist
> cur_attrs
;
5490 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5492 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5495 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5497 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5498 if (cur_attrs
.count(j
->first
) > 0) {
5499 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5502 ASSERT_EQ(correct
, true);
5505 string to_remove
= attrs
.begin()->first
;
5506 t
.omap_rmkey(cid
, hoid
, to_remove
);
5507 r
= queue_transaction(store
, ch
, std::move(t
));
5510 attrs
.erase(to_remove
);
5517 bl1
.append("omap_header");
5518 ObjectStore::Transaction t
;
5519 t
.omap_setheader(cid
, hoid
, bl1
);
5520 r
= queue_transaction(store
, ch
, std::move(t
));
5522 t
= ObjectStore::Transaction();
5525 bl2
.append("value");
5526 map
<string
, bufferlist
> to_add
;
5527 to_add
.insert(pair
<string
, bufferlist
>("key", bl2
));
5528 t
.omap_setkeys(cid
, hoid
, to_add
);
5529 r
= queue_transaction(store
, ch
, std::move(t
));
5533 map
<string
, bufferlist
> cur_attrs
;
5534 r
= store
->omap_get(ch
, hoid
, &bl3
, &cur_attrs
);
5536 ASSERT_EQ(cur_attrs
.size(), size_t(1));
5537 ASSERT_TRUE(bl_eq(bl1
, bl3
));
5540 r
= store
->omap_get_keys(ch
, hoid
, &keys
);
5542 ASSERT_EQ(keys
.size(), size_t(1));
5545 // test omap_clear, omap_rmkey_range
5548 map
<string
,bufferlist
> to_set
;
5549 for (int n
=0; n
<10; ++n
) {
5550 to_set
[stringify(n
)].append("foo");
5554 ObjectStore::Transaction t
;
5555 t
.remove(cid
, hoid
);
5557 t
.omap_setheader(cid
, hoid
, h
);
5558 t
.omap_setkeys(cid
, hoid
, to_set
);
5559 r
= queue_transaction(store
, ch
, std::move(t
));
5563 ObjectStore::Transaction t
;
5564 t
.omap_rmkeyrange(cid
, hoid
, "3", "7");
5565 r
= queue_transaction(store
, ch
, std::move(t
));
5570 map
<string
,bufferlist
> m
;
5571 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5572 ASSERT_EQ(6u, hdr
.length());
5573 ASSERT_TRUE(m
.count("2"));
5574 ASSERT_TRUE(!m
.count("3"));
5575 ASSERT_TRUE(!m
.count("6"));
5576 ASSERT_TRUE(m
.count("7"));
5577 ASSERT_TRUE(m
.count("8"));
5578 //cout << m << std::endl;
5579 ASSERT_EQ(6u, m
.size());
5582 ObjectStore::Transaction t
;
5583 t
.omap_clear(cid
, hoid
);
5584 r
= queue_transaction(store
, ch
, std::move(t
));
5589 map
<string
,bufferlist
> m
;
5590 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5591 ASSERT_EQ(0u, hdr
.length());
5592 ASSERT_EQ(0u, m
.size());
5596 ObjectStore::Transaction t
;
5597 t
.remove(cid
, hoid
);
5598 t
.remove_collection(cid
);
5599 r
= queue_transaction(store
, ch
, std::move(t
));
5603 TEST_P(StoreTest
, OMapIterator
) {
5605 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5607 auto ch
= store
->create_new_collection(cid
);
5610 ObjectStore::Transaction t
;
5611 t
.create_collection(cid
, 0);
5612 r
= queue_transaction(store
, ch
, std::move(t
));
5616 map
<string
, bufferlist
> attrs
;
5618 ObjectStore::Transaction t
;
5620 t
.omap_clear(cid
, hoid
);
5621 map
<string
, bufferlist
> start_set
;
5622 t
.omap_setkeys(cid
, hoid
, start_set
);
5623 r
= queue_transaction(store
, ch
, std::move(t
));
5626 ObjectMap::ObjectMapIterator iter
;
5629 for (int i
= 0; i
< 100; i
++) {
5631 std::cout
<< "On iteration " << i
<< std::endl
;
5635 // FileStore may deadlock two active iterators over the same data
5636 iter
= ObjectMap::ObjectMapIterator();
5638 iter
= store
->get_omap_iterator(ch
, hoid
);
5639 for (iter
->seek_to_first(), count
=0; iter
->valid(); iter
->next(), count
++) {
5640 string key
= iter
->key();
5641 bufferlist value
= iter
->value();
5642 correct
= attrs
.count(key
) && (string(value
.c_str()) == string(attrs
[key
].c_str()));
5644 if (attrs
.count(key
) > 0) {
5645 std::cout
<< "key " << key
<< "in omap , " << value
.c_str() << " : " << attrs
[key
].c_str() << std::endl
;
5648 std::cout
<< "key " << key
<< "should not exists in omap" << std::endl
;
5650 ASSERT_EQ(correct
, true);
5652 ASSERT_EQ((int)attrs
.size(), count
);
5654 // FileStore may deadlock an active iterator vs queue_transaction
5655 iter
= ObjectMap::ObjectMapIterator();
5658 snprintf(buf
, sizeof(buf
), "%d", i
);
5660 bufferptr
bp(buf
, strlen(buf
) + 1);
5662 map
<string
, bufferlist
> to_add
;
5663 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5664 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5665 ObjectStore::Transaction t
;
5666 t
.omap_setkeys(cid
, hoid
, to_add
);
5667 r
= queue_transaction(store
, ch
, std::move(t
));
5671 iter
= store
->get_omap_iterator(ch
, hoid
);
5673 string bound_key
= "key-5";
5674 iter
->lower_bound(bound_key
);
5675 correct
= bound_key
<= iter
->key();
5677 std::cout
<< "lower bound, bound key is " << bound_key
<< " < iter key is " << iter
->key() << std::endl
;
5679 ASSERT_EQ(correct
, true);
5681 iter
->upper_bound(bound_key
);
5682 correct
= iter
->key() > bound_key
;
5684 std::cout
<< "upper bound, bound key is " << bound_key
<< " >= iter key is " << iter
->key() << std::endl
;
5686 ASSERT_EQ(correct
, true);
5688 // FileStore may deadlock an active iterator vs queue_transaction
5689 iter
= ObjectMap::ObjectMapIterator();
5691 ObjectStore::Transaction t
;
5692 t
.remove(cid
, hoid
);
5693 t
.remove_collection(cid
);
5694 r
= queue_transaction(store
, ch
, std::move(t
));
5699 TEST_P(StoreTest
, XattrTest
) {
5701 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5703 for (unsigned i
= 0; i
< 10000; ++i
) {
5707 for (unsigned i
= 0; i
< 10; ++i
) {
5711 auto ch
= store
->create_new_collection(cid
);
5713 ObjectStore::Transaction t
;
5714 t
.create_collection(cid
, 0);
5716 r
= queue_transaction(store
, ch
, std::move(t
));
5720 map
<string
, bufferlist
> attrs
;
5722 ObjectStore::Transaction t
;
5723 t
.setattr(cid
, hoid
, "attr1", small
);
5724 attrs
["attr1"] = small
;
5725 t
.setattr(cid
, hoid
, "attr2", big
);
5726 attrs
["attr2"] = big
;
5727 t
.setattr(cid
, hoid
, "attr3", small
);
5728 attrs
["attr3"] = small
;
5729 t
.setattr(cid
, hoid
, "attr1", small
);
5730 attrs
["attr1"] = small
;
5731 t
.setattr(cid
, hoid
, "attr4", big
);
5732 attrs
["attr4"] = big
;
5733 t
.setattr(cid
, hoid
, "attr3", big
);
5734 attrs
["attr3"] = big
;
5735 r
= queue_transaction(store
, ch
, std::move(t
));
5739 map
<string
, bufferptr
> aset
;
5740 store
->getattrs(ch
, hoid
, aset
);
5741 ASSERT_EQ(aset
.size(), attrs
.size());
5742 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
5746 bl
.push_back(i
->second
);
5747 ASSERT_TRUE(attrs
[i
->first
] == bl
);
5751 ObjectStore::Transaction t
;
5752 t
.rmattr(cid
, hoid
, "attr2");
5753 attrs
.erase("attr2");
5754 r
= queue_transaction(store
, ch
, std::move(t
));
5759 store
->getattrs(ch
, hoid
, aset
);
5760 ASSERT_EQ(aset
.size(), attrs
.size());
5761 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
5765 bl
.push_back(i
->second
);
5766 ASSERT_TRUE(attrs
[i
->first
] == bl
);
5770 r
= store
->getattr(ch
, hoid
, "attr2", bp
);
5771 ASSERT_EQ(r
, -ENODATA
);
5773 r
= store
->getattr(ch
, hoid
, "attr3", bp
);
5777 ASSERT_TRUE(bl2
== attrs
["attr3"]);
5779 ObjectStore::Transaction t
;
5780 t
.remove(cid
, hoid
);
5781 t
.remove_collection(cid
);
5782 r
= queue_transaction(store
, ch
, std::move(t
));
5788 unsigned num_objects
,
5789 unsigned common_suffix_size
,
5792 coll_t
cid(spg_t(pg_t(0,52),shard_id_t::NO_SHARD
));
5793 coll_t
tid(spg_t(pg_t(1<<common_suffix_size
,52),shard_id_t::NO_SHARD
));
5794 auto ch
= store
->create_new_collection(cid
);
5795 auto tch
= store
->create_new_collection(tid
);
5798 ObjectStore::Transaction t
;
5799 t
.create_collection(cid
, common_suffix_size
);
5800 r
= queue_transaction(store
, ch
, std::move(t
));
5804 small
.append("small");
5806 ObjectStore::Transaction t
;
5807 for (uint32_t i
= 0; i
< (2 - (int)clones
)*num_objects
; ++i
) {
5808 stringstream objname
;
5809 objname
<< "obj" << i
;
5810 ghobject_t
a(hobject_t(
5814 i
<<common_suffix_size
,
5816 t
.write(cid
, a
, 0, small
.length(), small
,
5817 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
5819 objname
<< "-clone";
5820 ghobject_t
b(hobject_t(
5824 i
<<common_suffix_size
,
5829 r
= queue_transaction(store
, ch
, std::move(t
));
5831 t
= ObjectStore::Transaction();
5834 r
= queue_transaction(store
, ch
, std::move(t
));
5838 ObjectStore::Transaction t
;
5839 t
.create_collection(tid
, common_suffix_size
+ 1);
5840 t
.split_collection(cid
, common_suffix_size
+1, 1<<common_suffix_size
, tid
);
5841 r
= queue_transaction(store
, ch
, std::move(t
));
5847 vector
<ghobject_t
> objects
;
5848 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5851 ASSERT_EQ(objects
.size(), num_objects
);
5852 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5855 ASSERT_EQ(!!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
5859 r
= collection_list(store
, tch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5862 ASSERT_EQ(objects
.size(), num_objects
);
5863 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5866 ASSERT_EQ(!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
5869 // merge them again!
5871 ObjectStore::Transaction t
;
5872 t
.merge_collection(tid
, cid
, common_suffix_size
);
5873 r
= queue_transaction(store
, ch
, std::move(t
));
5877 // check and clean up
5878 ObjectStore::Transaction t
;
5880 vector
<ghobject_t
> objects
;
5881 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5884 ASSERT_EQ(objects
.size(), num_objects
* 2); // both halves
5886 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5892 r
= queue_transaction(store
, ch
, std::move(t
));
5894 t
= ObjectStore::Transaction();
5898 t
.remove_collection(cid
);
5899 r
= queue_transaction(store
, ch
, std::move(t
));
5903 ASSERT_TRUE(!store
->collection_exists(tid
));
5906 TEST_P(StoreTest
, ColSplitTest0
) {
5907 colsplittest(store
.get(), 10, 5, false);
5909 TEST_P(StoreTest
, ColSplitTest1
) {
5910 colsplittest(store
.get(), 10000, 11, false);
5912 TEST_P(StoreTest
, ColSplitTest1Clones
) {
5913 colsplittest(store
.get(), 10000, 11, true);
5915 TEST_P(StoreTest
, ColSplitTest2
) {
5916 colsplittest(store
.get(), 100, 7, false);
5918 TEST_P(StoreTest
, ColSplitTest2Clones
) {
5919 colsplittest(store
.get(), 100, 7, true);
5923 TEST_P(StoreTest
, ColSplitTest3
) {
5924 colsplittest(store
.get(), 100000, 25);
5928 void test_merge_skewed(ObjectStore
*store
,
5929 unsigned base
, unsigned bits
,
5930 unsigned anum
, unsigned bnum
)
5932 cout
<< __func__
<< " 0x" << std::hex
<< base
<< std::dec
5934 << " anum " << anum
<< " bnum " << bnum
<< std::endl
;
5936 make merge source pgs have radically different # of objects in them,
5937 which should trigger different splitting in filestore, and verify that
5938 post-merge all objects are accessible.
5941 coll_t
a(spg_t(pg_t(base
, 0), shard_id_t::NO_SHARD
));
5942 coll_t
b(spg_t(pg_t(base
| (1<<bits
), 0), shard_id_t::NO_SHARD
));
5944 auto cha
= store
->create_new_collection(a
);
5945 auto chb
= store
->create_new_collection(b
);
5947 ObjectStore::Transaction t
;
5948 t
.create_collection(a
, bits
+ 1);
5949 r
= queue_transaction(store
, cha
, std::move(t
));
5953 ObjectStore::Transaction t
;
5954 t
.create_collection(b
, bits
+ 1);
5955 r
= queue_transaction(store
, chb
, std::move(t
));
5960 small
.append("small");
5961 string suffix
= "ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooaaaaaaaaaa";
5962 set
<ghobject_t
> aobjects
, bobjects
;
5965 ObjectStore::Transaction t
;
5966 for (unsigned i
= 0; i
< 1000; ++i
) {
5967 string objname
= "a" + stringify(i
) + suffix
;
5968 ghobject_t
o(hobject_t(
5975 t
.write(a
, o
, 0, small
.length(), small
, 0);
5977 r
= queue_transaction(store
, cha
, std::move(t
));
5979 t
= ObjectStore::Transaction();
5982 r
= queue_transaction(store
, cha
, std::move(t
));
5987 ObjectStore::Transaction t
;
5988 for (unsigned i
= 0; i
< 10; ++i
) {
5989 string objname
= "b" + stringify(i
) + suffix
;
5990 ghobject_t
o(hobject_t(
5994 (i
<<(base
+1)) | base
| (1<<bits
),
5997 t
.write(b
, o
, 0, small
.length(), small
, 0);
5999 r
= queue_transaction(store
, chb
, std::move(t
));
6001 t
= ObjectStore::Transaction();
6004 r
= queue_transaction(store
, chb
, std::move(t
));
6010 ObjectStore::Transaction t
;
6011 t
.merge_collection(b
, a
, bits
);
6012 r
= queue_transaction(store
, cha
, std::move(t
));
6018 vector
<ghobject_t
> got
;
6019 collection_list(store
, cha
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6021 set
<ghobject_t
> gotset
;
6022 for (auto& o
: got
) {
6023 ASSERT_TRUE(aobjects
.count(o
) || bobjects
.count(o
));
6026 // check both listing and stat-ability (different code paths!)
6028 for (auto& o
: aobjects
) {
6029 ASSERT_TRUE(gotset
.count(o
));
6030 int r
= store
->stat(cha
, o
, &st
, false);
6033 for (auto& o
: bobjects
) {
6034 ASSERT_TRUE(gotset
.count(o
));
6035 int r
= store
->stat(cha
, o
, &st
, false);
6042 ObjectStore::Transaction t
;
6043 for (auto &o
: aobjects
) {
6046 r
= queue_transaction(store
, cha
, std::move(t
));
6050 ObjectStore::Transaction t
;
6051 for (auto &o
: bobjects
) {
6054 t
.remove_collection(a
);
6055 r
= queue_transaction(store
, cha
, std::move(t
));
6060 TEST_P(StoreTest
, MergeSkewed
) {
6061 if (string(GetParam()) != "filestore")
6064 // this is sufficient to exercise merges with different hashing levels
6065 test_merge_skewed(store
.get(), 0xf, 4, 10, 10000);
6066 test_merge_skewed(store
.get(), 0xf, 4, 10000, 10);
6069 // this covers a zillion variations that all boil down to the same thing
6070 for (unsigned base = 3; base < 0x1000; base *= 5) {
6073 for (bits = 0; t; t >>= 1) {
6076 for (unsigned b = bits; b < bits + 10; b += 3) {
6077 for (auto anum : { 10, 1000, 10000 }) {
6078 for (auto bnum : { 10, 1000, 10000 }) {
6082 test_merge_skewed(store.get(), base, b, anum, bnum);
6092 * This test tests adding two different groups
6093 * of objects, each with 1 common prefix and 1
6094 * different prefix. We then remove half
6095 * in order to verify that the merging correctly
6096 * stops at the common prefix subdir. See bug
6098 TEST_P(StoreTest
, TwoHash
) {
6101 auto ch
= store
->create_new_collection(cid
);
6103 ObjectStore::Transaction t
;
6104 t
.create_collection(cid
, 0);
6105 r
= queue_transaction(store
, ch
, std::move(t
));
6108 std::cout
<< "Making objects" << std::endl
;
6109 for (int i
= 0; i
< 360; ++i
) {
6110 ObjectStore::Transaction t
;
6114 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6117 o
.hobj
.set_hash((i
<< 16) | 0xB1);
6119 r
= queue_transaction(store
, ch
, std::move(t
));
6122 std::cout
<< "Removing half" << std::endl
;
6123 for (int i
= 1; i
< 8; ++i
) {
6124 ObjectStore::Transaction t
;
6127 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6129 r
= queue_transaction(store
, ch
, std::move(t
));
6132 std::cout
<< "Checking" << std::endl
;
6133 for (int i
= 1; i
< 8; ++i
) {
6134 ObjectStore::Transaction t
;
6136 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6138 bool exists
= store
->exists(ch
, o
);
6139 ASSERT_EQ(exists
, false);
6143 o
.hobj
.set_hash(0xA1);
6145 bool exists
= store
->exists(ch
, o
);
6146 ASSERT_EQ(exists
, true);
6148 std::cout
<< "Cleanup" << std::endl
;
6149 for (int i
= 0; i
< 360; ++i
) {
6150 ObjectStore::Transaction t
;
6152 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6155 o
.hobj
.set_hash((i
<< 16) | 0xB1);
6157 r
= queue_transaction(store
, ch
, std::move(t
));
6160 ObjectStore::Transaction t
;
6161 t
.remove_collection(cid
);
6162 r
= queue_transaction(store
, ch
, std::move(t
));
6166 TEST_P(StoreTest
, Rename
) {
6167 coll_t
cid(spg_t(pg_t(0, 2122),shard_id_t::NO_SHARD
));
6168 ghobject_t
srcoid(hobject_t("src_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6169 ghobject_t
dstoid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6173 auto ch
= store
->create_new_collection(cid
);
6176 ObjectStore::Transaction t
;
6177 t
.create_collection(cid
, 0);
6178 t
.write(cid
, srcoid
, 0, a
.length(), a
);
6179 r
= queue_transaction(store
, ch
, std::move(t
));
6182 ASSERT_TRUE(store
->exists(ch
, srcoid
));
6184 ObjectStore::Transaction t
;
6185 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
6186 t
.write(cid
, srcoid
, 0, b
.length(), b
);
6187 t
.setattr(cid
, srcoid
, "attr", b
);
6188 r
= queue_transaction(store
, ch
, std::move(t
));
6191 ASSERT_TRUE(store
->exists(ch
, srcoid
));
6192 ASSERT_TRUE(store
->exists(ch
, dstoid
));
6195 store
->read(ch
, srcoid
, 0, 3, bl
);
6196 ASSERT_TRUE(bl_eq(b
, bl
));
6197 store
->read(ch
, dstoid
, 0, 3, bl
);
6198 ASSERT_TRUE(bl_eq(a
, bl
));
6201 ObjectStore::Transaction t
;
6202 t
.remove(cid
, dstoid
);
6203 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
6204 r
= queue_transaction(store
, ch
, std::move(t
));
6207 ASSERT_TRUE(store
->exists(ch
, dstoid
));
6208 ASSERT_FALSE(store
->exists(ch
, srcoid
));
6211 store
->read(ch
, dstoid
, 0, 3, bl
);
6212 ASSERT_TRUE(bl_eq(b
, bl
));
6215 ObjectStore::Transaction t
;
6216 t
.remove(cid
, dstoid
);
6217 t
.remove_collection(cid
);
6218 r
= queue_transaction(store
, ch
, std::move(t
));
6223 TEST_P(StoreTest
, MoveRename
) {
6224 coll_t
cid(spg_t(pg_t(0, 212),shard_id_t::NO_SHARD
));
6225 ghobject_t
temp_oid(hobject_t("tmp_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6226 ghobject_t
oid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6227 auto ch
= store
->create_new_collection(cid
);
6230 ObjectStore::Transaction t
;
6231 t
.create_collection(cid
, 0);
6233 r
= queue_transaction(store
, ch
, std::move(t
));
6236 ASSERT_TRUE(store
->exists(ch
, oid
));
6237 bufferlist data
, attr
;
6238 map
<string
, bufferlist
> omap
;
6239 data
.append("data payload");
6240 attr
.append("attr value");
6241 omap
["omap_key"].append("omap value");
6243 ObjectStore::Transaction t
;
6244 t
.touch(cid
, temp_oid
);
6245 t
.write(cid
, temp_oid
, 0, data
.length(), data
);
6246 t
.setattr(cid
, temp_oid
, "attr", attr
);
6247 t
.omap_setkeys(cid
, temp_oid
, omap
);
6248 r
= queue_transaction(store
, ch
, std::move(t
));
6251 ASSERT_TRUE(store
->exists(ch
, temp_oid
));
6253 ObjectStore::Transaction t
;
6255 t
.collection_move_rename(cid
, temp_oid
, cid
, oid
);
6256 r
= queue_transaction(store
, ch
, std::move(t
));
6259 ASSERT_TRUE(store
->exists(ch
, oid
));
6260 ASSERT_FALSE(store
->exists(ch
, temp_oid
));
6263 r
= store
->read(ch
, oid
, 0, 1000, newdata
);
6265 ASSERT_TRUE(bl_eq(data
, newdata
));
6267 r
= store
->getattr(ch
, oid
, "attr", newattr
);
6269 ASSERT_TRUE(bl_eq(attr
, newattr
));
6271 keys
.insert("omap_key");
6272 map
<string
, bufferlist
> newomap
;
6273 r
= store
->omap_get_values(ch
, oid
, keys
, &newomap
);
6275 ASSERT_EQ(1u, newomap
.size());
6276 ASSERT_TRUE(newomap
.count("omap_key"));
6277 ASSERT_TRUE(bl_eq(omap
["omap_key"], newomap
["omap_key"]));
6280 ObjectStore::Transaction t
;
6282 t
.remove_collection(cid
);
6283 r
= queue_transaction(store
, ch
, std::move(t
));
6288 TEST_P(StoreTest
, BigRGWObjectName
) {
6289 coll_t
cid(spg_t(pg_t(0,12),shard_id_t::NO_SHARD
));
6292 "default.4106.50_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
6299 shard_id_t::NO_SHARD
);
6300 ghobject_t
oid2(oid
);
6301 oid2
.generation
= 17;
6302 ghobject_t
oidhead(oid
);
6303 oidhead
.generation
= ghobject_t::NO_GEN
;
6305 auto ch
= store
->create_new_collection(cid
);
6309 ObjectStore::Transaction t
;
6310 t
.create_collection(cid
, 0);
6311 t
.touch(cid
, oidhead
);
6312 t
.collection_move_rename(cid
, oidhead
, cid
, oid
);
6313 t
.touch(cid
, oidhead
);
6314 t
.collection_move_rename(cid
, oidhead
, cid
, oid2
);
6315 r
= queue_transaction(store
, ch
, std::move(t
));
6320 ObjectStore::Transaction t
;
6322 r
= queue_transaction(store
, ch
, std::move(t
));
6327 vector
<ghobject_t
> objects
;
6328 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6331 ASSERT_EQ(objects
.size(), 1u);
6332 ASSERT_EQ(objects
[0], oid2
);
6335 ASSERT_FALSE(store
->exists(ch
, oid
));
6338 ObjectStore::Transaction t
;
6339 t
.remove(cid
, oid2
);
6340 t
.remove_collection(cid
);
6341 r
= queue_transaction(store
, ch
, std::move(t
));
6347 TEST_P(StoreTest
, SetAllocHint
) {
6349 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, 0, ""));
6350 auto ch
= store
->create_new_collection(cid
);
6353 ObjectStore::Transaction t
;
6354 t
.create_collection(cid
, 0);
6356 r
= queue_transaction(store
, ch
, std::move(t
));
6360 ObjectStore::Transaction t
;
6361 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
6362 r
= queue_transaction(store
, ch
, std::move(t
));
6366 ObjectStore::Transaction t
;
6367 t
.remove(cid
, hoid
);
6368 r
= queue_transaction(store
, ch
, std::move(t
));
6372 ObjectStore::Transaction t
;
6373 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
6374 r
= queue_transaction(store
, ch
, std::move(t
));
6378 ObjectStore::Transaction t
;
6379 t
.remove_collection(cid
);
6380 r
= queue_transaction(store
, ch
, std::move(t
));
6385 TEST_P(StoreTest
, TryMoveRename
) {
6387 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6388 ghobject_t
hoid2(hobject_t("test_hint2", "", CEPH_NOSNAP
, 0, -1, ""));
6389 auto ch
= store
->create_new_collection(cid
);
6392 ObjectStore::Transaction t
;
6393 t
.create_collection(cid
, 0);
6394 r
= queue_transaction(store
, ch
, std::move(t
));
6398 ObjectStore::Transaction t
;
6399 t
.try_rename(cid
, hoid
, hoid2
);
6400 r
= queue_transaction(store
, ch
, std::move(t
));
6404 ObjectStore::Transaction t
;
6406 r
= queue_transaction(store
, ch
, std::move(t
));
6410 ObjectStore::Transaction t
;
6411 t
.try_rename(cid
, hoid
, hoid2
);
6412 r
= queue_transaction(store
, ch
, std::move(t
));
6416 ASSERT_EQ(store
->stat(ch
, hoid
, &st
), -ENOENT
);
6417 ASSERT_EQ(store
->stat(ch
, hoid2
, &st
), 0);
6420 #if defined(WITH_BLUESTORE)
6421 TEST_P(StoreTest
, BluestoreOnOffCSumTest
) {
6422 if (string(GetParam()) != "bluestore")
6424 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6425 g_conf().apply_changes(nullptr);
6429 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
6431 auto ch
= store
->open_collection(cid
);
6434 auto ch
= store
->create_new_collection(cid
);
6436 ObjectStore::Transaction t
;
6437 t
.create_collection(cid
, 0);
6438 cerr
<< "Creating collection " << cid
<< std::endl
;
6439 r
= queue_transaction(store
, ch
, std::move(t
));
6443 //write with csum enabled followed by read with csum disabled
6444 size_t block_size
= 64*1024;
6445 ObjectStore::Transaction t
;
6446 bufferlist bl
, orig
;
6447 bl
.append(std::string(block_size
, 'a'));
6449 t
.remove(cid
, hoid
);
6450 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6451 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6452 cerr
<< "Remove then create" << std::endl
;
6453 r
= queue_transaction(store
, ch
, std::move(t
));
6456 SetVal(g_conf(), "bluestore_csum_type", "none");
6457 g_conf().apply_changes(nullptr);
6460 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6461 ASSERT_EQ((int)block_size
, r
);
6462 ASSERT_TRUE(bl_eq(orig
, in
));
6466 //write with csum disabled followed by read with csum enabled
6468 size_t block_size
= 64*1024;
6469 ObjectStore::Transaction t
;
6470 bufferlist bl
, orig
;
6471 bl
.append(std::string(block_size
, 'a'));
6473 t
.remove(cid
, hoid
);
6474 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6475 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6476 cerr
<< "Remove then create" << std::endl
;
6477 r
= queue_transaction(store
, ch
, std::move(t
));
6480 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6481 g_conf().apply_changes(nullptr);
6484 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6485 ASSERT_EQ((int)block_size
, r
);
6486 ASSERT_TRUE(bl_eq(orig
, in
));
6489 //'mixed' non-overlapping writes to the same blob
6491 ObjectStore::Transaction t
;
6492 bufferlist bl
, orig
;
6493 size_t block_size
= 8000;
6494 bl
.append(std::string(block_size
, 'a'));
6496 t
.remove(cid
, hoid
);
6497 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6498 cerr
<< "Remove then create" << std::endl
;
6499 r
= queue_transaction(store
, ch
, std::move(t
));
6502 SetVal(g_conf(), "bluestore_csum_type", "none");
6503 g_conf().apply_changes(nullptr);
6505 ObjectStore::Transaction t2
;
6506 t2
.write(cid
, hoid
, block_size
*2, bl
.length(), bl
);
6507 cerr
<< "Append 'unprotected'" << std::endl
;
6508 r
= queue_transaction(store
, ch
, std::move(t2
));
6512 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6513 ASSERT_EQ((int)block_size
, r
);
6514 ASSERT_TRUE(bl_eq(orig
, in
));
6516 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6517 ASSERT_EQ((int)block_size
, r
);
6518 ASSERT_TRUE(bl_eq(orig
, in
));
6520 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6521 g_conf().apply_changes(nullptr);
6523 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6524 ASSERT_EQ((int)block_size
, r
);
6525 ASSERT_TRUE(bl_eq(orig
, in
));
6527 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6528 ASSERT_EQ((int)block_size
, r
);
6529 ASSERT_TRUE(bl_eq(orig
, in
));
6532 //partially blob overwrite under a different csum enablement mode
6534 ObjectStore::Transaction t
;
6535 bufferlist bl
, orig
, orig2
;
6536 size_t block_size0
= 0x10000;
6537 size_t block_size
= 9000;
6538 size_t block_size2
= 5000;
6539 bl
.append(std::string(block_size0
, 'a'));
6540 t
.remove(cid
, hoid
);
6541 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6542 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6543 cerr
<< "Remove then create" << std::endl
;
6544 r
= queue_transaction(store
, ch
, std::move(t
));
6547 SetVal(g_conf(), "bluestore_csum_type", "none");
6548 g_conf().apply_changes(nullptr);
6550 ObjectStore::Transaction t2
;
6552 bl
.append(std::string(block_size
, 'b'));
6553 t2
.write(cid
, hoid
, 0, bl
.length(), bl
);
6554 t2
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6555 cerr
<< "Overwrite with unprotected data" << std::endl
;
6556 r
= queue_transaction(store
, ch
, std::move(t2
));
6561 orig
.append( std::string(block_size0
- block_size
, 'a'));
6564 r
= store
->read(ch
, hoid
, 0, block_size0
, in
);
6565 ASSERT_EQ((int)block_size0
, r
);
6566 ASSERT_TRUE(bl_eq(orig
, in
));
6568 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6569 ASSERT_EQ((int)block_size
, r
);
6570 ASSERT_TRUE(bl_eq(orig2
, in
));
6572 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6573 g_conf().apply_changes(nullptr);
6575 ObjectStore::Transaction t3
;
6577 bl
.append(std::string(block_size2
, 'c'));
6578 t3
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6579 cerr
<< "Overwrite with protected data" << std::endl
;
6580 r
= queue_transaction(store
, ch
, std::move(t3
));
6585 orig
.append( std::string(block_size
- block_size2
, 'b'));
6586 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6587 ASSERT_EQ((int)block_size
, r
);
6588 ASSERT_TRUE(bl_eq(orig
, in
));
6592 ObjectStore::Transaction t
;
6593 t
.remove(cid
, hoid
);
6594 t
.remove_collection(cid
);
6595 cerr
<< "Cleaning" << std::endl
;
6596 r
= queue_transaction(store
, ch
, std::move(t
));
6602 INSTANTIATE_TEST_SUITE_P(
6608 #if defined(WITH_BLUESTORE)
6613 // Note: instantiate all stores to preserve store numbering order only
6614 INSTANTIATE_TEST_SUITE_P(
6616 StoreTestSpecificAUSize
,
6620 #if defined(WITH_BLUESTORE)
6625 void doMany4KWritesTest(boost::scoped_ptr
<ObjectStore
>& store
,
6626 unsigned max_objects
,
6628 unsigned max_object_size
,
6629 unsigned max_write_size
,
6630 unsigned write_alignment
)
6632 MixedGenerator
gen(555);
6633 gen_type
rng(time(NULL
));
6634 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
6635 store_statfs_t res_stat
;
6637 SyntheticWorkloadState
test_obj(store
.get(),
6645 for (unsigned i
= 0; i
< max_objects
; ++i
) {
6646 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
6649 for (unsigned i
= 0; i
< max_ops
; ++i
) {
6651 cerr
<< "Op " << i
<< std::endl
;
6652 test_obj
.print_internal_state();
6656 test_obj
.wait_for_done();
6657 test_obj
.statfs(res_stat
);
6658 if (!(res_stat
.data_stored
<= max_object_size
) ||
6659 !(res_stat
.allocated
<= max_object_size
)) {
6660 // this will provide more insight on the mismatch and
6661 // helps to avoid any races during stats collection
6662 test_obj
.fsck(false);
6663 // retrieving stats once again and assert if still broken
6664 test_obj
.statfs(res_stat
);
6665 ASSERT_LE(res_stat
.data_stored
, max_object_size
);
6666 ASSERT_LE(res_stat
.allocated
, max_object_size
);
6668 test_obj
.shutdown();
6671 TEST_P(StoreTestSpecificAUSize
, Many4KWritesTest
) {
6672 if (string(GetParam()) != "bluestore")
6675 StartDeferred(0x10000);
6677 const unsigned max_object
= 4*1024*1024;
6678 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0);
6681 TEST_P(StoreTestSpecificAUSize
, Many4KWritesNoCSumTest
) {
6682 if (string(GetParam()) != "bluestore")
6684 StartDeferred(0x10000);
6685 SetVal(g_conf(), "bluestore_csum_type", "none");
6686 g_ceph_context
->_conf
.apply_changes(nullptr);
6687 const unsigned max_object
= 4*1024*1024;
6689 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0 );
6692 TEST_P(StoreTestSpecificAUSize
, TooManyBlobsTest
) {
6693 if (string(GetParam()) != "bluestore")
6695 StartDeferred(0x10000);
6696 const unsigned max_object
= 4*1024*1024;
6697 doMany4KWritesTest(store
, 1, 1000, max_object
, 4*1024, 0);
6700 #if defined(WITH_BLUESTORE)
6701 void get_mempool_stats(uint64_t* total_bytes
, uint64_t* total_items
)
6703 uint64_t meta_allocated
= mempool::bluestore_cache_meta::allocated_bytes();
6704 uint64_t onode_allocated
= mempool::bluestore_cache_onode::allocated_bytes();
6705 uint64_t other_allocated
= mempool::bluestore_cache_other::allocated_bytes();
6707 uint64_t meta_items
= mempool::bluestore_cache_meta::allocated_items();
6708 uint64_t onode_items
= mempool::bluestore_cache_onode::allocated_items();
6709 uint64_t other_items
= mempool::bluestore_cache_other::allocated_items();
6710 cout
<< "meta(" << meta_allocated
<< "/" << meta_items
6711 << ") onode(" << onode_allocated
<< "/" << onode_items
6712 << ") other(" << other_allocated
<< "/" << other_items
6713 << ")" << std::endl
;
6714 *total_bytes
= meta_allocated
+ onode_allocated
+ other_allocated
;
6715 *total_items
= onode_items
;
6718 TEST_P(StoreTestSpecificAUSize
, OnodeSizeTracking
) {
6720 if (string(GetParam()) != "bluestore")
6723 size_t block_size
= 4096;
6724 StartDeferred(block_size
);
6725 SetVal(g_conf(), "bluestore_compression_mode", "none");
6726 SetVal(g_conf(), "bluestore_csum_type", "none");
6727 SetVal(g_conf(), "bluestore_cache_size_hdd", "400000000");
6728 SetVal(g_conf(), "bluestore_cache_size_ssd", "400000000");
6729 g_conf().apply_changes(nullptr);
6733 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6734 size_t obj_size
= 4 * 1024 * 1024;
6735 uint64_t total_bytes
, total_bytes2
;
6736 uint64_t total_onodes
;
6737 get_mempool_stats(&total_bytes
, &total_onodes
);
6738 ASSERT_EQ(total_onodes
, 0u);
6740 auto ch
= store
->create_new_collection(cid
);
6742 ObjectStore::Transaction t
;
6743 t
.create_collection(cid
, 0);
6744 r
= queue_transaction(store
, ch
, std::move(t
));
6748 ObjectStore::Transaction t
;
6749 bufferlist bl
, orig
, orig2
;
6751 bl
.append(std::string(obj_size
, 'a'));
6752 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6753 r
= queue_transaction(store
, ch
, std::move(t
));
6756 get_mempool_stats(&total_bytes
, &total_onodes
);
6757 ASSERT_NE(total_bytes
, 0u);
6758 ASSERT_EQ(total_onodes
, 1u);
6761 ObjectStore::Transaction t
;
6762 t
.truncate(cid
, hoid
, 0);
6763 r
= queue_transaction(store
, ch
, std::move(t
));
6767 for(size_t i
= 0; i
< 1; ++i
) {
6769 bl
.append(std::string(block_size
* (i
+1), 'a'));
6770 for( size_t j
= 0; j
< obj_size
; j
+= bl
.length()) {
6771 ObjectStore::Transaction t
;
6772 t
.write(cid
, hoid
, j
, bl
.length(), bl
);
6773 r
= queue_transaction(store
, ch
, std::move(t
));
6776 get_mempool_stats(&total_bytes2
, &total_onodes
);
6777 ASSERT_NE(total_bytes2
, 0u);
6778 ASSERT_EQ(total_onodes
, 1u);
6781 cout
<<" mempool dump:\n";
6782 JSONFormatter
f(true);
6783 f
.open_object_section("transaction");
6791 for (size_t i
= 0; i
< obj_size
; i
+= 0x1000) {
6792 store
->read(ch
, hoid
, i
, 0x1000, bl
);
6795 get_mempool_stats(&total_bytes
, &total_onodes
);
6796 ASSERT_NE(total_bytes
, 0u);
6797 ASSERT_EQ(total_onodes
, 1u);
6800 cout
<<" mempool dump:\n";
6801 JSONFormatter
f(true);
6802 f
.open_object_section("transaction");
6809 ObjectStore::Transaction t
;
6810 t
.remove(cid
, hoid
);
6811 t
.remove_collection(cid
);
6812 cerr
<< "Cleaning" << std::endl
;
6813 r
= queue_transaction(store
, ch
, std::move(t
));
6818 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwrite
) {
6820 if (string(GetParam()) != "bluestore")
6823 size_t block_size
= 4096;
6824 StartDeferred(block_size
);
6825 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
6826 g_conf().apply_changes(nullptr);
6830 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6832 const PerfCounters
* logger
= store
->get_perf_counters();
6834 auto ch
= store
->create_new_collection(cid
);
6836 ObjectStore::Transaction t
;
6837 t
.create_collection(cid
, 0);
6838 r
= queue_transaction(store
, ch
, std::move(t
));
6842 ObjectStore::Transaction t
;
6845 bl
.append(std::string(block_size
* 2, 'a'));
6846 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6847 r
= queue_transaction(store
, ch
, std::move(t
));
6851 // overwrite at the beginning
6852 ObjectStore::Transaction t
;
6855 bl
.append(std::string(block_size
, 'b'));
6856 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6857 r
= queue_transaction(store
, ch
, std::move(t
));
6862 ObjectStore::Transaction t
;
6865 bl
.append(std::string(block_size
* 2, 'c'));
6866 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6867 r
= queue_transaction(store
, ch
, std::move(t
));
6871 // append with a gap
6872 ObjectStore::Transaction t
;
6875 bl
.append(std::string(block_size
* 2, 'd'));
6876 t
.write(cid
, hoid
, block_size
* 5, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6877 r
= queue_transaction(store
, ch
, std::move(t
));
6881 // We need to issue a read to trigger cache stat update that refresh
6882 // perf counters. additionally we need to wait some time for mempool
6883 // thread to update stats.
6885 bufferlist bl
, expected
;
6886 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6887 ASSERT_EQ(r
, (int)block_size
);
6888 expected
.append(string(block_size
, 'b'));
6889 ASSERT_TRUE(bl_eq(expected
, bl
));
6890 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6891 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
6895 ObjectStore::Transaction t
;
6898 bl
.append(std::string(block_size
* 2, 'e'));
6900 // Currently we are unable to reuse blob when overwriting in a single step
6901 t
.write(cid
, hoid
, block_size
* 6, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6902 r
= queue_transaction(store
, ch
, std::move(t
));
6906 // We need to issue a read to trigger cache stat update that refresh
6907 // perf counters. additionally we need to wait some time for mempool
6908 // thread to update stats.
6910 bufferlist bl
, expected
;
6911 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6912 ASSERT_EQ(r
, (int)block_size
);
6913 expected
.append(string(block_size
, 'b'));
6914 ASSERT_TRUE(bl_eq(expected
, bl
));
6915 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6916 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
6920 ObjectStore::Transaction t
;
6923 bl
.append(std::string(block_size
, 'f'));
6925 t
.write(cid
, hoid
, block_size
* 4, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6926 r
= queue_transaction(store
, ch
, std::move(t
));
6930 // we need to wait some time for mempool
6931 // thread to update stats to be able to check blob/extent numbers from
6935 bufferlist bl
, expected
;
6936 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
6937 ASSERT_EQ(r
, (int)block_size
);
6938 expected
.append(string(block_size
, 'b'));
6939 ASSERT_TRUE(bl_eq(expected
, bl
));
6943 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
6944 ASSERT_EQ(r
, (int)block_size
);
6945 expected
.append(string(block_size
, 'a'));
6946 ASSERT_TRUE(bl_eq(expected
, bl
));
6950 r
= store
->read(ch
, hoid
, block_size
* 2, block_size
* 2, bl
);
6951 ASSERT_EQ(r
, (int)block_size
* 2);
6952 expected
.append(string(block_size
* 2, 'c'));
6953 ASSERT_TRUE(bl_eq(expected
, bl
));
6957 r
= store
->read(ch
, hoid
, block_size
* 4, block_size
, bl
);
6958 ASSERT_EQ(r
, (int)block_size
);
6959 expected
.append(string(block_size
, 'f'));
6960 ASSERT_TRUE(bl_eq(expected
, bl
));
6964 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
, bl
);
6965 ASSERT_EQ(r
, (int)block_size
);
6966 expected
.append(string(block_size
, 'd'));
6967 ASSERT_TRUE(bl_eq(expected
, bl
));
6971 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
* 3, bl
);
6972 ASSERT_EQ(r
, (int)block_size
* 3);
6973 expected
.append(string(block_size
, 'd'));
6974 expected
.append(string(block_size
* 2, 'e'));
6975 ASSERT_TRUE(bl_eq(expected
, bl
));
6977 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
6978 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
6982 ObjectStore::Transaction t
;
6983 t
.remove(cid
, hoid
);
6984 t
.remove_collection(cid
);
6985 cerr
<< "Cleaning" << std::endl
;
6986 r
= queue_transaction(store
, ch
, std::move(t
));
6991 TEST_P(StoreTestSpecificAUSize
, DeferredOnBigOverwrite
) {
6993 if (string(GetParam()) != "bluestore")
6996 size_t block_size
= 4096;
6997 StartDeferred(block_size
);
6998 SetVal(g_conf(), "bluestore_max_blob_size", "131072");
6999 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
7001 g_conf().apply_changes(nullptr);
7005 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7006 ghobject_t
hoid2(hobject_t("test2", "", CEPH_NOSNAP
, 0, -1, ""));
7008 PerfCounters
* logger
= const_cast<PerfCounters
*>(store
->get_perf_counters());
7010 auto ch
= store
->create_new_collection(cid
);
7012 ObjectStore::Transaction t
;
7013 t
.create_collection(cid
, 0);
7014 r
= queue_transaction(store
, ch
, std::move(t
));
7018 ObjectStore::Transaction t
;
7021 bl
.append(std::string(block_size
* 2, 'c'));
7022 bl2
.append(std::string(block_size
* 3, 'd'));
7024 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7025 t
.set_alloc_hint(cid
, hoid2
, block_size
* 4, block_size
* 4,
7026 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
);
7027 t
.write(cid
, hoid2
, 0, bl2
.length(), bl2
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7028 r
= queue_transaction(store
, ch
, std::move(t
));
7031 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 2u);
7032 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 0u);
7035 struct store_statfs_t statfs
;
7036 int r
= store
->statfs(&statfs
);
7038 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 5);
7039 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 5);
7042 // overwrite at the beginning, 4K alignment
7044 ObjectStore::Transaction t
;
7047 bl
.append(std::string(block_size
, 'b'));
7048 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7049 r
= queue_transaction(store
, ch
, std::move(t
));
7052 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 3u);
7053 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
7056 bufferlist bl
, expected
;
7057 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7058 ASSERT_EQ(r
, (int)block_size
);
7059 expected
.append(string(block_size
, 'b'));
7060 ASSERT_TRUE(bl_eq(expected
, bl
));
7063 bufferlist bl
, expected
;
7064 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7065 ASSERT_EQ(r
, (int)block_size
);
7066 expected
.append(string(block_size
, 'c'));
7067 ASSERT_TRUE(bl_eq(expected
, bl
));
7070 // overwrite at the end, 4K alignment
7072 ObjectStore::Transaction t
;
7075 bl
.append(std::string(block_size
, 'g'));
7076 t
.write(cid
, hoid
, block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7077 r
= queue_transaction(store
, ch
, std::move(t
));
7080 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 4u);
7081 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 2u);
7084 bufferlist bl
, expected
;
7085 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7086 ASSERT_EQ(r
, (int)block_size
);
7087 expected
.append(string(block_size
, 'b'));
7088 ASSERT_TRUE(bl_eq(expected
, bl
));
7091 bufferlist bl
, expected
;
7092 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7093 ASSERT_EQ(r
, (int)block_size
);
7094 expected
.append(string(block_size
, 'g'));
7095 ASSERT_TRUE(bl_eq(expected
, bl
));
7098 // overwrite at 4K, 12K alignment
7100 ObjectStore::Transaction t
;
7103 bl
.append(std::string(block_size
, 'e'));
7104 t
.write(cid
, hoid2
, block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7105 r
= queue_transaction(store
, ch
, std::move(t
));
7108 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 5u);
7109 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 3u);
7111 // makes sure deferred has been submitted
7112 // and do all the checks again
7113 sleep(g_conf().get_val
<double>("bluestore_max_defer_interval") + 2);
7115 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 5u);
7116 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 3u);
7119 bufferlist bl
, expected
;
7120 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7121 ASSERT_EQ(r
, (int)block_size
);
7122 expected
.append(string(block_size
, 'b'));
7123 ASSERT_TRUE(bl_eq(expected
, bl
));
7126 bufferlist bl
, expected
;
7127 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7128 ASSERT_EQ(r
, (int)block_size
);
7129 expected
.append(string(block_size
, 'g'));
7130 ASSERT_TRUE(bl_eq(expected
, bl
));
7133 bufferlist bl
, expected
;
7134 r
= store
->read(ch
, hoid2
, 0, block_size
, bl
);
7135 ASSERT_EQ(r
, (int)block_size
);
7136 expected
.append(string(block_size
, 'd'));
7137 ASSERT_TRUE(bl_eq(expected
, bl
));
7140 bufferlist bl
, expected
;
7141 r
= store
->read(ch
, hoid2
, block_size
, block_size
, bl
);
7142 ASSERT_EQ(r
, (int)block_size
);
7143 expected
.append(string(block_size
, 'e'));
7144 ASSERT_TRUE(bl_eq(expected
, bl
));
7147 bufferlist bl
, expected
;
7148 r
= store
->read(ch
, hoid2
, block_size
* 2, block_size
, bl
);
7149 ASSERT_EQ(r
, (int)block_size
);
7150 expected
.append(string(block_size
, 'd'));
7151 ASSERT_TRUE(bl_eq(expected
, bl
));
7155 struct store_statfs_t statfs
;
7156 int r
= store
->statfs(&statfs
);
7158 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 5);
7159 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 5);
7161 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
7162 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
7165 ObjectStore::Transaction t
;
7166 t
.remove(cid
, hoid
);
7167 t
.remove(cid
, hoid2
);
7168 r
= queue_transaction(store
, ch
, std::move(t
));
7173 ObjectStore::Transaction t
;
7175 bl
.append(std::string(block_size
* 2, 'f'));
7177 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7178 r
= queue_transaction(store
, ch
, std::move(t
));
7181 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 6u);
7182 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 3u);
7185 ObjectStore::Transaction t
;
7186 t
.zero(cid
, hoid
, 0, 100);
7187 r
= queue_transaction(store
, ch
, std::move(t
));
7191 bufferlist bl
, expected
;
7192 r
= store
->read(ch
, hoid
, 0, 100, bl
);
7193 ASSERT_EQ(r
, (int)100);
7194 expected
.append(string(100, 0));
7195 ASSERT_TRUE(bl_eq(expected
, bl
));
7198 bufferlist bl
, expected
;
7199 r
= store
->read(ch
, hoid
, 100, block_size
* 2 - 100, bl
);
7200 ASSERT_EQ(r
, (int)block_size
* 2 - 100);
7201 expected
.append(string(block_size
* 2 - 100, 'f'));
7202 ASSERT_TRUE(bl_eq(expected
, bl
));
7206 struct store_statfs_t statfs
;
7207 int r
= store
->statfs(&statfs
);
7209 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 2 - 100);
7210 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 2);
7212 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7213 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
7216 ObjectStore::Transaction t
;
7218 bl
.append(std::string(block_size
, 'g'));
7220 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7221 r
= queue_transaction(store
, ch
, std::move(t
));
7224 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 7u);
7225 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 4u);
7227 bufferlist bl
, expected
;
7228 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7229 ASSERT_EQ(r
, (int)block_size
);
7230 expected
.append(string(block_size
, 'g'));
7231 ASSERT_TRUE(bl_eq(expected
, bl
));
7234 bufferlist bl
, expected
;
7235 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7236 ASSERT_EQ(r
, (int)block_size
);
7237 expected
.append(string(block_size
, 'f'));
7238 ASSERT_TRUE(bl_eq(expected
, bl
));
7242 struct store_statfs_t statfs
;
7243 int r
= store
->statfs(&statfs
);
7245 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 2);
7246 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 2);
7248 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7249 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
7251 // check whether full overwrite bypass deferred
7253 ObjectStore::Transaction t
;
7255 bl
.append(std::string(block_size
* 2, 'h'));
7257 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7258 r
= queue_transaction(store
, ch
, std::move(t
));
7261 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 8u);
7262 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 4u);
7265 bufferlist bl
, expected
;
7266 r
= store
->read(ch
, hoid
, 0, block_size
* 2, bl
);
7267 ASSERT_EQ(r
, (int)block_size
* 2);
7268 expected
.append(string(block_size
* 2, 'h'));
7269 ASSERT_TRUE(bl_eq(expected
, bl
));
7273 struct store_statfs_t statfs
;
7274 int r
= store
->statfs(&statfs
);
7276 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 2);
7277 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 2);
7281 ObjectStore::Transaction t
;
7282 t
.remove(cid
, hoid
);
7283 t
.remove(cid
, hoid2
);
7284 r
= queue_transaction(store
, ch
, std::move(t
));
7289 ObjectStore::Transaction t
;
7291 bl
.append(std::string(block_size
* 32, 'a'));
7293 // this will create two 128K aligned blobs
7294 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7295 t
.write(cid
, hoid
, bl
.length(), bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7296 r
= queue_transaction(store
, ch
, std::move(t
));
7299 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 10u);
7300 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 4u);
7302 // check whether overwrite (less than prefer_deferred_size) partially overlapping two adjacent blobs goes
7305 ObjectStore::Transaction t
;
7307 bl
.append(std::string(block_size
* 3, 'b'));
7309 t
.write(cid
, hoid
, 0x20000 - block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7310 r
= queue_transaction(store
, ch
, std::move(t
));
7313 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 11u);
7314 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 6u);
7317 bufferlist bl
, expected
;
7318 r
= store
->read(ch
, hoid
, 0, 0x20000 - block_size
, bl
);
7319 ASSERT_EQ(r
, 0x20000 - block_size
);
7320 expected
.append(string(r
, 'a'));
7321 ASSERT_TRUE(bl_eq(expected
, bl
));
7324 r
= store
->read(ch
, hoid
, 0x20000 - block_size
, block_size
* 3, bl
);
7325 ASSERT_EQ(r
, 3 * block_size
);
7326 expected
.append(string(r
, 'b'));
7327 ASSERT_TRUE(bl_eq(expected
, bl
));
7330 r
= store
->read(ch
, hoid
, 0x20000 + 2 * block_size
, block_size
* 30, bl
);
7331 ASSERT_EQ(r
, 30 * block_size
);
7332 expected
.append(string(r
, 'a'));
7333 ASSERT_TRUE(bl_eq(expected
, bl
));
7338 struct store_statfs_t statfs
;
7339 int r
= store
->statfs(&statfs
);
7341 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 64);
7342 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 64);
7345 // check whether overwrite (larger than prefer_deferred_size) partially
7346 // overlapping two adjacent blobs goes deferred
7348 ObjectStore::Transaction t
;
7350 bl
.append(std::string(block_size
* 30, 'c'));
7352 t
.write(cid
, hoid
, 0x10000 + block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7353 r
= queue_transaction(store
, ch
, std::move(t
));
7357 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 12u);
7358 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 8u);
7361 bufferlist bl
, expected
;
7362 r
= store
->read(ch
, hoid
, 0, 0x11000, bl
);
7363 ASSERT_EQ(r
, 0x11000);
7364 expected
.append(string(r
, 'a'));
7365 ASSERT_TRUE(bl_eq(expected
, bl
));
7368 r
= store
->read(ch
, hoid
, 0x11000, block_size
* 30, bl
);
7369 ASSERT_EQ(r
, block_size
* 30);
7370 expected
.append(string(r
, 'c'));
7371 ASSERT_TRUE(bl_eq(expected
, bl
));
7374 r
= store
->read(ch
, hoid
, block_size
* 47, 0x10000 + block_size
, bl
);
7375 ASSERT_EQ(r
, 0x10000 + block_size
);
7376 expected
.append(string(r
, 'a'));
7377 ASSERT_TRUE(bl_eq(expected
, bl
));
7382 struct store_statfs_t statfs
;
7383 int r
= store
->statfs(&statfs
);
7385 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 64);
7386 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 64);
7390 // check whether overwrite (prefer_deferred_size < 120K < 2 * prefer_defer_size) partially
7391 // overlapping two adjacent blobs goes partly deferred
7393 ObjectStore::Transaction t
;
7395 bl
.append(std::string(block_size
* 30, 'e'));
7397 t
.write(cid
, hoid
, 0x20000 - block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7398 r
= queue_transaction(store
, ch
, std::move(t
));
7402 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
7403 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
7404 ASSERT_EQ(logger
->get(l_bluestore_write_deferred
), 1u);
7405 ASSERT_EQ(logger
->get(l_bluestore_write_deferred_bytes
), block_size
);
7408 struct store_statfs_t statfs
;
7409 int r
= store
->statfs(&statfs
);
7411 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 64);
7412 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 64);
7416 ObjectStore::Transaction t
;
7417 t
.remove(cid
, hoid
);
7418 t
.remove(cid
, hoid2
);
7419 t
.remove_collection(cid
);
7420 cerr
<< "Cleaning" << std::endl
;
7421 r
= queue_transaction(store
, ch
, std::move(t
));
7426 TEST_P(StoreTestSpecificAUSize
, DeferredOnBigOverwrite2
) {
7428 if (string(GetParam()) != "bluestore")
7431 size_t block_size
= 4096;
7432 StartDeferred(block_size
);
7433 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
7434 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
7436 g_conf().apply_changes(nullptr);
7440 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7442 PerfCounters
* logger
= const_cast<PerfCounters
*>(store
->get_perf_counters());
7444 auto ch
= store
->create_new_collection(cid
);
7446 ObjectStore::Transaction t
;
7447 t
.create_collection(cid
, 0);
7448 r
= queue_transaction(store
, ch
, std::move(t
));
7452 ObjectStore::Transaction t
;
7455 bl
.append(std::string(128 * 1024, 'c'));
7457 t
.write(cid
, hoid
, 0x1000, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7458 r
= queue_transaction(store
, ch
, std::move(t
));
7460 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
7461 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
7462 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 3u);
7463 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 0u);
7464 ASSERT_EQ(logger
->get(l_bluestore_write_deferred
), 0u);
7465 ASSERT_EQ(logger
->get(l_bluestore_write_deferred_bytes
), 0);
7470 ObjectStore::Transaction t
;
7473 bl
.append(std::string(128 * 1024, 'c'));
7475 t
.write(cid
, hoid
, 0x2000, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7476 r
= queue_transaction(store
, ch
, std::move(t
));
7479 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
7480 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
7481 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 3u);
7482 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
7483 ASSERT_EQ(logger
->get(l_bluestore_write_deferred
), 1u);
7484 ASSERT_EQ(logger
->get(l_bluestore_write_deferred_bytes
), 57344);
7488 ObjectStore::Transaction t
;
7489 t
.remove(cid
, hoid
);
7490 t
.remove(cid
, hoid
);
7491 t
.remove_collection(cid
);
7492 cerr
<< "Cleaning" << std::endl
;
7493 r
= queue_transaction(store
, ch
, std::move(t
));
7498 TEST_P(StoreTestSpecificAUSize
, DeferredOnBigOverwrite3
) {
7500 if (string(GetParam()) != "bluestore")
7503 size_t block_size
= 4096;
7504 StartDeferred(block_size
);
7505 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
7506 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
7508 g_conf().apply_changes(nullptr);
7512 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7514 PerfCounters
* logger
= const_cast<PerfCounters
*>(store
->get_perf_counters());
7516 auto ch
= store
->create_new_collection(cid
);
7518 ObjectStore::Transaction t
;
7519 t
.create_collection(cid
, 0);
7520 r
= queue_transaction(store
, ch
, std::move(t
));
7526 ObjectStore::Transaction t
;
7529 bl
.append(std::string(4096 * 1024, 'c'));
7531 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7532 r
= queue_transaction(store
, ch
, std::move(t
));
7535 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
7536 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
7537 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 64u);
7538 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 0u);
7539 ASSERT_EQ(logger
->get(l_bluestore_write_deferred
), 0u);
7540 ASSERT_EQ(logger
->get(l_bluestore_write_deferred_bytes
), 0u);
7544 ObjectStore::Transaction t
;
7547 bl
.append(std::string(4096 * 1024, 'c'));
7549 t
.write(cid
, hoid
, 0x1000, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7550 r
= queue_transaction(store
, ch
, std::move(t
));
7553 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
7554 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
7555 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 65u);
7556 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
7557 ASSERT_EQ(logger
->get(l_bluestore_write_deferred
), 1u);
7558 ASSERT_EQ(logger
->get(l_bluestore_write_deferred_bytes
), 61440);
7561 ObjectStore::Transaction t
;
7562 t
.remove(cid
, hoid
);
7563 t
.remove_collection(cid
);
7564 cerr
<< "Cleaning" << std::endl
;
7565 r
= queue_transaction(store
, ch
, std::move(t
));
7570 TEST_P(StoreTestSpecificAUSize
, DeferredDifferentChunks
) {
7572 if (string(GetParam()) != "bluestore")
7575 size_t alloc_size
= 4096;
7576 size_t large_object_size
= 1 * 1024 * 1024;
7577 size_t prefer_deferred_size
= 65536;
7578 StartDeferred(alloc_size
);
7579 SetVal(g_conf(), "bluestore_max_blob_size", "131072");
7580 SetVal(g_conf(), "bluestore_prefer_deferred_size",
7581 stringify(prefer_deferred_size
).c_str());
7582 g_conf().apply_changes(nullptr);
7586 const PerfCounters
* logger
= store
->get_perf_counters();
7587 size_t exp_bluestore_write_big
= 0;
7588 size_t exp_bluestore_write_big_deferred
= 0;
7590 ObjectStore::CollectionHandle ch
= store
->create_new_collection(cid
);
7592 ObjectStore::Transaction t
;
7593 t
.create_collection(cid
, 0);
7594 r
= queue_transaction(store
, ch
, std::move(t
));
7597 for (size_t expected_write_size
= 1024; expected_write_size
<= prefer_deferred_size
; expected_write_size
*= 2) {
7598 //create object with hint
7599 ghobject_t
hoid(hobject_t("test-"+to_string(expected_write_size
), "", CEPH_NOSNAP
, 0, -1, ""));
7601 ObjectStore::Transaction t
;
7603 t
.set_alloc_hint(cid
, hoid
, large_object_size
, expected_write_size
,
7604 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
|
7605 CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY
);
7606 r
= queue_transaction(store
, ch
, std::move(t
));
7612 ObjectStore::Transaction t
;
7614 bl
.append(std::string(large_object_size
, 'h'));
7615 t
.write(cid
, hoid
, 0, bl
.length(), bl
,
7616 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7617 r
= queue_transaction(store
, ch
, std::move(t
));
7618 ++exp_bluestore_write_big
;
7621 ASSERT_EQ(logger
->get(l_bluestore_write_big
), exp_bluestore_write_big
);
7622 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), exp_bluestore_write_big_deferred
);
7624 // check whether write will properly use deferred
7626 ObjectStore::Transaction t
;
7628 bl
.append(std::string(alloc_size
+ 2, 'z'));
7629 t
.write(cid
, hoid
, large_object_size
- 2 * alloc_size
- 1, bl
.length(), bl
,
7630 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7631 r
= queue_transaction(store
, ch
, std::move(t
));
7632 ++exp_bluestore_write_big
;
7633 if (expected_write_size
< prefer_deferred_size
)
7634 ++exp_bluestore_write_big_deferred
;
7637 ASSERT_EQ(logger
->get(l_bluestore_write_big
), exp_bluestore_write_big
);
7638 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), exp_bluestore_write_big_deferred
);
7642 ch
= store
->open_collection(cid
);
7644 for (size_t expected_write_size
= 1024; expected_write_size
<= 65536; expected_write_size
*= 2) {
7645 ghobject_t
hoid(hobject_t("test-"+to_string(expected_write_size
), "", CEPH_NOSNAP
, 0, -1, ""));
7647 bufferlist bl
, expected
;
7648 r
= store
->read(ch
, hoid
, 0, large_object_size
, bl
);
7649 ASSERT_EQ(r
, large_object_size
);
7650 expected
.append(string(large_object_size
- 2 * alloc_size
- 1, 'h'));
7651 expected
.append(string(alloc_size
+ 2, 'z'));
7652 expected
.append(string(alloc_size
- 1, 'h'));
7653 ASSERT_TRUE(bl_eq(expected
, bl
));
7657 ObjectStore::Transaction t
;
7658 for (size_t expected_write_size
= 1024; expected_write_size
<= 65536; expected_write_size
*= 2) {
7659 ghobject_t
hoid(hobject_t("test-"+to_string(expected_write_size
), "", CEPH_NOSNAP
, 0, -1, ""));
7660 t
.remove(cid
, hoid
);
7662 t
.remove_collection(cid
);
7663 cerr
<< "Cleaning" << std::endl
;
7664 r
= queue_transaction(store
, ch
, std::move(t
));
7669 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwriteReverse
) {
7671 if (string(GetParam()) != "bluestore")
7674 size_t block_size
= 4096;
7675 StartDeferred(block_size
);
7676 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
7677 g_conf().apply_changes(nullptr);
7681 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
7683 auto ch
= store
->create_new_collection(cid
);
7685 const PerfCounters
* logger
= store
->get_perf_counters();
7687 ObjectStore::Transaction t
;
7688 t
.create_collection(cid
, 0);
7689 r
= queue_transaction(store
, ch
, std::move(t
));
7693 ObjectStore::Transaction t
;
7696 bl
.append(std::string(block_size
* 2, 'a'));
7697 t
.write(cid
, hoid
, block_size
* 10, bl
.length(), bl
,
7698 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7699 r
= queue_transaction(store
, ch
, std::move(t
));
7704 ObjectStore::Transaction t
;
7707 bl
.append(std::string(block_size
, 'b'));
7708 t
.write(cid
, hoid
, block_size
* 9, bl
.length(), bl
,
7709 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7710 r
= queue_transaction(store
, ch
, std::move(t
));
7714 // We need to issue a read to trigger cache stat update that refresh
7715 // perf counters. additionally we need to wait some time for mempool
7716 // thread to update stats.
7718 bufferlist bl
, expected
;
7719 r
= store
->read(ch
, hoid
, block_size
* 9, block_size
* 2, bl
);
7720 ASSERT_EQ(r
, (int)block_size
* 2);
7721 expected
.append(string(block_size
, 'b'));
7722 expected
.append(string(block_size
, 'a'));
7723 ASSERT_TRUE(bl_eq(expected
, bl
));
7724 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7725 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
7730 // prepend existing with a gap
7731 ObjectStore::Transaction t
;
7734 bl
.append(std::string(block_size
, 'c'));
7735 t
.write(cid
, hoid
, block_size
* 7, bl
.length(), bl
,
7736 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7737 r
= queue_transaction(store
, ch
, std::move(t
));
7741 // We need to issue a read to trigger cache stat update that refresh
7742 // perf counters. additionally we need to wait some time for mempool
7743 // thread to update stats.
7745 bufferlist bl
, expected
;
7746 r
= store
->read(ch
, hoid
, block_size
* 7, block_size
* 3, bl
);
7747 ASSERT_EQ(r
, (int)block_size
* 3);
7748 expected
.append(string(block_size
, 'c'));
7749 expected
.append(string(block_size
, 0));
7750 expected
.append(string(block_size
, 'b'));
7751 ASSERT_TRUE(bl_eq(expected
, bl
));
7752 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7753 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
7757 // append after existing with a gap
7758 ObjectStore::Transaction t
;
7761 bl
.append(std::string(block_size
, 'd'));
7762 t
.write(cid
, hoid
, block_size
* 13, bl
.length(), bl
,
7763 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7764 r
= queue_transaction(store
, ch
, std::move(t
));
7768 // We need to issue a read to trigger cache stat update that refresh
7769 // perf counters. additionally we need to wait some time for mempool
7770 // thread to update stats.
7772 bufferlist bl
, expected
;
7773 r
= store
->read(ch
, hoid
, block_size
* 11, block_size
* 3, bl
);
7774 ASSERT_EQ(r
, (int)block_size
* 3);
7775 expected
.append(string(block_size
, 'a'));
7776 expected
.append(string(block_size
, 0));
7777 expected
.append(string(block_size
, 'd'));
7778 ASSERT_TRUE(bl_eq(expected
, bl
));
7779 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7780 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
7784 // append twice to the next max_blob slot
7785 ObjectStore::Transaction t
;
7788 bl
.append(std::string(block_size
, 'e'));
7789 t
.write(cid
, hoid
, block_size
* 17, bl
.length(), bl
,
7790 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7791 t
.write(cid
, hoid
, block_size
* 19, bl
.length(), bl
,
7792 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7793 r
= queue_transaction(store
, ch
, std::move(t
));
7797 // We need to issue a read to trigger cache stat update that refresh
7798 // perf counters. additionally we need to wait some time for mempool
7799 // thread to update stats.
7801 bufferlist bl
, expected
;
7802 r
= store
->read(ch
, hoid
, block_size
* 17, block_size
* 3, bl
);
7803 ASSERT_EQ(r
, (int)block_size
* 3);
7804 expected
.append(string(block_size
, 'e'));
7805 expected
.append(string(block_size
, 0));
7806 expected
.append(string(block_size
, 'e'));
7807 ASSERT_TRUE(bl_eq(expected
, bl
));
7808 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
7809 ASSERT_EQ(logger
->get(l_bluestore_extents
), 5u);
7812 // fill gaps at the second slot
7813 ObjectStore::Transaction t
;
7816 bl
.append(std::string(block_size
, 'f'));
7817 t
.write(cid
, hoid
, block_size
* 16, bl
.length(), bl
,
7818 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7819 t
.write(cid
, hoid
, block_size
* 18, bl
.length(), bl
,
7820 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7821 r
= queue_transaction(store
, ch
, std::move(t
));
7825 // We need to issue a read to trigger cache stat update that refresh
7826 // perf counters. additionally we need to wait some time for mempool
7827 // thread to update stats.
7829 bufferlist bl
, expected
;
7830 r
= store
->read(ch
, hoid
, block_size
* 16, block_size
* 4, bl
);
7831 ASSERT_EQ(r
, (int)block_size
* 4);
7832 expected
.append(string(block_size
, 'f'));
7833 expected
.append(string(block_size
, 'e'));
7834 expected
.append(string(block_size
, 'f'));
7835 expected
.append(string(block_size
, 'e'));
7836 ASSERT_TRUE(bl_eq(expected
, bl
));
7837 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
7838 ASSERT_EQ(logger
->get(l_bluestore_extents
), 4u);
7841 ObjectStore::Transaction t
;
7842 t
.remove(cid
, hoid
);
7843 t
.remove_collection(cid
);
7844 cerr
<< "Cleaning" << std::endl
;
7845 r
= queue_transaction(store
, ch
, std::move(t
));
7850 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnSmallOverwrite
) {
7852 if (string(GetParam()) != "bluestore")
7855 size_t block_size
= 4096;
7856 StartDeferred(block_size
);
7857 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
7858 g_conf().apply_changes(nullptr);
7862 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
7864 const PerfCounters
* logger
= store
->get_perf_counters();
7865 auto ch
= store
->create_new_collection(cid
);
7868 ObjectStore::Transaction t
;
7869 t
.create_collection(cid
, 0);
7870 r
= queue_transaction(store
, ch
, std::move(t
));
7874 ObjectStore::Transaction t
;
7877 bl
.append(std::string(block_size
, 'a'));
7878 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7879 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
,
7880 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7881 r
= queue_transaction(store
, ch
, std::move(t
));
7885 // write small into the gap
7886 ObjectStore::Transaction t
;
7889 bl
.append(std::string(3, 'b'));
7890 t
.write(cid
, hoid
, block_size
+ 1, bl
.length(), bl
,
7891 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7892 r
= queue_transaction(store
, ch
, std::move(t
));
7896 // We need to issue a read to trigger cache stat update that refresh
7897 // perf counters. additionally we need to wait some time for mempool
7898 // thread to update stats.
7900 bufferlist bl
, expected
;
7901 r
= store
->read(ch
, hoid
, 0, block_size
* 3, bl
);
7902 ASSERT_EQ(r
, (int)block_size
* 3);
7903 expected
.append(string(block_size
, 'a'));
7904 expected
.append(string(1, 0));
7905 expected
.append(string(3, 'b'));
7906 expected
.append(string(block_size
- 4, 0));
7907 expected
.append(string(block_size
, 'a'));
7908 ASSERT_TRUE(bl_eq(expected
, bl
));
7910 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7911 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
7914 ObjectStore::Transaction t
;
7915 t
.remove(cid
, hoid
);
7916 t
.remove_collection(cid
);
7917 cerr
<< "Cleaning" << std::endl
;
7918 r
= queue_transaction(store
, ch
, std::move(t
));
7923 // The test case to reproduce an issue when write happens
7924 // to a zero space between the extents sharing the same spanning blob
7925 // with unloaded shard map.
7926 // Second extent might be filled with zeros this way due to wrong result
7927 // returned by has_any_extents() call in do_write_small. The latter is caused
7928 // by incompletly loaded extent map.
7929 TEST_P(StoreTestSpecificAUSize
, SmallWriteOnShardedExtents
) {
7930 if (string(GetParam()) != "bluestore")
7933 size_t block_size
= 0x10000;
7934 StartDeferred(block_size
);
7936 SetVal(g_conf(), "bluestore_csum_type", "xxhash64");
7937 SetVal(g_conf(), "bluestore_max_blob_size", "524288"); // for sure
7939 g_conf().apply_changes(nullptr);
7943 ghobject_t
hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
7944 auto ch
= store
->create_new_collection(cid
);
7947 ObjectStore::Transaction t
;
7948 t
.create_collection(cid
, 0);
7949 r
= queue_transaction(store
, ch
, std::move(t
));
7953 //doing some tricks to have sharded extents/spanning objects
7954 ObjectStore::Transaction t
;
7957 bl
.append(std::string(0x80000, 'a'));
7958 t
.write(cid
, hoid1
, 0, bl
.length(), bl
, 0);
7959 t
.zero(cid
, hoid1
, 0x719e0, 0x75b0 );
7960 r
= queue_transaction(store
, ch
, std::move(t
));
7963 bl2
.append(std::string(0x70000, 'b'));
7964 t
.write(cid
, hoid1
, 0, bl2
.length(), bl2
, 0);
7965 t
.zero(cid
, hoid1
, 0, 0x50000);
7966 r
= queue_transaction(store
, ch
, std::move(t
));
7973 ch
= store
->open_collection(cid
);
7976 // do a write to zero space in between some extents sharing the same blob
7977 ObjectStore::Transaction t
;
7980 bl
.append(std::string(0x6520, 'c'));
7981 t
.write(cid
, hoid1
, 0x71c00, bl
.length(), bl
, 0);
7983 r
= queue_transaction(store
, ch
, std::move(t
));
7988 ObjectStore::Transaction t
;
7989 bufferlist bl
, expected
;
7991 r
= store
->read(ch
, hoid1
, 0x70000, 0x9c00, bl
);
7992 ASSERT_EQ(r
, (int)0x9c00);
7993 expected
.append(string(0x19e0, 'a'));
7994 expected
.append(string(0x220, 0));
7995 expected
.append(string(0x6520, 'c'));
7996 expected
.append(string(0xe70, 0));
7997 expected
.append(string(0xc70, 'a'));
7998 ASSERT_TRUE(bl_eq(expected
, bl
));
8004 ObjectStore::Transaction t
;
8005 t
.remove(cid
, hoid1
);
8006 t
.remove_collection(cid
);
8007 cerr
<< "Cleaning" << std::endl
;
8008 r
= queue_transaction(store
, ch
, std::move(t
));
8013 #endif //#if defined(WITH_BLUESTORE)
8015 TEST_P(StoreTest
, KVDBHistogramTest
) {
8016 if (string(GetParam()) != "bluestore")
8022 string
base("testobj.");
8024 bufferptr
ap(0x1000);
8025 memset(ap
.c_str(), 'a', 0x1000);
8027 auto ch
= store
->create_new_collection(cid
);
8029 ObjectStore::Transaction t
;
8030 t
.create_collection(cid
, 0);
8031 r
= queue_transaction(store
, ch
, std::move(t
));
8034 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
8035 ObjectStore::Transaction t
;
8037 snprintf(buf
, sizeof(buf
), "%d", i
);
8038 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
8039 t
.write(cid
, hoid
, 0, 0x1000, a
);
8040 r
= queue_transaction(store
, ch
, std::move(t
));
8044 std::unique_ptr
<Formatter
> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
8045 store
->generate_db_histogram(f
.get());
8050 TEST_P(StoreTest
, KVDBStatsTest
) {
8051 if (string(GetParam()) != "bluestore")
8054 SetVal(g_conf(), "rocksdb_perf", "true");
8055 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
8056 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
8057 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
8058 g_ceph_context
->_conf
.apply_changes(nullptr);
8059 int r
= store
->umount();
8061 r
= store
->mount(); //to force rocksdb stats
8066 string
base("testobj.");
8068 bufferptr
ap(0x1000);
8069 memset(ap
.c_str(), 'a', 0x1000);
8071 auto ch
= store
->create_new_collection(cid
);
8073 ObjectStore::Transaction t
;
8074 t
.create_collection(cid
, 0);
8075 r
= queue_transaction(store
, ch
, std::move(t
));
8078 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
8079 ObjectStore::Transaction t
;
8081 snprintf(buf
, sizeof(buf
), "%d", i
);
8082 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
8083 t
.write(cid
, hoid
, 0, 0x1000, a
);
8084 r
= queue_transaction(store
, ch
, std::move(t
));
8088 std::unique_ptr
<Formatter
> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
8089 store
->get_db_statistics(f
.get());
8094 #if defined(WITH_BLUESTORE)
8095 TEST_P(StoreTestSpecificAUSize
, garbageCollection
) {
8098 int buf_len
= 256 * 1024;
8099 int overlap_offset
= 64 * 1024;
8100 int write_offset
= buf_len
;
8101 if (string(GetParam()) != "bluestore")
8104 #define WRITE_AT(offset, _length) {\
8105 ObjectStore::Transaction t;\
8106 if ((uint64_t)_length != bl.length()) { \
8107 buffer::ptr p(bl.c_str(), _length);\
8109 bl_tmp.push_back(p);\
8110 t.write(cid, hoid, offset, bl_tmp.length(), bl_tmp);\
8112 t.write(cid, hoid, offset, bl.length(), bl);\
8114 r = queue_transaction(store, ch, std::move(t));\
8118 StartDeferred(65536);
8120 SetVal(g_conf(), "bluestore_compression_max_blob_size", "524288");
8121 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
8122 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
8123 SetVal(g_conf(), "bluestore_compression_mode", "force");
8124 g_conf().apply_changes(nullptr);
8126 auto ch
= store
->create_new_collection(cid
);
8128 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
8131 r
= store
->read(ch
, hoid
, 0, 5, in
);
8132 ASSERT_EQ(-ENOENT
, r
);
8135 ObjectStore::Transaction t
;
8136 t
.create_collection(cid
, 0);
8137 cerr
<< "Creating collection " << cid
<< std::endl
;
8138 r
= queue_transaction(store
, ch
, std::move(t
));
8143 data
.resize(buf_len
);
8147 bool exists
= store
->exists(ch
, hoid
);
8148 ASSERT_TRUE(!exists
);
8150 ObjectStore::Transaction t
;
8152 cerr
<< "Creating object " << hoid
<< std::endl
;
8153 r
= queue_transaction(store
, ch
, std::move(t
));
8156 exists
= store
->exists(ch
, hoid
);
8157 ASSERT_EQ(true, exists
);
8161 for(size_t i
= 0; i
< data
.size(); i
++)
8167 struct store_statfs_t statfs
;
8168 WRITE_AT(0, buf_len
);
8169 int r
= store
->statfs(&statfs
);
8171 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
8174 struct store_statfs_t statfs
;
8175 WRITE_AT(write_offset
- 2 * overlap_offset
, buf_len
);
8176 int r
= store
->statfs(&statfs
);
8178 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
8179 const PerfCounters
* counters
= store
->get_perf_counters();
8180 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0u);
8184 struct store_statfs_t statfs
;
8185 WRITE_AT(write_offset
- overlap_offset
, buf_len
);
8186 int r
= store
->statfs(&statfs
);
8188 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
8189 const PerfCounters
* counters
= store
->get_perf_counters();
8190 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x10000u
);
8193 struct store_statfs_t statfs
;
8194 WRITE_AT(write_offset
- 3 * overlap_offset
, buf_len
);
8195 int r
= store
->statfs(&statfs
);
8197 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
8198 const PerfCounters
* counters
= store
->get_perf_counters();
8199 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
8202 struct store_statfs_t statfs
;
8203 WRITE_AT(write_offset
+ 1, overlap_offset
-1);
8204 int r
= store
->statfs(&statfs
);
8206 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
8207 const PerfCounters
* counters
= store
->get_perf_counters();
8208 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
8211 struct store_statfs_t statfs
;
8212 WRITE_AT(write_offset
+ 1, overlap_offset
);
8213 int r
= store
->statfs(&statfs
);
8215 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
8216 const PerfCounters
* counters
= store
->get_perf_counters();
8217 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x3ffffu
);
8220 struct store_statfs_t statfs
;
8221 WRITE_AT(0, buf_len
-1);
8222 int r
= store
->statfs(&statfs
);
8224 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
8225 const PerfCounters
* counters
= store
->get_perf_counters();
8226 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
8228 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "1"); //forbid GC when saving = 0
8230 struct store_statfs_t statfs
;
8231 WRITE_AT(1, overlap_offset
-2);
8232 WRITE_AT(overlap_offset
* 2 + 1, overlap_offset
-2);
8233 int r
= store
->statfs(&statfs
);
8235 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
8236 const PerfCounters
* counters
= store
->get_perf_counters();
8237 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
8240 struct store_statfs_t statfs
;
8241 WRITE_AT(overlap_offset
+ 1, overlap_offset
-2);
8242 int r
= store
->statfs(&statfs
);
8244 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x0);
8245 const PerfCounters
* counters
= store
->get_perf_counters();
8246 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40007u
);
8249 ObjectStore::Transaction t
;
8250 t
.remove(cid
, hoid
);
8251 cerr
<< "Cleaning" << std::endl
;
8252 r
= queue_transaction(store
, ch
, std::move(t
));
8258 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice
) {
8259 if (string(GetParam()) != "bluestore")
8262 SetVal(g_conf(), "bluestore_block_size",
8263 stringify(0x280005000).c_str()); //10 Gb + 4K
8264 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
8265 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
8266 StartDeferred(0x4000);
8268 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
8273 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice2
) {
8274 if (string(GetParam()) != "bluestore")
8277 SetVal(g_conf(), "bluestore_block_size",
8278 stringify(0x280005000).c_str()); //10 Gb + 20K
8279 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
8280 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
8281 StartDeferred(0x1000);
8283 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
8288 ghobject_t
make_object(const char* name
, int64_t pool
) {
8289 sobject_t soid
{name
, CEPH_NOSNAP
};
8290 uint32_t hash
= std::hash
<sobject_t
>{}(soid
);
8291 return ghobject_t
{hobject_t
{soid
, "", hash
, pool
, ""}};
8295 TEST_P(StoreTestSpecificAUSize
, BluestoreRepairTest
) {
8296 if (string(GetParam()) != "bluestore")
8298 const size_t offs_base
= 65536 / 2;
8301 // Now we need standalone db to pass "false free fix" section below
8302 // Due to new BlueFS allocation model (single allocator for main device)
8303 // it might cause "false free" blob overwrite by BlueFS/DB stuff
8304 // and hence fail the test case and corrupt data.
8307 SetVal(g_conf(), "bluestore_block_db_create", "true");
8308 SetVal(g_conf(), "bluestore_block_db_size", "4294967296");
8310 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
8311 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
8312 SetVal(g_conf(), "bluestore_max_blob_size",
8313 stringify(2 * offs_base
).c_str());
8314 SetVal(g_conf(), "bluestore_extent_map_shard_max_size", "12000");
8315 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "false");
8317 StartDeferred(0x10000);
8319 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
8321 // fill the store with some data
8322 const uint64_t pool
= 555;
8323 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
8324 auto ch
= store
->create_new_collection(cid
);
8326 ghobject_t hoid
= make_object("Object 1", pool
);
8327 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
8328 ghobject_t hoid2
= make_object("Object 2", pool
);
8329 ghobject_t hoid_cloned
= hoid2
;
8330 hoid_cloned
.hobj
.snap
= 1;
8331 ghobject_t hoid3
= make_object("Object 3", pool
);
8332 ghobject_t hoid3_cloned
= hoid3
;
8333 hoid3_cloned
.hobj
.snap
= 1;
8335 bl
.append("1234512345");
8337 const size_t repeats
= 16;
8339 auto ch
= store
->create_new_collection(cid
);
8340 cerr
<< "create collection + write" << std::endl
;
8341 ObjectStore::Transaction t
;
8342 t
.create_collection(cid
, 0);
8343 for( auto i
= 0ul; i
< repeats
; ++i
) {
8344 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
8345 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
8347 for( auto i
= 0ul; i
< repeats
; ++i
) {
8348 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
8350 t
.clone(cid
, hoid2
, hoid_cloned
);
8352 r
= queue_transaction(store
, ch
, std::move(t
));
8357 //////////// leaked pextent fix ////////////
8358 cerr
<< "fix leaked pextents" << std::endl
;
8359 ASSERT_EQ(bstore
->fsck(false), 0);
8360 ASSERT_EQ(bstore
->repair(false), 0);
8362 bstore
->inject_leaked(0x30000);
8364 ASSERT_EQ(bstore
->fsck(false), 1);
8365 ASSERT_EQ(bstore
->repair(false), 0);
8366 ASSERT_EQ(bstore
->fsck(false), 0);
8368 //////////// false free fix ////////////
8369 cerr
<< "fix false free pextents" << std::endl
;
8371 bstore
->inject_false_free(cid
, hoid
);
8373 ASSERT_EQ(bstore
->fsck(false), 2);
8374 ASSERT_EQ(bstore
->repair(false), 0);
8375 ASSERT_EQ(bstore
->fsck(false), 0);
8377 //////////// verify invalid statfs ///////////
8378 cerr
<< "fix invalid statfs" << std::endl
;
8379 store_statfs_t statfs0
, statfs
;
8381 ASSERT_EQ(bstore
->statfs(&statfs0
), 0);
8383 statfs
.allocated
+= 0x10000;
8384 statfs
.data_stored
+= 0x10000;
8385 ASSERT_FALSE(statfs0
== statfs
);
8386 bstore
->inject_statfs("bluestore_statfs", statfs
);
8389 ASSERT_EQ(bstore
->fsck(false), 2);
8390 ASSERT_EQ(bstore
->repair(false), 0);
8391 ASSERT_EQ(bstore
->fsck(false), 0);
8392 ASSERT_EQ(bstore
->mount(), 0);
8393 ASSERT_EQ(bstore
->statfs(&statfs
), 0);
8394 // adjust free/internal meta space to success in comparison
8395 statfs0
.available
= statfs
.available
;
8396 statfs0
.internal_metadata
= statfs
.internal_metadata
;
8397 ASSERT_EQ(statfs0
, statfs
);
8399 ///////// undecodable shared blob key / stray shared blob records ///////
8400 cerr
<< "undecodable shared blob key" << std::endl
;
8401 bstore
->inject_broken_shared_blob_key("undec1",
8403 bstore
->inject_broken_shared_blob_key("undecodable key 2",
8405 bstore
->inject_broken_shared_blob_key("undecodable key 3",
8408 ASSERT_EQ(bstore
->fsck(false), 3);
8409 ASSERT_EQ(bstore
->repair(false), 0);
8410 ASSERT_EQ(bstore
->fsck(false), 0);
8412 cerr
<< "misreferencing" << std::endl
;
8414 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, 0);
8415 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, (offs_base
* repeats
) / 2);
8416 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, offs_base
* (repeats
-1) );
8419 ASSERT_EQ(bstore
->fsck(false), 6);
8420 ASSERT_EQ(bstore
->repair(false), 0);
8422 ASSERT_EQ(bstore
->fsck(true), 0);
8424 // reproducing issues #21040 & 20983
8425 SetVal(g_conf(), "bluestore_debug_inject_bug21040", "true");
8426 g_ceph_context
->_conf
.apply_changes(nullptr);
8429 cerr
<< "repro bug #21040" << std::endl
;
8431 auto ch
= store
->open_collection(cid
);
8433 ObjectStore::Transaction t
;
8434 bl
.append("0123456789012345");
8435 t
.write(cid
, hoid3
, offs_base
, bl
.length(), bl
);
8438 t
.write(cid
, hoid3
, 0, bl
.length(), bl
);
8440 r
= queue_transaction(store
, ch
, std::move(t
));
8444 ObjectStore::Transaction t
;
8445 t
.clone(cid
, hoid3
, hoid3_cloned
);
8446 r
= queue_transaction(store
, ch
, std::move(t
));
8451 ASSERT_EQ(bstore
->fsck(false), 3);
8452 ASSERT_LE(bstore
->repair(false), 0);
8453 ASSERT_EQ(bstore
->fsck(false), 0);
8456 cerr
<< "Zombie spanning blob" << std::endl
;
8459 ghobject_t hoid4
= make_object("Object 4", pool
);
8460 auto ch
= store
->open_collection(cid
);
8463 string
s(0x1000, 'a');
8465 ObjectStore::Transaction t
;
8466 for(size_t i
= 0; i
< 0x10; i
++) {
8467 t
.write(cid
, hoid4
, i
* bl
.length(), bl
.length(), bl
);
8469 r
= queue_transaction(store
, ch
, std::move(t
));
8474 bstore
->inject_zombie_spanning_blob(cid
, hoid4
, 12345);
8475 bstore
->inject_zombie_spanning_blob(cid
, hoid4
, 23456);
8476 bstore
->inject_zombie_spanning_blob(cid
, hoid4
, 23457);
8480 ASSERT_EQ(bstore
->fsck(false), 1);
8481 ASSERT_LE(bstore
->repair(false), 0);
8482 ASSERT_EQ(bstore
->fsck(false), 0);
8485 cerr
<< "Completing" << std::endl
;
8490 TEST_P(StoreTestSpecificAUSize
, BluestoreBrokenZombieRepairTest
) {
8491 if (string(GetParam()) != "bluestore")
8494 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
8495 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
8497 StartDeferred(0x10000);
8499 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
8503 cerr
<< "initializing" << std::endl
;
8505 const size_t col_count
= 16;
8506 const size_t obj_count
= 1024;
8507 ObjectStore::CollectionHandle ch
[col_count
];
8508 ghobject_t hoid
[col_count
][obj_count
];
8510 unique_ptr
<coll_t
> cid
[col_count
];
8512 for (size_t i
= 0; i
< col_count
; i
++) {
8513 cid
[i
].reset(new coll_t(spg_t(pg_t(0, i
), shard_id_t::NO_SHARD
)));
8514 ch
[i
] = store
->create_new_collection(*cid
[i
]);
8515 for (size_t j
= 0; j
< obj_count
; j
++) {
8516 hoid
[i
][j
] = make_object(stringify(j
).c_str(), i
);
8520 for (size_t i
= 0; i
< col_count
; i
++) {
8521 ObjectStore::Transaction t
;
8522 t
.create_collection(*cid
[i
], 0);
8523 r
= queue_transaction(store
, ch
[i
], std::move(t
));
8526 cerr
<< "onode preparing" << std::endl
;
8528 string
s(0x1000, 'a');
8531 for (size_t i
= 0; i
< col_count
; i
++) {
8532 for (size_t j
= 0; j
< obj_count
; j
++) {
8533 ObjectStore::Transaction t
;
8534 t
.write(*cid
[i
], hoid
[i
][j
], bl
.length(), bl
.length(), bl
);
8535 r
= queue_transaction(store
, ch
[i
], std::move(t
));
8539 cerr
<< "Zombie spanning blob injection" << std::endl
;
8543 for (size_t i
= 0; i
< col_count
; i
++) {
8544 for (size_t j
= 0; j
< obj_count
; j
++) {
8545 bstore
->inject_zombie_spanning_blob(*cid
[i
], hoid
[i
][j
], 12345);
8549 cerr
<< "fscking/fixing" << std::endl
;
8551 ASSERT_EQ(bstore
->fsck(false), col_count
* obj_count
);
8552 ASSERT_LE(bstore
->quick_fix(), 0);
8553 ASSERT_EQ(bstore
->fsck(false), 0);
8556 cerr
<< "Completing" << std::endl
;
8560 TEST_P(StoreTest
, BluestoreRepairGlobalStats
) {
8561 if (string(GetParam()) != "bluestore")
8563 const size_t offs_base
= 65536 / 2;
8565 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
8567 // start with global stats
8568 bstore
->inject_global_statfs({});
8570 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
8573 // fill the store with some data
8574 const uint64_t pool
= 555;
8575 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
8576 auto ch
= store
->create_new_collection(cid
);
8578 ghobject_t hoid
= make_object("Object 1", pool
);
8579 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
8580 ghobject_t hoid2
= make_object("Object 2", pool
);
8581 ghobject_t hoid_cloned
= hoid2
;
8582 hoid_cloned
.hobj
.snap
= 1;
8583 ghobject_t hoid3
= make_object("Object 3", pool
);
8584 ghobject_t hoid3_cloned
= hoid3
;
8585 hoid3_cloned
.hobj
.snap
= 1;
8587 bl
.append("1234512345");
8589 const size_t repeats
= 16;
8591 auto ch
= store
->create_new_collection(cid
);
8592 cerr
<< "create collection + write" << std::endl
;
8593 ObjectStore::Transaction t
;
8594 t
.create_collection(cid
, 0);
8595 for( auto i
= 0ul; i
< repeats
; ++i
) {
8596 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
8597 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
8599 for( auto i
= 0ul; i
< repeats
; ++i
) {
8600 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
8602 t
.clone(cid
, hoid2
, hoid_cloned
);
8604 r
= queue_transaction(store
, ch
, std::move(t
));
8610 // enable per-pool stats collection hence causing fsck to fail
8611 cerr
<< "per-pool statfs" << std::endl
;
8612 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
8613 g_ceph_context
->_conf
.apply_changes(nullptr);
8615 ASSERT_EQ(bstore
->fsck(false), 1);
8616 ASSERT_EQ(bstore
->repair(false), 0);
8617 ASSERT_EQ(bstore
->fsck(false), 0);
8622 TEST_P(StoreTest
, BluestoreRepairGlobalStatsFixOnMount
) {
8623 if (string(GetParam()) != "bluestore")
8625 const size_t offs_base
= 65536 / 2;
8627 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
8629 // start with global stats
8630 bstore
->inject_global_statfs({});
8632 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
8635 // fill the store with some data
8636 const uint64_t pool
= 555;
8637 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
8638 auto ch
= store
->create_new_collection(cid
);
8640 ghobject_t hoid
= make_object("Object 1", pool
);
8641 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
8642 ghobject_t hoid2
= make_object("Object 2", pool
);
8643 ghobject_t hoid_cloned
= hoid2
;
8644 hoid_cloned
.hobj
.snap
= 1;
8645 ghobject_t hoid3
= make_object("Object 3", pool
);
8646 ghobject_t hoid3_cloned
= hoid3
;
8647 hoid3_cloned
.hobj
.snap
= 1;
8649 bl
.append("1234512345");
8651 const size_t repeats
= 16;
8653 auto ch
= store
->create_new_collection(cid
);
8654 cerr
<< "create collection + write" << std::endl
;
8655 ObjectStore::Transaction t
;
8656 t
.create_collection(cid
, 0);
8657 for( auto i
= 0ul; i
< repeats
; ++i
) {
8658 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
8659 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
8661 for( auto i
= 0ul; i
< repeats
; ++i
) {
8662 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
8664 t
.clone(cid
, hoid2
, hoid_cloned
);
8666 r
= queue_transaction(store
, ch
, std::move(t
));
8672 // enable per-pool stats collection hence causing fsck to fail
8673 cerr
<< "per-pool statfs" << std::endl
;
8674 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
8675 g_ceph_context
->_conf
.apply_changes(nullptr);
8677 ASSERT_EQ(bstore
->fsck(false), 1);
8679 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
8682 ASSERT_EQ(bstore
->fsck(false), 0);
8687 TEST_P(StoreTest
, BluestoreStatistics
) {
8688 if (string(GetParam()) != "bluestore")
8691 SetVal(g_conf(), "rocksdb_perf", "true");
8692 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
8693 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
8694 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
8697 SetVal(g_conf(), "bluestore_cache_size_ssd", "0");
8698 SetVal(g_conf(), "bluestore_cache_size_hdd", "0");
8699 SetVal(g_conf(), "bluestore_cache_size", "0");
8700 g_ceph_context
->_conf
.apply_changes(nullptr);
8702 int r
= store
->umount();
8707 BlueStore
* bstore
= NULL
;
8708 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
8711 ghobject_t
hoid(hobject_t("test_db_statistics", "", CEPH_NOSNAP
, 0, 0, ""));
8712 auto ch
= bstore
->create_new_collection(cid
);
8714 bl
.append("0123456789abcdefghi");
8716 ObjectStore::Transaction t
;
8717 t
.create_collection(cid
, 0);
8719 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
8720 cerr
<< "Write object" << std::endl
;
8721 r
= queue_transaction(bstore
, ch
, std::move(t
));
8725 bufferlist readback
;
8726 r
= store
->read(ch
, hoid
, 0, bl
.length(), readback
);
8727 ASSERT_EQ(static_cast<int>(bl
.length()), r
);
8728 ASSERT_TRUE(bl_eq(bl
, readback
));
8730 std::unique_ptr
<Formatter
> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
8731 EXPECT_NO_THROW(store
->get_db_statistics(f
.get()));
8736 TEST_P(StoreTest
, BluestorePerPoolOmapFixOnMount
)
8738 if (string(GetParam()) != "bluestore")
8741 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
8742 const uint64_t pool
= 555;
8743 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
8744 ghobject_t oid
= make_object("Object 1", pool
);
8745 ghobject_t oid2
= make_object("Object 2", pool
);
8746 // fill the store with some data
8747 auto ch
= store
->create_new_collection(cid
);
8748 map
<string
, bufferlist
> omap
;
8752 omap
["omap_key"].append("omap value");
8753 ObjectStore::Transaction t
;
8754 t
.create_collection(cid
, 0);
8756 t
.omap_setheader(cid
, oid
, h
);
8758 t
.omap_setheader(cid
, oid2
, h
);
8759 int r
= queue_transaction(store
, ch
, std::move(t
));
8763 // inject legacy omaps
8764 bstore
->inject_legacy_omap();
8765 bstore
->inject_legacy_omap(cid
, oid
);
8766 bstore
->inject_legacy_omap(cid
, oid2
);
8770 // check we injected an issue
8771 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
8772 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
8773 g_ceph_context
->_conf
.apply_changes(nullptr);
8774 ASSERT_EQ(bstore
->fsck(false), 3);
8776 // set autofix and mount
8777 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
8778 g_ceph_context
->_conf
.apply_changes(nullptr);
8782 // check we fixed it..
8783 ASSERT_EQ(bstore
->fsck(false), 0);
8787 // Now repro https://tracker.ceph.com/issues/43824
8789 // inject legacy omaps again
8790 bstore
->inject_legacy_omap();
8791 bstore
->inject_legacy_omap(cid
, oid
);
8792 bstore
->inject_legacy_omap(cid
, oid2
);
8795 // check we injected an issue
8796 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
8797 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
8798 g_ceph_context
->_conf
.apply_changes(nullptr);
8800 ch
= store
->open_collection(cid
);
8803 // write to onode which will partiall revert per-pool
8804 // omap repair done on mount due to #43824.
8805 // And object removal will leave stray per-pool omap recs
8807 ObjectStore::Transaction t
;
8810 //this triggers onode rec update and hence legacy omap
8811 t
.write(cid
, oid
, 0, bl
.length(), bl
);
8812 t
.remove(cid
, oid2
); // this will trigger stray per-pool omap
8813 int r
= queue_transaction(store
, ch
, std::move(t
));
8817 // check omap's been fixed.
8818 ASSERT_EQ(bstore
->fsck(false), 0); // this will fail without fix for #43824
8823 TEST_P(StoreTest
, SpuriousReadErrorTest
) {
8824 if (string(GetParam()) != "bluestore")
8828 auto logger
= store
->get_perf_counters();
8830 auto ch
= store
->create_new_collection(cid
);
8831 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
8833 ObjectStore::Transaction t
;
8834 t
.create_collection(cid
, 0);
8835 cerr
<< "Creating collection " << cid
<< std::endl
;
8836 r
= queue_transaction(store
, ch
, std::move(t
));
8839 bufferlist test_data
;
8840 bufferptr
ap(0x2000);
8841 memset(ap
.c_str(), 'a', 0x2000);
8842 test_data
.append(ap
);
8844 ObjectStore::Transaction t
;
8845 t
.write(cid
, hoid
, 0, 0x2000, test_data
);
8846 r
= queue_transaction(store
, ch
, std::move(t
));
8848 // force cache clear
8849 EXPECT_EQ(store
->umount(), 0);
8850 EXPECT_EQ(store
->mount(), 0);
8852 ch
= store
->open_collection(cid
);
8854 cerr
<< "Injecting CRC error with no retry, expecting EIO" << std::endl
;
8855 SetVal(g_conf(), "bluestore_retry_disk_reads", "0");
8856 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "1");
8857 g_ceph_context
->_conf
.apply_changes(nullptr);
8860 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8862 ASSERT_EQ(logger
->get(l_bluestore_read_eio
), 1u);
8863 ASSERT_EQ(logger
->get(l_bluestore_reads_with_retries
), 0u);
8866 cerr
<< "Injecting CRC error with retries, expecting success after several retries" << std::endl
;
8867 SetVal(g_conf(), "bluestore_retry_disk_reads", "255");
8868 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "0.8");
8870 * Probabilistic test: 25 reads, each has a 80% chance of failing with 255 retries
8871 * Probability of at least one retried read: 1 - (0.2 ** 25) = 100% - 3e-18
8872 * Probability of a random test failure: 1 - ((1 - (0.8 ** 255)) ** 25) ~= 5e-24
8874 g_ceph_context
->_conf
.apply_changes(nullptr);
8876 for (int i
= 0; i
< 25; ++i
) {
8878 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8879 ASSERT_EQ(0x2000, r
);
8880 ASSERT_TRUE(bl_eq(test_data
, in
));
8882 ASSERT_GE(logger
->get(l_bluestore_reads_with_retries
), 1u);
8886 TEST_P(StoreTest
, mergeRegionTest
) {
8887 if (string(GetParam()) != "bluestore")
8890 SetVal(g_conf(), "bluestore_fsck_on_mount", "true");
8891 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
8892 SetVal(g_conf(), "bdev_debug_inflight_ios", "true");
8893 g_ceph_context
->_conf
.apply_changes(nullptr);
8895 uint32_t chunk_size
= g_ceph_context
->_conf
->bdev_block_size
;
8898 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
8899 auto ch
= store
->create_new_collection(cid
);
8901 ObjectStore::Transaction t
;
8902 t
.create_collection(cid
, 0);
8903 r
= queue_transaction(store
, ch
, std::move(t
));
8907 ObjectStore::Transaction t
;
8909 cerr
<< "Creating object " << hoid
<< std::endl
;
8910 r
= queue_transaction(store
, ch
, std::move(t
));
8914 bl5
.append("abcde");
8915 uint64_t offset
= 0;
8917 ObjectStore::Transaction t
;
8918 t
.write(cid
, hoid
, offset
, 5, bl5
);
8919 t
.write(cid
, hoid
, 0xa + offset
, 5, bl5
);
8920 t
.write(cid
, hoid
, 0x14 + offset
, 5, bl5
);
8921 r
= queue_transaction(store
, ch
, std::move(t
));
8924 { // 2. adjacent regions
8925 ObjectStore::Transaction t
;
8926 offset
= chunk_size
;
8927 t
.write(cid
, hoid
, offset
, 5, bl5
);
8928 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
8929 r
= queue_transaction(store
, ch
, std::move(t
));
8933 ObjectStore::Transaction t
;
8934 offset
= chunk_size
* 2;
8935 t
.write(cid
, hoid
, offset
, 5, bl5
);
8936 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, 5, bl5
);
8937 r
= queue_transaction(store
, ch
, std::move(t
));
8941 ObjectStore::Transaction t
;
8943 blc2
.append_zero(chunk_size
+ 2);
8945 offset
= chunk_size
* 3;
8946 t
.write(cid
, hoid
, offset
, chunk_size
+ 2, blc2
);
8947 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
8948 r
= queue_transaction(store
, ch
, std::move(t
));
8952 ObjectStore::Transaction t
;
8953 uint64_t final_len
= 0;
8954 offset
= chunk_size
* 10;
8956 bl2c2
.append_zero(chunk_size
* 2);
8957 t
.write(cid
, hoid
, offset
+ chunk_size
* 3 - 3, chunk_size
* 2, bl2c2
);
8958 bl2c2
.append_zero(2);
8959 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, chunk_size
* 2 + 2, bl2c2
);
8960 r
= queue_transaction(store
, ch
, std::move(t
));
8963 final_len
= (offset
+ chunk_size
* 3 - 3) + (chunk_size
* 2);
8965 r
= store
->read(ch
, hoid
, 0, final_len
, bl
);
8966 ASSERT_EQ(final_len
, static_cast<uint64_t>(r
));
8970 TEST_P(StoreTestSpecificAUSize
, BluestoreEnforceHWSettingsHdd
) {
8971 if (string(GetParam()) != "bluestore")
8974 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
8975 StartDeferred(0x1000);
8979 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
8980 auto ch
= store
->create_new_collection(cid
);
8982 ObjectStore::Transaction t
;
8983 t
.create_collection(cid
, 0);
8984 cerr
<< "Creating collection " << cid
<< std::endl
;
8985 r
= queue_transaction(store
, ch
, std::move(t
));
8989 ObjectStore::Transaction t
;
8990 bufferlist bl
, orig
;
8991 string
s(g_ceph_context
->_conf
->bluestore_max_blob_size_hdd
, '0');
8993 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
8994 cerr
<< "write" << std::endl
;
8995 r
= queue_transaction(store
, ch
, std::move(t
));
8998 const PerfCounters
* logger
= store
->get_perf_counters();
8999 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 1u);
9003 TEST_P(StoreTestSpecificAUSize
, BluestoreEnforceHWSettingsSsd
) {
9004 if (string(GetParam()) != "bluestore")
9007 SetVal(g_conf(), "bluestore_debug_enforce_settings", "ssd");
9008 StartDeferred(0x1000);
9012 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
9013 auto ch
= store
->create_new_collection(cid
);
9015 ObjectStore::Transaction t
;
9016 t
.create_collection(cid
, 0);
9017 cerr
<< "Creating collection " << cid
<< std::endl
;
9018 r
= queue_transaction(store
, ch
, std::move(t
));
9022 ObjectStore::Transaction t
;
9023 bufferlist bl
, orig
;
9024 string
s(g_ceph_context
->_conf
->bluestore_max_blob_size_ssd
* 8, '0');
9026 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
9027 cerr
<< "write" << std::endl
;
9028 r
= queue_transaction(store
, ch
, std::move(t
));
9031 const PerfCounters
* logger
= store
->get_perf_counters();
9032 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 8u);
9036 TEST_P(StoreTestSpecificAUSize
, ReproNoBlobMultiTest
) {
9038 if(string(GetParam()) != "bluestore")
9041 SetVal(g_conf(), "bluestore_block_db_create", "true");
9042 SetVal(g_conf(), "bluestore_block_db_size", "4294967296");
9043 SetVal(g_conf(), "bluestore_block_size", "12884901888");
9044 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
9046 g_conf().apply_changes(nullptr);
9048 StartDeferred(65536);
9052 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
9053 ghobject_t hoid2
= hoid
;
9054 hoid2
.hobj
.snap
= 1;
9056 auto ch
= store
->create_new_collection(cid
);
9058 ObjectStore::Transaction t
;
9059 t
.create_collection(cid
, 0);
9060 cerr
<< "Creating collection " << cid
<< std::endl
;
9061 r
= queue_transaction(store
, ch
, std::move(t
));
9065 bool exists
= store
->exists(ch
, hoid
);
9066 ASSERT_TRUE(!exists
);
9068 ObjectStore::Transaction t
;
9070 cerr
<< "Creating object " << hoid
<< std::endl
;
9071 r
= queue_transaction(store
, ch
, std::move(t
));
9074 exists
= store
->exists(ch
, hoid
);
9075 ASSERT_EQ(true, exists
);
9080 const int size
= 0x100;
9082 memset(ap
.c_str(), 'a', size
);
9085 uint64_t blob_size
= 524288;
9087 for (i
= 0; i
<= 512; i
++) {
9088 offs
= 0 + i
* size
;
9089 ObjectStore::Transaction t
;
9090 ghobject_t hoid2
= hoid
;
9091 hoid2
.hobj
.snap
= i
+ 1;
9092 while (offs
< 128 * 1024 * 1024) {
9094 t
.write(cid
, hoid
, offs
, ap
.length(), bl
);
9096 total
+= ap
.length();
9098 t
.clone(cid
, hoid
, hoid2
);
9099 r
= queue_transaction(store
, ch
, std::move(t
));
9102 cerr
<< "Total written = " << total
<< std::endl
;
9105 cerr
<< "Finalizing" << std::endl
;
9106 const PerfCounters
* logger
= store
->get_perf_counters();
9107 ASSERT_GE(logger
->get(l_bluestore_gc_merged
), 1024*1024*1024);
9111 void doManySetAttr(ObjectStore
* store
,
9112 std::function
<void(ObjectStore
*)> do_check_fn
)
9114 MixedGenerator
gen(447);
9115 gen_type
rng(time(NULL
));
9116 coll_t
cid(spg_t(pg_t(0, 447), shard_id_t::NO_SHARD
));
9118 SyntheticWorkloadState
test_obj(store
, &gen
, &rng
, cid
, 0, 0, 0);
9120 size_t object_count
= 256;
9121 for (size_t i
= 0; i
< object_count
; ++i
) {
9122 if (!(i
% 10)) cerr
<< "seeding object " << i
<< std::endl
;
9125 for (size_t i
= 0; i
< object_count
; ++i
) {
9127 cerr
<< "Op " << i
<< std::endl
;
9128 test_obj
.print_internal_state();
9130 test_obj
.set_fixed_attrs(1024, 64, 4096); // 1024 attributes, 64 bytes name and 4K value
9132 test_obj
.wait_for_done();
9134 std::cout
<< "done" << std::endl
;
9136 AdminSocket
* admin_socket
= g_ceph_context
->get_admin_socket();
9137 ceph_assert(admin_socket
);
9139 ceph::bufferlist in
, out
;
9142 auto r
= admin_socket
->execute_command(
9143 { "{\"prefix\": \"bluefs stats\"}" },
9146 cerr
<< "failure querying: " << cpp_strerror(r
) << std::endl
;
9148 std::cout
<< std::string(out
.c_str(), out
.length()) << std::endl
;
9150 test_obj
.shutdown();
9153 TEST_P(StoreTestSpecificAUSize
, SpilloverTest
) {
9154 if (string(GetParam()) != "bluestore")
9157 SetVal(g_conf(), "bluestore_block_db_create", "true");
9158 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
9159 SetVal(g_conf(), "bluestore_volume_selection_policy", "rocksdb_original");
9161 g_conf().apply_changes(nullptr);
9163 StartDeferred(65536);
9164 doManySetAttr(store
.get(),
9165 [&](ObjectStore
* _store
) {
9167 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
9168 ceph_assert(bstore
);
9170 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
9171 //experimentally it was discovered that this case results in 400+MB spillover
9172 //using lower 300MB threshold just to be safe enough
9173 std::cout
<< "db_used:" << logger
->get(l_bluefs_db_used_bytes
) << std::endl
;
9174 std::cout
<< "slow_used:" << logger
->get(l_bluefs_slow_used_bytes
) << std::endl
;
9175 ASSERT_GE(logger
->get(l_bluefs_slow_used_bytes
), 16 * 1024 * 1024);
9181 TEST_P(StoreTestSpecificAUSize
, SpilloverFixedTest
) {
9182 if (string(GetParam()) != "bluestore")
9185 SetVal(g_conf(), "bluestore_block_db_create", "true");
9186 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
9187 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
9188 SetVal(g_conf(), "bluestore_volume_selection_reserved", "1"); // just use non-zero to enable
9190 g_conf().apply_changes(nullptr);
9192 StartDeferred(65536);
9193 doManySetAttr(store
.get(),
9194 [&](ObjectStore
* _store
) {
9196 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
9197 ceph_assert(bstore
);
9199 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
9200 ASSERT_EQ(0, logger
->get(l_bluefs_slow_used_bytes
));
9205 TEST_P(StoreTestSpecificAUSize
, SpilloverFixed2Test
) {
9206 if (string(GetParam()) != "bluestore")
9209 SetVal(g_conf(), "bluestore_block_db_create", "true");
9210 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
9211 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
9212 //default 2.0 factor results in too high threshold, using less value
9213 // that results in less but still present spillover.
9214 SetVal(g_conf(), "bluestore_volume_selection_reserved_factor", "0.5");
9216 g_conf().apply_changes(nullptr);
9218 StartDeferred(65536);
9219 doManySetAttr(store
.get(),
9220 [&](ObjectStore
* _store
) {
9222 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
9223 ceph_assert(bstore
);
9225 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
9226 ASSERT_LE(logger
->get(l_bluefs_slow_used_bytes
), 300 * 1024 * 1024); // see SpilloverTest for 300MB choice rationale
9231 TEST_P(StoreTestSpecificAUSize
, SpilloverFixed3Test
) {
9232 if (string(GetParam()) != "bluestore")
9235 SetVal(g_conf(), "bluestore_block_db_create", "true");
9236 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
9237 SetVal(g_conf(), "bluestore_volume_selection_policy", "fit_to_fast");
9239 g_conf().apply_changes(nullptr);
9241 StartDeferred(65536);
9242 doManySetAttr(store
.get(),
9243 [&](ObjectStore
* _store
) {
9245 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
9246 ceph_assert(bstore
);
9248 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
9249 ASSERT_EQ(logger
->get(l_bluefs_slow_used_bytes
), 0); // reffering to SpilloverFixedTest
9254 TEST_P(StoreTestSpecificAUSize
, Ticket45195Repro
) {
9255 if (string(GetParam()) != "bluestore")
9258 SetVal(g_conf(), "bluestore_default_buffered_write", "true");
9259 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
9260 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
9261 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9262 g_conf().apply_changes(nullptr);
9264 StartDeferred(0x1000);
9268 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
9269 auto ch
= store
->create_new_collection(cid
);
9271 ObjectStore::Transaction t
;
9272 t
.create_collection(cid
, 0);
9273 cerr
<< "Creating collection " << cid
<< std::endl
;
9274 r
= queue_transaction(store
, ch
, std::move(t
));
9278 size_t large_object_size
= 1 * 1024 * 1024;
9279 size_t expected_write_size
= 0x8000;
9280 ObjectStore::Transaction t
;
9282 t
.set_alloc_hint(cid
, hoid
, large_object_size
, expected_write_size
,
9283 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
|
9284 CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY
);
9285 r
= queue_transaction(store
, ch
, std::move(t
));
9289 ObjectStore::Transaction t
;
9290 bufferlist bl
, orig
;
9291 string
s(0xc000, '0');
9293 t
.write(cid
, hoid
, 0xb000, bl
.length(), bl
);
9294 r
= queue_transaction(store
, ch
, std::move(t
));
9298 ObjectStore::Transaction t
;
9299 bufferlist bl
, orig
;
9300 string
s(0x10000, '1');
9302 t
.write(cid
, hoid
, 0x16000, bl
.length(), bl
);
9303 r
= queue_transaction(store
, ch
, std::move(t
));
9307 ObjectStore::Transaction t
;
9308 bufferlist bl
, orig
;
9309 string
s(0x4000, '1');
9311 t
.write(cid
, hoid
, 0x1b000, bl
.length(), bl
);
9312 r
= queue_transaction(store
, ch
, std::move(t
));
9316 r
= store
->read(ch
, hoid
, 0xb000, 0xb000, bl
);
9317 ASSERT_EQ(r
, 0xb000);
9322 ch
= store
->open_collection(cid
);
9324 ObjectStore::Transaction t
;
9325 bufferlist bl
, orig
;
9326 string
s(0xf000, '3');
9328 t
.write(cid
, hoid
, 0xf000, bl
.length(), bl
);
9329 cerr
<< "write4" << std::endl
;
9330 r
= queue_transaction(store
, ch
, std::move(t
));
9334 r
= store
->read(ch
, hoid
, 0xb000, 0x10000, bl
);
9335 ASSERT_EQ(r
, 0x10000);
9338 #endif // WITH_BLUESTORE
9340 int main(int argc
, char **argv
) {
9341 vector
<const char*> args
;
9342 argv_to_vec(argc
, (const char **)argv
, args
);
9344 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
9345 CODE_ENVIRONMENT_UTILITY
,
9346 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
9347 common_init_finish(g_ceph_context
);
9349 // make sure we can adjust any config settings
9350 g_ceph_context
->_conf
._clear_safe_to_start_threads();
9352 g_ceph_context
->_conf
.set_val_or_die("osd_journal_size", "400");
9353 g_ceph_context
->_conf
.set_val_or_die("filestore_index_retry_probability", "0.5");
9354 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_timeout", "1000");
9355 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_suicide_timeout", "10000");
9356 //g_ceph_context->_conf.set_val_or_die("filestore_fiemap", "true");
9357 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mkfs", "false");
9358 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mount", "false");
9359 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_umount", "false");
9360 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_small_allocations", "4");
9361 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_freelist", "true");
9362 g_ceph_context
->_conf
.set_val_or_die("bluestore_clone_cow", "true");
9363 g_ceph_context
->_conf
.set_val_or_die("bluestore_max_alloc_size", "196608");
9365 // set small cache sizes so we see trimming during Synthetic tests
9366 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_hdd", "4000000");
9367 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_ssd", "4000000");
9369 // very short *_max prealloc so that we fall back to async submits
9370 g_ceph_context
->_conf
.set_val_or_die("bluestore_blobid_prealloc", "10");
9371 g_ceph_context
->_conf
.set_val_or_die("bluestore_nid_prealloc", "10");
9372 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_randomize_serial_transaction",
9375 g_ceph_context
->_conf
.set_val_or_die("bdev_debug_aio", "true");
9377 // specify device size
9378 g_ceph_context
->_conf
.set_val_or_die("bluestore_block_size",
9379 stringify(DEF_STORE_TEST_BLOCKDEV_SIZE
));
9381 g_ceph_context
->_conf
.set_val_or_die(
9382 "enable_experimental_unrecoverable_data_corrupting_features", "*");
9383 g_ceph_context
->_conf
.apply_changes(nullptr);
9385 ::testing::InitGoogleTest(&argc
, argv
);
9386 return RUN_ALL_TESTS();
9391 * compile-command: "cd ../.. ; make ceph_test_objectstore &&
9392 * ./ceph_test_objectstore \
9393 * --gtest_filter=*.collect_metadata* --log-to-stderr=true --debug-filestore=20