From 1bb7a8b2acd24845ce0a44b9d488cecd7ded3a3a Mon Sep 17 00:00:00 2001
From: Vladimir Davydov <vdavydov.dev@gmail.com>
Date: Mon, 19 Jun 2017 18:40:06 +0300
Subject: [PATCH] vinyl: add per-index cache statistics

This patch adds the cache section to index.info with the following
counters in it:

  cache
    rows                # number of tuples in the cache
    bytes               # cache memory size
    lookup              # lookups in the cache
    get                 # reads from the cache
      rows
      bytes
    put                 # write to the cache
      rows
      bytes
    invalidate          # overwrites in the cache
      rows
      bytes
    evict               # evictions due to memory quota
      rows
      bytes

Needed for #1662
---
 src/box/vinyl.c    | 15 +++++++++++----
 src/box/vy_cache.c | 34 +++++++++++++++++++++++-----------
 src/box/vy_cache.h |  8 ++++----
 src/box/vy_mem.c   |  3 +--
 src/box/vy_run.c   |  3 +--
 src/box/vy_stat.h  | 40 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 80 insertions(+), 23 deletions(-)

diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 38c125171e..606970eb82 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -232,7 +232,6 @@ struct vy_stat {
 	int64_t dump_total;
 	/* iterators statistics */
 	struct vy_iterator_stat txw_stat;
-	struct vy_iterator_stat cache_stat;
 };
 
 static struct vy_stat *
@@ -4491,7 +4490,6 @@ vy_info_append_performance(struct vy_env *env, struct info_handler *h)
 
 	info_table_begin(h, "iterator");
 	vy_info_append_iterator_stat(h, "txw", &stat->txw_stat);
-	vy_info_append_iterator_stat(h, "cache", &stat->cache_stat);
 	info_table_end(h);
 
 	info_table_end(h);
