std::ostream& operator<<(std::ostream& out, const lba_map_val_t& v)
{
- return out << "lba_map_val_t("
- << v.pladdr
- << "~0x" << std::hex << v.len
+ out << "lba_map_val_t(";
+ if (v.shadow_paddr != P_ADDR_NULL) {
+ out << '[' << v.pladdr << ',' << v.shadow_paddr << ']';
+ } else {
+ out << v.pladdr;
+ }
+ return out << "~0x" << std::hex << v.len
<< ", type=" << (extent_types_t)v.type
<< ", checksum=0x" << v.checksum
<< ", refcount=" << std::dec << v.refcount
extent_len_t len = 0; ///< length of mapping
pladdr_t pladdr; ///< direct addr of mapping or
// laddr of a direct lba mapping(see btree_lba_manager.h)
+ paddr_t shadow_paddr;
extent_ref_count_t refcount = 0; ///< refcount
checksum_t checksum = 0; ///< checksum of original block written at paddr (TODO)
extent_types_t type = extent_types_t::NONE;
lba_map_val_t(
extent_len_t len,
pladdr_t pladdr,
+ paddr_t shadow_paddr,
extent_ref_count_t refcount,
checksum_t checksum,
extent_types_t type)
- : len(len), pladdr(pladdr), refcount(refcount),
- checksum(checksum), type(type) {}
+ : len(len), pladdr(pladdr), shadow_paddr(shadow_paddr),
+ refcount(refcount), checksum(checksum), type(type) {}
bool operator==(const lba_map_val_t&) const = default;
};
struct __attribute__((packed)) lba_map_val_le_t {
extent_len_le_t len = init_extent_len_le(0);
pladdr_le_t pladdr;
+ paddr_le_t shadow_paddr;
extent_ref_count_le_t refcount{0};
checksum_le_t checksum{0};
extent_types_le_t type{EXTENT_TYPES_MAX};
return lba_map_val_t{
len,
pladdr,
+ shadow_paddr,
refcount,
checksum,
static_cast<extent_types_t>(type)};
const LBACursor &indirect_cursor)
{
ceph_assert(indirect_cursor.is_indirect());
+ ceph_assert(!indirect_cursor.has_shadow_paddr());
return get_cursors(
c,
btree,
lba_map_val_t val{
len,
pladdr_t{P_ADDR_ZERO},
+ P_ADDR_NULL,
EXTENT_DEFAULT_REF_COUNT,
0,
type};
lba_map_val_t{
ext->get_length(),
pladdr_t{ext->get_paddr()},
+ P_ADDR_NULL,
EXTENT_DEFAULT_REF_COUNT,
ext->get_last_committed_crc(),
ext->get_type()},
lba_map_val_t{
len,
pladdr_t{inter_key.get_local_clone_id()},
+ P_ADDR_NULL,
EXTENT_DEFAULT_REF_COUNT,
0,
mapping->get_extent_type()},
}
ceph_assert((pos.get_key() + pos.get_val().len) > begin);
if (pos.get_val().pladdr.is_paddr()) {
- f(pos.get_key(), pos.get_val().pladdr.get_paddr(), pos.get_val().len);
+ f(pos.get_key(), pos.get_val().pladdr.get_paddr(),
+ pos.get_val().shadow_paddr, pos.get_val().len);
}
return LBABtree::iterate_repeat_ret_inner(
interruptible::ready_future_marker{},
assert(!addr.is_null());
lba_map_val_t ret = in;
ceph_assert(in.pladdr.is_paddr());
- ceph_assert(in.pladdr.get_paddr() == prev_addr);
ceph_assert(in.len == prev_len);
- ret.pladdr = addr;
- ret.len = len;
- ret.checksum = checksum;
+ if (prev_addr == in.pladdr.get_paddr()) {
+ ret.pladdr = addr;
+ ret.len = len;
+ ret.checksum = checksum;
+ if (ret.shadow_paddr != P_ADDR_NULL) {
+ ceph_assert(
+ addr.get_device_id() != ret.shadow_paddr.get_device_id());
+ }
+ } else {
+ ceph_assert(in.shadow_paddr == prev_addr);
+ ret.shadow_paddr = addr;
+ }
return ret;
},
&nextent
} else {
auto paddr = val.pladdr.get_paddr();
val.pladdr = paddr + remap.offset;
+ if (val.shadow_paddr != P_ADDR_NULL) {
+ val.shadow_paddr = val.shadow_paddr.add_offset(remap.offset);
+ }
}
val.refcount = EXTENT_DEFAULT_REF_COUNT;
// Checksum will be updated when the committing the transaction
if (!iter.is_end()) {
assert(iter.get_key() >= dest_laddr + ret.src->get_length());
}
+ paddr_t shadow = P_ADDR_NULL;
+ if (!ret.src->is_indirect() && ret.src->has_shadow_paddr()) {
+ shadow = ret.src->get_shadow_paddr();
+ }
// insert the src mapping to dest
// attach extent to the new mapping if it exists
pladdr_t addr;
lba_map_val_t{
ret.src->get_length(),
std::move(addr),
+ shadow,
EXTENT_DEFAULT_REF_COUNT,
ret.src->is_indirect() ? 0 : ret.src->get_checksum(),
ret.src->get_extent_type()},
lba_map_val_t val = in;
val.pladdr = ret.dest->get_key().get_local_clone_id();
val.checksum = 0;
+ val.shadow_paddr = P_ADDR_NULL;
return val;
},
nullptr
laddr_t dest_laddr,
LBACursorRef dest) final {
assert(src->is_indirect());
+ assert(!src->has_shadow_paddr());
return _move_mapping(
t, std::move(src), dest_laddr, std::move(dest), nullptr);
}
{
len,
pladdr_t(P_ADDR_ZERO),
+ P_ADDR_NULL,
EXTENT_DEFAULT_REF_COUNT,
0,
type
{
len,
pladdr_t(intermediate_key.get_local_clone_id()),
+ P_ADDR_NULL,
EXTENT_DEFAULT_REF_COUNT,
0, // crc will only be used and checked with LBA direct mappings
// also see pin_to_extent(_by_type)
LogicalChildNode& extent) {
return {
laddr,
- {len, pladdr_t(paddr), refcount, checksum, extent.get_type()},
+ {len, pladdr_t(paddr), P_ADDR_NULL, refcount, checksum, extent.get_type()},
&extent
};
}
* checksum : ceph_le32[1] 4B
* size : ceph_le32[1] 4B
* meta : lba_node_meta_le_t[1] 36B
- * keys : laddr_le_t[CAPACITY] (106*16)B
- * values : lba_map_val_le_t[CAPACITY] (106*21)B
- * = 4077B
+ * keys : laddr_le_t[CAPACITY] (88*16)B
+ * values : lba_map_val_le_t[CAPACITY] (88*30)B
+ * = 4092B
*
* TODO: update FixedKVNodeLayout to handle the above calculation
* TODO: the above alignment probably isn't portable without further work
*/
-constexpr size_t LEAF_NODE_CAPACITY = 106;
+constexpr size_t LEAF_NODE_CAPACITY = 88;
struct LBALeafNode
: FixedKVLeafNode<
}
extent_types_t get_extent_type() const {
+ assert(iter.get_val().type != extent_types_t::NONE);
assert(is_viewable());
assert(!is_end());
return iter.get_val().type;
}
+ bool has_shadow_paddr() const {
+ return iter.get_val().shadow_paddr != P_ADDR_NULL;
+ }
+
+ paddr_t get_shadow_paddr() const {
+ assert(has_shadow_paddr());
+ return iter.get_val().shadow_paddr;
+ }
+
base_iertr::future<> refresh();
private:
using scan_mappings_iertr = base_iertr;
using scan_mappings_ret = scan_mappings_iertr::future<>;
using scan_mappings_func_t = std::function<
- void(laddr_t, paddr_t, extent_len_t)>;
+ void(laddr_t, paddr_t, paddr_t, extent_len_t)>;
virtual scan_mappings_ret scan_mappings(
Transaction &t,
laddr_t begin,
return direct_cursor->get_length();
}
+ bool has_shadow_val() const {
+ assert(is_linked_direct());
+ assert(!direct_cursor->is_end());
+ return direct_cursor->has_shadow_paddr();
+ }
+
+ paddr_t get_shadow_val() const {
+ assert(is_linked_direct());
+ assert(!direct_cursor->is_end());
+ return direct_cursor->get_shadow_paddr();
+ }
+
checksum_t get_checksum() const {
assert(is_linked_direct());
assert(!direct_cursor->is_end());
extent_ref_count_t refcount = cursor->get_refcount();
auto laddr = cursor->get_laddr();
auto length = cursor->get_length();
+ paddr_t shadow_addr = P_ADDR_NULL;
+ if (cursor->has_shadow_paddr()) {
+ shadow_addr = cursor->get_shadow_paddr();
+ }
assert(refcount > 0);
--refcount;
co_await lba_manager->update_mapping_refcount(
t, std::move(cursor), -1);
if (refcount == 0) {
cache->retire_extent(t, ref);
+ if (shadow_addr != P_ADDR_NULL) {
+ if (auto shadow = ref->get_shadow(); shadow) {
+ t.add_absent_to_retired_set(shadow);
+ } else {
+ auto laddr = ref->get_laddr();
+ cache->retire_absent_extent_addr_by_type(
+ t, laddr, shadow_addr, length, ref->get_type(),
+ [laddr](auto &extent) {
+ auto lextent = extent.template cast<LogicalChildNode>();
+ assert(extent.is_logical());
+ assert(!lextent->has_laddr());
+ assert(!extent.has_been_invalidated());
+ lextent->set_laddr(laddr);
+ extent.set_shadow_extent(true);
+ });
+ }
+ }
}
DEBUGT("removed {}~0x{:x} refcount={} -- {}",
t, laddr, length,
}
);
}
+ if (mapping.has_shadow_val()) {
+ cache->retire_absent_extent_addr(
+ t, mapping.get_intermediate_base(),
+ mapping.get_shadow_val(),
+ mapping.get_intermediate_length());
+ }
}
LBACursorRef indirect_cursor;
if (!mapping.is_indirect() && mapping.is_zero_reserved()) {
SUBDEBUGT(seastore_tm, "zero reserved, mapping {}, {} remaps",
t, mapping, remaps);
+ ceph_assert(!mapping.has_shadow_val());
//TODO: drop this assert
assert(mapping.get_extent_type() == extent_types_t::OBJECT_DATA_BLOCK);
auto type = mapping.get_extent_type();
lextent->set_laddr(laddr);
}
);
+ if (pin.has_shadow_val()) {
+ cache->retire_absent_extent_addr_by_type(
+ t, pin.get_key(), pin.get_shadow_val(),
+ original_len, pin.get_extent_type(),
+ [laddr](auto &extent) {
+ auto lextent = extent.template cast<LogicalChildNode>();
+ assert(extent.is_logical());
+ assert(!lextent->has_laddr());
+ assert(!extent.has_been_invalidated());
+ lextent->set_laddr(laddr);
+ }
+ );
+ }
+
}
}
auto remap_len = remap.len;
auto remap_laddr = (original_laddr + remap_offset).checked_to_laddr();
auto remap_paddr = original_paddr.add_offset(remap_offset);
+ auto shadow_paddr = P_ADDR_NULL;
+ if (pin.has_shadow_val()) {
+ assert(pin.get_shadow_val() != P_ADDR_NULL);
+ shadow_paddr = pin.get_shadow_val().add_offset(remap_offset);
+ }
SUBDEBUGT(seastore_tm, "remap direct pin into {}~0x{:x} {} ...",
t, remap_laddr, remap_len, remap_paddr);
ceph_assert(remap_len < original_len);
remap_offset,
remap_len,
original_bptr);
+ if (shadow_paddr != P_ADDR_NULL) {
+ SUBTRACET(seastore_tm, "remap shadow {}", t, shadow_paddr);
+ auto cold_ext = cache->alloc_remapped_extent<T>(
+ t,
+ remap_laddr,
+ shadow_paddr,
+ remap_offset,
+ remap_len,
+ std::nullopt);
+ boost::ignore_unused(cold_ext);
+ }
// user must initialize the logical extent themselves.
remapped_extent->set_seen_by_users();
remap.extent = remapped_extent.get();
}
static auto get_map_val(extent_len_t len, extent_types_t type) {
- return lba_map_val_t{0, (pladdr_t)P_ADDR_NULL, len, 0, type};
+ return lba_map_val_t{0, (pladdr_t)P_ADDR_NULL, P_ADDR_NULL, len, 0, type};
}
device_off_t next_off = 0;
*t.t,
L_ADDR_MIN,
L_ADDR_MAX,
- [iter=t.mappings.begin(), &t](auto l, auto p, auto len) mutable {
+ [iter=t.mappings.begin(), &t](auto l, auto p, auto s, auto len) mutable {
EXPECT_NE(iter, t.mappings.end());
EXPECT_EQ(l, iter->first);
EXPECT_EQ(p, iter->second.addr);
t,
get_laddr_hint(0),
L_ADDR_MAX,
- [iter=overlay.begin(), &overlay](auto l, auto p, auto len) mutable {
+ [iter=overlay.begin(), &overlay](auto l, auto p, auto s, auto len) mutable {
EXPECT_NE(iter, overlay.end());
logger().debug(
"check_mappings: scan {}",
laddr_t ADDR = get_laddr_hint(0xFF * 4096);
epm->prefill_fragmented_devices();
auto t = create_transaction();
- for (int i = 0; i < 1974; i++) {
+ for (int i = 0; i < 1958; i++) {
auto extents = alloc_extents(t, (ADDR + i * 16384).checked_to_laddr(), 16384, 'a');
}
- alloc_extents_deemed_fail(t, (ADDR + 1974 * 16384).checked_to_laddr(), 16384, 'a');
+ alloc_extents_deemed_fail(t, (ADDR + 1958 * 16384).checked_to_laddr(), 16384, 'a');
check_mappings(t);
check();
submit_transaction(std::move(t));