1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
8 #include "test/crimson/gtest_seastar.h"
10 #include "test/crimson/seastore/transaction_manager_test_state.h"
12 #include "crimson/os/futurized_collection.h"
13 #include "crimson/os/seastore/seastore.h"
15 using namespace crimson
;
16 using namespace crimson::os
;
17 using namespace crimson::os::seastore
;
18 using CTransaction
= ceph::os::Transaction
;
22 [[maybe_unused
]] seastar::logger
& logger() {
23 return crimson::get_logger(ceph_subsys_test
);
28 struct seastore_test_t
:
29 public seastar_test_suite_t
,
32 coll_t coll_name
{spg_t
{pg_t
{0, 0}}};
37 seastar::future
<> set_up_fut() final
{
40 return seastore
->create_new_collection(coll_name
);
41 }).then([this](auto coll_ref
) {
44 t
.create_collection(coll_name
, 4);
45 return seastore
->do_transaction(
51 seastar::future
<> tear_down_fut() final
{
56 void do_transaction(CTransaction
&&t
) {
57 return seastore
->do_transaction(
63 const std::string
& key
,
64 const std::string
& value
) {
65 return seastore
->write_meta(key
, value
).get0();
68 std::tuple
<int, std::string
> get_meta(
69 const std::string
& key
) {
70 return seastore
->read_meta(key
).get();
73 struct object_state_t
{
75 const CollectionRef coll
;
78 std::map
<string
, bufferlist
> omap
;
90 seastore
.do_transaction(
101 SeaStore
&seastore
) {
104 seastore
.do_transaction(
106 std::move(t
)).get0();
112 const bufferlist
&val
) {
114 std::map
<string
, bufferlist
> arg
;
125 const bufferlist
&val
) {
127 set_omap(t
, key
, val
);
128 seastore
.do_transaction(
130 std::move(t
)).get0();
138 bufferlist new_contents
;
139 if (offset
> 0 && contents
.length()) {
140 new_contents
.substr_of(
143 std::min
<size_t>(offset
, contents
.length())
146 new_contents
.append_zero(offset
- new_contents
.length());
147 new_contents
.append(bl
);
149 auto tail_offset
= offset
+ bl
.length();
150 if (contents
.length() > tail_offset
) {
155 contents
.length() - tail_offset
);
156 new_contents
.append(tail
);
158 contents
.swap(new_contents
);
172 write(seastore
, t
, offset
, bl
);
173 seastore
.do_transaction(
175 std::move(t
)).get0();
182 auto buffer
= bufferptr(buffer::create(len
));
183 ::memset(buffer
.c_str(), fill
, len
);
186 write(seastore
, offset
, bl
);
198 auto ret
= seastore
.read(
203 EXPECT_EQ(ret
.length(), to_check
.length());
204 EXPECT_EQ(ret
, to_check
);
207 void check_size(SeaStore
&seastore
) {
208 auto st
= seastore
.stat(
211 EXPECT_EQ(contents
.length(), st
.st_size
);
219 t
.setattr(cid
, oid
, key
, val
);
220 seastore
.do_transaction(
222 std::move(t
)).get0();
225 SeaStore::attrs_t
get_attrs(
226 SeaStore
&seastore
) {
227 return seastore
.get_attrs(coll
, oid
)
228 .handle_error(SeaStore::get_attrs_ertr::discard_all
{})
232 ceph::bufferlist
get_attr(
234 std::string_view name
) {
235 return seastore
.get_attr(coll
, oid
, name
)
237 SeaStore::get_attr_errorator::discard_all
{})
244 std::set
<string
> to_check
;
245 to_check
.insert(key
);
246 auto result
= seastore
.omap_get_values(
249 to_check
).unsafe_get0();
250 if (result
.empty()) {
251 EXPECT_EQ(omap
.find(key
), omap
.end());
253 auto iter
= omap
.find(key
);
254 EXPECT_NE(iter
, omap
.end());
255 if (iter
!= omap
.end()) {
256 EXPECT_EQ(result
.size(), 1);
257 EXPECT_EQ(iter
->second
, result
.begin()->second
);
262 void check_omap(SeaStore
&seastore
) {
263 auto iter
= seastore
.get_omap_iterator(coll
, oid
).get0();
264 iter
->seek_to_first().get0();
265 auto refiter
= omap
.begin();
267 if (!iter
->valid() && refiter
== omap
.end())
270 if (!iter
->valid() || refiter
->first
< iter
->key()) {
272 "check_omap: missing omap key {}",
274 GTEST_FAIL() << "missing omap key " << refiter
->first
;
276 } else if (refiter
== omap
.end() || refiter
->first
> iter
->key()) {
278 "check_omap: extra omap key {}",
280 GTEST_FAIL() << "extra omap key" << iter
->key();
283 EXPECT_EQ(iter
->value(), refiter
->second
);
291 map
<ghobject_t
, object_state_t
> test_objects
;
292 object_state_t
&get_object(
293 const ghobject_t
&oid
) {
294 return test_objects
.emplace(
297 object_state_t
{coll_name
, coll
, oid
})).first
->second
;
301 object_state_t
&sobj
) {
303 sobj
.remove(*seastore
);
304 auto erased
= test_objects
.erase(sobj
.oid
);
305 ceph_assert(erased
== 1);
308 void validate_objects() const {
309 std::vector
<ghobject_t
> oids
;
310 for (auto& [oid
, obj
] : test_objects
) {
311 oids
.emplace_back(oid
);
313 auto ret
= seastore
->list_objects(
316 ghobject_t::get_max(),
317 std::numeric_limits
<uint64_t>::max()).get0();
318 EXPECT_EQ(std::get
<1>(ret
), ghobject_t::get_max());
319 EXPECT_EQ(std::get
<0>(ret
), oids
);
323 ghobject_t
make_oid(int i
) {
325 ss
<< "object_" << i
;
326 auto ret
= ghobject_t(
328 sobject_t(ss
.str(), CEPH_NOSNAP
)));
329 ret
.set_shard(shard_id_t(0));
330 ret
.hobj
.nspace
= "asdf";
334 template <typename T
, typename V
>
335 auto contains(const T
&t
, const V
&v
) {
342 TEST_F(seastore_test_t
, collection_create_list_remove
)
345 coll_t test_coll
{spg_t
{pg_t
{1, 0}}};
347 seastore
->create_new_collection(test_coll
).get0();
350 t
.create_collection(test_coll
, 4);
351 do_transaction(std::move(t
));
353 auto collections
= seastore
->list_collections().get0();
354 EXPECT_EQ(collections
.size(), 2);
355 EXPECT_TRUE(contains(collections
, coll_name
));
356 EXPECT_TRUE(contains(collections
, test_coll
));
362 t
.remove_collection(test_coll
);
363 do_transaction(std::move(t
));
365 auto collections
= seastore
->list_collections().get0();
366 EXPECT_EQ(collections
.size(), 1);
367 EXPECT_TRUE(contains(collections
, coll_name
));
372 TEST_F(seastore_test_t
, meta
) {
374 set_meta("key1", "value1");
375 set_meta("key2", "value2");
377 const auto [ret1
, value1
] = get_meta("key1");
378 const auto [ret2
, value2
] = get_meta("key2");
381 EXPECT_EQ(value1
, "value1");
382 EXPECT_EQ(value2
, "value2");
386 TEST_F(seastore_test_t
, touch_stat_list_remove
)
389 auto &test_obj
= get_object(make_oid(0));
390 test_obj
.touch(*seastore
);
391 test_obj
.check_size(*seastore
);
394 remove_object(test_obj
);
399 bufferlist
make_bufferlist(size_t len
) {
406 TEST_F(seastore_test_t
, omap_test_simple
)
409 auto &test_obj
= get_object(make_oid(0));
413 make_bufferlist(128));
414 test_obj
.check_omap_key(
420 TEST_F(seastore_test_t
, attr
)
423 auto& test_obj
= get_object(make_oid(0));
425 std::string
oi("asdfasdfasdf");
428 test_obj
.set_attr(*seastore
, OI_ATTR
, bl
);
430 std::string
ss("fdsfdsfs");
433 test_obj
.set_attr(*seastore
, SS_ATTR
, bl
);
435 std::string
test_val("ssssssssssss");
437 encode(test_val
, bl
);
438 test_obj
.set_attr(*seastore
, "test_key", bl
);
440 auto attrs
= test_obj
.get_attrs(*seastore
);
442 bufferlist bl2
= attrs
[OI_ATTR
];
445 bl2
= attrs
[SS_ATTR
];
448 std::string test_val2
;
450 bl2
= attrs
["test_key"];
451 decode(test_val2
, bl2
);
454 EXPECT_EQ(test_val
, test_val2
);
457 bl2
= test_obj
.get_attr(*seastore
, "test_key");
459 decode(test_val2
, bl2
);
460 EXPECT_EQ(test_val
, test_val2
);
462 std::cout
<< "test_key passed" << std::endl
;
463 char ss_array
[256] = {0};
464 std::string
ss_str(&ss_array
[0], 256);
467 test_obj
.set_attr(*seastore
, SS_ATTR
, bl
);
469 attrs
= test_obj
.get_attrs(*seastore
);
470 std::cout
<< "got attr" << std::endl
;
472 bl2
= attrs
[SS_ATTR
];
474 decode(ss_str2
, bl2
);
475 EXPECT_EQ(ss_str
, ss_str2
);
479 bl2
= test_obj
.get_attr(*seastore
, SS_ATTR
);
480 decode(ss_str2
, bl2
);
481 EXPECT_EQ(ss_str
, ss_str2
);
485 TEST_F(seastore_test_t
, omap_test_iterator
)
488 auto make_key
= [](unsigned i
) {
489 std::stringstream ss
;
493 auto &test_obj
= get_object(make_oid(0));
494 for (unsigned i
= 0; i
< 20; ++i
) {
498 make_bufferlist(128));
500 test_obj
.check_omap(*seastore
);
505 TEST_F(seastore_test_t
, simple_extent_test
)
508 auto &test_obj
= get_object(make_oid(0));
518 test_obj
.check_size(*seastore
);