lba_manager needs to preload BtreeLBAPin and parent nodes.
Signed-off-by: Samuel Just <sjust@redhat.com>
using replay_delta_ret = replay_delta_ertr::future<>;
replay_delta_ret replay_delta(paddr_t record_base, const delta_info_t &delta);
+ /**
+ * init_cached_extents
+ *
+ * Calls passed lambda for each dirty cached block. Intended for use
+ * after replay to allow lba_manager (or w/e) to read in any ancestor
+ * blocks.
+ */
+ using init_cached_extents_ertr = crimson::errorator<
+ crimson::ct_error::input_output_error>;
+ using init_cached_extents_ret = replay_delta_ertr::future<>;
+ template <typename F>
+ init_cached_extents_ret init_cached_extents(
+ Transaction &t,
+ F &&f)
+ {
+ std::vector<CachedExtentRef> dirty;
+ for (auto &e : extents) {
+ dirty.push_back(CachedExtentRef(&e));
+ }
+ return seastar::do_with(
+ std::forward<F>(f),
+ std::move(dirty),
+ [&t](auto &f, auto &refs) mutable {
+ return crimson::do_for_each(
+ refs,
+ [&t, &f](auto &e) { return f(t, e); });
+ });
+ }
+
/**
* print
*
virtual complete_transaction_ret complete_transaction(
Transaction &t) = 0;
+ /**
+ * Should be called after replay on each cached extent.
+ * Implementation must initialize the LBAPin on any
+ * LogicalCachedExtent's and may also read in any dependent
+ * structures, etc.
+ */
+ using init_cached_extent_ertr = crimson::errorator<
+ crimson::ct_error::input_output_error>;
+ using init_cached_extent_ret = init_cached_extent_ertr::future<>;
+ virtual init_cached_extent_ret init_cached_extent(
+ Transaction &t,
+ CachedExtentRef e) = 0;
+
virtual ~LBAManager() {}
};
using LBAManagerRef = std::unique_ptr<LBAManager>;
return complete_transaction_ertr::now();
}
+BtreeLBAManager::init_cached_extent_ret BtreeLBAManager::init_cached_extent(
+ Transaction &t,
+ CachedExtentRef e)
+{
+ logger().debug("{}: {}", __func__, *e);
+ return get_root(t).safe_then(
+ [this, &t, e=std::move(e)](LBANodeRef root) mutable {
+ if (is_lba_node(*e)) {
+ auto lban = e->cast<LBANode>();
+ logger().debug("init_cached_extent: lba node, getting root");
+ return root->lookup(
+ op_context_t{cache, pin_set, t},
+ lban->get_node_meta().begin,
+ lban->get_node_meta().depth
+ ).safe_then([this, &t, e=std::move(e)](LBANodeRef c) {
+ if (c->get_paddr() == e->get_paddr()) {
+ assert(&*c == &*e);
+ logger().debug("init_cached_extent: {} initialized", *e);
+ } else {
+ // e is obsolete
+ logger().debug("init_cached_extent: {} obsolete", *e);
+ cache.retire_extent(t, e);
+ }
+ return init_cached_extent_ertr::now();
+ });
+ } else if (e->is_logical()) {
+ auto logn = e->cast<LogicalCachedExtent>();
+ return root->lookup_range(
+ op_context_t{cache, pin_set, t},
+ logn->get_laddr(),
+ logn->get_length()).safe_then(
+ [this, &t, logn=std::move(logn)](auto pins) {
+ if (pins.size() == 1) {
+ auto pin = std::move(pins.front());
+ pins.pop_front();
+ if (pin->get_paddr() == logn->get_paddr()) {
+ logn->set_pin(std::move(pin));
+ logger().debug("init_cached_extent: {} initialized", *logn);
+ } else {
+ // paddr doesn't match, remapped, obsolete
+ logger().debug("init_cached_extent: {} obsolete", *logn);
+ cache.retire_extent(t, logn);
+ }
+ } else {
+ // set of extents changed, obsolete
+ logger().debug("init_cached_extent: {} obsolete", *logn);
+ cache.retire_extent(t, logn);
+ }
+ return init_cached_extent_ertr::now();
+ });
+ } else {
+ logger().debug("init_cached_extent: {} skipped", *e);
+ return init_cached_extent_ertr::now();
+ }
+ });
+}
+
BtreeLBAManager::BtreeLBAManager(
SegmentManager &segment_manager,
Cache &cache)
complete_transaction_ret complete_transaction(
Transaction &t) final;
+ init_cached_extent_ret init_cached_extent(
+ Transaction &t,
+ CachedExtentRef e) final;
+
private:
SegmentManager &segment_manager;
Cache &cache;
virtual lba_node_meta_t get_node_meta() const = 0;
+ /**
+ * lookup
+ *
+ * Returns the node at the specified depth responsible
+ * for laddr
+ */
+ using lookup_ertr = crimson::errorator<
+ crimson::ct_error::input_output_error>;
+ using lookup_ret = lookup_ertr::future<LBANodeRef>;
+ virtual lookup_ret lookup(
+ op_context_t c,
+ laddr_t addr,
+ depth_t depth) = 0;
+
/**
* lookup_range
*
<< ", meta=" << get_meta();
}
+LBAInternalNode::lookup_ret LBAInternalNode::lookup(
+ op_context_t c,
+ laddr_t addr,
+ depth_t depth)
+{
+ auto meta = get_meta();
+ if (depth == get_meta().depth) {
+ return lookup_ret(
+ lookup_ertr::ready_future_marker{},
+ this);
+ }
+ assert(meta.begin <= addr);
+ assert(meta.end > addr);
+ auto [begin, end] = bound(addr, 0);
+ assert(begin == end + 1);
+ return get_lba_btree_extent(
+ c,
+ meta.depth,
+ begin->get_val(),
+ get_paddr()).safe_then([c, addr, depth](auto child) {
+ return child->lookup(c, addr, depth);
+ });
+}
+
LBAInternalNode::lookup_range_ret LBAInternalNode::lookup_range(
op_context_t c,
laddr_t addr,
return is_mutation_pending() ? &delta_buffer : nullptr;
}
+ lookup_ret lookup(op_context_t c, laddr_t addr, depth_t depth) final;
+
lookup_range_ret lookup_range(
op_context_t c,
laddr_t addr,
return is_mutation_pending() ? &delta_buffer : nullptr;
}
+ lookup_ret lookup(op_context_t c, laddr_t addr, depth_t depth) final
+ {
+ return lookup_ret(
+ lookup_ertr::ready_future_marker{},
+ this);
+ }
+
lookup_range_ret lookup_range(
op_context_t c,
laddr_t addr,
return cache.replay_delta(paddr, e);
}).safe_then([this] {
return journal.open_for_write();
+ }).safe_then([this] {
+ return seastar::do_with(
+ create_transaction(),
+ [this](auto &t) {
+ return cache.init_cached_extents(*t, [this](auto &t, auto &e) {
+ return lba_manager.init_cached_extent(t, e);
+ }).safe_then([this, &t]() mutable {
+ return submit_transaction(std::move(t));
+ });
+ });
}).handle_error(
mount_ertr::pass_further{},
crimson::ct_error::all_same_way([] {