ceph_assert(extents.empty());
}
-Cache::retire_extent_ret Cache::retire_extent_if_cached(
+Cache::retire_extent_ret Cache::retire_extent(
Transaction &t, paddr_t addr, extent_len_t length)
{
if (auto ext = t.write_set.find_offset(addr); ext != t.write_set.end()) {
return alloc_new_extent<collection_manager::CollectionNode>(t, length);
case extent_types_t::OBJECT_DATA_BLOCK:
return alloc_new_extent<ObjectDataBlock>(t, length);
+ case extent_types_t::RETIRED_PLACEHOLDER:
+ ceph_assert(0 == "impossible");
+ return CachedExtentRef();
case extent_types_t::TEST_BLOCK:
return alloc_new_extent<TestBlock>(t, length);
case extent_types_t::TEST_BLOCK_PHYSICAL:
retire_extent(i);
}
+ for (auto &&i : t.retired_uncached) {
+ CachedExtentRef to_retire;
+ if (query_cache_for_extent(i.first, &to_retire) ==
+ Transaction::get_extent_ret::ABSENT) {
+ to_retire = CachedExtent::make_cached_extent_ref<
+ RetiredExtentPlaceholder
+ >(i.second);
+ to_retire->set_paddr(i.first);
+ }
+
+ t.retired_set.insert(to_retire);
+ extents.insert(*to_retire);
+ to_retire->dirty_from_or_retired_at = JOURNAL_SEQ_MAX;
+ retired_extent_gate.add_extent(*to_retire);
+ }
+
record.extents.reserve(t.fresh_block_list.size());
for (auto &i: t.fresh_block_list) {
logger().debug("try_construct_record: fresh block {}", *i);
i->get_paddr(),
i->get_length());
}
- for (auto &i: t.retired_uncached) {
- cleaner->mark_space_free(
- i.first,
- i.second);
- }
}
for (auto &i: t.mutated_block_list) {
logger().debug("try_construct_record: retiring {}", *i);
i->dirty_from_or_retired_at = last_commit;
}
+
retired_extent_gate.prune();
}
).safe_then([](auto extent) {
return CachedExtentRef(extent.detach(), false /* add_ref */);
});
+ case extent_types_t::RETIRED_PLACEHOLDER:
+ ceph_assert(0 == "impossible");
+ return get_extent_ertr::make_ready_future<CachedExtentRef>();
case extent_types_t::TEST_BLOCK:
return get_extent<TestBlock>(offset, length
).safe_then([](auto extent) {
t.add_to_retired_set(ref);
}
- /// Declare paddr retired in t, noop if not cached
+ /// Declare paddr retired in t
using retire_extent_ertr = base_ertr;
using retire_extent_ret = retire_extent_ertr::future<>;
- retire_extent_ret retire_extent_if_cached(
+ retire_extent_ret retire_extent(
Transaction &t, paddr_t addr, extent_len_t length);
/**
void replace_extent(CachedExtentRef next, CachedExtentRef prev);
Transaction::get_extent_ret query_cache_for_extent(
- Transaction &t,
paddr_t offset,
CachedExtentRef *out) {
- auto result = t.get_extent(offset, out);
- if (result != Transaction::get_extent_ret::ABSENT) {
- return result;
- } else if (auto iter = extents.find_offset(offset);
- iter != extents.end()) {
+ if (auto iter = extents.find_offset(offset);
+ iter != extents.end()) {
if (out)
*out = &*iter;
return Transaction::get_extent_ret::PRESENT;
}
}
+ Transaction::get_extent_ret query_cache_for_extent(
+ Transaction &t,
+ paddr_t offset,
+ CachedExtentRef *out) {
+ auto result = t.get_extent(offset, out);
+ if (result != Transaction::get_extent_ret::ABSENT) {
+ return result;
+ } else {
+ return query_cache_for_extent(offset, out);
+ }
+ }
+
};
using CacheRef = std::unique_ptr<Cache>;
paddr_t get_paddr() const { return poffset; }
/// Returns length of extent
- extent_len_t get_length() const { return ptr.length(); }
+ virtual extent_len_t get_length() const { return ptr.length(); }
/// Returns version, get_version() == 0 iff is_clean()
extent_version_t get_version() const {
version(other.version),
poffset(other.poffset) {}
+ struct retired_placeholder_t{};
+ CachedExtent(retired_placeholder_t) : state(extent_state_t::RETIRED) {}
friend class Cache;
- template <typename T>
- static TCachedExtentRef<T> make_cached_extent_ref(bufferptr &&ptr) {
- return new T(std::move(ptr));
+ template <typename T, typename... Args>
+ static TCachedExtentRef<T> make_cached_extent_ref(
+ Args&&... args) {
+ return new T(std::forward<Args>(args)...);
}
CachedExtentRef get_prior_instance() {
}
}
+/**
+ * RetiredExtentPlaceholder
+ *
+ * Cache::retire_extent(Transaction&, paddr_t, extent_len_t) can retire
+ * an extent not currently in cache. In that case, we need to add a
+ * placeholder to the cache until transactions that might reference
+ * the extent complete as in the case where the extent is already cached.
+ * Cache::complete_commit thus creates a RetiredExtentPlaceholder to
+ * serve that purpose. ptr is not populated, and state is set to
+ * RETIRED. Cache interfaces check for RETIRED and return EAGAIN if
+ * encountered, so references to these placeholder extents should not
+ * escape the Cache interface boundary.
+ */
+class RetiredExtentPlaceholder : public CachedExtent {
+ extent_len_t length;
+
+public:
+ template <typename... T>
+ RetiredExtentPlaceholder(extent_len_t length)
+ : CachedExtent(CachedExtent::retired_placeholder_t{}),
+ length(length) {}
+
+ extent_len_t get_length() const final { return length; }
+
+ CachedExtentRef duplicate_for_write() final {
+ ceph_assert(0 == "Should never happen for a placeholder");
+ return CachedExtentRef();
+ }
+
+ ceph::bufferlist get_delta() final {
+ ceph_assert(0 == "Should never happen for a placeholder");
+ return ceph::bufferlist();
+ }
+
+ static constexpr extent_types_t TYPE = extent_types_t::RETIRED_PLACEHOLDER;
+ extent_types_t get_type() const final {
+ return TYPE;
+ }
+
+ void apply_delta_and_adjust_crc(
+ paddr_t base, const ceph::bufferlist &bl) final {
+ ceph_assert(0 == "Should never happen for a placeholder");
+ }
+
+ bool is_logical() const final {
+ return false;
+ }
+
+ std::ostream &print_detail(std::ostream &out) const final {
+ return out << "RetiredExtentPlaceholder";
+ }
+
+ void on_delta_write(paddr_t record_block_offset) final {
+ ceph_assert(0 == "Should never happen for a placeholder");
+ }
+};
+
/**
* LogicalCachedExtent
*
return out << "COLL_BLOCK";
case extent_types_t::OBJECT_DATA_BLOCK:
return out << "OBJECT_DATA_BLOCK";
+ case extent_types_t::RETIRED_PLACEHOLDER:
+ return out << "RETIRED_PLACEHOLDER";
case extent_types_t::TEST_BLOCK:
return out << "TEST_BLOCK";
case extent_types_t::TEST_BLOCK_PHYSICAL:
ONODE_BLOCK_STAGED = 6,
COLL_BLOCK = 7,
OBJECT_DATA_BLOCK = 8,
+ RETIRED_PLACEHOLDER = 9,
// Test Block Types
TEST_BLOCK = 0xF0,
logger().debug(
"TransactionManager::dec_ref: offset {} refcount 0",
offset);
- return cache->retire_extent_if_cached(
+ return cache->retire_extent(
t, result.addr, result.length
).safe_then([] {
return ref_ret(