auto &backref_buffer = cache.get_backref_buffer();
if (backref_buffer) {
return seastar::do_with(
- backref_buffer->backrefs.begin(),
+ backref_buffer->backrefs_by_seq.begin(),
JOURNAL_SEQ_NULL,
[this, &t, &limit, &backref_buffer, max](auto &iter, auto &inserted_to) {
return trans_intr::repeat(
[&iter, this, &t, &limit, &backref_buffer, max, &inserted_to]()
-> merge_cached_backrefs_iertr::future<seastar::stop_iteration> {
- if (iter == backref_buffer->backrefs.end())
+ if (iter == backref_buffer->backrefs_by_seq.end())
return seastar::make_ready_future<seastar::stop_iteration>(
seastar::stop_iteration::yes);
auto &seq = iter->first;
- auto &backref_list = iter->second;
+ auto &backref_list = iter->second.br_list;
LOG_PREFIX(BtreeBackrefManager::merge_cached_backrefs);
DEBUGT("seq {}, limit {}, num_fresh_backref {}"
, t, seq, limit, t.get_num_fresh_backref());
backref_list,
[this, &t](auto &backref) {
LOG_PREFIX(BtreeBackrefManager::merge_cached_backrefs);
- if (backref->laddr != L_ADDR_NULL) {
+ if (backref.laddr != L_ADDR_NULL) {
DEBUGT("new mapping: {}~{} -> {}",
- t, backref->paddr, backref->len, backref->laddr);
+ t, backref.paddr, backref.len, backref.laddr);
return new_mapping(
t,
- backref->paddr,
- backref->len,
- backref->laddr,
- backref->type).si_then([](auto &&pin) {
+ backref.paddr,
+ backref.len,
+ backref.laddr,
+ backref.type).si_then([](auto &&pin) {
return seastar::now();
});
} else {
- DEBUGT("remove mapping: {}", t, backref->paddr);
+ DEBUGT("remove mapping: {}", t, backref.paddr);
return remove_mapping(
t,
- backref->paddr).si_then([](auto&&) {
+ backref.paddr).si_then([](auto&&) {
return seastar::now();
}).handle_error_interruptible(
crimson::ct_error::input_output_error::pass_further(),
});
}
+bool BtreeBackrefManager::backref_should_be_removed(paddr_t paddr) {
+ return cache.backref_should_be_removed(paddr);
+}
+
} // namespace crimson::os::seastore::backref
void cache_new_backref_extent(paddr_t paddr, extent_types_t type) final;
+ bool backref_should_be_removed(paddr_t paddr) final;
+
private:
SegmentManagerGroup &sm_group;
Cache &cache;
paddr_t start,
paddr_t end) = 0;
+ virtual bool backref_should_be_removed(paddr_t paddr) = 0;
+
using retrieve_backref_extents_iertr = trans_iertr<
crimson::errorator<
crimson::ct_error::input_output_error>
LOG_PREFIX(Cache::backref_batch_update);
DEBUG("inserting {} entries", list.size());
if (!backref_buffer) {
- backref_buffer = std::make_unique<backref_buffer_t>();
+ backref_buffer = std::make_unique<backref_cache_t>();
}
// backref_buf_entry_t::laddr == L_ADDR_NULL means erase
for (auto &ent : list) {
if (ent->laddr == L_ADDR_NULL) {
- auto [it, insert] = backref_remove_set.insert(*ent);
- boost::ignore_unused(insert);
+ auto insert_set_iter = backref_inserted_set.find(
+ ent->paddr, backref_buf_entry_t::cmp_t());
+ if (insert_set_iter == backref_inserted_set.end()) {
+ // backref to be removed isn't in the backref buffer,
+ // it must be in the backref tree.
+ auto [it, insert] = backref_remove_set.insert(*ent);
+ boost::ignore_unused(insert);
#ifndef NDEBUG
- if (!insert) {
- ERROR("backref_remove_set already contains {}", ent->paddr);
- }
+ if (!insert) {
+ ERROR("backref_remove_set already contains {}", ent->paddr);
+ }
#endif
- assert(insert);
- } else {
-#ifndef NDEBUG
- auto r = backref_remove_set.erase(ent->paddr, backref_buf_entry_t::cmp_t());
- if (r) {
- ERROR("backref_remove_set contains: {}", ent->paddr);
+ assert(insert);
+ } else {
+ // the backref insertion hasn't been applied to the
+ // backref tree
+ auto seq = insert_set_iter->seq;
+ auto it = backref_buffer->backrefs_by_seq.find(seq);
+ ceph_assert(it != backref_buffer->backrefs_by_seq.end());
+ auto &backref_buf = it->second;
+ assert(insert_set_iter->backref_buf_hook.is_linked());
+ backref_buf.br_list.erase(
+ backref_buf_entry_t::list_t::s_iterator_to(*insert_set_iter));
+ backref_inserted_set.erase(insert_set_iter);
}
- assert(!r);
-#endif
+ } else {
auto [it, insert] = backref_inserted_set.insert(*ent);
boost::ignore_unused(insert);
assert(insert);
}
}
- auto iter = backref_buffer->backrefs.find(seq);
- if (iter == backref_buffer->backrefs.end()) {
- backref_buffer->backrefs.emplace(
+ auto iter = backref_buffer->backrefs_by_seq.find(seq);
+ if (iter == backref_buffer->backrefs_by_seq.end()) {
+ backref_buffer->backrefs_by_seq.emplace(
seq, std::move(list));
} else {
- iter->second.insert(
- iter->second.end(),
+ for (auto &ref : list) {
+ iter->second.br_list.push_back(*ref);
+ }
+ iter->second.backrefs.insert(
+ iter->second.backrefs.end(),
std::make_move_iterator(list.begin()),
std::make_move_iterator(list.end()));
}
len(alloc_blk.len),
type(alloc_blk.type)
{}
- const paddr_t paddr = P_ADDR_NULL;
- const laddr_t laddr = L_ADDR_NULL;
- const extent_len_t len = 0;
- const extent_types_t type =
+ paddr_t paddr = P_ADDR_NULL;
+ laddr_t laddr = L_ADDR_NULL;
+ extent_len_t len = 0;
+ extent_types_t type =
extent_types_t::ROOT;
- const journal_seq_t seq;
+ journal_seq_t seq;
friend bool operator< (
const backref_buf_entry_t &l,
const backref_buf_entry_t &r) {
const backref_buf_entry_t &r) {
return l.paddr == r.paddr;
}
- using hook_t =
+ using set_hook_t =
boost::intrusive::set_member_hook<
boost::intrusive::link_mode<
boost::intrusive::auto_unlink>>;
- hook_t backref_set_hook;
+ set_hook_t backref_set_hook;
+
+ using list_hook_t =
+ boost::intrusive::list_member_hook<
+ boost::intrusive::link_mode<
+ boost::intrusive::auto_unlink>>;
+ list_hook_t backref_buf_hook;
+
using backref_set_member_options = boost::intrusive::member_hook<
backref_buf_entry_t,
- hook_t,
+ set_hook_t,
&backref_buf_entry_t::backref_set_hook>;
using set_t = boost::intrusive::set<
backref_buf_entry_t,
backref_set_member_options,
boost::intrusive::constant_time_size<false>>;
+
+ using backref_list_member_options = boost::intrusive::member_hook<
+ backref_buf_entry_t,
+ list_hook_t,
+ &backref_buf_entry_t::backref_buf_hook>;
+ using list_t = boost::intrusive::list<
+ backref_buf_entry_t,
+ backref_list_member_options,
+ boost::intrusive::constant_time_size<false>>;
struct cmp_t {
using is_transparent = paddr_t;
bool operator()(
using backref_buf_entry_ref =
std::unique_ptr<backref_buf_entry_t>;
-struct backref_buffer_t {
- std::map<journal_seq_t, std::vector<backref_buf_entry_ref>> backrefs;
+struct backref_buf_t {
+ backref_buf_t(std::vector<backref_buf_entry_ref> &&refs) : backrefs(std::move(refs)) {
+ for (auto &ref : backrefs) {
+ br_list.push_back(*ref);
+ }
+ }
+ std::vector<backref_buf_entry_ref> backrefs;
+ backref_buf_entry_t::list_t br_list;
};
-using backref_buffer_ref = std::unique_ptr<backref_buffer_t>;
+
+struct backref_cache_t {
+ std::map<journal_seq_t, backref_buf_t> backrefs_by_seq;
+};
+using backref_cache_ref = std::unique_ptr<backref_cache_t>;
/**
* Cache
}
}
- backref_buffer_ref backref_buffer;
+ backref_cache_ref backref_buffer;
// backrefs that needs to be inserted into the backref tree
backref_buf_entry_t::set_t backref_inserted_set;
backref_buf_entry_t::set_t backref_remove_set; // backrefs needs to be removed
return *it;
}
+ bool backref_should_be_removed(paddr_t addr) {
+ return backref_remove_set.find(
+ addr, backref_buf_entry_t::cmp_t()) != backref_remove_set.end();
+ }
+
const backref_buf_entry_t::set_t& get_backrefs() {
return backref_inserted_set;
}
return backref_remove_set;
}
- backref_buffer_ref& get_backref_buffer() {
+ backref_cache_ref& get_backref_buffer() {
return backref_buffer;
}
void trim_backref_bufs(const journal_seq_t &trim_to) {
LOG_PREFIX(Cache::trim_backref_bufs);
SUBDEBUG(seastore_cache, "trimming to {}", trim_to);
- if (backref_buffer && !backref_buffer->backrefs.empty()) {
- assert(backref_buffer->backrefs.rbegin()->first >= trim_to);
- auto iter = backref_buffer->backrefs.upper_bound(trim_to);
- backref_buffer->backrefs.erase(
- backref_buffer->backrefs.begin(), iter);
+ if (backref_buffer && !backref_buffer->backrefs_by_seq.empty()) {
+ assert(backref_buffer->backrefs_by_seq.rbegin()->first >= trim_to);
+ auto iter = backref_buffer->backrefs_by_seq.upper_bound(trim_to);
+ backref_buffer->backrefs_by_seq.erase(
+ backref_buffer->backrefs_by_seq.begin(), iter);
}
}
std::optional<journal_seq_t> get_oldest_backref_dirty_from() const {
LOG_PREFIX(Cache::get_oldest_backref_dirty_from);
journal_seq_t backref_oldest = JOURNAL_SEQ_NULL;
- if (backref_buffer && !backref_buffer->backrefs.empty()) {
- backref_oldest = backref_buffer->backrefs.begin()->first;
+ if (backref_buffer && !backref_buffer->backrefs_by_seq.empty()) {
+ backref_oldest = backref_buffer->backrefs_by_seq.begin()->first;
}
if (backref_oldest == JOURNAL_SEQ_NULL) {
SUBDEBUG(seastore_cache, "backref_oldest: null");
void SegmentCleaner::mark_space_free(
paddr_t addr,
- extent_len_t len,
- bool force)
+ extent_len_t len)
{
LOG_PREFIX(SegmentCleaner::mark_space_free);
- if (!init_complete && !force) {
+ if (!init_complete) {
return;
}
if (addr.get_addr_type() != addr_types_t::SEGMENT) {
void mark_space_free(
paddr_t addr,
- extent_len_t len,
- bool force = false);
+ extent_len_t len);
SpaceTrackerIRef get_empty_space_tracker() const {
return space_tracker->make_empty();
t,
addr,
len);
- if (addr.is_real()) {
+ if (addr.is_real() &&
+ !backref_manager->backref_should_be_removed(addr)) {
segment_cleaner->mark_space_used(
addr,
len ,
seastar::lowres_system_clock::time_point(),
true);
}
- auto &del_backrefs = backref_manager->get_cached_backref_removals();
- DEBUG("marking {} backrefs free", del_backrefs.size());
- for (auto &del_backref : del_backrefs) {
- segment_cleaner->mark_space_free(
- del_backref.paddr,
- del_backref.len,
- true);
- }
return seastar::now();
});
});
[this, &tracker](auto &t) {
return backref_manager->scan_mapped_space(
t,
- [&tracker](auto offset, auto len, depth_t) {
- if (offset.get_addr_type() == addr_types_t::SEGMENT) {
+ [&tracker, this](auto offset, auto len, depth_t) {
+ if (offset.get_addr_type() == addr_types_t::SEGMENT &&
+ !backref_manager->backref_should_be_removed(offset)) {
logger().debug("check_usage: tracker alloc {}~{}",
offset, len);
tracker->allocate(
backref.len);
}
}
- auto &del_backrefs = backref_manager->get_cached_backref_removals();
- for (auto &del_backref : del_backrefs) {
- if (del_backref.paddr.get_addr_type() == addr_types_t::SEGMENT) {
- logger().debug("check_usage: by backref, tracker release {}~{}",
- del_backref.paddr, del_backref.len);
- tracker->release(
- del_backref.paddr.as_seg_paddr().get_segment_id(),
- del_backref.paddr.as_seg_paddr().get_segment_off(),
- del_backref.len);
- }
- }
return seastar::now();
});
}).unsafe_get0();