}
// absent from transaction
- ext = query_cache(addr);
+ // retiring is not included by the cache hit metrics
+ ext = query_cache(addr, nullptr);
if (ext) {
if (ext->get_type() != extent_types_t::RETIRED_PLACEHOLDER) {
t.add_to_read_set(ext);
),
}
);
+
+ /*
+ * cache_query: cache_access and cache_hit
+ */
+ auto register_cache_access =
+ [this, &labels_by_src, &labels_by_ext]
+ (src_t src, const sm::label_instance& src_label,
+ extent_types_t ext, const sm::label_instance& ext_label) {
+ auto m_key = std::make_pair(src, ext);
+ stats.cache_query[m_key] = {0, 0};
+ {
+ metrics.add_group(
+ "cache",
+ {
+ sm::make_counter(
+ "cache_access",
+ stats.cache_query.find(m_key)->second.access,
+ sm::description("total number of cache accesses labeled by "
+ "transaction source and extent type"),
+ {src_label, ext_label}
+ ),
+ sm::make_counter(
+ "cache_hit",
+ stats.cache_query.find(m_key)->second.hit,
+ sm::description("total number of cache hits labeled by "
+ "transaction source and extent type"),
+ {src_label, ext_label}
+ ),
+ }
+ );
+ }
+ };
+
+ for (auto& [src, src_label] : labels_by_src) {
+ for (auto& [ext, ext_label] : labels_by_ext) {
+ if (ext != extent_types_t::RETIRED_PLACEHOLDER) {
+ register_cache_access(src, src_label, ext, ext_label);
+ }
+ }
+ }
+
+ metrics.add_group(
+ "cache",
+ {
+ sm::make_counter(
+ "cache_access",
+ [this] {
+ uint64_t total = 0;
+ for (auto& [k, v] : stats.cache_query) {
+ total += v.access;
+ }
+ return total;
+ },
+ sm::description("total number of cache accesses"),
+ {src_label("ALL")}
+ ),
+ sm::make_counter(
+ "cache_hit",
+ [this] {
+ uint64_t total = 0;
+ for (auto& [k, v] : stats.cache_query) {
+ total += v.hit;
+ }
+ return total;
+ },
+ sm::description("total number of cache hits"),
+ {src_label("ALL")}
+ ),
+ }
+ );
}
void Cache::add_extent(CachedExtentRef ref)
} else {
auto _get_extent_if_cached = [this](paddr_t addr)
-> get_extent_ertr::future<CachedExtentRef> {
- auto ret = query_cache(addr);
+ // replay is not included by the cache hit metrics
+ auto ret = query_cache(addr, nullptr);
if (ret) {
// no retired-placeholder should be exist yet because no transaction
// has been created.
}
};
auto extent_fut = (delta.pversion == 0 ?
+ // replay is not included by the cache hit metrics
get_extent_by_type(
- delta.type,
- delta.paddr,
- delta.laddr,
- delta.length) :
+ delta.type,
+ delta.paddr,
+ delta.laddr,
+ delta.length,
+ nullptr) :
_get_extent_if_cached(
delta.paddr)
).handle_error(
extent_types_t type,
paddr_t offset,
laddr_t laddr,
- segment_off_t length)
+ segment_off_t length,
+ const Transaction::src_t* p_src)
{
return [=] {
+ src_ext_t* p_metric_key = nullptr;
+ src_ext_t metric_key;
+ if (p_src) {
+ metric_key = std::make_pair(*p_src, type);
+ p_metric_key = &metric_key;
+ }
+
switch (type) {
case extent_types_t::ROOT:
assert(0 == "ROOT is never directly read");
return get_extent_ertr::make_ready_future<CachedExtentRef>();
case extent_types_t::LADDR_INTERNAL:
- return get_extent<lba_manager::btree::LBAInternalNode>(offset, length
+ return get_extent<lba_manager::btree::LBAInternalNode>(
+ offset, length, p_metric_key
).safe_then([](auto extent) {
return CachedExtentRef(extent.detach(), false /* add_ref */);
});
case extent_types_t::LADDR_LEAF:
- return get_extent<lba_manager::btree::LBALeafNode>(offset, length
+ return get_extent<lba_manager::btree::LBALeafNode>(
+ offset, length, p_metric_key
).safe_then([](auto extent) {
return CachedExtentRef(extent.detach(), false /* add_ref */);
});
case extent_types_t::OMAP_INNER:
- return get_extent<omap_manager::OMapInnerNode>(offset, length
+ return get_extent<omap_manager::OMapInnerNode>(
+ offset, length, p_metric_key
).safe_then([](auto extent) {
return CachedExtentRef(extent.detach(), false /* add_ref */);
});
case extent_types_t::OMAP_LEAF:
- return get_extent<omap_manager::OMapLeafNode>(offset, length
+ return get_extent<omap_manager::OMapLeafNode>(
+ offset, length, p_metric_key
).safe_then([](auto extent) {
return CachedExtentRef(extent.detach(), false /* add_ref */);
});
case extent_types_t::COLL_BLOCK:
- return get_extent<collection_manager::CollectionNode>(offset, length
+ return get_extent<collection_manager::CollectionNode>(
+ offset, length, p_metric_key
).safe_then([](auto extent) {
return CachedExtentRef(extent.detach(), false /* add_ref */);
});
case extent_types_t::ONODE_BLOCK_STAGED:
- return get_extent<onode::SeastoreNodeExtent>(offset, length
+ return get_extent<onode::SeastoreNodeExtent>(
+ offset, length, p_metric_key
).safe_then([](auto extent) {
return CachedExtentRef(extent.detach(), false /* add_ref */);
});
case extent_types_t::OBJECT_DATA_BLOCK:
- return get_extent<ObjectDataBlock>(offset, length
+ return get_extent<ObjectDataBlock>(
+ offset, length, p_metric_key
).safe_then([](auto extent) {
return CachedExtentRef(extent.detach(), false /* add_ref */);
});
ceph_assert(0 == "impossible");
return get_extent_ertr::make_ready_future<CachedExtentRef>();
case extent_types_t::TEST_BLOCK:
- return get_extent<TestBlock>(offset, length
+ return get_extent<TestBlock>(
+ offset, length, p_metric_key
).safe_then([](auto extent) {
return CachedExtentRef(extent.detach(), false /* add_ref */);
});
case extent_types_t::TEST_BLOCK_PHYSICAL:
- return get_extent<TestBlockPhysical>(offset, length
+ return get_extent<TestBlockPhysical>(
+ offset, length, p_metric_key
).safe_then([](auto extent) {
return CachedExtentRef(extent.detach(), false /* add_ref */);
});
* - extent_set if already in cache
* - disk
*/
+ using src_ext_t = std::pair<Transaction::src_t, extent_types_t>;
using get_extent_ertr = base_ertr;
template <typename T>
using get_extent_ret = get_extent_ertr::future<TCachedExtentRef<T>>;
template <typename T>
get_extent_ret<T> get_extent(
- paddr_t offset, ///< [in] starting addr
- segment_off_t length ///< [in] length
+ paddr_t offset, ///< [in] starting addr
+ segment_off_t length, ///< [in] length
+ const src_ext_t* p_metric_key ///< [in] cache query metric key
) {
- auto cached = query_cache(offset);
+ auto cached = query_cache(offset, p_metric_key);
if (!cached) {
auto ret = CachedExtent::make_cached_extent_ref<T>(
alloc_cache_buf(length));
get_extent_if_cached_iertr::future<CachedExtentRef>;
get_extent_if_cached_ret get_extent_if_cached(
Transaction &t,
- paddr_t offset) {
+ paddr_t offset,
+ extent_types_t type) {
CachedExtentRef ret;
auto result = t.get_extent(offset, &ret);
if (result != Transaction::get_extent_ret::ABSENT) {
}
// get_extent_ret::ABSENT from transaction
- ret = query_cache(offset);
+ 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) {
return seastar::make_ready_future<TCachedExtentRef<T>>(
ret->cast<T>());
} else {
+ auto metric_key = std::make_pair(t.get_src(), T::TYPE);
return trans_intr::make_interruptible(
- get_extent<T>(offset, length)
+ get_extent<T>(offset, length, &metric_key)
).si_then(
[&t, this](auto ref) {
if (!ref->is_valid()) {
* and read in the extent at location offset~length.
*/
get_extent_ertr::future<CachedExtentRef> get_extent_by_type(
- extent_types_t type, ///< [in] type tag
- paddr_t offset, ///< [in] starting addr
- laddr_t laddr, ///< [in] logical address if logical
- segment_off_t length ///< [in] length
+ extent_types_t type, ///< [in] type tag
+ paddr_t offset, ///< [in] starting addr
+ laddr_t laddr, ///< [in] logical address if logical
+ segment_off_t length, ///< [in] length
+ const Transaction::src_t* p_src ///< [in] src tag for cache query metric
);
using get_extent_by_type_iertr = get_extent_iertr;
} else if (status == Transaction::get_extent_ret::PRESENT) {
return seastar::make_ready_future<CachedExtentRef>(ret);
} else {
+ auto src = t.get_src();
return trans_intr::make_interruptible(
- get_extent_by_type(type, offset, laddr, length)
+ get_extent_by_type(type, offset, laddr, length, &src)
).si_then([=, &t](CachedExtentRef ret) {
if (!ret->is_valid()) {
LOG_PREFIX(Cache::get_extent_by_type);
*/
CachedExtent::list dirty;
- using src_ext_t = std::pair<Transaction::src_t, extent_types_t>;
+ struct query_counters_t {
+ uint64_t access;
+ uint64_t hit;
+ };
+
struct {
std::array<uint64_t, Transaction::SRC_MAX> trans_created_by_src;
std::array<uint64_t, Transaction::SRC_MAX> trans_committed_by_src;
std::unordered_map<src_ext_t, uint64_t,
boost::hash<src_ext_t>> trans_invalidated;
+ std::unordered_map<src_ext_t, query_counters_t,
+ boost::hash<src_ext_t>> cache_query;
} stats;
uint64_t& get_counter(
std::array<uint64_t, Transaction::SRC_MAX>& counters_by_src,
}
// Extents in cache may contain placeholders
- CachedExtentRef query_cache(paddr_t offset) {
+ CachedExtentRef query_cache(
+ paddr_t offset,
+ const src_ext_t* p_metric_key) {
+ query_counters_t* p_counters = nullptr;
+ if (p_metric_key) {
+ assert(stats.cache_query.count(*p_metric_key));
+ p_counters = &stats.cache_query[*p_metric_key];
+ ++p_counters->access;
+ }
if (auto iter = extents.find_offset(offset);
iter != extents.end()) {
+ if (p_metric_key &&
+ // retired_placeholder is not really cached yet
+ iter->get_type() != extent_types_t::RETIRED_PLACEHOLDER) {
+ ++p_counters->hit;
+ }
return CachedExtentRef(&*iter);
} else {
return CachedExtentRef();