}
/*
- * get_absent_extent
+ * prepare_absent_extent
*
- * The extent in query is supposed to be absent in Cache.
- * partially load buffer from partial_off~partial_len if not present.
+ * Prepare the extent that's absent in Cache, this is for later
+ * batch reads.
*/
template <typename T, typename Func>
- get_extent_iertr::future<TCachedExtentRef<T>> get_absent_extent(
+ TCachedExtentRef<T> prepare_absent_extent(
Transaction &t,
paddr_t offset,
extent_len_t length,
extent_len_t partial_off,
extent_len_t partial_len,
- Func &&extent_init_func,
- uint32_t pin_crc = CRC_NULL) {
- LOG_PREFIX(Cache::get_absent_extent);
+ Func &&extent_init_func) {
+ LOG_PREFIX(Cached::prepare_absent_extent);
#ifndef NDEBUG
{
}
#endif
- SUBTRACET(seastore_cache, "{} {}~0x{:x} is absent on t, query cache ...",
- t, T::TYPE, offset, length);
+ SUBTRACET(seastore_cache, "{} {}~0x{:x}", t, T::TYPE, offset, length);
ceph_assert(!booting);
const auto t_src = t.get_src();
touch_extent_by_range(
*ret, &t_src, t.get_cache_hint(),
partial_off, partial_len);
+ return ret;
+ }
+
+ /*
+ * get_absent_extent
+ *
+ * The extent in query is supposed to be absent in Cache.
+ * partially load buffer from partial_off~partial_len if not present.
+ */
+ template <typename T, typename Func>
+ get_extent_iertr::future<TCachedExtentRef<T>> get_absent_extent(
+ Transaction &t,
+ paddr_t offset,
+ extent_len_t length,
+ extent_len_t partial_off,
+ extent_len_t partial_len,
+ Func &&extent_init_func,
+ uint32_t pin_crc = CRC_NULL) {
+ LOG_PREFIX(Cache::get_absent_extent);
+ SUBTRACET(seastore_cache, "{} {}~0x{:x}", t, T::TYPE, offset, length);
+
+ auto ret = prepare_absent_extent<T>(
+ t, offset, length, partial_off, partial_len, std::move(extent_init_func));
+ const auto t_src = t.get_src();
return trans_intr::make_interruptible(
read_extent<T>(std::move(ret), partial_off, partial_len, &t_src, pin_crc));
}
});
}
+ template <typename T>
+ struct read_pin_t {
+ LBAMapping mapping;
+ const extent_len_t partial_off = 0;
+ const extent_len_t partial_len = 0;
+ read_pin_t(
+ LBAMapping mapping,
+ extent_len_t partial_off,
+ extent_len_t partial_len)
+ : mapping(std::move(mapping)),
+ partial_off(partial_off),
+ partial_len(partial_len) {}
+ maybe_indirect_extent_t<T> get_result() const {
+ bool is_clone = mapping.is_clone();
+ std::optional<indirect_info_t> maybe_indirect_info;
+ if (mapping.is_indirect()) {
+ auto intermediate_offset = mapping.get_intermediate_offset();
+ maybe_indirect_info = indirect_info_t{
+ intermediate_offset, mapping.get_length()};
+ }
+ return maybe_indirect_extent_t<T>{
+ extent, std::move(maybe_indirect_info), is_clone};
+ }
+ private:
+ TCachedExtentRef<T> extent;
+ std::function<void (T &)> on_read;
+
+ inline extent_len_t maybe_get_direct_partial_off() const {
+ extent_len_t direct_partial_off = partial_off;
+ if (mapping.is_indirect()) {
+ auto intermediate_offset = mapping.get_intermediate_offset();
+ direct_partial_off = intermediate_offset + partial_off;
+ }
+ return direct_partial_off;
+ }
+ Cache::read_extent_t<T> get_read_extent_param(bool full_extent) const {
+ return Cache::read_extent_t<T>{
+ extent,
+ full_extent ? 0 : maybe_get_direct_partial_off(),
+ full_extent ? extent->get_length() : partial_len};
+ }
+ void read_succeeded() {
+ if (on_read) {
+ on_read(*extent);
+ }
+ }
+ friend class TransactionManager;
+ };
+ template <typename T, typename U>
+ requires std::is_base_of_v<read_pin_t<T>, U>
+ base_iertr::future<> read_pins(
+ Transaction &t,
+ std::vector<U> &pins,
+ lextent_init_func_t<T> maybe_init = [](T&) {})
+ {
+ LOG_PREFIX(TransactionManager::read_pins);
+ static_assert(is_logical_type(T::TYPE));
+ co_await trans_intr::parallel_for_each(
+ pins,
+ seastar::coroutine::lambda(
+ [this, &t, FNAME, maybe_init=std::move(maybe_init)](auto &pin)
+ -> get_child_iertr::future<> {
+ assert(is_aligned(pin.partial_off, get_block_size()));
+ assert(is_aligned(pin.partial_len, get_block_size()));
+ // must be user-oriented required by maybe_init
+ assert(is_user_transaction(t.get_src()));
+ if (pin.mapping.is_zero_reserved()) {
+ co_return;
+ }
+
+ pin.mapping = co_await pin.mapping.refresh();
+ if (pin.mapping.is_indirect()) {
+ pin.mapping = co_await lba_manager->complete_indirect_lba_mapping(
+ t, std::move(pin.mapping));
+ }
+ SUBTRACET(seastore_tm, "{} {}~{}",
+ t, pin.mapping, pin.partial_off, pin.partial_len);
+ auto ret = get_extent_if_linked<T>(t, pin.mapping);
+ if (ret.index() == 1) {
+ auto extent = co_await std::move(std::get<1>(ret));
+ pin.extent = std::move(extent);
+ pin.on_read = [maybe_init=std::move(maybe_init)](auto &extent) {
+ if (!extent.is_seen_by_users()) {
+ maybe_init(extent);
+ extent.set_seen_by_users();
+ }
+ };
+ co_return;
+ } else {
+ auto &r = std::get<0>(ret);
+ pin.extent = cache->prepare_absent_extent<T>(
+ t,
+ pin.mapping.get_val(),
+ pin.mapping.get_intermediate_length(),
+ pin.maybe_get_direct_partial_off(),
+ pin.partial_len,
+ [laddr=pin.mapping.get_intermediate_base(),
+ maybe_init=std::move(maybe_init),
+ child_pos=std::move(r.child_pos),
+ &t, this]
+ (T &extent) mutable {
+ assert(extent.is_logical());
+ assert(!extent.has_laddr());
+ assert(!extent.has_been_invalidated());
+ child_pos.link_child(&extent);
+ child_pos.invalidate_retired_placeholder(t, *cache, extent);
+ extent.set_laddr(laddr);
+ maybe_init(extent);
+ extent.set_seen_by_users();
+ });
+ co_return;
+ }
+ })
+ );
+ std::vector<Cache::read_extent_t<T>> extents;
+ for (auto &pin : pins) {
+ if (pin.mapping.is_zero_reserved()) {
+ continue;
+ }
+ extents.emplace_back(pin.get_read_extent_param(
+ full_extent_integrity_check));
+ }
+ co_await cache->read_extents_maybe_partial(t, std::move(extents));
+ for (auto &pin : pins) {
+ pin.read_succeeded();
+ }
+ }
+
template <typename T>
base_iertr::future<maybe_indirect_extent_t<T>> read_pin(
Transaction &t,