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 #if defined(WITH_BLUESTORE)
30 #include "os/bluestore/BlueStore.h"
31 #include "os/bluestore/BlueFS.h"
33 #include "include/Context.h"
34 #include "common/buffer_instrumentation.h"
35 #include "common/ceph_argparse.h"
36 #include "common/admin_socket.h"
37 #include "global/global_init.h"
38 #include "common/ceph_mutex.h"
39 #include "common/Cond.h"
40 #include "common/errno.h"
41 #include "common/options.h" // for the size literals
42 #include "common/pretty_binary.h"
43 #include "include/stringify.h"
44 #include "include/coredumpctl.h"
45 #include "include/unordered_map.h"
47 #include "store_test_fixture.h"
51 using namespace std::placeholders
;
53 typedef boost::mt11213b gen_type
;
55 const uint64_t DEF_STORE_TEST_BLOCKDEV_SIZE
= 10240000000;
56 #define dout_context g_ceph_context
60 static bool bl_eq(bufferlist
& expected
, bufferlist
& actual
)
62 if (expected
.contents_equal(actual
))
66 if(expected
.length() != actual
.length()) {
67 cout
<< "--- buffer lengths mismatch " << std::hex
68 << "expected 0x" << expected
.length() << " != actual 0x"
69 << actual
.length() << std::dec
<< std::endl
;
70 derr
<< "--- buffer lengths mismatch " << std::hex
71 << "expected 0x" << expected
.length() << " != actual 0x"
72 << actual
.length() << std::dec
<< dendl
;
74 auto len
= std::min(expected
.length(), actual
.length());
75 while ( first
<len
&& expected
[first
] == actual
[first
])
78 while (last
> 0 && expected
[last
-1] == actual
[last
-1])
81 cout
<< "--- buffer mismatch between offset 0x" << std::hex
<< first
82 << " and 0x" << last
<< ", total 0x" << len
<< std::dec
84 derr
<< "--- buffer mismatch between offset 0x" << std::hex
<< first
85 << " and 0x" << last
<< ", total 0x" << len
<< std::dec
87 cout
<< "--- expected:\n";
88 expected
.hexdump(cout
);
89 cout
<< "--- actual:\n";
98 int queue_transaction(
100 ObjectStore::CollectionHandle ch
,
101 ObjectStore::Transaction
&&t
) {
103 ObjectStore::Transaction t2
;
105 return store
->queue_transaction(ch
, std::move(t2
));
107 return store
->queue_transaction(ch
, std::move(t
));
111 template <typename T
>
112 int collection_list(T
&store
, ObjectStore::CollectionHandle
&c
,
113 const ghobject_t
& start
, const ghobject_t
& end
, int max
,
114 vector
<ghobject_t
> *ls
, ghobject_t
*pnext
,
115 bool disable_legacy
= false) {
116 if (disable_legacy
|| rand() % 2) {
117 return store
->collection_list(c
, start
, end
, max
, ls
, pnext
);
119 return store
->collection_list_legacy(c
, start
, end
, max
, ls
, pnext
);
123 bool sorted(const vector
<ghobject_t
> &in
) {
125 for (vector
<ghobject_t
>::const_iterator i
= in
.begin();
129 cout
<< start
<< " should follow " << *i
<< std::endl
;
137 class StoreTest
: public StoreTestFixture
,
138 public ::testing::WithParamInterface
<const char*> {
141 : StoreTestFixture(GetParam())
143 void doCompressionTest();
144 void doSyntheticTest(
146 uint64_t max_obj
, uint64_t max_wr
, uint64_t align
);
149 class StoreTestDeferredSetup
: public StoreTest
{
150 void SetUp() override
{
155 void DeferredSetup() {
163 class StoreTestSpecificAUSize
: public StoreTestDeferredSetup
{
171 uint64_t align
)> MatrixTest
;
173 void StartDeferred(size_t min_alloc_size
) {
174 SetVal(g_conf(), "bluestore_min_alloc_size", stringify(min_alloc_size
).c_str());
179 // bluestore matrix testing
180 uint64_t max_write
= 40 * 1024;
181 uint64_t max_size
= 400 * 1024;
182 uint64_t alignment
= 0;
183 uint64_t num_ops
= 10000;
186 string
matrix_get(const char *k
) {
187 if (string(k
) == "max_write") {
188 return stringify(max_write
);
189 } else if (string(k
) == "max_size") {
190 return stringify(max_size
);
191 } else if (string(k
) == "alignment") {
192 return stringify(alignment
);
193 } else if (string(k
) == "num_ops") {
194 return stringify(num_ops
);
197 g_conf().get_val(k
, &buf
, -1);
204 void matrix_set(const char *k
, const char *v
) {
205 if (string(k
) == "max_write") {
206 max_write
= atoll(v
);
207 } else if (string(k
) == "max_size") {
209 } else if (string(k
) == "alignment") {
210 alignment
= atoll(v
);
211 } else if (string(k
) == "num_ops") {
214 SetVal(g_conf(), k
, v
);
218 void do_matrix_choose(const char *matrix
[][10],
219 int i
, int pos
, int num
,
223 for (count
= 0; matrix
[i
][count
+1]; ++count
) ;
224 for (int j
= 1; matrix
[i
][j
]; ++j
) {
225 matrix_set(matrix
[i
][0], matrix
[i
][j
]);
226 do_matrix_choose(matrix
,
233 cout
<< "---------------------- " << (pos
+ 1) << " / " << num
234 << " ----------------------" << std::endl
;
235 for (unsigned k
=0; matrix
[k
][0]; ++k
) {
236 cout
<< " " << matrix
[k
][0] << " = " << matrix_get(matrix
[k
][0])
239 g_ceph_context
->_conf
.apply_changes(nullptr);
240 fn(num_ops
, max_size
, max_write
, alignment
);
244 void do_matrix(const char *matrix
[][10],
247 if (strcmp(matrix
[0][0], "bluestore_min_alloc_size") == 0) {
249 for (count
= 0; matrix
[0][count
+1]; ++count
) ;
250 for (size_t j
= 1; matrix
[0][j
]; ++j
) {
254 StartDeferred(strtoll(matrix
[0][j
], NULL
, 10));
255 do_matrix_choose(matrix
, 1, j
- 1, count
, fn
);
259 do_matrix_choose(matrix
, 0, 0, 1, fn
);
265 class StoreTestOmapUpgrade
: public StoreTestDeferredSetup
{
267 void StartDeferred() {
282 std::string
generate_monotonic_name(uint32_t SUM
, uint32_t i
, double r
, double x
)
285 //std::cout << "r=" << r << " x=" << x << std::endl;
289 uint32_t hi
= 1 + gen() * 10;
290 uint32_t start
= ('z' - 'a' + 1 - hi
) * gen();
291 while (hi
- lo
> 0) {
292 uint32_t mid
= (lo
+ hi
+ 1 + (SUM
&1)) / 2; // round up or down, depending on SUM
293 // std::cout << "SUM=" << SUM << " x=" << gen.x << std::endl;
294 uint32_t mid_val
= gen() * (SUM
- 1) + 1;
295 // LEFT = lo .. mid - 1
297 // std::cout << "lo=" << lo << " hi=" << hi << " mid=" << mid
298 // << " SUM=" << SUM << " i=" << i << " x=" << gen.x << " mid_val=" << mid_val << std::endl;
308 //std::cout << "lo=" << lo << " hi=" << hi
309 // << " SUM=" << SUM << " i=" << i << std::endl;
311 s
.push_back('a' + lo
+ start
); // to keep alphabetic order
312 uint32_t cnt
= gen() * 8;
313 for (uint32_t j
= 0; j
< cnt
; j
++) {
314 s
.push_back('a' + ('z' - 'a' + 1) * gen());
321 std::string
gen_string(size_t size
, generator
& gen
) {
323 for (size_t i
= 0; i
< size
; i
++) {
324 s
.push_back('a' + ('z' - 'a' + 1 ) * gen());
329 void make_omap_data(size_t object_count
,
333 ObjectStore::CollectionHandle ch
= store
->open_collection(cid
);
334 for (size_t o
= 0; o
< object_count
; o
++)
336 ObjectStore::Transaction t
;
337 std::string oid
= generate_monotonic_name(object_count
, o
, 3.71, 0.5);
338 ghobject_t
hoid(hobject_t(oid
, "", CEPH_NOSNAP
, 0, poolid
, ""));
340 generator gen
{3.85 + 0.1 * o
/ object_count
, 1 - double(o
) / object_count
};
342 map
<string
, bufferlist
> start_set
;
343 size_t omap_count
= 1 + gen() * 20;
344 bool do_omap_header
= gen() > 0.5;
345 if (do_omap_header
) {
347 header
.append(gen_string(50, gen
));
348 t
.omap_setheader(cid
, hoid
, header
);
350 for (size_t i
= 0; i
< omap_count
; i
++) {
351 std::string name
= generate_monotonic_name(omap_count
, i
, 3.66 + 0.22 * o
/ object_count
, 0.5);
353 val
.append(gen_string(100, gen
));
354 start_set
.emplace(name
, val
);
356 t
.omap_setkeys(cid
, hoid
, start_set
);
357 r
= queue_transaction(store
, ch
, std::move(t
));
362 void check_omap_data(size_t object_count
,
366 ObjectStore::CollectionHandle ch
= store
->open_collection(cid
);
368 for (size_t o
= 0; o
< object_count
; o
++)
370 ObjectStore::Transaction t
;
371 std::string oid
= generate_monotonic_name(object_count
, o
, 3.71, 0.5);
372 ghobject_t
hoid(hobject_t(oid
, "", CEPH_NOSNAP
, 0, poolid
, ""));
373 generator gen
{3.85 + 0.1 * o
/ object_count
, 1 - double(o
) / object_count
};
375 bufferlist omap_header
;
376 map
<string
, bufferlist
> omap_set
;
377 r
= store
->omap_get(ch
, hoid
, &omap_header
, &omap_set
);
379 size_t omap_count
= 1 + gen() * 20;
380 bool do_omap_header
= gen() > 0.5;
381 if (do_omap_header
) {
382 std::string header_str
= gen_string(50, gen
);
383 ASSERT_EQ(header_str
, omap_header
.to_str());
385 auto it
= omap_set
.begin();
386 for (size_t i
= 0; i
< omap_count
; i
++) {
387 ASSERT_TRUE(it
!= omap_set
.end());
388 std::string name
= generate_monotonic_name(omap_count
, i
, 3.66 + 0.22 * o
/ object_count
, 0.5);
389 std::string val_gen
= gen_string(100, gen
);
390 ASSERT_EQ(it
->first
, name
);
391 ASSERT_EQ(it
->second
.to_str(), val_gen
);
398 TEST_P(StoreTest
, collect_metadata
) {
399 map
<string
,string
> pm
;
400 store
->collect_metadata(&pm
);
401 if (GetParam() == string("filestore")) {
402 ASSERT_NE(pm
.count("filestore_backend"), 0u);
403 ASSERT_NE(pm
.count("filestore_f_type"), 0u);
404 ASSERT_NE(pm
.count("backend_filestore_partition_path"), 0u);
405 ASSERT_NE(pm
.count("backend_filestore_dev_node"), 0u);
409 TEST_P(StoreTest
, Trivial
) {
412 TEST_P(StoreTest
, TrivialRemount
) {
413 int r
= store
->umount();
419 TEST_P(StoreTest
, TrivialRemountFsck
) {
420 if(string(GetParam()) != "bluestore")
422 int r
= store
->umount();
424 r
= store
->fsck(false);
430 TEST_P(StoreTest
, SimpleRemount
) {
432 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
433 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
435 bl
.append("1234512345");
437 auto ch
= store
->create_new_collection(cid
);
439 cerr
<< "create collection + write" << std::endl
;
440 ObjectStore::Transaction t
;
441 t
.create_collection(cid
, 0);
442 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
443 r
= queue_transaction(store
, ch
, std::move(t
));
451 ch
= store
->open_collection(cid
);
453 ObjectStore::Transaction t
;
454 t
.write(cid
, hoid2
, 0, bl
.length(), bl
);
455 r
= queue_transaction(store
, ch
, std::move(t
));
459 ObjectStore::Transaction t
;
461 t
.remove(cid
, hoid2
);
462 t
.remove_collection(cid
);
463 cerr
<< "remove collection" << std::endl
;
464 r
= queue_transaction(store
, ch
, std::move(t
));
472 ch
= store
->create_new_collection(cid
);
474 ObjectStore::Transaction t
;
475 t
.create_collection(cid
, 0);
476 r
= queue_transaction(store
, ch
, std::move(t
));
478 bool exists
= store
->exists(ch
, hoid
);
479 ASSERT_TRUE(!exists
);
482 ObjectStore::Transaction t
;
483 t
.remove_collection(cid
);
484 cerr
<< "remove collection" << std::endl
;
485 r
= queue_transaction(store
, ch
, std::move(t
));
490 TEST_P(StoreTest
, IORemount
) {
493 bl
.append("1234512345");
495 auto ch
= store
->create_new_collection(cid
);
497 cerr
<< "create collection + objects" << std::endl
;
498 ObjectStore::Transaction t
;
499 t
.create_collection(cid
, 0);
500 for (int n
=1; n
<=100; ++n
) {
501 ghobject_t
hoid(hobject_t(sobject_t("Object " + stringify(n
), CEPH_NOSNAP
)));
502 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
504 r
= queue_transaction(store
, ch
, std::move(t
));
509 cout
<< "overwrites" << std::endl
;
510 for (int n
=1; n
<=100; ++n
) {
511 ObjectStore::Transaction t
;
512 ghobject_t
hoid(hobject_t(sobject_t("Object " + stringify(n
), CEPH_NOSNAP
)));
513 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
514 r
= queue_transaction(store
, ch
, std::move(t
));
524 ObjectStore::Transaction t
;
525 for (int n
=1; n
<=100; ++n
) {
526 ghobject_t
hoid(hobject_t(sobject_t("Object " + stringify(n
), CEPH_NOSNAP
)));
529 t
.remove_collection(cid
);
530 auto ch
= store
->open_collection(cid
);
531 r
= queue_transaction(store
, ch
, std::move(t
));
536 TEST_P(StoreTest
, UnprintableCharsName
) {
538 string name
= "funnychars_";
539 for (unsigned i
= 0; i
< 256; ++i
) {
542 ghobject_t
oid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)));
544 auto ch
= store
->create_new_collection(cid
);
546 cerr
<< "create collection + object" << std::endl
;
547 ObjectStore::Transaction t
;
548 t
.create_collection(cid
, 0);
550 r
= queue_transaction(store
, ch
, std::move(t
));
559 cout
<< "removing" << std::endl
;
560 ObjectStore::Transaction t
;
562 t
.remove_collection(cid
);
563 auto ch
= store
->open_collection(cid
);
564 r
= queue_transaction(store
, ch
, std::move(t
));
569 TEST_P(StoreTest
, FiemapEmpty
) {
572 ghobject_t
oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP
)));
573 auto ch
= store
->create_new_collection(cid
);
575 ObjectStore::Transaction t
;
576 t
.create_collection(cid
, 0);
578 t
.truncate(cid
, oid
, 100000);
579 r
= queue_transaction(store
, ch
, std::move(t
));
584 store
->fiemap(ch
, oid
, 0, 100000, bl
);
585 map
<uint64_t,uint64_t> m
, e
;
586 auto p
= bl
.cbegin();
588 cout
<< " got " << m
<< std::endl
;
590 EXPECT_TRUE(m
== e
|| m
.empty());
593 ObjectStore::Transaction t
;
595 t
.remove_collection(cid
);
596 cerr
<< "remove collection" << std::endl
;
597 r
= queue_transaction(store
, ch
, std::move(t
));
602 TEST_P(StoreTest
, FiemapHoles
) {
603 const uint64_t MAX_EXTENTS
= 4000;
604 const uint64_t SKIP_STEP
= 65536;
607 ghobject_t
oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP
)));
610 auto ch
= store
->create_new_collection(cid
);
612 ObjectStore::Transaction t
;
613 t
.create_collection(cid
, 0);
615 for (uint64_t i
= 0; i
< MAX_EXTENTS
; i
++)
616 t
.write(cid
, oid
, SKIP_STEP
* i
, 3, bl
);
617 r
= queue_transaction(store
, ch
, std::move(t
));
621 //fiemap test from 0 to SKIP_STEP * (MAX_EXTENTS - 1) + 3
623 store
->fiemap(ch
, oid
, 0, SKIP_STEP
* (MAX_EXTENTS
- 1) + 3, bl
);
624 map
<uint64_t,uint64_t> m
, e
;
625 auto p
= bl
.cbegin();
627 cout
<< " got " << m
<< std::endl
;
628 ASSERT_TRUE(!m
.empty());
630 auto last
= m
.crbegin();
632 ASSERT_EQ(0u, last
->first
);
633 } else if (m
.size() == MAX_EXTENTS
) {
634 for (uint64_t i
= 0; i
< MAX_EXTENTS
; i
++) {
635 ASSERT_TRUE(m
.count(SKIP_STEP
* i
));
638 ASSERT_GT(last
->first
+ last
->second
, SKIP_STEP
* (MAX_EXTENTS
- 1));
641 // fiemap test from SKIP_STEP to SKIP_STEP * (MAX_EXTENTS - 2) + 3
643 store
->fiemap(ch
, oid
, SKIP_STEP
, SKIP_STEP
* (MAX_EXTENTS
- 2) + 3, bl
);
644 map
<uint64_t,uint64_t> m
, e
;
645 auto p
= bl
.cbegin();
647 cout
<< " got " << m
<< std::endl
;
648 ASSERT_TRUE(!m
.empty());
649 // kstore always returns [0, object_size] regardless of offset and length
650 // FIXME: if fiemap logic in kstore is refined
651 if (string(GetParam()) != "kstore") {
652 ASSERT_GE(m
[SKIP_STEP
], 3u);
653 auto last
= m
.crbegin();
655 ASSERT_EQ(SKIP_STEP
, last
->first
);
656 } else if (m
.size() == MAX_EXTENTS
- 2) {
657 for (uint64_t i
= 1; i
< MAX_EXTENTS
- 1; i
++) {
658 ASSERT_TRUE(m
.count(SKIP_STEP
*i
));
661 ASSERT_GT(last
->first
+ last
->second
, SKIP_STEP
* (MAX_EXTENTS
- 1));
665 ObjectStore::Transaction t
;
667 t
.remove_collection(cid
);
668 cerr
<< "remove collection" << std::endl
;
669 r
= queue_transaction(store
, ch
, std::move(t
));
674 TEST_P(StoreTest
, SimpleMetaColTest
) {
678 auto ch
= store
->create_new_collection(cid
);
679 ObjectStore::Transaction t
;
680 t
.create_collection(cid
, 0);
681 cerr
<< "create collection" << std::endl
;
682 r
= queue_transaction(store
, ch
, std::move(t
));
686 ObjectStore::Transaction t
;
687 t
.remove_collection(cid
);
688 cerr
<< "remove collection" << std::endl
;
689 auto ch
= store
->open_collection(cid
);
690 r
= queue_transaction(store
, ch
, std::move(t
));
694 auto ch
= store
->create_new_collection(cid
);
695 ObjectStore::Transaction t
;
696 t
.create_collection(cid
, 0);
697 cerr
<< "add collection" << std::endl
;
698 r
= queue_transaction(store
, ch
, std::move(t
));
702 ObjectStore::Transaction t
;
703 t
.remove_collection(cid
);
704 cerr
<< "remove collection" << std::endl
;
705 auto ch
= store
->open_collection(cid
);
706 r
= queue_transaction(store
, ch
, std::move(t
));
711 TEST_P(StoreTest
, SimplePGColTest
) {
712 coll_t
cid(spg_t(pg_t(1,2), shard_id_t::NO_SHARD
));
715 ObjectStore::Transaction t
;
716 auto ch
= store
->create_new_collection(cid
);
717 t
.create_collection(cid
, 4);
718 cerr
<< "create collection" << std::endl
;
719 r
= queue_transaction(store
, ch
, std::move(t
));
723 ObjectStore::Transaction t
;
724 t
.remove_collection(cid
);
725 cerr
<< "remove collection" << std::endl
;
726 auto ch
= store
->open_collection(cid
);
727 r
= queue_transaction(store
, ch
, std::move(t
));
731 ObjectStore::Transaction t
;
732 t
.create_collection(cid
, 4);
733 cerr
<< "add collection" << std::endl
;
734 auto ch
= store
->create_new_collection(cid
);
735 r
= queue_transaction(store
, ch
, std::move(t
));
739 ObjectStore::Transaction t
;
740 t
.remove_collection(cid
);
741 cerr
<< "remove collection" << std::endl
;
742 auto ch
= store
->open_collection(cid
);
743 r
= queue_transaction(store
, ch
, std::move(t
));
748 TEST_P(StoreTest
, SimpleColPreHashTest
) {
749 // Firstly we will need to revert the value making sure
750 // collection hint actually works
751 int merge_threshold
= g_ceph_context
->_conf
->filestore_merge_threshold
;
752 std::ostringstream oss
;
753 if (merge_threshold
> 0) {
754 oss
<< "-" << merge_threshold
;
755 SetVal(g_conf(), "filestore_merge_threshold", oss
.str().c_str());
758 uint32_t pg_num
= 128;
760 boost::uniform_int
<> pg_id_range(0, pg_num
);
761 gen_type
rng(time(NULL
));
762 int pg_id
= pg_id_range(rng
);
764 int objs_per_folder
= abs(merge_threshold
) * 16 * g_ceph_context
->_conf
->filestore_split_multiple
;
765 boost::uniform_int
<> folders_range(5, 256);
766 uint64_t expected_num_objs
= (uint64_t)objs_per_folder
* (uint64_t)folders_range(rng
);
768 coll_t
cid(spg_t(pg_t(pg_id
, 15), shard_id_t::NO_SHARD
));
770 auto ch
= store
->create_new_collection(cid
);
772 // Create a collection along with a hint
773 ObjectStore::Transaction t
;
774 t
.create_collection(cid
, 5);
775 cerr
<< "create collection" << std::endl
;
777 encode(pg_num
, hint
);
778 encode(expected_num_objs
, hint
);
779 t
.collection_hint(cid
, ObjectStore::Transaction::COLL_HINT_EXPECTED_NUM_OBJECTS
, hint
);
780 cerr
<< "collection hint" << std::endl
;
781 r
= queue_transaction(store
, ch
, std::move(t
));
785 // Remove the collection
786 ObjectStore::Transaction t
;
787 t
.remove_collection(cid
);
788 cerr
<< "remove collection" << std::endl
;
789 r
= queue_transaction(store
, ch
, std::move(t
));
794 TEST_P(StoreTest
, SmallBlockWrites
) {
797 auto ch
= store
->create_new_collection(cid
);
798 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
800 ObjectStore::Transaction t
;
801 t
.create_collection(cid
, 0);
802 cerr
<< "Creating collection " << cid
<< std::endl
;
803 r
= queue_transaction(store
, ch
, std::move(t
));
807 bufferptr
ap(0x1000);
808 memset(ap
.c_str(), 'a', 0x1000);
811 bufferptr
bp(0x1000);
812 memset(bp
.c_str(), 'b', 0x1000);
815 bufferptr
cp(0x1000);
816 memset(cp
.c_str(), 'c', 0x1000);
818 bufferptr
zp(0x1000);
823 ObjectStore::Transaction t
;
824 t
.write(cid
, hoid
, 0, 0x1000, a
);
825 r
= queue_transaction(store
, ch
, std::move(t
));
829 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
830 ASSERT_EQ(0x1000, r
);
832 ASSERT_TRUE(bl_eq(exp
, in
));
835 ObjectStore::Transaction t
;
836 t
.write(cid
, hoid
, 0x1000, 0x1000, b
);
837 r
= queue_transaction(store
, ch
, std::move(t
));
841 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
842 ASSERT_EQ(0x2000, r
);
845 ASSERT_TRUE(bl_eq(exp
, in
));
848 ObjectStore::Transaction t
;
849 t
.write(cid
, hoid
, 0x3000, 0x1000, c
);
850 r
= queue_transaction(store
, ch
, std::move(t
));
854 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
855 ASSERT_EQ(0x4000, r
);
860 ASSERT_TRUE(bl_eq(exp
, in
));
863 ObjectStore::Transaction t
;
864 t
.write(cid
, hoid
, 0x2000, 0x1000, a
);
865 r
= queue_transaction(store
, ch
, std::move(t
));
869 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
870 ASSERT_EQ(0x4000, r
);
875 ASSERT_TRUE(bl_eq(exp
, in
));
878 ObjectStore::Transaction t
;
879 t
.write(cid
, hoid
, 0, 0x1000, c
);
880 r
= queue_transaction(store
, ch
, std::move(t
));
885 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
886 ASSERT_EQ(0x4000, r
);
891 ASSERT_TRUE(bl_eq(exp
, in
));
894 ObjectStore::Transaction t
;
896 t
.remove_collection(cid
);
897 cerr
<< "Cleaning" << std::endl
;
898 r
= queue_transaction(store
, ch
, std::move(t
));
903 TEST_P(StoreTest
, BufferCacheReadTest
) {
906 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
908 auto ch
= store
->open_collection(cid
);
911 auto ch
= store
->create_new_collection(cid
);
913 ObjectStore::Transaction t
;
914 t
.create_collection(cid
, 0);
915 cerr
<< "Creating collection " << cid
<< std::endl
;
916 r
= queue_transaction(store
, ch
, std::move(t
));
920 bool exists
= store
->exists(ch
, hoid
);
921 ASSERT_TRUE(!exists
);
923 ObjectStore::Transaction t
;
925 cerr
<< "Creating object " << hoid
<< std::endl
;
926 r
= queue_transaction(store
, ch
, std::move(t
));
929 exists
= store
->exists(ch
, hoid
);
930 ASSERT_EQ(true, exists
);
933 ObjectStore::Transaction t
;
934 bufferlist bl
, newdata
;
936 t
.write(cid
, hoid
, 0, 5, bl
);
937 t
.write(cid
, hoid
, 10, 5, bl
);
938 cerr
<< "TwinWrite" << std::endl
;
939 r
= queue_transaction(store
, ch
, std::move(t
));
942 r
= store
->read(ch
, hoid
, 0, 15, newdata
);
947 expected
.append_zero(5);
949 ASSERT_TRUE(bl_eq(expected
, newdata
));
952 //overwrite over the same extents
954 ObjectStore::Transaction t
;
955 bufferlist bl
, newdata
;
957 t
.write(cid
, hoid
, 0, 5, bl
);
958 t
.write(cid
, hoid
, 10, 5, bl
);
959 cerr
<< "TwinWrite" << std::endl
;
960 r
= queue_transaction(store
, ch
, std::move(t
));
963 r
= store
->read(ch
, hoid
, 0, 15, newdata
);
968 expected
.append_zero(5);
970 ASSERT_TRUE(bl_eq(expected
, newdata
));
973 //additional write to an unused region of some blob
975 ObjectStore::Transaction t
;
976 bufferlist bl2
, newdata
;
977 bl2
.append("1234567890");
979 t
.write(cid
, hoid
, 20, bl2
.length(), bl2
);
980 cerr
<< "Append" << std::endl
;
981 r
= queue_transaction(store
, ch
, std::move(t
));
984 r
= store
->read(ch
, hoid
, 0, 30, newdata
);
988 expected
.append("edcba");
989 expected
.append_zero(5);
990 expected
.append("edcba");
991 expected
.append_zero(5);
992 expected
.append(bl2
);
994 ASSERT_TRUE(bl_eq(expected
, newdata
));
997 //additional write to an unused region of some blob and partial owerite over existing extents
999 ObjectStore::Transaction t
;
1000 bufferlist bl
, bl2
, bl3
, newdata
;
1002 bl2
.append("1234567890");
1005 t
.write(cid
, hoid
, 30, bl2
.length(), bl2
);
1006 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
1007 t
.write(cid
, hoid
, 13, bl3
.length(), bl3
);
1008 cerr
<< "TripleWrite" << std::endl
;
1009 r
= queue_transaction(store
, ch
, std::move(t
));
1012 r
= store
->read(ch
, hoid
, 0, 40, newdata
);
1015 bufferlist expected
;
1016 expected
.append("eDCBa");
1017 expected
.append_zero(5);
1018 expected
.append("edcBA");
1019 expected
.append_zero(5);
1020 expected
.append(bl2
);
1021 expected
.append(bl2
);
1023 ASSERT_TRUE(bl_eq(expected
, newdata
));
1028 void StoreTest::doCompressionTest()
1032 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1034 auto ch
= store
->open_collection(cid
);
1037 auto ch
= store
->create_new_collection(cid
);
1039 ObjectStore::Transaction t
;
1040 t
.create_collection(cid
, 0);
1041 cerr
<< "Creating collection " << cid
<< std::endl
;
1042 r
= queue_transaction(store
, ch
, std::move(t
));
1046 bool exists
= store
->exists(ch
, hoid
);
1047 ASSERT_TRUE(!exists
);
1049 ObjectStore::Transaction t
;
1051 cerr
<< "Creating object " << hoid
<< std::endl
;
1052 r
= queue_transaction(store
, ch
, std::move(t
));
1055 exists
= store
->exists(ch
, hoid
);
1056 ASSERT_EQ(true, exists
);
1059 data
.resize(0x10000 * 4);
1060 for(size_t i
= 0;i
< data
.size(); i
++)
1063 ObjectStore::Transaction t
;
1064 bufferlist bl
, newdata
;
1066 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1067 cerr
<< "CompressibleData (4xAU) Write" << std::endl
;
1068 r
= queue_transaction(store
, ch
, std::move(t
));
1071 r
= store
->read(ch
, hoid
, 0, data
.size() , newdata
);
1073 ASSERT_EQ(r
, (int)data
.size());
1075 bufferlist expected
;
1076 expected
.append(data
);
1077 ASSERT_TRUE(bl_eq(expected
, newdata
));
1080 r
= store
->read(ch
, hoid
, 0, 711 , newdata
);
1083 bufferlist expected
;
1084 expected
.append(data
.substr(0,711));
1085 ASSERT_TRUE(bl_eq(expected
, newdata
));
1088 r
= store
->read(ch
, hoid
, 0xf00f, data
.size(), newdata
);
1089 ASSERT_EQ(r
, int(data
.size() - 0xf00f) );
1091 bufferlist expected
;
1092 expected
.append(data
.substr(0xf00f));
1093 ASSERT_TRUE(bl_eq(expected
, newdata
));
1096 struct store_statfs_t statfs
;
1097 int r
= store
->statfs(&statfs
);
1099 ASSERT_EQ(statfs
.data_stored
, (unsigned)data
.size());
1100 ASSERT_LE(statfs
.data_compressed
, (unsigned)data
.size());
1101 ASSERT_EQ(statfs
.data_compressed_original
, (unsigned)data
.size());
1102 ASSERT_LE(statfs
.data_compressed_allocated
, (unsigned)data
.size());
1106 data2
.resize(0x10000 * 4 - 0x9000);
1107 for(size_t i
= 0;i
< data2
.size(); i
++)
1108 data2
[i
] = (i
+1) / 256;
1110 ObjectStore::Transaction t
;
1111 bufferlist bl
, newdata
;
1113 t
.write(cid
, hoid
, 0x8000, bl
.length(), bl
);
1114 cerr
<< "CompressibleData partial overwrite" << std::endl
;
1115 r
= queue_transaction(store
, ch
, std::move(t
));
1118 r
= store
->read(ch
, hoid
, 0, 0x10000, newdata
);
1119 ASSERT_EQ(r
, (int)0x10000);
1121 bufferlist expected
;
1122 expected
.append(data
.substr(0, 0x8000));
1123 expected
.append(data2
.substr(0, 0x8000));
1124 ASSERT_TRUE(bl_eq(expected
, newdata
));
1127 r
= store
->read(ch
, hoid
, 0x9000, 711 , newdata
);
1130 bufferlist expected
;
1131 expected
.append(data2
.substr(0x1000,711));
1132 ASSERT_TRUE(bl_eq(expected
, newdata
));
1135 r
= store
->read(ch
, hoid
, 0x0, 0x40000, newdata
);
1136 ASSERT_EQ(r
, int(0x40000) );
1138 bufferlist expected
;
1139 expected
.append(data
.substr(0, 0x8000));
1140 expected
.append(data2
.substr(0, 0x37000));
1141 expected
.append(data
.substr(0x3f000, 0x1000));
1142 ASSERT_TRUE(bl_eq(expected
, newdata
));
1145 data2
.resize(0x3f000);
1146 for(size_t i
= 0;i
< data2
.size(); i
++)
1147 data2
[i
] = (i
+2) / 256;
1149 ObjectStore::Transaction t
;
1150 bufferlist bl
, newdata
;
1152 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1153 cerr
<< "CompressibleData partial overwrite, two extents overlapped, single one to be removed" << std::endl
;
1154 r
= queue_transaction(store
, ch
, std::move(t
));
1157 r
= store
->read(ch
, hoid
, 0, 0x3e000 - 1, newdata
);
1158 ASSERT_EQ(r
, (int)0x3e000 - 1);
1160 bufferlist expected
;
1161 expected
.append(data2
.substr(0, 0x3e000 - 1));
1162 ASSERT_TRUE(bl_eq(expected
, newdata
));
1165 r
= store
->read(ch
, hoid
, 0x3e000-1, 0x2001, newdata
);
1166 ASSERT_EQ(r
, 0x2001);
1168 bufferlist expected
;
1169 expected
.append(data2
.substr(0x3e000-1, 0x1001));
1170 expected
.append(data
.substr(0x3f000, 0x1000));
1171 ASSERT_TRUE(bl_eq(expected
, newdata
));
1174 r
= store
->read(ch
, hoid
, 0x0, 0x40000, newdata
);
1175 ASSERT_EQ(r
, int(0x40000) );
1177 bufferlist expected
;
1178 expected
.append(data2
.substr(0, 0x3f000));
1179 expected
.append(data
.substr(0x3f000, 0x1000));
1180 ASSERT_TRUE(bl_eq(expected
, newdata
));
1183 data
.resize(0x1001);
1184 for(size_t i
= 0;i
< data
.size(); i
++)
1185 data
[i
] = (i
+3) / 256;
1187 ObjectStore::Transaction t
;
1188 bufferlist bl
, newdata
;
1190 t
.write(cid
, hoid
, 0x3f000-1, bl
.length(), bl
);
1191 cerr
<< "Small chunk partial overwrite, two extents overlapped, single one to be removed" << std::endl
;
1192 r
= queue_transaction(store
, ch
, std::move(t
));
1195 r
= store
->read(ch
, hoid
, 0x3e000, 0x2000, newdata
);
1196 ASSERT_EQ(r
, (int)0x2000);
1198 bufferlist expected
;
1199 expected
.append(data2
.substr(0x3e000, 0x1000 - 1));
1200 expected
.append(data
.substr(0, 0x1001));
1201 ASSERT_TRUE(bl_eq(expected
, newdata
));
1205 ObjectStore::Transaction t
;
1206 t
.remove(cid
, hoid
);
1207 cerr
<< "Cleaning object" << std::endl
;
1208 r
= queue_transaction(store
, ch
, std::move(t
));
1213 EXPECT_EQ(store
->umount(), 0);
1214 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1215 EXPECT_EQ(store
->mount(), 0);
1216 ch
= store
->open_collection(cid
);
1217 auto settingsBookmark
= BookmarkSettings();
1218 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
1219 g_ceph_context
->_conf
.apply_changes(nullptr);
1221 data
.resize(0x10000*6);
1223 for(size_t i
= 0;i
< data
.size(); i
++)
1225 ObjectStore::Transaction t
;
1226 bufferlist bl
, newdata
;
1228 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1229 cerr
<< "CompressibleData large blob" << std::endl
;
1230 r
= queue_transaction(store
, ch
, std::move(t
));
1235 EXPECT_EQ(store
->umount(), 0);
1236 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1237 EXPECT_EQ(store
->mount(), 0);
1238 ch
= store
->open_collection(cid
);
1240 ObjectStore::Transaction t
;
1241 t
.remove(cid
, hoid
);
1242 t
.remove_collection(cid
);
1243 cerr
<< "Cleaning" << std::endl
;
1244 r
= queue_transaction(store
, ch
, std::move(t
));
1249 TEST_P(StoreTest
, CompressionTest
) {
1250 if (string(GetParam()) != "bluestore")
1253 cout
<< "TODO: need to adjust statfs check for smr" << std::endl
;
1257 SetVal(g_conf(), "bluestore_compression_algorithm", "snappy");
1258 SetVal(g_conf(), "bluestore_compression_mode", "force");
1259 g_ceph_context
->_conf
.apply_changes(nullptr);
1260 doCompressionTest();
1262 SetVal(g_conf(), "bluestore_compression_algorithm", "zlib");
1263 SetVal(g_conf(), "bluestore_compression_mode", "aggressive");
1264 g_ceph_context
->_conf
.apply_changes(nullptr);
1265 doCompressionTest();
1268 TEST_P(StoreTest
, SimpleObjectTest
) {
1271 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1273 auto ch
= store
->open_collection(cid
);
1276 auto ch
= store
->create_new_collection(cid
);
1278 ObjectStore::Transaction t
;
1279 t
.create_collection(cid
, 0);
1280 cerr
<< "Creating collection " << cid
<< std::endl
;
1281 r
= queue_transaction(store
, ch
, std::move(t
));
1285 bool exists
= store
->exists(ch
, hoid
);
1286 ASSERT_TRUE(!exists
);
1288 ObjectStore::Transaction t
;
1290 cerr
<< "Creating object " << hoid
<< std::endl
;
1291 r
= queue_transaction(store
, ch
, std::move(t
));
1294 exists
= store
->exists(ch
, hoid
);
1295 ASSERT_EQ(true, exists
);
1298 ObjectStore::Transaction t
;
1299 t
.remove(cid
, hoid
);
1301 cerr
<< "Remove then create" << std::endl
;
1302 r
= queue_transaction(store
, ch
, std::move(t
));
1306 ObjectStore::Transaction t
;
1307 bufferlist bl
, orig
;
1310 t
.remove(cid
, hoid
);
1311 t
.write(cid
, hoid
, 0, 5, bl
);
1312 cerr
<< "Remove then create" << std::endl
;
1313 r
= queue_transaction(store
, ch
, std::move(t
));
1317 r
= store
->read(ch
, hoid
, 0, 5, in
);
1319 ASSERT_TRUE(bl_eq(orig
, in
));
1322 ObjectStore::Transaction t
;
1327 t
.write(cid
, hoid
, 5, 5, bl
);
1328 cerr
<< "Append" << std::endl
;
1329 r
= queue_transaction(store
, ch
, std::move(t
));
1333 r
= store
->read(ch
, hoid
, 0, 10, in
);
1335 ASSERT_TRUE(bl_eq(exp
, in
));
1338 ObjectStore::Transaction t
;
1340 bl
.append("abcdeabcde");
1342 t
.write(cid
, hoid
, 0, 10, bl
);
1343 cerr
<< "Full overwrite" << std::endl
;
1344 r
= queue_transaction(store
, ch
, std::move(t
));
1348 r
= store
->read(ch
, hoid
, 0, 10, in
);
1350 ASSERT_TRUE(bl_eq(exp
, in
));
1353 ObjectStore::Transaction t
;
1356 t
.write(cid
, hoid
, 3, 5, bl
);
1357 cerr
<< "Partial overwrite" << std::endl
;
1358 r
= queue_transaction(store
, ch
, std::move(t
));
1362 exp
.append("abcabcdede");
1363 r
= store
->read(ch
, hoid
, 0, 10, in
);
1366 ASSERT_TRUE(bl_eq(exp
, in
));
1370 ObjectStore::Transaction t
;
1373 t
.truncate(cid
, hoid
, 0);
1374 t
.write(cid
, hoid
, 5, 5, bl
);
1375 cerr
<< "Truncate + hole" << std::endl
;
1376 r
= queue_transaction(store
, ch
, std::move(t
));
1380 ObjectStore::Transaction t
;
1383 t
.write(cid
, hoid
, 0, 5, bl
);
1384 cerr
<< "Reverse fill-in" << std::endl
;
1385 r
= queue_transaction(store
, ch
, std::move(t
));
1390 exp
.append("abcdefghij");
1391 r
= store
->read(ch
, hoid
, 0, 10, in
);
1394 ASSERT_TRUE(bl_eq(exp
, in
));
1397 ObjectStore::Transaction t
;
1399 bl
.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1400 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1401 cerr
<< "larger overwrite" << std::endl
;
1402 r
= queue_transaction(store
, ch
, std::move(t
));
1406 r
= store
->read(ch
, hoid
, 0, bl
.length(), in
);
1407 ASSERT_EQ((int)bl
.length(), r
);
1409 ASSERT_TRUE(bl_eq(bl
, in
));
1413 bl
.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1415 //test: offset=len=0 mean read all data
1417 r
= store
->read(ch
, hoid
, 0, 0, in
);
1418 ASSERT_EQ((int)bl
.length(), r
);
1420 ASSERT_TRUE(bl_eq(bl
, in
));
1423 //verifying unaligned csums
1424 std::string
s1("1"), s2(0x1000, '2'), s3("00");
1426 ObjectStore::Transaction t
;
1430 t
.truncate(cid
, hoid
, 0);
1431 t
.write(cid
, hoid
, 0x1000-1, bl
.length(), bl
);
1432 cerr
<< "Write unaligned csum, stage 1" << std::endl
;
1433 r
= queue_transaction(store
, ch
, std::move(t
));
1437 bufferlist in
, exp1
, exp2
, exp3
;
1441 r
= store
->read(ch
, hoid
, 0x1000-1, 1, in
);
1443 ASSERT_TRUE(bl_eq(exp1
, in
));
1445 r
= store
->read(ch
, hoid
, 0x1000, 0x1000, in
);
1446 ASSERT_EQ(0x1000, r
);
1447 ASSERT_TRUE(bl_eq(exp2
, in
));
1450 ObjectStore::Transaction t
;
1453 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
1454 cerr
<< "Write unaligned csum, stage 2" << std::endl
;
1455 r
= queue_transaction(store
, ch
, std::move(t
));
1459 r
= store
->read(ch
, hoid
, 1, 2, in
);
1461 ASSERT_TRUE(bl_eq(exp3
, in
));
1463 r
= store
->read(ch
, hoid
, 0x1000-1, 1, in
);
1465 ASSERT_TRUE(bl_eq(exp1
, in
));
1467 r
= store
->read(ch
, hoid
, 0x1000, 0x1000, in
);
1468 ASSERT_EQ(0x1000, r
);
1469 ASSERT_TRUE(bl_eq(exp2
, in
));
1474 ObjectStore::Transaction t
;
1475 t
.remove(cid
, hoid
);
1476 t
.remove_collection(cid
);
1477 cerr
<< "Cleaning" << std::endl
;
1478 r
= queue_transaction(store
, ch
, std::move(t
));
1483 #if defined(WITH_BLUESTORE)
1485 TEST_P(StoreTestSpecificAUSize
, ReproBug41901Test
) {
1486 if(string(GetParam()) != "bluestore")
1489 cout
<< "SKIP (smr)" << std::endl
;
1493 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
1494 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
1495 g_conf().apply_changes(nullptr);
1496 StartDeferred(65536);
1500 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
1501 const PerfCounters
* logger
= store
->get_perf_counters();
1502 auto ch
= store
->create_new_collection(cid
);
1504 ObjectStore::Transaction t
;
1505 t
.create_collection(cid
, 0);
1506 cerr
<< "Creating collection " << cid
<< std::endl
;
1507 r
= queue_transaction(store
, ch
, std::move(t
));
1511 bool exists
= store
->exists(ch
, hoid
);
1512 ASSERT_TRUE(!exists
);
1514 ObjectStore::Transaction t
;
1516 cerr
<< "Creating object " << hoid
<< std::endl
;
1517 r
= queue_transaction(store
, ch
, std::move(t
));
1520 exists
= store
->exists(ch
, hoid
);
1521 ASSERT_EQ(true, exists
);
1524 ObjectStore::Transaction t
;
1525 bufferlist bl
, orig
;
1526 string
s(4096, 'a');
1528 t
.write(cid
, hoid
, 0x11000, bl
.length(), bl
);
1529 cerr
<< "write1" << std::endl
;
1530 r
= queue_transaction(store
, ch
, std::move(t
));
1534 ObjectStore::Transaction t
;
1535 bufferlist bl
, orig
;
1536 string
s(4096 * 3, 'a');
1538 t
.write(cid
, hoid
, 0x15000, bl
.length(), bl
);
1539 cerr
<< "write2" << std::endl
;
1540 r
= queue_transaction(store
, ch
, std::move(t
));
1543 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 2u);
1544 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 1u);
1547 ObjectStore::Transaction t
;
1548 bufferlist bl
, orig
;
1549 string
s(4096 * 2, 'a');
1551 t
.write(cid
, hoid
, 0xe000, bl
.length(), bl
);
1552 cerr
<< "write3" << std::endl
;
1553 r
= queue_transaction(store
, ch
, std::move(t
));
1556 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 3u);
1557 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 2u);
1561 ObjectStore::Transaction t
;
1562 bufferlist bl
, orig
;
1563 string
s(4096, 'a');
1565 t
.write(cid
, hoid
, 0xf000, bl
.length(), bl
);
1566 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1567 cerr
<< "write3" << std::endl
;
1568 r
= queue_transaction(store
, ch
, std::move(t
));
1571 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 5u);
1572 ASSERT_EQ(logger
->get(l_bluestore_write_small_unused
), 2u);
1574 ObjectStore::Transaction t
;
1575 t
.remove(cid
, hoid
);
1576 t
.remove_collection(cid
);
1577 cerr
<< "Cleaning" << std::endl
;
1578 r
= queue_transaction(store
, ch
, std::move(t
));
1584 TEST_P(StoreTestSpecificAUSize
, BluestoreStatFSTest
) {
1585 if(string(GetParam()) != "bluestore")
1588 cout
<< "TODO: fix this for smr" << std::endl
;
1591 SetVal(g_conf(), "bluestore_block_db_path", "");
1592 StartDeferred(65536);
1593 SetVal(g_conf(), "bluestore_compression_mode", "force");
1594 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
1595 // just a big number to disble gc
1596 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "100000");
1597 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
1598 g_conf().apply_changes(nullptr);
1602 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
1603 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
1608 ghobject_t hoid2
= hoid
;
1609 hoid2
.hobj
.snap
= 1;
1611 auto ch
= store
->open_collection(cid
);
1614 auto ch
= store
->create_new_collection(cid
);
1616 ObjectStore::Transaction t
;
1617 t
.create_collection(cid
, 0);
1618 cerr
<< "Creating collection " << cid
<< std::endl
;
1619 r
= queue_transaction(store
, ch
, std::move(t
));
1623 bool exists
= store
->exists(ch
, hoid
);
1624 ASSERT_TRUE(!exists
);
1626 ObjectStore::Transaction t
;
1628 cerr
<< "Creating object " << hoid
<< std::endl
;
1629 r
= queue_transaction(store
, ch
, std::move(t
));
1632 exists
= store
->exists(ch
, hoid
);
1633 ASSERT_EQ(true, exists
);
1636 struct store_statfs_t statfs
;
1637 int r
= store
->statfs(&statfs
);
1639 ASSERT_EQ( 0u, statfs
.allocated
);
1640 ASSERT_EQ( 0u, statfs
.data_stored
);
1641 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
1642 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
1644 struct store_statfs_t statfs_pool
;
1646 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1648 ASSERT_EQ( 0u, statfs_pool
.allocated
);
1649 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
1653 EXPECT_EQ(store
->umount(), 0);
1654 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1655 EXPECT_EQ(store
->mount(), 0);
1656 ch
= store
->open_collection(cid
);
1659 ObjectStore::Transaction t
;
1662 t
.write(cid
, hoid
, 0, 5, bl
);
1663 cerr
<< "Append 5 bytes" << std::endl
;
1664 r
= queue_transaction(store
, ch
, std::move(t
));
1667 struct store_statfs_t statfs
;
1668 int r
= store
->statfs(&statfs
);
1670 ASSERT_EQ(5, statfs
.data_stored
);
1671 ASSERT_EQ(0x10000, statfs
.allocated
);
1672 ASSERT_EQ(0, statfs
.data_compressed
);
1673 ASSERT_EQ(0, statfs
.data_compressed_original
);
1674 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1676 struct store_statfs_t statfs_pool
;
1678 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1680 ASSERT_EQ(5, statfs_pool
.data_stored
);
1681 ASSERT_EQ(0x10000, statfs_pool
.allocated
);
1682 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1683 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1684 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1686 // accessing unknown pool
1687 r
= store
->pool_statfs(poolid
+ 1, &statfs_pool
, &per_pool_omap
);
1689 ASSERT_EQ(0, statfs_pool
.data_stored
);
1690 ASSERT_EQ(0, statfs_pool
.allocated
);
1691 ASSERT_EQ(0, statfs_pool
.data_compressed
);
1692 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1693 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1697 EXPECT_EQ(store
->umount(), 0);
1698 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1699 EXPECT_EQ(store
->mount(), 0);
1700 ch
= store
->open_collection(cid
);
1703 ObjectStore::Transaction t
;
1704 std::string
s(0x30000, 'a');
1707 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1708 cerr
<< "Append 0x30000 compressible bytes" << std::endl
;
1709 r
= queue_transaction(store
, ch
, std::move(t
));
1712 struct store_statfs_t statfs
;
1713 int r
= store
->statfs(&statfs
);
1715 ASSERT_EQ(0x30005, statfs
.data_stored
);
1716 ASSERT_EQ(0x30000, statfs
.allocated
);
1717 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1718 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1719 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1721 struct store_statfs_t statfs_pool
;
1723 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1725 ASSERT_EQ(0x30005, statfs_pool
.data_stored
);
1726 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1727 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1728 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1729 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1732 EXPECT_EQ(store
->umount(), 0);
1733 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1734 EXPECT_EQ(store
->mount(), 0);
1735 ch
= store
->open_collection(cid
);
1738 ObjectStore::Transaction t
;
1739 t
.zero(cid
, hoid
, 1, 3);
1740 t
.zero(cid
, hoid
, 0x20000, 9);
1741 cerr
<< "Punch hole at 1~3, 0x20000~9" << std::endl
;
1742 r
= queue_transaction(store
, ch
, std::move(t
));
1745 struct store_statfs_t statfs
;
1746 int r
= store
->statfs(&statfs
);
1748 ASSERT_EQ(0x30005 - 3 - 9, statfs
.data_stored
);
1749 ASSERT_EQ(0x30000, statfs
.allocated
);
1750 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1751 ASSERT_EQ(0x20000 - 9, statfs
.data_compressed_original
);
1752 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1754 struct store_statfs_t statfs_pool
;
1756 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1758 ASSERT_EQ(0x30005 - 3 - 9, statfs_pool
.data_stored
);
1759 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1760 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1761 ASSERT_EQ(0x20000 - 9, statfs_pool
.data_compressed_original
);
1762 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1765 EXPECT_EQ(store
->umount(), 0);
1766 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1767 EXPECT_EQ(store
->mount(), 0);
1768 ch
= store
->open_collection(cid
);
1771 ObjectStore::Transaction t
;
1772 std::string
s(0x1000, 'b');
1775 t
.write(cid
, hoid
, 1, bl
.length(), bl
);
1776 t
.write(cid
, hoid
, 0x10001, bl
.length(), bl
);
1777 cerr
<< "Overwrite first and second(compressible) extents" << std::endl
;
1778 r
= queue_transaction(store
, ch
, std::move(t
));
1781 struct store_statfs_t statfs
;
1782 int r
= store
->statfs(&statfs
);
1784 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs
.data_stored
);
1785 ASSERT_EQ(0x40000, statfs
.allocated
);
1786 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1787 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs
.data_compressed_original
);
1788 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
1790 struct store_statfs_t statfs_pool
;
1792 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1794 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs_pool
.data_stored
);
1795 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1796 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1797 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs_pool
.data_compressed_original
);
1798 ASSERT_EQ(statfs_pool
.data_compressed_allocated
, 0x10000);
1801 EXPECT_EQ(store
->umount(), 0);
1802 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1803 EXPECT_EQ(store
->mount(), 0);
1804 ch
= store
->open_collection(cid
);
1807 ObjectStore::Transaction t
;
1808 std::string
s(0x10000, 'c');
1811 t
.write(cid
, hoid
, 0x10000, bl
.length(), bl
);
1812 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
1813 t
.write(cid
, hoid
, 0x30000, bl
.length(), bl
);
1814 cerr
<< "Overwrite compressed extent with 3 uncompressible ones" << std::endl
;
1815 r
= queue_transaction(store
, ch
, std::move(t
));
1818 struct store_statfs_t statfs
;
1819 int r
= store
->statfs(&statfs
);
1821 ASSERT_EQ(0x30000 + 0x1001, statfs
.data_stored
);
1822 ASSERT_EQ(0x40000, statfs
.allocated
);
1823 ASSERT_LE(statfs
.data_compressed
, 0);
1824 ASSERT_EQ(0, statfs
.data_compressed_original
);
1825 ASSERT_EQ(0, statfs
.data_compressed_allocated
);
1827 struct store_statfs_t statfs_pool
;
1829 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1831 ASSERT_EQ(0x30000 + 0x1001, statfs_pool
.data_stored
);
1832 ASSERT_EQ(0x40000, statfs_pool
.allocated
);
1833 ASSERT_LE(statfs_pool
.data_compressed
, 0);
1834 ASSERT_EQ(0, statfs_pool
.data_compressed_original
);
1835 ASSERT_EQ(0, statfs_pool
.data_compressed_allocated
);
1838 EXPECT_EQ(store
->umount(), 0);
1839 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1840 EXPECT_EQ(store
->mount(), 0);
1841 ch
= store
->open_collection(cid
);
1844 ObjectStore::Transaction t
;
1845 t
.zero(cid
, hoid
, 0, 0x40000);
1846 cerr
<< "Zero object" << std::endl
;
1847 r
= queue_transaction(store
, ch
, std::move(t
));
1849 struct store_statfs_t statfs
;
1850 int r
= store
->statfs(&statfs
);
1852 ASSERT_EQ(0u, statfs
.allocated
);
1853 ASSERT_EQ(0u, statfs
.data_stored
);
1854 ASSERT_EQ(0u, statfs
.data_compressed_original
);
1855 ASSERT_EQ(0u, statfs
.data_compressed
);
1856 ASSERT_EQ(0u, statfs
.data_compressed_allocated
);
1858 struct store_statfs_t statfs_pool
;
1860 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1862 ASSERT_EQ(0u, statfs_pool
.allocated
);
1863 ASSERT_EQ(0u, statfs_pool
.data_stored
);
1864 ASSERT_EQ(0u, statfs_pool
.data_compressed_original
);
1865 ASSERT_EQ(0u, statfs_pool
.data_compressed
);
1866 ASSERT_EQ(0u, statfs_pool
.data_compressed_allocated
);
1869 EXPECT_EQ(store
->umount(), 0);
1870 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1871 EXPECT_EQ(store
->mount(), 0);
1872 ch
= store
->open_collection(cid
);
1875 ObjectStore::Transaction t
;
1876 std::string
s(0x10000, 'c');
1881 bl
.append(s
.substr(0, 0x10000-2));
1882 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
1883 cerr
<< "Yet another compressible write" << std::endl
;
1884 r
= queue_transaction(store
, ch
, std::move(t
));
1886 struct store_statfs_t statfs
;
1887 r
= store
->statfs(&statfs
);
1889 ASSERT_EQ(0x40000 - 2, statfs
.data_stored
);
1890 ASSERT_EQ(0x30000, statfs
.allocated
);
1891 ASSERT_LE(statfs
.data_compressed
, 0x10000);
1892 ASSERT_EQ(0x20000, statfs
.data_compressed_original
);
1893 ASSERT_EQ(0x10000, statfs
.data_compressed_allocated
);
1895 struct store_statfs_t statfs_pool
;
1897 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1899 ASSERT_EQ(0x40000 - 2, statfs_pool
.data_stored
);
1900 ASSERT_EQ(0x30000, statfs_pool
.allocated
);
1901 ASSERT_LE(statfs_pool
.data_compressed
, 0x10000);
1902 ASSERT_EQ(0x20000, statfs_pool
.data_compressed_original
);
1903 ASSERT_EQ(0x10000, statfs_pool
.data_compressed_allocated
);
1906 EXPECT_EQ(store
->umount(), 0);
1907 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
1908 EXPECT_EQ(store
->mount(), 0);
1909 ch
= store
->open_collection(cid
);
1912 struct store_statfs_t statfs
;
1913 r
= store
->statfs(&statfs
);
1916 struct store_statfs_t statfs_pool
;
1918 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
1921 ObjectStore::Transaction t
;
1922 t
.clone(cid
, hoid
, hoid2
);
1923 cerr
<< "Clone compressed objecte" << std::endl
;
1924 r
= queue_transaction(store
, ch
, std::move(t
));
1926 struct store_statfs_t statfs2
;
1927 r
= store
->statfs(&statfs2
);
1929 ASSERT_GT(statfs2
.data_stored
, statfs
.data_stored
);
1930 ASSERT_EQ(statfs2
.allocated
, statfs
.allocated
);
1931 ASSERT_GT(statfs2
.data_compressed
, statfs
.data_compressed
);
1932 ASSERT_GT(statfs2
.data_compressed_original
, statfs
.data_compressed_original
);
1933 ASSERT_EQ(statfs2
.data_compressed_allocated
, statfs
.data_compressed_allocated
);
1935 struct store_statfs_t statfs2_pool
;
1936 r
= store
->pool_statfs(poolid
, &statfs2_pool
, &per_pool_omap
);
1938 ASSERT_GT(statfs2_pool
.data_stored
, statfs_pool
.data_stored
);
1939 ASSERT_EQ(statfs2_pool
.allocated
, statfs_pool
.allocated
);
1940 ASSERT_GT(statfs2_pool
.data_compressed
, statfs_pool
.data_compressed
);
1941 ASSERT_GT(statfs2_pool
.data_compressed_original
,
1942 statfs_pool
.data_compressed_original
);
1943 ASSERT_EQ(statfs2_pool
.data_compressed_allocated
,
1944 statfs_pool
.data_compressed_allocated
);
1949 auto poolid2
= poolid
+ 1;
1950 coll_t cid2
= coll_t(spg_t(pg_t(20, poolid2
), shard_id_t::NO_SHARD
));
1951 ghobject_t
hoid(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
1956 auto ch
= store
->create_new_collection(cid2
);
1960 struct store_statfs_t statfs1_pool
;
1962 int r
= store
->pool_statfs(poolid
, &statfs1_pool
, &per_pool_omap
);
1965 cerr
<< "Creating second collection " << cid2
<< std::endl
;
1966 ObjectStore::Transaction t
;
1967 t
.create_collection(cid2
, 0);
1968 r
= queue_transaction(store
, ch
, std::move(t
));
1971 t
= ObjectStore::Transaction();
1974 t
.write(cid2
, hoid
, 0, 5, bl
);
1975 r
= queue_transaction(store
, ch
, std::move(t
));
1978 struct store_statfs_t statfs2_pool
;
1979 r
= store
->pool_statfs(poolid2
, &statfs2_pool
, &per_pool_omap
);
1981 ASSERT_EQ(5, statfs2_pool
.data_stored
);
1982 ASSERT_EQ(0x10000, statfs2_pool
.allocated
);
1983 ASSERT_EQ(0, statfs2_pool
.data_compressed
);
1984 ASSERT_EQ(0, statfs2_pool
.data_compressed_original
);
1985 ASSERT_EQ(0, statfs2_pool
.data_compressed_allocated
);
1987 struct store_statfs_t statfs1_pool_again
;
1988 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
, &per_pool_omap
);
1990 // adjust 'available' since it has changed
1991 statfs1_pool_again
.available
= statfs1_pool
.available
;
1992 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
1994 t
= ObjectStore::Transaction();
1995 t
.remove(cid2
, hoid
);
1996 t
.remove_collection(cid2
);
1997 cerr
<< "Cleaning" << std::endl
;
1998 r
= queue_transaction(store
, ch
, std::move(t
));
2004 // verify ops on temporary object
2006 auto poolid3
= poolid
+ 2;
2007 coll_t cid3
= coll_t(spg_t(pg_t(20, poolid3
), shard_id_t::NO_SHARD
));
2008 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
),
2013 ghobject_t hoid3_temp
;
2014 hoid3_temp
.hobj
= hoid3
.hobj
.make_temp_hobject("Object 3 temp");
2015 auto ch3
= store
->create_new_collection(cid3
);
2017 struct store_statfs_t statfs1_pool
;
2019 int r
= store
->pool_statfs(poolid
, &statfs1_pool
, &per_pool_omap
);
2022 cerr
<< "Creating third collection " << cid3
<< std::endl
;
2023 ObjectStore::Transaction t
;
2024 t
.create_collection(cid3
, 0);
2025 r
= queue_transaction(store
, ch3
, std::move(t
));
2028 t
= ObjectStore::Transaction();
2031 t
.write(cid3
, hoid3_temp
, 0, 5, bl
);
2032 r
= queue_transaction(store
, ch3
, std::move(t
));
2035 struct store_statfs_t statfs3_pool
;
2036 r
= store
->pool_statfs(poolid3
, &statfs3_pool
, &per_pool_omap
);
2038 ASSERT_EQ(5, statfs3_pool
.data_stored
);
2039 ASSERT_EQ(0x10000, statfs3_pool
.allocated
);
2040 ASSERT_EQ(0, statfs3_pool
.data_compressed
);
2041 ASSERT_EQ(0, statfs3_pool
.data_compressed_original
);
2042 ASSERT_EQ(0, statfs3_pool
.data_compressed_allocated
);
2044 struct store_statfs_t statfs1_pool_again
;
2045 r
= store
->pool_statfs(poolid
, &statfs1_pool_again
, &per_pool_omap
);
2047 // adjust 'available' since it has changed
2048 statfs1_pool_again
.available
= statfs1_pool
.available
;
2049 ASSERT_EQ(statfs1_pool_again
, statfs1_pool
);
2054 EXPECT_EQ(store
->umount(), 0);
2055 EXPECT_EQ(store
->mount(), 0);
2056 ch
= store
->open_collection(cid
);
2057 ch3
= store
->open_collection(cid3
);
2059 t
= ObjectStore::Transaction();
2060 t
.collection_move_rename(
2063 r
= queue_transaction(store
, ch3
, std::move(t
));
2066 struct store_statfs_t statfs3_pool_again
;
2067 r
= store
->pool_statfs(poolid3
, &statfs3_pool_again
, &per_pool_omap
);
2069 ASSERT_EQ(statfs3_pool_again
, statfs3_pool
);
2074 EXPECT_EQ(store
->umount(), 0);
2075 EXPECT_EQ(store
->mount(), 0);
2076 ch
= store
->open_collection(cid
);
2077 ch3
= store
->open_collection(cid3
);
2079 t
= ObjectStore::Transaction();
2080 t
.remove(cid3
, hoid3
);
2081 t
.remove_collection(cid3
);
2082 cerr
<< "Cleaning" << std::endl
;
2083 r
= queue_transaction(store
, ch3
, std::move(t
));
2089 ObjectStore::Transaction t
;
2090 t
.remove(cid
, hoid
);
2091 t
.remove(cid
, hoid2
);
2092 t
.remove_collection(cid
);
2093 cerr
<< "Cleaning" << std::endl
;
2094 r
= queue_transaction(store
, ch
, std::move(t
));
2097 struct store_statfs_t statfs
;
2098 r
= store
->statfs(&statfs
);
2100 ASSERT_EQ( 0u, statfs
.allocated
);
2101 ASSERT_EQ( 0u, statfs
.data_stored
);
2102 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
2103 ASSERT_EQ( 0u, statfs
.data_compressed
);
2104 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
2106 struct store_statfs_t statfs_pool
;
2108 r
= store
->pool_statfs(poolid
, &statfs_pool
, &per_pool_omap
);
2110 ASSERT_EQ( 0u, statfs_pool
.allocated
);
2111 ASSERT_EQ( 0u, statfs_pool
.data_stored
);
2112 ASSERT_EQ( 0u, statfs_pool
.data_compressed_original
);
2113 ASSERT_EQ( 0u, statfs_pool
.data_compressed
);
2114 ASSERT_EQ( 0u, statfs_pool
.data_compressed_allocated
);
2118 TEST_P(StoreTestSpecificAUSize
, BluestoreFragmentedBlobTest
) {
2119 if(string(GetParam()) != "bluestore")
2122 cout
<< "TODO: fix this for smr" << std::endl
;
2125 SetVal(g_conf(), "bluestore_block_db_path", "");
2126 StartDeferred(0x10000);
2130 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2131 auto ch
= store
->create_new_collection(cid
);
2133 ObjectStore::Transaction t
;
2134 t
.create_collection(cid
, 0);
2135 cerr
<< "Creating collection " << cid
<< std::endl
;
2136 r
= queue_transaction(store
, ch
, std::move(t
));
2140 bool exists
= store
->exists(ch
, hoid
);
2141 ASSERT_TRUE(!exists
);
2143 ObjectStore::Transaction t
;
2145 cerr
<< "Creating object " << hoid
<< std::endl
;
2146 r
= queue_transaction(store
, ch
, std::move(t
));
2149 exists
= store
->exists(ch
, hoid
);
2150 ASSERT_EQ(true, exists
);
2153 struct store_statfs_t statfs
;
2154 int r
= store
->statfs(&statfs
);
2156 ASSERT_EQ(g_conf()->bluestore_block_size
, statfs
.total
);
2157 ASSERT_EQ(0u, statfs
.allocated
);
2158 ASSERT_EQ(0u, statfs
.data_stored
);
2159 ASSERT_TRUE(statfs
.available
> 0u && statfs
.available
< g_conf()->bluestore_block_size
);
2162 data
.resize(0x10000 * 3);
2164 ObjectStore::Transaction t
;
2165 for(size_t i
= 0;i
< data
.size(); i
++)
2166 data
[i
] = i
/ 256 + 1;
2167 bufferlist bl
, newdata
;
2169 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
2170 t
.zero(cid
, hoid
, 0x10000, 0x10000);
2171 cerr
<< "Append 3*0x10000 bytes and punch a hole 0x10000~10000" << std::endl
;
2172 r
= queue_transaction(store
, ch
, std::move(t
));
2175 struct store_statfs_t statfs
;
2176 int r
= store
->statfs(&statfs
);
2178 ASSERT_EQ(0x20000, statfs
.data_stored
);
2179 ASSERT_EQ(0x20000, statfs
.allocated
);
2181 r
= store
->read(ch
, hoid
, 0, data
.size(), newdata
);
2182 ASSERT_EQ(r
, (int)data
.size());
2184 bufferlist expected
;
2185 expected
.append(data
.substr(0, 0x10000));
2186 expected
.append(string(0x10000, 0));
2187 expected
.append(data
.substr(0x20000, 0x10000));
2188 ASSERT_TRUE(bl_eq(expected
, newdata
));
2192 r
= store
->read(ch
, hoid
, 1, data
.size()-2, newdata
);
2193 ASSERT_EQ(r
, (int)data
.size()-2);
2195 bufferlist expected
;
2196 expected
.append(data
.substr(1, 0x10000-1));
2197 expected
.append(string(0x10000, 0));
2198 expected
.append(data
.substr(0x20000, 0x10000 - 1));
2199 ASSERT_TRUE(bl_eq(expected
, newdata
));
2205 EXPECT_EQ(store
->umount(), 0);
2206 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2207 EXPECT_EQ(store
->mount(), 0);
2208 ch
= store
->open_collection(cid
);
2211 ObjectStore::Transaction t
;
2212 std::string
data2(3, 'b');
2213 bufferlist bl
, newdata
;
2215 t
.write(cid
, hoid
, 0x20000, bl
.length(), bl
);
2216 cerr
<< "Write 3 bytes after the hole" << std::endl
;
2217 r
= queue_transaction(store
, ch
, std::move(t
));
2220 struct store_statfs_t statfs
;
2221 int r
= store
->statfs(&statfs
);
2223 ASSERT_EQ(0x20000, statfs
.allocated
);
2224 ASSERT_EQ(0x20000, statfs
.data_stored
);
2226 r
= store
->read(ch
, hoid
, 0x20000-1, 21, newdata
);
2227 ASSERT_EQ(r
, (int)21);
2229 bufferlist expected
;
2230 expected
.append(string(0x1, 0));
2231 expected
.append(string(data2
));
2232 expected
.append(data
.substr(0x20003, 21-4));
2233 ASSERT_TRUE(bl_eq(expected
, newdata
));
2239 EXPECT_EQ(store
->umount(), 0);
2240 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2241 EXPECT_EQ(store
->mount(), 0);
2242 ch
= store
->open_collection(cid
);
2245 ObjectStore::Transaction t
;
2246 std::string
data2(3, 'a');
2247 bufferlist bl
, newdata
;
2249 t
.write(cid
, hoid
, 0x10000+1, bl
.length(), bl
);
2250 cerr
<< "Write 3 bytes to the hole" << std::endl
;
2251 r
= queue_transaction(store
, ch
, std::move(t
));
2254 struct store_statfs_t statfs
;
2255 int r
= store
->statfs(&statfs
);
2257 ASSERT_EQ(0x30000, statfs
.allocated
);
2258 ASSERT_EQ(0x20003, statfs
.data_stored
);
2260 r
= store
->read(ch
, hoid
, 0x10000-1, 0x10000+22, newdata
);
2261 ASSERT_EQ(r
, (int)0x10000+22);
2263 bufferlist expected
;
2264 expected
.append(data
.substr(0x10000-1, 1));
2265 expected
.append(string(0x1, 0));
2266 expected
.append(data2
);
2267 expected
.append(string(0x10000-4, 0));
2268 expected
.append(string(0x3, 'b'));
2269 expected
.append(data
.substr(0x20004, 21-3));
2270 ASSERT_TRUE(bl_eq(expected
, newdata
));
2275 ObjectStore::Transaction t
;
2276 bufferlist bl
, newdata
;
2277 bl
.append(string(0x30000, 'c'));
2278 t
.write(cid
, hoid
, 0, 0x30000, bl
);
2279 t
.zero(cid
, hoid
, 0, 0x10000);
2280 t
.zero(cid
, hoid
, 0x20000, 0x10000);
2281 cerr
<< "Rewrite an object and create two holes at the beginning and the end" << std::endl
;
2282 r
= queue_transaction(store
, ch
, std::move(t
));
2285 struct store_statfs_t statfs
;
2286 int r
= store
->statfs(&statfs
);
2288 ASSERT_EQ(0x10000, statfs
.allocated
);
2289 ASSERT_EQ(0x10000, statfs
.data_stored
);
2291 r
= store
->read(ch
, hoid
, 0, 0x30000, newdata
);
2292 ASSERT_EQ(r
, (int)0x30000);
2294 bufferlist expected
;
2295 expected
.append(string(0x10000, 0));
2296 expected
.append(string(0x10000, 'c'));
2297 expected
.append(string(0x10000, 0));
2298 ASSERT_TRUE(bl_eq(expected
, newdata
));
2305 EXPECT_EQ(store
->umount(), 0);
2306 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
2307 EXPECT_EQ(store
->mount(), 0);
2308 ch
= store
->open_collection(cid
);
2311 ObjectStore::Transaction t
;
2312 t
.remove(cid
, hoid
);
2313 t
.remove_collection(cid
);
2314 cerr
<< "Cleaning" << std::endl
;
2315 r
= queue_transaction(store
, ch
, std::move(t
));
2318 struct store_statfs_t statfs
;
2319 r
= store
->statfs(&statfs
);
2321 ASSERT_EQ( 0u, statfs
.allocated
);
2322 ASSERT_EQ( 0u, statfs
.data_stored
);
2323 ASSERT_EQ( 0u, statfs
.data_compressed_original
);
2324 ASSERT_EQ( 0u, statfs
.data_compressed
);
2325 ASSERT_EQ( 0u, statfs
.data_compressed_allocated
);
2330 TEST_P(StoreTest
, ManySmallWrite
) {
2333 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2334 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2335 auto ch
= store
->create_new_collection(cid
);
2337 ObjectStore::Transaction t
;
2338 t
.create_collection(cid
, 0);
2339 cerr
<< "Creating collection " << cid
<< std::endl
;
2340 r
= queue_transaction(store
, ch
, std::move(t
));
2347 for (int i
=0; i
<100; ++i
) {
2348 ObjectStore::Transaction t
;
2349 t
.write(cid
, a
, i
*4096, 4096, bl
, 0);
2350 r
= queue_transaction(store
, ch
, std::move(t
));
2353 for (int i
=0; i
<100; ++i
) {
2354 ObjectStore::Transaction t
;
2355 t
.write(cid
, b
, (rand() % 1024)*4096, 4096, bl
, 0);
2356 r
= queue_transaction(store
, ch
, std::move(t
));
2360 ObjectStore::Transaction t
;
2363 t
.remove_collection(cid
);
2364 cerr
<< "Cleaning" << std::endl
;
2365 r
= queue_transaction(store
, ch
, std::move(t
));
2370 TEST_P(StoreTest
, MultiSmallWriteSameBlock
) {
2373 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2374 auto ch
= store
->create_new_collection(cid
);
2376 ObjectStore::Transaction t
;
2377 t
.create_collection(cid
, 0);
2378 cerr
<< "Creating collection " << cid
<< std::endl
;
2379 r
= queue_transaction(store
, ch
, std::move(t
));
2385 // touch same block in both same transaction, tls, and pipelined txns
2387 ObjectStore::Transaction t
, u
;
2388 t
.write(cid
, a
, 0, 5, bl
, 0);
2389 t
.write(cid
, a
, 5, 5, bl
, 0);
2390 t
.write(cid
, a
, 4094, 5, bl
, 0);
2391 t
.write(cid
, a
, 9000, 5, bl
, 0);
2392 u
.write(cid
, a
, 10, 5, bl
, 0);
2393 u
.write(cid
, a
, 7000, 5, bl
, 0);
2394 t
.register_on_commit(&c
);
2395 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2396 store
->queue_transactions(ch
, v
);
2399 ObjectStore::Transaction t
, u
;
2400 t
.write(cid
, a
, 40, 5, bl
, 0);
2401 t
.write(cid
, a
, 45, 5, bl
, 0);
2402 t
.write(cid
, a
, 4094, 5, bl
, 0);
2403 t
.write(cid
, a
, 6000, 5, bl
, 0);
2404 u
.write(cid
, a
, 610, 5, bl
, 0);
2405 u
.write(cid
, a
, 11000, 5, bl
, 0);
2406 t
.register_on_commit(&d
);
2407 vector
<ObjectStore::Transaction
> v
= {t
, u
};
2408 store
->queue_transactions(ch
, v
);
2414 r
= store
->read(ch
, a
, 0, 16000, bl2
);
2418 ObjectStore::Transaction t
;
2420 t
.remove_collection(cid
);
2421 cerr
<< "Cleaning" << std::endl
;
2422 r
= queue_transaction(store
, ch
, std::move(t
));
2427 TEST_P(StoreTest
, SmallSkipFront
) {
2430 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2431 auto ch
= store
->create_new_collection(cid
);
2433 ObjectStore::Transaction t
;
2434 t
.create_collection(cid
, 0);
2435 cerr
<< "Creating collection " << cid
<< std::endl
;
2436 r
= queue_transaction(store
, ch
, std::move(t
));
2440 ObjectStore::Transaction t
;
2442 t
.truncate(cid
, a
, 3000);
2443 r
= queue_transaction(store
, ch
, std::move(t
));
2449 memset(bp
.c_str(), 1, 4096);
2451 ObjectStore::Transaction t
;
2452 t
.write(cid
, a
, 4096, 4096, bl
);
2453 r
= queue_transaction(store
, ch
, std::move(t
));
2458 ASSERT_EQ(8192, store
->read(ch
, a
, 0, 8192, bl
));
2459 for (unsigned i
=0; i
<4096; ++i
)
2460 ASSERT_EQ(0, bl
[i
]);
2461 for (unsigned i
=4096; i
<8192; ++i
)
2462 ASSERT_EQ(1, bl
[i
]);
2465 ObjectStore::Transaction t
;
2467 t
.remove_collection(cid
);
2468 cerr
<< "Cleaning" << std::endl
;
2469 r
= queue_transaction(store
, ch
, std::move(t
));
2474 TEST_P(StoreTest
, AppendDeferredVsTailCache
) {
2477 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2478 auto ch
= store
->create_new_collection(cid
);
2480 ObjectStore::Transaction t
;
2481 t
.create_collection(cid
, 0);
2482 cerr
<< "Creating collection " << cid
<< std::endl
;
2483 r
= store
->queue_transaction(ch
, std::move(t
));
2486 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2487 unsigned size
= min_alloc
/ 3;
2488 bufferptr
bpa(size
);
2489 memset(bpa
.c_str(), 1, bpa
.length());
2493 ObjectStore::Transaction t
;
2494 t
.write(cid
, a
, 0, bla
.length(), bla
, 0);
2495 r
= store
->queue_transaction(ch
, std::move(t
));
2499 // force cached tail to clear ...
2502 int r
= store
->umount();
2506 ch
= store
->open_collection(cid
);
2509 bufferptr
bpb(size
);
2510 memset(bpb
.c_str(), 2, bpb
.length());
2514 ObjectStore::Transaction t
;
2515 t
.write(cid
, a
, bla
.length(), blb
.length(), blb
, 0);
2516 r
= store
->queue_transaction(ch
, std::move(t
));
2519 bufferptr
bpc(size
);
2520 memset(bpc
.c_str(), 3, bpc
.length());
2524 ObjectStore::Transaction t
;
2525 t
.write(cid
, a
, bla
.length() + blb
.length(), blc
.length(), blc
, 0);
2526 r
= store
->queue_transaction(ch
, std::move(t
));
2535 ASSERT_EQ((int)final
.length(),
2536 store
->read(ch
, a
, 0, final
.length(), actual
));
2537 ASSERT_TRUE(bl_eq(final
, actual
));
2540 ObjectStore::Transaction t
;
2542 t
.remove_collection(cid
);
2543 cerr
<< "Cleaning" << std::endl
;
2544 r
= store
->queue_transaction(ch
, std::move(t
));
2549 TEST_P(StoreTest
, AppendZeroTrailingSharedBlock
) {
2552 ghobject_t
a(hobject_t(sobject_t("fooo", CEPH_NOSNAP
)));
2555 auto ch
= store
->create_new_collection(cid
);
2557 ObjectStore::Transaction t
;
2558 t
.create_collection(cid
, 0);
2559 cerr
<< "Creating collection " << cid
<< std::endl
;
2560 r
= store
->queue_transaction(ch
, std::move(t
));
2563 unsigned min_alloc
= g_conf()->bluestore_min_alloc_size
;
2564 unsigned size
= min_alloc
/ 3;
2565 bufferptr
bpa(size
);
2566 memset(bpa
.c_str(), 1, bpa
.length());
2569 // make sure there is some trailing gunk in the last block
2573 bt
.append("BADBADBADBAD");
2574 ObjectStore::Transaction t
;
2575 t
.write(cid
, a
, 0, bt
.length(), bt
, 0);
2576 r
= store
->queue_transaction(ch
, std::move(t
));
2580 ObjectStore::Transaction t
;
2581 t
.truncate(cid
, a
, size
);
2582 r
= store
->queue_transaction(ch
, std::move(t
));
2588 ObjectStore::Transaction t
;
2590 r
= store
->queue_transaction(ch
, std::move(t
));
2594 // append with implicit zeroing
2595 bufferptr
bpb(size
);
2596 memset(bpb
.c_str(), 2, bpb
.length());
2600 ObjectStore::Transaction t
;
2601 t
.write(cid
, a
, min_alloc
* 3, blb
.length(), blb
, 0);
2602 r
= store
->queue_transaction(ch
, std::move(t
));
2608 zeros
.append_zero(min_alloc
* 3 - size
);
2609 final
.append(zeros
);
2613 ASSERT_EQ((int)final
.length(),
2614 store
->read(ch
, a
, 0, final
.length(), actual
));
2615 final
.hexdump(cout
);
2616 actual
.hexdump(cout
);
2617 ASSERT_TRUE(bl_eq(final
, actual
));
2620 ObjectStore::Transaction t
;
2623 t
.remove_collection(cid
);
2624 cerr
<< "Cleaning" << std::endl
;
2625 r
= store
->queue_transaction(ch
, std::move(t
));
2630 TEST_P(StoreTest
, SmallSequentialUnaligned
) {
2633 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2634 auto ch
= store
->create_new_collection(cid
);
2636 ObjectStore::Transaction t
;
2637 t
.create_collection(cid
, 0);
2638 cerr
<< "Creating collection " << cid
<< std::endl
;
2639 r
= queue_transaction(store
, ch
, std::move(t
));
2647 for (int i
=0; i
<1000; ++i
) {
2648 ObjectStore::Transaction t
;
2649 t
.write(cid
, a
, i
*len
, len
, bl
, 0);
2650 r
= queue_transaction(store
, ch
, std::move(t
));
2654 ObjectStore::Transaction t
;
2656 t
.remove_collection(cid
);
2657 cerr
<< "Cleaning" << std::endl
;
2658 r
= queue_transaction(store
, ch
, std::move(t
));
2663 TEST_P(StoreTest
, ManyBigWrite
) {
2666 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2667 ghobject_t
b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
2668 auto ch
= store
->create_new_collection(cid
);
2670 ObjectStore::Transaction t
;
2671 t
.create_collection(cid
, 0);
2672 cerr
<< "Creating collection " << cid
<< std::endl
;
2673 r
= queue_transaction(store
, ch
, std::move(t
));
2677 bufferptr
bp(4 * 1048576);
2680 for (int i
=0; i
<10; ++i
) {
2681 ObjectStore::Transaction t
;
2682 t
.write(cid
, a
, i
*4*1048586, 4*1048576, bl
, 0);
2683 r
= queue_transaction(store
, ch
, std::move(t
));
2687 for (int i
=0; i
<10; ++i
) {
2688 ObjectStore::Transaction t
;
2689 t
.write(cid
, b
, (rand() % 256)*4*1048576, 4*1048576, bl
, 0);
2690 r
= queue_transaction(store
, ch
, std::move(t
));
2694 for (int i
=0; i
<10; ++i
) {
2695 ObjectStore::Transaction t
;
2696 t
.write(cid
, b
, (rand() % (256*4096))*1024, 4*1048576, bl
, 0);
2697 r
= queue_transaction(store
, ch
, std::move(t
));
2701 for (int i
=0; i
<10; ++i
) {
2702 ObjectStore::Transaction t
;
2703 t
.zero(cid
, b
, (rand() % (256*4096))*1024, 16*1048576);
2704 r
= queue_transaction(store
, ch
, std::move(t
));
2708 ObjectStore::Transaction t
;
2711 t
.remove_collection(cid
);
2712 cerr
<< "Cleaning" << std::endl
;
2713 r
= queue_transaction(store
, ch
, std::move(t
));
2718 TEST_P(StoreTest
, BigWriteBigZero
) {
2721 ghobject_t
a(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2722 auto ch
= store
->create_new_collection(cid
);
2724 ObjectStore::Transaction t
;
2725 t
.create_collection(cid
, 0);
2726 r
= queue_transaction(store
, ch
, std::move(t
));
2730 bufferptr
bp(1048576);
2731 memset(bp
.c_str(), 'b', bp
.length());
2735 memset(sp
.c_str(), 's', sp
.length());
2738 ObjectStore::Transaction t
;
2739 t
.write(cid
, a
, 0, bl
.length(), bl
);
2740 r
= queue_transaction(store
, ch
, std::move(t
));
2744 ObjectStore::Transaction t
;
2745 t
.zero(cid
, a
, bl
.length() / 4, bl
.length() / 2);
2746 r
= queue_transaction(store
, ch
, std::move(t
));
2750 ObjectStore::Transaction t
;
2751 t
.write(cid
, a
, bl
.length() / 2, s
.length(), s
);
2752 r
= queue_transaction(store
, ch
, std::move(t
));
2756 ObjectStore::Transaction t
;
2758 t
.remove_collection(cid
);
2759 r
= queue_transaction(store
, ch
, std::move(t
));
2764 TEST_P(StoreTest
, MiscFragmentTests
) {
2767 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
2768 auto ch
= store
->create_new_collection(cid
);
2770 ObjectStore::Transaction t
;
2771 t
.create_collection(cid
, 0);
2772 cerr
<< "Creating collection " << cid
<< std::endl
;
2773 r
= queue_transaction(store
, ch
, std::move(t
));
2777 bufferptr
bp(524288);
2781 ObjectStore::Transaction t
;
2782 t
.write(cid
, a
, 0, 524288, bl
, 0);
2783 r
= queue_transaction(store
, ch
, std::move(t
));
2787 ObjectStore::Transaction t
;
2788 t
.write(cid
, a
, 1048576, 524288, bl
, 0);
2789 r
= queue_transaction(store
, ch
, std::move(t
));
2794 int r
= store
->read(ch
, a
, 524288 + 131072, 1024, inbl
);
2796 ASSERT_EQ(inbl
.length(), 1024u);
2797 ASSERT_TRUE(inbl
.is_zero());
2800 ObjectStore::Transaction t
;
2801 t
.write(cid
, a
, 1048576 - 4096, 524288, bl
, 0);
2802 r
= queue_transaction(store
, ch
, std::move(t
));
2806 ObjectStore::Transaction t
;
2808 t
.remove_collection(cid
);
2809 cerr
<< "Cleaning" << std::endl
;
2810 r
= queue_transaction(store
, ch
, std::move(t
));
2816 TEST_P(StoreTest
, ZeroVsObjectSize
) {
2820 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2821 auto ch
= store
->create_new_collection(cid
);
2823 ObjectStore::Transaction t
;
2824 t
.create_collection(cid
, 0);
2825 cerr
<< "Creating collection " << cid
<< std::endl
;
2826 r
= queue_transaction(store
, ch
, std::move(t
));
2832 ObjectStore::Transaction t
;
2833 t
.write(cid
, hoid
, 0, 5, a
);
2834 r
= queue_transaction(store
, ch
, std::move(t
));
2837 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2838 ASSERT_EQ(5, stat
.st_size
);
2840 ObjectStore::Transaction t
;
2841 t
.zero(cid
, hoid
, 1, 2);
2842 r
= queue_transaction(store
, ch
, std::move(t
));
2845 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2846 ASSERT_EQ(5, stat
.st_size
);
2848 ObjectStore::Transaction t
;
2849 t
.zero(cid
, hoid
, 3, 200);
2850 r
= queue_transaction(store
, ch
, std::move(t
));
2853 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2854 ASSERT_EQ(203, stat
.st_size
);
2856 ObjectStore::Transaction t
;
2857 t
.zero(cid
, hoid
, 100000, 200);
2858 r
= queue_transaction(store
, ch
, std::move(t
));
2861 ASSERT_EQ(0, store
->stat(ch
, hoid
, &stat
));
2862 ASSERT_EQ(100200, stat
.st_size
);
2865 TEST_P(StoreTest
, ZeroLengthWrite
) {
2868 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2869 auto ch
= store
->create_new_collection(cid
);
2871 ObjectStore::Transaction t
;
2872 t
.create_collection(cid
, 0);
2874 r
= queue_transaction(store
, ch
, std::move(t
));
2878 ObjectStore::Transaction t
;
2880 t
.write(cid
, hoid
, 1048576, 0, empty
);
2881 r
= queue_transaction(store
, ch
, std::move(t
));
2885 r
= store
->stat(ch
, hoid
, &stat
);
2887 ASSERT_EQ(0, stat
.st_size
);
2890 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2894 TEST_P(StoreTest
, ZeroLengthZero
) {
2897 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
2898 auto ch
= store
->create_new_collection(cid
);
2900 ObjectStore::Transaction t
;
2901 t
.create_collection(cid
, 0);
2903 r
= queue_transaction(store
, ch
, std::move(t
));
2907 ObjectStore::Transaction t
;
2908 t
.zero(cid
, hoid
, 1048576, 0);
2909 r
= queue_transaction(store
, ch
, std::move(t
));
2913 r
= store
->stat(ch
, hoid
, &stat
);
2915 ASSERT_EQ(0, stat
.st_size
);
2918 r
= store
->read(ch
, hoid
, 0, 1048576, newdata
);
2922 TEST_P(StoreTest
, SimpleAttrTest
) {
2925 ghobject_t
hoid(hobject_t(sobject_t("attr object 1", CEPH_NOSNAP
)));
2926 bufferlist val
, val2
;
2927 val
.append("value");
2928 val
.append("value2");
2930 auto ch
= store
->open_collection(cid
);
2933 auto ch
= store
->create_new_collection(cid
);
2935 ObjectStore::Transaction t
;
2936 t
.create_collection(cid
, 0);
2937 r
= queue_transaction(store
, ch
, std::move(t
));
2942 int r
= store
->collection_empty(ch
, &empty
);
2948 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2949 ASSERT_EQ(-ENOENT
, r
);
2952 ObjectStore::Transaction t
;
2954 t
.setattr(cid
, hoid
, "foo", val
);
2955 t
.setattr(cid
, hoid
, "bar", val2
);
2956 r
= queue_transaction(store
, ch
, std::move(t
));
2961 int r
= store
->collection_empty(ch
, &empty
);
2963 ASSERT_TRUE(!empty
);
2967 r
= store
->getattr(ch
, hoid
, "nofoo", bp
);
2968 ASSERT_EQ(-ENODATA
, r
);
2970 r
= store
->getattr(ch
, hoid
, "foo", bp
);
2974 ASSERT_TRUE(bl_eq(val
, bl
));
2976 map
<string
,bufferptr
,less
<>> bm
;
2977 r
= store
->getattrs(ch
, hoid
, bm
);
2982 ObjectStore::Transaction t
;
2983 t
.remove(cid
, hoid
);
2984 t
.remove_collection(cid
);
2985 r
= queue_transaction(store
, ch
, std::move(t
));
2990 TEST_P(StoreTest
, SimpleListTest
) {
2992 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2993 auto ch
= store
->create_new_collection(cid
);
2995 ObjectStore::Transaction t
;
2996 t
.create_collection(cid
, 0);
2997 cerr
<< "Creating collection " << cid
<< std::endl
;
2998 r
= queue_transaction(store
, ch
, std::move(t
));
3001 set
<ghobject_t
> all
;
3003 ObjectStore::Transaction t
;
3004 for (int i
=0; i
<200; ++i
) {
3005 string
name("object_");
3006 name
+= stringify(i
);
3007 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
3008 ghobject_t::NO_GEN
, shard_id_t(1));
3012 cerr
<< "Creating object " << hoid
<< std::endl
;
3014 r
= queue_transaction(store
, ch
, std::move(t
));
3018 set
<ghobject_t
> saw
;
3019 vector
<ghobject_t
> objects
;
3020 ghobject_t next
, current
;
3021 while (!next
.is_max()) {
3022 int r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 50,
3025 ASSERT_TRUE(sorted(objects
));
3026 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
3027 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
3029 if (saw
.count(*p
)) {
3030 cout
<< "got DUP " << *p
<< std::endl
;
3032 //cout << "got new " << *p << std::endl;
3039 ASSERT_EQ(saw
.size(), all
.size());
3040 ASSERT_EQ(saw
, all
);
3043 ObjectStore::Transaction t
;
3044 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
3046 t
.remove_collection(cid
);
3047 cerr
<< "Cleaning" << std::endl
;
3048 r
= queue_transaction(store
, ch
, std::move(t
));
3053 TEST_P(StoreTest
, ListEndTest
) {
3055 coll_t
cid(spg_t(pg_t(0, 1), shard_id_t(1)));
3056 auto ch
= store
->create_new_collection(cid
);
3058 ObjectStore::Transaction t
;
3059 t
.create_collection(cid
, 0);
3060 cerr
<< "Creating collection " << cid
<< std::endl
;
3061 r
= queue_transaction(store
, ch
, std::move(t
));
3064 set
<ghobject_t
> all
;
3066 ObjectStore::Transaction t
;
3067 for (int i
=0; i
<200; ++i
) {
3068 string
name("object_");
3069 name
+= stringify(i
);
3070 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)),
3071 ghobject_t::NO_GEN
, shard_id_t(1));
3075 cerr
<< "Creating object " << hoid
<< std::endl
;
3077 r
= queue_transaction(store
, ch
, std::move(t
));
3081 ghobject_t
end(hobject_t(sobject_t("object_100", CEPH_NOSNAP
)),
3082 ghobject_t::NO_GEN
, shard_id_t(1));
3084 vector
<ghobject_t
> objects
;
3086 int r
= collection_list(store
, ch
, ghobject_t(), end
, 500, &objects
, &next
);
3088 for (auto &p
: objects
) {
3093 ObjectStore::Transaction t
;
3094 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
3096 t
.remove_collection(cid
);
3097 cerr
<< "Cleaning" << std::endl
;
3098 r
= queue_transaction(store
, ch
, std::move(t
));
3103 TEST_P(StoreTest
, List_0xfffffff_Hash_Test_in_meta
) {
3106 auto ch
= store
->create_new_collection(cid
);
3108 ObjectStore::Transaction t
;
3109 t
.create_collection(cid
, 0);
3110 r
= queue_transaction(store
, ch
, std::move(t
));
3114 ObjectStore::Transaction t
;
3115 ghobject_t
hoid(hobject_t(sobject_t("obj", CEPH_NOSNAP
),
3116 "", UINT32_C(0xffffffff), -1, "nspace"));
3118 r
= queue_transaction(store
, ch
, std::move(t
));
3122 vector
<ghobject_t
> objects
;
3123 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
3124 &objects
, nullptr, true);
3126 ASSERT_EQ(objects
.size(), 1);
3130 TEST_P(StoreTest
, List_0xfffffff_Hash_Test_in_PG
) {
3132 const int64_t poolid
= 1;
3133 coll_t
cid(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
3134 auto ch
= store
->create_new_collection(cid
);
3136 ObjectStore::Transaction t
;
3137 t
.create_collection(cid
, 0);
3138 r
= queue_transaction(store
, ch
, std::move(t
));
3142 ObjectStore::Transaction t
;
3143 ghobject_t
hoid(hobject_t(sobject_t("obj", CEPH_NOSNAP
),
3144 "", UINT32_C(0xffffffff), poolid
, "nspace"));
3146 r
= queue_transaction(store
, ch
, std::move(t
));
3150 vector
<ghobject_t
> objects
;
3151 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
3152 &objects
, nullptr, true);
3154 ASSERT_EQ(objects
.size(), 1);
3158 TEST_P(StoreTest
, Sort
) {
3160 hobject_t
a(sobject_t("a", CEPH_NOSNAP
));
3173 ghobject_t
a(hobject_t(sobject_t("a", CEPH_NOSNAP
)));
3174 ghobject_t
b(hobject_t(sobject_t("b", CEPH_NOSNAP
)));
3186 TEST_P(StoreTest
, MultipoolListTest
) {
3189 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
3190 auto ch
= store
->create_new_collection(cid
);
3192 ObjectStore::Transaction t
;
3193 t
.create_collection(cid
, 0);
3194 cerr
<< "Creating collection " << cid
<< std::endl
;
3195 r
= queue_transaction(store
, ch
, std::move(t
));
3198 set
<ghobject_t
> all
, saw
;
3200 ObjectStore::Transaction t
;
3201 for (int i
=0; i
<200; ++i
) {
3202 string
name("object_");
3203 name
+= stringify(i
);
3204 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
)));
3206 hoid
.hobj
.pool
= -2 - poolid
;
3208 hoid
.hobj
.pool
= poolid
;
3211 cerr
<< "Creating object " << hoid
<< std::endl
;
3213 r
= queue_transaction(store
, ch
, std::move(t
));
3217 vector
<ghobject_t
> objects
;
3218 ghobject_t next
, current
;
3219 while (!next
.is_max()) {
3220 int r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 50,
3223 cout
<< " got " << objects
.size() << " next " << next
<< std::endl
;
3224 for (vector
<ghobject_t
>::iterator p
= objects
.begin(); p
!= objects
.end();
3231 ASSERT_EQ(saw
, all
);
3234 ObjectStore::Transaction t
;
3235 for (set
<ghobject_t
>::iterator p
= all
.begin(); p
!= all
.end(); ++p
)
3237 t
.remove_collection(cid
);
3238 cerr
<< "Cleaning" << std::endl
;
3239 r
= queue_transaction(store
, ch
, std::move(t
));
3244 TEST_P(StoreTest
, SimpleCloneTest
) {
3248 SetDeathTestStyle("threadsafe");
3250 auto ch
= store
->create_new_collection(cid
);
3252 ObjectStore::Transaction t
;
3253 t
.create_collection(cid
, 0);
3254 cerr
<< "Creating collection " << cid
<< std::endl
;
3255 r
= queue_transaction(store
, ch
, std::move(t
));
3258 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
3259 "key", 123, -1, ""));
3260 bufferlist small
, large
, xlarge
, newdata
, attr
;
3261 small
.append("small");
3262 large
.append("large");
3263 xlarge
.append("xlarge");
3265 ObjectStore::Transaction t
;
3267 t
.setattr(cid
, hoid
, "attr1", small
);
3268 t
.setattr(cid
, hoid
, "attr2", large
);
3269 t
.setattr(cid
, hoid
, "attr3", xlarge
);
3270 t
.write(cid
, hoid
, 0, small
.length(), small
);
3271 t
.write(cid
, hoid
, 10, small
.length(), small
);
3272 cerr
<< "Creating object and set attr " << hoid
<< std::endl
;
3273 r
= queue_transaction(store
, ch
, std::move(t
));
3277 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
3278 "key", 123, -1, ""));
3279 ghobject_t
hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP
)));
3281 ObjectStore::Transaction t
;
3282 t
.clone(cid
, hoid
, hoid2
);
3283 t
.setattr(cid
, hoid2
, "attr2", small
);
3284 t
.rmattr(cid
, hoid2
, "attr1");
3285 t
.write(cid
, hoid
, 10, large
.length(), large
);
3286 t
.setattr(cid
, hoid
, "attr1", large
);
3287 t
.setattr(cid
, hoid
, "attr2", small
);
3288 cerr
<< "Clone object and rm attr" << std::endl
;
3289 r
= queue_transaction(store
, ch
, std::move(t
));
3292 r
= store
->read(ch
, hoid
, 10, 5, newdata
);
3294 ASSERT_TRUE(bl_eq(large
, newdata
));
3297 r
= store
->read(ch
, hoid
, 0, 5, newdata
);
3299 ASSERT_TRUE(bl_eq(small
, newdata
));
3302 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
3304 ASSERT_TRUE(bl_eq(small
, newdata
));
3306 r
= store
->getattr(ch
, hoid2
, "attr2", attr
);
3308 ASSERT_TRUE(bl_eq(small
, attr
));
3311 r
= store
->getattr(ch
, hoid2
, "attr3", attr
);
3313 ASSERT_TRUE(bl_eq(xlarge
, attr
));
3316 r
= store
->getattr(ch
, hoid
, "attr1", attr
);
3318 ASSERT_TRUE(bl_eq(large
, attr
));
3321 ObjectStore::Transaction t
;
3322 t
.remove(cid
, hoid
);
3323 t
.remove(cid
, hoid2
);
3324 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3329 memset(p
.c_str(), 1, p
.length());
3333 ObjectStore::Transaction t
;
3334 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3335 t
.clone(cid
, hoid
, hoid2
);
3337 memset(a
.c_str(), 2, a
.length());
3341 t
.write(cid
, hoid
, pl
.length(), a
.length(), al
);
3342 r
= queue_transaction(store
, ch
, std::move(t
));
3345 ASSERT_EQ((int)final
.length(),
3346 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3347 ASSERT_TRUE(bl_eq(rl
, final
));
3350 ObjectStore::Transaction t
;
3351 t
.remove(cid
, hoid
);
3352 t
.remove(cid
, hoid2
);
3353 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3358 memset(p
.c_str(), 111, p
.length());
3362 ObjectStore::Transaction t
;
3363 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3364 t
.clone(cid
, hoid
, hoid2
);
3369 memset(a
.c_str(), 112, a
.length());
3373 t
.write(cid
, hoid
, pl
.length() + z
.length(), a
.length(), al
);
3374 r
= queue_transaction(store
, ch
, std::move(t
));
3377 ASSERT_EQ((int)final
.length(),
3378 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3379 ASSERT_TRUE(bl_eq(rl
, final
));
3382 ObjectStore::Transaction t
;
3383 t
.remove(cid
, hoid
);
3384 t
.remove(cid
, hoid2
);
3385 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3390 memset(p
.c_str(), 5, p
.length());
3394 ObjectStore::Transaction t
;
3395 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3396 t
.clone(cid
, hoid
, hoid2
);
3401 memset(a
.c_str(), 6, a
.length());
3405 t
.write(cid
, hoid
, 17000, a
.length(), al
);
3406 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3408 ASSERT_EQ((int)final
.length(),
3409 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3410 /*cout << "expected:\n";
3411 final.hexdump(cout);
3414 ASSERT_TRUE(bl_eq(rl
, final
));
3417 ObjectStore::Transaction t
;
3418 t
.remove(cid
, hoid
);
3419 t
.remove(cid
, hoid2
);
3420 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3423 bufferptr
p(1048576);
3424 memset(p
.c_str(), 3, p
.length());
3427 ObjectStore::Transaction t
;
3428 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3429 t
.clone(cid
, hoid
, hoid2
);
3431 memset(a
.c_str(), 4, a
.length());
3434 t
.write(cid
, hoid
, a
.length(), a
.length(), al
);
3435 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3438 final
.substr_of(pl
, 0, al
.length());
3441 end
.substr_of(pl
, al
.length()*2, pl
.length() - al
.length()*2);
3443 ASSERT_EQ((int)final
.length(),
3444 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3445 /*cout << "expected:\n";
3446 final.hexdump(cout);
3449 ASSERT_TRUE(bl_eq(rl
, final
));
3452 ObjectStore::Transaction t
;
3453 t
.remove(cid
, hoid
);
3454 t
.remove(cid
, hoid2
);
3455 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3459 memset(p
.c_str(), 7, p
.length());
3462 ObjectStore::Transaction t
;
3463 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3464 t
.clone(cid
, hoid
, hoid2
);
3466 memset(a
.c_str(), 8, a
.length());
3469 t
.write(cid
, hoid
, 32768, a
.length(), al
);
3470 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3473 final
.substr_of(pl
, 0, 32768);
3476 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3478 ASSERT_EQ((int)final
.length(),
3479 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3480 /*cout << "expected:\n";
3481 final.hexdump(cout);
3484 ASSERT_TRUE(bl_eq(rl
, final
));
3487 ObjectStore::Transaction t
;
3488 t
.remove(cid
, hoid
);
3489 t
.remove(cid
, hoid2
);
3490 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3494 memset(p
.c_str(), 9, p
.length());
3497 ObjectStore::Transaction t
;
3498 t
.write(cid
, hoid
, 0, pl
.length(), pl
);
3499 t
.clone(cid
, hoid
, hoid2
);
3501 memset(a
.c_str(), 10, a
.length());
3504 t
.write(cid
, hoid
, 33768, a
.length(), al
);
3505 ASSERT_EQ(0, queue_transaction(store
, ch
, std::move(t
)));
3508 final
.substr_of(pl
, 0, 33768);
3511 end
.substr_of(pl
, final
.length(), pl
.length() - final
.length());
3513 ASSERT_EQ((int)final
.length(),
3514 store
->read(ch
, hoid
, 0, final
.length(), rl
));
3515 /*cout << "expected:\n";
3516 final.hexdump(cout);
3519 ASSERT_TRUE(bl_eq(rl
, final
));
3523 //verify if non-empty collection is properly handled after store reload
3525 r
= store
->umount();
3529 ch
= store
->open_collection(cid
);
3531 ObjectStore::Transaction t
;
3532 t
.remove_collection(cid
);
3533 cerr
<< "Invalid rm coll" << std::endl
;
3534 PrCtl unset_dumpable
;
3535 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3538 ObjectStore::Transaction t
;
3539 t
.touch(cid
, hoid3
); //new record in db
3540 r
= queue_transaction(store
, ch
, std::move(t
));
3544 ObjectStore::Transaction t
;
3545 //verify if non-empty collection is properly handled when there are some pending removes and live records in db
3546 cerr
<< "Invalid rm coll again" << std::endl
;
3548 r
= store
->umount();
3552 ch
= store
->open_collection(cid
);
3554 t
.remove(cid
, hoid
);
3555 t
.remove(cid
, hoid2
);
3556 t
.remove_collection(cid
);
3557 PrCtl unset_dumpable
;
3558 EXPECT_DEATH(queue_transaction(store
, ch
, std::move(t
)), "");
3561 ObjectStore::Transaction t
;
3562 t
.remove(cid
, hoid
);
3563 t
.remove(cid
, hoid2
);
3564 t
.remove(cid
, hoid3
);
3565 t
.remove_collection(cid
);
3566 cerr
<< "Cleaning" << std::endl
;
3567 r
= queue_transaction(store
, ch
, std::move(t
));
3572 TEST_P(StoreTest
, OmapSimple
) {
3575 auto ch
= store
->create_new_collection(cid
);
3577 ObjectStore::Transaction t
;
3578 t
.create_collection(cid
, 0);
3579 cerr
<< "Creating collection " << cid
<< std::endl
;
3580 r
= queue_transaction(store
, ch
, std::move(t
));
3583 ghobject_t
hoid(hobject_t(sobject_t("omap_obj", CEPH_NOSNAP
),
3584 "key", 123, -1, ""));
3586 small
.append("small");
3587 map
<string
,bufferlist
> km
;
3589 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3591 header
.append("this is a header");
3593 ObjectStore::Transaction t
;
3595 t
.omap_setkeys(cid
, hoid
, km
);
3596 t
.omap_setheader(cid
, hoid
, header
);
3597 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3598 r
= queue_transaction(store
, ch
, std::move(t
));
3604 map
<string
,bufferlist
> r
;
3605 store
->omap_get(ch
, hoid
, &h
, &r
);
3606 ASSERT_TRUE(bl_eq(header
, h
));
3607 ASSERT_EQ(r
.size(), km
.size());
3608 cout
<< "r: " << r
<< std::endl
;
3610 // test iterator with seek_to_first
3612 map
<string
,bufferlist
> r
;
3613 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3614 for (iter
->seek_to_first(); iter
->valid(); iter
->next()) {
3615 r
[iter
->key()] = iter
->value();
3617 cout
<< "r: " << r
<< std::endl
;
3618 ASSERT_EQ(r
.size(), km
.size());
3620 // test iterator with initial lower_bound
3622 map
<string
,bufferlist
> r
;
3623 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
3624 for (iter
->lower_bound(string()); iter
->valid(); iter
->next()) {
3625 r
[iter
->key()] = iter
->value();
3627 cout
<< "r: " << r
<< std::endl
;
3628 ASSERT_EQ(r
.size(), km
.size());
3631 ObjectStore::Transaction t
;
3632 t
.remove(cid
, hoid
);
3633 t
.remove_collection(cid
);
3634 cerr
<< "Cleaning" << std::endl
;
3635 r
= queue_transaction(store
, ch
, std::move(t
));
3640 TEST_P(StoreTest
, OmapCloneTest
) {
3643 auto ch
= store
->create_new_collection(cid
);
3645 ObjectStore::Transaction t
;
3646 t
.create_collection(cid
, 0);
3647 cerr
<< "Creating collection " << cid
<< std::endl
;
3648 r
= queue_transaction(store
, ch
, std::move(t
));
3651 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
),
3652 "key", 123, -1, ""));
3654 small
.append("small");
3655 map
<string
,bufferlist
> km
;
3657 km
["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3659 header
.append("this is a header");
3661 ObjectStore::Transaction t
;
3663 t
.omap_setkeys(cid
, hoid
, km
);
3664 t
.omap_setheader(cid
, hoid
, header
);
3665 cerr
<< "Creating object and set omap " << hoid
<< std::endl
;
3666 r
= queue_transaction(store
, ch
, std::move(t
));
3669 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
),
3670 "key", 123, -1, ""));
3672 ObjectStore::Transaction t
;
3673 t
.clone(cid
, hoid
, hoid2
);
3674 cerr
<< "Clone object" << std::endl
;
3675 r
= queue_transaction(store
, ch
, std::move(t
));
3679 map
<string
,bufferlist
> r
;
3681 store
->omap_get(ch
, hoid2
, &h
, &r
);
3682 ASSERT_TRUE(bl_eq(header
, h
));
3683 ASSERT_EQ(r
.size(), km
.size());
3686 ObjectStore::Transaction t
;
3687 t
.remove(cid
, hoid
);
3688 t
.remove(cid
, hoid2
);
3689 t
.remove_collection(cid
);
3690 cerr
<< "Cleaning" << std::endl
;
3691 r
= queue_transaction(store
, ch
, std::move(t
));
3696 TEST_P(StoreTest
, SimpleCloneRangeTest
) {
3699 auto ch
= store
->create_new_collection(cid
);
3701 ObjectStore::Transaction t
;
3702 t
.create_collection(cid
, 0);
3703 cerr
<< "Creating collection " << cid
<< std::endl
;
3704 r
= queue_transaction(store
, ch
, std::move(t
));
3707 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3708 hoid
.hobj
.pool
= -1;
3709 bufferlist small
, newdata
;
3710 small
.append("small");
3712 ObjectStore::Transaction t
;
3713 t
.write(cid
, hoid
, 10, 5, small
);
3714 cerr
<< "Creating object and write bl " << hoid
<< std::endl
;
3715 r
= queue_transaction(store
, ch
, std::move(t
));
3718 ghobject_t
hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP
)));
3719 hoid2
.hobj
.pool
= -1;
3721 ObjectStore::Transaction t
;
3722 t
.clone_range(cid
, hoid
, hoid2
, 10, 5, 10);
3723 cerr
<< "Clone range object" << std::endl
;
3724 r
= queue_transaction(store
, ch
, std::move(t
));
3726 r
= store
->read(ch
, hoid2
, 10, 5, newdata
);
3728 ASSERT_TRUE(bl_eq(small
, newdata
));
3731 ObjectStore::Transaction t
;
3732 t
.truncate(cid
, hoid
, 1024*1024);
3733 t
.clone_range(cid
, hoid
, hoid2
, 0, 1024*1024, 0);
3734 cerr
<< "Clone range object" << std::endl
;
3735 r
= queue_transaction(store
, ch
, std::move(t
));
3737 struct stat stat
, stat2
;
3738 r
= store
->stat(ch
, hoid
, &stat
);
3739 r
= store
->stat(ch
, hoid2
, &stat2
);
3740 ASSERT_EQ(stat
.st_size
, stat2
.st_size
);
3741 ASSERT_EQ(1024*1024, stat2
.st_size
);
3744 ObjectStore::Transaction t
;
3745 t
.remove(cid
, hoid
);
3746 t
.remove(cid
, hoid2
);
3747 r
= queue_transaction(store
, ch
, std::move(t
));
3752 #if defined(WITH_BLUESTORE)
3753 TEST_P(StoreTest
, BlueStoreUnshareBlobTest
) {
3754 if (string(GetParam()) != "bluestore")
3757 cout
<< "SKIP: non-deterministic behavior with smr" << std::endl
;
3762 auto ch
= store
->create_new_collection(cid
);
3764 ObjectStore::Transaction t
;
3765 t
.create_collection(cid
, 0);
3766 cerr
<< "Creating collection " << cid
<< std::endl
;
3767 r
= queue_transaction(store
, ch
, std::move(t
));
3770 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3771 hoid
.hobj
.pool
= -1;
3772 ghobject_t
hoid2(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3773 hoid2
.hobj
.pool
= -1;
3774 hoid2
.generation
= 2;
3776 // check if blob is unshared properly
3777 bufferlist data
, newdata
;
3778 data
.append(string(8192, 'a'));
3780 ObjectStore::Transaction t
;
3781 t
.write(cid
, hoid
, 0, data
.length(), data
);
3782 cerr
<< "Creating object and write 8K " << hoid
<< std::endl
;
3783 r
= queue_transaction(store
, ch
, std::move(t
));
3786 ObjectStore::Transaction t2
;
3787 t2
.clone_range(cid
, hoid
, hoid2
, 0, 4096, 0);
3788 cerr
<< "Clone range object" << std::endl
;
3789 r
= queue_transaction(store
, ch
, std::move(t2
));
3793 data
.append(string(4096, 'b'));
3795 ObjectStore::Transaction t3
;
3796 t3
.write(cid
, hoid
, 0, data
.length(), data
);
3797 cerr
<< "Writing 4k to source object " << hoid
<< std::endl
;
3798 r
= queue_transaction(store
, ch
, std::move(t3
));
3802 // this trims hoid one out of onode cache
3803 EXPECT_EQ(store
->umount(), 0);
3804 EXPECT_EQ(store
->mount(), 0);
3805 ch
= store
->open_collection(cid
);
3808 ObjectStore::Transaction t4
;
3809 t4
.remove(cid
, hoid2
);
3810 cerr
<< "Deleting dest object" << hoid2
<< std::endl
;
3811 r
= queue_transaction(store
, ch
, std::move(t4
));
3815 // this ensures remove operation submitted to kv store
3816 EXPECT_EQ(store
->umount(), 0);
3817 EXPECT_EQ(store
->mount(), 0);
3818 ch
= store
->open_collection(cid
);
3822 r
= store
->read(ch
, hoid
, 0, 0x2000, resdata
);
3823 ASSERT_EQ(r
, 0x2000);
3826 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
3827 auto* kv
= bstore
->get_kv();
3829 // to be inline with BlueStore.cc
3830 const string PREFIX_SHARED_BLOB
= "X";
3833 auto it
= kv
->get_iterator(PREFIX_SHARED_BLOB
);
3835 for (it
->lower_bound(string()); it
->valid(); it
->next()) {
3842 ObjectStore::Transaction t
;
3843 t
.remove(cid
, hoid
);
3844 t
.remove_collection(cid
);
3845 cerr
<< "Cleaning" << std::endl
;
3846 r
= queue_transaction(store
, ch
, std::move(t
));
3851 TEST_P(StoreTest
, BlueStoreUnshareBlobBugTest
) {
3852 if (string(GetParam()) != "bluestore")
3856 auto ch
= store
->create_new_collection(cid
);
3858 ObjectStore::Transaction t
;
3859 t
.create_collection(cid
, 0);
3860 cerr
<< "Creating collection " << cid
<< std::endl
;
3861 r
= queue_transaction(store
, ch
, std::move(t
));
3864 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3865 hoid
.hobj
.pool
= -1;
3866 ghobject_t
hoid2(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
3867 hoid2
.hobj
.pool
= -1;
3868 hoid2
.generation
= 2;
3870 // check if blob is unshared properly
3871 bufferlist data
, newdata
;
3872 data
.append(string(8192, 'a'));
3874 ObjectStore::Transaction t
;
3875 t
.write(cid
, hoid
, 0, data
.length(), data
);
3876 cerr
<< "Creating object and write 8K " << hoid
<< std::endl
;
3877 r
= queue_transaction(store
, ch
, std::move(t
));
3880 ObjectStore::Transaction t2
;
3881 t2
.clone_range(cid
, hoid
, hoid2
, 0, 4096, 0);
3882 cerr
<< "Clone range object" << std::endl
;
3883 r
= queue_transaction(store
, ch
, std::move(t2
));
3887 data
.append(string(4096, 'b'));
3889 ObjectStore::Transaction t3
;
3890 t3
.write(cid
, hoid
, 0, data
.length(), data
);
3891 cerr
<< "Writing 4k to source object " << hoid
<< std::endl
;
3892 r
= queue_transaction(store
, ch
, std::move(t3
));
3896 // this trims hoid one out of onode cache
3897 EXPECT_EQ(store
->umount(), 0);
3898 EXPECT_EQ(store
->mount(), 0);
3899 ch
= store
->open_collection(cid
);
3902 ObjectStore::Transaction t4
;
3903 t4
.write(cid
, hoid2
, 0, data
.length(), data
);
3904 cerr
<< "Writing 4k to second object " << hoid2
<< std::endl
;
3905 r
= queue_transaction(store
, ch
, std::move(t4
));
3909 r
= store
->read(ch
, hoid
, 0, 0x2000, resdata
);
3910 ASSERT_EQ(r
, 0x2000);
3913 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
3914 auto* kv
= bstore
->get_kv();
3916 // to be inline with BlueStore.cc
3917 const string PREFIX_SHARED_BLOB
= "X";
3920 auto it
= kv
->get_iterator(PREFIX_SHARED_BLOB
);
3922 for (it
->lower_bound(string()); it
->valid(); it
->next()) {
3925 // This shows a bug in unsharing a blob,
3926 // after writing to 0x0~1000 to hoid2 share blob at hoid should be
3927 //unshared but it doesn't in the current implementation
3932 ObjectStore::Transaction t
;
3933 t
.remove(cid
, hoid
);
3934 t
.remove(cid
, hoid2
);
3935 t
.remove_collection(cid
);
3936 cerr
<< "Cleaning" << std::endl
;
3937 r
= queue_transaction(store
, ch
, std::move(t
));
3943 TEST_P(StoreTest
, SimpleObjectLongnameTest
) {
3946 auto ch
= store
->create_new_collection(cid
);
3948 ObjectStore::Transaction t
;
3949 t
.create_collection(cid
, 0);
3950 cerr
<< "Creating collection " << cid
<< std::endl
;
3951 r
= queue_transaction(store
, ch
, std::move(t
));
3954 ghobject_t
hoid(hobject_t(sobject_t("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaObjectaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1", CEPH_NOSNAP
)));
3956 ObjectStore::Transaction t
;
3958 cerr
<< "Creating object " << hoid
<< std::endl
;
3959 r
= queue_transaction(store
, ch
, std::move(t
));
3963 ObjectStore::Transaction t
;
3964 t
.remove(cid
, hoid
);
3965 t
.remove_collection(cid
);
3966 cerr
<< "Cleaning" << std::endl
;
3967 r
= queue_transaction(store
, ch
, std::move(t
));
3972 ghobject_t
generate_long_name(unsigned i
)
3975 name
<< "object id " << i
<< " ";
3976 for (unsigned j
= 0; j
< 500; ++j
) name
<< 'a';
3977 ghobject_t
hoid(hobject_t(sobject_t(name
.str(), CEPH_NOSNAP
)));
3978 hoid
.hobj
.set_hash(i
% 2);
3982 TEST_P(StoreTest
, LongnameSplitTest
) {
3985 auto ch
= store
->create_new_collection(cid
);
3987 ObjectStore::Transaction t
;
3988 t
.create_collection(cid
, 0);
3989 cerr
<< "Creating collection " << cid
<< std::endl
;
3990 r
= queue_transaction(store
, ch
, std::move(t
));
3993 for (unsigned i
= 0; i
< 320; ++i
) {
3994 ObjectStore::Transaction t
;
3995 ghobject_t hoid
= generate_long_name(i
);
3997 cerr
<< "Creating object " << hoid
<< std::endl
;
3998 r
= queue_transaction(store
, ch
, std::move(t
));
4002 ghobject_t test_obj
= generate_long_name(319);
4003 ghobject_t test_obj_2
= test_obj
;
4004 test_obj_2
.generation
= 0;
4006 ObjectStore::Transaction t
;
4007 // should cause a split
4008 t
.collection_move_rename(
4011 r
= queue_transaction(store
, ch
, std::move(t
));
4015 for (unsigned i
= 0; i
< 319; ++i
) {
4016 ObjectStore::Transaction t
;
4017 ghobject_t hoid
= generate_long_name(i
);
4018 t
.remove(cid
, hoid
);
4019 cerr
<< "Removing object " << hoid
<< std::endl
;
4020 r
= queue_transaction(store
, ch
, std::move(t
));
4024 ObjectStore::Transaction t
;
4025 t
.remove(cid
, test_obj_2
);
4026 t
.remove_collection(cid
);
4027 cerr
<< "Cleaning" << std::endl
;
4028 r
= queue_transaction(store
, ch
, std::move(t
));
4034 TEST_P(StoreTest
, ManyObjectTest
) {
4035 int NUM_OBJS
= 2000;
4039 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
4040 set
<ghobject_t
> created
;
4041 auto ch
= store
->create_new_collection(cid
);
4043 ObjectStore::Transaction t
;
4044 t
.create_collection(cid
, 0);
4045 r
= queue_transaction(store
, ch
, std::move(t
));
4048 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
4050 cerr
<< "Object " << i
<< std::endl
;
4052 ObjectStore::Transaction t
;
4054 snprintf(buf
, sizeof(buf
), "%d", i
);
4055 ghobject_t
hoid(hobject_t(sobject_t(string(buf
) + base
, CEPH_NOSNAP
)));
4057 created
.insert(hoid
);
4058 r
= queue_transaction(store
, ch
, std::move(t
));
4062 for (set
<ghobject_t
>::iterator i
= created
.begin();
4066 ASSERT_TRUE(!store
->stat(ch
, *i
, &buf
));
4069 set
<ghobject_t
> listed
, listed2
;
4070 vector
<ghobject_t
> objects
;
4071 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
4075 cerr
<< "objects.size() is " << objects
.size() << std::endl
;
4076 for (vector
<ghobject_t
> ::iterator i
= objects
.begin();
4080 ASSERT_TRUE(created
.count(*i
));
4082 ASSERT_TRUE(listed
.size() == created
.size());
4084 ghobject_t start
, next
;
4086 r
= collection_list(
4089 ghobject_t::get_max(),
4090 ghobject_t::get_max(),
4096 ASSERT_TRUE(objects
.empty());
4100 ghobject_t start2
, next2
;
4102 r
= collection_list(store
, ch
, start
, ghobject_t::get_max(), 50, &objects
,
4104 ASSERT_TRUE(sorted(objects
));
4106 listed
.insert(objects
.begin(), objects
.end());
4107 if (objects
.size() < 50) {
4108 ASSERT_TRUE(next
.is_max());
4115 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
4116 ASSERT_TRUE(listed
.size() == created
.size());
4117 if (listed2
.size()) {
4118 ASSERT_EQ(listed
.size(), listed2
.size());
4120 for (set
<ghobject_t
>::iterator i
= listed
.begin();
4123 ASSERT_TRUE(created
.count(*i
));
4126 for (set
<ghobject_t
>::iterator i
= created
.begin();
4129 ObjectStore::Transaction t
;
4131 r
= queue_transaction(store
, ch
, std::move(t
));
4134 cerr
<< "cleaning up" << std::endl
;
4136 ObjectStore::Transaction t
;
4137 t
.remove_collection(cid
);
4138 r
= queue_transaction(store
, ch
, std::move(t
));
4144 class ObjectGenerator
{
4146 virtual ghobject_t
create_object(gen_type
*gen
) = 0;
4147 virtual ~ObjectGenerator() {}
4150 class MixedGenerator
: public ObjectGenerator
{
4154 explicit MixedGenerator(int64_t p
) : seq(0), poolid(p
) {}
4155 ghobject_t
create_object(gen_type
*gen
) override
{
4157 snprintf(buf
, sizeof(buf
), "OBJ_%u", seq
);
4160 for (unsigned i
= 0; i
< 300; ++i
) {
4161 name
.push_back('a');
4167 name
, string(), rand() & 2 ? CEPH_NOSNAP
: rand(),
4168 (((seq
/ 1024) % 2) * 0xF00 ) +
4174 class SyntheticWorkloadState
{
4177 map
<string
, bufferlist
> attrs
;
4180 static const unsigned max_in_flight
= 16;
4181 static const unsigned max_objects
= 3000;
4182 static const unsigned max_attr_size
= 5;
4183 static const unsigned max_attr_name_len
= 100;
4184 static const unsigned max_attr_value_len
= 1024 * 64;
4186 unsigned write_alignment
;
4187 unsigned max_object_len
, max_write_len
;
4189 map
<ghobject_t
, Object
> contents
;
4190 set
<ghobject_t
> available_objects
;
4191 set
<ghobject_t
>::iterator next_available_object
;
4192 set
<ghobject_t
> in_flight_objects
;
4193 ObjectGenerator
*object_gen
;
4196 ObjectStore::CollectionHandle ch
;
4198 ceph::mutex lock
= ceph::make_mutex("State lock");
4199 ceph::condition_variable cond
;
4203 explicit EnterExit(const char *m
) : msg(m
) {
4204 //cout << pthread_self() << " enter " << msg << std::endl;
4207 //cout << pthread_self() << " exit " << msg << std::endl;
4211 class C_SyntheticOnReadable
: public Context
{
4213 SyntheticWorkloadState
*state
;
4215 C_SyntheticOnReadable(SyntheticWorkloadState
*state
, ghobject_t hoid
)
4216 : state(state
), hoid(hoid
) {}
4218 void finish(int r
) override
{
4219 std::lock_guard locker
{state
->lock
};
4220 EnterExit
ee("onreadable finish");
4221 ASSERT_TRUE(state
->in_flight_objects
.count(hoid
));
4223 state
->in_flight_objects
.erase(hoid
);
4224 if (state
->contents
.count(hoid
))
4225 state
->available_objects
.insert(hoid
);
4226 --(state
->in_flight
);
4227 state
->cond
.notify_all();
4230 r
= state
->store
->read(state
->ch
, hoid
, 0, state
->contents
[hoid
].data
.length(), r2
);
4231 ceph_assert(bl_eq(state
->contents
[hoid
].data
, r2
));
4232 state
->cond
.notify_all();
4236 class C_SyntheticOnStash
: public Context
{
4238 SyntheticWorkloadState
*state
;
4239 ghobject_t oid
, noid
;
4241 C_SyntheticOnStash(SyntheticWorkloadState
*state
,
4242 ghobject_t oid
, ghobject_t noid
)
4243 : state(state
), oid(oid
), noid(noid
) {}
4245 void finish(int r
) override
{
4246 std::lock_guard locker
{state
->lock
};
4247 EnterExit
ee("stash finish");
4248 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
4250 state
->in_flight_objects
.erase(oid
);
4251 if (state
->contents
.count(noid
))
4252 state
->available_objects
.insert(noid
);
4253 --(state
->in_flight
);
4255 r
= state
->store
->read(
4257 state
->contents
[noid
].data
.length(), r2
);
4258 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
4259 state
->cond
.notify_all();
4263 class C_SyntheticOnClone
: public Context
{
4265 SyntheticWorkloadState
*state
;
4266 ghobject_t oid
, noid
;
4268 C_SyntheticOnClone(SyntheticWorkloadState
*state
,
4269 ghobject_t oid
, ghobject_t noid
)
4270 : state(state
), oid(oid
), noid(noid
) {}
4272 void finish(int r
) override
{
4273 std::lock_guard locker
{state
->lock
};
4274 EnterExit
ee("clone finish");
4275 ASSERT_TRUE(state
->in_flight_objects
.count(oid
));
4277 state
->in_flight_objects
.erase(oid
);
4278 if (state
->contents
.count(oid
))
4279 state
->available_objects
.insert(oid
);
4280 if (state
->contents
.count(noid
))
4281 state
->available_objects
.insert(noid
);
4282 --(state
->in_flight
);
4284 r
= state
->store
->read(state
->ch
, noid
, 0, state
->contents
[noid
].data
.length(), r2
);
4285 ceph_assert(bl_eq(state
->contents
[noid
].data
, r2
));
4286 state
->cond
.notify_all();
4290 static void filled_byte_array(bufferlist
& bl
, size_t size
)
4292 static const char alphanum
[] = "0123456789"
4293 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
4294 "abcdefghijklmnopqrstuvwxyz";
4299 for (unsigned int i
= 0; i
< size
- 1; i
++) {
4300 // severely limit entropy so we can compress...
4301 bp
[i
] = alphanum
[rand() % 10]; //(sizeof(alphanum) - 1)];
4303 bp
[size
- 1] = '\0';
4308 SyntheticWorkloadState(ObjectStore
*store
,
4309 ObjectGenerator
*gen
,
4315 : cid(cid
), write_alignment(alignment
), max_object_len(max_size
),
4316 max_write_len(max_write
), in_flight(0),
4317 next_available_object(available_objects
.end()),
4318 object_gen(gen
), rng(rng
), store(store
) {}
4321 ObjectStore::Transaction t
;
4322 ch
= store
->create_new_collection(cid
);
4323 t
.create_collection(cid
, 0);
4324 return queue_transaction(store
, ch
, std::move(t
));
4329 vector
<ghobject_t
> objects
;
4330 int r
= collection_list(store
, ch
, next
, ghobject_t::get_max(), 10,
4332 ceph_assert(r
>= 0);
4333 if (objects
.size() == 0)
4335 ObjectStore::Transaction t
;
4336 std::map
<std::string
, ceph::buffer::list
> attrset
;
4337 for (vector
<ghobject_t
>::iterator p
= objects
.begin();
4338 p
!= objects
.end(); ++p
) {
4341 queue_transaction(store
, ch
, std::move(t
));
4343 ObjectStore::Transaction t
;
4344 t
.remove_collection(cid
);
4345 queue_transaction(store
, ch
, std::move(t
));
4347 void statfs(store_statfs_t
& stat
) {
4348 store
->statfs(&stat
);
4351 ghobject_t
get_uniform_random_object(std::unique_lock
<ceph::mutex
>& locker
) {
4352 cond
.wait(locker
, [this] {
4353 return in_flight
< max_in_flight
&& !available_objects
.empty();
4355 boost::uniform_int
<> choose(0, available_objects
.size() - 1);
4356 int index
= choose(*rng
);
4357 set
<ghobject_t
>::iterator i
= available_objects
.begin();
4358 for ( ; index
> 0; --index
, ++i
) ;
4359 ghobject_t ret
= *i
;
4363 ghobject_t
get_next_object(std::unique_lock
<ceph::mutex
>& locker
) {
4364 cond
.wait(locker
, [this] {
4365 return in_flight
< max_in_flight
&& !available_objects
.empty();
4368 if (next_available_object
== available_objects
.end()) {
4369 next_available_object
= available_objects
.begin();
4372 ghobject_t ret
= *next_available_object
;
4373 ++next_available_object
;
4377 void wait_for_ready(std::unique_lock
<ceph::mutex
>& locker
) {
4378 cond
.wait(locker
, [this] { return in_flight
< max_in_flight
; });
4381 void wait_for_done() {
4382 std::unique_lock locker
{lock
};
4383 cond
.wait(locker
, [this] { return in_flight
== 0; });
4387 return (available_objects
.size() + in_flight_objects
.size()) < max_objects
;
4391 return (available_objects
.size() + in_flight_objects
.size()) > 0;
4394 unsigned get_random_alloc_hints() {
4397 boost::uniform_int
<> u(0, 3);
4400 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE
;
4403 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE
;
4408 boost::uniform_int
<> u(0, 3);
4411 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
;
4414 f
|= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ
;
4419 // append_only, immutable
4420 boost::uniform_int
<> u(0, 4);
4424 boost::uniform_int
<> u(0, 3);
4427 f
|= CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED
;
4430 f
|= CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED
;
4435 boost::uniform_int
<> u(0, 3);
4438 f
|= CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE
;
4441 f
|= CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE
;
4449 std::unique_lock locker
{lock
};
4450 EnterExit
ee("touch");
4453 wait_for_ready(locker
);
4454 ghobject_t new_obj
= object_gen
->create_object(rng
);
4455 available_objects
.erase(new_obj
);
4456 ObjectStore::Transaction t
;
4457 t
.touch(cid
, new_obj
);
4458 boost::uniform_int
<> u(17, 22);
4459 boost::uniform_int
<> v(12, 17);
4460 t
.set_alloc_hint(cid
, new_obj
,
4463 get_random_alloc_hints());
4465 in_flight_objects
.insert(new_obj
);
4466 if (!contents
.count(new_obj
))
4467 contents
[new_obj
] = Object();
4468 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4469 int status
= store
->queue_transaction(ch
, std::move(t
));
4474 std::unique_lock locker
{lock
};
4475 EnterExit
ee("stash");
4480 wait_for_ready(locker
);
4485 old_obj
= get_uniform_random_object(locker
);
4486 } while (--max
&& !contents
[old_obj
].data
.length());
4487 available_objects
.erase(old_obj
);
4488 ghobject_t new_obj
= old_obj
;
4489 new_obj
.generation
++;
4490 available_objects
.erase(new_obj
);
4492 ObjectStore::Transaction t
;
4493 t
.collection_move_rename(cid
, old_obj
, cid
, new_obj
);
4495 in_flight_objects
.insert(old_obj
);
4497 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
4498 contents
[new_obj
].data
= contents
[old_obj
].data
;
4499 contents
.erase(old_obj
);
4500 t
.register_on_applied(new C_SyntheticOnStash(this, old_obj
, new_obj
));
4501 int status
= store
->queue_transaction(ch
, std::move(t
));
4506 std::unique_lock locker
{lock
};
4507 EnterExit
ee("clone");
4512 wait_for_ready(locker
);
4517 old_obj
= get_uniform_random_object(locker
);
4518 } while (--max
&& !contents
[old_obj
].data
.length());
4519 available_objects
.erase(old_obj
);
4520 ghobject_t new_obj
= object_gen
->create_object(rng
);
4521 // make the hash match
4522 new_obj
.hobj
.set_hash(old_obj
.hobj
.get_hash());
4523 available_objects
.erase(new_obj
);
4525 ObjectStore::Transaction t
;
4526 t
.clone(cid
, old_obj
, new_obj
);
4528 in_flight_objects
.insert(old_obj
);
4530 contents
[new_obj
].attrs
= contents
[old_obj
].attrs
;
4531 contents
[new_obj
].data
= contents
[old_obj
].data
;
4533 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
4534 int status
= store
->queue_transaction(ch
, std::move(t
));
4539 std::unique_lock locker
{lock
};
4540 EnterExit
ee("clone_range");
4545 wait_for_ready(locker
);
4550 old_obj
= get_uniform_random_object(locker
);
4551 } while (--max
&& !contents
[old_obj
].data
.length());
4552 bufferlist
&srcdata
= contents
[old_obj
].data
;
4553 if (srcdata
.length() == 0) {
4556 available_objects
.erase(old_obj
);
4557 ghobject_t new_obj
= get_uniform_random_object(locker
);
4558 available_objects
.erase(new_obj
);
4560 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4561 boost::uniform_int
<> u2(0, max_write_len
);
4562 uint64_t srcoff
= u1(*rng
);
4563 // make src and dst offsets match, since that's what the osd does
4564 uint64_t dstoff
= srcoff
; //u1(*rng);
4565 uint64_t len
= u2(*rng
);
4566 if (write_alignment
) {
4567 srcoff
= round_up_to(srcoff
, write_alignment
);
4568 dstoff
= round_up_to(dstoff
, write_alignment
);
4569 len
= round_up_to(len
, write_alignment
);
4572 if (srcoff
> srcdata
.length() - 1) {
4573 srcoff
= srcdata
.length() - 1;
4575 if (srcoff
+ len
> srcdata
.length()) {
4576 len
= srcdata
.length() - srcoff
;
4579 cout
<< __func__
<< " from " << srcoff
<< "~" << len
4580 << " (size " << srcdata
.length() << ") to "
4581 << dstoff
<< "~" << len
<< std::endl
;
4583 ObjectStore::Transaction t
;
4584 t
.clone_range(cid
, old_obj
, new_obj
, srcoff
, len
, dstoff
);
4586 in_flight_objects
.insert(old_obj
);
4589 if (srcoff
< srcdata
.length()) {
4590 if (srcoff
+ len
> srcdata
.length()) {
4591 bl
.substr_of(srcdata
, srcoff
, srcdata
.length() - srcoff
);
4593 bl
.substr_of(srcdata
, srcoff
, len
);
4597 bufferlist
& dstdata
= contents
[new_obj
].data
;
4598 if (dstdata
.length() <= dstoff
) {
4599 if (bl
.length() > 0) {
4600 dstdata
.append_zero(dstoff
- dstdata
.length());
4605 ceph_assert(dstdata
.length() > dstoff
);
4606 dstdata
.cbegin().copy(dstoff
, value
);
4608 if (value
.length() < dstdata
.length())
4609 dstdata
.cbegin(value
.length()).copy(
4610 dstdata
.length() - value
.length(), value
);
4611 value
.swap(dstdata
);
4614 t
.register_on_applied(new C_SyntheticOnClone(this, old_obj
, new_obj
));
4615 int status
= store
->queue_transaction(ch
, std::move(t
));
4621 std::unique_lock locker
{lock
};
4622 EnterExit
ee("write");
4625 wait_for_ready(locker
);
4627 ghobject_t new_obj
= get_uniform_random_object(locker
);
4628 available_objects
.erase(new_obj
);
4629 ObjectStore::Transaction t
;
4631 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4632 boost::uniform_int
<> u2(0, max_write_len
);
4633 uint64_t offset
= u1(*rng
);
4634 uint64_t len
= u2(*rng
);
4636 if (write_alignment
) {
4637 offset
= round_up_to(offset
, write_alignment
);
4638 len
= round_up_to(len
, write_alignment
);
4641 filled_byte_array(bl
, len
);
4643 bufferlist
& data
= contents
[new_obj
].data
;
4644 if (data
.length() <= offset
) {
4646 data
.append_zero(offset
-data
.length());
4651 ceph_assert(data
.length() > offset
);
4652 data
.cbegin().copy(offset
, value
);
4654 if (value
.length() < data
.length())
4655 data
.cbegin(value
.length()).copy(
4656 data
.length()-value
.length(), value
);
4660 t
.write(cid
, new_obj
, offset
, len
, bl
);
4662 in_flight_objects
.insert(new_obj
);
4663 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4664 int status
= store
->queue_transaction(ch
, std::move(t
));
4669 std::unique_lock locker
{lock
};
4670 EnterExit
ee("truncate");
4673 wait_for_ready(locker
);
4675 ghobject_t obj
= get_uniform_random_object(locker
);
4676 available_objects
.erase(obj
);
4677 ObjectStore::Transaction t
;
4679 boost::uniform_int
<> choose(0, max_object_len
);
4680 size_t len
= choose(*rng
);
4681 if (write_alignment
) {
4682 len
= round_up_to(len
, write_alignment
);
4685 t
.truncate(cid
, obj
, len
);
4687 in_flight_objects
.insert(obj
);
4688 bufferlist
& data
= contents
[obj
].data
;
4689 if (data
.length() <= len
) {
4690 data
.append_zero(len
- data
.length());
4693 data
.cbegin().copy(len
, bl
);
4697 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4698 int status
= store
->queue_transaction(ch
, std::move(t
));
4703 std::unique_lock locker
{lock
};
4704 EnterExit
ee("zero");
4707 wait_for_ready(locker
);
4709 ghobject_t new_obj
= get_uniform_random_object(locker
);
4710 available_objects
.erase(new_obj
);
4711 ObjectStore::Transaction t
;
4713 boost::uniform_int
<> u1(0, max_object_len
- max_write_len
);
4714 boost::uniform_int
<> u2(0, max_write_len
);
4715 uint64_t offset
= u1(*rng
);
4716 uint64_t len
= u2(*rng
);
4717 if (write_alignment
) {
4718 offset
= round_up_to(offset
, write_alignment
);
4719 len
= round_up_to(len
, write_alignment
);
4723 auto& data
= contents
[new_obj
].data
;
4724 if (data
.length() < offset
+ len
) {
4725 data
.append_zero(offset
+len
-data
.length());
4728 n
.substr_of(data
, 0, offset
);
4730 if (data
.length() > offset
+ len
)
4731 data
.cbegin(offset
+ len
).copy(data
.length() - offset
- len
, n
);
4735 t
.zero(cid
, new_obj
, offset
, len
);
4737 in_flight_objects
.insert(new_obj
);
4738 t
.register_on_applied(new C_SyntheticOnReadable(this, new_obj
));
4739 int status
= store
->queue_transaction(ch
, std::move(t
));
4744 EnterExit
ee("read");
4745 boost::uniform_int
<> u1(0, max_object_len
/2);
4746 boost::uniform_int
<> u2(0, max_object_len
);
4747 uint64_t offset
= u1(*rng
);
4748 uint64_t len
= u2(*rng
);
4753 bufferlist expected
;
4756 std::unique_lock locker
{lock
};
4757 EnterExit
ee("read locked");
4760 wait_for_ready(locker
);
4762 obj
= get_uniform_random_object(locker
);
4763 expected
= contents
[obj
].data
;
4765 bufferlist bl
, result
;
4766 if (0) cout
<< " obj " << obj
4767 << " size " << expected
.length()
4768 << " offset " << offset
4769 << " len " << len
<< std::endl
;
4770 r
= store
->read(ch
, obj
, offset
, len
, result
);
4771 if (offset
>= expected
.length()) {
4774 size_t max_len
= expected
.length() - offset
;
4777 ceph_assert(len
== result
.length());
4778 ASSERT_EQ(len
, result
.length());
4779 expected
.cbegin(offset
).copy(len
, bl
);
4780 ASSERT_EQ(r
, (int)len
);
4781 ASSERT_TRUE(bl_eq(bl
, result
));
4786 std::unique_lock locker
{lock
};
4787 EnterExit
ee("setattrs");
4790 wait_for_ready(locker
);
4792 ghobject_t obj
= get_uniform_random_object(locker
);
4793 available_objects
.erase(obj
);
4794 ObjectStore::Transaction t
;
4796 boost::uniform_int
<> u0(1, max_attr_size
);
4797 boost::uniform_int
<> u1(4, max_attr_name_len
);
4798 boost::uniform_int
<> u2(4, max_attr_value_len
);
4799 boost::uniform_int
<> u3(0, 100);
4800 uint64_t size
= u0(*rng
);
4802 map
<string
, bufferlist
, less
<>> attrs
;
4804 for (map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4805 it
!= contents
[obj
].attrs
.end(); ++it
)
4806 keys
.insert(it
->first
);
4809 bufferlist name
, value
;
4810 uint64_t get_exist
= u3(*rng
);
4811 uint64_t value_len
= u2(*rng
);
4812 filled_byte_array(value
, value_len
);
4813 if (get_exist
< 50 && keys
.size()) {
4814 set
<string
>::iterator k
= keys
.begin();
4816 contents
[obj
].attrs
[*k
] = value
;
4819 name_len
= u1(*rng
);
4820 filled_byte_array(name
, name_len
);
4821 attrs
[name
.c_str()] = value
;
4822 contents
[obj
].attrs
[name
.c_str()] = value
;
4825 t
.setattrs(cid
, obj
, attrs
);
4827 in_flight_objects
.insert(obj
);
4828 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4829 int status
= store
->queue_transaction(ch
, std::move(t
));
4833 int set_fixed_attrs(size_t entries
, size_t key_size
, size_t val_size
) {
4834 std::unique_lock locker
{ lock
};
4835 EnterExit
ee("setattrs");
4838 wait_for_ready(locker
);
4840 ghobject_t obj
= get_next_object(locker
);
4841 available_objects
.erase(obj
);
4842 ObjectStore::Transaction t
;
4844 map
<string
, bufferlist
, less
<>> attrs
;
4848 bufferlist name
, value
;
4849 filled_byte_array(value
, val_size
);
4850 filled_byte_array(name
, key_size
);
4851 attrs
[name
.c_str()] = value
;
4852 contents
[obj
].attrs
[name
.c_str()] = value
;
4854 t
.setattrs(cid
, obj
, attrs
);
4856 in_flight_objects
.insert(obj
);
4857 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4858 int status
= store
->queue_transaction(ch
, std::move(t
));
4863 EnterExit
ee("getattrs");
4865 map
<string
, bufferlist
> expected
;
4867 std::unique_lock locker
{lock
};
4868 EnterExit
ee("getattrs locked");
4871 wait_for_ready(locker
);
4875 obj
= get_uniform_random_object(locker
);
4878 } while (contents
[obj
].attrs
.empty());
4879 expected
= contents
[obj
].attrs
;
4881 map
<string
, bufferlist
, less
<>> attrs
;
4882 int r
= store
->getattrs(ch
, obj
, attrs
);
4883 ASSERT_TRUE(r
== 0);
4884 ASSERT_TRUE(attrs
.size() == expected
.size());
4885 for (map
<string
, bufferlist
>::iterator it
= expected
.begin();
4886 it
!= expected
.end(); ++it
) {
4887 ASSERT_TRUE(bl_eq(attrs
[it
->first
], it
->second
));
4892 EnterExit
ee("getattr");
4896 map
<string
, bufferlist
> expected
;
4898 std::unique_lock locker
{lock
};
4899 EnterExit
ee("getattr locked");
4902 wait_for_ready(locker
);
4906 obj
= get_uniform_random_object(locker
);
4909 } while (contents
[obj
].attrs
.empty());
4910 expected
= contents
[obj
].attrs
;
4912 boost::uniform_int
<> u(0, expected
.size()-1);
4914 map
<string
, bufferlist
>::iterator it
= expected
.begin();
4921 r
= store
->getattr(ch
, obj
, it
->first
, bl
);
4923 ASSERT_TRUE(bl_eq(it
->second
, bl
));
4927 std::unique_lock locker
{lock
};
4928 EnterExit
ee("rmattr");
4931 wait_for_ready(locker
);
4936 obj
= get_uniform_random_object(locker
);
4939 } while (contents
[obj
].attrs
.empty());
4941 boost::uniform_int
<> u(0, contents
[obj
].attrs
.size()-1);
4943 map
<string
, bufferlist
>::iterator it
= contents
[obj
].attrs
.begin();
4949 available_objects
.erase(obj
);
4950 ObjectStore::Transaction t
;
4951 t
.rmattr(cid
, obj
, it
->first
);
4953 contents
[obj
].attrs
.erase(it
->first
);
4955 in_flight_objects
.insert(obj
);
4956 t
.register_on_applied(new C_SyntheticOnReadable(this, obj
));
4957 int status
= store
->queue_transaction(ch
, std::move(t
));
4961 void fsck(bool deep
) {
4962 std::unique_lock locker
{lock
};
4963 EnterExit
ee("fsck");
4964 cond
.wait(locker
, [this] { return in_flight
== 0; });
4967 int r
= store
->fsck(deep
);
4968 ceph_assert(r
== 0 || r
== -EOPNOTSUPP
);
4970 ch
= store
->open_collection(cid
);
4974 std::unique_lock locker
{lock
};
4975 EnterExit
ee("scan");
4976 cond
.wait(locker
, [this] { return in_flight
== 0; });
4977 vector
<ghobject_t
> objects
;
4978 set
<ghobject_t
> objects_set
, objects_set2
;
4979 ghobject_t next
, current
;
4981 //cerr << "scanning..." << std::endl;
4982 int r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 100,
4985 ASSERT_TRUE(sorted(objects
));
4986 objects_set
.insert(objects
.begin(), objects
.end());
4988 if (next
.is_max()) break;
4991 if (objects_set
.size() != available_objects
.size()) {
4992 for (set
<ghobject_t
>::iterator p
= objects_set
.begin();
4993 p
!= objects_set
.end();
4995 if (available_objects
.count(*p
) == 0) {
4996 cerr
<< "+ " << *p
<< std::endl
;
4999 for (set
<ghobject_t
>::iterator p
= available_objects
.begin();
5000 p
!= available_objects
.end();
5002 if (objects_set
.count(*p
) == 0)
5003 cerr
<< "- " << *p
<< std::endl
;
5004 //cerr << " objects_set: " << objects_set << std::endl;
5005 //cerr << " available_set: " << available_objects << std::endl;
5006 ceph_abort_msg("badness");
5009 ASSERT_EQ(objects_set
.size(), available_objects
.size());
5010 for (set
<ghobject_t
>::iterator i
= objects_set
.begin();
5011 i
!= objects_set
.end();
5013 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
5016 int r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(),
5017 INT_MAX
, &objects
, 0);
5019 objects_set2
.insert(objects
.begin(), objects
.end());
5020 ASSERT_EQ(objects_set2
.size(), available_objects
.size());
5021 for (set
<ghobject_t
>::iterator i
= objects_set2
.begin();
5022 i
!= objects_set2
.end();
5024 ASSERT_GT(available_objects
.count(*i
), (unsigned)0);
5025 if (available_objects
.count(*i
) == 0) {
5026 cerr
<< "+ " << *i
<< std::endl
;
5032 EnterExit
ee("stat");
5036 std::unique_lock locker
{lock
};
5037 EnterExit
ee("stat lock1");
5040 hoid
= get_uniform_random_object(locker
);
5041 in_flight_objects
.insert(hoid
);
5042 available_objects
.erase(hoid
);
5044 expected
= contents
[hoid
].data
.length();
5047 int r
= store
->stat(ch
, hoid
, &buf
);
5049 ceph_assert((uint64_t)buf
.st_size
== expected
);
5050 ASSERT_TRUE((uint64_t)buf
.st_size
== expected
);
5052 std::lock_guard locker
{lock
};
5053 EnterExit
ee("stat lock2");
5056 in_flight_objects
.erase(hoid
);
5057 available_objects
.insert(hoid
);
5062 std::unique_lock locker
{lock
};
5063 EnterExit
ee("unlink");
5066 ghobject_t to_remove
= get_uniform_random_object(locker
);
5067 ObjectStore::Transaction t
;
5068 t
.remove(cid
, to_remove
);
5070 available_objects
.erase(to_remove
);
5071 in_flight_objects
.insert(to_remove
);
5072 contents
.erase(to_remove
);
5073 t
.register_on_applied(new C_SyntheticOnReadable(this, to_remove
));
5074 int status
= store
->queue_transaction(ch
, std::move(t
));
5078 void print_internal_state() {
5079 std::lock_guard locker
{lock
};
5080 cerr
<< "available_objects: " << available_objects
.size()
5081 << " in_flight_objects: " << in_flight_objects
.size()
5082 << " total objects: " << in_flight_objects
.size() + available_objects
.size()
5083 << " in_flight " << in_flight
<< std::endl
;
5088 void StoreTest::doSyntheticTest(
5090 uint64_t max_obj
, uint64_t max_wr
, uint64_t align
)
5092 MixedGenerator
gen(555);
5093 gen_type
rng(time(NULL
));
5094 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
5096 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
5097 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
5098 g_ceph_context
->_conf
.apply_changes(nullptr);
5100 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
,
5101 max_obj
, max_wr
, align
);
5103 for (int i
= 0; i
< num_ops
/10; ++i
) {
5104 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
5107 for (int i
= 0; i
< num_ops
; ++i
) {
5109 cerr
<< "Op " << i
<< std::endl
;
5110 test_obj
.print_internal_state();
5112 boost::uniform_int
<> true_false(0, 999);
5113 int val
= true_false(rng
);
5115 test_obj
.fsck(true);
5116 } else if (val
> 997) {
5117 test_obj
.fsck(false);
5118 } else if (val
> 970) {
5120 } else if (val
> 950) {
5122 } else if (val
> 850) {
5124 } else if (val
> 800) {
5126 } else if (val
> 550) {
5128 } else if (val
> 500) {
5130 } else if (val
> 450) {
5131 test_obj
.clone_range();
5132 } else if (val
> 300) {
5134 } else if (val
> 100) {
5137 test_obj
.truncate();
5140 test_obj
.wait_for_done();
5141 test_obj
.shutdown();
5144 TEST_P(StoreTest
, Synthetic
) {
5145 doSyntheticTest(10000, 400*1024, 40*1024, 0);
5148 #if defined(WITH_BLUESTORE)
5149 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixSharding
) {
5150 if (string(GetParam()) != "bluestore")
5153 const char *m
[][10] = {
5154 { "bluestore_min_alloc_size", "4096", 0 }, // must be the first!
5155 { "num_ops", "50000", 0 },
5156 { "max_write", "65536", 0 },
5157 { "max_size", "262144", 0 },
5158 { "alignment", "4096", 0 },
5159 { "bluestore_max_blob_size", "65536", 0 },
5160 { "bluestore_extent_map_shard_min_size", "60", 0 },
5161 { "bluestore_extent_map_shard_max_size", "300", 0 },
5162 { "bluestore_extent_map_shard_target_size", "150", 0 },
5163 { "bluestore_default_buffered_read", "true", 0 },
5164 { "bluestore_default_buffered_write", "true", 0 },
5167 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5170 TEST_P(StoreTestSpecificAUSize
, ZipperPatternSharded
) {
5171 if(string(GetParam()) != "bluestore")
5173 StartDeferred(4096);
5177 ghobject_t
a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
5178 auto ch
= store
->create_new_collection(cid
);
5180 ObjectStore::Transaction t
;
5181 t
.create_collection(cid
, 0);
5182 cerr
<< "Creating collection " << cid
<< std::endl
;
5183 r
= queue_transaction(store
, ch
, std::move(t
));
5191 for (int i
=0; i
<1000; ++i
) {
5192 ObjectStore::Transaction t
;
5193 t
.write(cid
, a
, i
*2*len
, len
, bl
, 0);
5194 r
= queue_transaction(store
, ch
, std::move(t
));
5197 for (int i
=0; i
<1000; ++i
) {
5198 ObjectStore::Transaction t
;
5199 t
.write(cid
, a
, i
*2*len
+ 1, len
, bl
, 0);
5200 r
= queue_transaction(store
, ch
, std::move(t
));
5204 ObjectStore::Transaction t
;
5206 t
.remove_collection(cid
);
5207 cerr
<< "Cleaning" << std::endl
;
5208 r
= queue_transaction(store
, ch
, std::move(t
));
5213 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumAlgorithm
) {
5214 if (string(GetParam()) != "bluestore")
5217 const char *m
[][10] = {
5218 { "bluestore_min_alloc_size", "65536", 0 }, // must be the first!
5219 { "max_write", "65536", 0 },
5220 { "max_size", "1048576", 0 },
5221 { "alignment", "16", 0 },
5222 { "bluestore_csum_type", "crc32c", "crc32c_16", "crc32c_8", "xxhash32",
5223 "xxhash64", "none", 0 },
5224 { "bluestore_default_buffered_write", "false", 0 },
5227 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5230 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCsumVsCompression
) {
5231 if (string(GetParam()) != "bluestore")
5234 const char *m
[][10] = {
5235 { "bluestore_min_alloc_size", "4096", "16384", 0 }, //to be the first!
5236 { "max_write", "131072", 0 },
5237 { "max_size", "262144", 0 },
5238 { "alignment", "512", 0 },
5239 { "bluestore_compression_mode", "force", 0},
5240 { "bluestore_compression_algorithm", "snappy", "zlib", 0 },
5241 { "bluestore_csum_type", "crc32c", 0 },
5242 { "bluestore_default_buffered_read", "true", "false", 0 },
5243 { "bluestore_default_buffered_write", "true", "false", 0 },
5244 { "bluestore_sync_submit_transaction", "false", 0 },
5247 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5250 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompression
) {
5251 if (string(GetParam()) != "bluestore")
5254 const char *m
[][10] = {
5255 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5256 { "max_write", "1048576", 0 },
5257 { "max_size", "4194304", 0 },
5258 { "alignment", "65536", 0 },
5259 { "bluestore_compression_mode", "force", "aggressive", "passive", "none", 0},
5260 { "bluestore_default_buffered_write", "false", 0 },
5261 { "bluestore_sync_submit_transaction", "true", 0 },
5264 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5267 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixCompressionAlgorithm
) {
5268 if (string(GetParam()) != "bluestore")
5271 const char *m
[][10] = {
5272 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5273 { "max_write", "1048576", 0 },
5274 { "max_size", "4194304", 0 },
5275 { "alignment", "65536", 0 },
5276 { "bluestore_compression_algorithm", "zlib", "snappy", 0 },
5277 { "bluestore_compression_mode", "force", 0 },
5278 { "bluestore_default_buffered_write", "false", 0 },
5281 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5284 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixNoCsum
) {
5285 if (string(GetParam()) != "bluestore")
5288 const char *m
[][10] = {
5289 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5290 { "max_write", "65536", 0 },
5291 { "max_size", "1048576", 0 },
5292 { "alignment", "512", 0 },
5293 { "bluestore_max_blob_size", "262144", 0 },
5294 { "bluestore_compression_mode", "force", "none", 0},
5295 { "bluestore_csum_type", "none", 0},
5296 { "bluestore_default_buffered_read", "true", "false", 0 },
5297 { "bluestore_default_buffered_write", "true", 0 },
5298 { "bluestore_sync_submit_transaction", "true", "false", 0 },
5301 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5304 TEST_P(StoreTestSpecificAUSize
, SyntheticMatrixPreferDeferred
) {
5305 if (string(GetParam()) != "bluestore")
5308 const char *m
[][10] = {
5309 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5310 { "max_write", "65536", 0 },
5311 { "max_size", "1048576", 0 },
5312 { "alignment", "512", 0 },
5313 { "bluestore_max_blob_size", "262144", 0 },
5314 { "bluestore_compression_mode", "force", "none", 0},
5315 { "bluestore_prefer_deferred_size", "32768", "0", 0},
5318 do_matrix(m
, std::bind(&StoreTest::doSyntheticTest
, this, _1
, _2
, _3
, _4
));
5320 #endif // WITH_BLUESTORE
5322 TEST_P(StoreTest
, AttrSynthetic
) {
5323 MixedGenerator
gen(447);
5324 gen_type
rng(time(NULL
));
5325 coll_t
cid(spg_t(pg_t(0,447),shard_id_t::NO_SHARD
));
5327 SyntheticWorkloadState
test_obj(store
.get(), &gen
, &rng
, cid
, 40*1024, 4*1024, 0);
5329 for (int i
= 0; i
< 500; ++i
) {
5330 if (!(i
% 10)) cerr
<< "seeding object " << i
<< std::endl
;
5333 for (int i
= 0; i
< 1000; ++i
) {
5335 cerr
<< "Op " << i
<< std::endl
;
5336 test_obj
.print_internal_state();
5338 boost::uniform_int
<> true_false(0, 99);
5339 int val
= true_false(rng
);
5342 } else if (val
> 93) {
5344 } else if (val
> 75) {
5346 } else if (val
> 47) {
5347 test_obj
.setattrs();
5348 } else if (val
> 45) {
5350 } else if (val
> 37) {
5352 } else if (val
> 30) {
5353 test_obj
.getattrs();
5358 test_obj
.wait_for_done();
5359 test_obj
.shutdown();
5362 TEST_P(StoreTest
, HashCollisionTest
) {
5363 int64_t poolid
= 11;
5364 coll_t
cid(spg_t(pg_t(0,poolid
),shard_id_t::NO_SHARD
));
5366 auto ch
= store
->create_new_collection(cid
);
5368 ObjectStore::Transaction t
;
5369 t
.create_collection(cid
, 0);
5370 r
= queue_transaction(store
, ch
, std::move(t
));
5374 for (int i
= 0; i
< 100; ++i
) base
.append("aaaaa");
5375 set
<ghobject_t
> created
;
5376 for (int n
= 0; n
< 10; ++n
) {
5378 sprintf(nbuf
, "n%d", n
);
5379 for (int i
= 0; i
< 1000; ++i
) {
5381 sprintf(buf
, "%d", i
);
5383 cerr
<< "Object n" << n
<< " "<< i
<< std::endl
;
5385 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, 0, poolid
, string(nbuf
)));
5387 ObjectStore::Transaction t
;
5389 r
= queue_transaction(store
, ch
, std::move(t
));
5392 created
.insert(hoid
);
5395 vector
<ghobject_t
> objects
;
5396 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5399 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
5400 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
5401 ASSERT_TRUE(listed
.size() == created
.size());
5404 ghobject_t current
, next
;
5406 r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 60, &objects
,
5409 ASSERT_TRUE(sorted(objects
));
5410 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5413 if (listed
.count(*i
))
5414 cerr
<< *i
<< " repeated" << std::endl
;
5417 if (objects
.size() < 50) {
5418 ASSERT_TRUE(next
.is_max());
5424 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
5425 ASSERT_TRUE(listed
.size() == created
.size());
5426 for (set
<ghobject_t
>::iterator i
= listed
.begin();
5429 ASSERT_TRUE(created
.count(*i
));
5432 for (set
<ghobject_t
>::iterator i
= created
.begin();
5435 ObjectStore::Transaction t
;
5437 r
= queue_transaction(store
, ch
, std::move(t
));
5440 ObjectStore::Transaction t
;
5441 t
.remove_collection(cid
);
5442 r
= queue_transaction(store
, ch
, std::move(t
));
5446 TEST_P(StoreTest
, HashCollisionSorting
) {
5447 bool disable_legacy
= (string(GetParam()) == "bluestore");
5449 char buf121664318_1
[] = {18, -119, -121, -111, 0};
5450 char buf121664318_2
[] = {19, 127, -121, 32, 0};
5451 char buf121664318_3
[] = {19, -118, 15, 19, 0};
5452 char buf121664318_4
[] = {28, 27, -116, -113, 0};
5453 char buf121664318_5
[] = {28, 27, -115, -124, 0};
5455 char buf121666222_1
[] = {18, -119, -120, -111, 0};
5456 char buf121666222_2
[] = {19, 127, -120, 32, 0};
5457 char buf121666222_3
[] = {19, -118, 15, 30, 0};
5458 char buf121666222_4
[] = {29, 17, -126, -113, 0};
5459 char buf121666222_5
[] = {29, 17, -125, -124, 0};
5461 std::map
<uint32_t, std::vector
<std::string
>> object_names
= {
5462 {121664318, {{buf121664318_1
},
5467 {121666222, {{buf121666222_1
},
5471 {buf121666222_5
}}}};
5473 int64_t poolid
= 111;
5474 coll_t cid
= coll_t(spg_t(pg_t(0, poolid
), shard_id_t::NO_SHARD
));
5475 auto ch
= store
->create_new_collection(cid
);
5477 ObjectStore::Transaction t
;
5478 t
.create_collection(cid
, 0);
5479 int r
= queue_transaction(store
, ch
, std::move(t
));
5483 std::set
<ghobject_t
> created
;
5484 for (auto &[hash
, names
] : object_names
) {
5485 for (auto &name
: names
) {
5486 ghobject_t
hoid(hobject_t(sobject_t(name
, CEPH_NOSNAP
),
5491 ASSERT_EQ(hash
, hoid
.hobj
.get_hash());
5492 ObjectStore::Transaction t
;
5494 int r
= queue_transaction(store
, ch
, std::move(t
));
5496 created
.insert(hoid
);
5500 vector
<ghobject_t
> objects
;
5501 int r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(),
5502 INT_MAX
, &objects
, 0, disable_legacy
);
5504 ASSERT_EQ(created
.size(), objects
.size());
5505 auto it
= objects
.begin();
5506 for (auto &hoid
: created
) {
5507 ASSERT_EQ(hoid
, *it
);
5511 for (auto i
= created
.begin(); i
!= created
.end(); i
++) {
5513 for (j
++; j
!= created
.end(); j
++) {
5514 std::set
<ghobject_t
> created_sub(i
, j
);
5517 r
= collection_list(store
, ch
, *i
, ghobject_t::get_max(),
5518 created_sub
.size(), &objects
, &next
, disable_legacy
);
5520 ASSERT_EQ(created_sub
.size(), objects
.size());
5521 it
= objects
.begin();
5522 for (auto &hoid
: created_sub
) {
5523 ASSERT_EQ(hoid
, *it
);
5526 if (j
== created
.end()) {
5527 ASSERT_TRUE(next
.is_max());
5529 ASSERT_EQ(*j
, next
);
5534 for (auto i
= created
.begin(); i
!= created
.end(); i
++) {
5536 for (j
++; j
!= created
.end(); j
++) {
5537 std::set
<ghobject_t
> created_sub(i
, j
);
5540 r
= collection_list(store
, ch
, *i
, *j
, INT_MAX
, &objects
, &next
,
5543 ASSERT_EQ(created_sub
.size(), objects
.size());
5544 it
= objects
.begin();
5545 for (auto &hoid
: created_sub
) {
5546 ASSERT_EQ(hoid
, *it
);
5549 if (j
== created
.end()) {
5550 ASSERT_TRUE(next
.is_max());
5552 ASSERT_EQ(*j
, next
);
5558 TEST_P(StoreTest
, ScrubTest
) {
5559 int64_t poolid
= 111;
5560 coll_t
cid(spg_t(pg_t(0, poolid
),shard_id_t(1)));
5562 auto ch
= store
->create_new_collection(cid
);
5564 ObjectStore::Transaction t
;
5565 t
.create_collection(cid
, 0);
5566 r
= queue_transaction(store
, ch
, std::move(t
));
5569 string base
= "aaaaa";
5570 set
<ghobject_t
> created
;
5571 for (int i
= 0; i
< 1000; ++i
) {
5573 sprintf(buf
, "%d", i
);
5575 cerr
<< "Object " << i
<< std::endl
;
5577 ghobject_t
hoid(hobject_t(string(buf
) + base
, string(), CEPH_NOSNAP
, i
,
5579 ghobject_t::NO_GEN
, shard_id_t(1));
5581 ObjectStore::Transaction t
;
5583 r
= queue_transaction(store
, ch
, std::move(t
));
5586 created
.insert(hoid
);
5589 // Add same hobject_t but different generation
5591 ghobject_t
hoid1(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""),
5592 ghobject_t::NO_GEN
, shard_id_t(1));
5593 ghobject_t
hoid2(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)1, shard_id_t(1));
5594 ghobject_t
hoid3(hobject_t("same-object", string(), CEPH_NOSNAP
, 0, poolid
, ""), (gen_t
)2, shard_id_t(1));
5595 ObjectStore::Transaction t
;
5596 t
.touch(cid
, hoid1
);
5597 t
.touch(cid
, hoid2
);
5598 t
.touch(cid
, hoid3
);
5599 r
= queue_transaction(store
, ch
, std::move(t
));
5600 created
.insert(hoid1
);
5601 created
.insert(hoid2
);
5602 created
.insert(hoid3
);
5606 vector
<ghobject_t
> objects
;
5607 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
5610 set
<ghobject_t
> listed(objects
.begin(), objects
.end());
5611 cerr
<< "listed.size() is " << listed
.size() << " and created.size() is " << created
.size() << std::endl
;
5612 ASSERT_TRUE(listed
.size() == created
.size());
5615 ghobject_t current
, next
;
5617 r
= collection_list(store
, ch
, current
, ghobject_t::get_max(), 60, &objects
,
5620 ASSERT_TRUE(sorted(objects
));
5621 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
5622 i
!= objects
.end(); ++i
) {
5623 if (listed
.count(*i
))
5624 cerr
<< *i
<< " repeated" << std::endl
;
5627 if (objects
.size() < 50) {
5628 ASSERT_TRUE(next
.is_max());
5632 current
= next
.get_boundary();
5634 cerr
<< "listed.size() is " << listed
.size() << std::endl
;
5635 ASSERT_TRUE(listed
.size() == created
.size());
5636 for (set
<ghobject_t
>::iterator i
= listed
.begin();
5639 ASSERT_TRUE(created
.count(*i
));
5642 for (set
<ghobject_t
>::iterator i
= created
.begin();
5645 ObjectStore::Transaction t
;
5647 r
= queue_transaction(store
, ch
, std::move(t
));
5650 ObjectStore::Transaction t
;
5651 t
.remove_collection(cid
);
5652 r
= queue_transaction(store
, ch
, std::move(t
));
5657 TEST_P(StoreTest
, OMapTest
) {
5659 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5660 auto ch
= store
->create_new_collection(cid
);
5663 ObjectStore::Transaction t
;
5664 t
.create_collection(cid
, 0);
5665 r
= queue_transaction(store
, ch
, std::move(t
));
5669 map
<string
, bufferlist
> attrs
;
5671 ObjectStore::Transaction t
;
5673 t
.omap_clear(cid
, hoid
);
5674 map
<string
, bufferlist
> start_set
;
5675 t
.omap_setkeys(cid
, hoid
, start_set
);
5676 r
= queue_transaction(store
, ch
, std::move(t
));
5680 for (int i
= 0; i
< 100; i
++) {
5682 std::cout
<< "On iteration " << i
<< std::endl
;
5684 ObjectStore::Transaction t
;
5686 map
<string
, bufferlist
> cur_attrs
;
5687 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5689 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5692 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5694 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5695 if (cur_attrs
.count(j
->first
) > 0) {
5696 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5699 ASSERT_EQ(correct
, true);
5701 ASSERT_EQ(attrs
.size(), cur_attrs
.size());
5704 snprintf(buf
, sizeof(buf
), "%d", i
);
5706 bufferptr
bp(buf
, strlen(buf
) + 1);
5708 map
<string
, bufferlist
> to_add
;
5709 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5710 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5711 t
.omap_setkeys(cid
, hoid
, to_add
);
5712 r
= queue_transaction(store
, ch
, std::move(t
));
5717 while (attrs
.size()) {
5719 std::cout
<< "removal: On iteration " << i
<< std::endl
;
5721 ObjectStore::Transaction t
;
5723 map
<string
, bufferlist
> cur_attrs
;
5724 r
= store
->omap_get(ch
, hoid
, &bl
, &cur_attrs
);
5726 for (map
<string
, bufferlist
>::iterator j
= attrs
.begin();
5729 bool correct
= cur_attrs
.count(j
->first
) && string(cur_attrs
[j
->first
].c_str()) == string(j
->second
.c_str());
5731 std::cout
<< j
->first
<< " is present in cur_attrs " << cur_attrs
.count(j
->first
) << " times " << std::endl
;
5732 if (cur_attrs
.count(j
->first
) > 0) {
5733 std::cout
<< j
->second
.c_str() << " : " << cur_attrs
[j
->first
].c_str() << std::endl
;
5736 ASSERT_EQ(correct
, true);
5739 string to_remove
= attrs
.begin()->first
;
5740 t
.omap_rmkey(cid
, hoid
, to_remove
);
5741 r
= queue_transaction(store
, ch
, std::move(t
));
5744 attrs
.erase(to_remove
);
5751 bl1
.append("omap_header");
5752 ObjectStore::Transaction t
;
5753 t
.omap_setheader(cid
, hoid
, bl1
);
5754 r
= queue_transaction(store
, ch
, std::move(t
));
5756 t
= ObjectStore::Transaction();
5759 bl2
.append("value");
5760 map
<string
, bufferlist
> to_add
;
5761 to_add
.insert(pair
<string
, bufferlist
>("key", bl2
));
5762 t
.omap_setkeys(cid
, hoid
, to_add
);
5763 r
= queue_transaction(store
, ch
, std::move(t
));
5767 map
<string
, bufferlist
> cur_attrs
;
5768 r
= store
->omap_get(ch
, hoid
, &bl3
, &cur_attrs
);
5770 ASSERT_EQ(cur_attrs
.size(), size_t(1));
5771 ASSERT_TRUE(bl_eq(bl1
, bl3
));
5774 r
= store
->omap_get_keys(ch
, hoid
, &keys
);
5776 ASSERT_EQ(keys
.size(), size_t(1));
5779 // test omap_clear, omap_rmkey_range
5782 map
<string
,bufferlist
> to_set
;
5783 for (int n
=0; n
<10; ++n
) {
5784 to_set
[stringify(n
)].append("foo");
5788 ObjectStore::Transaction t
;
5789 t
.remove(cid
, hoid
);
5791 t
.omap_setheader(cid
, hoid
, h
);
5792 t
.omap_setkeys(cid
, hoid
, to_set
);
5793 r
= queue_transaction(store
, ch
, std::move(t
));
5797 ObjectStore::Transaction t
;
5798 t
.omap_rmkeyrange(cid
, hoid
, "3", "7");
5799 r
= queue_transaction(store
, ch
, std::move(t
));
5804 map
<string
,bufferlist
> m
;
5805 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5806 ASSERT_EQ(6u, hdr
.length());
5807 ASSERT_TRUE(m
.count("2"));
5808 ASSERT_TRUE(!m
.count("3"));
5809 ASSERT_TRUE(!m
.count("6"));
5810 ASSERT_TRUE(m
.count("7"));
5811 ASSERT_TRUE(m
.count("8"));
5812 //cout << m << std::endl;
5813 ASSERT_EQ(6u, m
.size());
5816 ObjectStore::Transaction t
;
5817 t
.omap_clear(cid
, hoid
);
5818 r
= queue_transaction(store
, ch
, std::move(t
));
5823 map
<string
,bufferlist
> m
;
5824 store
->omap_get(ch
, hoid
, &hdr
, &m
);
5825 ASSERT_EQ(0u, hdr
.length());
5826 ASSERT_EQ(0u, m
.size());
5830 ObjectStore::Transaction t
;
5831 t
.remove(cid
, hoid
);
5832 t
.remove_collection(cid
);
5833 r
= queue_transaction(store
, ch
, std::move(t
));
5837 TEST_P(StoreTest
, OMapIterator
) {
5839 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5841 auto ch
= store
->create_new_collection(cid
);
5844 ObjectStore::Transaction t
;
5845 t
.create_collection(cid
, 0);
5846 r
= queue_transaction(store
, ch
, std::move(t
));
5850 map
<string
, bufferlist
> attrs
;
5852 ObjectStore::Transaction t
;
5854 t
.omap_clear(cid
, hoid
);
5855 map
<string
, bufferlist
> start_set
;
5856 t
.omap_setkeys(cid
, hoid
, start_set
);
5857 r
= queue_transaction(store
, ch
, std::move(t
));
5860 ObjectMap::ObjectMapIterator iter
;
5863 for (int i
= 0; i
< 100; i
++) {
5865 std::cout
<< "On iteration " << i
<< std::endl
;
5869 // FileStore may deadlock two active iterators over the same data
5870 iter
= ObjectMap::ObjectMapIterator();
5872 iter
= store
->get_omap_iterator(ch
, hoid
);
5873 for (iter
->seek_to_first(), count
=0; iter
->valid(); iter
->next(), count
++) {
5874 string key
= iter
->key();
5875 bufferlist value
= iter
->value();
5876 correct
= attrs
.count(key
) && (string(value
.c_str()) == string(attrs
[key
].c_str()));
5878 if (attrs
.count(key
) > 0) {
5879 std::cout
<< "key " << key
<< "in omap , " << value
.c_str() << " : " << attrs
[key
].c_str() << std::endl
;
5882 std::cout
<< "key " << key
<< "should not exists in omap" << std::endl
;
5884 ASSERT_EQ(correct
, true);
5886 ASSERT_EQ((int)attrs
.size(), count
);
5888 // FileStore may deadlock an active iterator vs queue_transaction
5889 iter
= ObjectMap::ObjectMapIterator();
5892 snprintf(buf
, sizeof(buf
), "%d", i
);
5894 bufferptr
bp(buf
, strlen(buf
) + 1);
5896 map
<string
, bufferlist
> to_add
;
5897 to_add
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5898 attrs
.insert(pair
<string
, bufferlist
>("key-" + string(buf
), bl
));
5899 ObjectStore::Transaction t
;
5900 t
.omap_setkeys(cid
, hoid
, to_add
);
5901 r
= queue_transaction(store
, ch
, std::move(t
));
5905 iter
= store
->get_omap_iterator(ch
, hoid
);
5907 string bound_key
= "key-5";
5908 iter
->lower_bound(bound_key
);
5909 correct
= bound_key
<= iter
->key();
5911 std::cout
<< "lower bound, bound key is " << bound_key
<< " < iter key is " << iter
->key() << std::endl
;
5913 ASSERT_EQ(correct
, true);
5915 iter
->upper_bound(bound_key
);
5916 correct
= iter
->key() > bound_key
;
5918 std::cout
<< "upper bound, bound key is " << bound_key
<< " >= iter key is " << iter
->key() << std::endl
;
5920 ASSERT_EQ(correct
, true);
5922 // FileStore may deadlock an active iterator vs queue_transaction
5923 iter
= ObjectMap::ObjectMapIterator();
5925 ObjectStore::Transaction t
;
5926 t
.remove(cid
, hoid
);
5927 t
.remove_collection(cid
);
5928 r
= queue_transaction(store
, ch
, std::move(t
));
5933 TEST_P(StoreTest
, XattrTest
) {
5935 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, 0, ""));
5937 for (unsigned i
= 0; i
< 10000; ++i
) {
5941 for (unsigned i
= 0; i
< 10; ++i
) {
5945 auto ch
= store
->create_new_collection(cid
);
5947 ObjectStore::Transaction t
;
5948 t
.create_collection(cid
, 0);
5950 r
= queue_transaction(store
, ch
, std::move(t
));
5954 map
<string
, bufferlist
> attrs
;
5956 ObjectStore::Transaction t
;
5957 t
.setattr(cid
, hoid
, "attr1", small
);
5958 attrs
["attr1"] = small
;
5959 t
.setattr(cid
, hoid
, "attr2", big
);
5960 attrs
["attr2"] = big
;
5961 t
.setattr(cid
, hoid
, "attr3", small
);
5962 attrs
["attr3"] = small
;
5963 t
.setattr(cid
, hoid
, "attr1", small
);
5964 attrs
["attr1"] = small
;
5965 t
.setattr(cid
, hoid
, "attr4", big
);
5966 attrs
["attr4"] = big
;
5967 t
.setattr(cid
, hoid
, "attr3", big
);
5968 attrs
["attr3"] = big
;
5969 r
= queue_transaction(store
, ch
, std::move(t
));
5973 map
<string
, bufferptr
, less
<>> aset
;
5974 store
->getattrs(ch
, hoid
, aset
);
5975 ASSERT_EQ(aset
.size(), attrs
.size());
5976 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
5980 bl
.push_back(i
->second
);
5981 ASSERT_TRUE(attrs
[i
->first
] == bl
);
5985 ObjectStore::Transaction t
;
5986 t
.rmattr(cid
, hoid
, "attr2");
5987 attrs
.erase("attr2");
5988 r
= queue_transaction(store
, ch
, std::move(t
));
5993 store
->getattrs(ch
, hoid
, aset
);
5994 ASSERT_EQ(aset
.size(), attrs
.size());
5995 for (map
<string
, bufferptr
>::iterator i
= aset
.begin();
5999 bl
.push_back(i
->second
);
6000 ASSERT_TRUE(attrs
[i
->first
] == bl
);
6004 r
= store
->getattr(ch
, hoid
, "attr2", bp
);
6005 ASSERT_EQ(r
, -ENODATA
);
6007 r
= store
->getattr(ch
, hoid
, "attr3", bp
);
6011 ASSERT_TRUE(bl2
== attrs
["attr3"]);
6013 ObjectStore::Transaction t
;
6014 t
.remove(cid
, hoid
);
6015 t
.remove_collection(cid
);
6016 r
= queue_transaction(store
, ch
, std::move(t
));
6022 unsigned num_objects
,
6023 unsigned common_suffix_size
,
6026 coll_t
cid(spg_t(pg_t(0,52),shard_id_t::NO_SHARD
));
6027 coll_t
tid(spg_t(pg_t(1<<common_suffix_size
,52),shard_id_t::NO_SHARD
));
6028 auto ch
= store
->create_new_collection(cid
);
6029 auto tch
= store
->create_new_collection(tid
);
6032 ObjectStore::Transaction t
;
6033 t
.create_collection(cid
, common_suffix_size
);
6034 r
= queue_transaction(store
, ch
, std::move(t
));
6038 small
.append("small");
6040 ObjectStore::Transaction t
;
6041 for (uint32_t i
= 0; i
< (2 - (int)clones
)*num_objects
; ++i
) {
6042 stringstream objname
;
6043 objname
<< "obj" << i
;
6044 ghobject_t
a(hobject_t(
6048 i
<<common_suffix_size
,
6050 t
.write(cid
, a
, 0, small
.length(), small
,
6051 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
6053 objname
<< "-clone";
6054 ghobject_t
b(hobject_t(
6058 i
<<common_suffix_size
,
6063 r
= queue_transaction(store
, ch
, std::move(t
));
6065 t
= ObjectStore::Transaction();
6068 r
= queue_transaction(store
, ch
, std::move(t
));
6072 ObjectStore::Transaction t
;
6073 t
.create_collection(tid
, common_suffix_size
+ 1);
6074 t
.split_collection(cid
, common_suffix_size
+1, 1<<common_suffix_size
, tid
);
6075 r
= queue_transaction(store
, ch
, std::move(t
));
6081 vector
<ghobject_t
> objects
;
6082 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6085 ASSERT_EQ(objects
.size(), num_objects
);
6086 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
6089 ASSERT_EQ(!!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
6093 r
= collection_list(store
, tch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6096 ASSERT_EQ(objects
.size(), num_objects
);
6097 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
6100 ASSERT_EQ(!(i
->hobj
.get_hash() & (1<<common_suffix_size
)), 0u);
6103 // merge them again!
6105 ObjectStore::Transaction t
;
6106 t
.merge_collection(tid
, cid
, common_suffix_size
);
6107 r
= queue_transaction(store
, ch
, std::move(t
));
6111 // check and clean up
6112 ObjectStore::Transaction t
;
6114 vector
<ghobject_t
> objects
;
6115 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6118 ASSERT_EQ(objects
.size(), num_objects
* 2); // both halves
6120 for (vector
<ghobject_t
>::iterator i
= objects
.begin();
6126 r
= queue_transaction(store
, ch
, std::move(t
));
6128 t
= ObjectStore::Transaction();
6132 t
.remove_collection(cid
);
6133 r
= queue_transaction(store
, ch
, std::move(t
));
6137 ASSERT_TRUE(!store
->collection_exists(tid
));
6140 TEST_P(StoreTest
, ColSplitTest0
) {
6141 colsplittest(store
.get(), 10, 5, false);
6143 TEST_P(StoreTest
, ColSplitTest1
) {
6144 colsplittest(store
.get(), 10000, 11, false);
6146 TEST_P(StoreTest
, ColSplitTest1Clones
) {
6147 colsplittest(store
.get(), 10000, 11, true);
6149 TEST_P(StoreTest
, ColSplitTest2
) {
6150 colsplittest(store
.get(), 100, 7, false);
6152 TEST_P(StoreTest
, ColSplitTest2Clones
) {
6153 colsplittest(store
.get(), 100, 7, true);
6157 TEST_P(StoreTest
, ColSplitTest3
) {
6158 colsplittest(store
.get(), 100000, 25);
6162 void test_merge_skewed(ObjectStore
*store
,
6163 unsigned base
, unsigned bits
,
6164 unsigned anum
, unsigned bnum
)
6166 cout
<< __func__
<< " 0x" << std::hex
<< base
<< std::dec
6168 << " anum " << anum
<< " bnum " << bnum
<< std::endl
;
6170 make merge source pgs have radically different # of objects in them,
6171 which should trigger different splitting in filestore, and verify that
6172 post-merge all objects are accessible.
6175 coll_t
a(spg_t(pg_t(base
, 0), shard_id_t::NO_SHARD
));
6176 coll_t
b(spg_t(pg_t(base
| (1<<bits
), 0), shard_id_t::NO_SHARD
));
6178 auto cha
= store
->create_new_collection(a
);
6179 auto chb
= store
->create_new_collection(b
);
6181 ObjectStore::Transaction t
;
6182 t
.create_collection(a
, bits
+ 1);
6183 r
= queue_transaction(store
, cha
, std::move(t
));
6187 ObjectStore::Transaction t
;
6188 t
.create_collection(b
, bits
+ 1);
6189 r
= queue_transaction(store
, chb
, std::move(t
));
6194 small
.append("small");
6195 string suffix
= "ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooaaaaaaaaaa";
6196 set
<ghobject_t
> aobjects
, bobjects
;
6199 ObjectStore::Transaction t
;
6200 for (unsigned i
= 0; i
< 1000; ++i
) {
6201 string objname
= "a" + stringify(i
) + suffix
;
6202 ghobject_t
o(hobject_t(
6209 t
.write(a
, o
, 0, small
.length(), small
, 0);
6211 r
= queue_transaction(store
, cha
, std::move(t
));
6213 t
= ObjectStore::Transaction();
6216 r
= queue_transaction(store
, cha
, std::move(t
));
6221 ObjectStore::Transaction t
;
6222 for (unsigned i
= 0; i
< 10; ++i
) {
6223 string objname
= "b" + stringify(i
) + suffix
;
6224 ghobject_t
o(hobject_t(
6228 (i
<<(base
+1)) | base
| (1<<bits
),
6231 t
.write(b
, o
, 0, small
.length(), small
, 0);
6233 r
= queue_transaction(store
, chb
, std::move(t
));
6235 t
= ObjectStore::Transaction();
6238 r
= queue_transaction(store
, chb
, std::move(t
));
6244 ObjectStore::Transaction t
;
6245 t
.merge_collection(b
, a
, bits
);
6246 r
= queue_transaction(store
, cha
, std::move(t
));
6252 vector
<ghobject_t
> got
;
6253 collection_list(store
, cha
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6255 set
<ghobject_t
> gotset
;
6256 for (auto& o
: got
) {
6257 ASSERT_TRUE(aobjects
.count(o
) || bobjects
.count(o
));
6260 // check both listing and stat-ability (different code paths!)
6262 for (auto& o
: aobjects
) {
6263 ASSERT_TRUE(gotset
.count(o
));
6264 int r
= store
->stat(cha
, o
, &st
, false);
6267 for (auto& o
: bobjects
) {
6268 ASSERT_TRUE(gotset
.count(o
));
6269 int r
= store
->stat(cha
, o
, &st
, false);
6276 ObjectStore::Transaction t
;
6277 for (auto &o
: aobjects
) {
6280 r
= queue_transaction(store
, cha
, std::move(t
));
6284 ObjectStore::Transaction t
;
6285 for (auto &o
: bobjects
) {
6288 t
.remove_collection(a
);
6289 r
= queue_transaction(store
, cha
, std::move(t
));
6294 TEST_P(StoreTest
, MergeSkewed
) {
6295 if (string(GetParam()) != "filestore")
6298 // this is sufficient to exercise merges with different hashing levels
6299 test_merge_skewed(store
.get(), 0xf, 4, 10, 10000);
6300 test_merge_skewed(store
.get(), 0xf, 4, 10000, 10);
6303 // this covers a zillion variations that all boil down to the same thing
6304 for (unsigned base = 3; base < 0x1000; base *= 5) {
6307 for (bits = 0; t; t >>= 1) {
6310 for (unsigned b = bits; b < bits + 10; b += 3) {
6311 for (auto anum : { 10, 1000, 10000 }) {
6312 for (auto bnum : { 10, 1000, 10000 }) {
6316 test_merge_skewed(store.get(), base, b, anum, bnum);
6326 * This test tests adding two different groups
6327 * of objects, each with 1 common prefix and 1
6328 * different prefix. We then remove half
6329 * in order to verify that the merging correctly
6330 * stops at the common prefix subdir. See bug
6332 TEST_P(StoreTest
, TwoHash
) {
6335 auto ch
= store
->create_new_collection(cid
);
6337 ObjectStore::Transaction t
;
6338 t
.create_collection(cid
, 0);
6339 r
= queue_transaction(store
, ch
, std::move(t
));
6342 std::cout
<< "Making objects" << std::endl
;
6343 for (int i
= 0; i
< 360; ++i
) {
6344 ObjectStore::Transaction t
;
6348 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6351 o
.hobj
.set_hash((i
<< 16) | 0xB1);
6353 r
= queue_transaction(store
, ch
, std::move(t
));
6356 std::cout
<< "Removing half" << std::endl
;
6357 for (int i
= 1; i
< 8; ++i
) {
6358 ObjectStore::Transaction t
;
6361 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6363 r
= queue_transaction(store
, ch
, std::move(t
));
6366 std::cout
<< "Checking" << std::endl
;
6367 for (int i
= 1; i
< 8; ++i
) {
6368 ObjectStore::Transaction t
;
6370 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6372 bool exists
= store
->exists(ch
, o
);
6373 ASSERT_EQ(exists
, false);
6377 o
.hobj
.set_hash(0xA1);
6379 bool exists
= store
->exists(ch
, o
);
6380 ASSERT_EQ(exists
, true);
6382 std::cout
<< "Cleanup" << std::endl
;
6383 for (int i
= 0; i
< 360; ++i
) {
6384 ObjectStore::Transaction t
;
6386 o
.hobj
.set_hash((i
<< 16) | 0xA1);
6389 o
.hobj
.set_hash((i
<< 16) | 0xB1);
6391 r
= queue_transaction(store
, ch
, std::move(t
));
6394 ObjectStore::Transaction t
;
6395 t
.remove_collection(cid
);
6396 r
= queue_transaction(store
, ch
, std::move(t
));
6400 TEST_P(StoreTest
, Rename
) {
6401 coll_t
cid(spg_t(pg_t(0, 2122),shard_id_t::NO_SHARD
));
6402 ghobject_t
srcoid(hobject_t("src_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6403 ghobject_t
dstoid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6407 auto ch
= store
->create_new_collection(cid
);
6410 ObjectStore::Transaction t
;
6411 t
.create_collection(cid
, 0);
6412 t
.write(cid
, srcoid
, 0, a
.length(), a
);
6413 r
= queue_transaction(store
, ch
, std::move(t
));
6416 ASSERT_TRUE(store
->exists(ch
, srcoid
));
6418 ObjectStore::Transaction t
;
6419 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
6420 t
.write(cid
, srcoid
, 0, b
.length(), b
);
6421 t
.setattr(cid
, srcoid
, "attr", b
);
6422 r
= queue_transaction(store
, ch
, std::move(t
));
6425 ASSERT_TRUE(store
->exists(ch
, srcoid
));
6426 ASSERT_TRUE(store
->exists(ch
, dstoid
));
6429 store
->read(ch
, srcoid
, 0, 3, bl
);
6430 ASSERT_TRUE(bl_eq(b
, bl
));
6431 store
->read(ch
, dstoid
, 0, 3, bl
);
6432 ASSERT_TRUE(bl_eq(a
, bl
));
6435 ObjectStore::Transaction t
;
6436 t
.remove(cid
, dstoid
);
6437 t
.collection_move_rename(cid
, srcoid
, cid
, dstoid
);
6438 r
= queue_transaction(store
, ch
, std::move(t
));
6441 ASSERT_TRUE(store
->exists(ch
, dstoid
));
6442 ASSERT_FALSE(store
->exists(ch
, srcoid
));
6445 store
->read(ch
, dstoid
, 0, 3, bl
);
6446 ASSERT_TRUE(bl_eq(b
, bl
));
6449 ObjectStore::Transaction t
;
6450 t
.remove(cid
, dstoid
);
6451 t
.remove_collection(cid
);
6452 r
= queue_transaction(store
, ch
, std::move(t
));
6457 TEST_P(StoreTest
, MoveRename
) {
6458 coll_t
cid(spg_t(pg_t(0, 212),shard_id_t::NO_SHARD
));
6459 ghobject_t
temp_oid(hobject_t("tmp_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6460 ghobject_t
oid(hobject_t("dest_oid", "", CEPH_NOSNAP
, 0, 0, ""));
6461 auto ch
= store
->create_new_collection(cid
);
6464 ObjectStore::Transaction t
;
6465 t
.create_collection(cid
, 0);
6467 r
= queue_transaction(store
, ch
, std::move(t
));
6470 ASSERT_TRUE(store
->exists(ch
, oid
));
6471 bufferlist data
, attr
;
6472 map
<string
, bufferlist
> omap
;
6473 data
.append("data payload");
6474 attr
.append("attr value");
6475 omap
["omap_key"].append("omap value");
6477 ObjectStore::Transaction t
;
6478 t
.touch(cid
, temp_oid
);
6479 t
.write(cid
, temp_oid
, 0, data
.length(), data
);
6480 t
.setattr(cid
, temp_oid
, "attr", attr
);
6481 t
.omap_setkeys(cid
, temp_oid
, omap
);
6482 r
= queue_transaction(store
, ch
, std::move(t
));
6485 ASSERT_TRUE(store
->exists(ch
, temp_oid
));
6487 ObjectStore::Transaction t
;
6489 t
.collection_move_rename(cid
, temp_oid
, cid
, oid
);
6490 r
= queue_transaction(store
, ch
, std::move(t
));
6493 ASSERT_TRUE(store
->exists(ch
, oid
));
6494 ASSERT_FALSE(store
->exists(ch
, temp_oid
));
6497 r
= store
->read(ch
, oid
, 0, 1000, newdata
);
6499 ASSERT_TRUE(bl_eq(data
, newdata
));
6501 r
= store
->getattr(ch
, oid
, "attr", newattr
);
6503 ASSERT_TRUE(bl_eq(attr
, newattr
));
6505 keys
.insert("omap_key");
6506 map
<string
, bufferlist
> newomap
;
6507 r
= store
->omap_get_values(ch
, oid
, keys
, &newomap
);
6509 ASSERT_EQ(1u, newomap
.size());
6510 ASSERT_TRUE(newomap
.count("omap_key"));
6511 ASSERT_TRUE(bl_eq(omap
["omap_key"], newomap
["omap_key"]));
6514 ObjectStore::Transaction t
;
6516 t
.remove_collection(cid
);
6517 r
= queue_transaction(store
, ch
, std::move(t
));
6522 TEST_P(StoreTest
, BigRGWObjectName
) {
6523 coll_t
cid(spg_t(pg_t(0,12),shard_id_t::NO_SHARD
));
6526 "default.4106.50_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
6533 shard_id_t::NO_SHARD
);
6534 ghobject_t
oid2(oid
);
6535 oid2
.generation
= 17;
6536 ghobject_t
oidhead(oid
);
6537 oidhead
.generation
= ghobject_t::NO_GEN
;
6539 auto ch
= store
->create_new_collection(cid
);
6543 ObjectStore::Transaction t
;
6544 t
.create_collection(cid
, 0);
6545 t
.touch(cid
, oidhead
);
6546 t
.collection_move_rename(cid
, oidhead
, cid
, oid
);
6547 t
.touch(cid
, oidhead
);
6548 t
.collection_move_rename(cid
, oidhead
, cid
, oid2
);
6549 r
= queue_transaction(store
, ch
, std::move(t
));
6554 ObjectStore::Transaction t
;
6556 r
= queue_transaction(store
, ch
, std::move(t
));
6561 vector
<ghobject_t
> objects
;
6562 r
= collection_list(store
, ch
, ghobject_t(), ghobject_t::get_max(), INT_MAX
,
6565 ASSERT_EQ(objects
.size(), 1u);
6566 ASSERT_EQ(objects
[0], oid2
);
6569 ASSERT_FALSE(store
->exists(ch
, oid
));
6572 ObjectStore::Transaction t
;
6573 t
.remove(cid
, oid2
);
6574 t
.remove_collection(cid
);
6575 r
= queue_transaction(store
, ch
, std::move(t
));
6581 TEST_P(StoreTest
, SetAllocHint
) {
6583 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, 0, ""));
6584 auto ch
= store
->create_new_collection(cid
);
6587 ObjectStore::Transaction t
;
6588 t
.create_collection(cid
, 0);
6590 r
= queue_transaction(store
, ch
, std::move(t
));
6594 ObjectStore::Transaction t
;
6595 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
6596 r
= queue_transaction(store
, ch
, std::move(t
));
6600 ObjectStore::Transaction t
;
6601 t
.remove(cid
, hoid
);
6602 r
= queue_transaction(store
, ch
, std::move(t
));
6606 ObjectStore::Transaction t
;
6607 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*4, 0);
6608 r
= queue_transaction(store
, ch
, std::move(t
));
6612 ObjectStore::Transaction t
;
6613 t
.remove_collection(cid
);
6614 r
= queue_transaction(store
, ch
, std::move(t
));
6619 TEST_P(StoreTest
, TryMoveRename
) {
6621 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
6622 ghobject_t
hoid2(hobject_t("test_hint2", "", CEPH_NOSNAP
, 0, -1, ""));
6623 auto ch
= store
->create_new_collection(cid
);
6626 ObjectStore::Transaction t
;
6627 t
.create_collection(cid
, 0);
6628 r
= queue_transaction(store
, ch
, std::move(t
));
6632 ObjectStore::Transaction t
;
6633 t
.try_rename(cid
, hoid
, hoid2
);
6634 r
= queue_transaction(store
, ch
, std::move(t
));
6638 ObjectStore::Transaction t
;
6640 r
= queue_transaction(store
, ch
, std::move(t
));
6644 ObjectStore::Transaction t
;
6645 t
.try_rename(cid
, hoid
, hoid2
);
6646 r
= queue_transaction(store
, ch
, std::move(t
));
6650 ASSERT_EQ(store
->stat(ch
, hoid
, &st
), -ENOENT
);
6651 ASSERT_EQ(store
->stat(ch
, hoid2
, &st
), 0);
6654 #if defined(WITH_BLUESTORE)
6655 TEST_P(StoreTest
, BluestoreOnOffCSumTest
) {
6656 if (string(GetParam()) != "bluestore")
6658 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6659 g_conf().apply_changes(nullptr);
6663 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
6665 auto ch
= store
->open_collection(cid
);
6668 auto ch
= store
->create_new_collection(cid
);
6670 ObjectStore::Transaction t
;
6671 t
.create_collection(cid
, 0);
6672 cerr
<< "Creating collection " << cid
<< std::endl
;
6673 r
= queue_transaction(store
, ch
, std::move(t
));
6677 //write with csum enabled followed by read with csum disabled
6678 size_t block_size
= 64*1024;
6679 ObjectStore::Transaction t
;
6680 bufferlist bl
, orig
;
6681 bl
.append(std::string(block_size
, 'a'));
6683 t
.remove(cid
, hoid
);
6684 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6685 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6686 cerr
<< "Remove then create" << std::endl
;
6687 r
= queue_transaction(store
, ch
, std::move(t
));
6690 SetVal(g_conf(), "bluestore_csum_type", "none");
6691 g_conf().apply_changes(nullptr);
6694 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6695 ASSERT_EQ((int)block_size
, r
);
6696 ASSERT_TRUE(bl_eq(orig
, in
));
6700 //write with csum disabled followed by read with csum enabled
6702 size_t block_size
= 64*1024;
6703 ObjectStore::Transaction t
;
6704 bufferlist bl
, orig
;
6705 bl
.append(std::string(block_size
, 'a'));
6707 t
.remove(cid
, hoid
);
6708 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6709 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6710 cerr
<< "Remove then create" << std::endl
;
6711 r
= queue_transaction(store
, ch
, std::move(t
));
6714 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6715 g_conf().apply_changes(nullptr);
6718 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6719 ASSERT_EQ((int)block_size
, r
);
6720 ASSERT_TRUE(bl_eq(orig
, in
));
6723 //'mixed' non-overlapping writes to the same blob
6725 ObjectStore::Transaction t
;
6726 bufferlist bl
, orig
;
6727 size_t block_size
= 8000;
6728 bl
.append(std::string(block_size
, 'a'));
6730 t
.remove(cid
, hoid
);
6731 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6732 cerr
<< "Remove then create" << std::endl
;
6733 r
= queue_transaction(store
, ch
, std::move(t
));
6736 SetVal(g_conf(), "bluestore_csum_type", "none");
6737 g_conf().apply_changes(nullptr);
6739 ObjectStore::Transaction t2
;
6740 t2
.write(cid
, hoid
, block_size
*2, bl
.length(), bl
);
6741 cerr
<< "Append 'unprotected'" << std::endl
;
6742 r
= queue_transaction(store
, ch
, std::move(t2
));
6746 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6747 ASSERT_EQ((int)block_size
, r
);
6748 ASSERT_TRUE(bl_eq(orig
, in
));
6750 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6751 ASSERT_EQ((int)block_size
, r
);
6752 ASSERT_TRUE(bl_eq(orig
, in
));
6754 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6755 g_conf().apply_changes(nullptr);
6757 r
= store
->read(ch
, hoid
, 0, block_size
, in
);
6758 ASSERT_EQ((int)block_size
, r
);
6759 ASSERT_TRUE(bl_eq(orig
, in
));
6761 r
= store
->read(ch
, hoid
, block_size
*2, block_size
, in
);
6762 ASSERT_EQ((int)block_size
, r
);
6763 ASSERT_TRUE(bl_eq(orig
, in
));
6766 //partially blob overwrite under a different csum enablement mode
6768 ObjectStore::Transaction t
;
6769 bufferlist bl
, orig
, orig2
;
6770 size_t block_size0
= 0x10000;
6771 size_t block_size
= 9000;
6772 size_t block_size2
= 5000;
6773 bl
.append(std::string(block_size0
, 'a'));
6774 t
.remove(cid
, hoid
);
6775 t
.set_alloc_hint(cid
, hoid
, 4*1024*1024, 1024*8, 0);
6776 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
6777 cerr
<< "Remove then create" << std::endl
;
6778 r
= queue_transaction(store
, ch
, std::move(t
));
6781 SetVal(g_conf(), "bluestore_csum_type", "none");
6782 g_conf().apply_changes(nullptr);
6784 ObjectStore::Transaction t2
;
6786 bl
.append(std::string(block_size
, 'b'));
6787 t2
.write(cid
, hoid
, 0, bl
.length(), bl
);
6788 t2
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6789 cerr
<< "Overwrite with unprotected data" << std::endl
;
6790 r
= queue_transaction(store
, ch
, std::move(t2
));
6795 orig
.append( std::string(block_size0
- block_size
, 'a'));
6798 r
= store
->read(ch
, hoid
, 0, block_size0
, in
);
6799 ASSERT_EQ((int)block_size0
, r
);
6800 ASSERT_TRUE(bl_eq(orig
, in
));
6802 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6803 ASSERT_EQ((int)block_size
, r
);
6804 ASSERT_TRUE(bl_eq(orig2
, in
));
6806 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6807 g_conf().apply_changes(nullptr);
6809 ObjectStore::Transaction t3
;
6811 bl
.append(std::string(block_size2
, 'c'));
6812 t3
.write(cid
, hoid
, block_size0
, bl
.length(), bl
);
6813 cerr
<< "Overwrite with protected data" << std::endl
;
6814 r
= queue_transaction(store
, ch
, std::move(t3
));
6819 orig
.append( std::string(block_size
- block_size2
, 'b'));
6820 r
= store
->read(ch
, hoid
, block_size0
, block_size
, in
);
6821 ASSERT_EQ((int)block_size
, r
);
6822 ASSERT_TRUE(bl_eq(orig
, in
));
6826 ObjectStore::Transaction t
;
6827 t
.remove(cid
, hoid
);
6828 t
.remove_collection(cid
);
6829 cerr
<< "Cleaning" << std::endl
;
6830 r
= queue_transaction(store
, ch
, std::move(t
));
6836 INSTANTIATE_TEST_SUITE_P(
6841 #if defined(WITH_BLUESTORE)
6846 // Note: instantiate all stores to preserve store numbering order only
6847 INSTANTIATE_TEST_SUITE_P(
6849 StoreTestSpecificAUSize
,
6852 #if defined(WITH_BLUESTORE)
6857 // Note: instantiate all stores to preserve store numbering order only
6858 INSTANTIATE_TEST_SUITE_P(
6860 StoreTestOmapUpgrade
,
6863 #if defined(WITH_BLUESTORE)
6868 #if defined(WITH_BLUESTORE)
6869 INSTANTIATE_TEST_SUITE_P(
6871 StoreTestDeferredSetup
,
6877 struct deferred_test_t
{
6878 uint32_t bdev_block_size
;
6879 uint32_t min_alloc_size
;
6880 uint32_t max_blob_size
;
6881 uint32_t prefer_deferred_size
;
6884 void PrintTo(const deferred_test_t
& t
, ::std::ostream
* os
)
6886 *os
<< t
.bdev_block_size
<< "/" << t
.min_alloc_size
<< "/"
6887 << t
.max_blob_size
<< "/" << t
.prefer_deferred_size
;
6890 class DeferredWriteTest
: public StoreTestFixture
,
6891 public ::testing::WithParamInterface
<deferred_test_t
> {
6894 : StoreTestFixture("bluestore")
6896 void SetUp() override
{
6900 void DeferredSetup() {
6901 StoreTestFixture::SetUp();
6904 std::vector
<uint32_t> offsets
= {0, 3000, 4096, 20000, 32768, 65000, 65536, 80000, 128 * 1024};
6905 std::vector
<uint32_t> lengths
= {1, 1000, 4096, 12000, 32768, 30000, 80000, 128 * 1024};
6908 TEST_P(DeferredWriteTest
, NewData
) {
6909 const bool print
= false;
6910 deferred_test_t t
= GetParam();
6911 SetVal(g_conf(), "bdev_block_size", stringify(t
.bdev_block_size
).c_str());
6912 SetVal(g_conf(), "bluestore_min_alloc_size", stringify(t
.min_alloc_size
).c_str());
6913 SetVal(g_conf(), "bluestore_max_blob_size", stringify(t
.max_blob_size
).c_str());
6914 SetVal(g_conf(), "bluestore_prefer_deferred_size", stringify(t
.prefer_deferred_size
).c_str());
6915 g_conf().apply_changes(nullptr);
6920 const PerfCounters
* logger
= store
->get_perf_counters();
6921 ObjectStore::CollectionHandle ch
= store
->create_new_collection(cid
);
6923 ObjectStore::Transaction t
;
6924 t
.create_collection(cid
, 0);
6925 r
= queue_transaction(store
, ch
, std::move(t
));
6929 for (auto offset
:offsets
) {
6930 for (auto length
:lengths
) {
6931 std::string hname
= fmt::format("test-{}-{}", offset
, length
);
6932 ghobject_t
hoid(hobject_t(hname
, "", CEPH_NOSNAP
, 0, -1, ""));
6934 ObjectStore::Transaction t
;
6936 r
= queue_transaction(store
, ch
, std::move(t
));
6940 std::cout
<< hname
<< std::endl
;
6942 auto w_new
= logger
->get(l_bluestore_write_new
);
6943 auto w_big_deferred
= logger
->get(l_bluestore_write_big_deferred
);
6944 auto i_deferred_w
= logger
->get(l_bluestore_issued_deferred_writes
);
6946 ObjectStore::Transaction t
;
6948 bl
.append(std::string(length
, 'x'));
6949 t
.write(cid
, hoid
, offset
, bl
.length(), bl
,
6950 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
6951 r
= queue_transaction(store
, ch
, std::move(t
));
6954 uint32_t first_db
= offset
/ t
.bdev_block_size
;
6955 uint32_t last_db
= (offset
+ length
- 1) / t
.bdev_block_size
;
6957 uint32_t write_size
= (last_db
- first_db
+ 1) * t
.bdev_block_size
;
6958 if (write_size
< t
.prefer_deferred_size
) {
6959 // expect no direct writes
6960 ASSERT_EQ(w_new
, logger
->get(l_bluestore_write_new
));
6962 // expect no deferred
6963 ASSERT_EQ(w_big_deferred
, logger
->get(l_bluestore_write_big_deferred
));
6964 ASSERT_EQ(i_deferred_w
, logger
->get(l_bluestore_issued_deferred_writes
));
6971 #if defined(WITH_BLUESTORE)
6972 INSTANTIATE_TEST_SUITE_P(
6976 // bdev alloc blob deferred
6977 deferred_test_t
{4 * 1024, 4 * 1024, 16 * 1024, 32 * 1024},
6978 deferred_test_t
{4 * 1024, 16 * 1024, 64 * 1024, 64 * 1024},
6979 deferred_test_t
{4 * 1024, 64 * 1024, 64 * 1024, 4 * 1024},
6980 deferred_test_t
{4 * 1024, 4 * 1024, 64 * 1024, 0 * 1024},
6981 deferred_test_t
{4 * 1024, 16 * 1024, 32 * 1024, 32 * 1024},
6982 deferred_test_t
{4 * 1024, 16 * 1024, 64 * 1024, 128 * 1024}
6986 void doMany4KWritesTest(ObjectStore
* store
,
6987 unsigned max_objects
,
6989 unsigned max_object_size
,
6990 unsigned max_write_size
,
6991 unsigned write_alignment
)
6993 MixedGenerator
gen(555);
6994 gen_type
rng(time(NULL
));
6995 coll_t
cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD
));
6996 store_statfs_t res_stat
;
6998 SyntheticWorkloadState
test_obj(store
,
7006 for (unsigned i
= 0; i
< max_objects
; ++i
) {
7007 if (!(i
% 500)) cerr
<< "seeding object " << i
<< std::endl
;
7010 for (unsigned i
= 0; i
< max_ops
; ++i
) {
7012 cerr
<< "Op " << i
<< std::endl
;
7013 test_obj
.print_internal_state();
7017 test_obj
.wait_for_done();
7018 test_obj
.statfs(res_stat
);
7019 if (!(res_stat
.data_stored
<= max_object_size
) ||
7020 !(res_stat
.allocated
<= max_object_size
)) {
7021 // this will provide more insight on the mismatch and
7022 // helps to avoid any races during stats collection
7023 test_obj
.fsck(false);
7024 // retrieving stats once again and assert if still broken
7025 test_obj
.statfs(res_stat
);
7026 ASSERT_LE(res_stat
.data_stored
, max_object_size
);
7027 ASSERT_LE(res_stat
.allocated
, max_object_size
);
7029 test_obj
.shutdown();
7032 TEST_P(StoreTestSpecificAUSize
, Many4KWritesTest
) {
7033 if (string(GetParam()) != "bluestore")
7036 cout
<< "SKIP: no deferred; assertions around res_stat.allocated don't apply"
7041 StartDeferred(0x10000);
7043 const unsigned max_object
= 4*1024*1024;
7044 doMany4KWritesTest(store
.get(), 1, 1000, max_object
, 4*1024, 0);
7047 TEST_P(StoreTestSpecificAUSize
, Many4KWritesNoCSumTest
) {
7048 if (string(GetParam()) != "bluestore")
7051 cout
<< "SKIP: no deferred; assertions around res_stat.allocated don't apply"
7055 StartDeferred(0x10000);
7056 SetVal(g_conf(), "bluestore_csum_type", "none");
7057 g_ceph_context
->_conf
.apply_changes(nullptr);
7058 const unsigned max_object
= 4*1024*1024;
7060 doMany4KWritesTest(store
.get(), 1, 1000, max_object
, 4*1024, 0 );
7063 TEST_P(StoreTestSpecificAUSize
, TooManyBlobsTest
) {
7064 if (string(GetParam()) != "bluestore")
7067 cout
<< "SKIP: no deferred; assertions around res_stat.allocated don't apply"
7071 StartDeferred(0x10000);
7072 const unsigned max_object
= 4*1024*1024;
7073 doMany4KWritesTest(store
.get(), 1, 1000, max_object
, 4*1024, 0);
7076 #if defined(WITH_BLUESTORE)
7077 void get_mempool_stats(uint64_t* total_bytes
, uint64_t* total_items
)
7079 uint64_t meta_allocated
= mempool::bluestore_cache_meta::allocated_bytes();
7080 uint64_t onode_allocated
= mempool::bluestore_cache_onode::allocated_bytes();
7081 uint64_t other_allocated
= mempool::bluestore_cache_other::allocated_bytes();
7083 uint64_t meta_items
= mempool::bluestore_cache_meta::allocated_items();
7084 uint64_t onode_items
= mempool::bluestore_cache_onode::allocated_items();
7085 uint64_t other_items
= mempool::bluestore_cache_other::allocated_items();
7086 cout
<< "meta(" << meta_allocated
<< "/" << meta_items
7087 << ") onode(" << onode_allocated
<< "/" << onode_items
7088 << ") other(" << other_allocated
<< "/" << other_items
7089 << ")" << std::endl
;
7090 *total_bytes
= meta_allocated
+ onode_allocated
+ other_allocated
;
7091 *total_items
= onode_items
;
7094 TEST_P(StoreTestSpecificAUSize
, OnodeSizeTracking
) {
7096 if (string(GetParam()) != "bluestore")
7099 size_t block_size
= 4096;
7100 StartDeferred(block_size
);
7101 SetVal(g_conf(), "bluestore_compression_mode", "none");
7102 SetVal(g_conf(), "bluestore_csum_type", "none");
7103 SetVal(g_conf(), "bluestore_cache_size_hdd", "400000000");
7104 SetVal(g_conf(), "bluestore_cache_size_ssd", "400000000");
7105 g_conf().apply_changes(nullptr);
7109 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
7110 size_t obj_size
= 4 * 1024 * 1024;
7111 uint64_t total_bytes_prev
;
7112 uint64_t total_bytes
, total_bytes2
;
7113 uint64_t total_onodes
;
7114 get_mempool_stats(&total_bytes
, &total_onodes
);
7115 total_bytes_prev
= total_bytes
;
7116 // 5u for onode_cache_shards vector
7117 ASSERT_EQ(total_onodes
, 5u);
7118 ASSERT_EQ(total_bytes
, 40u);
7120 auto ch
= store
->create_new_collection(cid
);
7122 ObjectStore::Transaction t
;
7123 t
.create_collection(cid
, 0);
7124 r
= queue_transaction(store
, ch
, std::move(t
));
7128 ObjectStore::Transaction t
;
7129 bufferlist bl
, orig
, orig2
;
7131 bl
.append(std::string(obj_size
, 'a'));
7132 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7133 r
= queue_transaction(store
, ch
, std::move(t
));
7136 get_mempool_stats(&total_bytes
, &total_onodes
);
7137 ASSERT_GT(total_bytes
- total_bytes_prev
, 0u);
7138 ASSERT_EQ(total_onodes
, 6u);
7141 ObjectStore::Transaction t
;
7142 t
.truncate(cid
, hoid
, 0);
7143 r
= queue_transaction(store
, ch
, std::move(t
));
7147 for(size_t i
= 0; i
< 1; ++i
) {
7149 bl
.append(std::string(block_size
* (i
+1), 'a'));
7150 for( size_t j
= 0; j
< obj_size
; j
+= bl
.length()) {
7151 ObjectStore::Transaction t
;
7152 t
.write(cid
, hoid
, j
, bl
.length(), bl
);
7153 r
= queue_transaction(store
, ch
, std::move(t
));
7156 get_mempool_stats(&total_bytes2
, &total_onodes
);
7157 ASSERT_NE(total_bytes2
, 0u);
7158 ASSERT_EQ(total_onodes
, 6u);
7161 cout
<<" mempool dump:\n";
7162 JSONFormatter
f(true);
7163 f
.open_object_section("transaction");
7171 for (size_t i
= 0; i
< obj_size
; i
+= 0x1000) {
7172 store
->read(ch
, hoid
, i
, 0x1000, bl
);
7175 get_mempool_stats(&total_bytes
, &total_onodes
);
7176 ASSERT_NE(total_bytes
, 0u);
7177 ASSERT_EQ(total_onodes
, 6u);
7180 cout
<<" mempool dump:\n";
7181 JSONFormatter
f(true);
7182 f
.open_object_section("transaction");
7189 ObjectStore::Transaction t
;
7190 t
.remove(cid
, hoid
);
7191 t
.remove_collection(cid
);
7192 cerr
<< "Cleaning" << std::endl
;
7193 r
= queue_transaction(store
, ch
, std::move(t
));
7198 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwrite
) {
7200 if (string(GetParam()) != "bluestore")
7203 size_t block_size
= 4096;
7204 StartDeferred(block_size
);
7205 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
7206 g_conf().apply_changes(nullptr);
7210 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
7212 const PerfCounters
* logger
= store
->get_perf_counters();
7214 auto ch
= store
->create_new_collection(cid
);
7216 ObjectStore::Transaction t
;
7217 t
.create_collection(cid
, 0);
7218 r
= queue_transaction(store
, ch
, std::move(t
));
7222 ObjectStore::Transaction t
;
7225 bl
.append(std::string(block_size
* 2, 'a'));
7226 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7227 r
= queue_transaction(store
, ch
, std::move(t
));
7231 // overwrite at the beginning
7232 ObjectStore::Transaction t
;
7235 bl
.append(std::string(block_size
, 'b'));
7236 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7237 r
= queue_transaction(store
, ch
, std::move(t
));
7242 ObjectStore::Transaction t
;
7245 bl
.append(std::string(block_size
* 2, 'c'));
7246 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7247 r
= queue_transaction(store
, ch
, std::move(t
));
7251 // append with a gap
7252 ObjectStore::Transaction t
;
7255 bl
.append(std::string(block_size
* 2, 'd'));
7256 t
.write(cid
, hoid
, block_size
* 5, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7257 r
= queue_transaction(store
, ch
, std::move(t
));
7261 // We need to issue a read to trigger cache stat update that refresh
7262 // perf counters. additionally we need to wait some time for mempool
7263 // thread to update stats.
7265 bufferlist bl
, expected
;
7266 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7267 ASSERT_EQ(r
, (int)block_size
);
7268 expected
.append(string(block_size
, 'b'));
7269 ASSERT_TRUE(bl_eq(expected
, bl
));
7270 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7271 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
7275 ObjectStore::Transaction t
;
7278 bl
.append(std::string(block_size
* 2, 'e'));
7280 // Currently we are unable to reuse blob when overwriting in a single step
7281 t
.write(cid
, hoid
, block_size
* 6, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7282 r
= queue_transaction(store
, ch
, std::move(t
));
7286 // We need to issue a read to trigger cache stat update that refresh
7287 // perf counters. additionally we need to wait some time for mempool
7288 // thread to update stats.
7290 bufferlist bl
, expected
;
7291 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7292 ASSERT_EQ(r
, (int)block_size
);
7293 expected
.append(string(block_size
, 'b'));
7294 ASSERT_TRUE(bl_eq(expected
, bl
));
7295 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7296 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
7300 ObjectStore::Transaction t
;
7303 bl
.append(std::string(block_size
, 'f'));
7305 t
.write(cid
, hoid
, block_size
* 4, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
7306 r
= queue_transaction(store
, ch
, std::move(t
));
7310 // we need to wait some time for mempool
7311 // thread to update stats to be able to check blob/extent numbers from
7315 bufferlist bl
, expected
;
7316 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7317 ASSERT_EQ(r
, (int)block_size
);
7318 expected
.append(string(block_size
, 'b'));
7319 ASSERT_TRUE(bl_eq(expected
, bl
));
7323 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7324 ASSERT_EQ(r
, (int)block_size
);
7325 expected
.append(string(block_size
, 'a'));
7326 ASSERT_TRUE(bl_eq(expected
, bl
));
7330 r
= store
->read(ch
, hoid
, block_size
* 2, block_size
* 2, bl
);
7331 ASSERT_EQ(r
, (int)block_size
* 2);
7332 expected
.append(string(block_size
* 2, 'c'));
7333 ASSERT_TRUE(bl_eq(expected
, bl
));
7337 r
= store
->read(ch
, hoid
, block_size
* 4, block_size
, bl
);
7338 ASSERT_EQ(r
, (int)block_size
);
7339 expected
.append(string(block_size
, 'f'));
7340 ASSERT_TRUE(bl_eq(expected
, bl
));
7344 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
, bl
);
7345 ASSERT_EQ(r
, (int)block_size
);
7346 expected
.append(string(block_size
, 'd'));
7347 ASSERT_TRUE(bl_eq(expected
, bl
));
7351 r
= store
->read(ch
, hoid
, block_size
* 5, block_size
* 3, bl
);
7352 ASSERT_EQ(r
, (int)block_size
* 3);
7353 expected
.append(string(block_size
, 'd'));
7354 expected
.append(string(block_size
* 2, 'e'));
7355 ASSERT_TRUE(bl_eq(expected
, bl
));
7357 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7358 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
7362 ObjectStore::Transaction t
;
7363 t
.remove(cid
, hoid
);
7364 t
.remove_collection(cid
);
7365 cerr
<< "Cleaning" << std::endl
;
7366 r
= queue_transaction(store
, ch
, std::move(t
));
7371 TEST_P(StoreTestSpecificAUSize
, ZeroBlockDetectionSmallAppend
) {
7372 CephContext
*cct
= (new CephContext(CEPH_ENTITY_TYPE_CLIENT
))->get();
7373 if (string(GetParam()) != "bluestore" || !cct
->_conf
->bluestore_zero_block_detection
) {
7374 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7377 size_t block_size
= 65536;
7378 StartDeferred(block_size
);
7382 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7384 const PerfCounters
* logger
= store
->get_perf_counters();
7386 auto ch
= store
->create_new_collection(cid
);
7388 ObjectStore::Transaction t
;
7389 t
.create_collection(cid
, 0);
7390 r
= queue_transaction(store
, ch
, std::move(t
));
7395 ObjectStore::Transaction t
;
7398 bl
.append_zero(4096);
7400 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7401 r
= queue_transaction(store
, ch
, std::move(t
));
7403 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 1u);
7404 ASSERT_EQ(logger
->get(l_bluestore_write_small_bytes
), 4096u);
7405 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped
), 1u);
7406 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped_bytes
), 4096u);
7409 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
7411 ASSERT_TRUE(in
.is_zero());
7415 // [2] append non-zeros
7416 ObjectStore::Transaction t
;
7419 bl
.append(std::string(4096, 'c'));
7421 t
.write(cid
, hoid
, 4096, bl
.length(), bl
);
7422 r
= queue_transaction(store
, ch
, std::move(t
));
7424 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 2u);
7425 ASSERT_EQ(logger
->get(l_bluestore_write_small_bytes
), 4096u*2);
7426 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped
), 1u);
7427 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped_bytes
), 4096u);
7429 bufferlist in
, _exp
;
7430 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
7431 ASSERT_EQ(4096 * 2, r
);
7432 _exp
.append_zero(4096);
7434 ASSERT_TRUE(bl_eq(_exp
, in
));
7438 ObjectStore::Transaction t
;
7439 t
.remove(cid
, hoid
);
7440 t
.remove_collection(cid
);
7441 cerr
<< "Cleaning" << std::endl
;
7442 r
= queue_transaction(store
, ch
, std::move(t
));
7447 TEST_P(StoreTestSpecificAUSize
, ZeroBlockDetectionSmallOverwrite
) {
7448 CephContext
*cct
= (new CephContext(CEPH_ENTITY_TYPE_CLIENT
))->get();
7449 if (string(GetParam()) != "bluestore" || !cct
->_conf
->bluestore_zero_block_detection
) {
7450 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7453 GTEST_SKIP() << "smr, skipping";
7456 size_t block_size
= 65536;
7457 StartDeferred(block_size
);
7461 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7463 const PerfCounters
* logger
= store
->get_perf_counters();
7465 auto ch
= store
->create_new_collection(cid
);
7467 ObjectStore::Transaction t
;
7468 t
.create_collection(cid
, 0);
7469 r
= queue_transaction(store
, ch
, std::move(t
));
7474 // {setting up the scenario} append non-zeros
7475 ObjectStore::Transaction t
;
7478 bl
.append(std::string(4096, 'c'));
7480 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7481 r
= queue_transaction(store
, ch
, std::move(t
));
7483 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 1u);
7484 ASSERT_EQ(logger
->get(l_bluestore_write_small_bytes
), 4096u);
7485 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped
), 0u);
7486 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped_bytes
), 0u);
7488 bufferlist in
, _exp
;
7489 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
7492 ASSERT_TRUE(bl_eq(_exp
, in
));
7496 // [1] overwrite non-zeros with zeros
7497 ObjectStore::Transaction t
;
7500 bl
.append_zero(4096);
7502 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7503 r
= queue_transaction(store
, ch
, std::move(t
));
7505 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 2u);
7506 ASSERT_EQ(logger
->get(l_bluestore_write_small_bytes
), 4096u*2);
7507 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped
), 0u);
7508 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped_bytes
), 0u);
7511 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
7513 ASSERT_TRUE(in
.is_zero());
7517 // [2] overwrite zeros with non-zeros
7518 ObjectStore::Transaction t
;
7521 bl
.append(std::string(4096, 'c'));
7523 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7524 r
= queue_transaction(store
, ch
, std::move(t
));
7526 ASSERT_EQ(logger
->get(l_bluestore_write_small
), 3u);
7527 ASSERT_EQ(logger
->get(l_bluestore_write_small_bytes
), 4096u*3);
7528 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped
), 0u);
7529 ASSERT_EQ(logger
->get(l_bluestore_write_small_skipped_bytes
), 0u);
7531 bufferlist in
, _exp
;
7532 r
= store
->read(ch
, hoid
, 0, 0x4000, in
);
7535 ASSERT_TRUE(bl_eq(_exp
, in
));
7539 ObjectStore::Transaction t
;
7540 t
.remove(cid
, hoid
);
7541 t
.remove_collection(cid
);
7542 cerr
<< "Cleaning" << std::endl
;
7543 r
= queue_transaction(store
, ch
, std::move(t
));
7548 TEST_P(StoreTestSpecificAUSize
, ZeroBlockDetectionBigAppend
) {
7549 CephContext
*cct
= (new CephContext(CEPH_ENTITY_TYPE_CLIENT
))->get();
7550 if (string(GetParam()) != "bluestore" || !cct
->_conf
->bluestore_zero_block_detection
) {
7551 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7554 size_t block_size
= 4096;
7555 StartDeferred(block_size
);
7559 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7561 const PerfCounters
* logger
= store
->get_perf_counters();
7563 auto ch
= store
->create_new_collection(cid
);
7565 ObjectStore::Transaction t
;
7566 t
.create_collection(cid
, 0);
7567 r
= queue_transaction(store
, ch
, std::move(t
));
7573 ObjectStore::Transaction t
;
7576 bl
.append_zero(block_size
* 2);
7578 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7579 r
= queue_transaction(store
, ch
, std::move(t
));
7581 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
7582 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), 4096u*2);
7583 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 0u);
7584 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_blobs
), 1u);
7585 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_bytes
), 4096u*2);
7588 r
= store
->read(ch
, hoid
, 0, block_size
* 8, in
);
7589 ASSERT_EQ(block_size
* 2, r
);
7590 ASSERT_TRUE(in
.is_zero());
7594 // [2] append non-zeros
7595 ObjectStore::Transaction t
;
7598 bl
.append(std::string(block_size
* 2, 'c'));
7600 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
);
7601 r
= queue_transaction(store
, ch
, std::move(t
));
7603 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 2u);
7604 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), 4096u*4);
7605 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 1u);
7606 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_blobs
), 1u);
7607 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_bytes
), 4096u*2);
7609 bufferlist in
, _exp
;
7610 r
= store
->read(ch
, hoid
, 0, block_size
* 8, in
);
7611 ASSERT_EQ(block_size
* 4, r
);
7612 _exp
.append_zero(block_size
* 2);
7614 ASSERT_TRUE(bl_eq(_exp
, in
));
7618 ObjectStore::Transaction t
;
7619 t
.remove(cid
, hoid
);
7620 t
.remove_collection(cid
);
7621 cerr
<< "Cleaning" << std::endl
;
7622 r
= queue_transaction(store
, ch
, std::move(t
));
7627 TEST_P(StoreTestSpecificAUSize
, ZeroBlockDetectionBigOverwrite
) {
7628 CephContext
*cct
= (new CephContext(CEPH_ENTITY_TYPE_CLIENT
))->get();
7629 if (string(GetParam()) != "bluestore" || !cct
->_conf
->bluestore_zero_block_detection
) {
7630 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7633 GTEST_SKIP() << "smr, skipping";
7636 size_t block_size
= 4096;
7637 StartDeferred(block_size
);
7641 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7643 const PerfCounters
* logger
= store
->get_perf_counters();
7645 auto ch
= store
->create_new_collection(cid
);
7647 ObjectStore::Transaction t
;
7648 t
.create_collection(cid
, 0);
7649 r
= queue_transaction(store
, ch
, std::move(t
));
7654 // {setting up the scenario} append non-zeros
7655 ObjectStore::Transaction t
;
7658 bl
.append(std::string(block_size
* 2, 'c'));
7660 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7661 r
= queue_transaction(store
, ch
, std::move(t
));
7663 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
7664 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), 4096u*2);
7665 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 1u);
7666 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_blobs
), 0u);
7667 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_bytes
), 0u);
7669 bufferlist in
, _exp
;
7670 r
= store
->read(ch
, hoid
, 0, block_size
* 8, in
);
7671 ASSERT_EQ(block_size
* 2, r
);
7673 ASSERT_TRUE(bl_eq(_exp
, in
));
7677 // [1] overwrite non-zeros with zeros
7678 ObjectStore::Transaction t
;
7681 bl
.append_zero(block_size
* 2);
7683 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7684 r
= queue_transaction(store
, ch
, std::move(t
));
7686 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 2u);
7687 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), 4096u*4);
7688 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 1u);
7689 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_blobs
), 1u);
7690 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_bytes
), 4096u*2);
7693 r
= store
->read(ch
, hoid
, 0, block_size
* 8, in
);
7694 ASSERT_EQ(block_size
* 2, r
);
7695 ASSERT_TRUE(in
.is_zero());
7699 // [2] overwrite zeros with non-zeros
7700 ObjectStore::Transaction t
;
7703 bl
.append(std::string(block_size
* 2, 'c'));
7705 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
7706 r
= queue_transaction(store
, ch
, std::move(t
));
7708 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 3u);
7709 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), 4096u*6);
7710 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 2u);
7711 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_blobs
), 1u);
7712 ASSERT_EQ(logger
->get(l_bluestore_write_big_skipped_bytes
), 4096u*2);
7714 bufferlist in
, _exp
;
7715 r
= store
->read(ch
, hoid
, 0, block_size
* 8, in
);
7716 ASSERT_EQ(block_size
* 2, r
);
7718 ASSERT_TRUE(bl_eq(_exp
, in
));
7722 ObjectStore::Transaction t
;
7723 t
.remove(cid
, hoid
);
7724 t
.remove_collection(cid
);
7725 cerr
<< "Cleaning" << std::endl
;
7726 r
= queue_transaction(store
, ch
, std::move(t
));
7731 TEST_P(StoreTestSpecificAUSize
, DeferredOnBigOverwrite
) {
7733 if (string(GetParam()) != "bluestore")
7736 cout
<< "SKIP: no deferred" << std::endl
;
7740 size_t block_size
= 4096;
7741 StartDeferred(block_size
);
7742 SetVal(g_conf(), "bluestore_max_blob_size", "131072");
7743 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
7745 g_conf().apply_changes(nullptr);
7749 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
7750 ghobject_t
hoid2(hobject_t("test2", "", CEPH_NOSNAP
, 0, -1, ""));
7752 PerfCounters
* logger
= const_cast<PerfCounters
*>(store
->get_perf_counters());
7754 auto ch
= store
->create_new_collection(cid
);
7756 ObjectStore::Transaction t
;
7757 t
.create_collection(cid
, 0);
7758 r
= queue_transaction(store
, ch
, std::move(t
));
7762 ObjectStore::Transaction t
;
7765 bl
.append(std::string(block_size
* 2, 'c'));
7766 bl2
.append(std::string(block_size
* 3, 'd'));
7768 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7769 t
.set_alloc_hint(cid
, hoid2
, block_size
* 4, block_size
* 4,
7770 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
);
7771 t
.write(cid
, hoid2
, 0, bl2
.length(), bl2
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7772 r
= queue_transaction(store
, ch
, std::move(t
));
7775 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 2u);
7776 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 0u);
7779 struct store_statfs_t statfs
;
7780 int r
= store
->statfs(&statfs
);
7782 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 5);
7783 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 5);
7786 // overwrite at the beginning, 4K alignment
7788 ObjectStore::Transaction t
;
7791 bl
.append(std::string(block_size
, 'b'));
7792 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7793 r
= queue_transaction(store
, ch
, std::move(t
));
7796 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 3u);
7797 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
7800 bufferlist bl
, expected
;
7801 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7802 ASSERT_EQ(r
, (int)block_size
);
7803 expected
.append(string(block_size
, 'b'));
7804 ASSERT_TRUE(bl_eq(expected
, bl
));
7807 bufferlist bl
, expected
;
7808 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7809 ASSERT_EQ(r
, (int)block_size
);
7810 expected
.append(string(block_size
, 'c'));
7811 ASSERT_TRUE(bl_eq(expected
, bl
));
7814 // overwrite at the end, 4K alignment
7816 ObjectStore::Transaction t
;
7819 bl
.append(std::string(block_size
, 'g'));
7820 t
.write(cid
, hoid
, block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7821 r
= queue_transaction(store
, ch
, std::move(t
));
7824 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 4u);
7825 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 2u);
7828 bufferlist bl
, expected
;
7829 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7830 ASSERT_EQ(r
, (int)block_size
);
7831 expected
.append(string(block_size
, 'b'));
7832 ASSERT_TRUE(bl_eq(expected
, bl
));
7835 bufferlist bl
, expected
;
7836 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7837 ASSERT_EQ(r
, (int)block_size
);
7838 expected
.append(string(block_size
, 'g'));
7839 ASSERT_TRUE(bl_eq(expected
, bl
));
7842 // overwrite at 4K, 12K alignment
7844 ObjectStore::Transaction t
;
7847 bl
.append(std::string(block_size
, 'e'));
7848 t
.write(cid
, hoid2
, block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7849 r
= queue_transaction(store
, ch
, std::move(t
));
7852 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 5u);
7853 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 3u);
7855 // makes sure deferred has been submitted
7856 // and do all the checks again
7857 sleep(g_conf().get_val
<double>("bluestore_max_defer_interval") + 2);
7859 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 5u);
7860 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 3u);
7863 bufferlist bl
, expected
;
7864 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7865 ASSERT_EQ(r
, (int)block_size
);
7866 expected
.append(string(block_size
, 'b'));
7867 ASSERT_TRUE(bl_eq(expected
, bl
));
7870 bufferlist bl
, expected
;
7871 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7872 ASSERT_EQ(r
, (int)block_size
);
7873 expected
.append(string(block_size
, 'g'));
7874 ASSERT_TRUE(bl_eq(expected
, bl
));
7877 bufferlist bl
, expected
;
7878 r
= store
->read(ch
, hoid2
, 0, block_size
, bl
);
7879 ASSERT_EQ(r
, (int)block_size
);
7880 expected
.append(string(block_size
, 'd'));
7881 ASSERT_TRUE(bl_eq(expected
, bl
));
7884 bufferlist bl
, expected
;
7885 r
= store
->read(ch
, hoid2
, block_size
, block_size
, bl
);
7886 ASSERT_EQ(r
, (int)block_size
);
7887 expected
.append(string(block_size
, 'e'));
7888 ASSERT_TRUE(bl_eq(expected
, bl
));
7891 bufferlist bl
, expected
;
7892 r
= store
->read(ch
, hoid2
, block_size
* 2, block_size
, bl
);
7893 ASSERT_EQ(r
, (int)block_size
);
7894 expected
.append(string(block_size
, 'd'));
7895 ASSERT_TRUE(bl_eq(expected
, bl
));
7899 struct store_statfs_t statfs
;
7900 int r
= store
->statfs(&statfs
);
7902 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 5);
7903 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 5);
7905 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
7906 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
7909 ObjectStore::Transaction t
;
7910 t
.remove(cid
, hoid
);
7911 t
.remove(cid
, hoid2
);
7912 r
= queue_transaction(store
, ch
, std::move(t
));
7917 ObjectStore::Transaction t
;
7919 bl
.append(std::string(block_size
* 2, 'f'));
7921 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7922 r
= queue_transaction(store
, ch
, std::move(t
));
7925 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 6u);
7926 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 3u);
7929 ObjectStore::Transaction t
;
7930 t
.zero(cid
, hoid
, 0, 100);
7931 r
= queue_transaction(store
, ch
, std::move(t
));
7935 bufferlist bl
, expected
;
7936 r
= store
->read(ch
, hoid
, 0, 100, bl
);
7937 ASSERT_EQ(r
, (int)100);
7938 expected
.append(string(100, 0));
7939 ASSERT_TRUE(bl_eq(expected
, bl
));
7942 bufferlist bl
, expected
;
7943 r
= store
->read(ch
, hoid
, 100, block_size
* 2 - 100, bl
);
7944 ASSERT_EQ(r
, (int)block_size
* 2 - 100);
7945 expected
.append(string(block_size
* 2 - 100, 'f'));
7946 ASSERT_TRUE(bl_eq(expected
, bl
));
7950 struct store_statfs_t statfs
;
7951 int r
= store
->statfs(&statfs
);
7953 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 2 - 100);
7954 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 2);
7956 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7957 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
7960 ObjectStore::Transaction t
;
7962 bl
.append(std::string(block_size
, 'g'));
7964 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
7965 r
= queue_transaction(store
, ch
, std::move(t
));
7968 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 7u);
7969 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 4u);
7971 bufferlist bl
, expected
;
7972 r
= store
->read(ch
, hoid
, 0, block_size
, bl
);
7973 ASSERT_EQ(r
, (int)block_size
);
7974 expected
.append(string(block_size
, 'g'));
7975 ASSERT_TRUE(bl_eq(expected
, bl
));
7978 bufferlist bl
, expected
;
7979 r
= store
->read(ch
, hoid
, block_size
, block_size
, bl
);
7980 ASSERT_EQ(r
, (int)block_size
);
7981 expected
.append(string(block_size
, 'f'));
7982 ASSERT_TRUE(bl_eq(expected
, bl
));
7986 struct store_statfs_t statfs
;
7987 int r
= store
->statfs(&statfs
);
7989 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 2);
7990 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 2);
7992 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
7993 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
7995 // check whether full overwrite bypass deferred
7997 ObjectStore::Transaction t
;
7999 bl
.append(std::string(block_size
* 2, 'h'));
8001 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8002 r
= queue_transaction(store
, ch
, std::move(t
));
8005 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 8u);
8006 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 4u);
8009 bufferlist bl
, expected
;
8010 r
= store
->read(ch
, hoid
, 0, block_size
* 2, bl
);
8011 ASSERT_EQ(r
, (int)block_size
* 2);
8012 expected
.append(string(block_size
* 2, 'h'));
8013 ASSERT_TRUE(bl_eq(expected
, bl
));
8017 struct store_statfs_t statfs
;
8018 int r
= store
->statfs(&statfs
);
8020 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 2);
8021 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 2);
8025 ObjectStore::Transaction t
;
8026 t
.remove(cid
, hoid
);
8027 t
.remove(cid
, hoid2
);
8028 r
= queue_transaction(store
, ch
, std::move(t
));
8033 ObjectStore::Transaction t
;
8035 bl
.append(std::string(block_size
* 32, 'a'));
8037 // this will create two 128K aligned blobs
8038 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8039 t
.write(cid
, hoid
, bl
.length(), bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8040 r
= queue_transaction(store
, ch
, std::move(t
));
8043 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 10u);
8044 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 4u);
8046 // check whether overwrite (less than prefer_deferred_size) partially overlapping two adjacent blobs goes
8049 ObjectStore::Transaction t
;
8051 bl
.append(std::string(block_size
* 3, 'b'));
8053 t
.write(cid
, hoid
, 0x20000 - block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8054 r
= queue_transaction(store
, ch
, std::move(t
));
8057 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 11u);
8058 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 6u);
8061 bufferlist bl
, expected
;
8062 r
= store
->read(ch
, hoid
, 0, 0x20000 - block_size
, bl
);
8063 ASSERT_EQ(r
, 0x20000 - block_size
);
8064 expected
.append(string(r
, 'a'));
8065 ASSERT_TRUE(bl_eq(expected
, bl
));
8068 r
= store
->read(ch
, hoid
, 0x20000 - block_size
, block_size
* 3, bl
);
8069 ASSERT_EQ(r
, 3 * block_size
);
8070 expected
.append(string(r
, 'b'));
8071 ASSERT_TRUE(bl_eq(expected
, bl
));
8074 r
= store
->read(ch
, hoid
, 0x20000 + 2 * block_size
, block_size
* 30, bl
);
8075 ASSERT_EQ(r
, 30 * block_size
);
8076 expected
.append(string(r
, 'a'));
8077 ASSERT_TRUE(bl_eq(expected
, bl
));
8082 struct store_statfs_t statfs
;
8083 int r
= store
->statfs(&statfs
);
8085 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 64);
8086 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 64);
8089 // check whether overwrite (larger than prefer_deferred_size) partially
8090 // overlapping two adjacent blobs goes deferred
8092 ObjectStore::Transaction t
;
8094 bl
.append(std::string(block_size
* 30, 'c'));
8096 t
.write(cid
, hoid
, 0x10000 + block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8097 r
= queue_transaction(store
, ch
, std::move(t
));
8101 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 12u);
8102 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 8u);
8105 bufferlist bl
, expected
;
8106 r
= store
->read(ch
, hoid
, 0, 0x11000, bl
);
8107 ASSERT_EQ(r
, 0x11000);
8108 expected
.append(string(r
, 'a'));
8109 ASSERT_TRUE(bl_eq(expected
, bl
));
8112 r
= store
->read(ch
, hoid
, 0x11000, block_size
* 30, bl
);
8113 ASSERT_EQ(r
, block_size
* 30);
8114 expected
.append(string(r
, 'c'));
8115 ASSERT_TRUE(bl_eq(expected
, bl
));
8118 r
= store
->read(ch
, hoid
, block_size
* 47, 0x10000 + block_size
, bl
);
8119 ASSERT_EQ(r
, 0x10000 + block_size
);
8120 expected
.append(string(r
, 'a'));
8121 ASSERT_TRUE(bl_eq(expected
, bl
));
8126 struct store_statfs_t statfs
;
8127 int r
= store
->statfs(&statfs
);
8129 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 64);
8130 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 64);
8134 // check whether overwrite (prefer_deferred_size < 120K < 2 * prefer_defer_size) partially
8135 // overlapping two adjacent blobs goes partly deferred
8137 ObjectStore::Transaction t
;
8139 bl
.append(std::string(block_size
* 30, 'e'));
8141 t
.write(cid
, hoid
, 0x20000 - block_size
, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8142 r
= queue_transaction(store
, ch
, std::move(t
));
8146 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
8147 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
8148 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), 1u);
8149 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
), block_size
);
8152 struct store_statfs_t statfs
;
8153 int r
= store
->statfs(&statfs
);
8155 ASSERT_EQ(statfs
.data_stored
, (unsigned)block_size
* 64);
8156 ASSERT_LE(statfs
.allocated
, (unsigned)block_size
* 64);
8160 ObjectStore::Transaction t
;
8161 t
.remove(cid
, hoid
);
8162 t
.remove(cid
, hoid2
);
8163 t
.remove_collection(cid
);
8164 cerr
<< "Cleaning" << std::endl
;
8165 r
= queue_transaction(store
, ch
, std::move(t
));
8170 TEST_P(StoreTestSpecificAUSize
, DeferredOnBigOverwrite2
) {
8172 if (string(GetParam()) != "bluestore")
8175 cout
<< "SKIP: no deferred" << std::endl
;
8179 size_t block_size
= 4096;
8180 StartDeferred(block_size
);
8181 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8182 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
8184 g_conf().apply_changes(nullptr);
8188 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
8190 PerfCounters
* logger
= const_cast<PerfCounters
*>(store
->get_perf_counters());
8192 auto ch
= store
->create_new_collection(cid
);
8194 ObjectStore::Transaction t
;
8195 t
.create_collection(cid
, 0);
8196 r
= queue_transaction(store
, ch
, std::move(t
));
8200 ObjectStore::Transaction t
;
8203 bl
.append(std::string(128 * 1024, 'c'));
8205 t
.write(cid
, hoid
, 0x1000, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8206 r
= queue_transaction(store
, ch
, std::move(t
));
8208 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
8209 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
8210 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 3u);
8211 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 0u);
8212 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), 0u);
8213 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
), 0);
8218 ObjectStore::Transaction t
;
8221 bl
.append(std::string(128 * 1024, 'c'));
8223 t
.write(cid
, hoid
, 0x2000, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8224 r
= queue_transaction(store
, ch
, std::move(t
));
8227 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
8228 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
8229 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 3u);
8230 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
8231 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), 1u);
8232 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
), 57344);
8236 ObjectStore::Transaction t
;
8237 t
.remove(cid
, hoid
);
8238 t
.remove(cid
, hoid
);
8239 t
.remove_collection(cid
);
8240 cerr
<< "Cleaning" << std::endl
;
8241 r
= queue_transaction(store
, ch
, std::move(t
));
8246 TEST_P(StoreTestSpecificAUSize
, DeferredOnBigOverwrite3
) {
8248 if (string(GetParam()) != "bluestore")
8251 cout
<< "SKIP: no deferred" << std::endl
;
8255 size_t block_size
= 4096;
8256 StartDeferred(block_size
);
8257 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8258 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
8260 g_conf().apply_changes(nullptr);
8264 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
8266 PerfCounters
* logger
= const_cast<PerfCounters
*>(store
->get_perf_counters());
8268 auto ch
= store
->create_new_collection(cid
);
8270 ObjectStore::Transaction t
;
8271 t
.create_collection(cid
, 0);
8272 r
= queue_transaction(store
, ch
, std::move(t
));
8278 ObjectStore::Transaction t
;
8281 bl
.append(std::string(4096 * 1024, 'c'));
8283 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8284 r
= queue_transaction(store
, ch
, std::move(t
));
8287 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
8288 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
8289 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 64u);
8290 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 0u);
8291 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), 0u);
8292 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
), 0u);
8296 ObjectStore::Transaction t
;
8299 bl
.append(std::string(4096 * 1024, 'c'));
8301 t
.write(cid
, hoid
, 0x1000, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8302 r
= queue_transaction(store
, ch
, std::move(t
));
8305 ASSERT_EQ(logger
->get(l_bluestore_write_big
), 1u);
8306 ASSERT_EQ(logger
->get(l_bluestore_write_big_bytes
), bl
.length());
8307 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 65u);
8308 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), 1u);
8309 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), 1u);
8310 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
), 61440);
8313 ObjectStore::Transaction t
;
8314 t
.remove(cid
, hoid
);
8315 t
.remove_collection(cid
);
8316 cerr
<< "Cleaning" << std::endl
;
8317 r
= queue_transaction(store
, ch
, std::move(t
));
8322 TEST_P(StoreTestSpecificAUSize
, DeferredDifferentChunks
) {
8324 if (string(GetParam()) != "bluestore")
8327 cout
<< "SKIP: no deferred" << std::endl
;
8331 size_t alloc_size
= 4096;
8332 size_t large_object_size
= 1 * 1024 * 1024;
8333 size_t prefer_deferred_size
= 65536;
8334 StartDeferred(alloc_size
);
8335 SetVal(g_conf(), "bluestore_max_blob_size", "131072");
8336 SetVal(g_conf(), "bluestore_prefer_deferred_size",
8337 stringify(prefer_deferred_size
).c_str());
8338 g_conf().apply_changes(nullptr);
8342 const PerfCounters
* logger
= store
->get_perf_counters();
8343 size_t exp_bluestore_write_big
= 0;
8344 size_t exp_bluestore_write_big_deferred
= 0;
8346 ObjectStore::CollectionHandle ch
= store
->create_new_collection(cid
);
8348 ObjectStore::Transaction t
;
8349 t
.create_collection(cid
, 0);
8350 r
= queue_transaction(store
, ch
, std::move(t
));
8353 for (size_t expected_write_size
= 1024; expected_write_size
<= prefer_deferred_size
; expected_write_size
*= 2) {
8354 //create object with hint
8355 ghobject_t
hoid(hobject_t("test-"+to_string(expected_write_size
), "", CEPH_NOSNAP
, 0, -1, ""));
8357 ObjectStore::Transaction t
;
8359 t
.set_alloc_hint(cid
, hoid
, large_object_size
, expected_write_size
,
8360 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
|
8361 CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY
);
8362 r
= queue_transaction(store
, ch
, std::move(t
));
8368 ObjectStore::Transaction t
;
8370 bl
.append(std::string(large_object_size
, 'h'));
8371 t
.write(cid
, hoid
, 0, bl
.length(), bl
,
8372 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8373 r
= queue_transaction(store
, ch
, std::move(t
));
8374 ++exp_bluestore_write_big
;
8377 ASSERT_EQ(logger
->get(l_bluestore_write_big
), exp_bluestore_write_big
);
8378 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), exp_bluestore_write_big_deferred
);
8380 // check whether write will properly use deferred
8382 ObjectStore::Transaction t
;
8384 bl
.append(std::string(alloc_size
+ 2, 'z'));
8385 t
.write(cid
, hoid
, large_object_size
- 2 * alloc_size
- 1, bl
.length(), bl
,
8386 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8387 r
= queue_transaction(store
, ch
, std::move(t
));
8388 ++exp_bluestore_write_big
;
8389 if (expected_write_size
< prefer_deferred_size
)
8390 ++exp_bluestore_write_big_deferred
;
8393 ASSERT_EQ(logger
->get(l_bluestore_write_big
), exp_bluestore_write_big
);
8394 ASSERT_EQ(logger
->get(l_bluestore_write_big_deferred
), exp_bluestore_write_big_deferred
);
8398 ch
= store
->open_collection(cid
);
8400 for (size_t expected_write_size
= 1024; expected_write_size
<= 65536; expected_write_size
*= 2) {
8401 ghobject_t
hoid(hobject_t("test-"+to_string(expected_write_size
), "", CEPH_NOSNAP
, 0, -1, ""));
8403 bufferlist bl
, expected
;
8404 r
= store
->read(ch
, hoid
, 0, large_object_size
, bl
);
8405 ASSERT_EQ(r
, large_object_size
);
8406 expected
.append(string(large_object_size
- 2 * alloc_size
- 1, 'h'));
8407 expected
.append(string(alloc_size
+ 2, 'z'));
8408 expected
.append(string(alloc_size
- 1, 'h'));
8409 ASSERT_TRUE(bl_eq(expected
, bl
));
8413 ObjectStore::Transaction t
;
8414 for (size_t expected_write_size
= 1024; expected_write_size
<= 65536; expected_write_size
*= 2) {
8415 ghobject_t
hoid(hobject_t("test-"+to_string(expected_write_size
), "", CEPH_NOSNAP
, 0, -1, ""));
8416 t
.remove(cid
, hoid
);
8418 t
.remove_collection(cid
);
8419 cerr
<< "Cleaning" << std::endl
;
8420 r
= queue_transaction(store
, ch
, std::move(t
));
8425 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnOverwriteReverse
) {
8427 if (string(GetParam()) != "bluestore")
8430 cout
<< "SKIP: no overwrite" << std::endl
;
8434 size_t block_size
= 4096;
8435 StartDeferred(block_size
);
8436 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8437 g_conf().apply_changes(nullptr);
8441 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
8443 auto ch
= store
->create_new_collection(cid
);
8445 const PerfCounters
* logger
= store
->get_perf_counters();
8447 ObjectStore::Transaction t
;
8448 t
.create_collection(cid
, 0);
8449 r
= queue_transaction(store
, ch
, std::move(t
));
8453 ObjectStore::Transaction t
;
8456 bl
.append(std::string(block_size
* 2, 'a'));
8457 t
.write(cid
, hoid
, block_size
* 10, bl
.length(), bl
,
8458 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8459 r
= queue_transaction(store
, ch
, std::move(t
));
8464 ObjectStore::Transaction t
;
8467 bl
.append(std::string(block_size
, 'b'));
8468 t
.write(cid
, hoid
, block_size
* 9, bl
.length(), bl
,
8469 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8470 r
= queue_transaction(store
, ch
, std::move(t
));
8474 // We need to issue a read to trigger cache stat update that refresh
8475 // perf counters. additionally we need to wait some time for mempool
8476 // thread to update stats.
8478 bufferlist bl
, expected
;
8479 r
= store
->read(ch
, hoid
, block_size
* 9, block_size
* 2, bl
);
8480 ASSERT_EQ(r
, (int)block_size
* 2);
8481 expected
.append(string(block_size
, 'b'));
8482 expected
.append(string(block_size
, 'a'));
8483 ASSERT_TRUE(bl_eq(expected
, bl
));
8484 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
8485 ASSERT_EQ(logger
->get(l_bluestore_extents
), 1u);
8490 // prepend existing with a gap
8491 ObjectStore::Transaction t
;
8494 bl
.append(std::string(block_size
, 'c'));
8495 t
.write(cid
, hoid
, block_size
* 7, bl
.length(), bl
,
8496 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8497 r
= queue_transaction(store
, ch
, std::move(t
));
8501 // We need to issue a read to trigger cache stat update that refresh
8502 // perf counters. additionally we need to wait some time for mempool
8503 // thread to update stats.
8505 bufferlist bl
, expected
;
8506 r
= store
->read(ch
, hoid
, block_size
* 7, block_size
* 3, bl
);
8507 ASSERT_EQ(r
, (int)block_size
* 3);
8508 expected
.append(string(block_size
, 'c'));
8509 expected
.append(string(block_size
, 0));
8510 expected
.append(string(block_size
, 'b'));
8511 ASSERT_TRUE(bl_eq(expected
, bl
));
8512 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
8513 ASSERT_EQ(logger
->get(l_bluestore_extents
), 2u);
8517 // append after existing with a gap
8518 ObjectStore::Transaction t
;
8521 bl
.append(std::string(block_size
, 'd'));
8522 t
.write(cid
, hoid
, block_size
* 13, bl
.length(), bl
,
8523 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8524 r
= queue_transaction(store
, ch
, std::move(t
));
8528 // We need to issue a read to trigger cache stat update that refresh
8529 // perf counters. additionally we need to wait some time for mempool
8530 // thread to update stats.
8532 bufferlist bl
, expected
;
8533 r
= store
->read(ch
, hoid
, block_size
* 11, block_size
* 3, bl
);
8534 ASSERT_EQ(r
, (int)block_size
* 3);
8535 expected
.append(string(block_size
, 'a'));
8536 expected
.append(string(block_size
, 0));
8537 expected
.append(string(block_size
, 'd'));
8538 ASSERT_TRUE(bl_eq(expected
, bl
));
8539 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
8540 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
8544 // append twice to the next max_blob slot
8545 ObjectStore::Transaction t
;
8548 bl
.append(std::string(block_size
, 'e'));
8549 t
.write(cid
, hoid
, block_size
* 17, bl
.length(), bl
,
8550 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8551 t
.write(cid
, hoid
, block_size
* 19, bl
.length(), bl
,
8552 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8553 r
= queue_transaction(store
, ch
, std::move(t
));
8557 // We need to issue a read to trigger cache stat update that refresh
8558 // perf counters. additionally we need to wait some time for mempool
8559 // thread to update stats.
8561 bufferlist bl
, expected
;
8562 r
= store
->read(ch
, hoid
, block_size
* 17, block_size
* 3, bl
);
8563 ASSERT_EQ(r
, (int)block_size
* 3);
8564 expected
.append(string(block_size
, 'e'));
8565 expected
.append(string(block_size
, 0));
8566 expected
.append(string(block_size
, 'e'));
8567 ASSERT_TRUE(bl_eq(expected
, bl
));
8568 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
8569 ASSERT_EQ(logger
->get(l_bluestore_extents
), 5u);
8572 // fill gaps at the second slot
8573 ObjectStore::Transaction t
;
8576 bl
.append(std::string(block_size
, 'f'));
8577 t
.write(cid
, hoid
, block_size
* 16, bl
.length(), bl
,
8578 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8579 t
.write(cid
, hoid
, block_size
* 18, bl
.length(), bl
,
8580 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8581 r
= queue_transaction(store
, ch
, std::move(t
));
8585 // We need to issue a read to trigger cache stat update that refresh
8586 // perf counters. additionally we need to wait some time for mempool
8587 // thread to update stats.
8589 bufferlist bl
, expected
;
8590 r
= store
->read(ch
, hoid
, block_size
* 16, block_size
* 4, bl
);
8591 ASSERT_EQ(r
, (int)block_size
* 4);
8592 expected
.append(string(block_size
, 'f'));
8593 expected
.append(string(block_size
, 'e'));
8594 expected
.append(string(block_size
, 'f'));
8595 expected
.append(string(block_size
, 'e'));
8596 ASSERT_TRUE(bl_eq(expected
, bl
));
8597 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 2u);
8598 ASSERT_EQ(logger
->get(l_bluestore_extents
), 4u);
8601 ObjectStore::Transaction t
;
8602 t
.remove(cid
, hoid
);
8603 t
.remove_collection(cid
);
8604 cerr
<< "Cleaning" << std::endl
;
8605 r
= queue_transaction(store
, ch
, std::move(t
));
8610 TEST_P(StoreTestSpecificAUSize
, BlobReuseOnSmallOverwrite
) {
8612 if (string(GetParam()) != "bluestore")
8615 cout
<< "SKIP: no overwrite" << std::endl
;
8619 size_t block_size
= 4096;
8620 StartDeferred(block_size
);
8621 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8622 g_conf().apply_changes(nullptr);
8626 ghobject_t
hoid(hobject_t("test_hint", "", CEPH_NOSNAP
, 0, -1, ""));
8628 const PerfCounters
* logger
= store
->get_perf_counters();
8629 auto ch
= store
->create_new_collection(cid
);
8632 ObjectStore::Transaction t
;
8633 t
.create_collection(cid
, 0);
8634 r
= queue_transaction(store
, ch
, std::move(t
));
8638 ObjectStore::Transaction t
;
8641 bl
.append(std::string(block_size
, 'a'));
8642 t
.write(cid
, hoid
, 0, bl
.length(), bl
, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8643 t
.write(cid
, hoid
, block_size
* 2, bl
.length(), bl
,
8644 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8645 r
= queue_transaction(store
, ch
, std::move(t
));
8649 // write small into the gap
8650 ObjectStore::Transaction t
;
8653 bl
.append(std::string(3, 'b'));
8654 t
.write(cid
, hoid
, block_size
+ 1, bl
.length(), bl
,
8655 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
8656 r
= queue_transaction(store
, ch
, std::move(t
));
8660 // We need to issue a read to trigger cache stat update that refresh
8661 // perf counters. additionally we need to wait some time for mempool
8662 // thread to update stats.
8664 bufferlist bl
, expected
;
8665 r
= store
->read(ch
, hoid
, 0, block_size
* 3, bl
);
8666 ASSERT_EQ(r
, (int)block_size
* 3);
8667 expected
.append(string(block_size
, 'a'));
8668 expected
.append(string(1, 0));
8669 expected
.append(string(3, 'b'));
8670 expected
.append(string(block_size
- 4, 0));
8671 expected
.append(string(block_size
, 'a'));
8672 ASSERT_TRUE(bl_eq(expected
, bl
));
8674 ASSERT_EQ(logger
->get(l_bluestore_blobs
), 1u);
8675 ASSERT_EQ(logger
->get(l_bluestore_extents
), 3u);
8678 ObjectStore::Transaction t
;
8679 t
.remove(cid
, hoid
);
8680 t
.remove_collection(cid
);
8681 cerr
<< "Cleaning" << std::endl
;
8682 r
= queue_transaction(store
, ch
, std::move(t
));
8687 // The test case to reproduce an issue when write happens
8688 // to a zero space between the extents sharing the same spanning blob
8689 // with unloaded shard map.
8690 // Second extent might be filled with zeros this way due to wrong result
8691 // returned by has_any_extents() call in do_write_small. The latter is caused
8692 // by incompletly loaded extent map.
8693 TEST_P(StoreTestSpecificAUSize
, SmallWriteOnShardedExtents
) {
8694 if (string(GetParam()) != "bluestore")
8697 size_t block_size
= 0x10000;
8698 StartDeferred(block_size
);
8700 SetVal(g_conf(), "bluestore_csum_type", "xxhash64");
8701 SetVal(g_conf(), "bluestore_max_blob_size", "524288"); // for sure
8703 g_conf().apply_changes(nullptr);
8707 ghobject_t
hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
8708 auto ch
= store
->create_new_collection(cid
);
8711 ObjectStore::Transaction t
;
8712 t
.create_collection(cid
, 0);
8713 r
= queue_transaction(store
, ch
, std::move(t
));
8717 //doing some tricks to have sharded extents/spanning objects
8718 ObjectStore::Transaction t
;
8721 bl
.append(std::string(0x80000, 'a'));
8722 t
.write(cid
, hoid1
, 0, bl
.length(), bl
, 0);
8723 t
.zero(cid
, hoid1
, 0x719e0, 0x75b0 );
8724 r
= queue_transaction(store
, ch
, std::move(t
));
8727 bl2
.append(std::string(0x70000, 'b'));
8728 t
.write(cid
, hoid1
, 0, bl2
.length(), bl2
, 0);
8729 t
.zero(cid
, hoid1
, 0, 0x50000);
8730 r
= queue_transaction(store
, ch
, std::move(t
));
8737 ch
= store
->open_collection(cid
);
8740 // do a write to zero space in between some extents sharing the same blob
8741 ObjectStore::Transaction t
;
8744 bl
.append(std::string(0x6520, 'c'));
8745 t
.write(cid
, hoid1
, 0x71c00, bl
.length(), bl
, 0);
8747 r
= queue_transaction(store
, ch
, std::move(t
));
8752 ObjectStore::Transaction t
;
8753 bufferlist bl
, expected
;
8755 r
= store
->read(ch
, hoid1
, 0x70000, 0x9c00, bl
);
8756 ASSERT_EQ(r
, (int)0x9c00);
8757 expected
.append(string(0x19e0, 'a'));
8758 expected
.append(string(0x220, 0));
8759 expected
.append(string(0x6520, 'c'));
8760 expected
.append(string(0xe70, 0));
8761 expected
.append(string(0xc70, 'a'));
8762 ASSERT_TRUE(bl_eq(expected
, bl
));
8768 ObjectStore::Transaction t
;
8769 t
.remove(cid
, hoid1
);
8770 t
.remove_collection(cid
);
8771 cerr
<< "Cleaning" << std::endl
;
8772 r
= queue_transaction(store
, ch
, std::move(t
));
8777 TEST_P(StoreTestSpecificAUSize
, ReproBug56488Test
) {
8779 if (string(GetParam()) != "bluestore")
8782 cout
<< "SKIP: no deferred" << std::endl
;
8786 size_t alloc_size
= 65536;
8787 size_t write_size
= 4096;
8788 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
8789 SetVal(g_conf(), "bluestore_block_db_create", "true");
8790 SetVal(g_conf(), "bluestore_block_db_size", stringify(1 << 30).c_str());
8792 g_conf().apply_changes(nullptr);
8793 StartDeferred(alloc_size
);
8797 const PerfCounters
* logger
= store
->get_perf_counters();
8799 ObjectStore::CollectionHandle ch
= store
->create_new_collection(cid
);
8801 ObjectStore::Transaction t
;
8802 t
.create_collection(cid
, 0);
8803 r
= queue_transaction(store
, ch
, std::move(t
));
8807 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
8809 ObjectStore::Transaction t
;
8811 r
= queue_transaction(store
, ch
, std::move(t
));
8815 auto issued_dw
= logger
->get(l_bluestore_issued_deferred_writes
);
8816 auto issued_dw_bytes
= logger
->get(l_bluestore_issued_deferred_write_bytes
);
8818 ObjectStore::Transaction t
;
8820 bl
.append(std::string(write_size
, 'x'));
8821 t
.write(cid
, hoid
, 0, bl
.length(), bl
,
8822 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8823 r
= queue_transaction(store
, ch
, std::move(t
));
8826 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), issued_dw
+ 1);
8827 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
),
8828 issued_dw_bytes
+ write_size
);
8831 ghobject_t
hoid(hobject_t("test-a", "", CEPH_NOSNAP
, 0, -1, ""));
8833 ObjectStore::Transaction t
;
8835 r
= queue_transaction(store
, ch
, std::move(t
));
8839 auto issued_dw
= logger
->get(l_bluestore_issued_deferred_writes
);
8840 auto issued_dw_bytes
= logger
->get(l_bluestore_issued_deferred_write_bytes
);
8842 ObjectStore::Transaction t
;
8844 bl
.append(std::string(write_size
* 2, 'x'));
8845 t
.write(cid
, hoid
, alloc_size
- write_size
, bl
.length(), bl
,
8846 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
8847 r
= queue_transaction(store
, ch
, std::move(t
));
8850 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_writes
), issued_dw
+ 2);
8851 ASSERT_EQ(logger
->get(l_bluestore_issued_deferred_write_bytes
),
8852 issued_dw_bytes
+ write_size
* 2);
8855 ObjectStore::Transaction t
;
8856 ghobject_t
hoid(hobject_t("test", "", CEPH_NOSNAP
, 0, -1, ""));
8857 t
.remove(cid
, hoid
);
8858 ghobject_t
hoid_a(hobject_t("test-a", "", CEPH_NOSNAP
, 0, -1, ""));
8859 t
.remove(cid
, hoid_a
);
8860 t
.remove_collection(cid
);
8861 cerr
<< "Cleaning" << std::endl
;
8862 r
= queue_transaction(store
, ch
, std::move(t
));
8867 #endif //#if defined(WITH_BLUESTORE)
8869 TEST_P(StoreTest
, KVDBHistogramTest
) {
8870 if (string(GetParam()) != "bluestore")
8876 string
base("testobj.");
8878 bufferptr
ap(0x1000);
8879 memset(ap
.c_str(), 'a', 0x1000);
8881 auto ch
= store
->create_new_collection(cid
);
8883 ObjectStore::Transaction t
;
8884 t
.create_collection(cid
, 0);
8885 r
= queue_transaction(store
, ch
, std::move(t
));
8888 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
8889 ObjectStore::Transaction t
;
8891 snprintf(buf
, sizeof(buf
), "%d", i
);
8892 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
8893 t
.write(cid
, hoid
, 0, 0x1000, a
);
8894 r
= queue_transaction(store
, ch
, std::move(t
));
8898 std::unique_ptr
<Formatter
> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
8899 store
->generate_db_histogram(f
.get());
8904 TEST_P(StoreTest
, KVDBStatsTest
) {
8905 if (string(GetParam()) != "bluestore")
8908 SetVal(g_conf(), "rocksdb_perf", "true");
8909 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
8910 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
8911 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
8912 g_ceph_context
->_conf
.apply_changes(nullptr);
8913 int r
= store
->umount();
8915 r
= store
->mount(); //to force rocksdb stats
8920 string
base("testobj.");
8922 bufferptr
ap(0x1000);
8923 memset(ap
.c_str(), 'a', 0x1000);
8925 auto ch
= store
->create_new_collection(cid
);
8927 ObjectStore::Transaction t
;
8928 t
.create_collection(cid
, 0);
8929 r
= queue_transaction(store
, ch
, std::move(t
));
8932 for (int i
= 0; i
< NUM_OBJS
; ++i
) {
8933 ObjectStore::Transaction t
;
8935 snprintf(buf
, sizeof(buf
), "%d", i
);
8936 ghobject_t
hoid(hobject_t(sobject_t(base
+ string(buf
), CEPH_NOSNAP
)));
8937 t
.write(cid
, hoid
, 0, 0x1000, a
);
8938 r
= queue_transaction(store
, ch
, std::move(t
));
8942 std::unique_ptr
<Formatter
> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
8943 store
->get_db_statistics(f
.get());
8948 #if defined(WITH_BLUESTORE)
8949 TEST_P(StoreTestSpecificAUSize
, garbageCollection
) {
8952 int buf_len
= 256 * 1024;
8953 int overlap_offset
= 64 * 1024;
8954 int write_offset
= buf_len
;
8955 if (string(GetParam()) != "bluestore")
8958 cout
<< "SKIP: assertions about allocations need to be adjusted" << std::endl
;
8962 #define WRITE_AT(offset, _length) {\
8963 ObjectStore::Transaction t;\
8964 if ((uint64_t)_length != bl.length()) { \
8965 buffer::ptr p(bl.c_str(), _length);\
8967 bl_tmp.push_back(p);\
8968 t.write(cid, hoid, offset, bl_tmp.length(), bl_tmp);\
8970 t.write(cid, hoid, offset, bl.length(), bl);\
8972 r = queue_transaction(store, ch, std::move(t));\
8976 StartDeferred(65536);
8978 SetVal(g_conf(), "bluestore_compression_max_blob_size", "524288");
8979 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
8980 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
8981 SetVal(g_conf(), "bluestore_compression_mode", "force");
8982 g_conf().apply_changes(nullptr);
8984 auto ch
= store
->create_new_collection(cid
);
8986 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
8989 r
= store
->read(ch
, hoid
, 0, 5, in
);
8990 ASSERT_EQ(-ENOENT
, r
);
8993 ObjectStore::Transaction t
;
8994 t
.create_collection(cid
, 0);
8995 cerr
<< "Creating collection " << cid
<< std::endl
;
8996 r
= queue_transaction(store
, ch
, std::move(t
));
9001 data
.resize(buf_len
);
9005 bool exists
= store
->exists(ch
, hoid
);
9006 ASSERT_TRUE(!exists
);
9008 ObjectStore::Transaction t
;
9010 cerr
<< "Creating object " << hoid
<< std::endl
;
9011 r
= queue_transaction(store
, ch
, std::move(t
));
9014 exists
= store
->exists(ch
, hoid
);
9015 ASSERT_EQ(true, exists
);
9019 for(size_t i
= 0; i
< data
.size(); i
++)
9025 struct store_statfs_t statfs
;
9026 WRITE_AT(0, buf_len
);
9027 int r
= store
->statfs(&statfs
);
9029 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
9032 struct store_statfs_t statfs
;
9033 WRITE_AT(write_offset
- 2 * overlap_offset
, buf_len
);
9034 int r
= store
->statfs(&statfs
);
9036 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
9037 const PerfCounters
* counters
= store
->get_perf_counters();
9038 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0u);
9042 struct store_statfs_t statfs
;
9043 WRITE_AT(write_offset
- overlap_offset
, buf_len
);
9044 int r
= store
->statfs(&statfs
);
9046 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
9047 const PerfCounters
* counters
= store
->get_perf_counters();
9048 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x10000u
);
9051 struct store_statfs_t statfs
;
9052 WRITE_AT(write_offset
- 3 * overlap_offset
, buf_len
);
9053 int r
= store
->statfs(&statfs
);
9055 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
9056 const PerfCounters
* counters
= store
->get_perf_counters();
9057 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
9060 struct store_statfs_t statfs
;
9061 WRITE_AT(write_offset
+ 1, overlap_offset
-1);
9062 int r
= store
->statfs(&statfs
);
9064 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x20000);
9065 const PerfCounters
* counters
= store
->get_perf_counters();
9066 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x20000u
);
9069 struct store_statfs_t statfs
;
9070 WRITE_AT(write_offset
+ 1, overlap_offset
);
9071 int r
= store
->statfs(&statfs
);
9073 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
9074 const PerfCounters
* counters
= store
->get_perf_counters();
9075 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x3ffffu
);
9078 struct store_statfs_t statfs
;
9079 WRITE_AT(0, buf_len
-1);
9080 int r
= store
->statfs(&statfs
);
9082 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
9083 const PerfCounters
* counters
= store
->get_perf_counters();
9084 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
9086 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "1"); //forbid GC when saving = 0
9088 struct store_statfs_t statfs
;
9089 WRITE_AT(1, overlap_offset
-2);
9090 WRITE_AT(overlap_offset
* 2 + 1, overlap_offset
-2);
9091 int r
= store
->statfs(&statfs
);
9093 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x10000);
9094 const PerfCounters
* counters
= store
->get_perf_counters();
9095 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40001u
);
9098 struct store_statfs_t statfs
;
9099 WRITE_AT(overlap_offset
+ 1, overlap_offset
-2);
9100 int r
= store
->statfs(&statfs
);
9102 ASSERT_EQ(statfs
.data_compressed_allocated
, 0x0);
9103 const PerfCounters
* counters
= store
->get_perf_counters();
9104 ASSERT_EQ(counters
->get(l_bluestore_gc_merged
), 0x40007u
);
9107 ObjectStore::Transaction t
;
9108 t
.remove(cid
, hoid
);
9109 cerr
<< "Cleaning" << std::endl
;
9110 r
= queue_transaction(store
, ch
, std::move(t
));
9116 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice
) {
9117 if (string(GetParam()) != "bluestore")
9120 SetVal(g_conf(), "bluestore_block_size",
9121 stringify(0x280005000).c_str()); //10 Gb + 4K
9122 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9123 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9124 StartDeferred(0x4000);
9126 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
9131 TEST_P(StoreTestSpecificAUSize
, fsckOnUnalignedDevice2
) {
9132 if (string(GetParam()) != "bluestore")
9135 SetVal(g_conf(), "bluestore_block_size",
9136 stringify(0x280005000).c_str()); //10 Gb + 20K
9137 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9138 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9139 StartDeferred(0x1000);
9141 ASSERT_EQ(store
->fsck(false), 0); // do fsck explicitly
9146 ghobject_t
make_object(const char* name
, int64_t pool
) {
9147 sobject_t soid
{name
, CEPH_NOSNAP
};
9148 uint32_t hash
= std::hash
<sobject_t
>{}(soid
);
9149 return ghobject_t
{hobject_t
{soid
, "", hash
, pool
, ""}};
9153 TEST_P(StoreTestSpecificAUSize
, BluestoreRepairTest
) {
9154 if (string(GetParam()) != "bluestore")
9157 cout
<< "TODO: repair mismatched write pointer (+ dead bytes mismatch)" << std::endl
;
9160 const size_t offs_base
= 65536 / 2;
9163 // Now we need standalone db to pass "false free fix" section below
9164 // Due to new BlueFS allocation model (single allocator for main device)
9165 // it might cause "false free" blob overwrite by BlueFS/DB stuff
9166 // and hence fail the test case and corrupt data.
9169 SetVal(g_conf(), "bluestore_block_db_create", "true");
9170 SetVal(g_conf(), "bluestore_block_db_size", "4294967296");
9172 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9173 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9174 SetVal(g_conf(), "bluestore_max_blob_size",
9175 stringify(2 * offs_base
).c_str());
9176 SetVal(g_conf(), "bluestore_extent_map_shard_max_size", "12000");
9178 StartDeferred(0x10000);
9180 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9182 // fill the store with some data
9183 const uint64_t pool
= 555;
9184 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9185 auto ch
= store
->create_new_collection(cid
);
9187 ghobject_t hoid
= make_object("Object 1", pool
);
9188 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
9189 ghobject_t hoid2
= make_object("Object 2", pool
);
9190 ghobject_t hoid_cloned
= hoid2
;
9191 hoid_cloned
.hobj
.snap
= 1;
9192 ghobject_t hoid3
= make_object("Object 3", pool
);
9193 ghobject_t hoid3_cloned
= hoid3
;
9194 hoid3_cloned
.hobj
.snap
= 1;
9196 bl
.append("1234512345");
9198 const size_t repeats
= 16;
9200 auto ch
= store
->create_new_collection(cid
);
9201 cerr
<< "create collection + write" << std::endl
;
9202 ObjectStore::Transaction t
;
9203 t
.create_collection(cid
, 0);
9204 for( auto i
= 0ul; i
< repeats
; ++i
) {
9205 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
9206 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
9208 for( auto i
= 0ul; i
< repeats
; ++i
) {
9209 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
9211 t
.clone(cid
, hoid2
, hoid_cloned
);
9213 r
= queue_transaction(store
, ch
, std::move(t
));
9218 bool err_was_injected
= false;
9219 //////////// leaked pextent fix ////////////
9220 cerr
<< "fix leaked pextents" << std::endl
;
9221 ASSERT_EQ(bstore
->fsck(false), 0);
9222 ASSERT_EQ(bstore
->repair(false), 0);
9224 if (!bstore
->has_null_manager()) {
9225 bstore
->inject_leaked(0x30000);
9226 err_was_injected
= true;
9230 if (err_was_injected
) {
9231 ASSERT_EQ(bstore
->fsck(false), 1);
9233 ASSERT_EQ(bstore
->repair(false), 0);
9234 ASSERT_EQ(bstore
->fsck(false), 0);
9236 //////////// false free fix ////////////
9237 cerr
<< "fix false free pextents" << std::endl
;
9239 if (!bstore
->has_null_manager()) {
9240 bstore
->inject_false_free(cid
, hoid
);
9241 err_was_injected
= true;
9244 if (err_was_injected
) {
9245 ASSERT_EQ(bstore
->fsck(false), 2);
9246 ASSERT_EQ(bstore
->repair(false), 0);
9248 ASSERT_EQ(bstore
->fsck(false), 0);
9251 ///////// undecodable shared blob key / stray shared blob records ///////
9253 cerr
<< "undecodable shared blob key" << std::endl
;
9254 bstore
->inject_broken_shared_blob_key("undec1",
9256 bstore
->inject_broken_shared_blob_key("undecodable key 2",
9258 bstore
->inject_broken_shared_blob_key("undecodable key 3",
9261 ASSERT_EQ(bstore
->fsck(false), 3);
9262 ASSERT_EQ(bstore
->repair(false), 0);
9263 ASSERT_EQ(bstore
->fsck(false), 0);
9265 cerr
<< "misreferencing" << std::endl
;
9267 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, 0);
9268 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, (offs_base
* repeats
) / 2);
9269 bstore
->inject_misreference(cid
, hoid
, cid
, hoid_dup
, offs_base
* (repeats
-1) );
9270 int expected_errors
= bstore
->has_null_manager() ? 3 : 6;
9272 ASSERT_EQ(bstore
->fsck(false), expected_errors
);
9273 ASSERT_EQ(bstore
->repair(false), 0);
9275 ASSERT_EQ(bstore
->fsck(true), 0);
9277 // reproducing issues #21040 & 20983
9278 SetVal(g_conf(), "bluestore_debug_inject_bug21040", "true");
9279 g_ceph_context
->_conf
.apply_changes(nullptr);
9282 cerr
<< "repro bug #21040" << std::endl
;
9284 auto ch
= store
->open_collection(cid
);
9286 ObjectStore::Transaction t
;
9287 bl
.append("0123456789012345");
9288 t
.write(cid
, hoid3
, offs_base
, bl
.length(), bl
);
9291 t
.write(cid
, hoid3
, 0, bl
.length(), bl
);
9293 r
= queue_transaction(store
, ch
, std::move(t
));
9297 ObjectStore::Transaction t
;
9298 t
.clone(cid
, hoid3
, hoid3_cloned
);
9299 r
= queue_transaction(store
, ch
, std::move(t
));
9304 // depending on statfs tracking we might meet or miss relevant error
9305 // hence error count >= 3
9306 ASSERT_GE(bstore
->fsck(false), 3);
9307 ASSERT_LE(bstore
->repair(false), 0);
9308 ASSERT_EQ(bstore
->fsck(false), 0);
9311 cerr
<< "Zombie spanning blob" << std::endl
;
9314 ghobject_t hoid4
= make_object("Object 4", pool
);
9315 auto ch
= store
->open_collection(cid
);
9318 string
s(0x1000, 'a');
9320 ObjectStore::Transaction t
;
9321 for(size_t i
= 0; i
< 0x10; i
++) {
9322 t
.write(cid
, hoid4
, i
* bl
.length(), bl
.length(), bl
);
9324 r
= queue_transaction(store
, ch
, std::move(t
));
9329 bstore
->inject_zombie_spanning_blob(cid
, hoid4
, 12345);
9330 bstore
->inject_zombie_spanning_blob(cid
, hoid4
, 23456);
9331 bstore
->inject_zombie_spanning_blob(cid
, hoid4
, 23457);
9335 ASSERT_EQ(bstore
->fsck(false), 1);
9336 ASSERT_LE(bstore
->repair(false), 0);
9337 ASSERT_EQ(bstore
->fsck(false), 0);
9340 //////////// verify invalid statfs ///////////
9341 cerr
<< "fix invalid statfs" << std::endl
;
9342 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
9344 "bluestore_debug_inject_allocation_from_file_failure", "1");
9345 store_statfs_t statfs0
;
9346 store_statfs_t statfs
;
9348 ASSERT_EQ(bstore
->statfs(&statfs0
), 0);
9350 statfs
.allocated
+= 0x10000;
9351 statfs
.data_stored
+= 0x10000;
9352 ASSERT_FALSE(statfs0
== statfs
);
9353 // this enforces global stats usage
9354 bstore
->inject_statfs("bluestore_statfs", statfs
);
9357 ASSERT_GE(bstore
->fsck(false), 1); // global stats mismatch might omitted when
9358 // NCB restore is applied. Hence using >= for
9360 ASSERT_EQ(bstore
->repair(false), 0);
9361 ASSERT_EQ(bstore
->fsck(false), 0);
9362 ASSERT_EQ(bstore
->mount(), 0);
9363 ASSERT_EQ(bstore
->statfs(&statfs
), 0);
9364 // adjust free/internal meta space to success in comparison
9365 statfs0
.available
= statfs
.available
;
9366 statfs0
.internal_metadata
= statfs
.internal_metadata
;
9367 ASSERT_EQ(statfs0
, statfs
);
9370 "bluestore_debug_inject_allocation_from_file_failure", "0");
9371 cerr
<< "fix invalid statfs2" << std::endl
;
9372 ASSERT_EQ(bstore
->statfs(&statfs0
), 0);
9374 statfs
.allocated
+= 0x20000;
9375 statfs
.data_stored
+= 0x20000;
9376 ASSERT_FALSE(statfs0
== statfs
);
9377 // this enforces global stats usage
9378 bstore
->inject_statfs("bluestore_statfs", statfs
);
9381 ASSERT_EQ(bstore
->fsck(false), 2);
9382 ASSERT_EQ(bstore
->repair(false), 0);
9383 ASSERT_EQ(bstore
->fsck(false), 0);
9384 ASSERT_EQ(bstore
->mount(), 0);
9385 ASSERT_EQ(bstore
->statfs(&statfs
), 0);
9386 // adjust free/internal meta space to success in comparison
9387 statfs0
.available
= statfs
.available
;
9388 statfs0
.internal_metadata
= statfs
.internal_metadata
;
9389 ASSERT_EQ(statfs0
, statfs
);
9391 cerr
<< "Completing" << std::endl
;
9394 TEST_P(StoreTestSpecificAUSize
, BluestoreBrokenZombieRepairTest
) {
9395 if (string(GetParam()) != "bluestore")
9398 cout
<< "SKIP: smr repair is different" << std::endl
;
9401 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9402 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9404 StartDeferred(0x10000);
9406 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9410 cerr
<< "initializing" << std::endl
;
9412 const size_t col_count
= 16;
9413 const size_t obj_count
= 1024;
9414 ObjectStore::CollectionHandle ch
[col_count
];
9415 ghobject_t hoid
[col_count
][obj_count
];
9417 unique_ptr
<coll_t
> cid
[col_count
];
9419 for (size_t i
= 0; i
< col_count
; i
++) {
9420 cid
[i
].reset(new coll_t(spg_t(pg_t(0, i
), shard_id_t::NO_SHARD
)));
9421 ch
[i
] = store
->create_new_collection(*cid
[i
]);
9422 for (size_t j
= 0; j
< obj_count
; j
++) {
9423 hoid
[i
][j
] = make_object(stringify(j
).c_str(), i
);
9427 for (size_t i
= 0; i
< col_count
; i
++) {
9428 ObjectStore::Transaction t
;
9429 t
.create_collection(*cid
[i
], 0);
9430 r
= queue_transaction(store
, ch
[i
], std::move(t
));
9433 cerr
<< "onode preparing" << std::endl
;
9435 string
s(0x1000, 'a');
9438 for (size_t i
= 0; i
< col_count
; i
++) {
9439 for (size_t j
= 0; j
< obj_count
; j
++) {
9440 ObjectStore::Transaction t
;
9441 t
.write(*cid
[i
], hoid
[i
][j
], bl
.length(), bl
.length(), bl
);
9442 r
= queue_transaction(store
, ch
[i
], std::move(t
));
9446 cerr
<< "Zombie spanning blob injection" << std::endl
;
9450 for (size_t i
= 0; i
< col_count
; i
++) {
9451 for (size_t j
= 0; j
< obj_count
; j
++) {
9452 bstore
->inject_zombie_spanning_blob(*cid
[i
], hoid
[i
][j
], 12345);
9456 cerr
<< "fscking/fixing" << std::endl
;
9458 ASSERT_EQ(bstore
->fsck(false), col_count
* obj_count
);
9459 ASSERT_LE(bstore
->quick_fix(), 0);
9460 ASSERT_EQ(bstore
->fsck(false), 0);
9463 cerr
<< "Completing" << std::endl
;
9467 TEST_P(StoreTestSpecificAUSize
, BluestoreRepairSharedBlobTest
) {
9468 if (string(GetParam()) != "bluestore")
9471 cout
<< "TODO: repair mismatched write pointer (+ dead bytes mismatch)" << std::endl
;
9475 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9476 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9478 const size_t block_size
= 0x1000;
9479 StartDeferred(block_size
);
9481 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9483 // fill the store with some data
9484 const uint64_t pool
= 555;
9485 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9486 auto ch
= store
->create_new_collection(cid
);
9488 ghobject_t hoid
= make_object("Object 1", pool
);
9489 ghobject_t hoid_cloned
= hoid
;
9490 hoid_cloned
.hobj
.snap
= 1;
9491 ghobject_t hoid2
= make_object("Object 2", pool
);
9493 string
s(block_size
, 1);
9498 ObjectStore::Transaction t
;
9499 t
.create_collection(cid
, 0);
9500 r
= queue_transaction(store
, ch
, std::move(t
));
9504 // check the scenario when shared blob contains
9505 // references to extents from two objects which don't overlapp
9508 cerr
<< "introduce 2 non-overlapped extents in a shared blob"
9511 ObjectStore::Transaction t
;
9512 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
9513 t
.write(cid
, hoid2
, 0, bl
.length(), bl
); // to make a gap in allocations
9514 t
.write(cid
, hoid
, block_size
* 2 , bl
.length(), bl
);
9515 t
.clone(cid
, hoid
, hoid_cloned
);
9516 t
.zero(cid
, hoid
, 0, bl
.length());
9517 t
.zero(cid
, hoid_cloned
, block_size
* 2, bl
.length());
9518 r
= queue_transaction(store
, ch
, std::move(t
));
9525 _key_encode_u64(1, &key
);
9526 bluestore_shared_blob_t
sb(1);
9527 sb
.ref_map
.get(0x822000, block_size
);
9528 sb
.ref_map
.get(0x824000, block_size
);
9529 sb
.ref_map
.get(0x824000, block_size
);
9532 bstore
->inject_broken_shared_blob_key(key
, bl
);
9535 ASSERT_EQ(bstore
->fsck(false), 2);
9536 ASSERT_EQ(bstore
->repair(false), 0);
9537 ASSERT_EQ(bstore
->fsck(false), 0);
9539 cerr
<< "Completing" << std::endl
;
9543 TEST_P(StoreTestSpecificAUSize
, BluestoreBrokenNoSharedBlobRepairTest
) {
9544 if (string(GetParam()) != "bluestore")
9547 cout
<< "SKIP: smr repair is different" << std::endl
;
9551 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9552 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9554 StartDeferred(0x10000);
9556 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9561 cerr
<< "initializing" << std::endl
;
9563 const uint64_t pool
= 555;
9564 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9565 auto ch
= store
->create_new_collection(cid
);
9567 ghobject_t hoid
= make_object("Object", pool
);
9568 ghobject_t hoid_cloned
= hoid
;
9569 hoid_cloned
.hobj
.snap
= 1;
9572 ObjectStore::Transaction t
;
9573 t
.create_collection(cid
, 0);
9574 r
= queue_transaction(store
, ch
, std::move(t
));
9578 ObjectStore::Transaction t
;
9580 bl
.append("0123456789012345");
9581 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
9583 r
= queue_transaction(store
, ch
, std::move(t
));
9587 ObjectStore::Transaction t
;
9588 t
.clone(cid
, hoid
, hoid_cloned
);
9589 r
= queue_transaction(store
, ch
, std::move(t
));
9593 // injecting an error and checking
9594 cerr
<< "injecting" << std::endl
;
9595 sleep(3); // need some time for the previous write to land
9596 bstore
->inject_no_shared_blob_key();
9597 bstore
->inject_stray_shared_blob_key(12345678);
9600 cerr
<< "fscking/fixing" << std::endl
;
9601 // we need to check for null-manager before umount()
9602 bool has_null_manager
= bstore
->has_null_manager();
9604 // depending on the allocation map's source we can
9605 // either observe or don't observe an additional
9606 // extent leak detection. Hence adjusting the expected
9608 size_t expected_error_count
=
9610 4: // 4 sb ref mismatch errors [+ 1 optional statfs, hence ASSERT_GE]
9611 7; // 4 sb ref mismatch errors + 1 statfs + 1 block leak + 1 non-free
9612 ASSERT_GE(bstore
->fsck(false), expected_error_count
);
9613 // repair might report less errors than fsck above showed
9614 // as some errors, e.g. statfs mismatch, are implicitly fixed
9615 // before the detection during the previous repair steps...
9616 ASSERT_LE(bstore
->repair(false), expected_error_count
);
9617 ASSERT_EQ(bstore
->fsck(false), 0);
9620 cerr
<< "Completing" << std::endl
;
9624 TEST_P(StoreTest
, BluestoreRepairGlobalStats
) {
9625 if (string(GetParam()) != "bluestore")
9627 const size_t offs_base
= 65536 / 2;
9629 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9631 // start with global stats
9632 bstore
->inject_global_statfs({});
9634 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
9637 // fill the store with some data
9638 const uint64_t pool
= 555;
9639 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9640 auto ch
= store
->create_new_collection(cid
);
9642 ghobject_t hoid
= make_object("Object 1", pool
);
9643 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
9644 ghobject_t hoid2
= make_object("Object 2", pool
);
9645 ghobject_t hoid_cloned
= hoid2
;
9646 hoid_cloned
.hobj
.snap
= 1;
9647 ghobject_t hoid3
= make_object("Object 3", pool
);
9648 ghobject_t hoid3_cloned
= hoid3
;
9649 hoid3_cloned
.hobj
.snap
= 1;
9651 bl
.append("1234512345");
9653 const size_t repeats
= 16;
9655 auto ch
= store
->create_new_collection(cid
);
9656 cerr
<< "create collection + write" << std::endl
;
9657 ObjectStore::Transaction t
;
9658 t
.create_collection(cid
, 0);
9659 for( auto i
= 0ul; i
< repeats
; ++i
) {
9660 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
9661 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
9663 for( auto i
= 0ul; i
< repeats
; ++i
) {
9664 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
9666 t
.clone(cid
, hoid2
, hoid_cloned
);
9668 r
= queue_transaction(store
, ch
, std::move(t
));
9674 // enable per-pool stats collection hence causing fsck to fail
9675 cerr
<< "per-pool statfs" << std::endl
;
9676 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
9677 g_ceph_context
->_conf
.apply_changes(nullptr);
9679 ASSERT_EQ(bstore
->fsck(false), 1);
9680 ASSERT_EQ(bstore
->repair(false), 0);
9681 ASSERT_EQ(bstore
->fsck(false), 0);
9686 TEST_P(StoreTest
, BluestoreRepairGlobalStatsFixOnMount
) {
9687 if (string(GetParam()) != "bluestore")
9689 const size_t offs_base
= 65536 / 2;
9691 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9693 // start with global stats
9694 bstore
->inject_global_statfs({});
9696 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
9699 // fill the store with some data
9700 const uint64_t pool
= 555;
9701 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9702 auto ch
= store
->create_new_collection(cid
);
9704 ghobject_t hoid
= make_object("Object 1", pool
);
9705 ghobject_t hoid_dup
= make_object("Object 1(dup)", pool
);
9706 ghobject_t hoid2
= make_object("Object 2", pool
);
9707 ghobject_t hoid_cloned
= hoid2
;
9708 hoid_cloned
.hobj
.snap
= 1;
9709 ghobject_t hoid3
= make_object("Object 3", pool
);
9710 ghobject_t hoid3_cloned
= hoid3
;
9711 hoid3_cloned
.hobj
.snap
= 1;
9713 bl
.append("1234512345");
9715 const size_t repeats
= 16;
9717 auto ch
= store
->create_new_collection(cid
);
9718 cerr
<< "create collection + write" << std::endl
;
9719 ObjectStore::Transaction t
;
9720 t
.create_collection(cid
, 0);
9721 for( auto i
= 0ul; i
< repeats
; ++i
) {
9722 t
.write(cid
, hoid
, i
* offs_base
, bl
.length(), bl
);
9723 t
.write(cid
, hoid_dup
, i
* offs_base
, bl
.length(), bl
);
9725 for( auto i
= 0ul; i
< repeats
; ++i
) {
9726 t
.write(cid
, hoid2
, i
* offs_base
, bl
.length(), bl
);
9728 t
.clone(cid
, hoid2
, hoid_cloned
);
9730 r
= queue_transaction(store
, ch
, std::move(t
));
9736 // enable per-pool stats collection hence causing fsck to fail
9737 cerr
<< "per-pool statfs" << std::endl
;
9738 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
9739 g_ceph_context
->_conf
.apply_changes(nullptr);
9741 ASSERT_EQ(bstore
->fsck(false), 1);
9743 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
9746 ASSERT_EQ(bstore
->fsck(false), 0);
9751 TEST_P(StoreTest
, BluestoreStatistics
) {
9752 if (string(GetParam()) != "bluestore")
9755 SetVal(g_conf(), "rocksdb_perf", "true");
9756 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
9757 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
9758 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
9761 SetVal(g_conf(), "bluestore_cache_size_ssd", "0");
9762 SetVal(g_conf(), "bluestore_cache_size_hdd", "0");
9763 SetVal(g_conf(), "bluestore_cache_size", "0");
9764 g_ceph_context
->_conf
.apply_changes(nullptr);
9766 int r
= store
->umount();
9771 BlueStore
* bstore
= NULL
;
9772 EXPECT_NO_THROW(bstore
= dynamic_cast<BlueStore
*> (store
.get()));
9775 ghobject_t
hoid(hobject_t("test_db_statistics", "", CEPH_NOSNAP
, 0, 0, ""));
9776 auto ch
= bstore
->create_new_collection(cid
);
9778 bl
.append("0123456789abcdefghi");
9780 ObjectStore::Transaction t
;
9781 t
.create_collection(cid
, 0);
9783 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
9784 cerr
<< "Write object" << std::endl
;
9785 r
= queue_transaction(bstore
, ch
, std::move(t
));
9789 bufferlist readback
;
9790 r
= store
->read(ch
, hoid
, 0, bl
.length(), readback
);
9791 ASSERT_EQ(static_cast<int>(bl
.length()), r
);
9792 ASSERT_TRUE(bl_eq(bl
, readback
));
9794 std::unique_ptr
<Formatter
> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
9795 EXPECT_NO_THROW(store
->get_db_statistics(f
.get()));
9800 TEST_P(StoreTest
, BluestoreStrayOmapDetection
)
9802 if (string(GetParam()) != "bluestore")
9805 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9806 const uint64_t pool
= 555;
9807 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9808 ghobject_t oid
= make_object("Object 1", pool
);
9809 ghobject_t oid2
= make_object("Object 2", pool
);
9810 // fill the store with some data
9811 auto ch
= store
->create_new_collection(cid
);
9815 ObjectStore::Transaction t
;
9816 t
.create_collection(cid
, 0);
9818 t
.omap_setheader(cid
, oid
, h
);
9820 t
.omap_setheader(cid
, oid2
, h
);
9821 int r
= queue_transaction(store
, ch
, std::move(t
));
9825 // inject stray omap
9826 bstore
->inject_stray_omap(123456, "somename");
9829 // check we detect injected stray omap..
9831 ASSERT_EQ(bstore
->fsck(false), 1);
9832 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9836 TEST_P(StoreTest
, BluestorePerPoolOmapFixOnMount
)
9838 if (string(GetParam()) != "bluestore")
9841 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
9842 const uint64_t pool
= 555;
9843 coll_t
cid(spg_t(pg_t(0, pool
), shard_id_t::NO_SHARD
));
9844 ghobject_t oid
= make_object("Object 1", pool
);
9845 ghobject_t oid2
= make_object("Object 2", pool
);
9846 // fill the store with some data
9847 auto ch
= store
->create_new_collection(cid
);
9848 map
<string
, bufferlist
> omap
;
9852 omap
["omap_key"].append("omap value");
9853 ObjectStore::Transaction t
;
9854 t
.create_collection(cid
, 0);
9856 t
.omap_setheader(cid
, oid
, h
);
9858 t
.omap_setheader(cid
, oid2
, h
);
9859 int r
= queue_transaction(store
, ch
, std::move(t
));
9863 // inject legacy omaps
9864 bstore
->inject_legacy_omap();
9865 bstore
->inject_legacy_omap(cid
, oid
);
9866 bstore
->inject_legacy_omap(cid
, oid2
);
9870 // check we injected an issue
9871 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
9872 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
9873 g_ceph_context
->_conf
.apply_changes(nullptr);
9874 ASSERT_EQ(bstore
->fsck(false), 3);
9876 // set autofix and mount
9877 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
9878 g_ceph_context
->_conf
.apply_changes(nullptr);
9882 // check we fixed it..
9883 ASSERT_EQ(bstore
->fsck(false), 0);
9887 // Now repro https://tracker.ceph.com/issues/43824
9889 // inject legacy omaps again
9890 bstore
->inject_legacy_omap();
9891 bstore
->inject_legacy_omap(cid
, oid
);
9892 bstore
->inject_legacy_omap(cid
, oid2
);
9895 // check we injected an issue
9896 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
9897 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
9898 g_ceph_context
->_conf
.apply_changes(nullptr);
9900 ch
= store
->open_collection(cid
);
9903 // write to onode which will partiall revert per-pool
9904 // omap repair done on mount due to #43824.
9905 // And object removal will leave stray per-pool omap recs
9907 ObjectStore::Transaction t
;
9910 //this triggers onode rec update and hence legacy omap
9911 t
.write(cid
, oid
, 0, bl
.length(), bl
);
9912 t
.remove(cid
, oid2
); // this will trigger stray per-pool omap
9913 int r
= queue_transaction(store
, ch
, std::move(t
));
9917 // check omap's been fixed.
9918 ASSERT_EQ(bstore
->fsck(false), 0); // this will fail without fix for #43824
9923 class hugepaged_raw
;
9925 static bool is_hugepaged(const bufferptr
& bp
)
9928 static_cast<const ceph::buffer_instrumentation::instrumented_bptr
&>(bp
);
9929 return ibp
.is_raw_marked
<BlockDevice::hugepaged_raw_marker_t
>();
9932 // disabled by default b/c of the dependency on huge page ssome test
9933 // environments might not offer without extra configuration.
9934 TEST_P(StoreTestDeferredSetup
, DISABLED_BluestoreHugeReads
)
9936 if (string(GetParam()) != "bluestore") {
9940 constexpr static size_t HUGE_BUFFER_SIZE
{2_M
};
9941 cout
<< "Configuring huge page pools" << std::endl
;
9943 SetVal(g_conf(), "bdev_read_preallocated_huge_buffers",
9944 fmt::format("{}=2", HUGE_BUFFER_SIZE
).c_str());
9945 SetVal(g_conf(), "bluestore_max_blob_size",
9946 std::to_string(HUGE_BUFFER_SIZE
).c_str());
9947 // let's verify the per-IOContext no-cache override
9948 SetVal(g_conf(), "bluestore_default_buffered_read", "true");
9949 g_ceph_context
->_conf
.apply_changes(nullptr);
9954 ghobject_t
hoid(hobject_t("test_huge_buffers", "", CEPH_NOSNAP
, 0, 0, ""));
9955 auto ch
= store
->create_new_collection(cid
);
9959 bufferptr bp
{HUGE_BUFFER_SIZE
};
9960 // non-zeros! Otherwise the deduplication will take place.
9961 ::memset(bp
.c_str(), 0x42, HUGE_BUFFER_SIZE
);
9962 bl
.push_back(std::move(bp
));
9963 ASSERT_EQ(bl
.get_num_buffers(), 1);
9964 ASSERT_EQ(bl
.length(), HUGE_BUFFER_SIZE
);
9967 cout
<< "Write object" << std::endl
;
9969 ObjectStore::Transaction t
;
9970 t
.create_collection(cid
, 0);
9972 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
9973 const auto r
= queue_transaction(store
, ch
, std::move(t
));
9977 // force cache clear
9979 EXPECT_EQ(store
->umount(), 0);
9980 EXPECT_EQ(store
->mount(), 0);
9981 ch
= store
->open_collection(cid
);
9984 // we want to extend the life-time of all huge paged-backed
9985 // bufferlists to validate the behaviour on pool exhaustion.
9986 bufferlist bl_1_huge
, bl_2_huge
, bl_3_plain
;
9988 cout
<< "Read object 1st time" << std::endl
;
9990 const auto r
= store
->read(ch
, hoid
, 0, HUGE_BUFFER_SIZE
, bl_1_huge
);
9991 ASSERT_EQ(static_cast<int>(HUGE_BUFFER_SIZE
), r
);
9992 ASSERT_TRUE(bl_eq(bl
, bl_1_huge
));
9993 ASSERT_EQ(bl_1_huge
.get_num_buffers(), 1);
9994 ASSERT_TRUE(is_hugepaged(bl_1_huge
.front()));
9997 cout
<< "Read object 2nd time" << std::endl
;
9999 const auto r
= store
->read(ch
, hoid
, 0, HUGE_BUFFER_SIZE
, bl_2_huge
);
10000 ASSERT_EQ(static_cast<int>(HUGE_BUFFER_SIZE
), r
);
10001 ASSERT_TRUE(bl_eq(bl
, bl_2_huge
));
10002 ASSERT_EQ(bl_2_huge
.get_num_buffers(), 1);
10003 ASSERT_TRUE(is_hugepaged(bl_2_huge
.front()));
10006 cout
<< "Read object 3rd time" << std::endl
;
10008 const auto r
= store
->read(ch
, hoid
, 0, HUGE_BUFFER_SIZE
, bl_3_plain
);
10009 ASSERT_EQ(static_cast<int>(HUGE_BUFFER_SIZE
), r
);
10010 ASSERT_TRUE(bl_eq(bl
, bl_3_plain
));
10011 ASSERT_EQ(bl_3_plain
.get_num_buffers(), 1);
10012 ASSERT_FALSE(is_hugepaged(bl_3_plain
.front()));
10016 TEST_P(StoreTest
, SpuriousReadErrorTest
) {
10017 if (string(GetParam()) != "bluestore")
10021 auto logger
= store
->get_perf_counters();
10023 auto ch
= store
->create_new_collection(cid
);
10024 ghobject_t
hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP
)));
10026 ObjectStore::Transaction t
;
10027 t
.create_collection(cid
, 0);
10028 cerr
<< "Creating collection " << cid
<< std::endl
;
10029 r
= queue_transaction(store
, ch
, std::move(t
));
10032 bufferlist test_data
;
10033 bufferptr
ap(0x2000);
10034 memset(ap
.c_str(), 'a', 0x2000);
10035 test_data
.append(ap
);
10037 ObjectStore::Transaction t
;
10038 t
.write(cid
, hoid
, 0, 0x2000, test_data
);
10039 r
= queue_transaction(store
, ch
, std::move(t
));
10041 // force cache clear
10042 EXPECT_EQ(store
->umount(), 0);
10043 EXPECT_EQ(store
->mount(), 0);
10045 ch
= store
->open_collection(cid
);
10047 cerr
<< "Injecting CRC error with no retry, expecting EIO" << std::endl
;
10048 SetVal(g_conf(), "bluestore_retry_disk_reads", "0");
10049 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "1");
10050 g_ceph_context
->_conf
.apply_changes(nullptr);
10053 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
10054 ASSERT_EQ(-EIO
, r
);
10055 ASSERT_EQ(logger
->get(l_bluestore_read_eio
), 1u);
10056 ASSERT_EQ(logger
->get(l_bluestore_reads_with_retries
), 0u);
10059 cerr
<< "Injecting CRC error with retries, expecting success after several retries" << std::endl
;
10060 SetVal(g_conf(), "bluestore_retry_disk_reads", "255");
10061 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "0.8");
10063 * Probabilistic test: 25 reads, each has a 80% chance of failing with 255 retries
10064 * Probability of at least one retried read: 1 - (0.2 ** 25) = 100% - 3e-18
10065 * Probability of a random test failure: 1 - ((1 - (0.8 ** 255)) ** 25) ~= 5e-24
10067 g_ceph_context
->_conf
.apply_changes(nullptr);
10069 for (int i
= 0; i
< 25; ++i
) {
10071 r
= store
->read(ch
, hoid
, 0, 0x2000, in
, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
10072 ASSERT_EQ(0x2000, r
);
10073 ASSERT_TRUE(bl_eq(test_data
, in
));
10075 ASSERT_GE(logger
->get(l_bluestore_reads_with_retries
), 1u);
10079 TEST_P(StoreTest
, mergeRegionTest
) {
10080 if (string(GetParam()) != "bluestore")
10083 SetVal(g_conf(), "bluestore_fsck_on_mount", "true");
10084 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
10085 SetVal(g_conf(), "bdev_debug_inflight_ios", "true");
10086 g_ceph_context
->_conf
.apply_changes(nullptr);
10088 uint32_t chunk_size
= g_ceph_context
->_conf
->bdev_block_size
;
10091 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
10092 auto ch
= store
->create_new_collection(cid
);
10094 ObjectStore::Transaction t
;
10095 t
.create_collection(cid
, 0);
10096 r
= queue_transaction(store
, ch
, std::move(t
));
10100 ObjectStore::Transaction t
;
10101 t
.touch(cid
, hoid
);
10102 cerr
<< "Creating object " << hoid
<< std::endl
;
10103 r
= queue_transaction(store
, ch
, std::move(t
));
10107 bl5
.append("abcde");
10108 uint64_t offset
= 0;
10109 { // 1. same region
10110 ObjectStore::Transaction t
;
10111 t
.write(cid
, hoid
, offset
, 5, bl5
);
10112 t
.write(cid
, hoid
, 0xa + offset
, 5, bl5
);
10113 t
.write(cid
, hoid
, 0x14 + offset
, 5, bl5
);
10114 r
= queue_transaction(store
, ch
, std::move(t
));
10117 { // 2. adjacent regions
10118 ObjectStore::Transaction t
;
10119 offset
= chunk_size
;
10120 t
.write(cid
, hoid
, offset
, 5, bl5
);
10121 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
10122 r
= queue_transaction(store
, ch
, std::move(t
));
10125 { // 3. front merge
10126 ObjectStore::Transaction t
;
10127 offset
= chunk_size
* 2;
10128 t
.write(cid
, hoid
, offset
, 5, bl5
);
10129 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, 5, bl5
);
10130 r
= queue_transaction(store
, ch
, std::move(t
));
10134 ObjectStore::Transaction t
;
10136 blc2
.append_zero(chunk_size
+ 2);
10138 offset
= chunk_size
* 3;
10139 t
.write(cid
, hoid
, offset
, chunk_size
+ 2, blc2
);
10140 t
.write(cid
, hoid
, offset
+ chunk_size
+ 3, 5, bl5
);
10141 r
= queue_transaction(store
, ch
, std::move(t
));
10144 { // 5. overlapping
10145 ObjectStore::Transaction t
;
10146 uint64_t final_len
= 0;
10147 offset
= chunk_size
* 10;
10149 bl2c2
.append_zero(chunk_size
* 2);
10150 t
.write(cid
, hoid
, offset
+ chunk_size
* 3 - 3, chunk_size
* 2, bl2c2
);
10151 bl2c2
.append_zero(2);
10152 t
.write(cid
, hoid
, offset
+ chunk_size
- 2, chunk_size
* 2 + 2, bl2c2
);
10153 r
= queue_transaction(store
, ch
, std::move(t
));
10156 final_len
= (offset
+ chunk_size
* 3 - 3) + (chunk_size
* 2);
10158 r
= store
->read(ch
, hoid
, 0, final_len
, bl
);
10159 ASSERT_EQ(final_len
, static_cast<uint64_t>(r
));
10163 TEST_P(StoreTest
, FixSMRWritePointer
) {
10164 if(string(GetParam()) != "bluestore")
10168 int r
= store
->umount();
10171 // copied from StoreTestFixture
10172 std::string path
= GetParam() + ".test_temp_dir"s
;
10174 std::string p
= path
+ "/block";
10175 BlockDevice
* bdev
= BlockDevice::create(g_ceph_context
, p
, nullptr, nullptr, nullptr, nullptr);
10178 ASSERT_EQ(true, bdev
->is_smr());
10180 std::vector
<uint64_t> wp
= bdev
->get_zones();
10181 uint64_t first_seq_zone
= bdev
->get_conventional_region_size() / bdev
->get_zone_size();
10183 IOContext
ioc(g_ceph_context
, NULL
, true);
10185 bl
.append(std::string(1024 * 1024, 'x'));
10186 r
= bdev
->aio_write(wp
[first_seq_zone
], bl
, &ioc
, false);
10188 bdev
->aio_submit(&ioc
);
10193 r
= store
->mount();
10198 TEST_P(StoreTestSpecificAUSize
, BluestoreEnforceHWSettingsHdd
) {
10199 if (string(GetParam()) != "bluestore")
10202 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
10203 StartDeferred(0x1000);
10207 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
10208 auto ch
= store
->create_new_collection(cid
);
10210 ObjectStore::Transaction t
;
10211 t
.create_collection(cid
, 0);
10212 cerr
<< "Creating collection " << cid
<< std::endl
;
10213 r
= queue_transaction(store
, ch
, std::move(t
));
10217 ObjectStore::Transaction t
;
10218 bufferlist bl
, orig
;
10219 string
s(g_ceph_context
->_conf
->bluestore_max_blob_size_hdd
, '0');
10221 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
10222 cerr
<< "write" << std::endl
;
10223 r
= queue_transaction(store
, ch
, std::move(t
));
10226 const PerfCounters
* logger
= store
->get_perf_counters();
10227 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 1u);
10231 TEST_P(StoreTestSpecificAUSize
, BluestoreEnforceHWSettingsSsd
) {
10232 if (string(GetParam()) != "bluestore")
10235 SetVal(g_conf(), "bluestore_debug_enforce_settings", "ssd");
10236 StartDeferred(0x1000);
10240 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
10241 auto ch
= store
->create_new_collection(cid
);
10243 ObjectStore::Transaction t
;
10244 t
.create_collection(cid
, 0);
10245 cerr
<< "Creating collection " << cid
<< std::endl
;
10246 r
= queue_transaction(store
, ch
, std::move(t
));
10250 ObjectStore::Transaction t
;
10251 bufferlist bl
, orig
;
10252 string
s(g_ceph_context
->_conf
->bluestore_max_blob_size_ssd
* 8, '0');
10254 t
.write(cid
, hoid
, 0, bl
.length(), bl
);
10255 cerr
<< "write" << std::endl
;
10256 r
= queue_transaction(store
, ch
, std::move(t
));
10259 const PerfCounters
* logger
= store
->get_perf_counters();
10260 ASSERT_EQ(logger
->get(l_bluestore_write_big_blobs
), 8u);
10264 TEST_P(StoreTestSpecificAUSize
, ReproNoBlobMultiTest
) {
10266 if(string(GetParam()) != "bluestore")
10269 cout
<< "SKIP (FIXME): bluestore gc does not seem to do the trick here" << std::endl
;
10273 SetVal(g_conf(), "bluestore_block_db_create", "true");
10274 SetVal(g_conf(), "bluestore_block_db_size", "4294967296");
10275 SetVal(g_conf(), "bluestore_block_size", "12884901888");
10276 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
10278 g_conf().apply_changes(nullptr);
10280 StartDeferred(65536);
10284 ghobject_t
hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP
)));
10285 ghobject_t hoid2
= hoid
;
10286 hoid2
.hobj
.snap
= 1;
10288 auto ch
= store
->create_new_collection(cid
);
10290 ObjectStore::Transaction t
;
10291 t
.create_collection(cid
, 0);
10292 cerr
<< "Creating collection " << cid
<< std::endl
;
10293 r
= queue_transaction(store
, ch
, std::move(t
));
10297 bool exists
= store
->exists(ch
, hoid
);
10298 ASSERT_TRUE(!exists
);
10300 ObjectStore::Transaction t
;
10301 t
.touch(cid
, hoid
);
10302 cerr
<< "Creating object " << hoid
<< std::endl
;
10303 r
= queue_transaction(store
, ch
, std::move(t
));
10306 exists
= store
->exists(ch
, hoid
);
10307 ASSERT_EQ(true, exists
);
10312 const int size
= 0x100;
10313 bufferptr
ap(size
);
10314 memset(ap
.c_str(), 'a', size
);
10317 uint64_t blob_size
= 524288;
10318 uint64_t total
= 0;
10319 for (i
= 0; i
<= 512; i
++) {
10320 offs
= 0 + i
* size
;
10321 ObjectStore::Transaction t
;
10322 ghobject_t hoid2
= hoid
;
10323 hoid2
.hobj
.snap
= i
+ 1;
10324 while (offs
< 128 * 1024 * 1024) {
10326 t
.write(cid
, hoid
, offs
, ap
.length(), bl
);
10328 total
+= ap
.length();
10330 t
.clone(cid
, hoid
, hoid2
);
10331 r
= queue_transaction(store
, ch
, std::move(t
));
10334 cerr
<< "Total written = " << total
<< std::endl
;
10337 cerr
<< "Finalizing" << std::endl
;
10338 const PerfCounters
* logger
= store
->get_perf_counters();
10339 ASSERT_GE(logger
->get(l_bluestore_gc_merged
), 1024*1024*1024);
10343 void doManySetAttr(ObjectStore
* store
,
10344 std::function
<void(ObjectStore
*)> do_check_fn
)
10346 MixedGenerator
gen(447);
10347 gen_type
rng(time(NULL
));
10348 coll_t
cid(spg_t(pg_t(0, 447), shard_id_t::NO_SHARD
));
10350 SyntheticWorkloadState
test_obj(store
, &gen
, &rng
, cid
, 0, 0, 0);
10352 size_t object_count
= 256;
10353 for (size_t i
= 0; i
< object_count
; ++i
) {
10354 if (!(i
% 10)) cerr
<< "seeding object " << i
<< std::endl
;
10357 for (size_t i
= 0; i
< object_count
; ++i
) {
10359 cerr
<< "Op " << i
<< std::endl
;
10360 test_obj
.print_internal_state();
10362 test_obj
.set_fixed_attrs(1024, 64, 4096); // 1024 attributes, 64 bytes name and 4K value
10364 test_obj
.wait_for_done();
10366 std::cout
<< "done" << std::endl
;
10367 do_check_fn(store
);
10368 AdminSocket
* admin_socket
= g_ceph_context
->get_admin_socket();
10369 ceph_assert(admin_socket
);
10371 ceph::bufferlist in
, out
;
10374 auto r
= admin_socket
->execute_command(
10375 { "{\"prefix\": \"bluefs stats\"}" },
10378 cerr
<< "failure querying: " << cpp_strerror(r
) << std::endl
;
10380 std::cout
<< std::string(out
.c_str(), out
.length()) << std::endl
;
10382 test_obj
.shutdown();
10385 TEST_P(StoreTestSpecificAUSize
, SpilloverTest
) {
10386 if (string(GetParam()) != "bluestore")
10389 cout
<< "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl
;
10393 SetVal(g_conf(), "bluestore_block_db_create", "true");
10394 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10395 SetVal(g_conf(), "bluestore_volume_selection_policy", "rocksdb_original");
10396 // original RocksDB settings used before https://github.com/ceph/ceph/pull/47221/
10397 // which enable BlueFS spillover.
10398 SetVal(g_conf(), "bluestore_rocksdb_options",
10399 "compression=kNoCompression,max_write_buffer_number=4,"
10400 "min_write_buffer_number_to_merge=1,recycle_log_file_num=4,"
10401 "write_buffer_size=268435456,writable_file_max_buffer_size=0,"
10402 "compaction_readahead_size=2097152,max_background_compactions=2,"
10403 "max_total_wal_size=1073741824");
10405 g_conf().apply_changes(nullptr);
10407 StartDeferred(65536);
10408 doManySetAttr(store
.get(),
10409 [&](ObjectStore
* _store
) {
10411 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
10412 ceph_assert(bstore
);
10414 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
10415 //experimentally it was discovered that this case results in 400+MB spillover
10416 //using lower 300MB threshold just to be safe enough
10417 std::cout
<< "DB used:" << logger
->get(l_bluefs_db_used_bytes
) << std::endl
;
10418 std::cout
<< "SLOW used:" << logger
->get(l_bluefs_slow_used_bytes
) << std::endl
;
10419 ASSERT_GE(logger
->get(l_bluefs_slow_used_bytes
), 16 * 1024 * 1024);
10421 struct store_statfs_t statfs
;
10422 osd_alert_list_t alerts
;
10423 int r
= store
->statfs(&statfs
, &alerts
);
10425 ASSERT_EQ(alerts
.count("BLUEFS_SPILLOVER"), 1);
10426 std::cout
<< "spillover_alert:" << alerts
.find("BLUEFS_SPILLOVER")->second
10432 TEST_P(StoreTestSpecificAUSize
, SpilloverFixedTest
) {
10433 if (string(GetParam()) != "bluestore")
10436 cout
<< "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl
;
10440 SetVal(g_conf(), "bluestore_block_db_create", "true");
10441 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10442 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
10443 SetVal(g_conf(), "bluestore_volume_selection_reserved", "1"); // just use non-zero to enable
10445 g_conf().apply_changes(nullptr);
10447 StartDeferred(65536);
10448 doManySetAttr(store
.get(),
10449 [&](ObjectStore
* _store
) {
10451 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
10452 ceph_assert(bstore
);
10454 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
10455 ASSERT_EQ(0, logger
->get(l_bluefs_slow_used_bytes
));
10460 TEST_P(StoreTestSpecificAUSize
, SpilloverFixed2Test
) {
10461 if (string(GetParam()) != "bluestore")
10464 cout
<< "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl
;
10468 SetVal(g_conf(), "bluestore_block_db_create", "true");
10469 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10470 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
10471 //default 2.0 factor results in too high threshold, using less value
10472 // that results in less but still present spillover.
10473 SetVal(g_conf(), "bluestore_volume_selection_reserved_factor", "0.5");
10475 g_conf().apply_changes(nullptr);
10477 StartDeferred(65536);
10478 doManySetAttr(store
.get(),
10479 [&](ObjectStore
* _store
) {
10481 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
10482 ceph_assert(bstore
);
10484 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
10485 ASSERT_LE(logger
->get(l_bluefs_slow_used_bytes
), 300 * 1024 * 1024); // see SpilloverTest for 300MB choice rationale
10490 TEST_P(StoreTestSpecificAUSize
, SpilloverFixed3Test
) {
10491 if (string(GetParam()) != "bluestore")
10494 cout
<< "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl
;
10498 SetVal(g_conf(), "bluestore_block_db_create", "true");
10499 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10500 SetVal(g_conf(), "bluestore_volume_selection_policy", "fit_to_fast");
10502 g_conf().apply_changes(nullptr);
10504 StartDeferred(65536);
10505 doManySetAttr(store
.get(),
10506 [&](ObjectStore
* _store
) {
10508 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (_store
);
10509 ceph_assert(bstore
);
10511 const PerfCounters
* logger
= bstore
->get_bluefs_perf_counters();
10512 ASSERT_EQ(logger
->get(l_bluefs_slow_used_bytes
), 0); // reffering to SpilloverFixedTest
10517 TEST_P(StoreTestSpecificAUSize
, Ticket45195Repro
) {
10518 if (string(GetParam()) != "bluestore")
10524 SetVal(g_conf(), "bluestore_default_buffered_write", "true");
10525 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
10526 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
10527 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
10528 g_conf().apply_changes(nullptr);
10530 StartDeferred(0x1000);
10534 ghobject_t
hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP
)));
10535 auto ch
= store
->create_new_collection(cid
);
10537 ObjectStore::Transaction t
;
10538 t
.create_collection(cid
, 0);
10539 cerr
<< "Creating collection " << cid
<< std::endl
;
10540 r
= queue_transaction(store
, ch
, std::move(t
));
10544 size_t large_object_size
= 1 * 1024 * 1024;
10545 size_t expected_write_size
= 0x8000;
10546 ObjectStore::Transaction t
;
10547 t
.touch(cid
, hoid
);
10548 t
.set_alloc_hint(cid
, hoid
, large_object_size
, expected_write_size
,
10549 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
|
10550 CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY
);
10551 r
= queue_transaction(store
, ch
, std::move(t
));
10555 ObjectStore::Transaction t
;
10556 bufferlist bl
, orig
;
10557 string
s(0xc000, '0');
10559 t
.write(cid
, hoid
, 0xb000, bl
.length(), bl
);
10560 r
= queue_transaction(store
, ch
, std::move(t
));
10564 ObjectStore::Transaction t
;
10565 bufferlist bl
, orig
;
10566 string
s(0x10000, '1');
10568 t
.write(cid
, hoid
, 0x16000, bl
.length(), bl
);
10569 r
= queue_transaction(store
, ch
, std::move(t
));
10573 ObjectStore::Transaction t
;
10574 bufferlist bl
, orig
;
10575 string
s(0x4000, '1');
10577 t
.write(cid
, hoid
, 0x1b000, bl
.length(), bl
);
10578 r
= queue_transaction(store
, ch
, std::move(t
));
10582 r
= store
->read(ch
, hoid
, 0xb000, 0xb000, bl
);
10583 ASSERT_EQ(r
, 0xb000);
10588 ch
= store
->open_collection(cid
);
10590 ObjectStore::Transaction t
;
10591 bufferlist bl
, orig
;
10592 string
s(0xf000, '3');
10594 t
.write(cid
, hoid
, 0xf000, bl
.length(), bl
);
10595 cerr
<< "write4" << std::endl
;
10596 r
= queue_transaction(store
, ch
, std::move(t
));
10600 r
= store
->read(ch
, hoid
, 0xb000, 0x10000, bl
);
10601 ASSERT_EQ(r
, 0x10000);
10604 TEST_P(StoreTestOmapUpgrade
, WithOmapHeader
) {
10605 if (string(GetParam()) != "bluestore")
10608 SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
10609 g_conf().apply_changes(nullptr);
10612 int64_t poolid
= 11;
10613 coll_t
cid(spg_t(pg_t(1, poolid
), shard_id_t::NO_SHARD
));
10614 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, poolid
, ""));
10615 auto ch
= store
->create_new_collection(cid
);
10618 ObjectStore::Transaction t
;
10619 t
.create_collection(cid
, 0);
10620 r
= queue_transaction(store
, ch
, std::move(t
));
10624 map
<string
, bufferlist
> attrs
;
10625 bufferlist expected_header
;
10626 expected_header
.append("this is a header");
10628 ObjectStore::Transaction t
;
10629 t
.touch(cid
, hoid
);
10631 header
.append(expected_header
);
10632 t
.omap_setheader(cid
, hoid
, header
);
10633 map
<string
, bufferlist
> start_set
;
10635 bl
.append(string("value"));
10636 start_set
.emplace(string("key1"), bl
);
10637 t
.omap_setkeys(cid
, hoid
, start_set
);
10638 r
= queue_transaction(store
, ch
, std::move(t
));
10641 map
<string
,bufferlist
> res
;
10643 r
= store
->omap_get(ch
, hoid
, &h
, &res
);
10645 ASSERT_TRUE(bl_eq(h
, expected_header
));
10646 ASSERT_EQ(res
.size(), 1);
10647 ASSERT_EQ(res
.begin()->first
, "key1");
10650 ASSERT_EQ(store
->fsck(false), 0);
10651 SetVal(g_conf(), "bluestore_debug_legacy_omap", "false");
10652 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
10653 g_conf().apply_changes(nullptr);
10654 ASSERT_EQ(store
->fsck(false), 2);
10655 ASSERT_EQ(store
->quick_fix(), 0);
10657 ch
= store
->open_collection(cid
);
10659 map
<string
,bufferlist
> res
;
10661 r
= store
->omap_get(ch
, hoid
, &h
, &res
);
10663 ASSERT_EQ(res
.size(), 1);
10664 ASSERT_EQ(res
.begin()->first
, "key1");
10667 ObjectStore::Transaction t
;
10668 t
.remove(cid
, hoid
);
10669 t
.remove_collection(cid
);
10670 r
= queue_transaction(store
, ch
, std::move(t
));
10675 TEST_P(StoreTestSpecificAUSize
, BluefsWriteInSingleDiskEnvTest
) {
10676 if (string(GetParam()) != "bluestore")
10679 g_conf().apply_changes(nullptr);
10681 StartDeferred(0x1000);
10683 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
10684 ceph_assert(bstore
);
10685 bstore
->inject_bluefs_file("db.slow", "store_test_injection_slow", 1 << 20ul);
10686 bstore
->inject_bluefs_file("db.wal", "store_test_injection_wal", 1 << 20ul);
10687 bstore
->inject_bluefs_file("db", "store_test_injection_wal", 1 << 20ul);
10689 AdminSocket
* admin_socket
= g_ceph_context
->get_admin_socket();
10690 ceph_assert(admin_socket
);
10692 ceph::bufferlist in
, out
;
10694 auto r
= admin_socket
->execute_command(
10695 { "{\"prefix\": \"bluefs stats\"}" },
10698 cerr
<< "failure querying: " << cpp_strerror(r
) << std::endl
;
10700 std::cout
<< std::string(out
.c_str(), out
.length()) << std::endl
;
10704 TEST_P(StoreTestSpecificAUSize
, BluefsWriteInNoWalDiskEnvTest
) {
10705 if (string(GetParam()) != "bluestore")
10708 SetVal(g_conf(), "bluestore_block_db_path", "db");
10709 SetVal(g_conf(), "bluestore_block_db_size", stringify(1ull << 31).c_str());
10710 SetVal(g_conf(), "bluestore_block_db_create", "true");
10712 g_conf().apply_changes(nullptr);
10714 StartDeferred(0x1000);
10716 BlueStore
* bstore
= dynamic_cast<BlueStore
*> (store
.get());
10717 ceph_assert(bstore
);
10718 bstore
->inject_bluefs_file("db.slow", "store_test_injection_slow", 1 << 20ul);
10719 bstore
->inject_bluefs_file("db.wal", "store_test_injection_wal", 1 << 20ul);
10720 bstore
->inject_bluefs_file("db", "store_test_injection_wal", 1 << 20ul);
10722 AdminSocket
* admin_socket
= g_ceph_context
->get_admin_socket();
10723 ceph_assert(admin_socket
);
10725 ceph::bufferlist in
, out
;
10727 auto r
= admin_socket
->execute_command(
10728 { "{\"prefix\": \"bluefs stats\"}" },
10731 cerr
<< "failure querying: " << cpp_strerror(r
) << std::endl
;
10734 std::cout
<< std::string(out
.c_str(), out
.length()) << std::endl
;
10738 TEST_P(StoreTestOmapUpgrade
, NoOmapHeader
) {
10739 if (string(GetParam()) != "bluestore")
10742 SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
10743 g_conf().apply_changes(nullptr);
10746 int64_t poolid
= 11;
10747 coll_t
cid(spg_t(pg_t(1, poolid
), shard_id_t::NO_SHARD
));
10748 ghobject_t
hoid(hobject_t("tesomap", "", CEPH_NOSNAP
, 0, poolid
, ""));
10749 auto ch
= store
->create_new_collection(cid
);
10752 ObjectStore::Transaction t
;
10753 t
.create_collection(cid
, 0);
10754 r
= queue_transaction(store
, ch
, std::move(t
));
10758 map
<string
, bufferlist
> attrs
;
10760 ObjectStore::Transaction t
;
10761 t
.touch(cid
, hoid
);
10762 map
<string
, bufferlist
> start_set
;
10764 bl
.append(string("value"));
10765 start_set
.emplace(string("key1"), bl
);
10766 t
.omap_setkeys(cid
, hoid
, start_set
);
10767 r
= queue_transaction(store
, ch
, std::move(t
));
10770 map
<string
,bufferlist
> res
;
10772 r
= store
->omap_get(ch
, hoid
, &h
, &res
);
10774 ASSERT_EQ(h
.length(), 0);
10775 ASSERT_EQ(res
.size(), 1);
10776 ASSERT_EQ(res
.begin()->first
, "key1");
10779 ASSERT_EQ(store
->fsck(false), 0);
10780 SetVal(g_conf(), "bluestore_debug_legacy_omap", "false");
10781 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
10782 g_conf().apply_changes(nullptr);
10783 ASSERT_EQ(store
->fsck(false), 2);
10784 ASSERT_EQ(store
->quick_fix(), 0);
10786 ch
= store
->open_collection(cid
);
10788 map
<string
,bufferlist
> res
;
10790 r
= store
->omap_get(ch
, hoid
, &h
, &res
);
10792 ASSERT_EQ(res
.size(), 1);
10793 ASSERT_EQ(res
.begin()->first
, "key1");
10796 ObjectStore::Transaction t
;
10797 t
.remove(cid
, hoid
);
10798 t
.remove_collection(cid
);
10799 r
= queue_transaction(store
, ch
, std::move(t
));
10804 TEST_P(StoreTestOmapUpgrade
, LargeLegacyToPG
) {
10805 if (string(GetParam()) != "bluestore")
10808 SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
10809 g_conf().apply_changes(nullptr);
10814 ObjectStore::CollectionHandle ch
;
10817 cid
= coll_t(spg_t(pg_t(1, poolid
), shard_id_t::NO_SHARD
));
10818 ch
= store
->create_new_collection(cid
);
10821 ObjectStore::Transaction t
;
10822 t
.create_collection(cid
, 0);
10823 r
= queue_transaction(store
, ch
, std::move(t
));
10826 //ASSERT_EQ(false, g_conf().get_val<bool>("bluestore_debug_inject_upgrade_bug53062"));
10827 map
<string
, bufferlist
> attrs
;
10828 bufferlist expected_header
;
10829 expected_header
.append("this is a header");
10831 size_t object_count
= 1000;
10832 make_omap_data(object_count
, poolid
, cid
);
10833 //checking just written data
10834 check_omap_data(object_count
, poolid
, cid
);
10837 ASSERT_EQ(store
->fsck(false), 0);
10838 SetVal(g_conf(), "bluestore_debug_legacy_omap", "false");
10839 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
10840 g_conf().apply_changes(nullptr);
10841 ASSERT_EQ(store
->fsck(false), 1001);
10842 ASSERT_EQ(store
->quick_fix(), 0);
10844 ch
= store
->open_collection(cid
);
10846 //checking quick_fix() data
10847 check_omap_data(object_count
, poolid
, cid
);
10850 ObjectStore::Transaction t
;
10851 for (size_t o
= 0; o
< object_count
; o
++)
10853 std::string oid
= generate_monotonic_name(object_count
, o
, 3.71, 0.5);
10854 ghobject_t
hoid(hobject_t(oid
, "", CEPH_NOSNAP
, 0, poolid
, ""));
10855 t
.remove(cid
, hoid
);
10857 t
.remove_collection(cid
);
10858 r
= queue_transaction(store
, ch
, std::move(t
));
10863 #endif // WITH_BLUESTORE
10865 int main(int argc
, char **argv
) {
10866 auto args
= argv_to_vec(argc
, argv
);
10867 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
10868 CODE_ENVIRONMENT_UTILITY
,
10869 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
10870 common_init_finish(g_ceph_context
);
10872 for (auto& i
: args
) {
10873 if (i
== "--smr"s
) {
10874 #if defined(HAVE_LIBZBD)
10875 derr
<< "Adjusting tests for smr mode." << dendl
;
10878 derr
<< "smr mode selected, but support not compiled in" << dendl
;
10884 // make sure we can adjust any config settings
10885 g_ceph_context
->_conf
._clear_safe_to_start_threads();
10887 g_ceph_context
->_conf
.set_val_or_die("osd_journal_size", "400");
10888 g_ceph_context
->_conf
.set_val_or_die("filestore_index_retry_probability", "0.5");
10889 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_timeout", "1000");
10890 g_ceph_context
->_conf
.set_val_or_die("filestore_op_thread_suicide_timeout", "10000");
10891 //g_ceph_context->_conf.set_val_or_die("filestore_fiemap", "true");
10892 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mkfs", "false");
10893 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_mount", "false");
10894 g_ceph_context
->_conf
.set_val_or_die("bluestore_fsck_on_umount", "false");
10895 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_small_allocations", "4");
10896 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_freelist", "true");
10897 g_ceph_context
->_conf
.set_val_or_die("bluestore_clone_cow", "true");
10898 g_ceph_context
->_conf
.set_val_or_die("bluestore_max_alloc_size", "196608");
10899 // set small cache sizes so we see trimming during Synthetic tests
10900 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_hdd", "4000000");
10901 g_ceph_context
->_conf
.set_val_or_die("bluestore_cache_size_ssd", "4000000");
10902 g_ceph_context
->_conf
.set_val_or_die(
10903 "bluestore_debug_inject_allocation_from_file_failure", "0.66");
10905 // very short *_max prealloc so that we fall back to async submits
10906 g_ceph_context
->_conf
.set_val_or_die("bluestore_blobid_prealloc", "10");
10907 g_ceph_context
->_conf
.set_val_or_die("bluestore_nid_prealloc", "10");
10908 g_ceph_context
->_conf
.set_val_or_die("bluestore_debug_randomize_serial_transaction",
10911 g_ceph_context
->_conf
.set_val_or_die("bdev_debug_aio", "true");
10913 // specify device size
10914 g_ceph_context
->_conf
.set_val_or_die("bluestore_block_size",
10915 stringify(DEF_STORE_TEST_BLOCKDEV_SIZE
));
10917 g_ceph_context
->_conf
.set_val_or_die(
10918 "enable_experimental_unrecoverable_data_corrupting_features", "*");
10919 g_ceph_context
->_conf
.apply_changes(nullptr);
10921 ::testing::InitGoogleTest(&argc
, argv
);
10922 return RUN_ALL_TESTS();
10927 * compile-command: "cd ../.. ; make ceph_test_objectstore &&
10928 * ./ceph_test_objectstore \
10929 * --gtest_filter=*.collect_metadata* --log-to-stderr=true --debug-filestore=20