]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/crimson/seastore/test_btree_lba_manager.cc
update ceph source to reef 18.2.1
[ceph.git] / ceph / src / test / crimson / seastore / test_btree_lba_manager.cc
CommitLineData
f67539c2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "test/crimson/gtest_seastar.h"
5
6#include "crimson/common/log.h"
7
8#include "crimson/os/seastore/journal.h"
9#include "crimson/os/seastore/cache.h"
10#include "crimson/os/seastore/segment_manager/ephemeral.h"
11#include "crimson/os/seastore/lba_manager/btree/btree_lba_manager.h"
12
13#include "test/crimson/seastore/test_block.h"
14
15namespace {
16 [[maybe_unused]] seastar::logger& logger() {
17 return crimson::get_logger(ceph_subsys_test);
18 }
19}
20
21using namespace crimson;
22using namespace crimson::os;
23using namespace crimson::os::seastore;
24using namespace crimson::os::seastore::lba_manager;
25using namespace crimson::os::seastore::lba_manager::btree;
26
20effc67 27struct btree_test_base :
1e59de90 28 public seastar_test_suite_t, SegmentProvider, JournalTrimmer {
20effc67 29
f67539c2 30 segment_manager::EphemeralSegmentManagerRef segment_manager;
1e59de90 31 SegmentManagerGroupRef sms;
20effc67 32 JournalRef journal;
1e59de90 33 ExtentPlacementManagerRef epm;
20effc67 34 CacheRef cache;
f67539c2 35
20effc67 36 size_t block_size;
f67539c2 37
20effc67
TL
38 WritePipeline pipeline;
39
40 segment_id_t next;
41
1e59de90
TL
42 std::map<segment_id_t, segment_seq_t> segment_seqs;
43 std::map<segment_id_t, segment_type_t> segment_types;
44
45 journal_seq_t dummy_tail;
46
47 mutable segment_info_t tmp_info;
48
20effc67 49 btree_test_base() = default;
f67539c2 50
1e59de90
TL
51 /*
52 * JournalTrimmer interfaces
53 */
54 journal_seq_t get_journal_head() const final { return dummy_tail; }
55
56 void set_journal_head(journal_seq_t) final {}
57
58 journal_seq_t get_dirty_tail() const final { return dummy_tail; }
59
60 journal_seq_t get_alloc_tail() const final { return dummy_tail; }
61
62 void update_journal_tails(journal_seq_t, journal_seq_t) final {}
63
64 bool try_reserve_inline_usage(std::size_t) final { return true; }
65
66 void release_inline_usage(std::size_t) final {}
67
68 std::size_t get_trim_size_per_cycle() const final {
69 return 0;
70 }
71
72 /*
73 * SegmentProvider interfaces
74 */
75 const segment_info_t& get_seg_info(segment_id_t id) const final {
76 tmp_info = {};
77 tmp_info.seq = segment_seqs.at(id);
78 tmp_info.type = segment_types.at(id);
79 return tmp_info;
80 }
20effc67 81
1e59de90
TL
82 segment_id_t allocate_segment(
83 segment_seq_t seq,
84 segment_type_t type,
85 data_category_t,
86 rewrite_gen_t
87 ) final {
20effc67
TL
88 auto ret = next;
89 next = segment_id_t{
1e59de90 90 segment_manager->get_device_id(),
20effc67 91 next.device_segment_id() + 1};
1e59de90
TL
92 segment_seqs[ret] = seq;
93 segment_types[ret] = type;
94 return ret;
f67539c2
TL
95 }
96
1e59de90
TL
97 void close_segment(segment_id_t) final {}
98
99 void update_segment_avail_bytes(segment_type_t, paddr_t) final {}
100
101 void update_modify_time(segment_id_t, sea_time_point, std::size_t) final {}
102
103 SegmentManagerGroup* get_segment_manager_group() final { return sms.get(); }
f67539c2 104
20effc67
TL
105 virtual void complete_commit(Transaction &t) {}
106 seastar::future<> submit_transaction(TransactionRef t)
f67539c2 107 {
1e59de90 108 auto record = cache->prepare_record(*t, JOURNAL_SEQ_NULL, JOURNAL_SEQ_NULL);
20effc67
TL
109 return journal->submit_record(std::move(record), t->get_handle()).safe_then(
110 [this, t=std::move(t)](auto submit_result) mutable {
111 cache->complete_commit(
112 *t,
113 submit_result.record_block_base,
114 submit_result.write_result.start_seq);
115 complete_commit(*t);
116 }).handle_error(crimson::ct_error::assert_all{});
f67539c2
TL
117 }
118
20effc67 119 virtual LBAManager::mkfs_ret test_structure_setup(Transaction &t) = 0;
f67539c2 120 seastar::future<> set_up_fut() final {
20effc67 121 segment_manager = segment_manager::create_test_ephemeral();
f67539c2
TL
122 return segment_manager->init(
123 ).safe_then([this] {
1e59de90
TL
124 return segment_manager->mkfs(
125 segment_manager::get_ephemeral_device_config(0, 1, 0));
126 }).safe_then([this] {
127 sms.reset(new SegmentManagerGroup());
128 journal = journal::make_segmented(*this, *this);
129 epm.reset(new ExtentPlacementManager());
130 cache.reset(new Cache(*epm));
131
132 block_size = segment_manager->get_block_size();
133 next = segment_id_t{segment_manager->get_device_id(), 0};
134 sms->add_segment_manager(segment_manager.get());
135 epm->test_init_no_background(segment_manager.get());
136 journal->set_write_pipeline(&pipeline);
137
138 return journal->open_for_mkfs().discard_result();
139 }).safe_then([this] {
140 dummy_tail = journal_seq_t{0,
141 paddr_t::make_seg_paddr(segment_id_t(segment_manager->get_device_id(), 0), 0)};
142 return epm->open_for_write();
143 }).safe_then([this] {
f67539c2 144 return seastar::do_with(
20effc67
TL
145 cache->create_transaction(
146 Transaction::src_t::MUTATE, "test_set_up_fut", false),
147 [this](auto &ref_t) {
148 return with_trans_intr(*ref_t, [&](auto &t) {
149 cache->init();
150 return cache->mkfs(t
151 ).si_then([this, &t] {
152 return test_structure_setup(t);
153 });
154 }).safe_then([this, &ref_t] {
155 return submit_transaction(std::move(ref_t));
f67539c2
TL
156 });
157 });
158 }).handle_error(
159 crimson::ct_error::all_same_way([] {
160 ceph_assert(0 == "error");
161 })
162 );
163 }
164
20effc67 165 virtual void test_structure_reset() {}
f67539c2 166 seastar::future<> tear_down_fut() final {
20effc67 167 return cache->close(
f67539c2 168 ).safe_then([this] {
20effc67 169 return journal->close();
1e59de90
TL
170 }).safe_then([this] {
171 return epm->close();
20effc67
TL
172 }).safe_then([this] {
173 test_structure_reset();
174 segment_manager.reset();
1e59de90 175 sms.reset();
20effc67 176 journal.reset();
1e59de90 177 epm.reset();
20effc67 178 cache.reset();
f67539c2
TL
179 }).handle_error(
180 crimson::ct_error::all_same_way([] {
181 ASSERT_FALSE("Unable to close");
182 })
183 );
184 }
20effc67
TL
185};
186
187struct lba_btree_test : btree_test_base {
188 std::map<laddr_t, lba_map_val_t> check;
189
190 auto get_op_context(Transaction &t) {
1e59de90 191 return op_context_t<laddr_t>{*cache, t};
20effc67
TL
192 }
193
194 LBAManager::mkfs_ret test_structure_setup(Transaction &t) final {
195 return cache->get_root(
196 t
197 ).si_then([this, &t](RootBlockRef croot) {
198 auto mut_croot = cache->duplicate_for_write(
199 t, croot
200 )->cast<RootBlock>();
1e59de90
TL
201 mut_croot->root.lba_root =
202 LBABtree::mkfs(mut_croot, get_op_context(t));
20effc67
TL
203 });
204 }
205
20effc67
TL
206 template <typename F>
207 auto lba_btree_update(F &&f) {
208 auto tref = cache->create_transaction(
209 Transaction::src_t::MUTATE, "test_btree_update", false);
210 auto &t = *tref;
211 with_trans_intr(
212 t,
213 [this, tref=std::move(tref), f=std::forward<F>(f)](auto &t) mutable {
214 return cache->get_root(
215 t
1e59de90 216 ).si_then([f=std::move(f), &t](RootBlockRef croot) {
20effc67 217 return seastar::do_with(
1e59de90
TL
218 LBABtree(croot),
219 [f=std::move(f), &t](auto &btree) mutable {
20effc67
TL
220 return std::invoke(
221 std::move(f), btree, t
1e59de90 222 );
20effc67
TL
223 });
224 }).si_then([this, tref=std::move(tref)]() mutable {
225 return submit_transaction(std::move(tref));
226 });
227 }).unsafe_get0();
228 }
229
230 template <typename F>
231 auto lba_btree_read(F &&f) {
232 auto t = cache->create_transaction(
233 Transaction::src_t::READ, "test_btree_read", false);
234 return with_trans_intr(
235 *t,
236 [this, f=std::forward<F>(f)](auto &t) mutable {
237 return cache->get_root(
238 t
239 ).si_then([f=std::move(f), &t](RootBlockRef croot) mutable {
240 return seastar::do_with(
1e59de90 241 LBABtree(croot),
20effc67
TL
242 [f=std::move(f), &t](auto &btree) mutable {
243 return std::invoke(
244 std::move(f), btree, t
245 );
246 });
247 });
248 }).unsafe_get0();
249 }
250
251 static auto get_map_val(extent_len_t len) {
aee94f69 252 return lba_map_val_t{0, (pladdr_t)P_ADDR_NULL, len, 0};
20effc67
TL
253 }
254
1e59de90
TL
255 device_off_t next_off = 0;
256 paddr_t get_paddr() {
257 next_off += block_size;
258 return make_fake_paddr(next_off);
259 }
260
20effc67
TL
261 void insert(laddr_t addr, extent_len_t len) {
262 ceph_assert(check.count(addr) == 0);
263 check.emplace(addr, get_map_val(len));
1e59de90
TL
264 lba_btree_update([=, this](auto &btree, auto &t) {
265 auto extent = cache->alloc_new_extent<TestBlock>(
266 t,
267 TestBlock::SIZE,
268 placement_hint_t::HOT,
269 0,
270 get_paddr());
20effc67 271 return btree.insert(
1e59de90
TL
272 get_op_context(t), addr, get_map_val(len), extent.get()
273 ).si_then([addr, extent](auto p){
274 auto& [iter, inserted] = p;
275 assert(inserted);
276 extent->set_laddr(addr);
277 });
20effc67
TL
278 });
279 }
280
281 void remove(laddr_t addr) {
282 auto iter = check.find(addr);
283 ceph_assert(iter != check.end());
284 auto len = iter->second.len;
285 check.erase(iter++);
1e59de90 286 lba_btree_update([=, this](auto &btree, auto &t) {
20effc67
TL
287 return btree.lower_bound(
288 get_op_context(t), addr
289 ).si_then([this, len, addr, &btree, &t](auto iter) {
290 EXPECT_FALSE(iter.is_end());
291 EXPECT_TRUE(iter.get_key() == addr);
292 EXPECT_TRUE(iter.get_val().len == len);
293 return btree.remove(
294 get_op_context(t), iter
295 );
296 });
297 });
298 }
299
300 void check_lower_bound(laddr_t addr) {
301 auto iter = check.lower_bound(addr);
1e59de90 302 auto result = lba_btree_read([=, this](auto &btree, auto &t) {
20effc67
TL
303 return btree.lower_bound(
304 get_op_context(t), addr
305 ).si_then([](auto iter)
306 -> std::optional<std::pair<const laddr_t, const lba_map_val_t>> {
307 if (iter.is_end()) {
308 return std::nullopt;
309 } else {
310 return std::make_optional(
311 std::make_pair(iter.get_key(), iter.get_val()));
312 }
313 });
314 });
315 if (iter == check.end()) {
316 EXPECT_FALSE(result);
317 } else {
318 EXPECT_TRUE(result);
319 decltype(result) to_check = *iter;
320 EXPECT_EQ(to_check, *result);
321 }
322 }
323};
324
325TEST_F(lba_btree_test, basic)
326{
327 run_async([this] {
328 constexpr unsigned total = 16<<10;
329 for (unsigned i = 0; i < total; i += 16) {
330 insert(i, 8);
331 }
332
333 for (unsigned i = 0; i < total; i += 16) {
334 check_lower_bound(i);
335 check_lower_bound(i + 4);
336 check_lower_bound(i + 8);
337 check_lower_bound(i + 12);
338 }
339 });
340}
341
342struct btree_lba_manager_test : btree_test_base {
343 BtreeLBAManagerRef lba_manager;
344
345 btree_lba_manager_test() = default;
346
1e59de90 347 void complete_commit(Transaction &t) final {}
20effc67
TL
348
349 LBAManager::mkfs_ret test_structure_setup(Transaction &t) final {
1e59de90 350 lba_manager.reset(new BtreeLBAManager(*cache));
20effc67
TL
351 return lba_manager->mkfs(t);
352 }
f67539c2 353
20effc67
TL
354 void test_structure_reset() final {
355 lba_manager.reset();
356 }
f67539c2
TL
357
358 struct test_extent_t {
359 paddr_t addr;
360 size_t len = 0;
361 unsigned refcount = 0;
362 };
363 using test_lba_mapping_t = std::map<laddr_t, test_extent_t>;
364 test_lba_mapping_t test_lba_mappings;
365 struct test_transaction_t {
366 TransactionRef t;
367 test_lba_mapping_t mappings;
368 };
369
20effc67 370 auto create_transaction(bool create_fake_extent=true) {
f67539c2 371 auto t = test_transaction_t{
20effc67
TL
372 cache->create_transaction(
373 Transaction::src_t::MUTATE, "test_mutate_lba", false),
f67539c2
TL
374 test_lba_mappings
375 };
20effc67 376 if (create_fake_extent) {
1e59de90
TL
377 cache->alloc_new_extent<TestBlockPhysical>(
378 *t.t,
379 TestBlockPhysical::SIZE,
380 placement_hint_t::HOT,
381 0);
20effc67 382 };
f67539c2
TL
383 return t;
384 }
385
386 auto create_weak_transaction() {
387 auto t = test_transaction_t{
20effc67
TL
388 cache->create_transaction(
389 Transaction::src_t::READ, "test_read_weak", true),
f67539c2
TL
390 test_lba_mappings
391 };
392 return t;
393 }
394
395 void submit_test_transaction(test_transaction_t t) {
20effc67 396 submit_transaction(std::move(t.t)).get();
f67539c2
TL
397 test_lba_mappings.swap(t.mappings);
398 }
399
400 auto get_overlap(test_transaction_t &t, laddr_t addr, size_t len) {
401 auto bottom = t.mappings.upper_bound(addr);
402 if (bottom != t.mappings.begin())
403 --bottom;
404 if (bottom != t.mappings.end() &&
405 bottom->first + bottom->second.len <= addr)
406 ++bottom;
407
408 auto top = t.mappings.lower_bound(addr + len);
409 return std::make_pair(
410 bottom,
411 top
412 );
413 }
414
1e59de90 415 device_off_t next_off = 0;
f67539c2
TL
416 paddr_t get_paddr() {
417 next_off += block_size;
418 return make_fake_paddr(next_off);
419 }
420
421 auto alloc_mapping(
422 test_transaction_t &t,
423 laddr_t hint,
1e59de90 424 size_t len) {
20effc67
TL
425 auto ret = with_trans_intr(
426 *t.t,
1e59de90
TL
427 [=, this](auto &t) {
428 auto extent = cache->alloc_new_extent<TestBlock>(
429 t,
430 TestBlock::SIZE,
431 placement_hint_t::HOT,
432 0,
433 get_paddr());
434 return lba_manager->alloc_extent(
aee94f69 435 t, hint, len, extent->get_paddr(), *extent);
20effc67 436 }).unsafe_get0();
f67539c2
TL
437 logger().debug("alloc'd: {}", *ret);
438 EXPECT_EQ(len, ret->get_length());
1e59de90 439 auto [b, e] = get_overlap(t, ret->get_key(), len);
f67539c2
TL
440 EXPECT_EQ(b, e);
441 t.mappings.emplace(
442 std::make_pair(
1e59de90 443 ret->get_key(),
f67539c2 444 test_extent_t{
1e59de90 445 ret->get_val(),
f67539c2
TL
446 ret->get_length(),
447 1
448 }
449 ));
450 return ret;
451 }
452
f67539c2
TL
453 auto decref_mapping(
454 test_transaction_t &t,
455 laddr_t addr) {
456 return decref_mapping(t, t.mappings.find(addr));
457 }
458
459 void decref_mapping(
460 test_transaction_t &t,
461 test_lba_mapping_t::iterator target) {
462 ceph_assert(target != t.mappings.end());
463 ceph_assert(target->second.refcount > 0);
464 target->second.refcount--;
465
1e59de90 466 (void) with_trans_intr(
f67539c2 467 *t.t,
1e59de90 468 [=, this](auto &t) {
20effc67
TL
469 return lba_manager->decref_extent(
470 t,
aee94f69
TL
471 target->first,
472 true
1e59de90
TL
473 ).si_then([this, &t, target](auto result) {
474 EXPECT_EQ(result.refcount, target->second.refcount);
475 if (result.refcount == 0) {
aee94f69
TL
476 return cache->retire_extent_addr(
477 t, result.addr.get_paddr(), result.length);
1e59de90
TL
478 }
479 return Cache::retire_extent_iertr::now();
480 });
481 }).unsafe_get0();
f67539c2
TL
482 if (target->second.refcount == 0) {
483 t.mappings.erase(target);
484 }
485 }
486
487 auto incref_mapping(
488 test_transaction_t &t,
489 laddr_t addr) {
490 return incref_mapping(t, t.mappings.find(addr));
491 }
492
493 void incref_mapping(
494 test_transaction_t &t,
495 test_lba_mapping_t::iterator target) {
496 ceph_assert(target->second.refcount > 0);
497 target->second.refcount++;
20effc67 498 auto refcnt = with_trans_intr(
f67539c2 499 *t.t,
1e59de90 500 [=, this](auto &t) {
20effc67
TL
501 return lba_manager->incref_extent(
502 t,
503 target->first);
504 }).unsafe_get0().refcount;
f67539c2
TL
505 EXPECT_EQ(refcnt, target->second.refcount);
506 }
507
508 std::vector<laddr_t> get_mapped_addresses() {
509 std::vector<laddr_t> addresses;
510 addresses.reserve(test_lba_mappings.size());
511 for (auto &i: test_lba_mappings) {
512 addresses.push_back(i.first);
513 }
514 return addresses;
515 }
516
517 std::vector<laddr_t> get_mapped_addresses(test_transaction_t &t) {
518 std::vector<laddr_t> addresses;
519 addresses.reserve(t.mappings.size());
520 for (auto &i: t.mappings) {
521 addresses.push_back(i.first);
522 }
523 return addresses;
524 }
525
526 void check_mappings() {
527 auto t = create_transaction();
528 check_mappings(t);
529 }
530
531 void check_mappings(test_transaction_t &t) {
1e59de90
TL
532 (void)with_trans_intr(
533 *t.t,
534 [=, this](auto &t) {
535 return lba_manager->check_child_trackers(t);
536 }).unsafe_get0();
f67539c2 537 for (auto &&i: t.mappings) {
20effc67
TL
538 auto laddr = i.first;
539 auto len = i.second.len;
540
541 auto ret_list = with_trans_intr(
542 *t.t,
1e59de90 543 [=, this](auto &t) {
20effc67
TL
544 return lba_manager->get_mappings(
545 t, laddr, len);
546 }).unsafe_get0();
f67539c2
TL
547 EXPECT_EQ(ret_list.size(), 1);
548 auto &ret = *ret_list.begin();
1e59de90
TL
549 EXPECT_EQ(i.second.addr, ret->get_val());
550 EXPECT_EQ(laddr, ret->get_key());
20effc67
TL
551 EXPECT_EQ(len, ret->get_length());
552
553 auto ret_pin = with_trans_intr(
554 *t.t,
1e59de90 555 [=, this](auto &t) {
20effc67
TL
556 return lba_manager->get_mapping(
557 t, laddr);
558 }).unsafe_get0();
1e59de90
TL
559 EXPECT_EQ(i.second.addr, ret_pin->get_val());
560 EXPECT_EQ(laddr, ret_pin->get_key());
20effc67 561 EXPECT_EQ(len, ret_pin->get_length());
f67539c2 562 }
20effc67 563 with_trans_intr(
f67539c2 564 *t.t,
1e59de90 565 [=, &t, this](auto &) {
20effc67
TL
566 return lba_manager->scan_mappings(
567 *t.t,
568 0,
569 L_ADDR_MAX,
570 [iter=t.mappings.begin(), &t](auto l, auto p, auto len) mutable {
571 EXPECT_NE(iter, t.mappings.end());
572 EXPECT_EQ(l, iter->first);
573 EXPECT_EQ(p, iter->second.addr);
574 EXPECT_EQ(len, iter->second.len);
575 ++iter;
576 });
f67539c2
TL
577 }).unsafe_get();
578 }
579};
580
581TEST_F(btree_lba_manager_test, basic)
582{
583 run_async([this] {
584 laddr_t laddr = 0x12345678 * block_size;
585 {
586 // write initial mapping
587 auto t = create_transaction();
588 check_mappings(t); // check in progress transaction sees mapping
589 check_mappings(); // check concurrent does not
1e59de90 590 auto ret = alloc_mapping(t, laddr, block_size);
f67539c2
TL
591 submit_test_transaction(std::move(t));
592 }
593 check_mappings(); // check new transaction post commit sees it
594 });
595}
596
597TEST_F(btree_lba_manager_test, force_split)
598{
599 run_async([this] {
600 for (unsigned i = 0; i < 40; ++i) {
601 auto t = create_transaction();
602 logger().debug("opened transaction");
603 for (unsigned j = 0; j < 5; ++j) {
1e59de90 604 auto ret = alloc_mapping(t, 0, block_size);
f67539c2
TL
605 if ((i % 10 == 0) && (j == 3)) {
606 check_mappings(t);
607 check_mappings();
608 }
609 }
610 logger().debug("submitting transaction");
611 submit_test_transaction(std::move(t));
612 check_mappings();
613 }
614 });
615}
616
617TEST_F(btree_lba_manager_test, force_split_merge)
618{
619 run_async([this] {
620 for (unsigned i = 0; i < 80; ++i) {
621 auto t = create_transaction();
622 logger().debug("opened transaction");
623 for (unsigned j = 0; j < 5; ++j) {
1e59de90 624 auto ret = alloc_mapping(t, 0, block_size);
f67539c2
TL
625 // just to speed things up a bit
626 if ((i % 100 == 0) && (j == 3)) {
627 check_mappings(t);
628 check_mappings();
629 }
1e59de90
TL
630 incref_mapping(t, ret->get_key());
631 decref_mapping(t, ret->get_key());
f67539c2
TL
632 }
633 logger().debug("submitting transaction");
634 submit_test_transaction(std::move(t));
635 if (i % 50 == 0) {
636 check_mappings();
637 }
638 }
639 {
640 auto addresses = get_mapped_addresses();
641 auto t = create_transaction();
642 for (unsigned i = 0; i != addresses.size(); ++i) {
643 if (i % 2 == 0) {
644 incref_mapping(t, addresses[i]);
645 decref_mapping(t, addresses[i]);
646 decref_mapping(t, addresses[i]);
647 }
648 logger().debug("submitting transaction");
649 if (i % 7 == 0) {
650 submit_test_transaction(std::move(t));
651 t = create_transaction();
652 }
653 if (i % 13 == 0) {
654 check_mappings();
655 check_mappings(t);
656 }
657 }
658 submit_test_transaction(std::move(t));
659 }
660 {
661 auto addresses = get_mapped_addresses();
662 auto t = create_transaction();
663 for (unsigned i = 0; i != addresses.size(); ++i) {
664 incref_mapping(t, addresses[i]);
665 decref_mapping(t, addresses[i]);
666 decref_mapping(t, addresses[i]);
667 }
668 check_mappings(t);
669 submit_test_transaction(std::move(t));
670 check_mappings();
671 }
672 });
673}
674
675TEST_F(btree_lba_manager_test, single_transaction_split_merge)
676{
677 run_async([this] {
678 {
679 auto t = create_transaction();
20effc67 680 for (unsigned i = 0; i < 400; ++i) {
1e59de90 681 alloc_mapping(t, 0, block_size);
f67539c2
TL
682 }
683 check_mappings(t);
684 submit_test_transaction(std::move(t));
685 }
686 check_mappings();
687
688 {
689 auto addresses = get_mapped_addresses();
690 auto t = create_transaction();
691 for (unsigned i = 0; i != addresses.size(); ++i) {
692 if (i % 4 != 0) {
693 decref_mapping(t, addresses[i]);
694 }
695 }
696 check_mappings(t);
697 submit_test_transaction(std::move(t));
698 }
699 check_mappings();
700
701 {
702 auto t = create_transaction();
703 for (unsigned i = 0; i < 600; ++i) {
1e59de90 704 alloc_mapping(t, 0, block_size);
f67539c2
TL
705 }
706 auto addresses = get_mapped_addresses(t);
707 for (unsigned i = 0; i != addresses.size(); ++i) {
708 decref_mapping(t, addresses[i]);
709 }
710 check_mappings(t);
711 submit_test_transaction(std::move(t));
712 }
713 check_mappings();
714 });
715}
20effc67
TL
716
717TEST_F(btree_lba_manager_test, split_merge_multi)
718{
719 run_async([this] {
720 auto iterate = [&](auto f) {
721 for (uint64_t i = 0; i < (1<<10); ++i) {
722 auto t = create_transaction(false);
723 logger().debug("opened transaction");
724 for (unsigned j = 0; j < 5; ++j) {
725 f(t, (i * 5) + j);
726 }
727 logger().debug("submitting transaction");
728 submit_test_transaction(std::move(t));
729 }
730 };
731 iterate([&](auto &t, auto idx) {
1e59de90 732 alloc_mapping(t, idx * block_size, block_size);
20effc67
TL
733 });
734 check_mappings();
735 iterate([&](auto &t, auto idx) {
736 if ((idx % 32) > 0) {
737 decref_mapping(t, idx * block_size);
738 }
739 });
740 check_mappings();
741 iterate([&](auto &t, auto idx) {
742 if ((idx % 32) > 0) {
1e59de90 743 alloc_mapping(t, idx * block_size, block_size);
20effc67
TL
744 }
745 });
746 check_mappings();
747 iterate([&](auto &t, auto idx) {
748 decref_mapping(t, idx * block_size);
749 });
750 check_mappings();
751 });
752}