extent_init_func(*ret);
return read_extent<T>(
std::move(ret));
+ } else if (!cached->is_fully_loaded()) {
+ auto ret = TCachedExtentRef<T>(static_cast<T*>(cached.get()));
+ on_cache(*ret);
+ SUBDEBUG(seastore_cache,
+ "{} {}~{} is present without been fully loaded, reading ... -- {}",
+ T::TYPE, offset, length, *ret);
+ auto bp = alloc_cache_buf(length);
+ ret->set_bptr(std::move(bp));
+ return read_extent<T>(
+ std::move(ret));
} else {
SUBTRACE(seastore_cache,
"{} {}~{} is present in cache -- {}",
auto result = t.get_extent(offset, &ret);
if (result == Transaction::get_extent_ret::RETIRED) {
SUBDEBUGT(seastore_cache, "{} {} is retired on t -- {}",
- t, type, offset, *ret);
+ t, type, offset, *ret);
return get_extent_if_cached_iertr::make_ready_future<
CachedExtentRef>(ret);
} else if (result == Transaction::get_extent_ret::PRESENT) {
- SUBTRACET(seastore_cache, "{} {} is present on t -- {}",
- t, type, offset, *ret);
- return ret->wait_io().then([ret] {
- return get_extent_if_cached_iertr::make_ready_future<
- CachedExtentRef>(ret);
- });
+ if (ret->is_fully_loaded()) {
+ SUBTRACET(seastore_cache, "{} {} is present on t -- {}",
+ t, type, offset, *ret);
+ return ret->wait_io().then([ret] {
+ return get_extent_if_cached_iertr::make_ready_future<
+ CachedExtentRef>(ret);
+ });
+ } else {
+ SUBDEBUGT(seastore_cache, "{} {} is present on t -- {}"
+ " without being fully loaded", t, type, offset, *ret);
+ return get_extent_if_cached_iertr::make_ready_future<
+ CachedExtentRef>();
+ }
}
// get_extent_ret::ABSENT from transaction
auto metric_key = std::make_pair(t.get_src(), type);
ret = query_cache(offset, &metric_key);
- if (!ret ||
- // retired_placeholder is not really cached yet
- ret->get_type() == extent_types_t::RETIRED_PLACEHOLDER) {
- SUBDEBUGT(seastore_cache, "{} {} is absent{}",
- t, type, offset, !!ret ? "(placeholder)" : "");
- return get_extent_if_cached_iertr::make_ready_future<
- CachedExtentRef>();
+ if (!ret) {
+ SUBDEBUGT(seastore_cache, "{} {} is absent", t, type, offset);
+ return get_extent_if_cached_iertr::make_ready_future<CachedExtentRef>();
+ } else if (ret->get_type() == extent_types_t::RETIRED_PLACEHOLDER) {
+ // retired_placeholder is not really cached yet
+ SUBDEBUGT(seastore_cache, "{} {} is absent(placeholder)",
+ t, type, offset);
+ return get_extent_if_cached_iertr::make_ready_future<CachedExtentRef>();
+ } else if (!ret->is_fully_loaded()) {
+ SUBDEBUGT(seastore_cache, "{} {} is present without "
+ "being fully loaded", t, type, offset);
+ return get_extent_if_cached_iertr::make_ready_future<CachedExtentRef>();
}
- // present in cache and is not a retired_placeholder
+ // present in cache(fully loaded) and is not a retired_placeholder
SUBDEBUGT(seastore_cache, "{} {} is present in cache -- {}",
t, type, offset, *ret);
t.add_to_read_set(ret);
CachedExtentRef ret;
LOG_PREFIX(Cache::get_extent);
auto result = t.get_extent(offset, &ret);
- if (result != Transaction::get_extent_ret::ABSENT) {
- SUBTRACET(seastore_cache, "{} {}~{} is {} on t -- {}",
- t,
- T::TYPE,
- offset,
- length,
- result == Transaction::get_extent_ret::PRESENT ? "present" : "retired",
- *ret);
- assert(result != Transaction::get_extent_ret::RETIRED);
- return ret->wait_io().then([ret] {
- return seastar::make_ready_future<TCachedExtentRef<T>>(
- ret->cast<T>());
- });
+ if (result == Transaction::get_extent_ret::RETIRED) {
+ SUBERRORT(seastore_cache, "{} {}~{} is retired on t -- {}",
+ t, T::TYPE, offset, length, *ret);
+ ceph_abort("impossible");
+ } else if (result == Transaction::get_extent_ret::PRESENT) {
+ if (ret->is_fully_loaded()) {
+ SUBTRACET(seastore_cache, "{} {}~{} is present on t -- {}",
+ t, T::TYPE, offset, length, *ret);
+ return ret->wait_io().then([ret] {
+ return seastar::make_ready_future<TCachedExtentRef<T>>(
+ ret->cast<T>());
+ });
+ } else {
+ assert(!ret->is_mutable());
+ touch_extent(*ret);
+ SUBDEBUGT(seastore_cache, "{} {}~{} is present on t without been \
+ fully loaded, reading ... {}", t, T::TYPE, offset, length, *ret);
+ auto bp = alloc_cache_buf(ret->get_length());
+ ret->set_bptr(std::move(bp));
+ return read_extent<T>(
+ ret->cast<T>());
+ }
+ } else {
+ SUBTRACET(seastore_cache, "{} {}~{} is absent on t, query cache ...",
+ t, T::TYPE, offset, length);
+ auto f = [&t, this](CachedExtent &ext) {
+ t.add_to_read_set(CachedExtentRef(&ext));
+ touch_extent(ext);
+ };
+ auto metric_key = std::make_pair(t.get_src(), T::TYPE);
+ return trans_intr::make_interruptible(
+ get_extent<T>(
+ offset, length, &metric_key,
+ std::forward<Func>(extent_init_func), std::move(f))
+ );
}
-
- SUBTRACET(seastore_cache, "{} {}~{} is absent on t, query cache ...",
- t, T::TYPE, offset, length);
- auto f = [&t, this](CachedExtent &ext) {
- t.add_to_read_set(CachedExtentRef(&ext));
- touch_extent(ext);
- };
- auto metric_key = std::make_pair(t.get_src(), T::TYPE);
- return trans_intr::make_interruptible(
- get_extent<T>(
- offset, length, &metric_key,
- std::forward<Func>(extent_init_func), std::move(f))
- );
}
/*
extent_len_t length,
Func &&extent_init_func) {
CachedExtentRef ret;
- LOG_PREFIX(Cache::get_extent);
+ LOG_PREFIX(Cache::get_absent_extent);
#ifndef NDEBUG
auto r = t.get_extent(offset, &ret);
return get_absent_extent<T>(t, offset, length, [](T &){});
}
- seastar::future<CachedExtentRef> get_extent_viewable_by_trans(
+ get_extent_ertr::future<CachedExtentRef> get_extent_viewable_by_trans(
Transaction &t,
CachedExtentRef extent)
{
touch_extent(*p_extent);
}
}
+ // user should not see RETIRED_PLACEHOLDER extents
+ ceph_assert(p_extent->get_type() != extent_types_t::RETIRED_PLACEHOLDER);
+ if (!p_extent->is_fully_loaded()) {
+ assert(!p_extent->is_mutable());
+ touch_extent(*p_extent);
+ LOG_PREFIX(Cache::get_extent_viewable_by_trans);
+ SUBDEBUG(seastore_cache,
+ "{} {}~{} is present without been fully loaded, reading ... -- {}",
+ p_extent->get_type(), p_extent->get_paddr(),p_extent->get_length(),
+ *p_extent);
+ auto bp = alloc_cache_buf(p_extent->get_length());
+ p_extent->set_bptr(std::move(bp));
+ return read_extent<CachedExtent>(CachedExtentRef(p_extent));
+ }
return p_extent->wait_io(
).then([p_extent] {
- return CachedExtentRef(p_extent);
+ return get_extent_ertr::make_ready_future<CachedExtentRef>(
+ CachedExtentRef(p_extent));
});
}
template <typename T>
- seastar::future<TCachedExtentRef<T>> get_extent_viewable_by_trans(
+ get_extent_ertr::future<TCachedExtentRef<T>> get_extent_viewable_by_trans(
Transaction &t,
TCachedExtentRef<T> extent)
{
return get_extent_viewable_by_trans(t, CachedExtentRef(extent.get())
- ).then([](auto p_extent) {
+ ).safe_then([](auto p_extent) {
return p_extent->template cast<T>();
});
}
CachedExtentRef ret;
auto status = t.get_extent(offset, &ret);
if (status == Transaction::get_extent_ret::RETIRED) {
- SUBDEBUGT(seastore_cache, "{} {}~{} {} is retired on t -- {}",
+ SUBERRORT(seastore_cache, "{} {}~{} {} is retired on t -- {}",
t, type, offset, length, laddr, *ret);
- return seastar::make_ready_future<CachedExtentRef>();
+ ceph_abort("impossible");
} else if (status == Transaction::get_extent_ret::PRESENT) {
- SUBTRACET(seastore_cache, "{} {}~{} {} is present on t -- {}",
- t, type, offset, length, laddr, *ret);
- return ret->wait_io().then([ret] {
- return seastar::make_ready_future<CachedExtentRef>(ret);
- });
+ if (ret->is_fully_loaded()) {
+ SUBTRACET(seastore_cache, "{} {}~{} {} is present on t -- {}",
+ t, type, offset, length, laddr, *ret);
+ return ret->wait_io().then([ret] {
+ return seastar::make_ready_future<CachedExtentRef>(ret);
+ });
+ } else {
+ assert(!ret->is_mutable());
+ touch_extent(*ret);
+ SUBDEBUGT(seastore_cache, "{} {}~{} {} is present on t without been \
+ fully loaded, reading ...", t, type, offset, length, laddr);
+ auto bp = alloc_cache_buf(ret->get_length());
+ ret->set_bptr(std::move(bp));
+ return read_extent<CachedExtent>(
+ std::move(ret));
+ }
} else {
SUBTRACET(seastore_cache, "{} {}~{} {} is absent on t, query cache ...",
t, type, offset, length, laddr);
return ret;
}
+ /**
+ * alloc_remapped_extent
+ *
+ * Allocates an EXIST_CLEAN extent. Use the buffer to fill the new extent
+ * if buffer exists.
+ */
+ template <typename T>
+ TCachedExtentRef<T> alloc_remapped_extent(
+ Transaction &t,
+ laddr_t remap_laddr,
+ paddr_t remap_paddr,
+ extent_len_t remap_length,
+ laddr_t original_laddr,
+ std::optional<ceph::bufferptr> &&original_bptr) {
+ LOG_PREFIX(Cache::alloc_remapped_extent);
+ assert(remap_laddr >= original_laddr);
+ TCachedExtentRef<T> ext;
+ if (original_bptr.has_value()) {
+ // shallow copy the buffer from original extent
+ auto nbp = ceph::bufferptr(
+ *original_bptr,
+ remap_laddr - original_laddr,
+ remap_length);
+ // ExtentPlacementManager::alloc_new_extent will make a new
+ // (relative/temp) paddr, so make extent directly
+ ext = CachedExtent::make_cached_extent_ref<T>(std::move(nbp));
+ } else {
+ ext = CachedExtent::make_placeholder_cached_extent_ref<T>(remap_length);
+ }
+
+ ext->init(CachedExtent::extent_state_t::EXIST_CLEAN,
+ remap_paddr,
+ PLACEMENT_HINT_NULL,
+ NULL_GENERATION,
+ t.get_trans_id());
+
+ t.add_fresh_extent(ext);
+ SUBTRACET(seastore_cache, "allocated {} {}B, hint={}, has ptr? {} -- {}",
+ t, T::TYPE, remap_length, remap_laddr, original_bptr.has_value(), *ext);
+ return ext;
+ }
+
/**
* alloc_new_extent
*
{
if (p_src && is_background_transaction(*p_src))
return;
- if (ext.is_clean() && !ext.is_placeholder()) {
+ if (ext.is_stable_clean() && !ext.is_placeholder()) {
lru.move_to_top(ext);
}
}
}
void add_to_lru(CachedExtent &extent) {
- assert(extent.is_clean() && !extent.is_placeholder());
+ assert(extent.is_stable_clean() && !extent.is_placeholder());
if (!extent.primary_ref_list_hook.is_linked()) {
contents += extent.get_length();
}
void remove_from_lru(CachedExtent &extent) {
- assert(extent.is_clean() && !extent.is_placeholder());
+ assert(extent.is_stable_clean() && !extent.is_placeholder());
if (extent.primary_ref_list_hook.is_linked()) {
lru.erase(lru.s_iterator_to(extent));
}
void move_to_top(CachedExtent &extent) {
- assert(extent.is_clean() && !extent.is_placeholder());
+ assert(extent.is_stable_clean() && !extent.is_placeholder());
if (extent.primary_ref_list_hook.is_linked()) {
lru.erase(lru.s_iterator_to(extent));
io_stat_t fresh;
io_stat_t fresh_ool_written;
counter_by_extent_t<uint64_t> num_trans_invalidated;
+ uint64_t total_trans_invalidated = 0;
uint64_t num_ool_records = 0;
uint64_t ool_record_bytes = 0;
};
get_extent_ret<T> read_extent(
TCachedExtentRef<T>&& extent
) {
- assert(extent->state == CachedExtent::extent_state_t::CLEAN_PENDING);
+ assert(extent->state == CachedExtent::extent_state_t::CLEAN_PENDING ||
+ extent->state == CachedExtent::extent_state_t::EXIST_CLEAN ||
+ extent->state == CachedExtent::extent_state_t::CLEAN);
extent->set_io_wait();
return epm.read(
extent->get_paddr(),
extent->last_committed_crc = extent->get_crc32c();
extent->on_clean_read();
- } else {
+ } else if (extent->state == CachedExtent::extent_state_t::EXIST_CLEAN ||
+ extent->state == CachedExtent::extent_state_t::CLEAN) {
+ /* TODO: crc should be checked against LBA manager */
+ extent->last_committed_crc = extent->get_crc32c();
+ } else {
ceph_assert(!extent->is_valid());
}
extent->complete_io();