Skip to content

Commit 2721169

Browse files
committed
crimson/os/seastore/cache: add an efficient method to check if extents are
viewable to transactions Instead of searching the transaction's retired_set to determine whether an extent has been retired, we add the transaction that's retiring an extent to that extent's retired_transactions field and search that field to do the check. Since the probability of multiple transactions retiring the same extent is very low, this approach should be more cpu efficient. Signed-off-by: Xuehan Xu <[email protected]>
1 parent 09e06b5 commit 2721169

File tree

4 files changed

+104
-38
lines changed

4 files changed

+104
-38
lines changed

src/crimson/os/seastore/btree/btree_range_pin.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,27 @@ class BtreeNodeMapping : public PhysicalNodeMapping<key_t, val_t> {
194194
return parent->has_been_invalidated();
195195
}
196196

197+
bool is_unviewable_by_trans(CachedExtent& extent, Transaction &t) const {
198+
if (!extent.is_valid()) {
199+
return true;
200+
}
201+
if (extent.is_pending()) {
202+
assert(extent.is_pending_in_trans(t.get_trans_id()));
203+
return false;
204+
}
205+
auto &pendings = extent.mutation_pendings;
206+
auto trans_id = t.get_trans_id();
207+
bool unviewable = (pendings.find(trans_id, trans_spec_view_t::cmp_t()) !=
208+
pendings.end());
209+
if (!unviewable) {
210+
auto &trans = extent.retired_transactions;
211+
unviewable = (trans.find(trans_id, trans_spec_view_t::cmp_t()) !=
212+
trans.end());
213+
assert(unviewable == t.is_retired(extent.get_paddr(), extent.get_length()));
214+
}
215+
return unviewable;
216+
}
217+
197218
get_child_ret_t<LogicalCachedExtent> get_logical_extent(Transaction&) final;
198219
bool is_stable() const final;
199220
bool is_data_stable() const final;