@@ -4549,6 +4547,7 @@ vy_index_info(struct vy_index *index, struct info_handler *h)
 {
 	char buf[1024];
 	struct vy_index_stat *stat = &index->stat;
+	struct vy_cache_stat *cache_stat = &index->cache.stat;
 
 	info_begin(h);
 
@@ -4579,6 +4578,15 @@ vy_index_info(struct vy_index *index, struct info_handler *h)
 	vy_info_append_compact_stat(h, "compact", &stat->disk.compact);
 	info_table_end(h);
 
+	info_table_begin(h, "cache");
+	vy_info_append_stmt_counter(h, NULL, &cache_stat->count);
+	info_append_int(h, "lookup", cache_stat->lookup);
+	vy_info_append_stmt_counter(h, "get", &cache_stat->get);
+	vy_info_append_stmt_counter(h, "put", &cache_stat->put);
+	vy_info_append_stmt_counter(h, "invalidate", &cache_stat->invalidate);
+	vy_info_append_stmt_counter(h, "evict", &cache_stat->evict);
+	info_table_end(h);
+
 	info_append_int(h, "range_count", index->range_count);
 	info_append_int(h, "run_count", index->run_count);
 	info_append_int(h, "run_avg", index->run_count / index->range_count);
@@ -7679,8 +7687,7 @@ vy_read_iterator_add_cache(struct vy_read_iterator *itr)
 {
 	struct vy_merge_src *sub_src =
 		vy_merge_iterator_add(&itr->merge_iterator, true, false);
-	struct vy_iterator_stat *stat = &itr->index->env->stat->cache_stat;
-	vy_cache_iterator_open(&sub_src->cache_iterator, stat,
+	vy_cache_iterator_open(&sub_src->cache_iterator,
 			       &itr->index->cache, itr->iterator_type,
 			       itr->key, itr->read_view);
 	if (itr->curr_stmt != NULL) {
diff --git a/src/box/vy_cache.c b/src/box/vy_cache.c
index 33799a89f9..7ce43a8efb 100644
--- a/src/box/vy_cache.c
+++ b/src/box/vy_cache.c
@@ -90,12 +90,14 @@ vy_cache_entry_new(struct vy_cache_env *env, struct vy_cache *cache,
 	rlist_add(&env->cache_lru, &entry->in_lru);
 	env->mem_used += vy_cache_entry_size(entry);
 	env->cached_count++;
+	vy_stmt_counter_acct_tuple(&cache->stat.count, stmt);
 	return entry;
 }
 
 static void
 vy_cache_entry_delete(struct vy_cache_env *env, struct vy_cache_entry *entry)
 {
+	vy_stmt_counter_unacct_tuple(&entry->cache->stat.count, entry->stmt);
 	assert(env->cached_count > 0);
 	env->cached_count--;
 	assert(env->mem_used >= vy_cache_entry_size(entry));
@@ -188,6 +190,7 @@ vy_cache_gc_step(struct vy_cache_env *env)
 		}
 	}
 	cache->version++;
+	vy_stmt_counter_acct_tuple(&cache->stat.evict, entry->stmt);
 	vy_cache_tree_delete(&cache->cache_tree, entry);
 	vy_cache_entry_delete(cache->env, entry);
 }
@@ -294,6 +297,8 @@ vy_cache_add(struct vy_cache *cache, struct tuple *stmt,
 	else if (direction < 0 && boundary_level < entry->right_boundary_level)
 		entry->right_boundary_level = boundary_level;
 
+	vy_stmt_counter_acct_tuple(&cache->stat.put, stmt);
+
 	/* Done if it's not a chain */
 	if (prev_stmt == NULL)
 		return;
@@ -419,6 +424,8 @@ vy_cache_on_write(struct vy_cache *cache, const struct tuple *stmt,
 			*deleted = to_delete->stmt;
 			tuple_ref(to_delete->stmt);
 		}
+		vy_stmt_counter_acct_tuple(&cache->stat.invalidate,
+					   to_delete->stmt);
 		vy_cache_tree_delete(&cache->cache_tree, to_delete);
 		vy_cache_entry_delete(cache->env, to_delete);
 	}
@@ -495,6 +502,14 @@ vy_cache_iterator_is_end_stop(struct vy_cache_iterator *itr,
 	}
 }
 
+static void
+vy_cache_iterator_get(struct vy_cache_iterator *itr, struct tuple **ret)
+{
+	*ret = itr->curr_stmt;
+	if (*ret != NULL)
+		vy_stmt_counter_acct_tuple(&itr->cache->stat.get, *ret);
+}
+
 /**
  * Find next (lower, older) record with the same key as current
  *
@@ -505,7 +520,6 @@ vy_cache_iterator_start(struct vy_cache_iterator *itr, struct tuple **ret,
 {
 	assert(!itr->search_started);
 	assert(itr->curr_stmt == NULL);
-	itr->stat->lookup_count++;
 	*ret = NULL;
 	*stop = false;
 	itr->search_started = true;
@@ -513,6 +527,8 @@ vy_cache_iterator_start(struct vy_cache_iterator *itr, struct tuple **ret,
 	struct vy_cache_tree *tree = &itr->cache->cache_tree;
 	const struct tuple *key = itr->key;
 
+	itr->cache->stat.lookup++;
+
 	if (tuple_field_count(itr->key) > 0) {
 		bool exact;
 		itr->curr_pos = itr->iterator_type == ITER_EQ ||
@@ -558,8 +574,7 @@ vy_cache_iterator_start(struct vy_cache_iterator *itr, struct tuple **ret,
 	}
 	itr->curr_stmt = candidate;
 	tuple_ref(itr->curr_stmt);
-	*ret = itr->curr_stmt;
-	return;
+	vy_cache_iterator_get(itr, ret);
 }
 
 static void
@@ -615,7 +630,6 @@ vy_cache_iterator_next_key(struct vy_stmt_iterator *vitr,
 	}
 	if (!itr->curr_stmt) /* End of search. */
 		return 0;
-	itr->stat->step_count++;
 
 	struct vy_cache_tree *tree = &itr->cache->cache_tree;
 	int dir = iterator_direction(itr->iterator_type);
@@ -677,7 +691,7 @@ vy_cache_iterator_next_key(struct vy_stmt_iterator *vitr,
 		itr->curr_stmt = stmt;
 		tuple_ref(itr->curr_stmt);
 	}
-	*ret = itr->curr_stmt;
+	vy_cache_iterator_get(itr, ret);
 	return 0;
 }
 
@@ -734,11 +748,11 @@ vy_cache_iterator_restore(struct vy_stmt_iterator *vitr,
 				vy_cache_tree_iterator_get_elem(tree, &pos);
 			assert(entry != NULL);
 			vy_cache_iterator_is_stop(itr, *entry, stop);
-			*ret = itr->curr_stmt;
+			vy_cache_iterator_get(itr, ret);
 			return 0;
 		}
 		if (itr->version == itr->cache->version) {
-			*ret = itr->curr_stmt;
+			vy_cache_iterator_get(itr, ret);
 			return 0;
 		}
 		while (true) {
@@ -765,7 +779,7 @@ vy_cache_iterator_restore(struct vy_stmt_iterator *vitr,
 				vy_cache_iterator_is_stop(itr, *entry, stop);
 			}
 		}
-		*ret = itr->curr_stmt;
+		vy_cache_iterator_get(itr, ret);
 		return rc;
 	}
 
@@ -826,13 +840,11 @@ static struct vy_stmt_iterator_iface vy_cache_iterator_iface = {
 };
 
 void
