}
}
+ /**
+ * alloc_new_extent
+ *
+ * Allocates a fresh extent. if delayed is true, addr will be alloc'd later
+ */
template <typename T>
TCachedExtentRef<T> alloc_new_extent(
Transaction &t, ///< [in, out] current transaction
using CachedExtentRef = boost::intrusive_ptr<CachedExtent>;
class SegmentedAllocator;
class TransactionManager;
+class ExtentPlacementManager;
// #define DEBUG_CACHED_EXTENT_REF
#ifdef DEBUG_CACHED_EXTENT_REF
friend class crimson::os::seastore::ool_record_t;
friend class crimson::os::seastore::SegmentedAllocator;
friend class crimson::os::seastore::TransactionManager;
+ friend class crimson::os::seastore::ExtentPlacementManager;
};
std::ostream &operator<<(std::ostream &, CachedExtent::extent_state_t);
void erase(CachedExtent &extent) {
assert(extent.parent_index);
- auto erased = extent_index.erase(extent);
+ auto erased = extent_index.erase(
+ extent_index.s_iterator_to(extent));
extent.parent_index = nullptr;
if (erased) {
finish_record_ret finish_write(
Transaction& t,
ool_record_t& record);
- segment_off_t fake_paddr_off = 0;
bool _needs_roll(segment_off_t length) const;
write_iertr::future<> _write(
return extent;
}
+ template<
+ typename T,
+ std::enable_if_t<std::is_base_of_v<LogicalCachedExtent, T>, int> = 0>
+ TCachedExtentRef<T> alloc_new_extent(
+ Transaction& t,
+ segment_off_t length,
+ ool_placement_hint_t hint = ool_placement_hint_t::NONE)
+ {
+ auto dtype = get_allocator_type(hint);
+ TCachedExtentRef<T> extent;
+ if (need_delayed_allocation(dtype)) {
+ // set a unique temperary paddr, this is necessary because
+ // transaction's write_set is indexed by paddr
+ extent = cache.alloc_new_extent<T>(t, length, true);
+ } else {
+ extent = cache.alloc_new_extent<T>(t, length);
+ }
+ extent->backend_type = dtype;
+ extent->hint = hint;
+ return extent;
+ }
+
/**
* delayed_alloc_or_ool_write
*
return out << "ZERO_SEG";
else if (t == FAKE_SEG_ID)
return out << "FAKE_SEG";
+ else if (t == DELAYED_TEMP_SEG_ID)
+ return out << "DELAYED_TEMP_SEG";
else
return out << t;
}
*/
constexpr segment_id_t ZERO_SEG_ID =
std::numeric_limits<segment_id_t>::max() - 5;
+constexpr segment_id_t DELAYED_TEMP_SEG_ID =
+ std::numeric_limits<segment_id_t>::max() - 6;
std::ostream &segment_to_stream(std::ostream &, const segment_id_t &t);
constexpr paddr_t zero_paddr() {
return paddr_t{ZERO_SEG_ID, 0};
}
+constexpr paddr_t delayed_temp_paddr(segment_off_t off) {
+ return paddr_t{DELAYED_TEMP_SEG_ID, off};
+}
struct __attribute((packed)) paddr_le_t {
ceph_le32 segment = ceph_le32(NULL_SEG_ID);
#include <boost/intrusive/list.hpp>
+#include "crimson/common/log.h"
#include "crimson/os/seastore/ordering_handle.h"
#include "crimson/os/seastore/seastore_types.h"
#include "crimson/os/seastore/cached_extent.h"
if (out)
*out = CachedExtentRef(&*iter);
return get_extent_ret::PRESENT;
+ } else if (auto iter = delayed_set.find_offset(addr);
+ iter != delayed_set.end()) {
+ if (out)
+ *out = CachedExtentRef(&*iter);
+ return get_extent_ret::PRESENT;
} else if (
auto iter = read_set.find(addr);
iter != read_set.end()) {
// will affect relative paddrs, and it should be rare to retire a fresh
// extent.
ref->state = CachedExtent::extent_state_t::INVALID;
- write_set.erase(*ref);
+ if (ref->is_inline()) {
+ write_set.erase(*ref);
+ } else {
+ // if ref is not relative, it must be in the delayed set
+ delayed_set.erase(*ref);
+ }
} else if (ref->is_mutation_pending()) {
ref->state = CachedExtent::extent_state_t::INVALID;
write_set.erase(*ref);
ceph_assert(!is_weak());
if (delayed) {
assert(ref->is_logical());
+ ref->set_paddr(delayed_temp_paddr(delayed_temp_offset));
+ delayed_temp_offset += ref->get_length();
delayed_alloc_list.emplace_back(ref->cast<LogicalCachedExtent>());
delayed_set.insert(*ref);
} else {
i->state = CachedExtent::extent_state_t::INVALID;
write_set.erase(*i++);
}
+ for (auto i = delayed_set.begin();
+ i != delayed_set.end();) {
+ delayed_set.erase(*i++);
+ }
}
friend class crimson::os::seastore::SeaStore;
void reset_preserve_handle(journal_seq_t initiated_after) {
root.reset();
offset = 0;
+ delayed_temp_offset = 0;
read_set.clear();
write_set.clear();
+ delayed_set.clear();
fresh_block_list.clear();
mutated_block_list.clear();
delayed_alloc_list.clear();
RootBlockRef root; ///< ref to root if read or written by transaction
segment_off_t offset = 0; ///< relative offset of next block
+ segment_off_t delayed_temp_offset = 0;
read_set_t<Transaction> read_set; ///< set of extents read by paddr
ExtentIndex write_set; ///< set of extents written by paddr
+ ExtentIndex delayed_set; ///< set of extents whose paddr
+ /// allocation are delayed
std::list<CachedExtentRef> fresh_block_list; ///< list of fresh blocks
std::list<CachedExtentRef> mutated_block_list; ///< list of mutated blocks
Transaction &t,
laddr_t hint,
extent_len_t len) {
- auto ext = cache->alloc_new_extent<T>(
+ auto ext = epm->alloc_new_extent<T>(
t,
len);
return lba_manager->alloc_extent(