src/crimson/os/seastore/cache.cc

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ void Cache::mark_transaction_conflicted(
884884
if (t.get_src() != Transaction::src_t::READ) {
885885
io_stat_t retire_stat;
886886
for (auto &i: t.retired_set) {
887-
retire_stat.increment(i->get_length());
887+
retire_stat.increment(i.extent->get_length());
888888
}
889889
efforts.retire.increment_stat(retire_stat);
890890

@@ -1249,18 +1249,19 @@ record_t Cache::prepare_record(
12491249
alloc_delta_t rel_delta;
12501250
rel_delta.op = alloc_delta_t::op_types_t::CLEAR;
12511251
for (auto &i: t.retired_set) {
1252+
auto &extent = i.extent;
12521253
get_by_ext(efforts.retire_by_ext,
1253-
i->get_type()).increment(i->get_length());
1254-
retire_stat.increment(i->get_length());
1255-
DEBUGT("retired and remove extent -- {}", t, *i);
1256-
commit_retire_extent(t, i);
1257-
if (is_backref_mapped_extent_node(i)
1258-
|| is_retired_placeholder(i->get_type())) {
1254+
extent->get_type()).increment(extent->get_length());
1255+
retire_stat.increment(extent->get_length());
1256+
DEBUGT("retired and remove extent -- {}", t, *extent);
1257+
commit_retire_extent(t, extent);
1258+
if (is_backref_mapped_extent_node(extent)
1259+
|| is_retired_placeholder(extent->get_type())) {
12591260
rel_delta.alloc_blk_ranges.emplace_back(
1260-
i->get_paddr(),
1261+
extent->get_paddr(),
12611262
L_ADDR_NULL,
1262-
i->get_length(),
1263-
i->get_type());
1263+
extent->get_length(),
1264+
extent->get_type());
12641265
}
12651266
}
12661267
alloc_deltas.emplace_back(std::move(rel_delta));
@@ -1621,7 +1622,8 @@ void Cache::complete_commit(
16211622
}
16221623

16231624
for (auto &i: t.retired_set) {
1624-
epm.mark_space_free(i->get_paddr(), i->get_length());
1625+
auto &extent = i.extent;
1626+
epm.mark_space_free(extent->get_paddr(), extent->get_length());
16251627
}
16261628
for (auto &i: t.existing_block_list) {
16271629
if (i->is_valid()) {
@@ -1638,24 +1640,25 @@ void Cache::complete_commit(
16381640

16391641
last_commit = start_seq;
16401642
for (auto &i: t.retired_set) {
1641-
i->dirty_from_or_retired_at = start_seq;
1642-
if (is_backref_mapped_extent_node(i)
1643-
|| is_retired_placeholder(i->get_type())) {
1643+
auto &extent = i.extent;
1644+
extent->dirty_from_or_retired_at = start_seq;
1645+
if (is_backref_mapped_extent_node(extent)
1646+
|| is_retired_placeholder(extent->get_type())) {
16441647
DEBUGT("backref_list free {} len {}",
16451648
t,
1646-
i->get_paddr(),
1647-
i->get_length());
1649+
extent->get_paddr(),
1650+
extent->get_length());
16481651
backref_list.emplace_back(
16491652
std::make_unique<backref_entry_t>(
1650-
i->get_paddr(),
1653+
extent->get_paddr(),
16511654
L_ADDR_NULL,
1652-
i->get_length(),
1653-
i->get_type(),
1655+
extent->get_length(),
1656+
extent->get_type(),
16541657
start_seq));
1655-
} else if (is_backref_node(i->get_type())) {
1656-
remove_backref_extent(i->get_paddr());
1658+
} else if (is_backref_node(extent->get_type())) {
1659+
remove_backref_extent(extent->get_paddr());
16571660
} else {
1658-
ERRORT("{}", t, *i);
1661+
ERRORT("{}", t, *extent);
16591662
ceph_abort("not possible");
16601663
}
16611664
}

src/crimson/os/seastore/cached_extent.h

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ class CachedExtent
651651
friend struct paddr_cmp;
652652
friend struct ref_paddr_cmp;
653653
friend class ExtentIndex;
654+
friend struct trans_retired_extent_link_t;
654655

655656
/// Pointer to containing index (or null)
656657
ExtentIndex *parent_index = nullptr;
@@ -735,6 +736,7 @@ class CachedExtent
735736

736737
protected:
737738
trans_view_set_t mutation_pendings;
739+
trans_view_set_t retired_transactions;
738740

739741
CachedExtent(CachedExtent &&other) = delete;
740742
CachedExtent(ceph::bufferptr &&_ptr) : ptr(std::move(_ptr)) {
@@ -884,17 +886,54 @@ struct paddr_cmp {
884886
}
885887
};
886888

889+
// trans_retired_extent_link_t is used to link stable extents with
890+
// the transactions that retired them. With this link, we can find
891+
// out whether an extent has been retired by a specific transaction
892+
// in a way that's more efficient than searching through the transaction's
893+
// retired_set (Transaction::is_retired())
894+
struct trans_retired_extent_link_t {
895+
CachedExtentRef extent;
896+
// We use trans_spec_view_t instead of transaction_id_t, so that,
897+
// when a transaction is deleted or reset, we can efficiently remove
898+
// that transaction from the extents' extent-transaction link set.
899+
// Otherwise, we have to search through each extent's "retired_transactions"
900+
// to remove the transaction
901+
trans_spec_view_t trans_view;
902+
trans_retired_extent_link_t(CachedExtentRef extent, transaction_id_t id)
903+
: extent(extent), trans_view{id}
904+
{
905+
assert(extent->is_stable());
906+
extent->retired_transactions.insert(trans_view);
907+
}
908+
};
909+
887910
/// Compare extent refs by paddr
888911
struct ref_paddr_cmp {
889912
using is_transparent = paddr_t;
890-
bool operator()(const CachedExtentRef &lhs, const CachedExtentRef &rhs) const {
891-
return lhs->poffset < rhs->poffset;
892-
}
893-
bool operator()(const paddr_t &lhs, const CachedExtentRef &rhs) const {
894-
return lhs < rhs->poffset;
895-
}
896-
bool operator()(const CachedExtentRef &lhs, const paddr_t &rhs) const {
897-
return lhs->poffset < rhs;
913+
bool operator()(
914+
const trans_retired_extent_link_t &lhs,
915+
const trans_retired_extent_link_t &rhs) const {
916+
return lhs.extent->poffset < rhs.extent->poffset;
917+
}
918+
bool operator()(
919+
const paddr_t &lhs,
920+
const trans_retired_extent_link_t &rhs) const {
921+
return lhs < rhs.extent->poffset;
922+
}
923+
bool operator()(
924+
const trans_retired_extent_link_t &lhs,
925+
const paddr_t &rhs) const {
926+
return lhs.extent->poffset < rhs;
927+
}
928+
bool operator()(
929+
const CachedExtentRef &lhs,
930+
const trans_retired_extent_link_t &rhs) const {
931+
return lhs->poffset < rhs.extent->poffset;
932+
}
933+
bool operator()(
934+
const trans_retired_extent_link_t &lhs,
935+
const CachedExtentRef &rhs) const {
936+
return lhs.extent->poffset < rhs->poffset;
898937
}
899938
};
900939

@@ -910,7 +949,7 @@ class addr_extent_set_base_t
910949

911950
using pextent_set_t = addr_extent_set_base_t<
912951
paddr_t,
913-
CachedExtentRef,
952+
trans_retired_extent_link_t,
914953
ref_paddr_cmp
915954
>;
916955

src/crimson/os/seastore/transaction.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,14 @@ class Transaction {
126126
ref->set_invalid(*this);
127127
write_set.erase(*ref);
128128
assert(ref->prior_instance);
129-
retired_set.insert(ref->prior_instance);
129+
retired_set.emplace(ref->prior_instance, trans_id);
130130
assert(read_set.count(ref->prior_instance->get_paddr()));
131131
ref->prior_instance.reset();
132132
} else {
133133
// && retired_set.count(ref->get_paddr()) == 0
134134
// If it's already in the set, insert here will be a noop,
135135
// which is what we want.
136-
retired_set.insert(ref);
136+
retired_set.emplace(ref, trans_id);
137137
}
138138
}
139139

@@ -262,9 +262,9 @@ class Transaction {
262262
{
263263
auto where = retired_set.find(&placeholder);
264264
assert(where != retired_set.end());
265-
assert(where->get() == &placeholder);
265+
assert(where->extent.get() == &placeholder);
266266
where = retired_set.erase(where);
267-
retired_set.emplace_hint(where, &extent);
267+
retired_set.emplace_hint(where, &extent, trans_id);
268268
}
269269
}
270270

@@ -318,11 +318,14 @@ class Transaction {
318318

319319
bool is_retired(paddr_t paddr, extent_len_t len) {
320320
auto iter = retired_set.lower_bound(paddr);
321-
if (iter == retired_set.end() ||
322-
(*iter)->get_paddr() != paddr) {
321+
if (iter == retired_set.end()) {
322+
return false;
323+
}
324+
auto &extent = iter->extent;
325+
if (extent->get_paddr() != paddr) {
323326
return false;
324327
} else {
325-
assert(len == (*iter)->get_length());
328+
assert(len == extent->get_length());
326329
return true;
327330
}
328331
}

0 commit comments

Comments
 (0)