-vy_cache_iterator_open(struct vy_cache_iterator *itr,
-		       struct vy_iterator_stat *stat, struct vy_cache *cache,
+vy_cache_iterator_open(struct vy_cache_iterator *itr, struct vy_cache *cache,
 		       enum iterator_type iterator_type,
 		       const struct tuple *key, const struct vy_read_view **rv)
 {
 	itr->base.iface = &vy_cache_iterator_iface;
-	itr->stat = stat;
 
 	itr->cache = cache;
 	itr->iterator_type = iterator_type;
diff --git a/src/box/vy_cache.h b/src/box/vy_cache.h
index 15f7d39842..2b2dab5150 100644
--- a/src/box/vy_cache.h
+++ b/src/box/vy_cache.h
@@ -39,6 +39,7 @@
 #include "index.h" /* enum iterator_type */
 #include "vy_stmt.h" /* for comparators */
 #include "vy_stmt_iterator.h" /* struct vy_stmt_iterator */
+#include "vy_stat.h"
 #include "small/mempool.h"
 
 #if defined(__cplusplus)
@@ -153,6 +154,8 @@ struct vy_cache {
 	uint32_t version;
 	/* Saved pointer to common cache environment */
 	struct vy_cache_env *env;
+	/* Cache statistics. */
+	struct vy_cache_stat stat;
 };
 
 /**
@@ -205,8 +208,6 @@ vy_cache_on_write(struct vy_cache *cache, const struct tuple *stmt,
 struct vy_cache_iterator {
 	/** Parent class, must be the first member */
 	struct vy_stmt_iterator base;
-	/** Iterator usage statistics */
-	struct vy_iterator_stat *stat;
 	/* The cache */
 	struct vy_cache *cache;
 
@@ -242,8 +243,7 @@ struct vy_cache_iterator {
  * @param vlsn - LSN visibility, iterator shows values with lsn <= vlsn
  */
 void
-vy_cache_iterator_open(struct vy_cache_iterator *itr,
-		       struct vy_iterator_stat *stat, struct vy_cache *cache,
+vy_cache_iterator_open(struct vy_cache_iterator *itr, struct vy_cache *cache,
 		       enum iterator_type iterator_type,
 		       const struct tuple *key, const struct vy_read_view **rv);
 
diff --git a/src/box/vy_mem.c b/src/box/vy_mem.c
index 215a64749a..d80a301c84 100644
--- a/src/box/vy_mem.c
+++ b/src/box/vy_mem.c
@@ -269,8 +269,7 @@ vy_mem_iterator_copy_to(struct vy_mem_iterator *itr, struct tuple **ret)
 	itr->last_stmt = vy_stmt_dup(itr->curr_stmt, tuple_format(itr->curr_stmt));
 	*ret = itr->last_stmt;
 	if (itr->last_stmt != NULL) {
-		itr->stat->get.rows++;
-		itr->stat->get.bytes += tuple_size(*ret);
+		vy_stmt_counter_acct_tuple(&itr->stat->get, *ret);
 		return 0;
 	}
 	return -1;
diff --git a/src/box/vy_run.c b/src/box/vy_run.c
index 75c2036168..0293f186b3 100644
--- a/src/box/vy_run.c
+++ b/src/box/vy_run.c
@@ -1551,8 +1551,7 @@ vy_run_iterator_get(struct vy_run_iterator *itr, struct tuple **result)
 	if (rc == 0) {
 		itr->curr_stmt_pos = itr->curr_pos;
 		itr->curr_stmt = *result;
-		itr->stat->get.rows++;
-		itr->stat->get.bytes += tuple_size(*result);
+		vy_stmt_counter_acct_tuple(&itr->stat->get, *result);
 	}
 	return rc;
 }
diff --git a/src/box/vy_stat.h b/src/box/vy_stat.h
index 23493ea322..e62fc26747 100644
--- a/src/box/vy_stat.h
+++ b/src/box/vy_stat.h
@@ -33,6 +33,8 @@
 
 #include <stdint.h>
 
+#include "tuple.h"
+
 #if defined(__cplusplus)
 extern "C" {
 #endif /* defined(__cplusplus) */
@@ -121,6 +123,44 @@ struct vy_index_stat {
 	} disk;
 };
 
+/** Tuple cache statistics. */
+struct vy_cache_stat {
+	/** Number of statements in the cache. */
+	struct vy_stmt_counter count;
+	/** Number of lookups in the cache. */
+	int64_t lookup;
+	/** Number of reads from the cache. */
+	struct vy_stmt_counter get;
+	/** Number of writes to the cache. */
+	struct vy_stmt_counter put;
+	/**
+	 * Number of statements removed from the cache
+	 * due to overwrite.
+	 */
+	struct vy_stmt_counter invalidate;
+	/**
+	 * Number of statements removed from the cache
+	 * due to memory shortage.
+	 */
+	struct vy_stmt_counter evict;
+};
+
+static inline void
+vy_stmt_counter_acct_tuple(struct vy_stmt_counter *c,
+			   const struct tuple *tuple)
+{
+	c->rows++;
+	c->bytes += tuple_size(tuple);
+}
+
+static inline void
+vy_stmt_counter_unacct_tuple(struct vy_stmt_counter *c,
+			     const struct tuple *tuple)
+{
+	c->rows--;
+	c->bytes -= tuple_size(tuple);
+}
+
 static inline void
 vy_stmt_counter_add(struct vy_stmt_counter *c1,
 		    const struct vy_stmt_counter *c2)
-- 
GitLab