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.
21 #include <sys/mount.h>
22 #include <boost/random/mersenne_twister.hpp>
23 #include <boost/random/uniform_int.hpp>
24 #include <boost/random/binomial_distribution.hpp>
25 #include <fmt/format.h>
26 #include <gtest/gtest.h>
28 #include "os/ObjectStore.h"
29 #include "os/filestore/FileStore.h"
30 #if defined(WITH_BLUESTORE)
31 #include "os/bluestore/BlueStore.h"
32 #include "os/bluestore/BlueFS.h"
34 #include "include/Context.h"
35 #include "common/buffer_instrumentation.h"
36 #include "common/ceph_argparse.h"
37 #include "common/admin_socket.h"
38 #include "global/global_init.h"
39 #include "common/ceph_mutex.h"
40 #include "common/Cond.h"
41 #include "common/errno.h"
42 #include "common/options.h" // for the size literals
43 #include "common/pretty_binary.h"
44 #include "include/stringify.h"
45 #include "include/coredumpctl.h"
46 #include "include/unordered_map.h"
48 #include "store_test_fixture.h"
52 using namespace std::placeholders
;
54 typedef boost::mt11213b gen_type
;
56 const uint64_t DEF_STORE_TEST_BLOCKDEV_SIZE
= 10240000000;
57 #define dout_context g_ceph_context
61 static bool bl_eq(bufferlist
& expected
, bufferlist
& actual
)
63 if (expected
.contents_equal(actual
))
67 if(expected
.length() != actual
.length()) {
68 cout
<< "--- buffer lengths mismatch " << std::hex
69 << "expected 0x" << expected
.length() << " != actual 0x"
70 << actual
.length() << std::dec
<< std::endl
;
71 derr
<< "--- buffer lengths mismatch " << std::hex
72 << "expected 0x" << expected
.length() << " != actual 0x"
73 << actual
.length() << std::dec
<< dendl
;
75 auto len
= std::min(expected
.length(), actual
.length());
76 while ( first
<len
&& expected
[first
] == actual
[first
])
79 while (last
> 0 && expected
[last
-1] == actual
[last
-1])
82 cout
<< "--- buffer mismatch between offset 0x" << std::hex
<< first
83 << " and 0x" << last
<< ", total 0x" << len
<< std::dec
85 derr
<< "--- buffer mismatch between offset 0x" << std::hex
<< first
86 << " and 0x" << last
<< ", total 0x" << len
<< std::dec
88 cout
<< "--- expected:\n";
89 expected
.hexdump(cout
);
90 cout
<< "--- actual:\n";
99 int queue_transaction(
101 ObjectStore::CollectionHandle ch
,
102 ObjectStore::Transaction
&&t
) {
104 ObjectStore::Transaction t2
;
106 return store
->queue_transaction(ch
, std::move(t2
));
108 return store
->queue_transaction(ch
, std::move(t
));
112 template <typename T
>
113 int collection_list(T
&store
, ObjectStore::CollectionHandle
&c
,
114 const ghobject_t
& start
, const ghobject_t
& end
, int max
,
115 vector
<ghobject_t
> *ls
, ghobject_t
*pnext
,
116 bool disable_legacy
= false) {
117 if (disable_legacy
|| rand() % 2) {
118 return store
->collection_list(c
, start
, end
, max
, ls
, pnext
);
120 return store
->collection_list_legacy(c
, start
, end
, max
, ls
, pnext
);
124 bool sorted(const vector
<ghobject_t
> &in
) {
126 for (vector
<ghobject_t
>::const_iterator i
= in
.begin();
130 cout
<< start
<< " should follow " << *i
<< std::endl
;
138 class StoreTest
: public StoreTestFixture
,
139 public ::testing::WithParamInterface
<const char*> {
142 : StoreTestFixture(GetParam())
144 void doCompressionTest();
145 void doSyntheticTest(
147 uint64_t max_obj
, uint64_t max_wr
, uint64_t align
);
150 class StoreTestDeferredSetup
: public StoreTest
{
151 void SetUp() override
{
156 void DeferredSetup() {
164 class StoreTestSpecificAUSize
: public StoreTestDeferredSetup
{
172 uint64_t align
)> MatrixTest
;
174 void StartDeferred(size_t min_alloc_size
) {
175 SetVal(g_conf(), "bluestore_min_alloc_size", stringify(min_alloc_size
).c_str());
180 // bluestore matrix testing
181 uint64_t max_write
= 40 * 1024;
182 uint64_t max_size
= 400 * 1024;
183 uint64_t alignment
= 0;
184 uint64_t num_ops
= 10000;
187 string
matrix_get(const char *k
) {
188 if (string(k
) == "max_write") {
189 return stringify(max_write
);
190 } else if (string(k
) == "max_size") {
191 return stringify(max_size
);
192 } else if (string(k
) == "alignment") {
193 return stringify(alignment
);
194 } else if (string(k
) == "num_ops") {
195 return stringify(num_ops
);
198 g_conf().get_val(k
, &buf
, -1);
205 void matrix_set(const char *k
, const char *v
) {
206 if (string(k
) == "max_write") {
207 max_write
= atoll(v
);
208 } else if (string(k
) == "max_size") {
210 } else if (string(k
) == "alignment") {
211 alignment
= atoll(v
);
212 } else if (string(k
) == "num_ops") {
215 SetVal(g_conf(), k
, v
);
219 void do_matrix_choose(const char *matrix
[][10],
220 int i
, int pos
, int num
,
224 for (count
= 0; matrix
[i
][count
+1]; ++count
) ;
225 for (int j
= 1; matrix
[i
][j
]; ++j
) {
226 matrix_set(matrix
[i
][0], matrix
[i
][j
]);
227 do_matrix_choose(matrix
,
234 cout
<< "---------------------- " << (pos
+ 1) << " / " << num
235 << " ----------------------" << std::endl
;
236 for (unsigned k
=0; matrix
[k
][0]; ++k
) {
237 cout
<< " " << matrix
[k
][0] << " = " << matrix_get(matrix
[k
][0])
240 g_ceph_context
->_conf
.apply_changes(nullptr);
241 fn(num_ops
, max_size
, max_write
, alignment
);
245 void do_matrix(const char *matrix
[][10],
248 if (strcmp(matrix
[0][0], "bluestore_min_alloc_size") == 0) {
250 for (count
= 0; matrix
[0][count
+1]; ++count
) ;
251 for (size_t j
= 1; matrix
[0][j
]; ++j
) {
255 StartDeferred(strtoll(matrix
[0][j
], NULL
, 10));
256 do_matrix_choose(matrix
, 1, j
- 1, count
, fn
);
260 do_matrix_choose(matrix
, 0, 0, 1, fn
);
266 class StoreTestOmapUpgrade
: public StoreTestDeferredSetup
{
268 void StartDeferred() {
283 std::string
generate_monotonic_name(uint32_t SUM
, uint32_t i
, double r
, double x
)
286 //std::cout << "r=" << r << " x=" << x << std::endl;
290 uint32_t hi
= 1 + gen() * 10;
291 uint32_t start
= ('z' - 'a' + 1 - hi
) * gen();
292 while (hi
- lo
> 0) {
293 uint32_t mid
= (lo
+ hi
+ 1 + (SUM
&1)) / 2; // round up or down, depending on SUM
294 // std::cout << "SUM=" << SUM << " x=" << gen.x << std::endl;
295 uint32_t mid_val
= gen() * (SUM
- 1) + 1;
296 // LEFT = lo .. mid - 1
298 // std::cout << "lo=" << lo << " hi=" << hi << " mid=" << mid
299 // << " SUM=" << SUM << " i=" << i << " x=" << gen.x << " mid_val=" << mid_val << std::endl;
309 //std::cout << "lo=" << lo << " hi=" << hi
310 // << " SUM=" << SUM << " i=" << i << std::endl;
312 s
.push_back('a' + lo
+ start
); // to keep alphabetic order
313 uint32_t cnt
= gen() * 8;
314 for (uint32_t j
= 0; j
< cnt
; j
++) {
315 s
.push_back('a' + ('z' - 'a' + 1) * gen());
322 std::string
gen_string(size_t size
, generator
& gen
) {
324 for (size_t i
= 0; i
< size
; i
++) {
325 s
.push_back('a' + ('z' - 'a' + 1 ) * gen());
330 void make_omap_data(size_t object_count
,
334 ObjectStore::CollectionHandle ch
= store
->open_collection(cid
);
335 for (size_t o
= 0; o
< object_count
; o
++)
337 ObjectStore::Transaction t
;
338 std::string oid
= generate_monotonic_name(object_count
, o
, 3.71, 0.5);
339 ghobject_t
hoid(hobject_t(oid
, "", CEPH_NOSNAP
, 0, poolid
, ""));
341 generator gen
{3.85 + 0.1 * o
/ object_count
, 1 - double(o
) / object_count
};
343 map
<string
, bufferlist
> start_set
;
344 size_t omap_count
= 1 + gen() * 20;
345 bool do_omap_header
= gen() > 0.5;
346 if (do_omap_header
) {
348 header
.append(gen_string(50, gen
));
349 t
.omap_setheader(cid
, hoid
, header
);
351 for (size_t i
= 0; i
< omap_count
; i
++) {
352 std::string name
= generate_monotonic_name(omap_count
, i
, 3.66 + 0.22 * o
/ object_count
, 0.5);
354 val
.append(gen_string(100, gen
));
355 start_set
.emplace(name
, val
);
357 t
.omap_setkeys(cid
, hoid
, start_set
);
358 r
= queue_transaction(store
, ch
, std::move(t
));
363 void check_omap_data(size_t object_count
,
367 ObjectStore::CollectionHandle ch
= store
->open_collection(cid
);
369 for (size_t o
= 0; o
< object_count
; o
++)
371 ObjectStore::Transaction t
;
372 std::string oid
= generate_monotonic_name(object_count
, o
, 3.71, 0.5);
373 ghobject_t
hoid(hobject_t(oid
, "", CEPH_NOSNAP
, 0, poolid
, ""));
374 generator gen
{3.85 + 0.1 * o
/ object_count
, 1 - double(o
) / object_count
};
376 bufferlist omap_header
;
377 map
<string
, bufferlist
> omap_set
;
378 r
= store
->omap_get(ch
, hoid
, &omap_header
, &omap_set
);
380 size_t omap_count
= 1 + gen() * 20;
381 bool do_omap_header
= gen() > 0.5;
382 if (do_omap_header
) {
383 std::string header_str
= gen_string(50, gen
);
384 ASSERT_EQ(header_str
, omap_header
.to_str());
386 auto it
= omap_set
.begin();
387 for (size_t i
= 0; i
< omap_count
; i
++) {
388 ASSERT_TRUE(it
!= omap_set
.end());
389 std::string name
= generate_monotonic_name(omap_count
, i
, 3.66 + 0.22 * o
/ object_count
, 0.5);
390 std::string val_gen
= gen_string(100, gen
);
391 ASSERT_EQ(it
->first
, name
);
392 ASSERT_EQ(it
->second
.to_str(), val_gen
);
399 TEST_P(StoreTest
, collect_metadata
) {
400 map
<string
,string
> pm
;
401 store
->collect_metadata(&pm
);
402 if (GetParam() == string("filestore")) {
403 ASSERT_NE(pm
.count("filestore_backend"), 0u);
404 ASSERT_NE(pm
.count("filestore_f_type"), 0u);
405 ASSERT_NE(pm
.count("backend_filestore_partition_path"), 0u);
406 ASSERT_NE(pm
.count("backend_filestore_dev_node"), 0u);
410 TEST_P(StoreTest
, Trivial
) {
413 TEST_P(StoreTest
, TrivialRemount
) {
414 int r
= store
->umount();
420 TEST_P(StoreTest
, TrivialRemountFsck
) {
421 if(string(GetParam()) != "bluestore")
423 int r
= store
->umount();
425 r
= store
->fsck(false);
431 TEST_P(StoreTest
, SimpleRemount
) {
433 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
434 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
436 bl
.append("1234512345");
438 auto ch
= store
->create_new_collection(cid
);
440 cerr
<< "create collection + write" << std::endl
;
441 ObjectStore::Transaction t
;
442 t
.create_collection(cid
, 0);
443 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
444 r
= queue_transaction(store
, ch
, std::move(t
));
452 ch
= store
->open_collection(cid
);
454 ObjectStore::Transaction t
;
455 t
.write(cid
, hoid2
, 0, bl
.length(), bl
);
456 r
= queue_transaction(store
, ch
, std::move(t
));
460 ObjectStore::Transaction t
;
462 t
.remove(cid
, hoid2
);
463 t
.remove_collection(cid
);
464 cerr
<< "remove collection" << std::endl
;
465 r
= queue_transaction(store
, ch
, std::move(t
));
473 ch
= store
->create_new_collection(cid
);
475 ObjectStore::Transaction t
;
476 t
.create_collection(cid
, 0);
477 r
= queue_transaction(store
, ch
, std::move(t
));
479 bool exists
= store
->exists(ch
, hoid
);
480 ASSERT_TRUE(!exists
);
483 ObjectStore::Transaction t
;
484 t
.remove_collection(cid
);
485 cerr
<< "remove collection" << std::endl
;
486 r
= queue_transaction(store
, ch
, std::move(t
));
491 TEST_P(StoreTest
, IORemount
) {
494 bl
.append("1234512345");
496 auto ch
= store
->create_new_collection(cid
);
498 cerr
<< "create collection + objects" << std::endl
;
499 ObjectStore::Transaction t
;
500 t
.create_collection(cid
, 0);
501 for (int n
=1; n
<=100; ++n
) {
502 ghobject_t
hoid(hobject_t(sobject_t("Object " + stringify(n
), CEPH_NOSNAP
)));
503 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
505 r
= queue_transaction(store
, ch
, std::move(t
));
510 cout
<< "overwrites" << std::endl
;
511 for (int n
=1; n
<=100; ++n
) {
512 ObjectStore::Transaction t
;
513 ghobject_t
hoid(hobject_t(sobject_t("Object " + stringify(n
), CEPH_NOSNAP
)));
514 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
515 r
= queue_transaction(store
, ch
, std::move(t
));
525 ObjectStore::Transaction t
;
526 for (int n
=1; n
<=100; ++n
) {
527 ghobject_t
hoid(hobject_t(sobject_t("Object " + stringify(n
), CEPH_NOSNAP
)));
530 t
.remove_collection(cid
);
531 auto ch
= store
->open_collection(cid
);
532 r
= queue_transaction(store
, ch
, std::move(t
));
537 TEST_P(StoreTest
, UnprintableCharsName
) {
539 string name
= "funnychars_";
540 for (unsigned i
= 0; i
< 256; ++i
) {
543 ghobject_t
oid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)));
545 auto ch
= store
->create_new_collection(cid
);
547 cerr
<< "create collection + object" << std::endl
;
548 ObjectStore::Transaction t
;
549 t
.create_collection(cid
, 0);
551 r
= queue_transaction(store
, ch
, std::move(t
));
560 cout
<< "removing" << std::endl
;
561 ObjectStore::Transaction t
;
563 t
.remove_collection(cid
);
564 auto ch
= store
->open_collection(cid
);
565 r
= queue_transaction(store
, ch
, std::move(t
));
570 TEST_P(StoreTest
, FiemapEmpty
) {
573 ghobject_t
oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP
)));
574 auto ch
= store
->create_new_collection(cid
);
576 ObjectStore::Transaction t
;
577 t
.create_collection(cid
, 0);
579 t
.truncate(cid
, oid
, 100000);
580 r
= queue_transaction(store
, ch
, std::move(t
));
585 store
->fiemap(ch
, oid
, 0, 100000, bl
);
586 map
<uint64_t,uint64_t> m
, e
;
587 auto p
= bl
.cbegin();
589 cout
<< " got " << m
<< std::endl
;
591 EXPECT_TRUE(m
== e
|| m
.empty());
594 ObjectStore::Transaction t
;
596 t
.remove_collection(cid
);
597 cerr
<< "remove collection" << std::endl
;
598 r
= queue_transaction(store
, ch
, std::move(t
));
603 TEST_P(StoreTest
, FiemapHoles
) {
604 const uint64_t MAX_EXTENTS
= 4000;
605 const uint64_t SKIP_STEP
= 65536;
608 ghobject_t
oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP
)));
611 auto ch
= store
->create_new_collection(cid
);
613 ObjectStore::Transaction t
;
614 t
.create_collection(cid
, 0);
616 for (uint64_t i
= 0; i
< MAX_EXTENTS
; i
++)
617 t
.write(cid
, oid
, SKIP_STEP
* i
, 3, bl
);
618 r
= queue_transaction(store
, ch
, std::move(t
));
622 //fiemap test from 0 to SKIP_STEP * (MAX_EXTENTS - 1) + 3
624 store
->fiemap(ch
, oid
, 0, SKIP_STEP
* (MAX_EXTENTS
- 1) + 3, bl
);
625 map
<uint64_t,uint64_t> m
, e
;
626 auto p
= bl
.cbegin();
628 cout
<< " got " << m
<< std::endl
;
629 ASSERT_TRUE(!m
.empty());
631 auto last
= m
.crbegin();
633 ASSERT_EQ(0u, last
->first
);
634 } else if (m
.size() == MAX_EXTENTS
) {
635 for (uint64_t i
= 0; i
< MAX_EXTENTS
; i
++) {
636 ASSERT_TRUE(m
.count(SKIP_STEP
* i
));
639 ASSERT_GT(last
->first
+ last
->second
, SKIP_STEP
* (MAX_EXTENTS
- 1));
642 // fiemap test from SKIP_STEP to SKIP_STEP * (MAX_EXTENTS - 2) + 3
644 store
->fiemap(ch
, oid
, SKIP_STEP
, SKIP_STEP
* (MAX_EXTENTS
- 2) + 3, bl
);
645 map
<uint64_t,uint64_t> m
, e
;
646 auto p
= bl
.cbegin();
648 cout
<< " got " << m
<< std::endl
;
649 ASSERT_TRUE(!m
.empty());
650 // kstore always returns [0, object_size] regardless of offset and length
651 // FIXME: if fiemap logic in kstore is refined
652 if (string(GetParam()) != "kstore") {
653 ASSERT_GE(m
[SKIP_STEP
], 3u);
654 auto last
= m
.crbegin();
656 ASSERT_EQ(SKIP_STEP
, last
->first
);
657 } else if (m
.size() == MAX_EXTENTS
- 2) {
658 for (uint64_t i
= 1; i
< MAX_EXTENTS
- 1; i
++) {
659 ASSERT_TRUE(m
.count(SKIP_STEP
*i
));
662 ASSERT_GT(last
->first
+ last
->second
, SKIP_STEP
* (MAX_EXTENTS
- 1));
666 ObjectStore::Transaction t
;
668 t
.remove_collection(cid
);
669 cerr
<< "remove collection" << std::endl
;
670 r
= queue_transaction(store
, ch
, std::move(t
));
675 TEST_P(StoreTest
, SimpleMetaColTest
) {
679 auto ch
= store
->create_new_collection(cid
);
680 ObjectStore::Transaction t
;
681 t
.create_collection(cid
, 0);
682 cerr
<< "create collection" << std::endl
;
683 r
= queue_transaction(store
, ch
, std::move(t
));
687 ObjectStore::Transaction t
;
688 t
.remove_collection(cid
);
689 cerr
<< "remove collection" << std::endl
;
690 auto ch
= store
->open_collection(cid
);
691 r
= queue_transaction(store
, ch
, std::move(t
));
695 auto ch
= store
->create_new_collection(cid
);
696 ObjectStore::Transaction t
;
697 t
.create_collection(cid
, 0);
698 cerr
<< "add collection" << std::endl
;
699 r
= queue_transaction(store
, ch
, std::move(t
));
703 ObjectStore::Transaction t
;
704 t
.remove_collection(cid
);
705 cerr
<< "remove collection" << std::endl
;
706 auto ch
= store
->open_collection(cid
);
707 r
= queue_transaction(store
, ch
, std::move(t
));
712 TEST_P(StoreTest
, SimplePGColTest
) {
713 coll_t
cid(spg_t(pg_t(1,2), shard_id_t::NO_SHARD
));
716 ObjectStore::Transaction t
;
717 auto ch
= store
->create_new_collection(cid
);
718 t
.create_collection(cid
, 4);
719 cerr
<< "create collection" << std::endl
;
720 r
= queue_transaction(store
, ch
, std::move(t
));
724 ObjectStore::Transaction t
;
725 t
.remove_collection(cid
);
726 cerr
<< "remove collection" << std::endl
;
727 auto ch
= store
->open_collection(cid
);
728 r
= queue_transaction(store
, ch
, std::move(t
));
732 ObjectStore::Transaction t
;
733 t
.create_collection(cid
, 4);
734 cerr
<< "add collection" << std::endl
;
735 auto ch
= store
->create_new_collection(cid
);
736 r
= queue_transaction(store
, ch
, std::move(t
));
740 ObjectStore::Transaction t
;
741 t
.remove_collection(cid
);
742 cerr
<< "remove collection" << std::endl
;
743 auto ch
= store
->open_collection(cid
);
744 r
= queue_transaction(store
, ch
, std::move(t
));
749 TEST_P(StoreTest
, SimpleColPreHashTest
) {
750 // Firstly we will need to revert the value making sure
751 // collection hint actually works
752 int merge_threshold
= g_ceph_context
->_conf
->filestore_merge_threshold
;
753 std::ostringstream oss
;
754 if (merge_threshold
> 0) {
755 oss
<< "-" << merge_threshold
;
756 SetVal(g_conf(), "filestore_merge_threshold", oss
.str().c_str());
759 uint32_t pg_num
= 128;
761 boost::uniform_int
<> pg_id_range(0, pg_num
);
762 gen_type
rng(time(NULL
));
763 int pg_id
= pg_id_range(rng
);
765 int objs_per_folder
= abs(merge_threshold
) * 16 * g_ceph_context
->_conf
->filestore_split_multiple
;
766 boost::uniform_int
<> folders_range(5, 256);
767 uint64_t expected_num_objs
= (uint64_t)objs_per_folder
* (uint64_t)folders_range(rng
);
769 coll_t
cid(spg_t(pg_t(pg_id
, 15), shard_id_t::NO_SHARD
));
771 auto ch
= store
->create_new_collection(cid
);
773 // Create a collection along with a hint
774 ObjectStore::Transaction t
;
775 t
.create_collection(cid
, 5);
776 cerr
<< "create collection" << std::endl
;
778 encode(pg_num
, hint
);
779 encode(expected_num_objs
, hint
);
780 t
.collection_hint(cid
, ObjectStore::Transaction::COLL_HINT_EXPECTED_NUM_OBJECTS
, hint
);
781 cerr
<< "collection hint" << std::endl
;
782 r
= queue_transaction(store
, ch
, std::move(t
));
786 // Remove the collection
787 ObjectStore::Transaction t
;
788 t
.remove_collection(cid
);
789 cerr
<< "remove collection" << std::endl
;
790 r
= queue_transaction(store
, ch
, std::move(t
));
795 TEST_P(StoreTest
, SmallBlockWrites
) {
798 auto ch
= store
->create_new_collection(cid
);
799 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
801 ObjectStore::Transaction t
;
802 t
.create_collection(cid
, 0);
803 cerr
<< "Creating collection " << cid
<< std::endl
;
804 r
= queue_transaction(store
, ch
, std::move(t
));
808 bufferptr
ap(0x1000);
809 memset(ap
.c_str(), 'a', 0x1000);
812 bufferptr
bp(0x1000);
813 memset(bp
.c_str(), 'b', 0x1000);
816 bufferptr
cp(0x1000);
817 memset(cp
.c_str(), 'c', 0x1000);
819 bufferptr
zp(0x1000);
824 ObjectStore::Transaction t
;
825 t
.write(cid
, hoid
, 0, 0x1000, a
);
826 r
= queue_transaction(store
, ch
, std::move(t
));
830 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
831 ASSERT_EQ(0x1000, r
);
833 ASSERT_TRUE(bl_eq(exp
, in
));
836 ObjectStore::Transaction t
;
837 t
.write(cid
, hoid
, 0x1000, 0x1000, b
);
838 r
= queue_transaction(store
, ch
, std::move(t
));
842 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
843 ASSERT_EQ(0x2000, r
);
846 ASSERT_TRUE(bl_eq(exp
, in
));
849 ObjectStore::Transaction t
;
850 t
.write(cid
, hoid
, 0x3000, 0x1000, c
);
851 r
= queue_transaction(store
, ch
, std::move(t
));
855 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
856 ASSERT_EQ(0x4000, r
);
861 ASSERT_TRUE(bl_eq(exp
, in
));
864 ObjectStore::Transaction t
;
865 t
.write(cid
, hoid
, 0x2000, 0x1000, a
);
866 r
= queue_transaction(store
, ch
, std::move(t
));
870 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
871 ASSERT_EQ(0x4000, r
);
876 ASSERT_TRUE(bl_eq(exp
, in
));
879 ObjectStore::Transaction t
;
880 t
.write(cid
, hoid
, 0, 0x1000, c
);
881 r
= queue_transaction(store
, ch
, std::move(t
));
886 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
887 ASSERT_EQ(0x4000, r
);
892 ASSERT_TRUE(bl_eq(exp
, in
));
895 ObjectStore::Transaction t
;
897 t
.remove_collection(cid
);
898 cerr
<< "Cleaning" << std::endl
;
899 r
= queue_transaction(store
, ch
, std::move(t
));
904 TEST_P(StoreTest
, BufferCacheReadTest
) {
907 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
909 auto ch
= store
->open_collection(cid
);
912 auto ch
= store
->create_new_collection(cid
);
914 ObjectStore::Transaction t
;
915 t
.create_collection(cid
, 0);
916 cerr
<< "Creating collection " << cid
<< std::endl
;
917 r
= queue_transaction(store
, ch
, std::move(t
));
921 bool exists
= store
->exists(ch
, hoid
);
922 ASSERT_TRUE(!exists
);
924 ObjectStore::Transaction t
;
926 cerr
<< "Creating object " << hoid
<< std::endl
;
927 r
= queue_transaction(store
, ch
, std::move(t
));
930 exists
= store
->exists(ch
, hoid
);
931 ASSERT_EQ(true, exists
);
934 ObjectStore::Transaction t
;
935 bufferlist bl
, newdata
;
937 t
.write(cid
, hoid
, 0, 5, bl
);
938 t
.write(cid
, hoid
, 10, 5, bl
);
939 cerr
<< "TwinWrite" << std::endl
;
940 r
= queue_transaction(store
, ch
, std::move(t
));
943 r
= store
->read(ch
, hoid
, 0, 15, newdata
);
948 expected
.append_zero(5);
950 ASSERT_TRUE(bl_eq(expected
, newdata
));
953 //overwrite over the same extents
955 ObjectStore::Transaction t
;
956 bufferlist bl
, newdata
;
958 t
.write(cid
, hoid
, 0, 5, bl
);
959 t
.write(cid
, hoid
, 10, 5, bl
);
960 cerr
<< "TwinWrite" << std::endl
;
961 r
= queue_transaction(store
, ch
, std::move(t
));
964 r
= store
->read(ch
, hoid
, 0, 15, newdata
);
969 expected
.append_zero(5);
971 ASSERT_TRUE(bl_eq(expected
, newdata
));
974 //additional write to an unused region of some blob
976 ObjectStore::Transaction t
;
977 bufferlist bl2
, newdata
;
978 bl2
.append("1234567890");
980 t
.write(cid
, hoid
, 20, bl2
.length(), bl2
);
981 cerr
<< "Append" << std::endl
;
982 r
= queue_transaction(store
, ch
, std::move(t
));
985 r
= store
->read(ch
, hoid
, 0, 30, newdata
);
989 expected
.append("edcba");
990 expected
.append_zero(5);
991 expected
.append("edcba");
992 expected
.append_zero(5);
993 expected
.append(bl2
);
995 ASSERT_TRUE(bl_eq(expected
, newdata
));
998 //additional write to an unused region of some blob and partial owerite over existing extents
1000 ObjectStore::Transaction t
;
1001 bufferlist bl
, bl2
, bl3
, newdata
;
1003 bl2
.append("1234567890");
1006 t
.write(cid
, hoid
, 30, bl2
.length(), bl2
);
1007 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
1008 t
.write(cid
, hoid
, 13, bl3
.length(), bl3
);
1009 cerr
<< "TripleWrite" << std::endl
;
1010 r
= queue_transaction(store
, ch
, std::move(t
));
1013 r
= store
->read(ch
, hoid
, 0, 40, newdata
);
1016 bufferlist expected
;
1017 expected
.append("eDCBa");
1018 expected
.append_zero(5);
1019 expected
.append("edcBA");
1020 expected
.append_zero(5);
1021 expected
.append(bl2
);
1022 expected
.append(bl2
);
1024 ASSERT_TRUE(bl_eq(expected
, newdata
));
1029 void StoreTest::doCompressionTest()
1033 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1035 auto ch
= store
->open_collection(cid
);
1038 auto ch
= store
->create_new_collection(cid
);
1040 ObjectStore::Transaction t
;
1041 t
.create_collection(cid
, 0);
1042 cerr
<< "Creating collection " << cid
<< std::endl
;
1043 r
= queue_transaction(store
, ch
, std::move(t
));
1047 bool exists
= store
->exists(ch
, hoid
);
1048 ASSERT_TRUE(!exists
);
1050 ObjectStore::Transaction t
;
1052 cerr
<< "Creating object " << hoid
<< std::endl
;
1053 r
= queue_transaction(store
, ch
, std::move(t
));
1056 exists
= store
->exists(ch
, hoid
);
1057 ASSERT_EQ(true, exists
);
1060 data
.resize(0x10000 * 4);
1061 for(size_t i
= 0;i
< data
.size(); i
++)
1064 ObjectStore::Transaction t
;
1065 bufferlist bl
, newdata
;
1067 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1068 cerr
<< "CompressibleData (4xAU) Write" << std::endl
;
1069 r
= queue_transaction(store
, ch
, std::move(t
));
1072 r
= store
->read(ch
, hoid
, 0, data
.size() , newdata
);
1074 ASSERT_EQ(r
, (int)data
.size());
1076 bufferlist expected
;
1077 expected
.append(data
);
1078 ASSERT_TRUE(bl_eq(expected
, newdata
));
1081 r
= store
->read(ch
, hoid
, 0, 711 , newdata
);
1084 bufferlist expected
;
1085 expected
.append(data
.substr(0,711));
1086 ASSERT_TRUE(bl_eq(expected
, newdata
));
1089 r
= store
->read(ch
, hoid
, 0xf00f, data
.size(), newdata
);
1090 ASSERT_EQ(r
, int(data
.size() - 0xf00f) );
1092 bufferlist expected
;
1093 expected
.append(data
.substr(0xf00f));
1094 ASSERT_TRUE(bl_eq(expected
, newdata
));
1097 struct store_statfs_t statfs
;
1098 int r
= store
->statfs(&statfs
);
1100 ASSERT_EQ(statfs
.data_stored
, (unsigned)data
.size());
1101 ASSERT_LE(statfs
.data_compressed
, (unsigned)data
.size());
1102 ASSERT_EQ(statfs
.data_compressed_original
, (unsigned)data
.size());
1103 ASSERT_LE(statfs
.data_compressed_allocated
, (unsigned)data
.size());
1107 data2
.resize(0x10000 * 4 - 0x9000);
1108 for(size_t i
= 0;i
< data2
.size(); i
++)
1109 data2
[i
] = (i
+1) / 256;
1111 ObjectStore::Transaction t
;
1112 bufferlist bl
, newdata
;
1114 t
.write(cid
, hoid
, 0x8000, bl
.length(), bl
);
1115 cerr
<< "CompressibleData partial overwrite" << std::endl
;
1116 r
= queue_transaction(store
, ch
, std::move(t
));
1119 r
= store
->read(ch
, hoid
, 0, 0x10000, newdata
);
1120 ASSERT_EQ(r
, (int)0x10000);
1122 bufferlist expected
;
1123 expected
.append(data
.substr(0, 0x8000));
1124 expected
.append(data2
.substr(0, 0x8000));
1125 ASSERT_TRUE(bl_eq(expected
, newdata
));
1128 r
= store
->read(ch
, hoid
, 0x9000, 711 , newdata
);
1131 bufferlist expected
;
1132 expected
.append(data2
.substr(0x1000,711));
1133 ASSERT_TRUE(bl_eq(expected
, newdata
));
1136 r
= store
->read(ch
, hoid
, 0x0, 0x40000, newdata
);
1137 ASSERT_EQ(r
, int(0x40000) );
1139 bufferlist expected
;
1140 expected
.append(data
.substr(0, 0x8000));
1141 expected
.append(data2
.substr(0, 0x37000));
1142 expected
.append(data
.substr(0x3f000, 0x1000));
1143 ASSERT_TRUE(bl_eq(expected
, newdata
));
1146 data2
.resize(0x3f000);
1147 for(size_t i
= 0;i
< data2
.size(); i
++)
1148 data2
[i
] = (i
+2) / 256;
1150 ObjectStore::Transaction t
;
1151 bufferlist bl
, newdata
;
1153 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1154 cerr
<< "CompressibleData partial overwrite, two extents overlapped, single one to be removed" << std::endl
;
1155 r
= queue_transaction(store
, ch
, std::move(t
));
1158 r
= store
->read(ch
, hoid
, 0, 0x3e000 - 1, newdata
);
1159 ASSERT_EQ(r
, (int)0x3e000 - 1);
1161 bufferlist expected
;
1162 expected
.append(data2
.substr(0, 0x3e000 - 1));
1163 ASSERT_TRUE(bl_eq(expected
, newdata
));
1166 r
= store
->read(ch
, hoid
, 0x3e000-1, 0x2001, newdata
);
1167 ASSERT_EQ(r
, 0x2001);
1169 bufferlist expected
;
1170 expected
.append(data2
.substr(0x3e000-1, 0x1001));
1171 expected
.append(data
.substr(0x3f000, 0x1000));
1172 ASSERT_TRUE(bl_eq(expected
, newdata
));
1175 r
= store
->read(ch
, hoid
, 0x0, 0x40000, newdata
);
1176 ASSERT_EQ(r
, int(0x40000) );
1178 bufferlist expected
;
1179 expected
.append(data2
.substr(0, 0x3f000));
1180 expected
.append(data
.substr(0x3f000, 0x1000));
1181 ASSERT_TRUE(bl_eq(expected
, newdata
));
1184 data
.resize(0x1001);
1185 for(size_t i
= 0;i
< data
.size(); i
++)
1186 data
[i
] = (i
+3) / 256;
1188 ObjectStore::Transaction t
;
1189 bufferlist bl
, newdata
;
1191 t
.write(cid
, hoid
, 0x3f000-1, bl
.length(), bl
);
1192 cerr
<< "Small chunk partial overwrite, two extents overlapped, single one to be removed" << std::endl
;
1193 r
= queue_transaction(store
, ch
, std::move(t
));
1196 r
= store
->read(ch
, hoid
, 0x3e000, 0x2000, newdata
);
1197 ASSERT_EQ(r
, (int)0x2000);
1199 bufferlist expected
;
1200 expected
.append(data2
.substr(0x3e000, 0x1000 - 1));
1201 expected
.append(data
.substr(0, 0x1001));
1202 ASSERT_TRUE(bl_eq(expected
, newdata
));
1206 ObjectStore::Transaction t
;
1207 t
.remove(cid
, hoid
);
1208 cerr
<< "Cleaning object" << std::endl
;
1209 r
= queue_transaction(store
, ch
, std::move(t
));
1214 EXPECT_EQ(store
->umount(), 0);
1215 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1216 EXPECT_EQ(store
->mount(), 0);
1217 ch
= store
->open_collection(cid
);
1218 auto settingsBookmark
= BookmarkSettings();
1219 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
1220 g_ceph_context
->_conf
.apply_changes(nullptr);
1222 data
.resize(0x10000*6);
1224 for(size_t i
= 0;i
< data
.size(); i
++)
1226 ObjectStore::Transaction t
;
1227 bufferlist bl
, newdata
;
1229 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1230 cerr
<< "CompressibleData large blob" << std::endl
;
1231 r
= queue_transaction(store
, ch
, std::move(t
));
1236 EXPECT_EQ(store
->umount(), 0);
1237 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1238 EXPECT_EQ(store
->mount(), 0);
1239 ch
= store
->open_collection(cid
);
1241 ObjectStore::Transaction t
;
1242 t
.remove(cid
, hoid
);
1243 t
.remove_collection(cid
);
1244 cerr
<< "Cleaning" << std::endl
;
1245 r
= queue_transaction(store
, ch
, std::move(t
));
1250 TEST_P(StoreTest
, CompressionTest
) {
1251 if (string(GetParam()) != "bluestore")
1254 cout
<< "TODO: need to adjust statfs check for smr" << std::endl
;
1258 SetVal(g_conf(), "bluestore_compression_algorithm", "snappy");
1259 SetVal(g_conf(), "bluestore_compression_mode", "force");
1260 g_ceph_context
->_conf
.apply_changes(nullptr);
1261 doCompressionTest();
1263 SetVal(g_conf(), "bluestore_compression_algorithm", "zlib");
1264 SetVal(g_conf(), "bluestore_compression_mode", "aggressive");
1265 g_ceph_context
->_conf
.apply_changes(nullptr);
1266 doCompressionTest();
1269 TEST_P(StoreTest
, SimpleObjectTest
) {
1272 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1274 auto ch
= store
->open_collection(cid
);
1277 auto ch
= store
->create_new_collection(cid
);
1279 ObjectStore::Transaction t
;
1280 t
.create_collection(cid
, 0);
1281 cerr
<< "Creating collection " << cid
<< std::endl
;
1282 r
= queue_transaction(store
, ch
, std::move(t
));
1286 bool exists
= store
->exists(ch
, hoid
);
1287 ASSERT_TRUE(!exists
);
1289 ObjectStore::Transaction t
;
1291 cerr
<< "Creating object " << hoid
<< std::endl
;
1292 r
= queue_transaction(store
, ch
, std::move(t
));
1295 exists
= store
->exists(ch
, hoid
);
1296 ASSERT_EQ(true, exists
);
1299 ObjectStore::Transaction t
;
1300 t
.remove(cid
, hoid
);
1302 cerr
<< "Remove then create" << std::endl
;
1303 r
= queue_transaction(store
, ch
, std::move(t
));
1307 ObjectStore::Transaction t
;
1308 bufferlist bl
, orig
;
1311 t
.remove(cid
, hoid
);
1312 t
.write(cid
, hoid
, 0, 5, bl
);
1313 cerr
<< "Remove then create" << std::endl
;
1314 r
= queue_transaction(store
, ch
, std::move(t
));
1318 r
= store
->read(ch
, hoid
, 0, 5, in
);
1320 ASSERT_TRUE(bl_eq(orig
, in
));
1323 ObjectStore::Transaction t
;
1328 t
.write(cid
, hoid
, 5, 5, bl
);
1329 cerr
<< "Append" << std::endl
;
1330 r
= queue_transaction(store
, ch
, std::move(t
));
1334 r
= store
->read(ch
, hoid
, 0, 10, in
);
1336 ASSERT_TRUE(bl_eq(exp
, in
));
1339 ObjectStore::Transaction t
;
1341 bl
.append("abcdeabcde");
1343 t
.write(cid
, hoid
, 0, 10, bl
);
1344 cerr
<< "Full overwrite" << std::endl
;
1345 r
= queue_transaction(store
, ch
, std::move(t
));
1349 r
= store
->read(ch
, hoid
, 0, 10, in
);
1351 ASSERT_TRUE(bl_eq(exp
, in
));
1354 ObjectStore::Transaction t
;
1357 t
.write(cid
, hoid
, 3, 5, bl
);
1358 cerr
<< "Partial overwrite" << std::endl
;
1359 r
= queue_transaction(store
, ch
, std::move(t
));
1363 exp
.append("abcabcdede");
1364 r
= store
->read(ch
, hoid
, 0, 10, in
);
1367 ASSERT_TRUE(bl_eq(exp
, in
));
1371 ObjectStore::Transaction t
;
1374 t
.truncate(cid
, hoid
, 0);
1375 t
.write(cid
, hoid
, 5, 5, bl
);
1376 cerr
<< "Truncate + hole" << std::endl
;
1377 r
= queue_transaction(store
, ch
, std::move(t
));
1381 ObjectStore::Transaction t
;
1384 t
.write(cid
, hoid
, 0, 5, bl
);
1385 cerr
<< "Reverse fill-in" << std::endl
;
1386 r
= queue_transaction(store
, ch
, std::move(t
));
1391 exp
.append("abcdefghij");
1392 r
= store
->read(ch
, hoid
, 0, 10, in
);
1395 ASSERT_TRUE(bl_eq(exp
, in
));
1398 ObjectStore::Transaction t
;
1400 bl
.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1401 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1402 cerr
<< "larger overwrite" << std::endl
;
1403 r
= queue_transaction(store
, ch
, std::move(t
));
1407 r
= store
->read(ch
, hoid
, 0, bl
.length(), in
);
1408 ASSERT_EQ((int)bl
.length(), r
);
1410 ASSERT_TRUE(bl_eq(bl
, in
));
1414 bl
.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1416 //test: offset=len=0 mean read all data
1418 r
= store
->read(ch
, hoid
, 0, 0, in
);
1419 ASSERT_EQ((int)bl
.length(), r
);
1421 ASSERT_TRUE(bl_eq(bl
, in
));
1424 //verifying unaligned csums
1425 std::string
s1("1"), s2(0x1000, '2'), s3("00");
1427 ObjectStore::Transaction t
;
1431 t
.truncate(cid
, hoid
, 0);
1432 t
.write(cid
, hoid
, 0x1000-1, bl
.length(), bl
);
1433 cerr
<< "Write unaligned csum, stage 1" << std::endl
;
1434 r
= queue_transaction(store
, ch
, std::move(t
));
1438 bufferlist in
, exp1
, exp2
, exp3
;
1442 r
= store
->read(ch
, hoid
, 0x1000-1, 1, in
);
1444 ASSERT_TRUE(bl_eq(exp1
, in
));
1446 r
= store
->read(ch
, hoid
, 0x1000, 0x1000, in
);
1447 ASSERT_EQ(0x1000, r
);
1448 ASSERT_TRUE(bl_eq(exp2
, in
));
1451 ObjectStore::Transaction t
;
1454 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
1455 cerr
<< "Write unaligned csum, stage 2" << std::endl
;
1456 r
= queue_transaction(store
, ch
, std::move(t
));
1460 r
= store
->read(ch
, hoid
, 1, 2, in
);
1462 ASSERT_TRUE(bl_eq(exp3
, in
));
1464 r
= store
->read(ch
, hoid
, 0x1000-1, 1, in
);
1466 ASSERT_TRUE(bl_eq(exp1
, in
));
1468 r
= store
->read(ch
, hoid
, 0x1000, 0x1000, in
);
1469 ASSERT_EQ(0x1000, r
);
1470 ASSERT_TRUE(bl_eq(exp2
, in
));
1475 ObjectStore::Transaction t
;
1476 t
.remove(cid
, hoid
);
1477 t
.remove_collection(cid
);
1478 cerr
<< "Cleaning" << std::endl
;
1479 r
= queue_transaction(store
, ch
, std::move(t
));
1484 #if defined(WITH_BLUESTORE)
1486 TEST_P(StoreTestSpecificAUSize
, ReproBug41901Test
) {
1487 if(string(GetParam()) != "bluestore")
1490 cout
<< "SKIP (smr)" << std::endl
;
1494 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
1495 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
1496 g_conf().apply_changes(nullptr);
1497 StartDeferred(65536);
1501 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1502 const PerfCounters
* logger
= store
->get_perf_counters();
1503 auto ch
= store
->create_new_collection(cid
);
1505 ObjectStore::Transaction t
;
1506 t
.create_collection(cid
, 0);
1507 cerr
<< "Creating collection " << cid
<< std::endl
;
1508 r
= queue_transaction(store
, ch
, std::move(t
));
1512 bool exists
= store
->exists(ch
, hoid
);
1513 ASSERT_TRUE(!exists
);
1515 ObjectStore::Transaction t
;
1517 cerr
<< "Creating object " << hoid
<< std::endl
;
1518 r
= queue_transaction(store
, ch
, std::move(t
));
1521 exists
= store
->exists(ch
, hoid
);
1522 ASSERT_EQ(true, exists
);
1525 ObjectStore::Transaction t
;
1526 bufferlist bl
, orig
;
1527 string
s(4096, 'a');
1529 t
.write(cid
, hoid
, 0x11000, bl
.length(), bl
);
1530 cerr
<< "write1" << std::endl
;
1531 r
= queue_transaction(store
, ch
, std::move(t
));
1535 ObjectStore::Transaction t
;
1536 bufferlist bl
, orig
;
1537 string
s(4096 * 3, 'a');
1539 t
.write(cid
, hoid
, 0x15000, bl
.length(), bl
);
1540 cerr
<< "write2" << std::endl
;
1541 r
= queue_transaction(store
, ch
, std::move(t
));
1544 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 2u);
1545 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 1u);
1548 ObjectStore::Transaction t
;
1549 bufferlist bl
, orig
;
1550 string
s(4096 * 2, 'a');
1552 t
.write(cid
, hoid
, 0xe000, bl
.length(), bl
);
1553 cerr
<< "write3" << std::endl
;
1554 r
= queue_transaction(store
, ch
, std::move(t
));
1557 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 3u);
1558 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 2u);
1562 ObjectStore::Transaction t
;
1563 bufferlist bl
, orig
;
1564 string
s(4096, 'a');
1566 t
.write(cid
, hoid
, 0xf000, bl
.length(), bl
);
1567 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1568 cerr
<< "write3" << std::endl
;
1569 r
= queue_transaction(store
, ch
, std::move(t
));
1572 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 5u);
1573 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 2u);
1575 ObjectStore::Transaction t
;
1576 t
.remove(cid
, hoid
);
1577 t
.remove_collection(cid
);
1578 cerr
<< "Cleaning" << std::endl
;
1579 r
= queue_transaction(store
, ch
, std::move(t
));
1585 TEST_P(StoreTestSpecificAUSize
, BluestoreStatFSTest
) {
1586 if(string(GetParam()) != "bluestore")
1589 cout
<< "TODO: fix this for smr" << std::endl
;
1592 SetVal(g_conf(), "bluestore_block_db_path", "");
1593 StartDeferred(65536);
1594 SetVal(g_conf(), "bluestore_compression_mode", "force");
1595 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
1596 // just a big number to disble gc
1597 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "100000");
1598 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
1599 g_conf().apply_changes(nullptr);
1603 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
1604 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
1609 ghobject_t hoid2
= hoid
;
1610 hoid2
.hobj
.snap
= 1;
1612 auto ch
= store
->open_collection(cid
);
1615 auto ch
= store
->create_new_collection(cid
);
1617 ObjectStore::Transaction t
;
1618 t
.create_collection(cid
, 0);
1619 cerr
<< "Creating collection " << cid
<< std::endl
;
1620 r
= queue_transaction(store
, ch
, std::move(t
));
1624 bool exists
= store
->exists(ch
, hoid
);
1625 ASSERT_TRUE(!exists
);
1627 ObjectStore::Transaction t
;
1629 cerr
<< "Creating object " << hoid
<< std::endl
;
1630 r
= queue_transaction(store
, ch
, std::move(t
));
1633 exists
= store
->exists(ch
, hoid
);
1634 ASSERT_EQ(true, exists
);
1637 struct store_statfs_t statfs
;
1638 int r
= store
->statfs(&statfs
);
1640 ASSERT_EQ( 0u, statfs
.allocated
);
1641 ASSERT_EQ( 0u, statfs
.data_stored
);
1642 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
1643 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
1645 struct store_statfs_t statfs_pool
;
1647 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1649 ASSERT_EQ( 0u, statfs_pool
.allocated
);
1650 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
1654 EXPECT_EQ(store
->umount(), 0);
1655 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1656 EXPECT_EQ(store
->mount(), 0);
1657 ch
= store
->open_collection(cid
);
1660 ObjectStore::Transaction t
;
1663 t
.write(cid
, hoid
, 0, 5, bl
);
1664 cerr
<< "Append 5 bytes" << std::endl
;
1665 r
= queue_transaction(store
, ch
, std::move(t
));
1668 struct store_statfs_t statfs
;
1669 int r
= store
->statfs(&statfs
);
1671 ASSERT_EQ(5, statfs
.data_stored
);
1672 ASSERT_EQ(0x10000, statfs
.allocated
);
1673 ASSERT_EQ(0, statfs
.data_compressed
);
1674 ASSERT_EQ(0, statfs
.data_compressed_original
);
1675 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1677 struct store_statfs_t statfs_pool
;
1679 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1681 ASSERT_EQ(5, statfs_pool
.data_stored
);
1682 ASSERT_EQ(0x10000, statfs_pool
.allocated
);
1683 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1684 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1685 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1687 // accessing unknown pool
1688 r
= store
->pool_statfs(poolid
+ 1, &statfs_pool
, &per_pool_omap
);
1690 ASSERT_EQ(0, statfs_pool
.data_stored
);
1691 ASSERT_EQ(0, statfs_pool
.allocated
);
1692 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1693 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1694 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1698 EXPECT_EQ(store
->umount(), 0);
1699 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1700 EXPECT_EQ(store
->mount(), 0);
1701 ch
= store
->open_collection(cid
);
1704 ObjectStore::Transaction t
;
1705 std::string
s(0x30000, 'a');
1708 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1709 cerr
<< "Append 0x30000 compressible bytes" << std::endl
;
1710 r
= queue_transaction(store
, ch
, std::move(t
));
1713 struct store_statfs_t statfs
;
1714 int r
= store
->statfs(&statfs
);
1716 ASSERT_EQ(0x30005, statfs
.data_stored
);
1717 ASSERT_EQ(0x30000, statfs
.allocated
);
1718 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1719 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1720 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1722 struct store_statfs_t statfs_pool
;
1724 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1726 ASSERT_EQ(0x30005, statfs_pool
.data_stored
);
1727 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1728 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1729 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1730 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1733 EXPECT_EQ(store
->umount(), 0);
1734 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1735 EXPECT_EQ(store
->mount(), 0);
1736 ch
= store
->open_collection(cid
);
1739 ObjectStore::Transaction t
;
1740 t
.zero(cid
, hoid
, 1, 3);
1741 t
.zero(cid
, hoid
, 0x20000, 9);
1742 cerr
<< "Punch hole at 1~3, 0x20000~9" << std::endl
;
1743 r
= queue_transaction(store
, ch
, std::move(t
));
1746 struct store_statfs_t statfs
;
1747 int r
= store
->statfs(&statfs
);
1749 ASSERT_EQ(0x30005 - 3 - 9, statfs
.data_stored
);
1750 ASSERT_EQ(0x30000, statfs
.allocated
);
1751 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1752 ASSERT_EQ(0x20000 - 9, statfs
.data_compressed_original
);
1753 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1755 struct store_statfs_t statfs_pool
;
1757 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1759 ASSERT_EQ(0x30005 - 3 - 9, statfs_pool
.data_stored
);
1760 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1761 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1762 ASSERT_EQ(0x20000 - 9, statfs_pool
.data_compressed_original
);
1763 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1766 EXPECT_EQ(store
->umount(), 0);
1767 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1768 EXPECT_EQ(store
->mount(), 0);
1769 ch
= store
->open_collection(cid
);
1772 ObjectStore::Transaction t
;
1773 std::string
s(0x1000, 'b');
1776 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
1777 t
.write(cid
, hoid
, 0x10001, bl
.length(), bl
);
1778 cerr
<< "Overwrite first and second(compressible) extents" << std::endl
;
1779 r
= queue_transaction(store
, ch
, std::move(t
));
1782 struct store_statfs_t statfs
;
1783 int r
= store
->statfs(&statfs
);
1785 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs
.data_stored
);
1786 ASSERT_EQ(0x40000, statfs
.allocated
);
1787 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1788 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs
.data_compressed_original
);
1789 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1791 struct store_statfs_t statfs_pool
;
1793 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1795 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs_pool
.data_stored
);
1796 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1797 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1798 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs_pool
.data_compressed_original
);
1799 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1802 EXPECT_EQ(store
->umount(), 0);
1803 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1804 EXPECT_EQ(store
->mount(), 0);
1805 ch
= store
->open_collection(cid
);
1808 ObjectStore::Transaction t
;
1809 std::string
s(0x10000, 'c');
1812 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1813 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
1814 t
.write(cid
, hoid
, 0x30000, bl
.length(), bl
);
1815 cerr
<< "Overwrite compressed extent with 3 uncompressible ones" << std::endl
;
1816 r
= queue_transaction(store
, ch
, std::move(t
));
1819 struct store_statfs_t statfs
;
1820 int r
= store
->statfs(&statfs
);
1822 ASSERT_EQ(0x30000 + 0x1001, statfs
.data_stored
);
1823 ASSERT_EQ(0x40000, statfs
.allocated
);
1824 ASSERT_LE(statfs
.data_compressed
, 0);
1825 ASSERT_EQ(0, statfs
.data_compressed_original
);
1826 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1828 struct store_statfs_t statfs_pool
;
1830 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1832 ASSERT_EQ(0x30000 + 0x1001, statfs_pool
.data_stored
);
1833 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1834 ASSERT_LE(statfs_pool
.data_compressed
, 0);
1835 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1836 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1839 EXPECT_EQ(store
->umount(), 0);
1840 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1841 EXPECT_EQ(store
->mount(), 0);
1842 ch
= store
->open_collection(cid
);
1845 ObjectStore::Transaction t
;
1846 t
.zero(cid
, hoid
, 0, 0x40000);
1847 cerr
<< "Zero object" << std::endl
;
1848 r
= queue_transaction(store
, ch
, std::move(t
));
1850 struct store_statfs_t statfs
;
1851 int r
= store
->statfs(&statfs
);
1853 ASSERT_EQ(0u, statfs
.allocated
);
1854 ASSERT_EQ(0u, statfs
.data_stored
);
1855 ASSERT_EQ(0u, statfs
.data_compressed_original
);
1856 ASSERT_EQ(0u, statfs
.data_compressed
);
1857 ASSERT_EQ(0u, statfs
.data_compressed_allocated
);
1859 struct store_statfs_t statfs_pool
;
1861 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1863 ASSERT_EQ(0u, statfs_pool
.allocated
);
1864 ASSERT_EQ(0u, statfs_pool
.data_stored
);
1865 ASSERT_EQ(0u, statfs_pool
.data_compressed_original
);
1866 ASSERT_EQ(0u, statfs_pool
.data_compressed
);
1867 ASSERT_EQ(0u, statfs_pool
.data_compressed_allocated
);
1870 EXPECT_EQ(store
->umount(), 0);
1871 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1872 EXPECT_EQ(store
->mount(), 0);
1873 ch
= store
->open_collection(cid
);
1876 ObjectStore::Transaction t
;
1877 std::string
s(0x10000, 'c');
1882 bl
.append(s
.substr(0, 0x10000-2));
1883 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1884 cerr
<< "Yet another compressible write" << std::endl
;
1885 r
= queue_transaction(store
, ch
, std::move(t
));
1887 struct store_statfs_t statfs
;
1888 r
= store
->statfs(&statfs
);
1890 ASSERT_EQ(0x40000 - 2, statfs
.data_stored
);
1891 ASSERT_EQ(0x30000, statfs
.allocated
);
1892 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1893 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1894 ASSERT_EQ(0x10000, statfs
.data_compressed_allocated
);
1896 struct store_statfs_t statfs_pool
;
1898 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1900 ASSERT_EQ(0x40000 - 2, statfs_pool
.data_stored
);
1901 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1902 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1903 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1904 ASSERT_EQ(0x10000, statfs_pool
.data_compressed_allocated
);
1907 EXPECT_EQ(store
->umount(), 0);
1908 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1909 EXPECT_EQ(store
->mount(), 0);
1910 ch
= store
->open_collection(cid
);
1913 struct store_statfs_t statfs
;
1914 r
= store
->statfs(&statfs
);
1917 struct store_statfs_t statfs_pool
;
1919 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1922 ObjectStore::Transaction t
;
1923 t
.clone(cid
, hoid
, hoid2
);
1924 cerr
<< "Clone compressed objecte" << std::endl
;
1925 r
= queue_transaction(store
, ch
, std::move(t
));
1927 struct store_statfs_t statfs2
;
1928 r
= store
->statfs(&statfs2
);
1930 ASSERT_GT(statfs2
.data_stored
, statfs
.data_stored
);
1931 ASSERT_EQ(statfs2
.allocated
, statfs
.allocated
);
1932 ASSERT_GT(statfs2
.data_compressed
, statfs
.data_compressed
);
1933 ASSERT_GT(statfs2
.data_compressed_original
, statfs
.data_compressed_original
);
1934 ASSERT_EQ(statfs2
.data_compressed_allocated
, statfs
.data_compressed_allocated
);
1936 struct store_statfs_t statfs2_pool
;
1937 r
= store
->pool_statfs(poolid
, &statfs2_pool
, &per_pool_omap
);
1939 ASSERT_GT(statfs2_pool
.data_stored
, statfs_pool
.data_stored
);
1940 ASSERT_EQ(statfs2_pool
.allocated
, statfs_pool
.allocated
);
1941 ASSERT_GT(statfs2_pool
.data_compressed
, statfs_pool
.data_compressed
);
1942 ASSERT_GT(statfs2_pool
.data_compressed_original
,
1943 statfs_pool
.data_compressed_original
);
1944 ASSERT_EQ(statfs2_pool
.data_compressed_allocated
,
1945 statfs_pool
.data_compressed_allocated
);
1950 auto poolid2
= poolid
+ 1;
1951 coll_t cid2
= coll_t(spg_t(pg_t(20, poolid2
), shard_id_t::NO_SHARD
));
1952 ghobject_t
hoid(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
1957 auto ch
= store
->create_new_collection(cid2
);
1961 struct store_statfs_t statfs1_pool
;
1963 int r
= store
->pool_statfs(poolid
, &statfs1_pool
, &per_pool_omap
);
1966 cerr
<< "Creating second collection " << cid2
<< std::endl
;
1967 ObjectStore::Transaction t
;
1968 t
.create_collection(cid2
, 0);
1969 r
= queue_transaction(store
, ch
, std::move(t
));
1972 t
= ObjectStore::Transaction();
1975 t
.write(cid2
, hoid
, 0, 5, bl
);
1976 r
= queue_transaction(store
, ch
, std::move(t
));
1979 struct store_statfs_t statfs2_pool
;
1980 r
= store
->pool_statfs(poolid2
, &statfs2_pool
, &per_pool_omap
);
1982 ASSERT_EQ(5, statfs2_pool
.data_stored
);
1983 ASSERT_EQ(0x10000, statfs2_pool
.allocated
);
1984 ASSERT_EQ(0, statfs2_pool
.data_compressed
);
1985 ASSERT_EQ(0, statfs2_pool
.data_compressed_original
);
1986 ASSERT_EQ(0, statfs2_pool
.data_compressed_allocated
);
1988 struct store_statfs_t statfs1_pool_again
;
1989 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
, &per_pool_omap
);
1991 // adjust 'available' since it has changed
1992 statfs1_pool_again
.available
= statfs1_pool
.available
;
1993 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
1995 t
= ObjectStore::Transaction();
1996 t
.remove(cid2
, hoid
);
1997 t
.remove_collection(cid2
);
1998 cerr
<< "Cleaning" << std::endl
;
1999 r
= queue_transaction(store
, ch
, std::move(t
));
2005 // verify ops on temporary object
2007 auto poolid3
= poolid
+ 2;
2008 coll_t cid3
= coll_t(spg_t(pg_t(20, poolid3
), shard_id_t::NO_SHARD
));
2009 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
),
2014 ghobject_t hoid3_temp
;
2015 hoid3_temp
.hobj
= hoid3
.hobj
.make_temp_hobject("Object 3 temp");
2016 auto ch3
= store
->create_new_collection(cid3
);
2018 struct store_statfs_t statfs1_pool
;
2020 int r
= store
->pool_statfs(poolid
, &statfs1_pool
, &per_pool_omap
);
2023 cerr
<< "Creating third collection " << cid3
<< std::endl
;
2024 ObjectStore::Transaction t
;
2025 t
.create_collection(cid3
, 0);
2026 r
= queue_transaction(store
, ch3
, std::move(t
));
2029 t
= ObjectStore::Transaction();
2032 t
.write(cid3
, hoid3_temp
, 0, 5, bl
);
2033 r
= queue_transaction(store
, ch3
, std::move(t
));
2036 struct store_statfs_t statfs3_pool
;
2037 r
= store
->pool_statfs(poolid3
, &statfs3_pool
, &per_pool_omap
);
2039 ASSERT_EQ(5, statfs3_pool
.data_stored
);
2040 ASSERT_EQ(0x10000, statfs3_pool
.allocated
);
2041 ASSERT_EQ(0, statfs3_pool
.data_compressed
);
2042 ASSERT_EQ(0, statfs3_pool
.data_compressed_original
);
2043 ASSERT_EQ(0, statfs3_pool
.data_compressed_allocated
);
2045 struct store_statfs_t statfs1_pool_again
;
2046 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
, &per_pool_omap
);
2048 // adjust 'available' since it has changed
2049 statfs1_pool_again
.available
= statfs1_pool
.available
;
2050 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
2055 EXPECT_EQ(store
->umount(), 0);
2056 EXPECT_EQ(store
->mount(), 0);
2057 ch
= store
->open_collection(cid
);
2058 ch3
= store
->open_collection(cid3
);
2060 t
= ObjectStore::Transaction();
2061 t
.collection_move_rename(
2064 r
= queue_transaction(store
, ch3
, std::move(t
));
2067 struct store_statfs_t statfs3_pool_again
;
2068 r
= store
->pool_statfs(poolid3
, &statfs3_pool_again
, &per_pool_omap
);
2070 ASSERT_EQ(statfs3_pool_again
, statfs3_pool
);
2075 EXPECT_EQ(store
->umount(), 0);
2076 EXPECT_EQ(store
->mount(), 0);
2077 ch
= store
->open_collection(cid
);
2078 ch3
= store
->open_collection(cid3
);
2080 t
= ObjectStore::Transaction();
2081 t
.remove(cid3
, hoid3
);
2082 t
.remove_collection(cid3
);
2083 cerr
<< "Cleaning" << std::endl
;
2084 r
= queue_transaction(store
, ch3
, std::move(t
));
2090 ObjectStore::Transaction t
;
2091 t
.remove(cid
, hoid
);
2092 t
.remove(cid
, hoid2
);
2093 t
.remove_collection(cid
);
2094 cerr
<< "Cleaning" << std::endl
;
2095 r
= queue_transaction(store
, ch
, std::move(t
));
2098 struct store_statfs_t statfs
;
2099 r
= store
->statfs(&statfs
);
2101 ASSERT_EQ( 0u, statfs
.allocated
);
2102 ASSERT_EQ( 0u, statfs
.data_stored
);
2103 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
2104 ASSERT_EQ( 0u, statfs
.data_compressed
);
2105 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
2107 struct store_statfs_t statfs_pool
;
2109 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
2111 ASSERT_EQ( 0u, statfs_pool
.allocated
);
2112 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
2113 ASSERT_EQ( 0u, statfs_pool
.data_compressed_original
);
2114 ASSERT_EQ( 0u, statfs_pool
.data_compressed
);
2115 ASSERT_EQ( 0u, statfs_pool
.data_compressed_allocated
);
2119 TEST_P(StoreTestSpecificAUSize
, BluestoreFragmentedBlobTest
) {
2120 if(string(GetParam()) != "bluestore")
2123 cout
<< "TODO: fix this for smr" << std::endl
;
2126 SetVal(g_conf(), "bluestore_block_db_path", "");
2127 StartDeferred(0x10000);
2131 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2132 auto ch
= store
->create_new_collection(cid
);
2134 ObjectStore::Transaction t
;
2135 t
.create_collection(cid
, 0);
2136 cerr
<< "Creating collection " << cid
<< std::endl
;
2137 r
= queue_transaction(store
, ch
, std::move(t
));
2141 bool exists
= store
->exists(ch
, hoid
);
2142 ASSERT_TRUE(!exists
);
2144 ObjectStore::Transaction t
;
2146 cerr
<< "Creating object " << hoid
<< std::endl
;
2147 r
= queue_transaction(store
, ch
, std::move(t
));
2150 exists
= store
->exists(ch
, hoid
);
2151 ASSERT_EQ(true, exists
);
2154 struct store_statfs_t statfs
;
2155 int r
= store
->statfs(&statfs
);
2157 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
2158 ASSERT_EQ(0u, statfs
.allocated
);
2159 ASSERT_EQ(0u, statfs
.data_stored
);
2160 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
2163 data
.resize(0x10000 * 3);
2165 ObjectStore::Transaction t
;
2166 for(size_t i
= 0;i
< data
.size(); i
++)
2167 data
[i
] = i
/ 256 + 1;
2168 bufferlist bl
, newdata
;
2170 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
2171 t
.zero(cid
, hoid
, 0x10000, 0x10000);
2172 cerr
<< "Append 3*0x10000 bytes and punch a hole 0x10000~10000" << std::endl
;
2173 r
= queue_transaction(store
, ch
, std::move(t
));
2176 struct store_statfs_t statfs
;
2177 int r
= store
->statfs(&statfs
);
2179 ASSERT_EQ(0x20000, statfs
.data_stored
);
2180 ASSERT_EQ(0x20000, statfs
.allocated
);
2182 r
= store
->read(ch
, hoid
, 0, data
.size(), newdata
);
2183 ASSERT_EQ(r
, (int)data
.size());
2185 bufferlist expected
;
2186 expected
.append(data
.substr(0, 0x10000));
2187 expected
.append(string(0x10000, 0));
2188 expected
.append(data
.substr(0x20000, 0x10000));
2189 ASSERT_TRUE(bl_eq(expected
, newdata
));
2193 r
= store
->read(ch
, hoid
, 1, data
.size()-2, newdata
);
2194 ASSERT_EQ(r
, (int)data
.size()-2);
2196 bufferlist expected
;
2197 expected
.append(data
.substr(1, 0x10000-1));
2198 expected
.append(string(0x10000, 0));
2199 expected
.append(data
.substr(0x20000, 0x10000 - 1));
2200 ASSERT_TRUE(bl_eq(expected
, newdata
));
2206 EXPECT_EQ(store
->umount(), 0);
2207 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2208 EXPECT_EQ(store
->mount(), 0);
2209 ch
= store
->open_collection(cid
);
2212 ObjectStore::Transaction t
;
2213 std::string
data2(3, 'b');
2214 bufferlist bl
, newdata
;
2216 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
2217 cerr
<< "Write 3 bytes after the hole" << std::endl
;
2218 r
= queue_transaction(store
, ch
, std::move(t
));
2221 struct store_statfs_t statfs
;
2222 int r
= store
->statfs(&statfs
);
2224 ASSERT_EQ(0x20000, statfs
.allocated
);
2225 ASSERT_EQ(0x20000, statfs
.data_stored
);
2227 r
= store
->read(ch
, hoid
, 0x20000-1, 21, newdata
);
2228 ASSERT_EQ(r
, (int)21);
2230 bufferlist expected
;
2231 expected
.append(string(0x1, 0));
2232 expected
.append(string(data2
));
2233 expected
.append(data
.substr(0x20003, 21-4));
2234 ASSERT_TRUE(bl_eq(expected
, newdata
));
2240 EXPECT_EQ(store
->umount(), 0);
2241 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2242 EXPECT_EQ(store
->mount(), 0);
2243 ch
= store
->open_collection(cid
);
2246 ObjectStore::Transaction t
;
2247 std::string
data2(3, 'a');
2248 bufferlist bl
, newdata
;
2250 t
.write(cid
, hoid
, 0x10000+1, bl
.length(), bl
);
2251 cerr
<< "Write 3 bytes to the hole" << std::endl
;
2252 r
= queue_transaction(store
, ch
, std::move(t
));
2255 struct store_statfs_t statfs
;
2256 int r
= store
->statfs(&statfs
);
2258 ASSERT_EQ(0x30000, statfs
.allocated
);
2259 ASSERT_EQ(0x20003, statfs
.data_stored
);
2261 r
= store
->read(ch
, hoid
, 0x10000-1, 0x10000+22, newdata
);
2262 ASSERT_EQ(r
, (int)0x10000+22);
2264 bufferlist expected
;
2265 expected
.append(data
.substr(0x10000-1, 1));
2266 expected
.append(string(0x1, 0));
2267 expected
.append(data2
);
2268 expected
.append(string(0x10000-4, 0));
2269 expected
.append(string(0x3, 'b'));
2270 expected
.append(data
.substr(0x20004, 21-3));
2271 ASSERT_TRUE(bl_eq(expected
, newdata
));
2276 ObjectStore::Transaction t
;
2277 bufferlist bl
, newdata
;
2278 bl
.append(string(0x30000, 'c'));
2279 t
.write(cid
, hoid
, 0, 0x30000, bl
);
2280 t
.zero(cid
, hoid
, 0, 0x10000);
2281 t
.zero(cid
, hoid
, 0x20000, 0x10000);
2282 cerr
<< "Rewrite an object and create two holes at the beginning and the end" << std::endl
;
2283 r
= queue_transaction(store
, ch
, std::move(t
));
2286 struct store_statfs_t statfs
;
2287 int r
= store
->statfs(&statfs
);
2289 ASSERT_EQ(0x10000, statfs
.allocated
);
2290 ASSERT_EQ(0x10000, statfs
.data_stored
);
2292 r
= store
->read(ch
, hoid
, 0, 0x30000, newdata
);
2293 ASSERT_EQ(r
, (int)0x30000);
2295 bufferlist expected
;
2296 expected
.append(string(0x10000, 0));
2297 expected
.append(string(0x10000, 'c'));
2298 expected
.append(string(0x10000, 0));
2299 ASSERT_TRUE(bl_eq(expected
, newdata
));
2306 EXPECT_EQ(store
->umount(), 0);
2307 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2308 EXPECT_EQ(store
->mount(), 0);
2309 ch
= store
->open_collection(cid
);
2312 ObjectStore::Transaction t
;
2313 t
.remove(cid
, hoid
);
2314 t
.remove_collection(cid
);
2315 cerr
<< "Cleaning" << std::endl
;
2316 r
= queue_transaction(store
, ch
, std::move(t
));
2319 struct store_statfs_t statfs
;
2320 r
= store
->statfs(&statfs
);
2322 ASSERT_EQ( 0u, statfs
.allocated
);
2323 ASSERT_EQ( 0u, statfs
.data_stored
);
2324 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
2325 ASSERT_EQ( 0u, statfs
.data_compressed
);
2326 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
2331 TEST_P(StoreTest
, ManySmallWrite
) {
2334 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2335 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2336 auto ch
= store
->create_new_collection(cid
);
2338 ObjectStore::Transaction t
;
2339 t
.create_collection(cid
, 0);
2340 cerr
<< "Creating collection " << cid
<< std::endl
;
2341 r
= queue_transaction(store
, ch
, std::move(t
));
2348 for (int i
=0; i
<100; ++i
) {
2349 ObjectStore::Transaction t
;
2350 t
.write(cid
, a
, i
*4096, 4096, bl
, 0);
2351 r
= queue_transaction(store
, ch
, std::move(t
));
2354 for (int i
=0; i
<100; ++i
) {
2355 ObjectStore::Transaction t
;
2356 t
.write(cid
, b
, (rand() % 1024)*4096, 4096, bl
, 0);
2357 r
= queue_transaction(store
, ch
, std::move(t
));
2361 ObjectStore::Transaction t
;
2364 t
.remove_collection(cid
);
2365 cerr
<< "Cleaning" << std::endl
;
2366 r
= queue_transaction(store
, ch
, std::move(t
));
2371 TEST_P(StoreTest
, MultiSmallWriteSameBlock
) {
2374 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2375 auto ch
= store
->create_new_collection(cid
);
2377 ObjectStore::Transaction t
;
2378 t
.create_collection(cid
, 0);
2379 cerr
<< "Creating collection " << cid
<< std::endl
;
2380 r
= queue_transaction(store
, ch
, std::move(t
));
2386 // touch same block in both same transaction, tls, and pipelined txns
2388 ObjectStore::Transaction t
, u
;
2389 t
.write(cid
, a
, 0, 5, bl
, 0);
2390 t
.write(cid
, a
, 5, 5, bl
, 0);
2391 t
.write(cid
, a
, 4094, 5, bl
, 0);
2392 t
.write(cid
, a
, 9000, 5, bl
, 0);
2393 u
.write(cid
, a
, 10, 5, bl
, 0);
2394 u
.write(cid
, a
, 7000, 5, bl
, 0);
2395 t
.register_on_commit(&c
);
2396 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2397 store
->queue_transactions(ch
, v
);
2400 ObjectStore::Transaction t
, u
;
2401 t
.write(cid
, a
, 40, 5, bl
, 0);
2402 t
.write(cid
, a
, 45, 5, bl
, 0);
2403 t
.write(cid
, a
, 4094, 5, bl
, 0);
2404 t
.write(cid
, a
, 6000, 5, bl
, 0);
2405 u
.write(cid
, a
, 610, 5, bl
, 0);
2406 u
.write(cid
, a
, 11000, 5, bl
, 0);
2407 t
.register_on_commit(&d
);
2408 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2409 store
->queue_transactions(ch
, v
);
2415 r
= store
->read(ch
, a
, 0, 16000, bl2
);
2419 ObjectStore::Transaction t
;
2421 t
.remove_collection(cid
);
2422 cerr
<< "Cleaning" << std::endl
;
2423 r
= queue_transaction(store
, ch
, std::move(t
));
2428 TEST_P(StoreTest
, SmallSkipFront
) {
2431 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2432 auto ch
= store
->create_new_collection(cid
);
2434 ObjectStore::Transaction t
;
2435 t
.create_collection(cid
, 0);
2436 cerr
<< "Creating collection " << cid
<< std::endl
;
2437 r
= queue_transaction(store
, ch
, std::move(t
));
2441 ObjectStore::Transaction t
;
2443 t
.truncate(cid
, a
, 3000);
2444 r
= queue_transaction(store
, ch
, std::move(t
));
2450 memset(bp
.c_str(), 1, 4096);
2452 ObjectStore::Transaction t
;
2453 t
.write(cid
, a
, 4096, 4096, bl
);
2454 r
= queue_transaction(store
, ch
, std::move(t
));
2459 ASSERT_EQ(8192, store
->read(ch
, a
, 0, 8192, bl
));
2460 for (unsigned i
=0; i
<4096; ++i
)
2461 ASSERT_EQ(0, bl
[i
]);
2462 for (unsigned i
=4096; i
<8192; ++i
)
2463 ASSERT_EQ(1, bl
[i
]);
2466 ObjectStore::Transaction t
;
2468 t
.remove_collection(cid
);
2469 cerr
<< "Cleaning" << std::endl
;
2470 r
= queue_transaction(store
, ch
, std::move(t
));
2475 TEST_P(StoreTest
, AppendDeferredVsTailCache
) {
2478 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2479 auto ch
= store
->create_new_collection(cid
);
2481 ObjectStore::Transaction t
;
2482 t
.create_collection(cid
, 0);
2483 cerr
<< "Creating collection " << cid
<< std::endl
;
2484 r
= store
->queue_transaction(ch
, std::move(t
));
2487 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2488 unsigned size
= min_alloc
/ 3;
2489 bufferptr
bpa(size
);
2490 memset(bpa
.c_str(), 1, bpa
.length());
2494 ObjectStore::Transaction t
;
2495 t
.write(cid
, a
, 0, bla
.length(), bla
, 0);
2496 r
= store
->queue_transaction(ch
, std::move(t
));
2500 // force cached tail to clear ...
2503 int r
= store
->umount();
2507 ch
= store
->open_collection(cid
);
2510 bufferptr
bpb(size
);
2511 memset(bpb
.c_str(), 2, bpb
.length());
2515 ObjectStore::Transaction t
;
2516 t
.write(cid
, a
, bla
.length(), blb
.length(), blb
, 0);
2517 r
= store
->queue_transaction(ch
, std::move(t
));
2520 bufferptr
bpc(size
);
2521 memset(bpc
.c_str(), 3, bpc
.length());
2525 ObjectStore::Transaction t
;
2526 t
.write(cid
, a
, bla
.length() + blb
.length(), blc
.length(), blc
, 0);
2527 r
= store
->queue_transaction(ch
, std::move(t
));
2536 ASSERT_EQ((int)final
.length(),
2537 store
->read(ch
, a
, 0, final
.length(), actual
));
2538 ASSERT_TRUE(bl_eq(final
, actual
));
2541 ObjectStore::Transaction t
;
2543 t
.remove_collection(cid
);
2544 cerr
<< "Cleaning" << std::endl
;
2545 r
= store
->queue_transaction(ch
, std::move(t
));
2550 TEST_P(StoreTest
, AppendZeroTrailingSharedBlock
) {
2553 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2556 auto ch
= store
->create_new_collection(cid
);
2558 ObjectStore::Transaction t
;
2559 t
.create_collection(cid
, 0);
2560 cerr
<< "Creating collection " << cid
<< std::endl
;
2561 r
= store
->queue_transaction(ch
, std::move(t
));
2564 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2565 unsigned size
= min_alloc
/ 3;
2566 bufferptr
bpa(size
);
2567 memset(bpa
.c_str(), 1, bpa
.length());
2570 // make sure there is some trailing gunk in the last block
2574 bt
.append("BADBADBADBAD");
2575 ObjectStore::Transaction t
;
2576 t
.write(cid
, a
, 0, bt
.length(), bt
, 0);
2577 r
= store
->queue_transaction(ch
, std::move(t
));
2581 ObjectStore::Transaction t
;
2582 t
.truncate(cid
, a
, size
);
2583 r
= store
->queue_transaction(ch
, std::move(t
));
2589 ObjectStore::Transaction t
;
2591 r
= store
->queue_transaction(ch
, std::move(t
));
2595 // append with implicit zeroing
2596 bufferptr
bpb(size
);
2597 memset(bpb
.c_str(), 2, bpb
.length());
2601 ObjectStore::Transaction t
;
2602 t
.write(cid
, a
, min_alloc
* 3, blb
.length(), blb
, 0);
2603 r
= store
->queue_transaction(ch
, std::move(t
));
2609 zeros
.append_zero(min_alloc
* 3 - size
);
2610 final
.append(zeros
);
2614 ASSERT_EQ((int)final
.length(),
2615 store
->read(ch
, a
, 0, final
.length(), actual
));
2616 final
.hexdump(cout
);
2617 actual
.hexdump(cout
);
2618 ASSERT_TRUE(bl_eq(final
, actual
));
2621 ObjectStore::Transaction t
;
2624 t
.remove_collection(cid
);
2625 cerr
<< "Cleaning" << std::endl
;
2626 r
= store
->queue_transaction(ch
, std::move(t
));
2631 TEST_P(StoreTest
, SmallSequentialUnaligned
) {
2634 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2635 auto ch
= store
->create_new_collection(cid
);
2637 ObjectStore::Transaction t
;
2638 t
.create_collection(cid
, 0);
2639 cerr
<< "Creating collection " << cid
<< std::endl
;
2640 r
= queue_transaction(store
, ch
, std::move(t
));
2648 for (int i
=0; i
<1000; ++i
) {
2649 ObjectStore::Transaction t
;
2650 t
.write(cid
, a
, i
*len
, len
, bl
, 0);
2651 r
= queue_transaction(store
, ch
, std::move(t
));
2655 ObjectStore::Transaction t
;
2657 t
.remove_collection(cid
);
2658 cerr
<< "Cleaning" << std::endl
;
2659 r
= queue_transaction(store
, ch
, std::move(t
));
2664 TEST_P(StoreTest
, ManyBigWrite
) {
2667 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2668 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2669 auto ch
= store
->create_new_collection(cid
);
2671 ObjectStore::Transaction t
;
2672 t
.create_collection(cid
, 0);
2673 cerr
<< "Creating collection " << cid
<< std::endl
;
2674 r
= queue_transaction(store
, ch
, std::move(t
));
2678 bufferptr
bp(4 * 1048576);
2681 for (int i
=0; i
<10; ++i
) {
2682 ObjectStore::Transaction t
;
2683 t
.write(cid
, a
, i
*4*1048586, 4*1048576, bl
, 0);
2684 r
= queue_transaction(store
, ch
, std::move(t
));
2688 for (int i
=0; i
<10; ++i
) {
2689 ObjectStore::Transaction t
;
2690 t
.write(cid
, b
, (rand() % 256)*4*1048576, 4*1048576, bl
, 0);
2691 r
= queue_transaction(store
, ch
, std::move(t
));
2695 for (int i
=0; i
<10; ++i
) {
2696 ObjectStore::Transaction t
;
2697 t
.write(cid
, b
, (rand() % (256*4096))*1024, 4*1048576, bl
, 0);
2698 r
= queue_transaction(store
, ch
, std::move(t
));
2702 for (int i
=0; i
<10; ++i
) {
2703 ObjectStore::Transaction t
;
2704 t
.zero(cid
, b
, (rand() % (256*4096))*1024, 16*1048576);
2705 r
= queue_transaction(store
, ch
, std::move(t
));
2709 ObjectStore::Transaction t
;
2712 t
.remove_collection(cid
);
2713 cerr
<< "Cleaning" << std::endl
;
2714 r
= queue_transaction(store
, ch
, std::move(t
));
2719 TEST_P(StoreTest
, BigWriteBigZero
) {
2722 ghobject_t
a(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2723 auto ch
= store
->create_new_collection(cid
);
2725 ObjectStore::Transaction t
;
2726 t
.create_collection(cid
, 0);
2727 r
= queue_transaction(store
, ch
, std::move(t
));
2731 bufferptr
bp(1048576);
2732 memset(bp
.c_str(), 'b', bp
.length());
2736 memset(sp
.c_str(), 's', sp
.length());
2739 ObjectStore::Transaction t
;
2740 t
.write(cid
, a
, 0, bl
.length(), bl
);
2741 r
= queue_transaction(store
, ch
, std::move(t
));
2745 ObjectStore::Transaction t
;
2746 t
.zero(cid
, a
, bl
.length() / 4, bl
.length() / 2);
2747 r
= queue_transaction(store
, ch
, std::move(t
));
2751 ObjectStore::Transaction t
;
2752 t
.write(cid
, a
, bl
.length() / 2, s
.length(), s
);
2753 r
= queue_transaction(store
, ch
, std::move(t
));
2757 ObjectStore::Transaction t
;
2759 t
.remove_collection(cid
);
2760 r
= queue_transaction(store
, ch
, std::move(t
));
2765 TEST_P(StoreTest
, MiscFragmentTests
) {
2768 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2769 auto ch
= store
->create_new_collection(cid
);
2771 ObjectStore::Transaction t
;
2772 t
.create_collection(cid
, 0);
2773 cerr
<< "Creating collection " << cid
<< std::endl
;
2774 r
= queue_transaction(store
, ch
, std::move(t
));
2778 bufferptr
bp(524288);
2782 ObjectStore::Transaction t
;
2783 t
.write(cid
, a
, 0, 524288, bl
, 0);
2784 r
= queue_transaction(store
, ch
, std::move(t
));
2788 ObjectStore::Transaction t
;
2789 t
.write(cid
, a
, 1048576, 524288, bl
, 0);
2790 r
= queue_transaction(store
, ch
, std::move(t
));
2795 int r
= store
->read(ch
, a
, 524288 + 131072, 1024, inbl
);
2797 ASSERT_EQ(inbl
.length(), 1024u);
2798 ASSERT_TRUE(inbl
.is_zero());
2801 ObjectStore::Transaction t
;
2802 t
.write(cid
, a
, 1048576 - 4096, 524288, bl
, 0);
2803 r
= queue_transaction(store
, ch
, std::move(t
));
2807 ObjectStore::Transaction t
;
2809 t
.remove_collection(cid
);
2810 cerr
<< "Cleaning" << std::endl
;
2811 r
= queue_transaction(store
, ch
, std::move(t
));
2817 TEST_P(StoreTest
, ZeroVsObjectSize
) {
2821 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2822 auto ch
= store
->create_new_collection(cid
);
2824 ObjectStore::Transaction t
;
2825 t
.create_collection(cid
, 0);
2826 cerr
<< "Creating collection " << cid
<< std::endl
;
2827 r
= queue_transaction(store
, ch
, std::move(t
));
2833 ObjectStore::Transaction t
;
2834 t
.write(cid
, hoid
, 0, 5, a
);
2835 r
= queue_transaction(store
, ch
, std::move(t
));
2838 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2839 ASSERT_EQ(5, stat
.st_size
);
2841 ObjectStore::Transaction t
;
2842 t
.zero(cid
, hoid
, 1, 2);
2843 r
= queue_transaction(store
, ch
, std::move(t
));
2846 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2847 ASSERT_EQ(5, stat
.st_size
);
2849 ObjectStore::Transaction t
;
2850 t
.zero(cid
, hoid
, 3, 200);
2851 r
= queue_transaction(store
, ch
, std::move(t
));
2854 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2855 ASSERT_EQ(203, stat
.st_size
);
2857 ObjectStore::Transaction t
;
2858 t
.zero(cid
, hoid
, 100000, 200);
2859 r
= queue_transaction(store
, ch
, std::move(t
));
2862 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2863 ASSERT_EQ(100200, stat
.st_size
);
2866 TEST_P(StoreTest
, ZeroLengthWrite
) {
2869 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2870 auto ch
= store
->create_new_collection(cid
);
2872 ObjectStore::Transaction t
;
2873 t
.create_collection(cid
, 0);
2875 r
= queue_transaction(store
, ch
, std::move(t
));
2879 ObjectStore::Transaction t
;
2881 t
.write(cid
, hoid
, 1048576, 0, empty
);
2882 r
= queue_transaction(store
, ch
, std::move(t
));
2886 r
= store
->stat(ch
, hoid
, &stat
);
2888 ASSERT_EQ(0, stat
.st_size
);
2891 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2895 TEST_P(StoreTest
, ZeroLengthZero
) {
2898 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2899 auto ch
= store
->create_new_collection(cid
);
2901 ObjectStore::Transaction t
;
2902 t
.create_collection(cid
, 0);
2904 r
= queue_transaction(store
, ch
, std::move(t
));
2908 ObjectStore::Transaction t
;
2909 t
.zero(cid
, hoid
, 1048576, 0);
2910 r
= queue_transaction(store
, ch
, std::move(t
));
2914 r
= store
->stat(ch
, hoid
, &stat
);
2916 ASSERT_EQ(0, stat
.st_size
);
2919 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2923 TEST_P(StoreTest
, SimpleAttrTest
) {
2926 ghobject_t
hoid(hobject_t(sobject_t("attr object 1", CEPH_NOSNAP
)));
2927 bufferlist val
, val2
;
2928 val
.append("value");
2929 val
.append("value2");
2931 auto ch
= store
->open_collection(cid
);
2934 auto ch
= store
->create_new_collection(cid
);
2936 ObjectStore::Transaction t
;
2937 t
.create_collection(cid
, 0);
2938 r
= queue_transaction(store
, ch
, std::move(t
));
2943 int r
= store
->collection_empty(ch
, &empty
);
2949 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2950 ASSERT_EQ(-ENOENT
, r
);
2953 ObjectStore::Transaction t
;
2955 t
.setattr(cid
, hoid
, "foo", val
);
2956 t
.setattr(cid
, hoid
, "bar", val2
);
2957 r
= queue_transaction(store
, ch
, std::move(t
));
2962 int r
= store
->collection_empty(ch
, &empty
);
2964 ASSERT_TRUE(!empty
);
2968 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2969 ASSERT_EQ(-ENODATA
, r
);
2971 r
= store
->getattr(ch
, hoid
, "foo", bp
);
2975 ASSERT_TRUE(bl_eq(val
, bl
));
2977 map
<string
,bufferptr
,less
<>> bm
;
2978 r
= store
->getattrs(ch
, hoid
, bm
);
2983 ObjectStore::Transaction t
;
2984 t
.remove(cid
, hoid
);
2985 t
.remove_collection(cid
);
2986 r
= queue_transaction(store
, ch
, std::move(t
));
2991 TEST_P(StoreTest
, SimpleListTest
) {
2993 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2994 auto ch
= store
->create_new_collection(cid
);
2996 ObjectStore::Transaction t
;
2997 t
.create_collection(cid
, 0);
2998 cerr
<< "Creating collection " << cid
<< std::endl
;
2999 r
= queue_transaction(store
, ch
, std::move(t
));
3002 set
<ghobject_t
> all
;
3004 ObjectStore::Transaction t
;
3005 for (int i
=0; i
<200; ++i
) {
3006 string
name("object_");
3007 name
+= stringify(i
);
3008 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
3009 ghobject_t::NO_GEN
, shard_id_t(1));
3013 cerr
<< "Creating object " << hoid
<< std::endl
;
3015 r
= queue_transaction(store
, ch
, std::move(t
));
3019 set
<ghobject_t
> saw
;
3020 vector
<ghobject_t
> objects
;
3021 ghobject_t next
, current
;
3022 while (!next
.is_max()) {
3023 int r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 50,
3026 ASSERT_TRUE(sorted(objects
));
3027 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
3028 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
3030 if (saw
.count(*p
)) {
3031 cout
<< "got DUP " << *p
<< std::endl
;
3033 //cout << "got new " << *p << std::endl;
3040 ASSERT_EQ(saw
.size(), all
.size());
3041 ASSERT_EQ(saw
, all
);
3044 ObjectStore::Transaction t
;
3045 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
3047 t
.remove_collection(cid
);
3048 cerr
<< "Cleaning" << std::endl
;
3049 r
= queue_transaction(store
, ch
, std::move(t
));
3054 TEST_P(StoreTest
, ListEndTest
) {
3056 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
3057 auto ch
= store
->create_new_collection(cid
);
3059 ObjectStore::Transaction t
;
3060 t
.create_collection(cid
, 0);
3061 cerr
<< "Creating collection " << cid
<< std::endl
;
3062 r
= queue_transaction(store
, ch
, std::move(t
));
3065 set
<ghobject_t
> all
;
3067 ObjectStore::Transaction t
;
3068 for (int i
=0; i
<200; ++i
) {
3069 string
name("object_");
3070 name
+= stringify(i
);
3071 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
3072 ghobject_t::NO_GEN
, shard_id_t(1));
3076 cerr
<< "Creating object " << hoid
<< std::endl
;
3078 r
= queue_transaction(store
, ch
, std::move(t
));
3082 ghobject_t
end(hobject_t(sobject_t("object_100", CEPH_NOSNAP
)),
3083 ghobject_t::NO_GEN
, shard_id_t(1));
3085 vector
<ghobject_t
> objects
;
3087 int r
= collection_list(store
, ch
, ghobject_t(), end
, 500, &objects
, &next
);
3089 for (auto &p
: objects
) {
3094 ObjectStore::Transaction t
;
3095 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
3097 t
.remove_collection(cid
);
3098 cerr
<< "Cleaning" << std::endl
;
3099 r
= queue_transaction(store
, ch
, std::move(t
));
3104 TEST_P(StoreTest
, List_0xfffffff_Hash_Test_in_meta
) {
3107 auto ch
= store
->create_new_collection(cid
);
3109 ObjectStore::Transaction t
;
3110 t
.create_collection(cid
, 0);
3111 r
= queue_transaction(store
, ch
, std::move(t
));
3115 ObjectStore::Transaction t
;
3116 ghobject_t
hoid(hobject_t(sobject_t("obj", CEPH_NOSNAP
),
3117 "", UINT32_C(0xffffffff), -1, "nspace"));
3119 r
= queue_transaction(store
, ch
, std::move(t
));
3123 vector
<ghobject_t
> objects
;
3124 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
3125 &objects
, nullptr, true);
3127 ASSERT_EQ(objects
.size(), 1);
3131 TEST_P(StoreTest
, List_0xfffffff_Hash_Test_in_PG
) {
3133 const int64_t poolid
= 1;
3134 coll_t
cid(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
3135 auto ch
= store
->create_new_collection(cid
);
3137 ObjectStore::Transaction t
;
3138 t
.create_collection(cid
, 0);
3139 r
= queue_transaction(store
, ch
, std::move(t
));
3143 ObjectStore::Transaction t
;
3144 ghobject_t
hoid(hobject_t(sobject_t("obj", CEPH_NOSNAP
),
3145 "", UINT32_C(0xffffffff), poolid
, "nspace"));
3147 r
= queue_transaction(store
, ch
, std::move(t
));
3151 vector
<ghobject_t
> objects
;
3152 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
3153 &objects
, nullptr, true);
3155 ASSERT_EQ(objects
.size(), 1);
3159 TEST_P(StoreTest
, Sort
) {
3161 hobject_t
a(sobject_t("a", CEPH_NOSNAP
));
3174 ghobject_t
a(hobject_t(sobject_t("a", CEPH_NOSNAP
)));
3175 ghobject_t
b(hobject_t(sobject_t("b", CEPH_NOSNAP
)));
3187 TEST_P(StoreTest
, MultipoolListTest
) {
3190 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
3191 auto ch
= store
->create_new_collection(cid
);
3193 ObjectStore::Transaction t
;
3194 t
.create_collection(cid
, 0);
3195 cerr
<< "Creating collection " << cid
<< std::endl
;
3196 r
= queue_transaction(store
, ch
, std::move(t
));
3199 set
<ghobject_t
> all
, saw
;
3201 ObjectStore::Transaction t
;
3202 for (int i
=0; i
<200; ++i
) {
3203 string
name("object_");
3204 name
+= stringify(i
);
3205 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)));
3207 hoid
.hobj
.pool
= -2 - poolid
;
3209 hoid
.hobj
.pool
= poolid
;
3212 cerr
<< "Creating object " << hoid
<< std::endl
;
3214 r
= queue_transaction(store
, ch
, std::move(t
));
3218 vector
<ghobject_t
> objects
;
3219 ghobject_t next
, current
;
3220 while (!next
.is_max()) {
3221 int r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 50,
3224 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
3225 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
3232 ASSERT_EQ(saw
, all
);
3235 ObjectStore::Transaction t
;
3236 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
3238 t
.remove_collection(cid
);
3239 cerr
<< "Cleaning" << std::endl
;
3240 r
= queue_transaction(store
, ch
, std::move(t
));
3245 TEST_P(StoreTest
, SimpleCloneTest
) {
3249 SetDeathTestStyle("threadsafe");
3251 auto ch
= store
->create_new_collection(cid
);
3253 ObjectStore::Transaction t
;
3254 t
.create_collection(cid
, 0);
3255 cerr
<< "Creating collection " << cid
<< std::endl
;
3256 r
= queue_transaction(store
, ch
, std::move(t
));
3259 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
3260 "key", 123, -1, ""));
3261 bufferlist small
, large
, xlarge
, newdata
, attr
;
3262 small
.append("small");
3263 large
.append("large");
3264 xlarge
.append("xlarge");
3266 ObjectStore::Transaction t
;
3268 t
.setattr(cid
, hoid
, "attr1", small
);
3269 t
.setattr(cid
, hoid
, "attr2", large
);
3270 t
.setattr(cid
, hoid
, "attr3", xlarge
);
3271 t
.write(cid
, hoid
, 0, small
.length(), small
);
3272 t
.write(cid
, hoid
, 10, small
.length(), small
);
3273 cerr
<< "Creating object and set attr " << hoid
<< std::endl
;
3274 r
= queue_transaction(store
, ch
, std::move(t
));
3278 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
3279 "key", 123, -1, ""));
3280 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
)));
3282 ObjectStore::Transaction t
;
3283 t
.clone(cid
, hoid
, hoid2
);
3284 t
.setattr(cid
, hoid2
, "attr2", small
);
3285 t
.rmattr(cid
, hoid2
, "attr1");
3286 t
.write(cid
, hoid
, 10, large
.length(), large
);
3287 t
.setattr(cid
, hoid
, "attr1", large
);
3288 t
.setattr(cid
, hoid
, "attr2", small
);
3289 cerr
<< "Clone object and rm attr" << std::endl
;
3290 r
= queue_transaction(store
, ch
, std::move(t
));
3293 r
= store
->read(ch
, hoid
, 10, 5, newdata
);
3295 ASSERT_TRUE(bl_eq(large
, newdata
));
3298 r
= store
->read(ch
, hoid
, 0, 5, newdata
);
3300 ASSERT_TRUE(bl_eq(small
, newdata
));
3303 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
3305 ASSERT_TRUE(bl_eq(small
, newdata
));
3307 r
= store
->getattr(ch
, hoid2
, "attr2", attr
);
3309 ASSERT_TRUE(bl_eq(small
, attr
));
3312 r
= store
->getattr(ch
, hoid2
, "attr3", attr
);
3314 ASSERT_TRUE(bl_eq(xlarge
, attr
));
3317 r
= store
->getattr(ch
, hoid
, "attr1", attr
);
3319 ASSERT_TRUE(bl_eq(large
, attr
));
3322 ObjectStore::Transaction t
;
3323 t
.remove(cid
, hoid
);
3324 t
.remove(cid
, hoid2
);
3325 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3330 memset(p
.c_str(), 1, p
.length());
3334 ObjectStore::Transaction t
;
3335 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3336 t
.clone(cid
, hoid
, hoid2
);
3338 memset(a
.c_str(), 2, a
.length());
3342 t
.write(cid
, hoid
, pl
.length(), a
.length(), al
);
3343 r
= queue_transaction(store
, ch
, std::move(t
));
3346 ASSERT_EQ((int)final
.length(),
3347 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3348 ASSERT_TRUE(bl_eq(rl
, final
));
3351 ObjectStore::Transaction t
;
3352 t
.remove(cid
, hoid
);
3353 t
.remove(cid
, hoid2
);
3354 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3359 memset(p
.c_str(), 111, p
.length());
3363 ObjectStore::Transaction t
;
3364 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3365 t
.clone(cid
, hoid
, hoid2
);
3370 memset(a
.c_str(), 112, a
.length());
3374 t
.write(cid
, hoid
, pl
.length() + z
.length(), a
.length(), al
);
3375 r
= queue_transaction(store
, ch
, std::move(t
));
3378 ASSERT_EQ((int)final
.length(),
3379 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3380 ASSERT_TRUE(bl_eq(rl
, final
));
3383 ObjectStore::Transaction t
;
3384 t
.remove(cid
, hoid
);
3385 t
.remove(cid
, hoid2
);
3386 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3391 memset(p
.c_str(), 5, p
.length());
3395 ObjectStore::Transaction t
;
3396 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3397 t
.clone(cid
, hoid
, hoid2
);
3402 memset(a
.c_str(), 6, a
.length());
3406 t
.write(cid
, hoid
, 17000, a
.length(), al
);
3407 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3409 ASSERT_EQ((int)final
.length(),
3410 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3411 /*cout << "expected:\n";
3412 final.hexdump(cout);
3415 ASSERT_TRUE(bl_eq(rl
, final
));
3418 ObjectStore::Transaction t
;
3419 t
.remove(cid
, hoid
);
3420 t
.remove(cid
, hoid2
);
3421 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3424 bufferptr
p(1048576);
3425 memset(p
.c_str(), 3, p
.length());
3428 ObjectStore::Transaction t
;
3429 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3430 t
.clone(cid
, hoid
, hoid2
);
3432 memset(a
.c_str(), 4, a
.length());
3435 t
.write(cid
, hoid
, a
.length(), a
.length(), al
);
3436 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3439 final
.substr_of(pl
, 0, al
.length());
3442 end
.substr_of(pl
, al
.length()*2, pl
.length() - al
.length()*2);
3444 ASSERT_EQ((int)final
.length(),
3445 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3446 /*cout << "expected:\n";
3447 final.hexdump(cout);
3450 ASSERT_TRUE(bl_eq(rl
, final
));
3453 ObjectStore::Transaction t
;
3454 t
.remove(cid
, hoid
);
3455 t
.remove(cid
, hoid2
);
3456 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3460 memset(p
.c_str(), 7, p
.length());
3463 ObjectStore::Transaction t
;
3464 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3465 t
.clone(cid
, hoid
, hoid2
);
3467 memset(a
.c_str(), 8, a
.length());
3470 t
.write(cid
, hoid
, 32768, a
.length(), al
);
3471 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3474 final
.substr_of(pl
, 0, 32768);
3477 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3479 ASSERT_EQ((int)final
.length(),
3480 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3481 /*cout << "expected:\n";
3482 final.hexdump(cout);
3485 ASSERT_TRUE(bl_eq(rl
, final
));
3488 ObjectStore::Transaction t
;
3489 t
.remove(cid
, hoid
);
3490 t
.remove(cid
, hoid2
);
3491 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3495 memset(p
.c_str(), 9, p
.length());
3498 ObjectStore::Transaction t
;
3499 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3500 t
.clone(cid
, hoid
, hoid2
);
3502 memset(a
.c_str(), 10, a
.length());
3505 t
.write(cid
, hoid
, 33768, a
.length(), al
);
3506 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3509 final
.substr_of(pl
, 0, 33768);
3512 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3514 ASSERT_EQ((int)final
.length(),
3515 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3516 /*cout << "expected:\n";
3517 final.hexdump(cout);
3520 ASSERT_TRUE(bl_eq(rl
, final
));
3524 //verify if non-empty collection is properly handled after store reload
3526 r
= store
->umount();
3530 ch
= store
->open_collection(cid
);
3532 ObjectStore::Transaction t
;
3533 t
.remove_collection(cid
);
3534 cerr
<< "Invalid rm coll" << std::endl
;
3535 PrCtl unset_dumpable
;
3536 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3539 ObjectStore::Transaction t
;
3540 t
.touch(cid
, hoid3
); //new record in db
3541 r
= queue_transaction(store
, ch
, std::move(t
));
3545 ObjectStore::Transaction t
;
3546 //verify if non-empty collection is properly handled when there are some pending removes and live records in db
3547 cerr
<< "Invalid rm coll again" << std::endl
;
3549 r
= store
->umount();
3553 ch
= store
->open_collection(cid
);
3555 t
.remove(cid
, hoid
);
3556 t
.remove(cid
, hoid2
);
3557 t
.remove_collection(cid
);
3558 PrCtl unset_dumpable
;
3559 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3562 ObjectStore::Transaction t
;
3563 t
.remove(cid
, hoid
);
3564 t
.remove(cid
, hoid2
);
3565 t
.remove(cid
, hoid3
);
3566 t
.remove_collection(cid
);
3567 cerr
<< "Cleaning" << std::endl
;
3568 r
= queue_transaction(store
, ch
, std::move(t
));
3573 TEST_P(StoreTest
, OmapSimple
) {
3576 auto ch
= store
->create_new_collection(cid
);
3578 ObjectStore::Transaction t
;
3579 t
.create_collection(cid
, 0);
3580 cerr
<< "Creating collection " << cid
<< std::endl
;
3581 r
= queue_transaction(store
, ch
, std::move(t
));
3584 ghobject_t
hoid(hobject_t(sobject_t("omap_obj", CEPH_NOSNAP
),
3585 "key", 123, -1, ""));
3587 small
.append("small");
3588 map
<string
,bufferlist
> km
;
3590 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3592 header
.append("this is a header");
3594 ObjectStore::Transaction t
;
3596 t
.omap_setkeys(cid
, hoid
, km
);
3597 t
.omap_setheader(cid
, hoid
, header
);
3598 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3599 r
= queue_transaction(store
, ch
, std::move(t
));
3605 map
<string
,bufferlist
> r
;
3606 store
->omap_get(ch
, hoid
, &h
, &r
);
3607 ASSERT_TRUE(bl_eq(header
, h
));
3608 ASSERT_EQ(r
.size(), km
.size());
3609 cout
<< "r: " << r
<< std::endl
;
3611 // test iterator with seek_to_first
3613 map
<string
,bufferlist
> r
;
3614 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3615 for (iter
->seek_to_first(); iter
->valid(); iter
->next()) {
3616 r
[iter
->key()] = iter
->value();
3618 cout
<< "r: " << r
<< std::endl
;
3619 ASSERT_EQ(r
.size(), km
.size());
3621 // test iterator with initial lower_bound
3623 map
<string
,bufferlist
> r
;
3624 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3625 for (iter
->lower_bound(string()); iter
->valid(); iter
->next()) {
3626 r
[iter
->key()] = iter
->value();
3628 cout
<< "r: " << r
<< std::endl
;
3629 ASSERT_EQ(r
.size(), km
.size());
3632 ObjectStore::Transaction t
;
3633 t
.remove(cid
, hoid
);
3634 t
.remove_collection(cid
);
3635 cerr
<< "Cleaning" << std::endl
;
3636 r
= queue_transaction(store
, ch
, std::move(t
));
3641 TEST_P(StoreTest
, OmapCloneTest
) {
3644 auto ch
= store
->create_new_collection(cid
);
3646 ObjectStore::Transaction t
;
3647 t
.create_collection(cid
, 0);
3648 cerr
<< "Creating collection " << cid
<< std::endl
;
3649 r
= queue_transaction(store
, ch
, std::move(t
));
3652 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
3653 "key", 123, -1, ""));
3655 small
.append("small");
3656 map
<string
,bufferlist
> km
;
3658 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3660 header
.append("this is a header");
3662 ObjectStore::Transaction t
;
3664 t
.omap_setkeys(cid
, hoid
, km
);
3665 t
.omap_setheader(cid
, hoid
, header
);
3666 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3667 r
= queue_transaction(store
, ch
, std::move(t
));
3670 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
3671 "key", 123, -1, ""));
3673 ObjectStore::Transaction t
;
3674 t
.clone(cid
, hoid
, hoid2
);
3675 cerr
<< "Clone object" << std::endl
;
3676 r
= queue_transaction(store
, ch
, std::move(t
));
3680 map
<string
,bufferlist
> r
;
3682 store
->omap_get(ch
, hoid2
, &h
, &r
);
3683 ASSERT_TRUE(bl_eq(header
, h
));
3684 ASSERT_EQ(r
.size(), km
.size());
3687 ObjectStore::Transaction t
;
3688 t
.remove(cid
, hoid
);
3689 t
.remove(cid
, hoid2
);
3690 t
.remove_collection(cid
);
3691 cerr
<< "Cleaning" << std::endl
;
3692 r
= queue_transaction(store
, ch
, std::move(t
));
3697 TEST_P(StoreTest
, SimpleCloneRangeTest
) {
3700 auto ch
= store
->create_new_collection(cid
);
3702 ObjectStore::Transaction t
;
3703 t
.create_collection(cid
, 0);
3704 cerr
<< "Creating collection " << cid
<< std::endl
;
3705 r
= queue_transaction(store
, ch
, std::move(t
));
3708 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3709 hoid
.hobj
.pool
= -1;
3710 bufferlist small
, newdata
;
3711 small
.append("small");
3713 ObjectStore::Transaction t
;
3714 t
.write(cid
, hoid
, 10, 5, small
);
3715 cerr
<< "Creating object and write bl " << hoid
<< std::endl
;
3716 r
= queue_transaction(store
, ch
, std::move(t
));
3719 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
3720 hoid2
.hobj
.pool
= -1;
3722 ObjectStore::Transaction t
;
3723 t
.clone_range(cid
, hoid
, hoid2
, 10, 5, 10);
3724 cerr
<< "Clone range object" << std::endl
;
3725 r
= queue_transaction(store
, ch
, std::move(t
));
3727 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
3729 ASSERT_TRUE(bl_eq(small
, newdata
));
3732 ObjectStore::Transaction t
;
3733 t
.truncate(cid
, hoid
, 1024*1024);
3734 t
.clone_range(cid
, hoid
, hoid2
, 0, 1024*1024, 0);
3735 cerr
<< "Clone range object" << std::endl
;
3736 r
= queue_transaction(store
, ch
, std::move(t
));
3738 struct stat stat
, stat2
;
3739 r
= store
->stat(ch
, hoid
, &stat
);
3740 r
= store
->stat(ch
, hoid2
, &stat2
);
3741 ASSERT_EQ(stat
.st_size
, stat2
.st_size
);
3742 ASSERT_EQ(1024*1024, stat2
.st_size
);
3745 ObjectStore::Transaction t
;
3746 t
.remove(cid
, hoid
);
3747 t
.remove(cid
, hoid2
);
3748 r
= queue_transaction(store
, ch
, std::move(t
));
3753 #if defined(WITH_BLUESTORE)
3754 TEST_P(StoreTest
, BlueStoreUnshareBlobTest
) {
3755 if (string(GetParam()) != "bluestore")
3758 cout
<< "SKIP: non-deterministic behavior with smr" << std::endl
;
3763 auto ch
= store
->create_new_collection(cid
);
3765 ObjectStore::Transaction t
;
3766 t
.create_collection(cid
, 0);
3767 cerr
<< "Creating collection " << cid
<< std::endl
;
3768 r
= queue_transaction(store
, ch
, std::move(t
));
3771 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3772 hoid
.hobj
.pool
= -1;
3773 ghobject_t
hoid2(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3774 hoid2
.hobj
.pool
= -1;
3775 hoid2
.generation
= 2;
3777 // check if blob is unshared properly
3778 bufferlist data
, newdata
;
3779 data
.append(string(8192, 'a'));
3781 ObjectStore::Transaction t
;
3782 t
.write(cid
, hoid
, 0, data
.length(), data
);
3783 cerr
<< "Creating object and write 8K " << hoid
<< std::endl
;
3784 r
= queue_transaction(store
, ch
, std::move(t
));
3787 ObjectStore::Transaction t2
;
3788 t2
.clone_range(cid
, hoid
, hoid2
, 0, 4096, 0);
3789 cerr
<< "Clone range object" << std::endl
;
3790 r
= queue_transaction(store
, ch
, std::move(t2
));
3794 data
.append(string(4096, 'b'));
3796 ObjectStore::Transaction t3
;
3797 t3
.write(cid
, hoid
, 0, data
.length(), data
);
3798 cerr
<< "Writing 4k to source object " << hoid
<< std::endl
;
3799 r
= queue_transaction(store
, ch
, std::move(t3
));
3803 // this trims hoid one out of onode cache
3804 EXPECT_EQ(store
->umount(), 0);
3805 EXPECT_EQ(store
->mount(), 0);
3806 ch
= store
->open_collection(cid
);
3809 ObjectStore::Transaction t4
;
3810 t4
.remove(cid
, hoid2
);
3811 cerr
<< "Deleting dest object" << hoid2
<< std::endl
;
3812 r
= queue_transaction(store
, ch
, std::move(t4
));
3816 // this ensures remove operation submitted to kv store
3817 EXPECT_EQ(store
->umount(), 0);
3818 EXPECT_EQ(store
->mount(), 0);
3819 ch
= store
->open_collection(cid
);
3823 r
= store
->read(ch
, hoid
, 0, 0x2000, resdata
);
3824 ASSERT_EQ(r
, 0x2000);
3827 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
3828 auto* kv
= bstore
->get_kv();
3830 // to be inline with BlueStore.cc
3831 const string PREFIX_SHARED_BLOB
= "X";
3834 auto it
= kv
->get_iterator(PREFIX_SHARED_BLOB
);
3836 for (it
->lower_bound(string()); it
->valid(); it
->next()) {
3843 ObjectStore::Transaction t
;
3844 t
.remove(cid
, hoid
);
3845 t
.remove_collection(cid
);
3846 cerr
<< "Cleaning" << std::endl
;
3847 r
= queue_transaction(store
, ch
, std::move(t
));
3852 TEST_P(StoreTest
, BlueStoreUnshareBlobBugTest
) {
3853 if (string(GetParam()) != "bluestore")
3857 auto ch
= store
->create_new_collection(cid
);
3859 ObjectStore::Transaction t
;
3860 t
.create_collection(cid
, 0);
3861 cerr
<< "Creating collection " << cid
<< std::endl
;
3862 r
= queue_transaction(store
, ch
, std::move(t
));
3865 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3866 hoid
.hobj
.pool
= -1;
3867 ghobject_t
hoid2(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3868 hoid2
.hobj
.pool
= -1;
3869 hoid2
.generation
= 2;
3871 // check if blob is unshared properly
3872 bufferlist data
, newdata
;
3873 data
.append(string(8192, 'a'));
3875 ObjectStore::Transaction t
;
3876 t
.write(cid
, hoid
, 0, data
.length(), data
);
3877 cerr
<< "Creating object and write 8K " << hoid
<< std::endl
;
3878 r
= queue_transaction(store
, ch
, std::move(t
));
3881 ObjectStore::Transaction t2
;
3882 t2
.clone_range(cid
, hoid
, hoid2
, 0, 4096, 0);
3883 cerr
<< "Clone range object" << std::endl
;
3884 r
= queue_transaction(store
, ch
, std::move(t2
));
3888 data
.append(string(4096, 'b'));
3890 ObjectStore::Transaction t3
;
3891 t3
.write(cid
, hoid
, 0, data
.length(), data
);
3892 cerr
<< "Writing 4k to source object " << hoid
<< std::endl
;
3893 r
= queue_transaction(store
, ch
, std::move(t3
));
3897 // this trims hoid one out of onode cache
3898 EXPECT_EQ(store
->umount(), 0);
3899 EXPECT_EQ(store
->mount(), 0);
3900 ch
= store
->open_collection(cid
);
3903 ObjectStore::Transaction t4
;
3904 t4
.write(cid
, hoid2
, 0, data
.length(), data
);
3905 cerr
<< "Writing 4k to second object " << hoid2
<< std::endl
;
3906 r
= queue_transaction(store
, ch
, std::move(t4
));
3910 r
= store
->read(ch
, hoid
, 0, 0x2000, resdata
);
3911 ASSERT_EQ(r
, 0x2000);
3914 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
3915 auto* kv
= bstore
->get_kv();
3917 // to be inline with BlueStore.cc
3918 const string PREFIX_SHARED_BLOB
= "X";
3921 auto it
= kv
->get_iterator(PREFIX_SHARED_BLOB
);
3923 for (it
->lower_bound(string()); it
->valid(); it
->next()) {
3926 // This shows a bug in unsharing a blob,
3927 // after writing to 0x0~1000 to hoid2 share blob at hoid should be
3928 //unshared but it doesn't in the current implementation
3933 ObjectStore::Transaction t
;
3934 t
.remove(cid
, hoid
);
3935 t
.remove(cid
, hoid2
);
3936 t
.remove_collection(cid
);
3937 cerr
<< "Cleaning" << std::endl
;
3938 r
= queue_transaction(store
, ch
, std::move(t
));
3944 TEST_P(StoreTest
, SimpleObjectLongnameTest
) {
3947 auto ch
= store
->create_new_collection(cid
);
3949 ObjectStore::Transaction t
;
3950 t
.create_collection(cid
, 0);
3951 cerr
<< "Creating collection " << cid
<< std::endl
;
3952 r
= queue_transaction(store
, ch
, std::move(t
));
3955 ghobject_t
hoid(hobject_t(sobject_t("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaObjectaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1", CEPH_NOSNAP
)));
3957 ObjectStore::Transaction t
;
3959 cerr
<< "Creating object " << hoid
<< std::endl
;
3960 r
= queue_transaction(store
, ch
, std::move(t
));
3964 ObjectStore::Transaction t
;
3965 t
.remove(cid
, hoid
);
3966 t
.remove_collection(cid
);
3967 cerr
<< "Cleaning" << std::endl
;
3968 r
= queue_transaction(store
, ch
, std::move(t
));
3973 ghobject_t
generate_long_name(unsigned i
)
3976 name
<< "object id " << i
<< " ";
3977 for (unsigned j
= 0; j
< 500; ++j
) name
<< 'a';
3978 ghobject_t
hoid(hobject_t(sobject_t(name
.str(), CEPH_NOSNAP
)));
3979 hoid
.hobj
.set_hash(i
% 2);
3983 TEST_P(StoreTest
, LongnameSplitTest
) {
3986 auto ch
= store
->create_new_collection(cid
);
3988 ObjectStore::Transaction t
;
3989 t
.create_collection(cid
, 0);
3990 cerr
<< "Creating collection " << cid
<< std::endl
;
3991 r
= queue_transaction(store
, ch
, std::move(t
));
3994 for (unsigned i
= 0; i
< 320; ++i
) {
3995 ObjectStore::Transaction t
;
3996 ghobject_t hoid
= generate_long_name(i
);
3998 cerr
<< "Creating object " << hoid
<< std::endl
;
3999 r
= queue_transaction(store
, ch
, std::move(t
));
4003 ghobject_t test_obj
= generate_long_name(319);
4004 ghobject_t test_obj_2
= test_obj
;
4005 test_obj_2
.generation
= 0;
4007 ObjectStore::Transaction t
;
4008 // should cause a split
4009 t
.collection_move_rename(
4012 r
= queue_transaction(store
, ch
, std::move(t
));
4016 for (unsigned i
= 0; i
< 319; ++i
) {
4017 ObjectStore::Transaction t
;
4018 ghobject_t hoid
= generate_long_name(i
);
4019 t
.remove(cid
, hoid
);
4020 cerr
<< "Removing object " << hoid
<< std::endl
;
4021 r
= queue_transaction(store
, ch
, std::move(t
));
4025 ObjectStore::Transaction t
;
4026 t
.remove(cid
, test_obj_2
);
4027 t
.remove_collection(cid
);
4028 cerr
<< "Cleaning" << std::endl
;
4029 r
= queue_transaction(store
, ch
, std::move(t
));
4035 TEST_P(StoreTest
, ManyObjectTest
) {
4036 int NUM_OBJS
= 2000;
4040 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
4041 set
<ghobject_t
> created
;
4042 auto ch
= store
->create_new_collection(cid
);
4044 ObjectStore::Transaction t
;
4045 t
.create_collection(cid
, 0);
4046 r
= queue_transaction(store
, ch
, std::move(t
));
4049 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
4051 cerr
<< "Object " << i
<< std::endl
;
4053 ObjectStore::Transaction t
;
4055 snprintf(buf
, sizeof(buf
), "%d", i
);
4056 ghobject_t
hoid(hobject_t(sobject_t(string(buf
) + base
, CEPH_NOSNAP
)));
4058 created
.insert(hoid
);
4059 r
= queue_transaction(store
, ch
, std::move(t
));
4063 for (set
<ghobject_t
>::iterator i
= created
.begin();
4067 ASSERT_TRUE(!store
->stat(ch
, *i
, &buf
));
4070 set
<ghobject_t
> listed
, listed2
;
4071 vector
<ghobject_t
> objects
;
4072 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
4076 cerr
<< "objects.size() is " << objects
.size() << std::endl
;
4077 for (vector
<ghobject_t
> ::iterator i
= objects
.begin();
4081 ASSERT_TRUE(created
.count(*i
));
4083 ASSERT_TRUE(listed
.size() == created
.size());
4085 ghobject_t start
, next
;
4087 r
= collection_list(
4090 ghobject_t::get_max(),
4091 ghobject_t::get_max(),
4097 ASSERT_TRUE(objects
.empty());
4101 ghobject_t start2
, next2
;
4103 r
= collection_list(store
, ch
, start
, ghobject_t::get_max(), 50, &objects
,
4105 ASSERT_TRUE(sorted(objects
));
4107 listed
.insert(objects
.begin(), objects
.end());
4108 if (objects
.size() < 50) {
4109 ASSERT_TRUE(next
.is_max());
4116 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
4117 ASSERT_TRUE(listed
.size() == created
.size());
4118 if (listed2
.size()) {
4119 ASSERT_EQ(listed
.size(), listed2
.size());
4121 for (set
<ghobject_t
>::iterator i
= listed
.begin();
4124 ASSERT_TRUE(created
.count(*i
));
4127 for (set
<ghobject_t
>::iterator i
= created
.begin();
4130 ObjectStore::Transaction t
;
4132 r
= queue_transaction(store
, ch
, std::move(t
));
4135 cerr
<< "cleaning up" << std::endl
;
4137 ObjectStore::Transaction t
;
4138 t
.remove_collection(cid
);
4139 r
= queue_transaction(store
, ch
, std::move(t
));
4145 class ObjectGenerator
{
4147 virtual ghobject_t
create_object(gen_type
*gen
) = 0;
4148 virtual ~ObjectGenerator() {}
4151 class MixedGenerator
: public ObjectGenerator
{
4155 explicit MixedGenerator(int64_t p
) : seq(0), poolid(p
) {}
4156 ghobject_t
create_object(gen_type
*gen
) override
{
4158 snprintf(buf
, sizeof(buf
), "OBJ_%u", seq
);
4161 for (unsigned i
= 0; i
< 300; ++i
) {
4162 name
.push_back('a');
4168 name
, string(), rand() & 2 ? CEPH_NOSNAP
: rand(),
4169 (((seq
/ 1024) % 2) * 0xF00 ) +
4175 class SyntheticWorkloadState
{
4178 map
<string
, bufferlist
> attrs
;
4181 static const unsigned max_in_flight
= 16;
4182 static const unsigned max_objects
= 3000;
4183 static const unsigned max_attr_size
= 5;
4184 static const unsigned max_attr_name_len
= 100;
4185 static const unsigned max_attr_value_len
= 1024 * 64;
4187 unsigned write_alignment
;
4188 unsigned max_object_len
, max_write_len
;
4190 map
<ghobject_t
, Object
> contents
;
4191 set
<ghobject_t
> available_objects
;
4192 set
<ghobject_t
>::iterator next_available_object
;
4193 set
<ghobject_t
> in_flight_objects
;
4194 ObjectGenerator
*object_gen
;
4197 ObjectStore::CollectionHandle ch
;
4199 ceph::mutex lock
= ceph::make_mutex("State lock");
4200 ceph::condition_variable cond
;
4204 explicit EnterExit(const char *m
) : msg(m
) {
4205 //cout << pthread_self() << " enter " << msg << std::endl;
4208 //cout << pthread_self() << " exit " << msg << std::endl;
4212 class C_SyntheticOnReadable
: public Context
{
4214 SyntheticWorkloadState
*state
;
4216 C_SyntheticOnReadable(SyntheticWorkloadState
*state
, ghobject_t hoid
)
4217 : state(state
), hoid(hoid
) {}
4219 void finish(int r
) override
{
4220 std::lock_guard locker
{state
->lock
};
4221 EnterExit
ee("onreadable finish");
4222 ASSERT_TRUE(state
->in_flight_objects
.count(hoid
));
4224 state
->in_flight_objects
.erase(hoid
);
4225 if (state
->contents
.count(hoid
))
4226 state
->available_objects
.insert(hoid
);
4227 --(state
->in_flight
);
4228 state
->cond
.notify_all();
4231 r
= state
->store
->read(state
->ch
, hoid
, 0, state
->contents
[hoid
].data
.length(), r2
);
4232 ceph_assert(bl_eq(state
->contents
[hoid
].data
, r2
));
4233 state
->cond
.notify_all();
4237 class C_SyntheticOnStash
: public Context
{
4239 SyntheticWorkloadState
*state
;
4240 ghobject_t oid
, noid
;
4242 C_SyntheticOnStash(SyntheticWorkloadState
*state
,
4243 ghobject_t oid
, ghobject_t noid
)
4244 : state(state
), oid(oid
), noid(noid
) {}
4246 void finish(int r
) override
{
4247 std::lock_guard locker
{state
->lock
};
4248 EnterExit
ee("stash finish");
4249 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
4251 state
->in_flight_objects
.erase(oid
);
4252 if (state
->contents
.count(noid
))
4253 state
->available_objects
.insert(noid
);
4254 --(state
->in_flight
);
4256 r
= state
->store
->read(
4258 state
->contents
[noid
].data
.length(), r2
);
4259 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
4260 state
->cond
.notify_all();
4264 class C_SyntheticOnClone
: public Context
{
4266 SyntheticWorkloadState
*state
;
4267 ghobject_t oid
, noid
;
4269 C_SyntheticOnClone(SyntheticWorkloadState
*state
,
4270 ghobject_t oid
, ghobject_t noid
)
4271 : state(state
), oid(oid
), noid(noid
) {}
4273 void finish(int r
) override
{
4274 std::lock_guard locker
{state
->lock
};
4275 EnterExit
ee("clone finish");
4276 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
4278 state
->in_flight_objects
.erase(oid
);
4279 if (state
->contents
.count(oid
))
4280 state
->available_objects
.insert(oid
);
4281 if (state
->contents
.count(noid
))
4282 state
->available_objects
.insert(noid
);
4283 --(state
->in_flight
);
4285 r
= state
->store
->read(state
->ch
, noid
, 0, state
->contents
[noid
].data
.length(), r2
);
4286 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
4287 state
->cond
.notify_all();
4291 static void filled_byte_array(bufferlist
& bl
, size_t size
)
4293 static const char alphanum
[] = "0123456789"
4294 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
4295 "abcdefghijklmnopqrstuvwxyz";
4300 for (unsigned int i
= 0; i
< size
- 1; i
++) {
4301 // severely limit entropy so we can compress...
4302 bp
[i
] = alphanum
[rand() % 10]; //(sizeof(alphanum) - 1)];
4304 bp
[size
- 1] = '\0';
4309 SyntheticWorkloadState(ObjectStore
*store
,
4310 ObjectGenerator
*gen
,
4316 : cid(cid
), write_alignment(alignment
), max_object_len(max_size
),
4317 max_write_len(max_write
), in_flight(0),
4318 next_available_object(available_objects
.end()),
4319 object_gen(gen
), rng(rng
), store(store
) {}
4322 ObjectStore::Transaction t
;
4323 ch
= store
->create_new_collection(cid
);
4324 t
.create_collection(cid
, 0);
4325 return queue_transaction(store
, ch
, std::move(t
));
4330 vector
<ghobject_t
> objects
;
4331 int r
= collection_list(store
, ch
, next
, ghobject_t::get_max(), 10,
4333 ceph_assert(r
>= 0);
4334 if (objects
.size() == 0)
4336 ObjectStore::Transaction t
;
4337 std::map
<std::string
, ceph::buffer::list
> attrset
;
4338 for (vector
<ghobject_t
>::iterator p
= objects
.begin();
4339 p
!= objects
.end(); ++p
) {
4342 queue_transaction(store
, ch
, std::move(t
));
4344 ObjectStore::Transaction t
;
4345 t
.remove_collection(cid
);
4346 queue_transaction(store
, ch
, std::move(t
));
4348 void statfs(store_statfs_t
& stat
) {
4349 store
->statfs(&stat
);
4352 ghobject_t
get_uniform_random_object(std::unique_lock
<ceph::mutex
>& locker
) {
4353 cond
.wait(locker
, [this] {
4354 return in_flight
< max_in_flight
&& !available_objects
.empty();
4356 boost::uniform_int
<> choose(0, available_objects
.size() - 1);
4357 int index
= choose(*rng
);
4358 set
<ghobject_t
>::iterator i
= available_objects
.begin();
4359 for ( ; index
> 0; --index
, ++i
) ;
4360 ghobject_t ret
= *i
;
4364 ghobject_t
get_next_object(std::unique_lock
<ceph::mutex
>& locker
) {
4365 cond
.wait(locker
, [this] {
4366 return in_flight
< max_in_flight
&& !available_objects
.empty();
4369 if (next_available_object
== available_objects
.end()) {
4370 next_available_object
= available_objects
.begin();
4373 ghobject_t ret
= *next_available_object
;
4374 ++next_available_object
;
4378 void wait_for_ready(std::unique_lock
<ceph::mutex
>& locker
) {
4379 cond
.wait(locker
, [this] { return in_flight
< max_in_flight
; });
4382 void wait_for_done() {
4383 std::unique_lock locker
{lock
};
4384 cond
.wait(locker
, [this] { return in_flight
== 0; });
4388 return (available_objects
.size() + in_flight_objects
.size()) < max_objects
;
4392 return (available_objects
.size() + in_flight_objects
.size()) > 0;
4395 unsigned get_random_alloc_hints() {
4398 boost::uniform_int
<> u(0, 3);
4401 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE
;
4404 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE
;
4409 boost::uniform_int
<> u(0, 3);
4412 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
;
4415 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ
;
4420 // append_only, immutable
4421 boost::uniform_int
<> u(0, 4);
4425 boost::uniform_int
<> u(0, 3);
4428 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED
;
4431 f
|= CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED
;
4436 boost::uniform_int
<> u(0, 3);
4439 f
|= CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE
;
4442 f
|= CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE
;
4450 std::unique_lock locker
{lock
};
4451 EnterExit
ee("touch");
4454 wait_for_ready(locker
);
4455 ghobject_t new_obj
= object_gen
->create_object(rng
);
4456 available_objects
.erase(new_obj
);
4457 ObjectStore::Transaction t
;
4458 t
.touch(cid
, new_obj
);
4459 boost::uniform_int
<> u(17, 22);
4460 boost::uniform_int
<> v(12, 17);
4461 t
.set_alloc_hint(cid
, new_obj
,
4464 get_random_alloc_hints());
4466 in_flight_objects
.insert(new_obj
);
4467 if (!contents
.count(new_obj
))
4468 contents
[new_obj
] = Object();
4469 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4470 int status
= store
->queue_transaction(ch
, std::move(t
));
4475 std::unique_lock locker
{lock
};
4476 EnterExit
ee("stash");
4481 wait_for_ready(locker
);
4486 old_obj
= get_uniform_random_object(locker
);
4487 } while (--max
&& !contents
[old_obj
].data
.length());
4488 available_objects
.erase(old_obj
);
4489 ghobject_t new_obj
= old_obj
;
4490 new_obj
.generation
++;
4491 available_objects
.erase(new_obj
);
4493 ObjectStore::Transaction t
;
4494 t
.collection_move_rename(cid
, old_obj
, cid
, new_obj
);
4496 in_flight_objects
.insert(old_obj
);
4498 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
4499 contents
[new_obj
].data
= contents
[old_obj
].data
;
4500 contents
.erase(old_obj
);
4501 t
.register_on_applied(new C_SyntheticOnStash(this, old_obj
, new_obj
));
4502 int status
= store
->queue_transaction(ch
, std::move(t
));
4507 std::unique_lock locker
{lock
};
4508 EnterExit
ee("clone");
4513 wait_for_ready(locker
);
4518 old_obj
= get_uniform_random_object(locker
);
4519 } while (--max
&& !contents
[old_obj
].data
.length());
4520 available_objects
.erase(old_obj
);
4521 ghobject_t new_obj
= object_gen
->create_object(rng
);
4522 // make the hash match
4523 new_obj
.hobj
.set_hash(old_obj
.hobj
.get_hash());
4524 available_objects
.erase(new_obj
);
4526 ObjectStore::Transaction t
;
4527 t
.clone(cid
, old_obj
, new_obj
);
4529 in_flight_objects
.insert(old_obj
);
4531 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
4532 contents
[new_obj
].data
= contents
[old_obj
].data
;
4534 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
4535 int status
= store
->queue_transaction(ch
, std::move(t
));
4540 std::unique_lock locker
{lock
};
4541 EnterExit
ee("clone_range");
4546 wait_for_ready(locker
);
4551 old_obj
= get_uniform_random_object(locker
);
4552 } while (--max
&& !contents
[old_obj
].data
.length());
4553 bufferlist
&srcdata
= contents
[old_obj
].data
;
4554 if (srcdata
.length() == 0) {
4557 available_objects
.erase(old_obj
);
4558 ghobject_t new_obj
= get_uniform_random_object(locker
);
4559 available_objects
.erase(new_obj
);
4561 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4562 boost::uniform_int
<> u2(0, max_write_len
);
4563 uint64_t srcoff
= u1(*rng
);
4564 // make src and dst offsets match, since that's what the osd does
4565 uint64_t dstoff
= srcoff
; //u1(*rng);
4566 uint64_t len
= u2(*rng
);
4567 if (write_alignment
) {
4568 srcoff
= round_up_to(srcoff
, write_alignment
);
4569 dstoff
= round_up_to(dstoff
, write_alignment
);
4570 len
= round_up_to(len
, write_alignment
);
4573 if (srcoff
> srcdata
.length() - 1) {
4574 srcoff
= srcdata
.length() - 1;
4576 if (srcoff
+ len
> srcdata
.length()) {
4577 len
= srcdata
.length() - srcoff
;
4580 cout
<< __func__
<< " from " << srcoff
<< "~" << len
4581 << " (size " << srcdata
.length() << ") to "
4582 << dstoff
<< "~" << len
<< std::endl
;
4584 ObjectStore::Transaction t
;
4585 t
.clone_range(cid
, old_obj
, new_obj
, srcoff
, len
, dstoff
);
4587 in_flight_objects
.insert(old_obj
);
4590 if (srcoff
< srcdata
.length()) {
4591 if (srcoff
+ len
> srcdata
.length()) {
4592 bl
.substr_of(srcdata
, srcoff
, srcdata
.length() - srcoff
);
4594 bl
.substr_of(srcdata
, srcoff
, len
);
4598 bufferlist
& dstdata
= contents
[new_obj
].data
;
4599 if (dstdata
.length() <= dstoff
) {
4600 if (bl
.length() > 0) {
4601 dstdata
.append_zero(dstoff
- dstdata
.length());
4606 ceph_assert(dstdata
.length() > dstoff
);
4607 dstdata
.cbegin().copy(dstoff
, value
);
4609 if (value
.length() < dstdata
.length())
4610 dstdata
.cbegin(value
.length()).copy(
4611 dstdata
.length() - value
.length(), value
);
4612 value
.swap(dstdata
);
4615 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
4616 int status
= store
->queue_transaction(ch
, std::move(t
));
4622 std::unique_lock locker
{lock
};
4623 EnterExit
ee("write");
4626 wait_for_ready(locker
);
4628 ghobject_t new_obj
= get_uniform_random_object(locker
);
4629 available_objects
.erase(new_obj
);
4630 ObjectStore::Transaction t
;
4632 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4633 boost::uniform_int
<> u2(0, max_write_len
);
4634 uint64_t offset
= u1(*rng
);
4635 uint64_t len
= u2(*rng
);
4637 if (write_alignment
) {
4638 offset
= round_up_to(offset
, write_alignment
);
4639 len
= round_up_to(len
, write_alignment
);
4642 filled_byte_array(bl
, len
);
4644 bufferlist
& data
= contents
[new_obj
].data
;
4645 if (data
.length() <= offset
) {
4647 data
.append_zero(offset
-data
.length());
4652 ceph_assert(data
.length() > offset
);
4653 data
.cbegin().copy(offset
, value
);
4655 if (value
.length() < data
.length())
4656 data
.cbegin(value
.length()).copy(
4657 data
.length()-value
.length(), value
);
4661 t
.write(cid
, new_obj
, offset
, len
, bl
);
4663 in_flight_objects
.insert(new_obj
);
4664 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4665 int status
= store
->queue_transaction(ch
, std::move(t
));
4670 std::unique_lock locker
{lock
};
4671 EnterExit
ee("truncate");
4674 wait_for_ready(locker
);
4676 ghobject_t obj
= get_uniform_random_object(locker
);
4677 available_objects
.erase(obj
);
4678 ObjectStore::Transaction t
;
4680 boost::uniform_int
<> choose(0, max_object_len
);
4681 size_t len
= choose(*rng
);
4682 if (write_alignment
) {
4683 len
= round_up_to(len
, write_alignment
);
4686 t
.truncate(cid
, obj
, len
);
4688 in_flight_objects
.insert(obj
);
4689 bufferlist
& data
= contents
[obj
].data
;
4690 if (data
.length() <= len
) {
4691 data
.append_zero(len
- data
.length());
4694 data
.cbegin().copy(len
, bl
);
4698 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4699 int status
= store
->queue_transaction(ch
, std::move(t
));
4704 std::unique_lock locker
{lock
};
4705 EnterExit
ee("zero");
4708 wait_for_ready(locker
);
4710 ghobject_t new_obj
= get_uniform_random_object(locker
);
4711 available_objects
.erase(new_obj
);
4712 ObjectStore::Transaction t
;
4714 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4715 boost::uniform_int
<> u2(0, max_write_len
);
4716 uint64_t offset
= u1(*rng
);
4717 uint64_t len
= u2(*rng
);
4718 if (write_alignment
) {
4719 offset
= round_up_to(offset
, write_alignment
);
4720 len
= round_up_to(len
, write_alignment
);
4724 auto& data
= contents
[new_obj
].data
;
4725 if (data
.length() < offset
+ len
) {
4726 data
.append_zero(offset
+len
-data
.length());
4729 n
.substr_of(data
, 0, offset
);
4731 if (data
.length() > offset
+ len
)
4732 data
.cbegin(offset
+ len
).copy(data
.length() - offset
- len
, n
);
4736 t
.zero(cid
, new_obj
, offset
, len
);
4738 in_flight_objects
.insert(new_obj
);
4739 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4740 int status
= store
->queue_transaction(ch
, std::move(t
));
4745 EnterExit
ee("read");
4746 boost::uniform_int
<> u1(0, max_object_len
/2);
4747 boost::uniform_int
<> u2(0, max_object_len
);
4748 uint64_t offset
= u1(*rng
);
4749 uint64_t len
= u2(*rng
);
4754 bufferlist expected
;
4757 std::unique_lock locker
{lock
};
4758 EnterExit
ee("read locked");
4761 wait_for_ready(locker
);
4763 obj
= get_uniform_random_object(locker
);
4764 expected
= contents
[obj
].data
;
4766 bufferlist bl
, result
;
4767 if (0) cout
<< " obj " << obj
4768 << " size " << expected
.length()
4769 << " offset " << offset
4770 << " len " << len
<< std::endl
;
4771 r
= store
->read(ch
, obj
, offset
, len
, result
);
4772 if (offset
>= expected
.length()) {
4775 size_t max_len
= expected
.length() - offset
;
4778 ceph_assert(len
== result
.length());
4779 ASSERT_EQ(len
, result
.length());
4780 expected
.cbegin(offset
).copy(len
, bl
);
4781 ASSERT_EQ(r
, (int)len
);
4782 ASSERT_TRUE(bl_eq(bl
, result
));
4787 std::unique_lock locker
{lock
};
4788 EnterExit
ee("setattrs");
4791 wait_for_ready(locker
);
4793 ghobject_t obj
= get_uniform_random_object(locker
);
4794 available_objects
.erase(obj
);
4795 ObjectStore::Transaction t
;
4797 boost::uniform_int
<> u0(1, max_attr_size
);
4798 boost::uniform_int
<> u1(4, max_attr_name_len
);
4799 boost::uniform_int
<> u2(4, max_attr_value_len
);
4800 boost::uniform_int
<> u3(0, 100);
4801 uint64_t size
= u0(*rng
);
4803 map
<string
, bufferlist
, less
<>> attrs
;
4805 for (map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4806 it
!= contents
[obj
].attrs
.end(); ++it
)
4807 keys
.insert(it
->first
);
4810 bufferlist name
, value
;
4811 uint64_t get_exist
= u3(*rng
);
4812 uint64_t value_len
= u2(*rng
);
4813 filled_byte_array(value
, value_len
);
4814 if (get_exist
< 50 && keys
.size()) {
4815 set
<string
>::iterator k
= keys
.begin();
4817 contents
[obj
].attrs
[*k
] = value
;
4820 name_len
= u1(*rng
);
4821 filled_byte_array(name
, name_len
);
4822 attrs
[name
.c_str()] = value
;
4823 contents
[obj
].attrs
[name
.c_str()] = value
;
4826 t
.setattrs(cid
, obj
, attrs
);
4828 in_flight_objects
.insert(obj
);
4829 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4830 int status
= store
->queue_transaction(ch
, std::move(t
));
4834 int set_fixed_attrs(size_t entries
, size_t key_size
, size_t val_size
) {
4835 std::unique_lock locker
{ lock
};
4836 EnterExit
ee("setattrs");
4839 wait_for_ready(locker
);
4841 ghobject_t obj
= get_next_object(locker
);
4842 available_objects
.erase(obj
);
4843 ObjectStore::Transaction t
;
4845 map
<string
, bufferlist
, less
<>> attrs
;
4849 bufferlist name
, value
;
4850 filled_byte_array(value
, val_size
);
4851 filled_byte_array(name
, key_size
);
4852 attrs
[name
.c_str()] = value
;
4853 contents
[obj
].attrs
[name
.c_str()] = value
;
4855 t
.setattrs(cid
, obj
, attrs
);
4857 in_flight_objects
.insert(obj
);
4858 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4859 int status
= store
->queue_transaction(ch
, std::move(t
));
4864 EnterExit
ee("getattrs");
4866 map
<string
, bufferlist
> expected
;
4868 std::unique_lock locker
{lock
};
4869 EnterExit
ee("getattrs locked");
4872 wait_for_ready(locker
);
4876 obj
= get_uniform_random_object(locker
);
4879 } while (contents
[obj
].attrs
.empty());
4880 expected
= contents
[obj
].attrs
;
4882 map
<string
, bufferlist
, less
<>> attrs
;
4883 int r
= store
->getattrs(ch
, obj
, attrs
);
4884 ASSERT_TRUE(r
== 0);
4885 ASSERT_TRUE(attrs
.size() == expected
.size());
4886 for (map
<string
, bufferlist
>::iterator it
= expected
.begin();
4887 it
!= expected
.end(); ++it
) {
4888 ASSERT_TRUE(bl_eq(attrs
[it
->first
], it
->second
));
4893 EnterExit
ee("getattr");
4897 map
<string
, bufferlist
> expected
;
4899 std::unique_lock locker
{lock
};
4900 EnterExit
ee("getattr locked");
4903 wait_for_ready(locker
);
4907 obj
= get_uniform_random_object(locker
);
4910 } while (contents
[obj
].attrs
.empty());
4911 expected
= contents
[obj
].attrs
;
4913 boost::uniform_int
<> u(0, expected
.size()-1);
4915 map
<string
, bufferlist
>::iterator it
= expected
.begin();
4922 r
= store
->getattr(ch
, obj
, it
->first
, bl
);
4924 ASSERT_TRUE(bl_eq(it
->second
, bl
));
4928 std::unique_lock locker
{lock
};
4929 EnterExit
ee("rmattr");
4932 wait_for_ready(locker
);
4937 obj
= get_uniform_random_object(locker
);
4940 } while (contents
[obj
].attrs
.empty());
4942 boost::uniform_int
<> u(0, contents
[obj
].attrs
.size()-1);
4944 map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4950 available_objects
.erase(obj
);
4951 ObjectStore::Transaction t
;
4952 t
.rmattr(cid
, obj
, it
->first
);
4954 contents
[obj
].attrs
.erase(it
->first
);
4956 in_flight_objects
.insert(obj
);
4957 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4958 int status
= store
->queue_transaction(ch
, std::move(t
));
4962 void fsck(bool deep
) {
4963 std::unique_lock locker
{lock
};
4964 EnterExit
ee("fsck");
4965 cond
.wait(locker
, [this] { return in_flight
== 0; });
4968 int r
= store
->fsck(deep
);
4969 ceph_assert(r
== 0 || r
== -EOPNOTSUPP
);
4971 ch
= store
->open_collection(cid
);
4975 std::unique_lock locker
{lock
};
4976 EnterExit
ee("scan");
4977 cond
.wait(locker
, [this] { return in_flight
== 0; });
4978 vector
<ghobject_t
> objects
;
4979 set
<ghobject_t
> objects_set
, objects_set2
;
4980 ghobject_t next
, current
;
4982 //cerr << "scanning..." << std::endl;
4983 int r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 100,
4986 ASSERT_TRUE(sorted(objects
));
4987 objects_set
.insert(objects
.begin(), objects
.end());
4989 if (next
.is_max()) break;
4992 if (objects_set
.size() != available_objects
.size()) {
4993 for (set
<ghobject_t
>::iterator p
= objects_set
.begin();
4994 p
!= objects_set
.end();
4996 if (available_objects
.count(*p
) == 0) {
4997 cerr
<< "+ " << *p
<< std::endl
;
5000 for (set
<ghobject_t
>::iterator p
= available_objects
.begin();
5001 p
!= available_objects
.end();
5003 if (objects_set
.count(*p
) == 0)
5004 cerr
<< "- " << *p
<< std::endl
;
5005 //cerr << " objects_set: " << objects_set << std::endl;
5006 //cerr << " available_set: " << available_objects << std::endl;
5007 ceph_abort_msg("badness");
5010 ASSERT_EQ(objects_set
.size(), available_objects
.size());
5011 for (set
<ghobject_t
>::iterator i
= objects_set
.begin();
5012 i
!= objects_set
.end();
5014 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
5017 int r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(),
5018 INT_MAX
, &objects
, 0);
5020 objects_set2
.insert(objects
.begin(), objects
.end());
5021 ASSERT_EQ(objects_set2
.size(), available_objects
.size());
5022 for (set
<ghobject_t
>::iterator i
= objects_set2
.begin();
5023 i
!= objects_set2
.end();
5025 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
5026 if (available_objects
.count(*i
) == 0) {
5027 cerr
<< "+ " << *i
<< std::endl
;
5033 EnterExit
ee("stat");
5037 std::unique_lock locker
{lock
};
5038 EnterExit
ee("stat lock1");
5041 hoid
= get_uniform_random_object(locker
);
5042 in_flight_objects
.insert(hoid
);
5043 available_objects
.erase(hoid
);
5045 expected
= contents
[hoid
].data
.length();
5048 int r
= store
->stat(ch
, hoid
, &buf
);
5050 ceph_assert((uint64_t)buf
.st_size
== expected
);
5051 ASSERT_TRUE((uint64_t)buf
.st_size
== expected
);
5053 std::lock_guard locker
{lock
};
5054 EnterExit
ee("stat lock2");
5057 in_flight_objects
.erase(hoid
);
5058 available_objects
.insert(hoid
);
5063 std::unique_lock locker
{lock
};
5064 EnterExit
ee("unlink");
5067 ghobject_t to_remove
= get_uniform_random_object(locker
);
5068 ObjectStore::Transaction t
;
5069 t
.remove(cid
, to_remove
);
5071 available_objects
.erase(to_remove
);
5072 in_flight_objects
.insert(to_remove
);
5073 contents
.erase(to_remove
);
5074 t
.register_on_applied(new C_SyntheticOnReadable(this, to_remove
));
5075 int status
= store
->queue_transaction(ch
, std::move(t
));
5079 void print_internal_state() {
5080 std::lock_guard locker
{lock
};
5081 cerr
<< "available_objects: " << available_objects
.size()
5082 << " in_flight_objects: " << in_flight_objects
.size()
5083 << " total objects: " << in_flight_objects
.size() + available_objects
.size()
5084 << " in_flight " << in_flight
<< std::endl
;
5089 void StoreTest::doSyntheticTest(
5091 uint64_t max_obj
, uint64_t max_wr
, uint64_t align
)
5093 MixedGenerator
gen(555);
5094 gen_type
rng(time(NULL
));
5095 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
5097 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
5098 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
5099 g_ceph_context
->_conf
.apply_changes(nullptr);
5101 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
,
5102 max_obj
, max_wr
, align
);
5104 for (int i
= 0; i
< num_ops
/10; ++i
) {
5105 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
5108 for (int i
= 0; i
< num_ops
; ++i
) {
5110 cerr
<< "Op " << i
<< std::endl
;
5111 test_obj
.print_internal_state();
5113 boost::uniform_int
<> true_false(0, 999);
5114 int val
= true_false(rng
);
5116 test_obj
.fsck(true);
5117 } else if (val
> 997) {
5118 test_obj
.fsck(false);
5119 } else if (val
> 970) {
5121 } else if (val
> 950) {
5123 } else if (val
> 850) {
5125 } else if (val
> 800) {
5127 } else if (val
> 550) {
5129 } else if (val
> 500) {
5131 } else if (val
> 450) {
5132 test_obj
.clone_range();
5133 } else if (val
> 300) {
5135 } else if (val
> 100) {
5138 test_obj
.truncate();
5141 test_obj
.wait_for_done();
5142 test_obj
.shutdown();
5145 TEST_P(StoreTest
, Synthetic
) {
5146 doSyntheticTest(10000, 400*1024, 40*1024, 0);
5149 #if defined(WITH_BLUESTORE)
5150 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixSharding
) {
5151 if (string(GetParam()) != "bluestore")
5154 const char *m
[][10] = {
5155 { "bluestore_min_alloc_size", "4096", 0 }, // must be the first!
5156 { "num_ops", "50000", 0 },
5157 { "max_write", "65536", 0 },
5158 { "max_size", "262144", 0 },
5159 { "alignment", "4096", 0 },
5160 { "bluestore_max_blob_size", "65536", 0 },
5161 { "bluestore_extent_map_shard_min_size", "60", 0 },
5162 { "bluestore_extent_map_shard_max_size", "300", 0 },
5163 { "bluestore_extent_map_shard_target_size", "150", 0 },
5164 { "bluestore_default_buffered_read", "true", 0 },
5165 { "bluestore_default_buffered_write", "true", 0 },
5168 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5171 TEST_P(StoreTestSpecificAUSize
, ZipperPatternSharded
) {
5172 if(string(GetParam()) != "bluestore")
5174 StartDeferred(4096);
5178 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
5179 auto ch
= store
->create_new_collection(cid
);
5181 ObjectStore::Transaction t
;
5182 t
.create_collection(cid
, 0);
5183 cerr
<< "Creating collection " << cid
<< std::endl
;
5184 r
= queue_transaction(store
, ch
, std::move(t
));
5192 for (int i
=0; i
<1000; ++i
) {
5193 ObjectStore::Transaction t
;
5194 t
.write(cid
, a
, i
*2*len
, len
, bl
, 0);
5195 r
= queue_transaction(store
, ch
, std::move(t
));
5198 for (int i
=0; i
<1000; ++i
) {
5199 ObjectStore::Transaction t
;
5200 t
.write(cid
, a
, i
*2*len
+ 1, len
, bl
, 0);
5201 r
= queue_transaction(store
, ch
, std::move(t
));
5205 ObjectStore::Transaction t
;
5207 t
.remove_collection(cid
);
5208 cerr
<< "Cleaning" << std::endl
;
5209 r
= queue_transaction(store
, ch
, std::move(t
));
5214 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumAlgorithm
) {
5215 if (string(GetParam()) != "bluestore")
5218 const char *m
[][10] = {
5219 { "bluestore_min_alloc_size", "65536", 0 }, // must be the first!
5220 { "max_write", "65536", 0 },
5221 { "max_size", "1048576", 0 },
5222 { "alignment", "16", 0 },
5223 { "bluestore_csum_type", "crc32c", "crc32c_16", "crc32c_8", "xxhash32",
5224 "xxhash64", "none", 0 },
5225 { "bluestore_default_buffered_write", "false", 0 },
5228 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5231 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumVsCompression
) {
5232 if (string(GetParam()) != "bluestore")
5235 const char *m
[][10] = {
5236 { "bluestore_min_alloc_size", "4096", "16384", 0 }, //to be the first!
5237 { "max_write", "131072", 0 },
5238 { "max_size", "262144", 0 },
5239 { "alignment", "512", 0 },
5240 { "bluestore_compression_mode", "force", 0},
5241 { "bluestore_compression_algorithm", "snappy", "zlib", 0 },
5242 { "bluestore_csum_type", "crc32c", 0 },
5243 { "bluestore_default_buffered_read", "true", "false", 0 },
5244 { "bluestore_default_buffered_write", "true", "false", 0 },
5245 { "bluestore_sync_submit_transaction", "false", 0 },
5248 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5251 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompression
) {
5252 if (string(GetParam()) != "bluestore")
5255 const char *m
[][10] = {
5256 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5257 { "max_write", "1048576", 0 },
5258 { "max_size", "4194304", 0 },
5259 { "alignment", "65536", 0 },
5260 { "bluestore_compression_mode", "force", "aggressive", "passive", "none", 0},
5261 { "bluestore_default_buffered_write", "false", 0 },
5262 { "bluestore_sync_submit_transaction", "true", 0 },
5265 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5268 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompressionAlgorithm
) {
5269 if (string(GetParam()) != "bluestore")
5272 const char *m
[][10] = {
5273 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5274 { "max_write", "1048576", 0 },
5275 { "max_size", "4194304", 0 },
5276 { "alignment", "65536", 0 },
5277 { "bluestore_compression_algorithm", "zlib", "snappy", 0 },
5278 { "bluestore_compression_mode", "force", 0 },
5279 { "bluestore_default_buffered_write", "false", 0 },
5282 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5285 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixNoCsum
) {
5286 if (string(GetParam()) != "bluestore")
5289 const char *m
[][10] = {
5290 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5291 { "max_write", "65536", 0 },
5292 { "max_size", "1048576", 0 },
5293 { "alignment", "512", 0 },
5294 { "bluestore_max_blob_size", "262144", 0 },
5295 { "bluestore_compression_mode", "force", "none", 0},
5296 { "bluestore_csum_type", "none", 0},
5297 { "bluestore_default_buffered_read", "true", "false", 0 },
5298 { "bluestore_default_buffered_write", "true", 0 },
5299 { "bluestore_sync_submit_transaction", "true", "false", 0 },
5302 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5305 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixPreferDeferred
) {
5306 if (string(GetParam()) != "bluestore")
5309 const char *m
[][10] = {
5310 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5311 { "max_write", "65536", 0 },
5312 { "max_size", "1048576", 0 },
5313 { "alignment", "512", 0 },
5314 { "bluestore_max_blob_size", "262144", 0 },
5315 { "bluestore_compression_mode", "force", "none", 0},
5316 { "bluestore_prefer_deferred_size", "32768", "0", 0},
5319 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5321 #endif // WITH_BLUESTORE
5323 TEST_P(StoreTest
, AttrSynthetic
) {
5324 MixedGenerator
gen(447);
5325 gen_type
rng(time(NULL
));
5326 coll_t
cid(spg_t(pg_t(0,447),shard_id_t::NO_SHARD
));
5328 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
, 40*1024, 4*1024, 0);
5330 for (int i
= 0; i
< 500; ++i
) {
5331 if (!(i
% 10)) cerr
<< "seeding object " << i
<< std::endl
;
5334 for (int i
= 0; i
< 1000; ++i
) {
5336 cerr
<< "Op " << i
<< std::endl
;
5337 test_obj
.print_internal_state();
5339 boost::uniform_int
<> true_false(0, 99);
5340 int val
= true_false(rng
);
5343 } else if (val
> 93) {
5345 } else if (val
> 75) {
5347 } else if (val
> 47) {
5348 test_obj
.setattrs();
5349 } else if (val
> 45) {
5351 } else if (val
> 37) {
5353 } else if (val
> 30) {
5354 test_obj
.getattrs();
5359 test_obj
.wait_for_done();
5360 test_obj
.shutdown();
5363 TEST_P(StoreTest
, HashCollisionTest
) {
5364 int64_t poolid
= 11;
5365 coll_t
cid(spg_t(pg_t(0,poolid
),shard_id_t::NO_SHARD
));
5367 auto ch
= store
->create_new_collection(cid
);
5369 ObjectStore::Transaction t
;
5370 t
.create_collection(cid
, 0);
5371 r
= queue_transaction(store
, ch
, std::move(t
));
5375 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
5376 set
<ghobject_t
> created
;
5377 for (int n
= 0; n
< 10; ++n
) {
5379 sprintf(nbuf
, "n%d", n
);
5380 for (int i
= 0; i
< 1000; ++i
) {
5382 sprintf(buf
, "%d", i
);
5384 cerr
<< "Object n" << n
<< " "<< i
<< std::endl
;
5386 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, 0, poolid
, string(nbuf
)));
5388 ObjectStore::Transaction t
;
5390 r
= queue_transaction(store
, ch
, std::move(t
));
5393 created
.insert(hoid
);
5396 vector
<ghobject_t
> objects
;
5397 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5400 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
5401 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
5402 ASSERT_TRUE(listed
.size() == created
.size());
5405 ghobject_t current
, next
;
5407 r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 60, &objects
,
5410 ASSERT_TRUE(sorted(objects
));
5411 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5414 if (listed
.count(*i
))
5415 cerr
<< *i
<< " repeated" << std::endl
;
5418 if (objects
.size() < 50) {
5419 ASSERT_TRUE(next
.is_max());
5425 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
5426 ASSERT_TRUE(listed
.size() == created
.size());
5427 for (set
<ghobject_t
>::iterator i
= listed
.begin();
5430 ASSERT_TRUE(created
.count(*i
));
5433 for (set
<ghobject_t
>::iterator i
= created
.begin();
5436 ObjectStore::Transaction t
;
5438 r
= queue_transaction(store
, ch
, std::move(t
));
5441 ObjectStore::Transaction t
;
5442 t
.remove_collection(cid
);
5443 r
= queue_transaction(store
, ch
, std::move(t
));
5447 TEST_P(StoreTest
, HashCollisionSorting
) {
5448 bool disable_legacy
= (string(GetParam()) == "bluestore");
5450 char buf121664318_1
[] = {18, -119, -121, -111, 0};
5451 char buf121664318_2
[] = {19, 127, -121, 32, 0};
5452 char buf121664318_3
[] = {19, -118, 15, 19, 0};
5453 char buf121664318_4
[] = {28, 27, -116, -113, 0};
5454 char buf121664318_5
[] = {28, 27, -115, -124, 0};
5456 char buf121666222_1
[] = {18, -119, -120, -111, 0};
5457 char buf121666222_2
[] = {19, 127, -120, 32, 0};
5458 char buf121666222_3
[] = {19, -118, 15, 30, 0};
5459 char buf121666222_4
[] = {29, 17, -126, -113, 0};
5460 char buf121666222_5
[] = {29, 17, -125, -124, 0};
5462 std::map
<uint32_t, std::vector
<std::string
>> object_names
= {
5463 {121664318, {{buf121664318_1
},
5468 {121666222, {{buf121666222_1
},
5472 {buf121666222_5
}}}};
5474 int64_t poolid
= 111;
5475 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
5476 auto ch
= store
->create_new_collection(cid
);
5478 ObjectStore::Transaction t
;
5479 t
.create_collection(cid
, 0);
5480 int r
= queue_transaction(store
, ch
, std::move(t
));
5484 std::set
<ghobject_t
> created
;
5485 for (auto &[hash
, names
] : object_names
) {
5486 for (auto &name
: names
) {
5487 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
),
5492 ASSERT_EQ(hash
, hoid
.hobj
.get_hash());
5493 ObjectStore::Transaction t
;
5495 int r
= queue_transaction(store
, ch
, std::move(t
));
5497 created
.insert(hoid
);
5501 vector
<ghobject_t
> objects
;
5502 int r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(),
5503 INT_MAX
, &objects
, 0, disable_legacy
);
5505 ASSERT_EQ(created
.size(), objects
.size());
5506 auto it
= objects
.begin();
5507 for (auto &hoid
: created
) {
5508 ASSERT_EQ(hoid
, *it
);
5512 for (auto i
= created
.begin(); i
!= created
.end(); i
++) {
5514 for (j
++; j
!= created
.end(); j
++) {
5515 std::set
<ghobject_t
> created_sub(i
, j
);
5518 r
= collection_list(store
, ch
, *i
, ghobject_t::get_max(),
5519 created_sub
.size(), &objects
, &next
, disable_legacy
);
5521 ASSERT_EQ(created_sub
.size(), objects
.size());
5522 it
= objects
.begin();
5523 for (auto &hoid
: created_sub
) {
5524 ASSERT_EQ(hoid
, *it
);
5527 if (j
== created
.end()) {
5528 ASSERT_TRUE(next
.is_max());
5530 ASSERT_EQ(*j
, next
);
5535 for (auto i
= created
.begin(); i
!= created
.end(); i
++) {
5537 for (j
++; j
!= created
.end(); j
++) {
5538 std::set
<ghobject_t
> created_sub(i
, j
);
5541 r
= collection_list(store
, ch
, *i
, *j
, INT_MAX
, &objects
, &next
,
5544 ASSERT_EQ(created_sub
.size(), objects
.size());
5545 it
= objects
.begin();
5546 for (auto &hoid
: created_sub
) {
5547 ASSERT_EQ(hoid
, *it
);
5550 if (j
== created
.end()) {
5551 ASSERT_TRUE(next
.is_max());
5553 ASSERT_EQ(*j
, next
);
5559 TEST_P(StoreTest
, ScrubTest
) {
5560 int64_t poolid
= 111;
5561 coll_t
cid(spg_t(pg_t(0, poolid
),shard_id_t(1)));
5563 auto ch
= store
->create_new_collection(cid
);
5565 ObjectStore::Transaction t
;
5566 t
.create_collection(cid
, 0);
5567 r
= queue_transaction(store
, ch
, std::move(t
));
5570 string base
= "aaaaa";
5571 set
<ghobject_t
> created
;
5572 for (int i
= 0; i
< 1000; ++i
) {
5574 sprintf(buf
, "%d", i
);
5576 cerr
<< "Object " << i
<< std::endl
;
5578 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, i
,
5580 ghobject_t::NO_GEN
, shard_id_t(1));
5582 ObjectStore::Transaction t
;
5584 r
= queue_transaction(store
, ch
, std::move(t
));
5587 created
.insert(hoid
);
5590 // Add same hobject_t but different generation
5592 ghobject_t
hoid1(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""),
5593 ghobject_t::NO_GEN
, shard_id_t(1));
5594 ghobject_t
hoid2(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)1, shard_id_t(1));
5595 ghobject_t
hoid3(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)2, shard_id_t(1));
5596 ObjectStore::Transaction t
;
5597 t
.touch(cid
, hoid1
);
5598 t
.touch(cid
, hoid2
);
5599 t
.touch(cid
, hoid3
);
5600 r
= queue_transaction(store
, ch
, std::move(t
));
5601 created
.insert(hoid1
);
5602 created
.insert(hoid2
);
5603 created
.insert(hoid3
);
5607 vector
<ghobject_t
> objects
;
5608 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5611 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
5612 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
5613 ASSERT_TRUE(listed
.size() == created
.size());
5616 ghobject_t current
, next
;
5618 r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 60, &objects
,
5621 ASSERT_TRUE(sorted(objects
));
5622 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5623 i
!= objects
.end(); ++i
) {
5624 if (listed
.count(*i
))
5625 cerr
<< *i
<< " repeated" << std::endl
;
5628 if (objects
.size() < 50) {
5629 ASSERT_TRUE(next
.is_max());
5633 current
= next
.get_boundary();
5635 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
5636 ASSERT_TRUE(listed
.size() == created
.size());
5637 for (set
<ghobject_t
>::iterator i
= listed
.begin();
5640 ASSERT_TRUE(created
.count(*i
));
5643 for (set
<ghobject_t
>::iterator i
= created
.begin();
5646 ObjectStore::Transaction t
;
5648 r
= queue_transaction(store
, ch
, std::move(t
));
5651 ObjectStore::Transaction t
;
5652 t
.remove_collection(cid
);
5653 r
= queue_transaction(store
, ch
, std::move(t
));
5658 TEST_P(StoreTest
, OMapTest
) {
5660 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5661 auto ch
= store
->create_new_collection(cid
);
5664 ObjectStore::Transaction t
;
5665 t
.create_collection(cid
, 0);
5666 r
= queue_transaction(store
, ch
, std::move(t
));
5670 map
<string
, bufferlist
> attrs
;
5672 ObjectStore::Transaction t
;
5674 t
.omap_clear(cid
, hoid
);
5675 map
<string
, bufferlist
> start_set
;
5676 t
.omap_setkeys(cid
, hoid
, start_set
);
5677 r
= queue_transaction(store
, ch
, std::move(t
));
5681 for (int i
= 0; i
< 100; i
++) {
5683 std::cout
<< "On iteration " << i
<< std::endl
;
5685 ObjectStore::Transaction t
;
5687 map
<string
, bufferlist
> cur_attrs
;
5688 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5690 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5693 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5695 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5696 if (cur_attrs
.count(j
->first
) > 0) {
5697 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5700 ASSERT_EQ(correct
, true);
5702 ASSERT_EQ(attrs
.size(), cur_attrs
.size());
5705 snprintf(buf
, sizeof(buf
), "%d", i
);
5707 bufferptr
bp(buf
, strlen(buf
) + 1);
5709 map
<string
, bufferlist
> to_add
;
5710 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5711 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5712 t
.omap_setkeys(cid
, hoid
, to_add
);
5713 r
= queue_transaction(store
, ch
, std::move(t
));
5718 while (attrs
.size()) {
5720 std::cout
<< "removal: On iteration " << i
<< std::endl
;
5722 ObjectStore::Transaction t
;
5724 map
<string
, bufferlist
> cur_attrs
;
5725 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5727 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5730 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5732 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5733 if (cur_attrs
.count(j
->first
) > 0) {
5734 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5737 ASSERT_EQ(correct
, true);
5740 string to_remove
= attrs
.begin()->first
;
5741 t
.omap_rmkey(cid
, hoid
, to_remove
);
5742 r
= queue_transaction(store
, ch
, std::move(t
));
5745 attrs
.erase(to_remove
);
5752 bl1
.append("omap_header");
5753 ObjectStore::Transaction t
;
5754 t
.omap_setheader(cid
, hoid
, bl1
);
5755 r
= queue_transaction(store
, ch
, std::move(t
));
5757 t
= ObjectStore::Transaction();
5760 bl2
.append("value");
5761 map
<string
, bufferlist
> to_add
;
5762 to_add
.insert(pair
<string
, bufferlist
>("key", bl2
));
5763 t
.omap_setkeys(cid
, hoid
, to_add
);
5764 r
= queue_transaction(store
, ch
, std::move(t
));
5768 map
<string
, bufferlist
> cur_attrs
;
5769 r
= store
->omap_get(ch
, hoid
, &bl3
, &cur_attrs
);
5771 ASSERT_EQ(cur_attrs
.size(), size_t(1));
5772 ASSERT_TRUE(bl_eq(bl1
, bl3
));
5775 r
= store
->omap_get_keys(ch
, hoid
, &keys
);
5777 ASSERT_EQ(keys
.size(), size_t(1));
5780 // test omap_clear, omap_rmkey_range
5783 map
<string
,bufferlist
> to_set
;
5784 for (int n
=0; n
<10; ++n
) {
5785 to_set
[stringify(n
)].append("foo");
5789 ObjectStore::Transaction t
;
5790 t
.remove(cid
, hoid
);
5792 t
.omap_setheader(cid
, hoid
, h
);
5793 t
.omap_setkeys(cid
, hoid
, to_set
);
5794 r
= queue_transaction(store
, ch
, std::move(t
));
5798 ObjectStore::Transaction t
;
5799 t
.omap_rmkeyrange(cid
, hoid
, "3", "7");
5800 r
= queue_transaction(store
, ch
, std::move(t
));
5805 map
<string
,bufferlist
> m
;
5806 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5807 ASSERT_EQ(6u, hdr
.length());
5808 ASSERT_TRUE(m
.count("2"));
5809 ASSERT_TRUE(!m
.count("3"));
5810 ASSERT_TRUE(!m
.count("6"));
5811 ASSERT_TRUE(m
.count("7"));
5812 ASSERT_TRUE(m
.count("8"));
5813 //cout << m << std::endl;
5814 ASSERT_EQ(6u, m
.size());
5817 ObjectStore::Transaction t
;
5818 t
.omap_clear(cid
, hoid
);
5819 r
= queue_transaction(store
, ch
, std::move(t
));
5824 map
<string
,bufferlist
> m
;
5825 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5826 ASSERT_EQ(0u, hdr
.length());
5827 ASSERT_EQ(0u, m
.size());
5831 ObjectStore::Transaction t
;
5832 t
.remove(cid
, hoid
);
5833 t
.remove_collection(cid
);
5834 r
= queue_transaction(store
, ch
, std::move(t
));
5838 TEST_P(StoreTest
, OMapIterator
) {
5840 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5842 auto ch
= store
->create_new_collection(cid
);
5845 ObjectStore::Transaction t
;
5846 t
.create_collection(cid
, 0);
5847 r
= queue_transaction(store
, ch
, std::move(t
));
5851 map
<string
, bufferlist
> attrs
;
5853 ObjectStore::Transaction t
;
5855 t
.omap_clear(cid
, hoid
);
5856 map
<string
, bufferlist
> start_set
;
5857 t
.omap_setkeys(cid
, hoid
, start_set
);
5858 r
= queue_transaction(store
, ch
, std::move(t
));
5861 ObjectMap::ObjectMapIterator iter
;
5864 for (int i
= 0; i
< 100; i
++) {
5866 std::cout
<< "On iteration " << i
<< std::endl
;
5870 // FileStore may deadlock two active iterators over the same data
5871 iter
= ObjectMap::ObjectMapIterator();
5873 iter
= store
->get_omap_iterator(ch
, hoid
);
5874 for (iter
->seek_to_first(), count
=0; iter
->valid(); iter
->next(), count
++) {
5875 string key
= iter
->key();
5876 bufferlist value
= iter
->value();
5877 correct
= attrs
.count(key
) && (string(value
.c_str()) == string(attrs
[key
].c_str()));
5879 if (attrs
.count(key
) > 0) {
5880 std::cout
<< "key " << key
<< "in omap , " << value
.c_str() << " : " << attrs
[key
].c_str() << std::endl
;
5883 std::cout
<< "key " << key
<< "should not exists in omap" << std::endl
;
5885 ASSERT_EQ(correct
, true);
5887 ASSERT_EQ((int)attrs
.size(), count
);
5889 // FileStore may deadlock an active iterator vs queue_transaction
5890 iter
= ObjectMap::ObjectMapIterator();
5893 snprintf(buf
, sizeof(buf
), "%d", i
);
5895 bufferptr
bp(buf
, strlen(buf
) + 1);
5897 map
<string
, bufferlist
> to_add
;
5898 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5899 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5900 ObjectStore::Transaction t
;
5901 t
.omap_setkeys(cid
, hoid
, to_add
);
5902 r
= queue_transaction(store
, ch
, std::move(t
));
5906 iter
= store
->get_omap_iterator(ch
, hoid
);
5908 string bound_key
= "key-5";
5909 iter
->lower_bound(bound_key
);
5910 correct
= bound_key
<= iter
->key();
5912 std::cout
<< "lower bound, bound key is " << bound_key
<< " < iter key is " << iter
->key() << std::endl
;
5914 ASSERT_EQ(correct
, true);
5916 iter
->upper_bound(bound_key
);
5917 correct
= iter
->key() > bound_key
;
5919 std::cout
<< "upper bound, bound key is " << bound_key
<< " >= iter key is " << iter
->key() << std::endl
;
5921 ASSERT_EQ(correct
, true);
5923 // FileStore may deadlock an active iterator vs queue_transaction
5924 iter
= ObjectMap::ObjectMapIterator();
5926 ObjectStore::Transaction t
;
5927 t
.remove(cid
, hoid
);
5928 t
.remove_collection(cid
);
5929 r
= queue_transaction(store
, ch
, std::move(t
));
5934 TEST_P(StoreTest
, XattrTest
) {
5936 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5938 for (unsigned i
= 0; i
< 10000; ++i
) {
5942 for (unsigned i
= 0; i
< 10; ++i
) {
5946 auto ch
= store
->create_new_collection(cid
);
5948 ObjectStore::Transaction t
;
5949 t
.create_collection(cid
, 0);
5951 r
= queue_transaction(store
, ch
, std::move(t
));
5955 map
<string
, bufferlist
> attrs
;
5957 ObjectStore::Transaction t
;
5958 t
.setattr(cid
, hoid
, "attr1", small
);
5959 attrs
["attr1"] = small
;
5960 t
.setattr(cid
, hoid
, "attr2", big
);
5961 attrs
["attr2"] = big
;
5962 t
.setattr(cid
, hoid
, "attr3", small
);
5963 attrs
["attr3"] = small
;
5964 t
.setattr(cid
, hoid
, "attr1", small
);
5965 attrs
["attr1"] = small
;
5966 t
.setattr(cid
, hoid
, "attr4", big
);
5967 attrs
["attr4"] = big
;
5968 t
.setattr(cid
, hoid
, "attr3", big
);
5969 attrs
["attr3"] = big
;
5970 r
= queue_transaction(store
, ch
, std::move(t
));
5974 map
<string
, bufferptr
, less
<>> aset
;
5975 store
->getattrs(ch
, hoid
, aset
);
5976 ASSERT_EQ(aset
.size(), attrs
.size());
5977 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
5981 bl
.push_back(i
->second
);
5982 ASSERT_TRUE(attrs
[i
->first
] == bl
);
5986 ObjectStore::Transaction t
;
5987 t
.rmattr(cid
, hoid
, "attr2");
5988 attrs
.erase("attr2");
5989 r
= queue_transaction(store
, ch
, std::move(t
));
5994 store
->getattrs(ch
, hoid
, aset
);
5995 ASSERT_EQ(aset
.size(), attrs
.size());
5996 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
6000 bl
.push_back(i
->second
);
6001 ASSERT_TRUE(attrs
[i
->first
] == bl
);
6005 r
= store
->getattr(ch
, hoid
, "attr2", bp
);
6006 ASSERT_EQ(r
, -ENODATA
);
6008 r
= store
->getattr(ch
, hoid
, "attr3", bp
);
6012 ASSERT_TRUE(bl2
== attrs
["attr3"]);
6014 ObjectStore::Transaction t
;
6015 t
.remove(cid
, hoid
);
6016 t
.remove_collection(cid
);
6017 r
= queue_transaction(store
, ch
, std::move(t
));
6023 unsigned num_objects
,
6024 unsigned common_suffix_size
,
6027 coll_t
cid(spg_t(pg_t(0,52),shard_id_t::NO_SHARD
));
6028 coll_t
tid(spg_t(pg_t(1<<common_suffix_size
,52),shard_id_t::NO_SHARD
));
6029 auto ch
= store
->create_new_collection(cid
);
6030 auto tch
= store
->create_new_collection(tid
);
6033 ObjectStore::Transaction t
;
6034 t
.create_collection(cid
, common_suffix_size
);
6035 r
= queue_transaction(store
, ch
, std::move(t
));
6039 small
.append("small");
6041 ObjectStore::Transaction t
;
6042 for (uint32_t i
= 0; i
< (2 - (int)clones
)*num_objects
; ++i
) {
6043 stringstream objname
;
6044 objname
<< "obj" << i
;
6045 ghobject_t
a(hobject_t(
6049 i
<<common_suffix_size
,
6051 t
.write(cid
, a
, 0, small
.length(), small
,
6052 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6054 objname
<< "-clone";
6055 ghobject_t
b(hobject_t(
6059 i
<<common_suffix_size
,
6064 r
= queue_transaction(store
, ch
, std::move(t
));
6066 t
= ObjectStore::Transaction();
6069 r
= queue_transaction(store
, ch
, std::move(t
));
6073 ObjectStore::Transaction t
;
6074 t
.create_collection(tid
, common_suffix_size
+ 1);
6075 t
.split_collection(cid
, common_suffix_size
+1, 1<<common_suffix_size
, tid
);
6076 r
= queue_transaction(store
, ch
, std::move(t
));
6082 vector
<ghobject_t
> objects
;
6083 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6086 ASSERT_EQ(objects
.size(), num_objects
);
6087 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
6090 ASSERT_EQ(!!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
6094 r
= collection_list(store
, tch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6097 ASSERT_EQ(objects
.size(), num_objects
);
6098 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
6101 ASSERT_EQ(!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
6104 // merge them again!
6106 ObjectStore::Transaction t
;
6107 t
.merge_collection(tid
, cid
, common_suffix_size
);
6108 r
= queue_transaction(store
, ch
, std::move(t
));
6112 // check and clean up
6113 ObjectStore::Transaction t
;
6115 vector
<ghobject_t
> objects
;
6116 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6119 ASSERT_EQ(objects
.size(), num_objects
* 2); // both halves
6121 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
6127 r
= queue_transaction(store
, ch
, std::move(t
));
6129 t
= ObjectStore::Transaction();
6133 t
.remove_collection(cid
);
6134 r
= queue_transaction(store
, ch
, std::move(t
));
6138 ASSERT_TRUE(!store
->collection_exists(tid
));
6141 TEST_P(StoreTest
, ColSplitTest0
) {
6142 colsplittest(store
.get(), 10, 5, false);
6144 TEST_P(StoreTest
, ColSplitTest1
) {
6145 colsplittest(store
.get(), 10000, 11, false);
6147 TEST_P(StoreTest
, ColSplitTest1Clones
) {
6148 colsplittest(store
.get(), 10000, 11, true);
6150 TEST_P(StoreTest
, ColSplitTest2
) {
6151 colsplittest(store
.get(), 100, 7, false);
6153 TEST_P(StoreTest
, ColSplitTest2Clones
) {
6154 colsplittest(store
.get(), 100, 7, true);
6158 TEST_P(StoreTest
, ColSplitTest3
) {
6159 colsplittest(store
.get(), 100000, 25);
6163 void test_merge_skewed(ObjectStore
*store
,
6164 unsigned base
, unsigned bits
,
6165 unsigned anum
, unsigned bnum
)
6167 cout
<< __func__
<< " 0x" << std::hex
<< base
<< std::dec
6169 << " anum " << anum
<< " bnum " << bnum
<< std::endl
;
6171 make merge source pgs have radically different # of objects in them,
6172 which should trigger different splitting in filestore, and verify that
6173 post-merge all objects are accessible.
6176 coll_t
a(spg_t(pg_t(base
, 0), shard_id_t::NO_SHARD
));
6177 coll_t
b(spg_t(pg_t(base
| (1<<bits
), 0), shard_id_t::NO_SHARD
));
6179 auto cha
= store
->create_new_collection(a
);
6180 auto chb
= store
->create_new_collection(b
);
6182 ObjectStore::Transaction t
;
6183 t
.create_collection(a
, bits
+ 1);
6184 r
= queue_transaction(store
, cha
, std::move(t
));
6188 ObjectStore::Transaction t
;
6189 t
.create_collection(b
, bits
+ 1);
6190 r
= queue_transaction(store
, chb
, std::move(t
));
6195 small
.append("small");
6196 string suffix
= "ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooaaaaaaaaaa";
6197 set
<ghobject_t
> aobjects
, bobjects
;
6200 ObjectStore::Transaction t
;
6201 for (unsigned i
= 0; i
< 1000; ++i
) {
6202 string objname
= "a" + stringify(i
) + suffix
;
6203 ghobject_t
o(hobject_t(
6210 t
.write(a
, o
, 0, small
.length(), small
, 0);
6212 r
= queue_transaction(store
, cha
, std::move(t
));
6214 t
= ObjectStore::Transaction();
6217 r
= queue_transaction(store
, cha
, std::move(t
));
6222 ObjectStore::Transaction t
;
6223 for (unsigned i
= 0; i
< 10; ++i
) {
6224 string objname
= "b" + stringify(i
) + suffix
;
6225 ghobject_t
o(hobject_t(
6229 (i
<<(base
+1)) | base
| (1<<bits
),
6232 t
.write(b
, o
, 0, small
.length(), small
, 0);
6234 r
= queue_transaction(store
, chb
, std::move(t
));
6236 t
= ObjectStore::Transaction();
6239 r
= queue_transaction(store
, chb
, std::move(t
));
6245 ObjectStore::Transaction t
;
6246 t
.merge_collection(b
, a
, bits
);
6247 r
= queue_transaction(store
, cha
, std::move(t
));
6253 vector
<ghobject_t
> got
;
6254 collection_list(store
, cha
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6256 set
<ghobject_t
> gotset
;
6257 for (auto& o
: got
) {
6258 ASSERT_TRUE(aobjects
.count(o
) || bobjects
.count(o
));
6261 // check both listing and stat-ability (different code paths!)
6263 for (auto& o
: aobjects
) {
6264 ASSERT_TRUE(gotset
.count(o
));
6265 int r
= store
->stat(cha
, o
, &st
, false);
6268 for (auto& o
: bobjects
) {
6269 ASSERT_TRUE(gotset
.count(o
));
6270 int r
= store
->stat(cha
, o
, &st
, false);
6277 ObjectStore::Transaction t
;
6278 for (auto &o
: aobjects
) {
6281 r
= queue_transaction(store
, cha
, std::move(t
));
6285 ObjectStore::Transaction t
;
6286 for (auto &o
: bobjects
) {
6289 t
.remove_collection(a
);
6290 r
= queue_transaction(store
, cha
, std::move(t
));
6295 TEST_P(StoreTest
, MergeSkewed
) {
6296 if (string(GetParam()) != "filestore")
6299 // this is sufficient to exercise merges with different hashing levels
6300 test_merge_skewed(store
.get(), 0xf, 4, 10, 10000);
6301 test_merge_skewed(store
.get(), 0xf, 4, 10000, 10);
6304 // this covers a zillion variations that all boil down to the same thing
6305 for (unsigned base = 3; base < 0x1000; base *= 5) {
6308 for (bits = 0; t; t >>= 1) {
6311 for (unsigned b = bits; b < bits + 10; b += 3) {
6312 for (auto anum : { 10, 1000, 10000 }) {
6313 for (auto bnum : { 10, 1000, 10000 }) {
6317 test_merge_skewed(store.get(), base, b, anum, bnum);
6327 * This test tests adding two different groups
6328 * of objects, each with 1 common prefix and 1
6329 * different prefix. We then remove half
6330 * in order to verify that the merging correctly
6331 * stops at the common prefix subdir. See bug
6333 TEST_P(StoreTest
, TwoHash
) {
6336 auto ch
= store
->create_new_collection(cid
);
6338 ObjectStore::Transaction t
;
6339 t
.create_collection(cid
, 0);
6340 r
= queue_transaction(store
, ch
, std::move(t
));
6343 std::cout
<< "Making objects" << std::endl
;
6344 for (int i
= 0; i
< 360; ++i
) {
6345 ObjectStore::Transaction t
;
6349 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6352 o
.hobj
.set_hash((i
<< 16) | 0xB1);
6354 r
= queue_transaction(store
, ch
, std::move(t
));
6357 std::cout
<< "Removing half" << std::endl
;
6358 for (int i
= 1; i
< 8; ++i
) {
6359 ObjectStore::Transaction t
;
6362 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6364 r
= queue_transaction(store
, ch
, std::move(t
));
6367 std::cout
<< "Checking" << std::endl
;
6368 for (int i
= 1; i
< 8; ++i
) {
6369 ObjectStore::Transaction t
;
6371 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6373 bool exists
= store
->exists(ch
, o
);
6374 ASSERT_EQ(exists
, false);
6378 o
.hobj
.set_hash(0xA1);
6380 bool exists
= store
->exists(ch
, o
);
6381 ASSERT_EQ(exists
, true);
6383 std::cout
<< "Cleanup" << std::endl
;
6384 for (int i
= 0; i
< 360; ++i
) {
6385 ObjectStore::Transaction t
;
6387 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6390 o
.hobj
.set_hash((i
<< 16) | 0xB1);
6392 r
= queue_transaction(store
, ch
, std::move(t
));
6395 ObjectStore::Transaction t
;
6396 t
.remove_collection(cid
);
6397 r
= queue_transaction(store
, ch
, std::move(t
));
6401 TEST_P(StoreTest
, Rename
) {
6402 coll_t
cid(spg_t(pg_t(0, 2122),shard_id_t::NO_SHARD
));
6403 ghobject_t
srcoid(hobject_t("src_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6404 ghobject_t
dstoid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6408 auto ch
= store
->create_new_collection(cid
);
6411 ObjectStore::Transaction t
;
6412 t
.create_collection(cid
, 0);
6413 t
.write(cid
, srcoid
, 0, a
.length(), a
);
6414 r
= queue_transaction(store
, ch
, std::move(t
));
6417 ASSERT_TRUE(store
->exists(ch
, srcoid
));
6419 ObjectStore::Transaction t
;
6420 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
6421 t
.write(cid
, srcoid
, 0, b
.length(), b
);
6422 t
.setattr(cid
, srcoid
, "attr", b
);
6423 r
= queue_transaction(store
, ch
, std::move(t
));
6426 ASSERT_TRUE(store
->exists(ch
, srcoid
));
6427 ASSERT_TRUE(store
->exists(ch
, dstoid
));
6430 store
->read(ch
, srcoid
, 0, 3, bl
);
6431 ASSERT_TRUE(bl_eq(b
, bl
));
6432 store
->read(ch
, dstoid
, 0, 3, bl
);
6433 ASSERT_TRUE(bl_eq(a
, bl
));
6436 ObjectStore::Transaction t
;
6437 t
.remove(cid
, dstoid
);
6438 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
6439 r
= queue_transaction(store
, ch
, std::move(t
));
6442 ASSERT_TRUE(store
->exists(ch
, dstoid
));
6443 ASSERT_FALSE(store
->exists(ch
, srcoid
));
6446 store
->read(ch
, dstoid
, 0, 3, bl
);
6447 ASSERT_TRUE(bl_eq(b
, bl
));
6450 ObjectStore::Transaction t
;
6451 t
.remove(cid
, dstoid
);
6452 t
.remove_collection(cid
);
6453 r
= queue_transaction(store
, ch
, std::move(t
));
6458 TEST_P(StoreTest
, MoveRename
) {
6459 coll_t
cid(spg_t(pg_t(0, 212),shard_id_t::NO_SHARD
));
6460 ghobject_t
temp_oid(hobject_t("tmp_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6461 ghobject_t
oid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6462 auto ch
= store
->create_new_collection(cid
);
6465 ObjectStore::Transaction t
;
6466 t
.create_collection(cid
, 0);
6468 r
= queue_transaction(store
, ch
, std::move(t
));
6471 ASSERT_TRUE(store
->exists(ch
, oid
));
6472 bufferlist data
, attr
;
6473 map
<string
, bufferlist
> omap
;
6474 data
.append("data payload");
6475 attr
.append("attr value");
6476 omap
["omap_key"].append("omap value");
6478 ObjectStore::Transaction t
;
6479 t
.touch(cid
, temp_oid
);
6480 t
.write(cid
, temp_oid
, 0, data
.length(), data
);
6481 t
.setattr(cid
, temp_oid
, "attr", attr
);
6482 t
.omap_setkeys(cid
, temp_oid
, omap
);
6483 r
= queue_transaction(store
, ch
, std::move(t
));
6486 ASSERT_TRUE(store
->exists(ch
, temp_oid
));
6488 ObjectStore::Transaction t
;
6490 t
.collection_move_rename(cid
, temp_oid
, cid
, oid
);
6491 r
= queue_transaction(store
, ch
, std::move(t
));
6494 ASSERT_TRUE(store
->exists(ch
, oid
));
6495 ASSERT_FALSE(store
->exists(ch
, temp_oid
));
6498 r
= store
->read(ch
, oid
, 0, 1000, newdata
);
6500 ASSERT_TRUE(bl_eq(data
, newdata
));
6502 r
= store
->getattr(ch
, oid
, "attr", newattr
);
6504 ASSERT_TRUE(bl_eq(attr
, newattr
));
6506 keys
.insert("omap_key");
6507 map
<string
, bufferlist
> newomap
;
6508 r
= store
->omap_get_values(ch
, oid
, keys
, &newomap
);
6510 ASSERT_EQ(1u, newomap
.size());
6511 ASSERT_TRUE(newomap
.count("omap_key"));
6512 ASSERT_TRUE(bl_eq(omap
["omap_key"], newomap
["omap_key"]));
6515 ObjectStore::Transaction t
;
6517 t
.remove_collection(cid
);
6518 r
= queue_transaction(store
, ch
, std::move(t
));
6523 TEST_P(StoreTest
, BigRGWObjectName
) {
6524 coll_t
cid(spg_t(pg_t(0,12),shard_id_t::NO_SHARD
));
6527 "default.4106.50_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
6534 shard_id_t::NO_SHARD
);
6535 ghobject_t
oid2(oid
);
6536 oid2
.generation
= 17;
6537 ghobject_t
oidhead(oid
);
6538 oidhead
.generation
= ghobject_t::NO_GEN
;
6540 auto ch
= store
->create_new_collection(cid
);
6544 ObjectStore::Transaction t
;
6545 t
.create_collection(cid
, 0);
6546 t
.touch(cid
, oidhead
);
6547 t
.collection_move_rename(cid
, oidhead
, cid
, oid
);
6548 t
.touch(cid
, oidhead
);
6549 t
.collection_move_rename(cid
, oidhead
, cid
, oid2
);
6550 r
= queue_transaction(store
, ch
, std::move(t
));
6555 ObjectStore::Transaction t
;
6557 r
= queue_transaction(store
, ch
, std::move(t
));
6562 vector
<ghobject_t
> objects
;
6563 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6566 ASSERT_EQ(objects
.size(), 1u);
6567 ASSERT_EQ(objects
[0], oid2
);
6570 ASSERT_FALSE(store
->exists(ch
, oid
));
6573 ObjectStore::Transaction t
;
6574 t
.remove(cid
, oid2
);
6575 t
.remove_collection(cid
);
6576 r
= queue_transaction(store
, ch
, std::move(t
));
6582 TEST_P(StoreTest
, SetAllocHint
) {
6584 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, 0, ""));
6585 auto ch
= store
->create_new_collection(cid
);
6588 ObjectStore::Transaction t
;
6589 t
.create_collection(cid
, 0);
6591 r
= queue_transaction(store
, ch
, std::move(t
));
6595 ObjectStore::Transaction t
;
6596 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
6597 r
= queue_transaction(store
, ch
, std::move(t
));
6601 ObjectStore::Transaction t
;
6602 t
.remove(cid
, hoid
);
6603 r
= queue_transaction(store
, ch
, std::move(t
));
6607 ObjectStore::Transaction t
;
6608 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
6609 r
= queue_transaction(store
, ch
, std::move(t
));
6613 ObjectStore::Transaction t
;
6614 t
.remove_collection(cid
);
6615 r
= queue_transaction(store
, ch
, std::move(t
));
6620 TEST_P(StoreTest
, TryMoveRename
) {
6622 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6623 ghobject_t
hoid2(hobject_t("test_hint2", "", CEPH_NOSNAP
, 0, -1, ""));
6624 auto ch
= store
->create_new_collection(cid
);
6627 ObjectStore::Transaction t
;
6628 t
.create_collection(cid
, 0);
6629 r
= queue_transaction(store
, ch
, std::move(t
));
6633 ObjectStore::Transaction t
;
6634 t
.try_rename(cid
, hoid
, hoid2
);
6635 r
= queue_transaction(store
, ch
, std::move(t
));
6639 ObjectStore::Transaction t
;
6641 r
= queue_transaction(store
, ch
, std::move(t
));
6645 ObjectStore::Transaction t
;
6646 t
.try_rename(cid
, hoid
, hoid2
);
6647 r
= queue_transaction(store
, ch
, std::move(t
));
6651 ASSERT_EQ(store
->stat(ch
, hoid
, &st
), -ENOENT
);
6652 ASSERT_EQ(store
->stat(ch
, hoid2
, &st
), 0);
6655 #if defined(WITH_BLUESTORE)
6656 TEST_P(StoreTest
, BluestoreOnOffCSumTest
) {
6657 if (string(GetParam()) != "bluestore")
6659 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6660 g_conf().apply_changes(nullptr);
6664 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
6666 auto ch
= store
->open_collection(cid
);
6669 auto ch
= store
->create_new_collection(cid
);
6671 ObjectStore::Transaction t
;
6672 t
.create_collection(cid
, 0);
6673 cerr
<< "Creating collection " << cid
<< std::endl
;
6674 r
= queue_transaction(store
, ch
, std::move(t
));
6678 //write with csum enabled followed by read with csum disabled
6679 size_t block_size
= 64*1024;
6680 ObjectStore::Transaction t
;
6681 bufferlist bl
, orig
;
6682 bl
.append(std::string(block_size
, 'a'));
6684 t
.remove(cid
, hoid
);
6685 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6686 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6687 cerr
<< "Remove then create" << std::endl
;
6688 r
= queue_transaction(store
, ch
, std::move(t
));
6691 SetVal(g_conf(), "bluestore_csum_type", "none");
6692 g_conf().apply_changes(nullptr);
6695 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6696 ASSERT_EQ((int)block_size
, r
);
6697 ASSERT_TRUE(bl_eq(orig
, in
));
6701 //write with csum disabled followed by read with csum enabled
6703 size_t block_size
= 64*1024;
6704 ObjectStore::Transaction t
;
6705 bufferlist bl
, orig
;
6706 bl
.append(std::string(block_size
, 'a'));
6708 t
.remove(cid
, hoid
);
6709 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6710 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6711 cerr
<< "Remove then create" << std::endl
;
6712 r
= queue_transaction(store
, ch
, std::move(t
));
6715 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6716 g_conf().apply_changes(nullptr);
6719 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6720 ASSERT_EQ((int)block_size
, r
);
6721 ASSERT_TRUE(bl_eq(orig
, in
));
6724 //'mixed' non-overlapping writes to the same blob
6726 ObjectStore::Transaction t
;
6727 bufferlist bl
, orig
;
6728 size_t block_size
= 8000;
6729 bl
.append(std::string(block_size
, 'a'));
6731 t
.remove(cid
, hoid
);
6732 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6733 cerr
<< "Remove then create" << std::endl
;
6734 r
= queue_transaction(store
, ch
, std::move(t
));
6737 SetVal(g_conf(), "bluestore_csum_type", "none");
6738 g_conf().apply_changes(nullptr);
6740 ObjectStore::Transaction t2
;
6741 t2
.write(cid
, hoid
, block_size
*2, bl
.length(), bl
);
6742 cerr
<< "Append 'unprotected'" << std::endl
;
6743 r
= queue_transaction(store
, ch
, std::move(t2
));
6747 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6748 ASSERT_EQ((int)block_size
, r
);
6749 ASSERT_TRUE(bl_eq(orig
, in
));
6751 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6752 ASSERT_EQ((int)block_size
, r
);
6753 ASSERT_TRUE(bl_eq(orig
, in
));
6755 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6756 g_conf().apply_changes(nullptr);
6758 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6759 ASSERT_EQ((int)block_size
, r
);
6760 ASSERT_TRUE(bl_eq(orig
, in
));
6762 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6763 ASSERT_EQ((int)block_size
, r
);
6764 ASSERT_TRUE(bl_eq(orig
, in
));
6767 //partially blob overwrite under a different csum enablement mode
6769 ObjectStore::Transaction t
;
6770 bufferlist bl
, orig
, orig2
;
6771 size_t block_size0
= 0x10000;
6772 size_t block_size
= 9000;
6773 size_t block_size2
= 5000;
6774 bl
.append(std::string(block_size0
, 'a'));
6775 t
.remove(cid
, hoid
);
6776 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6777 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6778 cerr
<< "Remove then create" << std::endl
;
6779 r
= queue_transaction(store
, ch
, std::move(t
));
6782 SetVal(g_conf(), "bluestore_csum_type", "none");
6783 g_conf().apply_changes(nullptr);
6785 ObjectStore::Transaction t2
;
6787 bl
.append(std::string(block_size
, 'b'));
6788 t2
.write(cid
, hoid
, 0, bl
.length(), bl
);
6789 t2
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6790 cerr
<< "Overwrite with unprotected data" << std::endl
;
6791 r
= queue_transaction(store
, ch
, std::move(t2
));
6796 orig
.append( std::string(block_size0
- block_size
, 'a'));
6799 r
= store
->read(ch
, hoid
, 0, block_size0
, in
);
6800 ASSERT_EQ((int)block_size0
, r
);
6801 ASSERT_TRUE(bl_eq(orig
, in
));
6803 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6804 ASSERT_EQ((int)block_size
, r
);
6805 ASSERT_TRUE(bl_eq(orig2
, in
));
6807 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6808 g_conf().apply_changes(nullptr);
6810 ObjectStore::Transaction t3
;
6812 bl
.append(std::string(block_size2
, 'c'));
6813 t3
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6814 cerr
<< "Overwrite with protected data" << std::endl
;
6815 r
= queue_transaction(store
, ch
, std::move(t3
));
6820 orig
.append( std::string(block_size
- block_size2
, 'b'));
6821 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6822 ASSERT_EQ((int)block_size
, r
);
6823 ASSERT_TRUE(bl_eq(orig
, in
));
6827 ObjectStore::Transaction t
;
6828 t
.remove(cid
, hoid
);
6829 t
.remove_collection(cid
);
6830 cerr
<< "Cleaning" << std::endl
;
6831 r
= queue_transaction(store
, ch
, std::move(t
));
6837 INSTANTIATE_TEST_SUITE_P(
6843 #if defined(WITH_BLUESTORE)
6848 // Note: instantiate all stores to preserve store numbering order only
6849 INSTANTIATE_TEST_SUITE_P(
6851 StoreTestSpecificAUSize
,
6855 #if defined(WITH_BLUESTORE)
6860 // Note: instantiate all stores to preserve store numbering order only
6861 INSTANTIATE_TEST_SUITE_P(
6863 StoreTestOmapUpgrade
,
6867 #if defined(WITH_BLUESTORE)
6872 #if defined(WITH_BLUESTORE)
6873 INSTANTIATE_TEST_SUITE_P(
6875 StoreTestDeferredSetup
,
6880 void doMany4KWritesTest(ObjectStore
* store
,
6881 unsigned max_objects
,
6883 unsigned max_object_size
,
6884 unsigned max_write_size
,
6885 unsigned write_alignment
)
6887 MixedGenerator
gen(555);
6888 gen_type
rng(time(NULL
));
6889 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
6890 store_statfs_t res_stat
;
6892 SyntheticWorkloadState
test_obj(store
,
6900 for (unsigned i
= 0; i
< max_objects
; ++i
) {
6901 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
6904 for (unsigned i
= 0; i
< max_ops
; ++i
) {
6906 cerr
<< "Op " << i
<< std::endl
;
6907 test_obj
.print_internal_state();
6911 test_obj
.wait_for_done();
6912 test_obj
.statfs(res_stat
);
6913 if (!(res_stat
.data_stored
<= max_object_size
) ||
6914 !(res_stat
.allocated
<= max_object_size
)) {
6915 // this will provide more insight on the mismatch and
6916 // helps to avoid any races during stats collection
6917 test_obj
.fsck(false);
6918 // retrieving stats once again and assert if still broken
6919 test_obj
.statfs(res_stat
);
6920 ASSERT_LE(res_stat
.data_stored
, max_object_size
);
6921 ASSERT_LE(res_stat
.allocated
, max_object_size
);
6923 test_obj
.shutdown();
6926 TEST_P(StoreTestSpecificAUSize
, Many4KWritesTest
) {
6927 if (string(GetParam()) != "bluestore")
6930 cout
<< "SKIP: no deferred; assertions around res_stat.allocated don't apply"
6935 StartDeferred(0x10000);
6937 const unsigned max_object
= 4*1024*1024;
6938 doMany4KWritesTest(store
.get(), 1, 1000, max_object
, 4*1024, 0);
6941 TEST_P(StoreTestSpecificAUSize
, Many4KWritesNoCSumTest
) {
6942 if (string(GetParam()) != "bluestore")
6945 cout
<< "SKIP: no deferred; assertions around res_stat.allocated don't apply"
6949 StartDeferred(0x10000);
6950 SetVal(g_conf(), "bluestore_csum_type", "none");
6951 g_ceph_context
->_conf
.apply_changes(nullptr);
6952 const unsigned max_object
= 4*1024*1024;
6954 doMany4KWritesTest(store
.get(), 1, 1000, max_object
, 4*1024, 0 );
6957 TEST_P(StoreTestSpecificAUSize
, TooManyBlobsTest
) {
6958 if (string(GetParam()) != "bluestore")
6961 cout
<< "SKIP: no deferred; assertions around res_stat.allocated don't apply"
6965 StartDeferred(0x10000);
6966 const unsigned max_object
= 4*1024*1024;
6967 doMany4KWritesTest(store
.get(), 1, 1000, max_object
, 4*1024, 0);
6970 #if defined(WITH_BLUESTORE)
6971 void get_mempool_stats(uint64_t* total_bytes
, uint64_t* total_items
)
6973 uint64_t meta_allocated
= mempool::bluestore_cache_meta::allocated_bytes();
6974 uint64_t onode_allocated
= mempool::bluestore_cache_onode::allocated_bytes();
6975 uint64_t other_allocated
= mempool::bluestore_cache_other::allocated_bytes();
6977 uint64_t meta_items
= mempool::bluestore_cache_meta::allocated_items();
6978 uint64_t onode_items
= mempool::bluestore_cache_onode::allocated_items();
6979 uint64_t other_items
= mempool::bluestore_cache_other::allocated_items();
6980 cout
<< "meta(" << meta_allocated
<< "/" << meta_items
6981 << ") onode(" << onode_allocated
<< "/" << onode_items
6982 << ") other(" << other_allocated
<< "/" << other_items
6983 << ")" << std::endl
;
6984 *total_bytes
= meta_allocated
+ onode_allocated
+ other_allocated
;
6985 *total_items
= onode_items
;
6988 TEST_P(StoreTestSpecificAUSize
, OnodeSizeTracking
) {
6990 if (string(GetParam()) != "bluestore")
6993 size_t block_size
= 4096;
6994 StartDeferred(block_size
);
6995 SetVal(g_conf(), "bluestore_compression_mode", "none");
6996 SetVal(g_conf(), "bluestore_csum_type", "none");
6997 SetVal(g_conf(), "bluestore_cache_size_hdd", "400000000");
6998 SetVal(g_conf(), "bluestore_cache_size_ssd", "400000000");
6999 g_conf().apply_changes(nullptr);
7003 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
7004 size_t obj_size
= 4 * 1024 * 1024;
7005 uint64_t total_bytes
, total_bytes2
;
7006 uint64_t total_onodes
;
7007 get_mempool_stats(&total_bytes
, &total_onodes
);
7008 ASSERT_EQ(total_onodes
, 0u);
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
;
7019 bufferlist bl
, orig
, orig2
;
7021 bl
.append(std::string(obj_size
, 'a'));
7022 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7023 r
= queue_transaction(store
, ch
, std::move(t
));
7026 get_mempool_stats(&total_bytes
, &total_onodes
);
7027 ASSERT_NE(total_bytes
, 0u);
7028 ASSERT_EQ(total_onodes
, 1u);
7031 ObjectStore::Transaction t
;
7032 t
.truncate(cid
, hoid
, 0);
7033 r
= queue_transaction(store
, ch
, std::move(t
));
7037 for(size_t i
= 0; i
< 1; ++i
) {
7039 bl
.append(std::string(block_size
* (i
+1), 'a'));
7040 for( size_t j
= 0; j
< obj_size
; j
+= bl
.length()) {
7041 ObjectStore::Transaction t
;
7042 t
.write(cid
, hoid
, j
, bl
.length(), bl
);
7043 r
= queue_transaction(store
, ch
, std::move(t
));
7046 get_mempool_stats(&total_bytes2
, &total_onodes
);
7047 ASSERT_NE(total_bytes2
, 0u);
7048 ASSERT_EQ(total_onodes
, 1u);
7051 cout
<<" mempool dump:\n";
7052 JSONFormatter
f(true);
7053 f
.open_object_section("transaction");
7061 for (size_t i
= 0; i
< obj_size
; i
+= 0x1000) {
7062 store
->read(ch
, hoid
, i
, 0x1000, bl
);
7065 get_mempool_stats(&total_bytes
, &total_onodes
);
7066 ASSERT_NE(total_bytes
, 0u);
7067 ASSERT_EQ(total_onodes
, 1u);
7070 cout
<<" mempool dump:\n";
7071 JSONFormatter
f(true);
7072 f
.open_object_section("transaction");
7079 ObjectStore::Transaction t
;
7080 t
.remove(cid
, hoid
);
7081 t
.remove_collection(cid
);
7082 cerr
<< "Cleaning" << std::endl
;
7083 r
= queue_transaction(store
, ch
, std::move(t
));
7088 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwrite
) {
7090 if (string(GetParam()) != "bluestore")
7093 size_t block_size
= 4096;
7094 StartDeferred(block_size
);
7095 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
7096 g_conf().apply_changes(nullptr);
7100 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
7102 const PerfCounters
* logger
= store
->get_perf_counters();
7104 auto ch
= store
->create_new_collection(cid
);
7106 ObjectStore::Transaction t
;
7107 t
.create_collection(cid
, 0);
7108 r
= queue_transaction(store
, ch
, std::move(t
));
7112 ObjectStore::Transaction t
;
7115 bl
.append(std::string(block_size
* 2, 'a'));
7116 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7117 r
= queue_transaction(store
, ch
, std::move(t
));
7121 // overwrite at the beginning
7122 ObjectStore::Transaction t
;
7125 bl
.append(std::string(block_size
, 'b'));
7126 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7127 r
= queue_transaction(store
, ch
, std::move(t
));
7132 ObjectStore::Transaction t
;
7135 bl
.append(std::string(block_size
* 2, 'c'));
7136 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7137 r
= queue_transaction(store
, ch
, std::move(t
));
7141 // append with a gap
7142 ObjectStore::Transaction t
;
7145 bl
.append(std::string(block_size
* 2, 'd'));
7146 t
.write(cid
, hoid
, block_size
* 5, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7147 r
= queue_transaction(store
, ch
, std::move(t
));
7151 // We need to issue a read to trigger cache stat update that refresh
7152 // perf counters. additionally we need to wait some time for mempool
7153 // thread to update stats.
7155 bufferlist bl
, expected
;
7156 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7157 ASSERT_EQ(r
, (int)block_size
);
7158 expected
.append(string(block_size
, 'b'));
7159 ASSERT_TRUE(bl_eq(expected
, bl
));
7160 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7161 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
7165 ObjectStore::Transaction t
;
7168 bl
.append(std::string(block_size
* 2, 'e'));
7170 // Currently we are unable to reuse blob when overwriting in a single step
7171 t
.write(cid
, hoid
, block_size
* 6, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7172 r
= queue_transaction(store
, ch
, std::move(t
));
7176 // We need to issue a read to trigger cache stat update that refresh
7177 // perf counters. additionally we need to wait some time for mempool
7178 // thread to update stats.
7180 bufferlist bl
, expected
;
7181 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7182 ASSERT_EQ(r
, (int)block_size
);
7183 expected
.append(string(block_size
, 'b'));
7184 ASSERT_TRUE(bl_eq(expected
, bl
));
7185 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7186 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
7190 ObjectStore::Transaction t
;
7193 bl
.append(std::string(block_size
, 'f'));
7195 t
.write(cid
, hoid
, block_size
* 4, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7196 r
= queue_transaction(store
, ch
, std::move(t
));
7200 // we need to wait some time for mempool
7201 // thread to update stats to be able to check blob/extent numbers from
7205 bufferlist bl
, expected
;
7206 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7207 ASSERT_EQ(r
, (int)block_size
);
7208 expected
.append(string(block_size
, 'b'));
7209 ASSERT_TRUE(bl_eq(expected
, bl
));
7213 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7214 ASSERT_EQ(r
, (int)block_size
);
7215 expected
.append(string(block_size
, 'a'));
7216 ASSERT_TRUE(bl_eq(expected
, bl
));
7220 r
= store
->read(ch
, hoid
, block_size
* 2, block_size
* 2, bl
);
7221 ASSERT_EQ(r
, (int)block_size
* 2);
7222 expected
.append(string(block_size
* 2, 'c'));
7223 ASSERT_TRUE(bl_eq(expected
, bl
));
7227 r
= store
->read(ch
, hoid
, block_size
* 4, block_size
, bl
);
7228 ASSERT_EQ(r
, (int)block_size
);
7229 expected
.append(string(block_size
, 'f'));
7230 ASSERT_TRUE(bl_eq(expected
, bl
));
7234 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
, bl
);
7235 ASSERT_EQ(r
, (int)block_size
);
7236 expected
.append(string(block_size
, 'd'));
7237 ASSERT_TRUE(bl_eq(expected
, bl
));
7241 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
* 3, bl
);
7242 ASSERT_EQ(r
, (int)block_size
* 3);
7243 expected
.append(string(block_size
, 'd'));
7244 expected
.append(string(block_size
* 2, 'e'));
7245 ASSERT_TRUE(bl_eq(expected
, bl
));
7247 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7248 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
7252 ObjectStore::Transaction t
;
7253 t
.remove(cid
, hoid
);
7254 t
.remove_collection(cid
);
7255 cerr
<< "Cleaning" << std::endl
;
7256 r
= queue_transaction(store
, ch
, std::move(t
));
7261 TEST_P(StoreTestSpecificAUSize
, ZeroBlockDetectionSmallAppend
) {
7262 CephContext
*cct
= (new CephContext(CEPH_ENTITY_TYPE_CLIENT
))->get();
7263 if (string(GetParam()) != "bluestore" || !cct
->_conf
->bluestore_zero_block_detection
) {
7264 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7267 size_t block_size
= 65536;
7268 StartDeferred(block_size
);
7272 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7274 const PerfCounters
* logger
= store
->get_perf_counters();
7276 auto ch
= store
->create_new_collection(cid
);
7278 ObjectStore::Transaction t
;
7279 t
.create_collection(cid
, 0);
7280 r
= queue_transaction(store
, ch
, std::move(t
));
7285 ObjectStore::Transaction t
;
7288 bl
.append_zero(4096);
7290 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7291 r
= queue_transaction(store
, ch
, std::move(t
));
7293 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 1u);
7294 ASSERT_EQ(logger
->get(l_bluestore_write_small_bytes
), 4096u);
7295 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped
), 1u);
7296 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped_bytes
), 4096u);
7299 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
7301 ASSERT_TRUE(in
.is_zero());
7305 // [2] append non-zeros
7306 ObjectStore::Transaction t
;
7309 bl
.append(std::string(4096, 'c'));
7311 t
.write(cid
, hoid
, 4096, bl
.length(), bl
);
7312 r
= queue_transaction(store
, ch
, std::move(t
));
7314 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 2u);
7315 ASSERT_EQ(logger
->get(l_bluestore_write_small_bytes
), 4096u*2);
7316 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped
), 1u);
7317 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped_bytes
), 4096u);
7319 bufferlist in
, _exp
;
7320 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
7321 ASSERT_EQ(4096 * 2, r
);
7322 _exp
.append_zero(4096);
7324 ASSERT_TRUE(bl_eq(_exp
, in
));
7328 ObjectStore::Transaction t
;
7329 t
.remove(cid
, hoid
);
7330 t
.remove_collection(cid
);
7331 cerr
<< "Cleaning" << std::endl
;
7332 r
= queue_transaction(store
, ch
, std::move(t
));
7337 TEST_P(StoreTestSpecificAUSize
, ZeroBlockDetectionSmallOverwrite
) {
7338 CephContext
*cct
= (new CephContext(CEPH_ENTITY_TYPE_CLIENT
))->get();
7339 if (string(GetParam()) != "bluestore" || !cct
->_conf
->bluestore_zero_block_detection
) {
7340 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7343 GTEST_SKIP() << "smr, skipping";
7346 size_t block_size
= 65536;
7347 StartDeferred(block_size
);
7351 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7353 const PerfCounters
* logger
= store
->get_perf_counters();
7355 auto ch
= store
->create_new_collection(cid
);
7357 ObjectStore::Transaction t
;
7358 t
.create_collection(cid
, 0);
7359 r
= queue_transaction(store
, ch
, std::move(t
));
7364 // {setting up the scenario} append non-zeros
7365 ObjectStore::Transaction t
;
7368 bl
.append(std::string(4096, 'c'));
7370 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7371 r
= queue_transaction(store
, ch
, std::move(t
));
7373 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 1u);
7374 ASSERT_EQ(logger
->get(l_bluestore_write_small_bytes
), 4096u);
7375 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped
), 0u);
7376 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped_bytes
), 0u);
7378 bufferlist in
, _exp
;
7379 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
7382 ASSERT_TRUE(bl_eq(_exp
, in
));
7386 // [1] overwrite non-zeros with zeros
7387 ObjectStore::Transaction t
;
7390 bl
.append_zero(4096);
7392 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7393 r
= queue_transaction(store
, ch
, std::move(t
));
7395 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 2u);
7396 ASSERT_EQ(logger
->get(l_bluestore_write_small_bytes
), 4096u*2);
7397 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped
), 0u);
7398 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped_bytes
), 0u);
7401 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
7403 ASSERT_TRUE(in
.is_zero());
7407 // [2] overwrite zeros with non-zeros
7408 ObjectStore::Transaction t
;
7411 bl
.append(std::string(4096, 'c'));
7413 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7414 r
= queue_transaction(store
, ch
, std::move(t
));
7416 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 3u);
7417 ASSERT_EQ(logger
->get(l_bluestore_write_small_bytes
), 4096u*3);
7418 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped
), 0u);
7419 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped_bytes
), 0u);
7421 bufferlist in
, _exp
;
7422 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
7425 ASSERT_TRUE(bl_eq(_exp
, in
));
7429 ObjectStore::Transaction t
;
7430 t
.remove(cid
, hoid
);
7431 t
.remove_collection(cid
);
7432 cerr
<< "Cleaning" << std::endl
;
7433 r
= queue_transaction(store
, ch
, std::move(t
));
7438 TEST_P(StoreTestSpecificAUSize
, ZeroBlockDetectionBigAppend
) {
7439 CephContext
*cct
= (new CephContext(CEPH_ENTITY_TYPE_CLIENT
))->get();
7440 if (string(GetParam()) != "bluestore" || !cct
->_conf
->bluestore_zero_block_detection
) {
7441 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7444 size_t block_size
= 4096;
7445 StartDeferred(block_size
);
7449 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7451 const PerfCounters
* logger
= store
->get_perf_counters();
7453 auto ch
= store
->create_new_collection(cid
);
7455 ObjectStore::Transaction t
;
7456 t
.create_collection(cid
, 0);
7457 r
= queue_transaction(store
, ch
, std::move(t
));
7463 ObjectStore::Transaction t
;
7466 bl
.append_zero(block_size
* 2);
7468 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7469 r
= queue_transaction(store
, ch
, std::move(t
));
7471 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
7472 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), 4096u*2);
7473 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 0u);
7474 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_blobs
), 1u);
7475 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_bytes
), 4096u*2);
7478 r
= store
->read(ch
, hoid
, 0, block_size
* 8, in
);
7479 ASSERT_EQ(block_size
* 2, r
);
7480 ASSERT_TRUE(in
.is_zero());
7484 // [2] append non-zeros
7485 ObjectStore::Transaction t
;
7488 bl
.append(std::string(block_size
* 2, 'c'));
7490 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
);
7491 r
= queue_transaction(store
, ch
, std::move(t
));
7493 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 2u);
7494 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), 4096u*4);
7495 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 1u);
7496 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_blobs
), 1u);
7497 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_bytes
), 4096u*2);
7499 bufferlist in
, _exp
;
7500 r
= store
->read(ch
, hoid
, 0, block_size
* 8, in
);
7501 ASSERT_EQ(block_size
* 4, r
);
7502 _exp
.append_zero(block_size
* 2);
7504 ASSERT_TRUE(bl_eq(_exp
, in
));
7508 ObjectStore::Transaction t
;
7509 t
.remove(cid
, hoid
);
7510 t
.remove_collection(cid
);
7511 cerr
<< "Cleaning" << std::endl
;
7512 r
= queue_transaction(store
, ch
, std::move(t
));
7517 TEST_P(StoreTestSpecificAUSize
, ZeroBlockDetectionBigOverwrite
) {
7518 CephContext
*cct
= (new CephContext(CEPH_ENTITY_TYPE_CLIENT
))->get();
7519 if (string(GetParam()) != "bluestore" || !cct
->_conf
->bluestore_zero_block_detection
) {
7520 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7523 GTEST_SKIP() << "smr, skipping";
7526 size_t block_size
= 4096;
7527 StartDeferred(block_size
);
7531 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7533 const PerfCounters
* logger
= store
->get_perf_counters();
7535 auto ch
= store
->create_new_collection(cid
);
7537 ObjectStore::Transaction t
;
7538 t
.create_collection(cid
, 0);
7539 r
= queue_transaction(store
, ch
, std::move(t
));
7544 // {setting up the scenario} append non-zeros
7545 ObjectStore::Transaction t
;
7548 bl
.append(std::string(block_size
* 2, 'c'));
7550 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7551 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
), 4096u*2);
7555 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 1u);
7556 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_blobs
), 0u);
7557 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_bytes
), 0u);
7559 bufferlist in
, _exp
;
7560 r
= store
->read(ch
, hoid
, 0, block_size
* 8, in
);
7561 ASSERT_EQ(block_size
* 2, r
);
7563 ASSERT_TRUE(bl_eq(_exp
, in
));
7567 // [1] overwrite non-zeros with zeros
7568 ObjectStore::Transaction t
;
7571 bl
.append_zero(block_size
* 2);
7573 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7574 r
= queue_transaction(store
, ch
, std::move(t
));
7576 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 2u);
7577 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), 4096u*4);
7578 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 1u);
7579 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_blobs
), 1u);
7580 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_bytes
), 4096u*2);
7583 r
= store
->read(ch
, hoid
, 0, block_size
* 8, in
);
7584 ASSERT_EQ(block_size
* 2, r
);
7585 ASSERT_TRUE(in
.is_zero());
7589 // [2] overwrite zeros with non-zeros
7590 ObjectStore::Transaction t
;
7593 bl
.append(std::string(block_size
* 2, 'c'));
7595 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7596 r
= queue_transaction(store
, ch
, std::move(t
));
7598 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 3u);
7599 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), 4096u*6);
7600 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 2u);
7601 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_blobs
), 1u);
7602 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_bytes
), 4096u*2);
7604 bufferlist in
, _exp
;
7605 r
= store
->read(ch
, hoid
, 0, block_size
* 8, in
);
7606 ASSERT_EQ(block_size
* 2, r
);
7608 ASSERT_TRUE(bl_eq(_exp
, in
));
7612 ObjectStore::Transaction t
;
7613 t
.remove(cid
, hoid
);
7614 t
.remove_collection(cid
);
7615 cerr
<< "Cleaning" << std::endl
;
7616 r
= queue_transaction(store
, ch
, std::move(t
));
7621 TEST_P(StoreTestSpecificAUSize
, DeferredOnBigOverwrite
) {
7623 if (string(GetParam()) != "bluestore")
7626 cout
<< "SKIP: no deferred" << std::endl
;
7630 size_t block_size
= 4096;
7631 StartDeferred(block_size
);
7632 SetVal(g_conf(), "bluestore_max_blob_size", "131072");
7633 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
7635 g_conf().apply_changes(nullptr);
7639 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7640 ghobject_t
hoid2(hobject_t("test2", "", CEPH_NOSNAP
, 0, -1, ""));
7642 PerfCounters
* logger
= const_cast<PerfCounters
*>(store
->get_perf_counters());
7644 auto ch
= store
->create_new_collection(cid
);
7646 ObjectStore::Transaction t
;
7647 t
.create_collection(cid
, 0);
7648 r
= queue_transaction(store
, ch
, std::move(t
));
7652 ObjectStore::Transaction t
;
7655 bl
.append(std::string(block_size
* 2, 'c'));
7656 bl2
.append(std::string(block_size
* 3, 'd'));
7658 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7659 t
.set_alloc_hint(cid
, hoid2
, block_size
* 4, block_size
* 4,
7660 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
);
7661 t
.write(cid
, hoid2
, 0, bl2
.length(), bl2
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7662 r
= queue_transaction(store
, ch
, std::move(t
));
7665 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 2u);
7666 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 0u);
7669 struct store_statfs_t statfs
;
7670 int r
= store
->statfs(&statfs
);
7672 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 5);
7673 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 5);
7676 // overwrite at the beginning, 4K alignment
7678 ObjectStore::Transaction t
;
7681 bl
.append(std::string(block_size
, 'b'));
7682 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7683 r
= queue_transaction(store
, ch
, std::move(t
));
7686 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 3u);
7687 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
7690 bufferlist bl
, expected
;
7691 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7692 ASSERT_EQ(r
, (int)block_size
);
7693 expected
.append(string(block_size
, 'b'));
7694 ASSERT_TRUE(bl_eq(expected
, bl
));
7697 bufferlist bl
, expected
;
7698 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7699 ASSERT_EQ(r
, (int)block_size
);
7700 expected
.append(string(block_size
, 'c'));
7701 ASSERT_TRUE(bl_eq(expected
, bl
));
7704 // overwrite at the end, 4K alignment
7706 ObjectStore::Transaction t
;
7709 bl
.append(std::string(block_size
, 'g'));
7710 t
.write(cid
, hoid
, block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7711 r
= queue_transaction(store
, ch
, std::move(t
));
7714 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 4u);
7715 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 2u);
7718 bufferlist bl
, expected
;
7719 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7720 ASSERT_EQ(r
, (int)block_size
);
7721 expected
.append(string(block_size
, 'b'));
7722 ASSERT_TRUE(bl_eq(expected
, bl
));
7725 bufferlist bl
, expected
;
7726 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7727 ASSERT_EQ(r
, (int)block_size
);
7728 expected
.append(string(block_size
, 'g'));
7729 ASSERT_TRUE(bl_eq(expected
, bl
));
7732 // overwrite at 4K, 12K alignment
7734 ObjectStore::Transaction t
;
7737 bl
.append(std::string(block_size
, 'e'));
7738 t
.write(cid
, hoid2
, block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7739 r
= queue_transaction(store
, ch
, std::move(t
));
7742 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 5u);
7743 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 3u);
7745 // makes sure deferred has been submitted
7746 // and do all the checks again
7747 sleep(g_conf().get_val
<double>("bluestore_max_defer_interval") + 2);
7749 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 5u);
7750 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 3u);
7753 bufferlist bl
, expected
;
7754 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7755 ASSERT_EQ(r
, (int)block_size
);
7756 expected
.append(string(block_size
, 'b'));
7757 ASSERT_TRUE(bl_eq(expected
, bl
));
7760 bufferlist bl
, expected
;
7761 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7762 ASSERT_EQ(r
, (int)block_size
);
7763 expected
.append(string(block_size
, 'g'));
7764 ASSERT_TRUE(bl_eq(expected
, bl
));
7767 bufferlist bl
, expected
;
7768 r
= store
->read(ch
, hoid2
, 0, block_size
, bl
);
7769 ASSERT_EQ(r
, (int)block_size
);
7770 expected
.append(string(block_size
, 'd'));
7771 ASSERT_TRUE(bl_eq(expected
, bl
));
7774 bufferlist bl
, expected
;
7775 r
= store
->read(ch
, hoid2
, block_size
, block_size
, bl
);
7776 ASSERT_EQ(r
, (int)block_size
);
7777 expected
.append(string(block_size
, 'e'));
7778 ASSERT_TRUE(bl_eq(expected
, bl
));
7781 bufferlist bl
, expected
;
7782 r
= store
->read(ch
, hoid2
, block_size
* 2, block_size
, bl
);
7783 ASSERT_EQ(r
, (int)block_size
);
7784 expected
.append(string(block_size
, 'd'));
7785 ASSERT_TRUE(bl_eq(expected
, bl
));
7789 struct store_statfs_t statfs
;
7790 int r
= store
->statfs(&statfs
);
7792 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 5);
7793 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 5);
7795 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
7796 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
7799 ObjectStore::Transaction t
;
7800 t
.remove(cid
, hoid
);
7801 t
.remove(cid
, hoid2
);
7802 r
= queue_transaction(store
, ch
, std::move(t
));
7807 ObjectStore::Transaction t
;
7809 bl
.append(std::string(block_size
* 2, 'f'));
7811 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7812 r
= queue_transaction(store
, ch
, std::move(t
));
7815 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 6u);
7816 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 3u);
7819 ObjectStore::Transaction t
;
7820 t
.zero(cid
, hoid
, 0, 100);
7821 r
= queue_transaction(store
, ch
, std::move(t
));
7825 bufferlist bl
, expected
;
7826 r
= store
->read(ch
, hoid
, 0, 100, bl
);
7827 ASSERT_EQ(r
, (int)100);
7828 expected
.append(string(100, 0));
7829 ASSERT_TRUE(bl_eq(expected
, bl
));
7832 bufferlist bl
, expected
;
7833 r
= store
->read(ch
, hoid
, 100, block_size
* 2 - 100, bl
);
7834 ASSERT_EQ(r
, (int)block_size
* 2 - 100);
7835 expected
.append(string(block_size
* 2 - 100, 'f'));
7836 ASSERT_TRUE(bl_eq(expected
, bl
));
7840 struct store_statfs_t statfs
;
7841 int r
= store
->statfs(&statfs
);
7843 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 2 - 100);
7844 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 2);
7846 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7847 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
7850 ObjectStore::Transaction t
;
7852 bl
.append(std::string(block_size
, 'g'));
7854 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7855 r
= queue_transaction(store
, ch
, std::move(t
));
7858 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 7u);
7859 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 4u);
7861 bufferlist bl
, expected
;
7862 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7863 ASSERT_EQ(r
, (int)block_size
);
7864 expected
.append(string(block_size
, 'g'));
7865 ASSERT_TRUE(bl_eq(expected
, bl
));
7868 bufferlist bl
, expected
;
7869 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7870 ASSERT_EQ(r
, (int)block_size
);
7871 expected
.append(string(block_size
, 'f'));
7872 ASSERT_TRUE(bl_eq(expected
, bl
));
7876 struct store_statfs_t statfs
;
7877 int r
= store
->statfs(&statfs
);
7879 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 2);
7880 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 2);
7882 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7883 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
7885 // check whether full overwrite bypass deferred
7887 ObjectStore::Transaction t
;
7889 bl
.append(std::string(block_size
* 2, 'h'));
7891 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7892 r
= queue_transaction(store
, ch
, std::move(t
));
7895 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 8u);
7896 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 4u);
7899 bufferlist bl
, expected
;
7900 r
= store
->read(ch
, hoid
, 0, block_size
* 2, bl
);
7901 ASSERT_EQ(r
, (int)block_size
* 2);
7902 expected
.append(string(block_size
* 2, 'h'));
7903 ASSERT_TRUE(bl_eq(expected
, bl
));
7907 struct store_statfs_t statfs
;
7908 int r
= store
->statfs(&statfs
);
7910 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 2);
7911 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 2);
7915 ObjectStore::Transaction t
;
7916 t
.remove(cid
, hoid
);
7917 t
.remove(cid
, hoid2
);
7918 r
= queue_transaction(store
, ch
, std::move(t
));
7923 ObjectStore::Transaction t
;
7925 bl
.append(std::string(block_size
* 32, 'a'));
7927 // this will create two 128K aligned blobs
7928 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7929 t
.write(cid
, hoid
, bl
.length(), bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7930 r
= queue_transaction(store
, ch
, std::move(t
));
7933 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 10u);
7934 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 4u);
7936 // check whether overwrite (less than prefer_deferred_size) partially overlapping two adjacent blobs goes
7939 ObjectStore::Transaction t
;
7941 bl
.append(std::string(block_size
* 3, 'b'));
7943 t
.write(cid
, hoid
, 0x20000 - block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7944 r
= queue_transaction(store
, ch
, std::move(t
));
7947 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 11u);
7948 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 6u);
7951 bufferlist bl
, expected
;
7952 r
= store
->read(ch
, hoid
, 0, 0x20000 - block_size
, bl
);
7953 ASSERT_EQ(r
, 0x20000 - block_size
);
7954 expected
.append(string(r
, 'a'));
7955 ASSERT_TRUE(bl_eq(expected
, bl
));
7958 r
= store
->read(ch
, hoid
, 0x20000 - block_size
, block_size
* 3, bl
);
7959 ASSERT_EQ(r
, 3 * block_size
);
7960 expected
.append(string(r
, 'b'));
7961 ASSERT_TRUE(bl_eq(expected
, bl
));
7964 r
= store
->read(ch
, hoid
, 0x20000 + 2 * block_size
, block_size
* 30, bl
);
7965 ASSERT_EQ(r
, 30 * block_size
);
7966 expected
.append(string(r
, 'a'));
7967 ASSERT_TRUE(bl_eq(expected
, bl
));
7972 struct store_statfs_t statfs
;
7973 int r
= store
->statfs(&statfs
);
7975 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 64);
7976 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 64);
7979 // check whether overwrite (larger than prefer_deferred_size) partially
7980 // overlapping two adjacent blobs goes deferred
7982 ObjectStore::Transaction t
;
7984 bl
.append(std::string(block_size
* 30, 'c'));
7986 t
.write(cid
, hoid
, 0x10000 + block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7987 r
= queue_transaction(store
, ch
, std::move(t
));
7991 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 12u);
7992 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 8u);
7995 bufferlist bl
, expected
;
7996 r
= store
->read(ch
, hoid
, 0, 0x11000, bl
);
7997 ASSERT_EQ(r
, 0x11000);
7998 expected
.append(string(r
, 'a'));
7999 ASSERT_TRUE(bl_eq(expected
, bl
));
8002 r
= store
->read(ch
, hoid
, 0x11000, block_size
* 30, bl
);
8003 ASSERT_EQ(r
, block_size
* 30);
8004 expected
.append(string(r
, 'c'));
8005 ASSERT_TRUE(bl_eq(expected
, bl
));
8008 r
= store
->read(ch
, hoid
, block_size
* 47, 0x10000 + block_size
, bl
);
8009 ASSERT_EQ(r
, 0x10000 + block_size
);
8010 expected
.append(string(r
, 'a'));
8011 ASSERT_TRUE(bl_eq(expected
, bl
));
8016 struct store_statfs_t statfs
;
8017 int r
= store
->statfs(&statfs
);
8019 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 64);
8020 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 64);
8024 // check whether overwrite (prefer_deferred_size < 120K < 2 * prefer_defer_size) partially
8025 // overlapping two adjacent blobs goes partly deferred
8027 ObjectStore::Transaction t
;
8029 bl
.append(std::string(block_size
* 30, 'e'));
8031 t
.write(cid
, hoid
, 0x20000 - block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8032 r
= queue_transaction(store
, ch
, std::move(t
));
8036 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
8037 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
8038 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), 1u);
8039 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
), block_size
);
8042 struct store_statfs_t statfs
;
8043 int r
= store
->statfs(&statfs
);
8045 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 64);
8046 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 64);
8050 ObjectStore::Transaction t
;
8051 t
.remove(cid
, hoid
);
8052 t
.remove(cid
, hoid2
);
8053 t
.remove_collection(cid
);
8054 cerr
<< "Cleaning" << std::endl
;
8055 r
= queue_transaction(store
, ch
, std::move(t
));
8060 TEST_P(StoreTestSpecificAUSize
, DeferredOnBigOverwrite2
) {
8062 if (string(GetParam()) != "bluestore")
8065 cout
<< "SKIP: no deferred" << std::endl
;
8069 size_t block_size
= 4096;
8070 StartDeferred(block_size
);
8071 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8072 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
8074 g_conf().apply_changes(nullptr);
8078 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
8080 PerfCounters
* logger
= const_cast<PerfCounters
*>(store
->get_perf_counters());
8082 auto ch
= store
->create_new_collection(cid
);
8084 ObjectStore::Transaction t
;
8085 t
.create_collection(cid
, 0);
8086 r
= queue_transaction(store
, ch
, std::move(t
));
8090 ObjectStore::Transaction t
;
8093 bl
.append(std::string(128 * 1024, 'c'));
8095 t
.write(cid
, hoid
, 0x1000, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8096 r
= queue_transaction(store
, ch
, std::move(t
));
8098 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
8099 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
8100 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 3u);
8101 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 0u);
8102 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), 0u);
8103 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
), 0);
8108 ObjectStore::Transaction t
;
8111 bl
.append(std::string(128 * 1024, 'c'));
8113 t
.write(cid
, hoid
, 0x2000, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8114 r
= queue_transaction(store
, ch
, std::move(t
));
8117 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
8118 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
8119 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 3u);
8120 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
8121 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), 1u);
8122 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
), 57344);
8126 ObjectStore::Transaction t
;
8127 t
.remove(cid
, hoid
);
8128 t
.remove(cid
, hoid
);
8129 t
.remove_collection(cid
);
8130 cerr
<< "Cleaning" << std::endl
;
8131 r
= queue_transaction(store
, ch
, std::move(t
));
8136 TEST_P(StoreTestSpecificAUSize
, DeferredOnBigOverwrite3
) {
8138 if (string(GetParam()) != "bluestore")
8141 cout
<< "SKIP: no deferred" << std::endl
;
8145 size_t block_size
= 4096;
8146 StartDeferred(block_size
);
8147 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8148 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
8150 g_conf().apply_changes(nullptr);
8154 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
8156 PerfCounters
* logger
= const_cast<PerfCounters
*>(store
->get_perf_counters());
8158 auto ch
= store
->create_new_collection(cid
);
8160 ObjectStore::Transaction t
;
8161 t
.create_collection(cid
, 0);
8162 r
= queue_transaction(store
, ch
, std::move(t
));
8168 ObjectStore::Transaction t
;
8171 bl
.append(std::string(4096 * 1024, 'c'));
8173 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8174 r
= queue_transaction(store
, ch
, std::move(t
));
8177 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
8178 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
8179 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 64u);
8180 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 0u);
8181 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), 0u);
8182 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
), 0u);
8186 ObjectStore::Transaction t
;
8189 bl
.append(std::string(4096 * 1024, 'c'));
8191 t
.write(cid
, hoid
, 0x1000, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8192 r
= queue_transaction(store
, ch
, std::move(t
));
8195 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
8196 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
8197 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 65u);
8198 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
8199 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), 1u);
8200 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
), 61440);
8203 ObjectStore::Transaction t
;
8204 t
.remove(cid
, hoid
);
8205 t
.remove_collection(cid
);
8206 cerr
<< "Cleaning" << std::endl
;
8207 r
= queue_transaction(store
, ch
, std::move(t
));
8212 TEST_P(StoreTestSpecificAUSize
, DeferredDifferentChunks
) {
8214 if (string(GetParam()) != "bluestore")
8217 cout
<< "SKIP: no deferred" << std::endl
;
8221 size_t alloc_size
= 4096;
8222 size_t large_object_size
= 1 * 1024 * 1024;
8223 size_t prefer_deferred_size
= 65536;
8224 StartDeferred(alloc_size
);
8225 SetVal(g_conf(), "bluestore_max_blob_size", "131072");
8226 SetVal(g_conf(), "bluestore_prefer_deferred_size",
8227 stringify(prefer_deferred_size
).c_str());
8228 g_conf().apply_changes(nullptr);
8232 const PerfCounters
* logger
= store
->get_perf_counters();
8233 size_t exp_bluestore_write_big
= 0;
8234 size_t exp_bluestore_write_big_deferred
= 0;
8236 ObjectStore::CollectionHandle ch
= store
->create_new_collection(cid
);
8238 ObjectStore::Transaction t
;
8239 t
.create_collection(cid
, 0);
8240 r
= queue_transaction(store
, ch
, std::move(t
));
8243 for (size_t expected_write_size
= 1024; expected_write_size
<= prefer_deferred_size
; expected_write_size
*= 2) {
8244 //create object with hint
8245 ghobject_t
hoid(hobject_t("test-"+to_string(expected_write_size
), "", CEPH_NOSNAP
, 0, -1, ""));
8247 ObjectStore::Transaction t
;
8249 t
.set_alloc_hint(cid
, hoid
, large_object_size
, expected_write_size
,
8250 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
|
8251 CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY
);
8252 r
= queue_transaction(store
, ch
, std::move(t
));
8258 ObjectStore::Transaction t
;
8260 bl
.append(std::string(large_object_size
, 'h'));
8261 t
.write(cid
, hoid
, 0, bl
.length(), bl
,
8262 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8263 r
= queue_transaction(store
, ch
, std::move(t
));
8264 ++exp_bluestore_write_big
;
8267 ASSERT_EQ(logger
->get(l_bluestore_write_big
), exp_bluestore_write_big
);
8268 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), exp_bluestore_write_big_deferred
);
8270 // check whether write will properly use deferred
8272 ObjectStore::Transaction t
;
8274 bl
.append(std::string(alloc_size
+ 2, 'z'));
8275 t
.write(cid
, hoid
, large_object_size
- 2 * alloc_size
- 1, bl
.length(), bl
,
8276 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8277 r
= queue_transaction(store
, ch
, std::move(t
));
8278 ++exp_bluestore_write_big
;
8279 if (expected_write_size
< prefer_deferred_size
)
8280 ++exp_bluestore_write_big_deferred
;
8283 ASSERT_EQ(logger
->get(l_bluestore_write_big
), exp_bluestore_write_big
);
8284 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), exp_bluestore_write_big_deferred
);
8288 ch
= store
->open_collection(cid
);
8290 for (size_t expected_write_size
= 1024; expected_write_size
<= 65536; expected_write_size
*= 2) {
8291 ghobject_t
hoid(hobject_t("test-"+to_string(expected_write_size
), "", CEPH_NOSNAP
, 0, -1, ""));
8293 bufferlist bl
, expected
;
8294 r
= store
->read(ch
, hoid
, 0, large_object_size
, bl
);
8295 ASSERT_EQ(r
, large_object_size
);
8296 expected
.append(string(large_object_size
- 2 * alloc_size
- 1, 'h'));
8297 expected
.append(string(alloc_size
+ 2, 'z'));
8298 expected
.append(string(alloc_size
- 1, 'h'));
8299 ASSERT_TRUE(bl_eq(expected
, bl
));
8303 ObjectStore::Transaction t
;
8304 for (size_t expected_write_size
= 1024; expected_write_size
<= 65536; expected_write_size
*= 2) {
8305 ghobject_t
hoid(hobject_t("test-"+to_string(expected_write_size
), "", CEPH_NOSNAP
, 0, -1, ""));
8306 t
.remove(cid
, hoid
);
8308 t
.remove_collection(cid
);
8309 cerr
<< "Cleaning" << std::endl
;
8310 r
= queue_transaction(store
, ch
, std::move(t
));
8315 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwriteReverse
) {
8317 if (string(GetParam()) != "bluestore")
8320 cout
<< "SKIP: no overwrite" << std::endl
;
8324 size_t block_size
= 4096;
8325 StartDeferred(block_size
);
8326 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8327 g_conf().apply_changes(nullptr);
8331 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
8333 auto ch
= store
->create_new_collection(cid
);
8335 const PerfCounters
* logger
= store
->get_perf_counters();
8337 ObjectStore::Transaction t
;
8338 t
.create_collection(cid
, 0);
8339 r
= queue_transaction(store
, ch
, std::move(t
));
8343 ObjectStore::Transaction t
;
8346 bl
.append(std::string(block_size
* 2, 'a'));
8347 t
.write(cid
, hoid
, block_size
* 10, bl
.length(), bl
,
8348 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8349 r
= queue_transaction(store
, ch
, std::move(t
));
8354 ObjectStore::Transaction t
;
8357 bl
.append(std::string(block_size
, 'b'));
8358 t
.write(cid
, hoid
, block_size
* 9, bl
.length(), bl
,
8359 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8360 r
= queue_transaction(store
, ch
, std::move(t
));
8364 // We need to issue a read to trigger cache stat update that refresh
8365 // perf counters. additionally we need to wait some time for mempool
8366 // thread to update stats.
8368 bufferlist bl
, expected
;
8369 r
= store
->read(ch
, hoid
, block_size
* 9, block_size
* 2, bl
);
8370 ASSERT_EQ(r
, (int)block_size
* 2);
8371 expected
.append(string(block_size
, 'b'));
8372 expected
.append(string(block_size
, 'a'));
8373 ASSERT_TRUE(bl_eq(expected
, bl
));
8374 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
8375 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
8380 // prepend existing with a gap
8381 ObjectStore::Transaction t
;
8384 bl
.append(std::string(block_size
, 'c'));
8385 t
.write(cid
, hoid
, block_size
* 7, bl
.length(), bl
,
8386 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8387 r
= queue_transaction(store
, ch
, std::move(t
));
8391 // We need to issue a read to trigger cache stat update that refresh
8392 // perf counters. additionally we need to wait some time for mempool
8393 // thread to update stats.
8395 bufferlist bl
, expected
;
8396 r
= store
->read(ch
, hoid
, block_size
* 7, block_size
* 3, bl
);
8397 ASSERT_EQ(r
, (int)block_size
* 3);
8398 expected
.append(string(block_size
, 'c'));
8399 expected
.append(string(block_size
, 0));
8400 expected
.append(string(block_size
, 'b'));
8401 ASSERT_TRUE(bl_eq(expected
, bl
));
8402 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
8403 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
8407 // append after existing with a gap
8408 ObjectStore::Transaction t
;
8411 bl
.append(std::string(block_size
, 'd'));
8412 t
.write(cid
, hoid
, block_size
* 13, bl
.length(), bl
,
8413 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8414 r
= queue_transaction(store
, ch
, std::move(t
));
8418 // We need to issue a read to trigger cache stat update that refresh
8419 // perf counters. additionally we need to wait some time for mempool
8420 // thread to update stats.
8422 bufferlist bl
, expected
;
8423 r
= store
->read(ch
, hoid
, block_size
* 11, block_size
* 3, bl
);
8424 ASSERT_EQ(r
, (int)block_size
* 3);
8425 expected
.append(string(block_size
, 'a'));
8426 expected
.append(string(block_size
, 0));
8427 expected
.append(string(block_size
, 'd'));
8428 ASSERT_TRUE(bl_eq(expected
, bl
));
8429 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
8430 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
8434 // append twice to the next max_blob slot
8435 ObjectStore::Transaction t
;
8438 bl
.append(std::string(block_size
, 'e'));
8439 t
.write(cid
, hoid
, block_size
* 17, bl
.length(), bl
,
8440 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8441 t
.write(cid
, hoid
, block_size
* 19, bl
.length(), bl
,
8442 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8443 r
= queue_transaction(store
, ch
, std::move(t
));
8447 // We need to issue a read to trigger cache stat update that refresh
8448 // perf counters. additionally we need to wait some time for mempool
8449 // thread to update stats.
8451 bufferlist bl
, expected
;
8452 r
= store
->read(ch
, hoid
, block_size
* 17, block_size
* 3, bl
);
8453 ASSERT_EQ(r
, (int)block_size
* 3);
8454 expected
.append(string(block_size
, 'e'));
8455 expected
.append(string(block_size
, 0));
8456 expected
.append(string(block_size
, 'e'));
8457 ASSERT_TRUE(bl_eq(expected
, bl
));
8458 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
8459 ASSERT_EQ(logger
->get(l_bluestore_extents
), 5u);
8462 // fill gaps at the second slot
8463 ObjectStore::Transaction t
;
8466 bl
.append(std::string(block_size
, 'f'));
8467 t
.write(cid
, hoid
, block_size
* 16, bl
.length(), bl
,
8468 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8469 t
.write(cid
, hoid
, block_size
* 18, bl
.length(), bl
,
8470 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8471 r
= queue_transaction(store
, ch
, std::move(t
));
8475 // We need to issue a read to trigger cache stat update that refresh
8476 // perf counters. additionally we need to wait some time for mempool
8477 // thread to update stats.
8479 bufferlist bl
, expected
;
8480 r
= store
->read(ch
, hoid
, block_size
* 16, block_size
* 4, bl
);
8481 ASSERT_EQ(r
, (int)block_size
* 4);
8482 expected
.append(string(block_size
, 'f'));
8483 expected
.append(string(block_size
, 'e'));
8484 expected
.append(string(block_size
, 'f'));
8485 expected
.append(string(block_size
, 'e'));
8486 ASSERT_TRUE(bl_eq(expected
, bl
));
8487 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
8488 ASSERT_EQ(logger
->get(l_bluestore_extents
), 4u);
8491 ObjectStore::Transaction t
;
8492 t
.remove(cid
, hoid
);
8493 t
.remove_collection(cid
);
8494 cerr
<< "Cleaning" << std::endl
;
8495 r
= queue_transaction(store
, ch
, std::move(t
));
8500 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnSmallOverwrite
) {
8502 if (string(GetParam()) != "bluestore")
8505 cout
<< "SKIP: no overwrite" << std::endl
;
8509 size_t block_size
= 4096;
8510 StartDeferred(block_size
);
8511 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8512 g_conf().apply_changes(nullptr);
8516 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
8518 const PerfCounters
* logger
= store
->get_perf_counters();
8519 auto ch
= store
->create_new_collection(cid
);
8522 ObjectStore::Transaction t
;
8523 t
.create_collection(cid
, 0);
8524 r
= queue_transaction(store
, ch
, std::move(t
));
8528 ObjectStore::Transaction t
;
8531 bl
.append(std::string(block_size
, 'a'));
8532 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8533 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
,
8534 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8535 r
= queue_transaction(store
, ch
, std::move(t
));
8539 // write small into the gap
8540 ObjectStore::Transaction t
;
8543 bl
.append(std::string(3, 'b'));
8544 t
.write(cid
, hoid
, block_size
+ 1, bl
.length(), bl
,
8545 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8546 r
= queue_transaction(store
, ch
, std::move(t
));
8550 // We need to issue a read to trigger cache stat update that refresh
8551 // perf counters. additionally we need to wait some time for mempool
8552 // thread to update stats.
8554 bufferlist bl
, expected
;
8555 r
= store
->read(ch
, hoid
, 0, block_size
* 3, bl
);
8556 ASSERT_EQ(r
, (int)block_size
* 3);
8557 expected
.append(string(block_size
, 'a'));
8558 expected
.append(string(1, 0));
8559 expected
.append(string(3, 'b'));
8560 expected
.append(string(block_size
- 4, 0));
8561 expected
.append(string(block_size
, 'a'));
8562 ASSERT_TRUE(bl_eq(expected
, bl
));
8564 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
8565 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
8568 ObjectStore::Transaction t
;
8569 t
.remove(cid
, hoid
);
8570 t
.remove_collection(cid
);
8571 cerr
<< "Cleaning" << std::endl
;
8572 r
= queue_transaction(store
, ch
, std::move(t
));
8577 // The test case to reproduce an issue when write happens
8578 // to a zero space between the extents sharing the same spanning blob
8579 // with unloaded shard map.
8580 // Second extent might be filled with zeros this way due to wrong result
8581 // returned by has_any_extents() call in do_write_small. The latter is caused
8582 // by incompletly loaded extent map.
8583 TEST_P(StoreTestSpecificAUSize
, SmallWriteOnShardedExtents
) {
8584 if (string(GetParam()) != "bluestore")
8587 size_t block_size
= 0x10000;
8588 StartDeferred(block_size
);
8590 SetVal(g_conf(), "bluestore_csum_type", "xxhash64");
8591 SetVal(g_conf(), "bluestore_max_blob_size", "524288"); // for sure
8593 g_conf().apply_changes(nullptr);
8597 ghobject_t
hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
8598 auto ch
= store
->create_new_collection(cid
);
8601 ObjectStore::Transaction t
;
8602 t
.create_collection(cid
, 0);
8603 r
= queue_transaction(store
, ch
, std::move(t
));
8607 //doing some tricks to have sharded extents/spanning objects
8608 ObjectStore::Transaction t
;
8611 bl
.append(std::string(0x80000, 'a'));
8612 t
.write(cid
, hoid1
, 0, bl
.length(), bl
, 0);
8613 t
.zero(cid
, hoid1
, 0x719e0, 0x75b0 );
8614 r
= queue_transaction(store
, ch
, std::move(t
));
8617 bl2
.append(std::string(0x70000, 'b'));
8618 t
.write(cid
, hoid1
, 0, bl2
.length(), bl2
, 0);
8619 t
.zero(cid
, hoid1
, 0, 0x50000);
8620 r
= queue_transaction(store
, ch
, std::move(t
));
8627 ch
= store
->open_collection(cid
);
8630 // do a write to zero space in between some extents sharing the same blob
8631 ObjectStore::Transaction t
;
8634 bl
.append(std::string(0x6520, 'c'));
8635 t
.write(cid
, hoid1
, 0x71c00, bl
.length(), bl
, 0);
8637 r
= queue_transaction(store
, ch
, std::move(t
));
8642 ObjectStore::Transaction t
;
8643 bufferlist bl
, expected
;
8645 r
= store
->read(ch
, hoid1
, 0x70000, 0x9c00, bl
);
8646 ASSERT_EQ(r
, (int)0x9c00);
8647 expected
.append(string(0x19e0, 'a'));
8648 expected
.append(string(0x220, 0));
8649 expected
.append(string(0x6520, 'c'));
8650 expected
.append(string(0xe70, 0));
8651 expected
.append(string(0xc70, 'a'));
8652 ASSERT_TRUE(bl_eq(expected
, bl
));
8658 ObjectStore::Transaction t
;
8659 t
.remove(cid
, hoid1
);
8660 t
.remove_collection(cid
);
8661 cerr
<< "Cleaning" << std::endl
;
8662 r
= queue_transaction(store
, ch
, std::move(t
));
8667 #endif //#if defined(WITH_BLUESTORE)
8669 TEST_P(StoreTest
, KVDBHistogramTest
) {
8670 if (string(GetParam()) != "bluestore")
8676 string
base("testobj.");
8678 bufferptr
ap(0x1000);
8679 memset(ap
.c_str(), 'a', 0x1000);
8681 auto ch
= store
->create_new_collection(cid
);
8683 ObjectStore::Transaction t
;
8684 t
.create_collection(cid
, 0);
8685 r
= queue_transaction(store
, ch
, std::move(t
));
8688 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
8689 ObjectStore::Transaction t
;
8691 snprintf(buf
, sizeof(buf
), "%d", i
);
8692 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
8693 t
.write(cid
, hoid
, 0, 0x1000, a
);
8694 r
= queue_transaction(store
, ch
, std::move(t
));
8698 std::unique_ptr
<Formatter
> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
8699 store
->generate_db_histogram(f
.get());
8704 TEST_P(StoreTest
, KVDBStatsTest
) {
8705 if (string(GetParam()) != "bluestore")
8708 SetVal(g_conf(), "rocksdb_perf", "true");
8709 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
8710 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
8711 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
8712 g_ceph_context
->_conf
.apply_changes(nullptr);
8713 int r
= store
->umount();
8715 r
= store
->mount(); //to force rocksdb stats
8720 string
base("testobj.");
8722 bufferptr
ap(0x1000);
8723 memset(ap
.c_str(), 'a', 0x1000);
8725 auto ch
= store
->create_new_collection(cid
);
8727 ObjectStore::Transaction t
;
8728 t
.create_collection(cid
, 0);
8729 r
= queue_transaction(store
, ch
, std::move(t
));
8732 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
8733 ObjectStore::Transaction t
;
8735 snprintf(buf
, sizeof(buf
), "%d", i
);
8736 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
8737 t
.write(cid
, hoid
, 0, 0x1000, a
);
8738 r
= queue_transaction(store
, ch
, std::move(t
));
8742 std::unique_ptr
<Formatter
> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
8743 store
->get_db_statistics(f
.get());
8748 #if defined(WITH_BLUESTORE)
8749 TEST_P(StoreTestSpecificAUSize
, garbageCollection
) {
8752 int buf_len
= 256 * 1024;
8753 int overlap_offset
= 64 * 1024;
8754 int write_offset
= buf_len
;
8755 if (string(GetParam()) != "bluestore")
8758 cout
<< "SKIP: assertions about allocations need to be adjusted" << std::endl
;
8762 #define WRITE_AT(offset, _length) {\
8763 ObjectStore::Transaction t;\
8764 if ((uint64_t)_length != bl.length()) { \
8765 buffer::ptr p(bl.c_str(), _length);\
8767 bl_tmp.push_back(p);\
8768 t.write(cid, hoid, offset, bl_tmp.length(), bl_tmp);\
8770 t.write(cid, hoid, offset, bl.length(), bl);\
8772 r = queue_transaction(store, ch, std::move(t));\
8776 StartDeferred(65536);
8778 SetVal(g_conf(), "bluestore_compression_max_blob_size", "524288");
8779 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
8780 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
8781 SetVal(g_conf(), "bluestore_compression_mode", "force");
8782 g_conf().apply_changes(nullptr);
8784 auto ch
= store
->create_new_collection(cid
);
8786 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
8789 r
= store
->read(ch
, hoid
, 0, 5, in
);
8790 ASSERT_EQ(-ENOENT
, r
);
8793 ObjectStore::Transaction t
;
8794 t
.create_collection(cid
, 0);
8795 cerr
<< "Creating collection " << cid
<< std::endl
;
8796 r
= queue_transaction(store
, ch
, std::move(t
));
8801 data
.resize(buf_len
);
8805 bool exists
= store
->exists(ch
, hoid
);
8806 ASSERT_TRUE(!exists
);
8808 ObjectStore::Transaction t
;
8810 cerr
<< "Creating object " << hoid
<< std::endl
;
8811 r
= queue_transaction(store
, ch
, std::move(t
));
8814 exists
= store
->exists(ch
, hoid
);
8815 ASSERT_EQ(true, exists
);
8819 for(size_t i
= 0; i
< data
.size(); i
++)
8825 struct store_statfs_t statfs
;
8826 WRITE_AT(0, buf_len
);
8827 int r
= store
->statfs(&statfs
);
8829 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
8832 struct store_statfs_t statfs
;
8833 WRITE_AT(write_offset
- 2 * overlap_offset
, buf_len
);
8834 int r
= store
->statfs(&statfs
);
8836 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
8837 const PerfCounters
* counters
= store
->get_perf_counters();
8838 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0u);
8842 struct store_statfs_t statfs
;
8843 WRITE_AT(write_offset
- overlap_offset
, buf_len
);
8844 int r
= store
->statfs(&statfs
);
8846 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
8847 const PerfCounters
* counters
= store
->get_perf_counters();
8848 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x10000u
);
8851 struct store_statfs_t statfs
;
8852 WRITE_AT(write_offset
- 3 * overlap_offset
, buf_len
);
8853 int r
= store
->statfs(&statfs
);
8855 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
8856 const PerfCounters
* counters
= store
->get_perf_counters();
8857 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
8860 struct store_statfs_t statfs
;
8861 WRITE_AT(write_offset
+ 1, overlap_offset
-1);
8862 int r
= store
->statfs(&statfs
);
8864 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
8865 const PerfCounters
* counters
= store
->get_perf_counters();
8866 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
8869 struct store_statfs_t statfs
;
8870 WRITE_AT(write_offset
+ 1, overlap_offset
);
8871 int r
= store
->statfs(&statfs
);
8873 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
8874 const PerfCounters
* counters
= store
->get_perf_counters();
8875 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x3ffffu
);
8878 struct store_statfs_t statfs
;
8879 WRITE_AT(0, buf_len
-1);
8880 int r
= store
->statfs(&statfs
);
8882 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
8883 const PerfCounters
* counters
= store
->get_perf_counters();
8884 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
8886 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "1"); //forbid GC when saving = 0
8888 struct store_statfs_t statfs
;
8889 WRITE_AT(1, overlap_offset
-2);
8890 WRITE_AT(overlap_offset
* 2 + 1, overlap_offset
-2);
8891 int r
= store
->statfs(&statfs
);
8893 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
8894 const PerfCounters
* counters
= store
->get_perf_counters();
8895 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
8898 struct store_statfs_t statfs
;
8899 WRITE_AT(overlap_offset
+ 1, overlap_offset
-2);
8900 int r
= store
->statfs(&statfs
);
8902 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x0);
8903 const PerfCounters
* counters
= store
->get_perf_counters();
8904 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40007u
);
8907 ObjectStore::Transaction t
;
8908 t
.remove(cid
, hoid
);
8909 cerr
<< "Cleaning" << std::endl
;
8910 r
= queue_transaction(store
, ch
, std::move(t
));
8916 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice
) {
8917 if (string(GetParam()) != "bluestore")
8920 SetVal(g_conf(), "bluestore_block_size",
8921 stringify(0x280005000).c_str()); //10 Gb + 4K
8922 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
8923 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
8924 StartDeferred(0x4000);
8926 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
8931 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice2
) {
8932 if (string(GetParam()) != "bluestore")
8935 SetVal(g_conf(), "bluestore_block_size",
8936 stringify(0x280005000).c_str()); //10 Gb + 20K
8937 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
8938 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
8939 StartDeferred(0x1000);
8941 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
8946 ghobject_t
make_object(const char* name
, int64_t pool
) {
8947 sobject_t soid
{name
, CEPH_NOSNAP
};
8948 uint32_t hash
= std::hash
<sobject_t
>{}(soid
);
8949 return ghobject_t
{hobject_t
{soid
, "", hash
, pool
, ""}};
8953 TEST_P(StoreTestSpecificAUSize
, BluestoreRepairTest
) {
8954 if (string(GetParam()) != "bluestore")
8957 cout
<< "TODO: repair mismatched write pointer (+ dead bytes mismatch)" << std::endl
;
8960 const size_t offs_base
= 65536 / 2;
8963 // Now we need standalone db to pass "false free fix" section below
8964 // Due to new BlueFS allocation model (single allocator for main device)
8965 // it might cause "false free" blob overwrite by BlueFS/DB stuff
8966 // and hence fail the test case and corrupt data.
8969 SetVal(g_conf(), "bluestore_block_db_create", "true");
8970 SetVal(g_conf(), "bluestore_block_db_size", "4294967296");
8972 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
8973 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
8974 SetVal(g_conf(), "bluestore_max_blob_size",
8975 stringify(2 * offs_base
).c_str());
8976 SetVal(g_conf(), "bluestore_extent_map_shard_max_size", "12000");
8977 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "false");
8979 StartDeferred(0x10000);
8981 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
8983 // fill the store with some data
8984 const uint64_t pool
= 555;
8985 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
8986 auto ch
= store
->create_new_collection(cid
);
8988 ghobject_t hoid
= make_object("Object 1", pool
);
8989 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
8990 ghobject_t hoid2
= make_object("Object 2", pool
);
8991 ghobject_t hoid_cloned
= hoid2
;
8992 hoid_cloned
.hobj
.snap
= 1;
8993 ghobject_t hoid3
= make_object("Object 3", pool
);
8994 ghobject_t hoid3_cloned
= hoid3
;
8995 hoid3_cloned
.hobj
.snap
= 1;
8997 bl
.append("1234512345");
8999 const size_t repeats
= 16;
9001 auto ch
= store
->create_new_collection(cid
);
9002 cerr
<< "create collection + write" << std::endl
;
9003 ObjectStore::Transaction t
;
9004 t
.create_collection(cid
, 0);
9005 for( auto i
= 0ul; i
< repeats
; ++i
) {
9006 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
9007 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
9009 for( auto i
= 0ul; i
< repeats
; ++i
) {
9010 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
9012 t
.clone(cid
, hoid2
, hoid_cloned
);
9014 r
= queue_transaction(store
, ch
, std::move(t
));
9019 bool err_was_injected
= false;
9020 //////////// leaked pextent fix ////////////
9021 cerr
<< "fix leaked pextents" << std::endl
;
9022 ASSERT_EQ(bstore
->fsck(false), 0);
9023 ASSERT_EQ(bstore
->repair(false), 0);
9025 if (!bstore
->has_null_fm()) {
9026 bstore
->inject_leaked(0x30000);
9027 err_was_injected
= true;
9031 if (err_was_injected
) {
9032 ASSERT_EQ(bstore
->fsck(false), 1);
9034 ASSERT_EQ(bstore
->repair(false), 0);
9035 ASSERT_EQ(bstore
->fsck(false), 0);
9037 //////////// false free fix ////////////
9038 cerr
<< "fix false free pextents" << std::endl
;
9040 if (!bstore
->has_null_fm()) {
9041 bstore
->inject_false_free(cid
, hoid
);
9042 err_was_injected
= true;
9045 if (err_was_injected
) {
9046 ASSERT_EQ(bstore
->fsck(false), 2);
9047 ASSERT_EQ(bstore
->repair(false), 0);
9049 ASSERT_EQ(bstore
->fsck(false), 0);
9051 //////////// verify invalid statfs ///////////
9052 cerr
<< "fix invalid statfs" << std::endl
;
9053 store_statfs_t statfs0
, statfs
;
9055 ASSERT_EQ(bstore
->statfs(&statfs0
), 0);
9057 statfs
.allocated
+= 0x10000;
9058 statfs
.data_stored
+= 0x10000;
9059 ASSERT_FALSE(statfs0
== statfs
);
9060 bstore
->inject_statfs("bluestore_statfs", statfs
);
9063 ASSERT_EQ(bstore
->fsck(false), 2);
9064 ASSERT_EQ(bstore
->repair(false), 0);
9065 ASSERT_EQ(bstore
->fsck(false), 0);
9066 ASSERT_EQ(bstore
->mount(), 0);
9067 ASSERT_EQ(bstore
->statfs(&statfs
), 0);
9068 // adjust free/internal meta space to success in comparison
9069 statfs0
.available
= statfs
.available
;
9070 statfs0
.internal_metadata
= statfs
.internal_metadata
;
9071 ASSERT_EQ(statfs0
, statfs
);
9073 ///////// undecodable shared blob key / stray shared blob records ///////
9074 cerr
<< "undecodable shared blob key" << std::endl
;
9075 bstore
->inject_broken_shared_blob_key("undec1",
9077 bstore
->inject_broken_shared_blob_key("undecodable key 2",
9079 bstore
->inject_broken_shared_blob_key("undecodable key 3",
9082 ASSERT_EQ(bstore
->fsck(false), 3);
9083 ASSERT_EQ(bstore
->repair(false), 0);
9084 ASSERT_EQ(bstore
->fsck(false), 0);
9086 cerr
<< "misreferencing" << std::endl
;
9088 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, 0);
9089 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, (offs_base
* repeats
) / 2);
9090 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, offs_base
* (repeats
-1) );
9091 int expected_errors
= bstore
->has_null_fm() ? 3 : 6;
9093 ASSERT_EQ(bstore
->fsck(false), expected_errors
);
9094 ASSERT_EQ(bstore
->repair(false), 0);
9096 ASSERT_EQ(bstore
->fsck(true), 0);
9098 // reproducing issues #21040 & 20983
9099 SetVal(g_conf(), "bluestore_debug_inject_bug21040", "true");
9100 g_ceph_context
->_conf
.apply_changes(nullptr);
9103 cerr
<< "repro bug #21040" << std::endl
;
9105 auto ch
= store
->open_collection(cid
);
9107 ObjectStore::Transaction t
;
9108 bl
.append("0123456789012345");
9109 t
.write(cid
, hoid3
, offs_base
, bl
.length(), bl
);
9112 t
.write(cid
, hoid3
, 0, bl
.length(), bl
);
9114 r
= queue_transaction(store
, ch
, std::move(t
));
9118 ObjectStore::Transaction t
;
9119 t
.clone(cid
, hoid3
, hoid3_cloned
);
9120 r
= queue_transaction(store
, ch
, std::move(t
));
9125 ASSERT_EQ(bstore
->fsck(false), 4);
9126 ASSERT_LE(bstore
->repair(false), 0);
9127 ASSERT_EQ(bstore
->fsck(false), 0);
9130 cerr
<< "Zombie spanning blob" << std::endl
;
9133 ghobject_t hoid4
= make_object("Object 4", pool
);
9134 auto ch
= store
->open_collection(cid
);
9137 string
s(0x1000, 'a');
9139 ObjectStore::Transaction t
;
9140 for(size_t i
= 0; i
< 0x10; i
++) {
9141 t
.write(cid
, hoid4
, i
* bl
.length(), bl
.length(), bl
);
9143 r
= queue_transaction(store
, ch
, std::move(t
));
9148 bstore
->inject_zombie_spanning_blob(cid
, hoid4
, 12345);
9149 bstore
->inject_zombie_spanning_blob(cid
, hoid4
, 23456);
9150 bstore
->inject_zombie_spanning_blob(cid
, hoid4
, 23457);
9154 ASSERT_EQ(bstore
->fsck(false), 1);
9155 ASSERT_LE(bstore
->repair(false), 0);
9156 ASSERT_EQ(bstore
->fsck(false), 0);
9159 cerr
<< "Completing" << std::endl
;
9164 TEST_P(StoreTestSpecificAUSize
, BluestoreBrokenZombieRepairTest
) {
9165 if (string(GetParam()) != "bluestore")
9168 cout
<< "SKIP: smr repair is different" << std::endl
;
9171 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9172 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9174 StartDeferred(0x10000);
9176 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9180 cerr
<< "initializing" << std::endl
;
9182 const size_t col_count
= 16;
9183 const size_t obj_count
= 1024;
9184 ObjectStore::CollectionHandle ch
[col_count
];
9185 ghobject_t hoid
[col_count
][obj_count
];
9187 unique_ptr
<coll_t
> cid
[col_count
];
9189 for (size_t i
= 0; i
< col_count
; i
++) {
9190 cid
[i
].reset(new coll_t(spg_t(pg_t(0, i
), shard_id_t::NO_SHARD
)));
9191 ch
[i
] = store
->create_new_collection(*cid
[i
]);
9192 for (size_t j
= 0; j
< obj_count
; j
++) {
9193 hoid
[i
][j
] = make_object(stringify(j
).c_str(), i
);
9197 for (size_t i
= 0; i
< col_count
; i
++) {
9198 ObjectStore::Transaction t
;
9199 t
.create_collection(*cid
[i
], 0);
9200 r
= queue_transaction(store
, ch
[i
], std::move(t
));
9203 cerr
<< "onode preparing" << std::endl
;
9205 string
s(0x1000, 'a');
9208 for (size_t i
= 0; i
< col_count
; i
++) {
9209 for (size_t j
= 0; j
< obj_count
; j
++) {
9210 ObjectStore::Transaction t
;
9211 t
.write(*cid
[i
], hoid
[i
][j
], bl
.length(), bl
.length(), bl
);
9212 r
= queue_transaction(store
, ch
[i
], std::move(t
));
9216 cerr
<< "Zombie spanning blob injection" << std::endl
;
9220 for (size_t i
= 0; i
< col_count
; i
++) {
9221 for (size_t j
= 0; j
< obj_count
; j
++) {
9222 bstore
->inject_zombie_spanning_blob(*cid
[i
], hoid
[i
][j
], 12345);
9226 cerr
<< "fscking/fixing" << std::endl
;
9228 ASSERT_EQ(bstore
->fsck(false), col_count
* obj_count
);
9229 ASSERT_LE(bstore
->quick_fix(), 0);
9230 ASSERT_EQ(bstore
->fsck(false), 0);
9233 cerr
<< "Completing" << std::endl
;
9237 TEST_P(StoreTestSpecificAUSize
, BluestoreRepairSharedBlobTest
) {
9238 if (string(GetParam()) != "bluestore")
9241 cout
<< "TODO: repair mismatched write pointer (+ dead bytes mismatch)" << std::endl
;
9245 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9246 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9248 const size_t block_size
= 0x1000;
9249 StartDeferred(block_size
);
9251 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9253 // fill the store with some data
9254 const uint64_t pool
= 555;
9255 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9256 auto ch
= store
->create_new_collection(cid
);
9258 ghobject_t hoid
= make_object("Object 1", pool
);
9259 ghobject_t hoid_cloned
= hoid
;
9260 hoid_cloned
.hobj
.snap
= 1;
9261 ghobject_t hoid2
= make_object("Object 2", pool
);
9263 string
s(block_size
, 1);
9268 ObjectStore::Transaction t
;
9269 t
.create_collection(cid
, 0);
9270 r
= queue_transaction(store
, ch
, std::move(t
));
9274 // check the scenario when shared blob contains
9275 // references to extents from two objects which don't overlapp
9278 cerr
<< "introduce 2 non-overlapped extents in a shared blob"
9281 ObjectStore::Transaction t
;
9282 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
9283 t
.write(cid
, hoid2
, 0, bl
.length(), bl
); // to make a gap in allocations
9284 t
.write(cid
, hoid
, block_size
* 2 , bl
.length(), bl
);
9285 t
.clone(cid
, hoid
, hoid_cloned
);
9286 t
.zero(cid
, hoid
, 0, bl
.length());
9287 t
.zero(cid
, hoid_cloned
, block_size
* 2, bl
.length());
9288 r
= queue_transaction(store
, ch
, std::move(t
));
9295 _key_encode_u64(1, &key
);
9296 bluestore_shared_blob_t
sb(1);
9297 sb
.ref_map
.get(0x2000, block_size
);
9298 sb
.ref_map
.get(0x4000, block_size
);
9299 sb
.ref_map
.get(0x4000, block_size
);
9302 bstore
->inject_broken_shared_blob_key(key
, bl
);
9305 ASSERT_EQ(bstore
->fsck(false), 2);
9306 ASSERT_EQ(bstore
->repair(false), 0);
9307 ASSERT_EQ(bstore
->fsck(false), 0);
9309 cerr
<< "Completing" << std::endl
;
9313 TEST_P(StoreTestSpecificAUSize
, BluestoreBrokenNoSharedBlobRepairTest
) {
9314 if (string(GetParam()) != "bluestore")
9317 cout
<< "SKIP: smr repair is different" << std::endl
;
9321 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9322 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9324 StartDeferred(0x10000);
9326 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9331 cerr
<< "initializing" << std::endl
;
9333 const uint64_t pool
= 555;
9334 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9335 auto ch
= store
->create_new_collection(cid
);
9337 ghobject_t hoid
= make_object("Object", pool
);
9338 ghobject_t hoid_cloned
= hoid
;
9339 hoid_cloned
.hobj
.snap
= 1;
9342 ObjectStore::Transaction t
;
9343 t
.create_collection(cid
, 0);
9344 r
= queue_transaction(store
, ch
, std::move(t
));
9348 ObjectStore::Transaction t
;
9350 bl
.append("0123456789012345");
9351 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
9353 r
= queue_transaction(store
, ch
, std::move(t
));
9357 ObjectStore::Transaction t
;
9358 t
.clone(cid
, hoid
, hoid_cloned
);
9359 r
= queue_transaction(store
, ch
, std::move(t
));
9363 // injecting an error and checking
9364 cerr
<< "injecting" << std::endl
;
9365 sleep(3); // need some time for the previous write to land
9366 bstore
->inject_no_shared_blob_key();
9367 bstore
->inject_stray_shared_blob_key(12345678);
9370 cerr
<< "fscking/fixing" << std::endl
;
9371 // we need to check for null-manager before umount()
9372 bool has_null_manager
= bstore
->has_null_manager();
9374 // depending on the allocation map's source we can
9375 // either observe or don't observe an additional
9376 // extent leak detection. Hence adjusting the expected
9378 size_t expected_error_count
=
9380 5: // 4 sb ref mismatch errors + 1 statfs mismatch
9381 7; // 4 sb ref mismatch errors + 1 statfs + 1 block leak + 1 non-free
9382 ASSERT_EQ(bstore
->fsck(false), expected_error_count
);
9383 // repair might report less errors than fsck above showed
9384 // as some errors, e.g. statfs mismatch, are implicitly fixed
9385 // before the detection during the previous repair steps...
9386 ASSERT_LE(bstore
->repair(false), expected_error_count
);
9387 ASSERT_EQ(bstore
->fsck(false), 0);
9390 cerr
<< "Completing" << std::endl
;
9394 TEST_P(StoreTest
, BluestoreRepairGlobalStats
) {
9395 if (string(GetParam()) != "bluestore")
9397 const size_t offs_base
= 65536 / 2;
9399 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9401 // start with global stats
9402 bstore
->inject_global_statfs({});
9404 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
9407 // fill the store with some data
9408 const uint64_t pool
= 555;
9409 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9410 auto ch
= store
->create_new_collection(cid
);
9412 ghobject_t hoid
= make_object("Object 1", pool
);
9413 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
9414 ghobject_t hoid2
= make_object("Object 2", pool
);
9415 ghobject_t hoid_cloned
= hoid2
;
9416 hoid_cloned
.hobj
.snap
= 1;
9417 ghobject_t hoid3
= make_object("Object 3", pool
);
9418 ghobject_t hoid3_cloned
= hoid3
;
9419 hoid3_cloned
.hobj
.snap
= 1;
9421 bl
.append("1234512345");
9423 const size_t repeats
= 16;
9425 auto ch
= store
->create_new_collection(cid
);
9426 cerr
<< "create collection + write" << std::endl
;
9427 ObjectStore::Transaction t
;
9428 t
.create_collection(cid
, 0);
9429 for( auto i
= 0ul; i
< repeats
; ++i
) {
9430 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
9431 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
9433 for( auto i
= 0ul; i
< repeats
; ++i
) {
9434 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
9436 t
.clone(cid
, hoid2
, hoid_cloned
);
9438 r
= queue_transaction(store
, ch
, std::move(t
));
9444 // enable per-pool stats collection hence causing fsck to fail
9445 cerr
<< "per-pool statfs" << std::endl
;
9446 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
9447 g_ceph_context
->_conf
.apply_changes(nullptr);
9449 ASSERT_EQ(bstore
->fsck(false), 1);
9450 ASSERT_EQ(bstore
->repair(false), 0);
9451 ASSERT_EQ(bstore
->fsck(false), 0);
9456 TEST_P(StoreTest
, BluestoreRepairGlobalStatsFixOnMount
) {
9457 if (string(GetParam()) != "bluestore")
9459 const size_t offs_base
= 65536 / 2;
9461 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9463 // start with global stats
9464 bstore
->inject_global_statfs({});
9466 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
9469 // fill the store with some data
9470 const uint64_t pool
= 555;
9471 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9472 auto ch
= store
->create_new_collection(cid
);
9474 ghobject_t hoid
= make_object("Object 1", pool
);
9475 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
9476 ghobject_t hoid2
= make_object("Object 2", pool
);
9477 ghobject_t hoid_cloned
= hoid2
;
9478 hoid_cloned
.hobj
.snap
= 1;
9479 ghobject_t hoid3
= make_object("Object 3", pool
);
9480 ghobject_t hoid3_cloned
= hoid3
;
9481 hoid3_cloned
.hobj
.snap
= 1;
9483 bl
.append("1234512345");
9485 const size_t repeats
= 16;
9487 auto ch
= store
->create_new_collection(cid
);
9488 cerr
<< "create collection + write" << std::endl
;
9489 ObjectStore::Transaction t
;
9490 t
.create_collection(cid
, 0);
9491 for( auto i
= 0ul; i
< repeats
; ++i
) {
9492 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
9493 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
9495 for( auto i
= 0ul; i
< repeats
; ++i
) {
9496 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
9498 t
.clone(cid
, hoid2
, hoid_cloned
);
9500 r
= queue_transaction(store
, ch
, std::move(t
));
9506 // enable per-pool stats collection hence causing fsck to fail
9507 cerr
<< "per-pool statfs" << std::endl
;
9508 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
9509 g_ceph_context
->_conf
.apply_changes(nullptr);
9511 ASSERT_EQ(bstore
->fsck(false), 1);
9513 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
9516 ASSERT_EQ(bstore
->fsck(false), 0);
9521 TEST_P(StoreTest
, BluestoreStatistics
) {
9522 if (string(GetParam()) != "bluestore")
9525 SetVal(g_conf(), "rocksdb_perf", "true");
9526 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
9527 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
9528 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
9531 SetVal(g_conf(), "bluestore_cache_size_ssd", "0");
9532 SetVal(g_conf(), "bluestore_cache_size_hdd", "0");
9533 SetVal(g_conf(), "bluestore_cache_size", "0");
9534 g_ceph_context
->_conf
.apply_changes(nullptr);
9536 int r
= store
->umount();
9541 BlueStore
* bstore
= NULL
;
9542 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
9545 ghobject_t
hoid(hobject_t("test_db_statistics", "", CEPH_NOSNAP
, 0, 0, ""));
9546 auto ch
= bstore
->create_new_collection(cid
);
9548 bl
.append("0123456789abcdefghi");
9550 ObjectStore::Transaction t
;
9551 t
.create_collection(cid
, 0);
9553 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
9554 cerr
<< "Write object" << std::endl
;
9555 r
= queue_transaction(bstore
, ch
, std::move(t
));
9559 bufferlist readback
;
9560 r
= store
->read(ch
, hoid
, 0, bl
.length(), readback
);
9561 ASSERT_EQ(static_cast<int>(bl
.length()), r
);
9562 ASSERT_TRUE(bl_eq(bl
, readback
));
9564 std::unique_ptr
<Formatter
> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
9565 EXPECT_NO_THROW(store
->get_db_statistics(f
.get()));
9570 TEST_P(StoreTest
, BluestoreStrayOmapDetection
)
9572 if (string(GetParam()) != "bluestore")
9575 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9576 const uint64_t pool
= 555;
9577 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9578 ghobject_t oid
= make_object("Object 1", pool
);
9579 ghobject_t oid2
= make_object("Object 2", pool
);
9580 // fill the store with some data
9581 auto ch
= store
->create_new_collection(cid
);
9585 ObjectStore::Transaction t
;
9586 t
.create_collection(cid
, 0);
9588 t
.omap_setheader(cid
, oid
, h
);
9590 t
.omap_setheader(cid
, oid2
, h
);
9591 int r
= queue_transaction(store
, ch
, std::move(t
));
9595 // inject stray omap
9596 bstore
->inject_stray_omap(123456, "somename");
9599 // check we detect injected stray omap..
9601 ASSERT_EQ(bstore
->fsck(false), 1);
9602 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9606 TEST_P(StoreTest
, BluestorePerPoolOmapFixOnMount
)
9608 if (string(GetParam()) != "bluestore")
9611 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9612 const uint64_t pool
= 555;
9613 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9614 ghobject_t oid
= make_object("Object 1", pool
);
9615 ghobject_t oid2
= make_object("Object 2", pool
);
9616 // fill the store with some data
9617 auto ch
= store
->create_new_collection(cid
);
9618 map
<string
, bufferlist
> omap
;
9622 omap
["omap_key"].append("omap value");
9623 ObjectStore::Transaction t
;
9624 t
.create_collection(cid
, 0);
9626 t
.omap_setheader(cid
, oid
, h
);
9628 t
.omap_setheader(cid
, oid2
, h
);
9629 int r
= queue_transaction(store
, ch
, std::move(t
));
9633 // inject legacy omaps
9634 bstore
->inject_legacy_omap();
9635 bstore
->inject_legacy_omap(cid
, oid
);
9636 bstore
->inject_legacy_omap(cid
, oid2
);
9640 // check we injected an issue
9641 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
9642 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
9643 g_ceph_context
->_conf
.apply_changes(nullptr);
9644 ASSERT_EQ(bstore
->fsck(false), 3);
9646 // set autofix and mount
9647 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
9648 g_ceph_context
->_conf
.apply_changes(nullptr);
9652 // check we fixed it..
9653 ASSERT_EQ(bstore
->fsck(false), 0);
9657 // Now repro https://tracker.ceph.com/issues/43824
9659 // inject legacy omaps again
9660 bstore
->inject_legacy_omap();
9661 bstore
->inject_legacy_omap(cid
, oid
);
9662 bstore
->inject_legacy_omap(cid
, oid2
);
9665 // check we injected an issue
9666 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
9667 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
9668 g_ceph_context
->_conf
.apply_changes(nullptr);
9670 ch
= store
->open_collection(cid
);
9673 // write to onode which will partiall revert per-pool
9674 // omap repair done on mount due to #43824.
9675 // And object removal will leave stray per-pool omap recs
9677 ObjectStore::Transaction t
;
9680 //this triggers onode rec update and hence legacy omap
9681 t
.write(cid
, oid
, 0, bl
.length(), bl
);
9682 t
.remove(cid
, oid2
); // this will trigger stray per-pool omap
9683 int r
= queue_transaction(store
, ch
, std::move(t
));
9687 // check omap's been fixed.
9688 ASSERT_EQ(bstore
->fsck(false), 0); // this will fail without fix for #43824
9693 class hugepaged_raw
;
9695 static bool is_hugepaged(const bufferptr
& bp
)
9698 static_cast<const ceph::buffer_instrumentation::instrumented_bptr
&>(bp
);
9699 return ibp
.is_raw_marked
<BlockDevice::hugepaged_raw_marker_t
>();
9702 // disabled by default b/c of the dependency on huge page ssome test
9703 // environments might not offer without extra configuration.
9704 TEST_P(StoreTestDeferredSetup
, DISABLED_BluestoreHugeReads
)
9706 if (string(GetParam()) != "bluestore") {
9710 constexpr static size_t HUGE_BUFFER_SIZE
{2_M
};
9711 cout
<< "Configuring huge page pools" << std::endl
;
9713 SetVal(g_conf(), "bdev_read_preallocated_huge_buffers",
9714 fmt::format("{}=2", HUGE_BUFFER_SIZE
).c_str());
9715 SetVal(g_conf(), "bluestore_max_blob_size",
9716 std::to_string(HUGE_BUFFER_SIZE
).c_str());
9717 // let's verify the per-IOContext no-cache override
9718 SetVal(g_conf(), "bluestore_default_buffered_read", "true");
9719 g_ceph_context
->_conf
.apply_changes(nullptr);
9724 ghobject_t
hoid(hobject_t("test_huge_buffers", "", CEPH_NOSNAP
, 0, 0, ""));
9725 auto ch
= store
->create_new_collection(cid
);
9729 bufferptr bp
{HUGE_BUFFER_SIZE
};
9730 // non-zeros! Otherwise the deduplication will take place.
9731 ::memset(bp
.c_str(), 0x42, HUGE_BUFFER_SIZE
);
9732 bl
.push_back(std::move(bp
));
9733 ASSERT_EQ(bl
.get_num_buffers(), 1);
9734 ASSERT_EQ(bl
.length(), HUGE_BUFFER_SIZE
);
9737 cout
<< "Write object" << std::endl
;
9739 ObjectStore::Transaction t
;
9740 t
.create_collection(cid
, 0);
9742 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
9743 const auto r
= queue_transaction(store
, ch
, std::move(t
));
9747 // force cache clear
9749 EXPECT_EQ(store
->umount(), 0);
9750 EXPECT_EQ(store
->mount(), 0);
9751 ch
= store
->open_collection(cid
);
9754 // we want to extend the life-time of all huge paged-backed
9755 // bufferlists to validate the behaviour on pool exhaustion.
9756 bufferlist bl_1_huge
, bl_2_huge
, bl_3_plain
;
9758 cout
<< "Read object 1st time" << std::endl
;
9760 const auto r
= store
->read(ch
, hoid
, 0, HUGE_BUFFER_SIZE
, bl_1_huge
);
9761 ASSERT_EQ(static_cast<int>(HUGE_BUFFER_SIZE
), r
);
9762 ASSERT_TRUE(bl_eq(bl
, bl_1_huge
));
9763 ASSERT_EQ(bl_1_huge
.get_num_buffers(), 1);
9764 ASSERT_TRUE(is_hugepaged(bl_1_huge
.front()));
9767 cout
<< "Read object 2nd time" << std::endl
;
9769 const auto r
= store
->read(ch
, hoid
, 0, HUGE_BUFFER_SIZE
, bl_2_huge
);
9770 ASSERT_EQ(static_cast<int>(HUGE_BUFFER_SIZE
), r
);
9771 ASSERT_TRUE(bl_eq(bl
, bl_2_huge
));
9772 ASSERT_EQ(bl_2_huge
.get_num_buffers(), 1);
9773 ASSERT_TRUE(is_hugepaged(bl_2_huge
.front()));
9776 cout
<< "Read object 3rd time" << std::endl
;
9778 const auto r
= store
->read(ch
, hoid
, 0, HUGE_BUFFER_SIZE
, bl_3_plain
);
9779 ASSERT_EQ(static_cast<int>(HUGE_BUFFER_SIZE
), r
);
9780 ASSERT_TRUE(bl_eq(bl
, bl_3_plain
));
9781 ASSERT_EQ(bl_3_plain
.get_num_buffers(), 1);
9782 ASSERT_FALSE(is_hugepaged(bl_3_plain
.front()));
9786 TEST_P(StoreTest
, SpuriousReadErrorTest
) {
9787 if (string(GetParam()) != "bluestore")
9791 auto logger
= store
->get_perf_counters();
9793 auto ch
= store
->create_new_collection(cid
);
9794 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
9796 ObjectStore::Transaction t
;
9797 t
.create_collection(cid
, 0);
9798 cerr
<< "Creating collection " << cid
<< std::endl
;
9799 r
= queue_transaction(store
, ch
, std::move(t
));
9802 bufferlist test_data
;
9803 bufferptr
ap(0x2000);
9804 memset(ap
.c_str(), 'a', 0x2000);
9805 test_data
.append(ap
);
9807 ObjectStore::Transaction t
;
9808 t
.write(cid
, hoid
, 0, 0x2000, test_data
);
9809 r
= queue_transaction(store
, ch
, std::move(t
));
9811 // force cache clear
9812 EXPECT_EQ(store
->umount(), 0);
9813 EXPECT_EQ(store
->mount(), 0);
9815 ch
= store
->open_collection(cid
);
9817 cerr
<< "Injecting CRC error with no retry, expecting EIO" << std::endl
;
9818 SetVal(g_conf(), "bluestore_retry_disk_reads", "0");
9819 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "1");
9820 g_ceph_context
->_conf
.apply_changes(nullptr);
9823 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
9825 ASSERT_EQ(logger
->get(l_bluestore_read_eio
), 1u);
9826 ASSERT_EQ(logger
->get(l_bluestore_reads_with_retries
), 0u);
9829 cerr
<< "Injecting CRC error with retries, expecting success after several retries" << std::endl
;
9830 SetVal(g_conf(), "bluestore_retry_disk_reads", "255");
9831 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "0.8");
9833 * Probabilistic test: 25 reads, each has a 80% chance of failing with 255 retries
9834 * Probability of at least one retried read: 1 - (0.2 ** 25) = 100% - 3e-18
9835 * Probability of a random test failure: 1 - ((1 - (0.8 ** 255)) ** 25) ~= 5e-24
9837 g_ceph_context
->_conf
.apply_changes(nullptr);
9839 for (int i
= 0; i
< 25; ++i
) {
9841 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
9842 ASSERT_EQ(0x2000, r
);
9843 ASSERT_TRUE(bl_eq(test_data
, in
));
9845 ASSERT_GE(logger
->get(l_bluestore_reads_with_retries
), 1u);
9849 TEST_P(StoreTest
, mergeRegionTest
) {
9850 if (string(GetParam()) != "bluestore")
9853 SetVal(g_conf(), "bluestore_fsck_on_mount", "true");
9854 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
9855 SetVal(g_conf(), "bdev_debug_inflight_ios", "true");
9856 g_ceph_context
->_conf
.apply_changes(nullptr);
9858 uint32_t chunk_size
= g_ceph_context
->_conf
->bdev_block_size
;
9861 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
9862 auto ch
= store
->create_new_collection(cid
);
9864 ObjectStore::Transaction t
;
9865 t
.create_collection(cid
, 0);
9866 r
= queue_transaction(store
, ch
, std::move(t
));
9870 ObjectStore::Transaction t
;
9872 cerr
<< "Creating object " << hoid
<< std::endl
;
9873 r
= queue_transaction(store
, ch
, std::move(t
));
9877 bl5
.append("abcde");
9878 uint64_t offset
= 0;
9880 ObjectStore::Transaction t
;
9881 t
.write(cid
, hoid
, offset
, 5, bl5
);
9882 t
.write(cid
, hoid
, 0xa + offset
, 5, bl5
);
9883 t
.write(cid
, hoid
, 0x14 + offset
, 5, bl5
);
9884 r
= queue_transaction(store
, ch
, std::move(t
));
9887 { // 2. adjacent regions
9888 ObjectStore::Transaction t
;
9889 offset
= chunk_size
;
9890 t
.write(cid
, hoid
, offset
, 5, bl5
);
9891 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
9892 r
= queue_transaction(store
, ch
, std::move(t
));
9896 ObjectStore::Transaction t
;
9897 offset
= chunk_size
* 2;
9898 t
.write(cid
, hoid
, offset
, 5, bl5
);
9899 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, 5, bl5
);
9900 r
= queue_transaction(store
, ch
, std::move(t
));
9904 ObjectStore::Transaction t
;
9906 blc2
.append_zero(chunk_size
+ 2);
9908 offset
= chunk_size
* 3;
9909 t
.write(cid
, hoid
, offset
, chunk_size
+ 2, blc2
);
9910 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
9911 r
= queue_transaction(store
, ch
, std::move(t
));
9915 ObjectStore::Transaction t
;
9916 uint64_t final_len
= 0;
9917 offset
= chunk_size
* 10;
9919 bl2c2
.append_zero(chunk_size
* 2);
9920 t
.write(cid
, hoid
, offset
+ chunk_size
* 3 - 3, chunk_size
* 2, bl2c2
);
9921 bl2c2
.append_zero(2);
9922 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, chunk_size
* 2 + 2, bl2c2
);
9923 r
= queue_transaction(store
, ch
, std::move(t
));
9926 final_len
= (offset
+ chunk_size
* 3 - 3) + (chunk_size
* 2);
9928 r
= store
->read(ch
, hoid
, 0, final_len
, bl
);
9929 ASSERT_EQ(final_len
, static_cast<uint64_t>(r
));
9933 TEST_P(StoreTest
, FixSMRWritePointer
) {
9934 if(string(GetParam()) != "bluestore")
9938 int r
= store
->umount();
9941 // copied from StoreTestFixture
9942 std::string path
= GetParam() + ".test_temp_dir"s
;
9944 std::string p
= path
+ "/block";
9945 BlockDevice
* bdev
= BlockDevice::create(g_ceph_context
, p
, nullptr, nullptr, nullptr, nullptr);
9948 ASSERT_EQ(true, bdev
->is_smr());
9950 std::vector
<uint64_t> wp
= bdev
->get_zones();
9951 uint64_t first_seq_zone
= bdev
->get_conventional_region_size() / bdev
->get_zone_size();
9953 IOContext
ioc(g_ceph_context
, NULL
, true);
9955 bl
.append(std::string(1024 * 1024, 'x'));
9956 r
= bdev
->aio_write(wp
[first_seq_zone
], bl
, &ioc
, false);
9958 bdev
->aio_submit(&ioc
);
9968 TEST_P(StoreTestSpecificAUSize
, BluestoreEnforceHWSettingsHdd
) {
9969 if (string(GetParam()) != "bluestore")
9972 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
9973 StartDeferred(0x1000);
9977 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
9978 auto ch
= store
->create_new_collection(cid
);
9980 ObjectStore::Transaction t
;
9981 t
.create_collection(cid
, 0);
9982 cerr
<< "Creating collection " << cid
<< std::endl
;
9983 r
= queue_transaction(store
, ch
, std::move(t
));
9987 ObjectStore::Transaction t
;
9988 bufferlist bl
, orig
;
9989 string
s(g_ceph_context
->_conf
->bluestore_max_blob_size_hdd
, '0');
9991 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
9992 cerr
<< "write" << std::endl
;
9993 r
= queue_transaction(store
, ch
, std::move(t
));
9996 const PerfCounters
* logger
= store
->get_perf_counters();
9997 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 1u);
10001 TEST_P(StoreTestSpecificAUSize
, BluestoreEnforceHWSettingsSsd
) {
10002 if (string(GetParam()) != "bluestore")
10005 SetVal(g_conf(), "bluestore_debug_enforce_settings", "ssd");
10006 StartDeferred(0x1000);
10010 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
10011 auto ch
= store
->create_new_collection(cid
);
10013 ObjectStore::Transaction t
;
10014 t
.create_collection(cid
, 0);
10015 cerr
<< "Creating collection " << cid
<< std::endl
;
10016 r
= queue_transaction(store
, ch
, std::move(t
));
10020 ObjectStore::Transaction t
;
10021 bufferlist bl
, orig
;
10022 string
s(g_ceph_context
->_conf
->bluestore_max_blob_size_ssd
* 8, '0');
10024 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
10025 cerr
<< "write" << std::endl
;
10026 r
= queue_transaction(store
, ch
, std::move(t
));
10029 const PerfCounters
* logger
= store
->get_perf_counters();
10030 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 8u);
10034 TEST_P(StoreTestSpecificAUSize
, ReproNoBlobMultiTest
) {
10036 if(string(GetParam()) != "bluestore")
10039 cout
<< "SKIP (FIXME): bluestore gc does not seem to do the trick here" << std::endl
;
10043 SetVal(g_conf(), "bluestore_block_db_create", "true");
10044 SetVal(g_conf(), "bluestore_block_db_size", "4294967296");
10045 SetVal(g_conf(), "bluestore_block_size", "12884901888");
10046 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
10048 g_conf().apply_changes(nullptr);
10050 StartDeferred(65536);
10054 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
10055 ghobject_t hoid2
= hoid
;
10056 hoid2
.hobj
.snap
= 1;
10058 auto ch
= store
->create_new_collection(cid
);
10060 ObjectStore::Transaction t
;
10061 t
.create_collection(cid
, 0);
10062 cerr
<< "Creating collection " << cid
<< std::endl
;
10063 r
= queue_transaction(store
, ch
, std::move(t
));
10067 bool exists
= store
->exists(ch
, hoid
);
10068 ASSERT_TRUE(!exists
);
10070 ObjectStore::Transaction t
;
10071 t
.touch(cid
, hoid
);
10072 cerr
<< "Creating object " << hoid
<< std::endl
;
10073 r
= queue_transaction(store
, ch
, std::move(t
));
10076 exists
= store
->exists(ch
, hoid
);
10077 ASSERT_EQ(true, exists
);
10082 const int size
= 0x100;
10083 bufferptr
ap(size
);
10084 memset(ap
.c_str(), 'a', size
);
10087 uint64_t blob_size
= 524288;
10088 uint64_t total
= 0;
10089 for (i
= 0; i
<= 512; i
++) {
10090 offs
= 0 + i
* size
;
10091 ObjectStore::Transaction t
;
10092 ghobject_t hoid2
= hoid
;
10093 hoid2
.hobj
.snap
= i
+ 1;
10094 while (offs
< 128 * 1024 * 1024) {
10096 t
.write(cid
, hoid
, offs
, ap
.length(), bl
);
10098 total
+= ap
.length();
10100 t
.clone(cid
, hoid
, hoid2
);
10101 r
= queue_transaction(store
, ch
, std::move(t
));
10104 cerr
<< "Total written = " << total
<< std::endl
;
10107 cerr
<< "Finalizing" << std::endl
;
10108 const PerfCounters
* logger
= store
->get_perf_counters();
10109 ASSERT_GE(logger
->get(l_bluestore_gc_merged
), 1024*1024*1024);
10113 void doManySetAttr(ObjectStore
* store
,
10114 std::function
<void(ObjectStore
*)> do_check_fn
)
10116 MixedGenerator
gen(447);
10117 gen_type
rng(time(NULL
));
10118 coll_t
cid(spg_t(pg_t(0, 447), shard_id_t::NO_SHARD
));
10120 SyntheticWorkloadState
test_obj(store
, &gen
, &rng
, cid
, 0, 0, 0);
10122 size_t object_count
= 256;
10123 for (size_t i
= 0; i
< object_count
; ++i
) {
10124 if (!(i
% 10)) cerr
<< "seeding object " << i
<< std::endl
;
10127 for (size_t i
= 0; i
< object_count
; ++i
) {
10129 cerr
<< "Op " << i
<< std::endl
;
10130 test_obj
.print_internal_state();
10132 test_obj
.set_fixed_attrs(1024, 64, 4096); // 1024 attributes, 64 bytes name and 4K value
10134 test_obj
.wait_for_done();
10136 std::cout
<< "done" << std::endl
;
10137 do_check_fn(store
);
10138 AdminSocket
* admin_socket
= g_ceph_context
->get_admin_socket();
10139 ceph_assert(admin_socket
);
10141 ceph::bufferlist in
, out
;
10144 auto r
= admin_socket
->execute_command(
10145 { "{\"prefix\": \"bluefs stats\"}" },
10148 cerr
<< "failure querying: " << cpp_strerror(r
) << std::endl
;
10150 std::cout
<< std::string(out
.c_str(), out
.length()) << std::endl
;
10152 test_obj
.shutdown();
10155 TEST_P(StoreTestSpecificAUSize
, SpilloverTest
) {
10156 if (string(GetParam()) != "bluestore")
10159 cout
<< "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl
;
10163 SetVal(g_conf(), "bluestore_block_db_create", "true");
10164 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10165 SetVal(g_conf(), "bluestore_volume_selection_policy", "rocksdb_original");
10167 g_conf().apply_changes(nullptr);
10169 StartDeferred(65536);
10170 doManySetAttr(store
.get(),
10171 [&](ObjectStore
* _store
) {
10173 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
10174 ceph_assert(bstore
);
10176 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
10177 //experimentally it was discovered that this case results in 400+MB spillover
10178 //using lower 300MB threshold just to be safe enough
10179 std::cout
<< "db_used:" << logger
->get(l_bluefs_db_used_bytes
) << std::endl
;
10180 std::cout
<< "slow_used:" << logger
->get(l_bluefs_slow_used_bytes
) << std::endl
;
10181 ASSERT_GE(logger
->get(l_bluefs_slow_used_bytes
), 16 * 1024 * 1024);
10187 TEST_P(StoreTestSpecificAUSize
, SpilloverFixedTest
) {
10188 if (string(GetParam()) != "bluestore")
10191 cout
<< "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl
;
10195 SetVal(g_conf(), "bluestore_block_db_create", "true");
10196 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10197 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
10198 SetVal(g_conf(), "bluestore_volume_selection_reserved", "1"); // just use non-zero to enable
10200 g_conf().apply_changes(nullptr);
10202 StartDeferred(65536);
10203 doManySetAttr(store
.get(),
10204 [&](ObjectStore
* _store
) {
10206 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
10207 ceph_assert(bstore
);
10209 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
10210 ASSERT_EQ(0, logger
->get(l_bluefs_slow_used_bytes
));
10215 TEST_P(StoreTestSpecificAUSize
, SpilloverFixed2Test
) {
10216 if (string(GetParam()) != "bluestore")
10219 cout
<< "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl
;
10223 SetVal(g_conf(), "bluestore_block_db_create", "true");
10224 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10225 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
10226 //default 2.0 factor results in too high threshold, using less value
10227 // that results in less but still present spillover.
10228 SetVal(g_conf(), "bluestore_volume_selection_reserved_factor", "0.5");
10230 g_conf().apply_changes(nullptr);
10232 StartDeferred(65536);
10233 doManySetAttr(store
.get(),
10234 [&](ObjectStore
* _store
) {
10236 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
10237 ceph_assert(bstore
);
10239 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
10240 ASSERT_LE(logger
->get(l_bluefs_slow_used_bytes
), 300 * 1024 * 1024); // see SpilloverTest for 300MB choice rationale
10245 TEST_P(StoreTestSpecificAUSize
, SpilloverFixed3Test
) {
10246 if (string(GetParam()) != "bluestore")
10249 cout
<< "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl
;
10253 SetVal(g_conf(), "bluestore_block_db_create", "true");
10254 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10255 SetVal(g_conf(), "bluestore_volume_selection_policy", "fit_to_fast");
10257 g_conf().apply_changes(nullptr);
10259 StartDeferred(65536);
10260 doManySetAttr(store
.get(),
10261 [&](ObjectStore
* _store
) {
10263 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
10264 ceph_assert(bstore
);
10266 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
10267 ASSERT_EQ(logger
->get(l_bluefs_slow_used_bytes
), 0); // reffering to SpilloverFixedTest
10272 TEST_P(StoreTestSpecificAUSize
, Ticket45195Repro
) {
10273 if (string(GetParam()) != "bluestore")
10279 SetVal(g_conf(), "bluestore_default_buffered_write", "true");
10280 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
10281 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
10282 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
10283 g_conf().apply_changes(nullptr);
10285 StartDeferred(0x1000);
10289 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
10290 auto ch
= store
->create_new_collection(cid
);
10292 ObjectStore::Transaction t
;
10293 t
.create_collection(cid
, 0);
10294 cerr
<< "Creating collection " << cid
<< std::endl
;
10295 r
= queue_transaction(store
, ch
, std::move(t
));
10299 size_t large_object_size
= 1 * 1024 * 1024;
10300 size_t expected_write_size
= 0x8000;
10301 ObjectStore::Transaction t
;
10302 t
.touch(cid
, hoid
);
10303 t
.set_alloc_hint(cid
, hoid
, large_object_size
, expected_write_size
,
10304 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
|
10305 CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY
);
10306 r
= queue_transaction(store
, ch
, std::move(t
));
10310 ObjectStore::Transaction t
;
10311 bufferlist bl
, orig
;
10312 string
s(0xc000, '0');
10314 t
.write(cid
, hoid
, 0xb000, bl
.length(), bl
);
10315 r
= queue_transaction(store
, ch
, std::move(t
));
10319 ObjectStore::Transaction t
;
10320 bufferlist bl
, orig
;
10321 string
s(0x10000, '1');
10323 t
.write(cid
, hoid
, 0x16000, bl
.length(), bl
);
10324 r
= queue_transaction(store
, ch
, std::move(t
));
10328 ObjectStore::Transaction t
;
10329 bufferlist bl
, orig
;
10330 string
s(0x4000, '1');
10332 t
.write(cid
, hoid
, 0x1b000, bl
.length(), bl
);
10333 r
= queue_transaction(store
, ch
, std::move(t
));
10337 r
= store
->read(ch
, hoid
, 0xb000, 0xb000, bl
);
10338 ASSERT_EQ(r
, 0xb000);
10343 ch
= store
->open_collection(cid
);
10345 ObjectStore::Transaction t
;
10346 bufferlist bl
, orig
;
10347 string
s(0xf000, '3');
10349 t
.write(cid
, hoid
, 0xf000, bl
.length(), bl
);
10350 cerr
<< "write4" << std::endl
;
10351 r
= queue_transaction(store
, ch
, std::move(t
));
10355 r
= store
->read(ch
, hoid
, 0xb000, 0x10000, bl
);
10356 ASSERT_EQ(r
, 0x10000);
10359 TEST_P(StoreTestOmapUpgrade
, WithOmapHeader
) {
10360 if (string(GetParam()) != "bluestore")
10363 SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
10364 g_conf().apply_changes(nullptr);
10367 int64_t poolid
= 11;
10368 coll_t
cid(spg_t(pg_t(1, poolid
), shard_id_t::NO_SHARD
));
10369 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, poolid
, ""));
10370 auto ch
= store
->create_new_collection(cid
);
10373 ObjectStore::Transaction t
;
10374 t
.create_collection(cid
, 0);
10375 r
= queue_transaction(store
, ch
, std::move(t
));
10379 map
<string
, bufferlist
> attrs
;
10380 bufferlist expected_header
;
10381 expected_header
.append("this is a header");
10383 ObjectStore::Transaction t
;
10384 t
.touch(cid
, hoid
);
10386 header
.append(expected_header
);
10387 t
.omap_setheader(cid
, hoid
, header
);
10388 map
<string
, bufferlist
> start_set
;
10390 bl
.append(string("value"));
10391 start_set
.emplace(string("key1"), bl
);
10392 t
.omap_setkeys(cid
, hoid
, start_set
);
10393 r
= queue_transaction(store
, ch
, std::move(t
));
10396 map
<string
,bufferlist
> res
;
10398 r
= store
->omap_get(ch
, hoid
, &h
, &res
);
10400 ASSERT_TRUE(bl_eq(h
, expected_header
));
10401 ASSERT_EQ(res
.size(), 1);
10402 ASSERT_EQ(res
.begin()->first
, "key1");
10405 ASSERT_EQ(store
->fsck(false), 0);
10406 SetVal(g_conf(), "bluestore_debug_legacy_omap", "false");
10407 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
10408 g_conf().apply_changes(nullptr);
10409 ASSERT_EQ(store
->fsck(false), 2);
10410 ASSERT_EQ(store
->quick_fix(), 0);
10412 ch
= store
->open_collection(cid
);
10414 map
<string
,bufferlist
> res
;
10416 r
= store
->omap_get(ch
, hoid
, &h
, &res
);
10418 ASSERT_EQ(res
.size(), 1);
10419 ASSERT_EQ(res
.begin()->first
, "key1");
10422 ObjectStore::Transaction t
;
10423 t
.remove(cid
, hoid
);
10424 t
.remove_collection(cid
);
10425 r
= queue_transaction(store
, ch
, std::move(t
));
10430 TEST_P(StoreTestSpecificAUSize
, BluefsWriteInSingleDiskEnvTest
) {
10431 if (string(GetParam()) != "bluestore")
10434 g_conf().apply_changes(nullptr);
10436 StartDeferred(0x1000);
10438 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
10439 ceph_assert(bstore
);
10440 bstore
->inject_bluefs_file("db.slow", "store_test_injection_slow", 1 << 20ul);
10441 bstore
->inject_bluefs_file("db.wal", "store_test_injection_wal", 1 << 20ul);
10442 bstore
->inject_bluefs_file("db", "store_test_injection_wal", 1 << 20ul);
10444 AdminSocket
* admin_socket
= g_ceph_context
->get_admin_socket();
10445 ceph_assert(admin_socket
);
10447 ceph::bufferlist in
, out
;
10449 auto r
= admin_socket
->execute_command(
10450 { "{\"prefix\": \"bluefs stats\"}" },
10453 cerr
<< "failure querying: " << cpp_strerror(r
) << std::endl
;
10455 std::cout
<< std::string(out
.c_str(), out
.length()) << std::endl
;
10459 TEST_P(StoreTestSpecificAUSize
, BluefsWriteInNoWalDiskEnvTest
) {
10460 if (string(GetParam()) != "bluestore")
10463 SetVal(g_conf(), "bluestore_block_db_path", "db");
10464 SetVal(g_conf(), "bluestore_block_db_size", stringify(1ull << 31).c_str());
10465 SetVal(g_conf(), "bluestore_block_db_create", "true");
10467 g_conf().apply_changes(nullptr);
10469 StartDeferred(0x1000);
10471 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
10472 ceph_assert(bstore
);
10473 bstore
->inject_bluefs_file("db.slow", "store_test_injection_slow", 1 << 20ul);
10474 bstore
->inject_bluefs_file("db.wal", "store_test_injection_wal", 1 << 20ul);
10475 bstore
->inject_bluefs_file("db", "store_test_injection_wal", 1 << 20ul);
10477 AdminSocket
* admin_socket
= g_ceph_context
->get_admin_socket();
10478 ceph_assert(admin_socket
);
10480 ceph::bufferlist in
, out
;
10482 auto r
= admin_socket
->execute_command(
10483 { "{\"prefix\": \"bluefs stats\"}" },
10486 cerr
<< "failure querying: " << cpp_strerror(r
) << std::endl
;
10489 std::cout
<< std::string(out
.c_str(), out
.length()) << std::endl
;
10493 TEST_P(StoreTestOmapUpgrade
, NoOmapHeader
) {
10494 if (string(GetParam()) != "bluestore")
10497 SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
10498 g_conf().apply_changes(nullptr);
10501 int64_t poolid
= 11;
10502 coll_t
cid(spg_t(pg_t(1, poolid
), shard_id_t::NO_SHARD
));
10503 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, poolid
, ""));
10504 auto ch
= store
->create_new_collection(cid
);
10507 ObjectStore::Transaction t
;
10508 t
.create_collection(cid
, 0);
10509 r
= queue_transaction(store
, ch
, std::move(t
));
10513 map
<string
, bufferlist
> attrs
;
10515 ObjectStore::Transaction t
;
10516 t
.touch(cid
, hoid
);
10517 map
<string
, bufferlist
> start_set
;
10519 bl
.append(string("value"));
10520 start_set
.emplace(string("key1"), bl
);
10521 t
.omap_setkeys(cid
, hoid
, start_set
);
10522 r
= queue_transaction(store
, ch
, std::move(t
));
10525 map
<string
,bufferlist
> res
;
10527 r
= store
->omap_get(ch
, hoid
, &h
, &res
);
10529 ASSERT_EQ(h
.length(), 0);
10530 ASSERT_EQ(res
.size(), 1);
10531 ASSERT_EQ(res
.begin()->first
, "key1");
10534 ASSERT_EQ(store
->fsck(false), 0);
10535 SetVal(g_conf(), "bluestore_debug_legacy_omap", "false");
10536 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
10537 g_conf().apply_changes(nullptr);
10538 ASSERT_EQ(store
->fsck(false), 2);
10539 ASSERT_EQ(store
->quick_fix(), 0);
10541 ch
= store
->open_collection(cid
);
10543 map
<string
,bufferlist
> res
;
10545 r
= store
->omap_get(ch
, hoid
, &h
, &res
);
10547 ASSERT_EQ(res
.size(), 1);
10548 ASSERT_EQ(res
.begin()->first
, "key1");
10551 ObjectStore::Transaction t
;
10552 t
.remove(cid
, hoid
);
10553 t
.remove_collection(cid
);
10554 r
= queue_transaction(store
, ch
, std::move(t
));
10559 TEST_P(StoreTestOmapUpgrade
, LargeLegacyToPG
) {
10560 if (string(GetParam()) != "bluestore")
10563 SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
10564 g_conf().apply_changes(nullptr);
10569 ObjectStore::CollectionHandle ch
;
10572 cid
= coll_t(spg_t(pg_t(1, poolid
), shard_id_t::NO_SHARD
));
10573 ch
= store
->create_new_collection(cid
);
10576 ObjectStore::Transaction t
;
10577 t
.create_collection(cid
, 0);
10578 r
= queue_transaction(store
, ch
, std::move(t
));
10581 //ASSERT_EQ(false, g_conf().get_val<bool>("bluestore_debug_inject_upgrade_bug53062"));
10582 map
<string
, bufferlist
> attrs
;
10583 bufferlist expected_header
;
10584 expected_header
.append("this is a header");
10586 size_t object_count
= 1000;
10587 make_omap_data(object_count
, poolid
, cid
);
10588 //checking just written data
10589 check_omap_data(object_count
, poolid
, cid
);
10592 ASSERT_EQ(store
->fsck(false), 0);
10593 SetVal(g_conf(), "bluestore_debug_legacy_omap", "false");
10594 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
10595 g_conf().apply_changes(nullptr);
10596 ASSERT_EQ(store
->fsck(false), 1001);
10597 ASSERT_EQ(store
->quick_fix(), 0);
10599 ch
= store
->open_collection(cid
);
10601 //checking quick_fix() data
10602 check_omap_data(object_count
, poolid
, cid
);
10605 ObjectStore::Transaction t
;
10606 for (size_t o
= 0; o
< object_count
; o
++)
10608 std::string oid
= generate_monotonic_name(object_count
, o
, 3.71, 0.5);
10609 ghobject_t
hoid(hobject_t(oid
, "", CEPH_NOSNAP
, 0, poolid
, ""));
10610 t
.remove(cid
, hoid
);
10612 t
.remove_collection(cid
);
10613 r
= queue_transaction(store
, ch
, std::move(t
));
10618 #endif // WITH_BLUESTORE
10620 int main(int argc
, char **argv
) {
10621 auto args
= argv_to_vec(argc
, argv
);
10622 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
10623 CODE_ENVIRONMENT_UTILITY
,
10624 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
10625 common_init_finish(g_ceph_context
);
10627 for (auto& i
: args
) {
10628 if (i
== "--smr"s
) {
10629 #if defined(HAVE_LIBZBD)
10630 derr
<< "Adjusting tests for smr mode." << dendl
;
10633 derr
<< "smr mode selected, but support not compiled in" << dendl
;
10639 // make sure we can adjust any config settings
10640 g_ceph_context
->_conf
._clear_safe_to_start_threads();
10642 g_ceph_context
->_conf
.set_val_or_die("osd_journal_size", "400");
10643 g_ceph_context
->_conf
.set_val_or_die("filestore_index_retry_probability", "0.5");
10644 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_timeout", "1000");
10645 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_suicide_timeout", "10000");
10646 //g_ceph_context->_conf.set_val_or_die("filestore_fiemap", "true");
10647 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mkfs", "false");
10648 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mount", "false");
10649 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_umount", "false");
10650 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_small_allocations", "4");
10651 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_freelist", "true");
10652 g_ceph_context
->_conf
.set_val_or_die("bluestore_clone_cow", "true");
10653 g_ceph_context
->_conf
.set_val_or_die("bluestore_max_alloc_size", "196608");
10655 // set small cache sizes so we see trimming during Synthetic tests
10656 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_hdd", "4000000");
10657 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_ssd", "4000000");
10659 // very short *_max prealloc so that we fall back to async submits
10660 g_ceph_context
->_conf
.set_val_or_die("bluestore_blobid_prealloc", "10");
10661 g_ceph_context
->_conf
.set_val_or_die("bluestore_nid_prealloc", "10");
10662 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_randomize_serial_transaction",
10665 g_ceph_context
->_conf
.set_val_or_die("bdev_debug_aio", "true");
10667 // specify device size
10668 g_ceph_context
->_conf
.set_val_or_die("bluestore_block_size",
10669 stringify(DEF_STORE_TEST_BLOCKDEV_SIZE
));
10671 g_ceph_context
->_conf
.set_val_or_die(
10672 "enable_experimental_unrecoverable_data_corrupting_features", "*");
10673 g_ceph_context
->_conf
.apply_changes(nullptr);
10675 ::testing::InitGoogleTest(&argc
, argv
);
10676 return RUN_ALL_TESTS();
10681 * compile-command: "cd ../.. ; make ceph_test_objectstore &&
10682 * ./ceph_test_objectstore \
10683 * --gtest_filter=*.collect_metadata* --log-to-stderr=true --debug-filestore=20