@@ -19,6 +19,22 @@ SET_SUBSYS(seastore_lba);
1919 * - TRACE: read operations, DEBUG details
2020 */
2121
22+ template <> struct fmt ::formatter<
23+ crimson::os::seastore::lba_manager::btree::LBABtree::iterator>
24+ : public fmt::formatter<std::string_view>
25+ {
26+ using Iter = crimson::os::seastore::lba_manager::btree::LBABtree::iterator;
27+
28+ template <typename FmtCtx>
29+ auto format (const Iter &iter, FmtCtx &ctx) const
30+ -> decltype(ctx.out()) {
31+ if (iter.is_end ()) {
32+ return fmt::format_to (ctx.out (), " end" );
33+ }
34+ return fmt::format_to (ctx.out (), " {}~{}" , iter.get_key (), iter.get_val ());
35+ }
36+ };
37+
2238namespace crimson ::os::seastore {
2339
2440template <typename T>
@@ -275,149 +291,179 @@ BtreeLBAManager::_get_mapping(
275291 });
276292}
277293
278- BtreeLBAManager::alloc_extents_ret
279- BtreeLBAManager::_alloc_extents (
294+ BtreeLBAManager::search_insert_position_ret
295+ BtreeLBAManager::search_insert_position (
296+ op_context_t c,
297+ LBABtree &btree,
298+ laddr_t hint,
299+ extent_len_t length,
300+ alloc_policy_t policy)
301+ {
302+ LOG_PREFIX (BtreeLBAManager::search_insert_position);
303+ auto lookup_attempts = stats.num_alloc_extents_iter_nexts ;
304+ using OptIter = std::optional<LBABtree::iterator>;
305+ return seastar::do_with (
306+ hint, OptIter (std::nullopt ),
307+ [this , c, &btree, hint, length, lookup_attempts, policy, FNAME]
308+ (laddr_t &last_end, OptIter &insert_iter)
309+ {
310+ return LBABtree::iterate_repeat (
311+ c,
312+ btree.upper_bound_right (c, hint),
313+ [this , c, hint, length, lookup_attempts, policy,
314+ &last_end, &insert_iter, FNAME](auto &iter)
315+ {
316+ ++stats.num_alloc_extents_iter_nexts ;
317+ if (iter.is_end () ||
318+ iter.get_key () >= (last_end + length)) {
319+ if (policy == alloc_policy_t ::deterministic) {
320+ ceph_assert (hint == last_end);
321+ }
322+ DEBUGT (" hint: {}~0x{:x}, allocated laddr: {}, insert position: {}, "
323+ " done with {} attempts" ,
324+ c.trans , hint, length, last_end, iter,
325+ stats.num_alloc_extents_iter_nexts - lookup_attempts);
326+ insert_iter.emplace (iter);
327+ return search_insert_position_iertr::make_ready_future<
328+ seastar::stop_iteration>(seastar::stop_iteration::yes);
329+ }
330+ ceph_assert (policy == alloc_policy_t ::linear_search);
331+ last_end = (iter.get_key () + iter.get_val ().len ).checked_to_laddr ();
332+ TRACET (" hint: {}~0x{:x}, current iter: {}, repeat ..." ,
333+ c.trans , hint, length, iter);
334+ return search_insert_position_iertr::make_ready_future<
335+ seastar::stop_iteration>(seastar::stop_iteration::no);
336+ }).si_then ([&last_end, &insert_iter] {
337+ ceph_assert (insert_iter);
338+ return search_insert_position_iertr::make_ready_future<
339+ insert_position_t >(last_end, *std::move (insert_iter));
340+ });
341+ });
342+ }
343+
344+ BtreeLBAManager::alloc_mappings_ret
345+ BtreeLBAManager::alloc_contiguous_mappings (
280346 Transaction &t,
281347 laddr_t hint,
282- std::vector<alloc_mapping_info_t > &alloc_infos)
348+ std::vector<alloc_mapping_info_t > &alloc_infos,
349+ alloc_policy_t policy)
283350{
284351 ceph_assert (hint != L_ADDR_NULL);
285352 extent_len_t total_len = 0 ;
286- #ifndef NDEBUG
287- bool laddr_null = (alloc_infos.front ().key == L_ADDR_NULL);
288- laddr_t last_end = hint;
289353 for (auto &info : alloc_infos) {
290- assert ((info.key == L_ADDR_NULL) == (laddr_null));
291- if (!laddr_null) {
292- assert (info.key >= last_end);
293- last_end = (info.key + info.value .len ).checked_to_laddr ();
294- }
354+ assert (info.key == L_ADDR_NULL);
355+ total_len += info.value .len ;
295356 }
296- #endif
297- if (alloc_infos.front ().key == L_ADDR_NULL) {
298- for (auto &info : alloc_infos) {
299- total_len += info.value .len ;
300- }
301- } else {
302- auto end = alloc_infos.back ().key + alloc_infos.back ().value .len ;
303- total_len = end.get_byte_distance <extent_len_t >(hint);
304- }
305-
306- struct state_t {
307- laddr_t last_end;
308357
309- std::optional<typename LBABtree::iterator> insert_iter;
310- std::optional<typename LBABtree::iterator> ret;
311-
312- state_t (laddr_t hint) : last_end(hint) {}
313- };
314-
315- LOG_PREFIX (BtreeLBAManager::_alloc_extents);
316- TRACET (" {}~{}, hint={}, num of extents: {}" ,
317- t, alloc_infos.front ().value .pladdr , total_len, hint, alloc_infos.size ());
358+ auto c = get_context (t);
359+ return with_btree<LBABtree>(
360+ cache,
361+ c,
362+ [this , c, hint, &alloc_infos, total_len, policy](auto &btree)
363+ {
364+ return search_insert_position (c, btree, hint, total_len, policy
365+ ).si_then ([this , c, &alloc_infos, &btree](insert_position_t res) {
366+ extent_len_t offset = 0 ;
367+ for (auto &info : alloc_infos) {
368+ info.key = (res.laddr + offset).checked_to_laddr ();
369+ offset += info.value .len ;
370+ }
371+ return insert_mappings (
372+ c, btree, std::move (res.insert_iter ), alloc_infos);
373+ });
374+ });
375+ }
318376
377+ BtreeLBAManager::alloc_mappings_ret
378+ BtreeLBAManager::alloc_sparse_mappings (
379+ Transaction &t,
380+ laddr_t hint,
381+ std::vector<alloc_mapping_info_t > &alloc_infos,
382+ alloc_policy_t policy)
383+ {
384+ ceph_assert (hint != L_ADDR_NULL);
385+ #ifndef NDEBUG
386+ assert (alloc_infos.front ().key != L_ADDR_NULL);
387+ for (size_t i = 1 ; i < alloc_infos.size (); i++) {
388+ auto &prev = alloc_infos[i - 1 ];
389+ auto &cur = alloc_infos[i];
390+ assert (cur.key != L_ADDR_NULL);
391+ assert (prev.key + prev.value .len <= cur.key );
392+ }
393+ #endif
394+ auto total_len = hint.get_byte_distance <extent_len_t >(
395+ alloc_infos.back ().key + alloc_infos.back ().value .len );
319396 auto c = get_context (t);
320- stats.num_alloc_extents += alloc_infos.size ();
321- auto lookup_attempts = stats.num_alloc_extents_iter_nexts ;
322- return seastar::do_with (
323- std::vector<LBAMappingRef>(),
324- [this , FNAME, &alloc_infos, hint, &t, total_len, c,
325- lookup_attempts](auto &rets) {
326- return crimson::os::seastore::with_btree_state<LBABtree, state_t >(
327- cache,
328- c,
329- hint,
330- [this , c, hint, total_len, addr=alloc_infos.front ().value .pladdr .get_paddr (), &rets,
331- lookup_attempts, &t, &alloc_infos, FNAME](auto &btree, auto &state) {
332- return LBABtree::iterate_repeat (
333- c,
334- btree.upper_bound_right (c, hint),
335- [this , &state, total_len, addr, &t, hint,
336- lookup_attempts, FNAME](auto &pos) {
337- ++stats.num_alloc_extents_iter_nexts ;
338- if (pos.is_end ()) {
339- DEBUGT (" {}~{}, hint={}, state: end, done with {} attempts, insert at {}" ,
340- t, addr, total_len, hint,
341- stats.num_alloc_extents_iter_nexts - lookup_attempts,
342- state.last_end );
343- state.insert_iter = pos;
344- return typename LBABtree::iterate_repeat_ret_inner (
345- interruptible::ready_future_marker{},
346- seastar::stop_iteration::yes);
347- } else if (pos.get_key () >= (state.last_end + total_len)) {
348- DEBUGT (" {}~{}, hint={}, state: {}~{}, done with {} attempts, insert at {} -- {}" ,
349- t, addr, total_len, hint,
350- pos.get_key (), pos.get_val ().len ,
351- stats.num_alloc_extents_iter_nexts - lookup_attempts,
352- state.last_end ,
353- pos.get_val ());
354- state.insert_iter = pos;
355- return typename LBABtree::iterate_repeat_ret_inner (
356- interruptible::ready_future_marker{},
357- seastar::stop_iteration::yes);
358- } else {
359- state.last_end = (pos.get_key () + pos.get_val ().len ).checked_to_laddr ();
360- TRACET (" {}~{}, hint={}, state: {}~{}, repeat ... -- {}" ,
361- t, addr, total_len, hint,
362- pos.get_key (), pos.get_val ().len ,
363- pos.get_val ());
364- return typename LBABtree::iterate_repeat_ret_inner (
365- interruptible::ready_future_marker{},
366- seastar::stop_iteration::no);
397+ return with_btree<LBABtree>(
398+ cache,
399+ c,
400+ [this , c, hint, &alloc_infos, total_len, policy](auto &btree)
401+ {
402+ return search_insert_position (c, btree, hint, total_len, policy
403+ ).si_then ([this , c, hint, &alloc_infos, &btree, policy](auto res) {
404+ if (policy != alloc_policy_t ::deterministic) {
405+ for (auto &info : alloc_infos) {
406+ auto offset = info.key .get_byte_distance <extent_len_t >(hint);
407+ info.key = (res.laddr + offset).checked_to_laddr ();
367408 }
368- }).si_then ([c, addr, hint, &btree, &state, &alloc_infos,
369- total_len, &rets, FNAME] {
370- return trans_intr::do_for_each (
371- alloc_infos,
372- [c, addr, hint, &btree, &state, FNAME,
373- total_len, &rets, refcount](auto &alloc_info) {
374- if (alloc_info.key != L_ADDR_NULL) {
375- state.last_end = alloc_info.key ;
409+ } // deterministic guarantees hint == res.laddr
410+ return insert_mappings (
411+ c, btree, std::move (res.insert_iter ), alloc_infos);
412+ });
413+ });
414+ }
415+
416+ BtreeLBAManager::alloc_mappings_ret
417+ BtreeLBAManager::insert_mappings (
418+ op_context_t c,
419+ LBABtree &btree,
420+ LBABtree::iterator iter,
421+ std::vector<alloc_mapping_info_t > &alloc_infos)
422+ {
423+ return seastar::do_with (
424+ std::move (iter), std::list<LBACursorRef>(),
425+ [c, &btree, &alloc_infos]
426+ (LBABtree::iterator &iter, std::list<LBACursorRef> &ret)
427+ {
428+ return trans_intr::do_for_each (
429+ alloc_infos.begin (),
430+ alloc_infos.end (),
431+ [c, &btree, &iter, &ret](auto &info)
432+ {
433+ assert (info.key != L_ADDR_NULL);
434+ return btree.insert (
435+ c, iter, info.key , info.value
436+ ).si_then ([c, &iter, &ret, &info](auto p) {
437+ ceph_assert (p.second );
438+ iter = std::move (p.first );
439+ auto &leaf_node = *iter.get_leaf_node ();
440+ leaf_node.insert_child_ptr (
441+ iter.get_leaf_pos (),
442+ info.extent ,
443+ leaf_node.get_size () - 1 /* the size before the insert*/ );
444+ if (is_valid_child_ptr (info.extent )) {
445+ ceph_assert (info.value .pladdr .is_paddr ());
446+ assert (info.value .pladdr == iter.get_val ().pladdr );
447+ assert (info.value .len == iter.get_val ().len );
448+ assert (info.extent ->is_logical ());
449+ if (info.extent ->has_laddr ()) {
450+ // see TM::remap_pin()
451+ assert (info.key == info.extent ->get_laddr ());
452+ assert (info.key == iter.get_key ());
453+ } else {
454+ // see TM::alloc_non_data_extent()
455+ // TM::alloc_data_extents()
456+ info.extent ->set_laddr (iter.get_key ());
376457 }
377- return btree.insert (
378- c,
379- *state.insert_iter ,
380- state.last_end ,
381- alloc_info.value
382- ).si_then ([&state, c, addr, total_len, hint, FNAME,
383- &alloc_info, &rets](auto &&p) {
384- auto [iter, inserted] = std::move (p);
385- auto &leaf_node = *iter.get_leaf_node ();
386- leaf_node.insert_child_ptr (
387- iter.get_leaf_pos (),
388- alloc_info.extent ,
389- leaf_node.get_size () - 1 /* the size before the insert*/ );
390- TRACET (" {}~{}, hint={}, inserted at {}" ,
391- c.trans , addr, total_len, hint, state.last_end );
392- if (is_valid_child_ptr (alloc_info.extent )) {
393- ceph_assert (alloc_info.value .pladdr .is_paddr ());
394- assert (alloc_info.value .pladdr == iter.get_val ().pladdr );
395- assert (alloc_info.value .len == iter.get_val ().len );
396- assert (alloc_info.extent ->is_logical ());
397- if (alloc_info.extent ->has_laddr ()) {
398- // see TM::remap_pin()
399- assert (alloc_info.key == alloc_info.extent ->get_laddr ());
400- assert (alloc_info.key == iter.get_key ());
401- } else {
402- // see TM::alloc_non_data_extent()
403- // TM::alloc_data_extents()
404- alloc_info.extent ->set_laddr (iter.get_key ());
405- }
406- }
407- ceph_assert (inserted);
408- rets.emplace_back (iter.get_pin (c));
409- return iter.next (c).si_then ([&state, &alloc_info](auto it) {
410- state.insert_iter = it;
411- if (alloc_info.key == L_ADDR_NULL) {
412- state.last_end = (state.last_end + alloc_info.value .len ).checked_to_laddr ();
413- }
414- });
415- });
458+ }
459+ ret.push_back (iter.get_cursor (c));
460+ return iter.next (c).si_then ([&iter](auto p) {
461+ iter = std::move (p);
416462 });
417463 });
418- }).si_then ([&rets]( auto &&state) {
419- return alloc_extent_iertr ::make_ready_future<
420- std::vector<LBAMappingRef >>(std::move (rets ));
464+ }).si_then ([&ret] {
465+ return alloc_mappings_iertr ::make_ready_future<
466+ std::list<LBACursorRef >>(std::move (ret ));
421467 });
422468 });
423469}
0 commit comments