From 5e28b70a8f4a7f1ebafbd20dadc7be893e2b0660 Mon Sep 17 00:00:00 2001
From: Vladimir Davydov <vdavydov.dev@gmail.com>
Date: Wed, 1 Nov 2017 16:47:50 +0300
Subject: [PATCH] vinyl: do not use rmean for calculating quota use rate

We have a timer for updating watermark every second. Let's reuse it for
quota use rate calculation. This will allow us to get rid of legacy
vinyl statistics.

Also, let's use EWMA for calculating the average. It is a more efficient
and common method, which allows to easily tune the period over which the
value is averaged.
---
 src/box/vinyl.c | 49 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 39 insertions(+), 10 deletions(-)

diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 2f1dceb874..fc2091bee8 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -44,6 +44,7 @@
 #include "vy_scheduler.h"
 #include "vy_stat.h"
 
+#include <math.h>
 #include <small/lsregion.h>
 #include <coio_file.h>
 
@@ -100,6 +101,17 @@ struct vy_env {
 	struct vy_quota     quota;
 	/** Timer for updating quota watermark. */
 	ev_timer            quota_timer;
+	/**
+	 * Amount of quota used since the last
+	 * invocation of the quota timer callback.
+	 */
+	size_t quota_use_curr;
+	/**
+	 * Quota use rate, in bytes per second.
+	 * Calculated as exponentially weighted
+	 * moving average of quota_use_curr.
+	 */
+	size_t quota_use_rate;
 	/** Common index environment. */
 	struct vy_index_env index_env;
 	/** Environment for cache subsystem */
@@ -126,6 +138,19 @@ struct vy_env {
 	int write_threads;
 };
 
+enum {
+	/**
+	 * Time interval between successive updates of
+	 * quota watermark and use rate, in seconds.
+	 */
+	VY_QUOTA_UPDATE_INTERVAL = 1,
+	/**
+	 * Period of time over which the quota use rate
+	 * is averaged, in seconds.
+	 */
+	VY_QUOTA_RATE_AVG_PERIOD = 5,
+};
+
 /** Mask passed to vy_gc(). */
 enum {
 	/** Delete incomplete runs. */
@@ -232,12 +257,6 @@ vy_stat_dump_bandwidth(struct vy_stat *s)
 	return histogram_percentile(s->dump_bw, 10);
 }
 
-static int64_t
-vy_stat_tx_write_rate(struct vy_stat *s)
-{
-	return rmean_mean(s->rmean, VY_STAT_TX_WRITE);
-}
-
 /** Cursor. */
 struct vy_cursor {
 	/**
@@ -2107,6 +2126,7 @@ vy_prepare(struct vy_env *env, struct vy_tx *tx)
 	rmean_collect(env->stat->rmean, VY_STAT_TX, 1);
 	rmean_collect(env->stat->rmean, VY_STAT_TX_OPS, tx->write_count);
 	rmean_collect(env->stat->rmean, VY_STAT_TX_WRITE, write_size);
+	env->quota_use_curr += write_size;
 	return 0;
 }
 
@@ -2179,7 +2199,15 @@ vy_env_quota_timer_cb(ev_loop *loop, ev_timer *timer, int events)
 
 	struct vy_env *e = timer->data;
 
-	int64_t tx_write_rate = vy_stat_tx_write_rate(e->stat);
+	/*
+	 * Update the quota use rate with the new measurement.
+	 */
+	static const double weight = 1 - exp(-VY_QUOTA_UPDATE_INTERVAL /
+					     (double)VY_QUOTA_RATE_AVG_PERIOD);
+	e->quota_use_rate = (1 - weight) * e->quota_use_rate +
+		weight * e->quota_use_curr / VY_QUOTA_UPDATE_INTERVAL;
+	e->quota_use_curr = 0;
+
 	int64_t dump_bandwidth = vy_stat_dump_bandwidth(e->stat);
 
 	/*
@@ -2191,10 +2219,10 @@ vy_env_quota_timer_cb(ev_loop *loop, ev_timer *timer, int events)
 	 *
 	 *   limit - watermark      watermark
 	 *   ----------------- = --------------
-	 *     tx_write_rate     dump_bandwidth
+	 *     quota_use_rate    dump_bandwidth
 	 */
 	size_t watermark = ((double)e->quota.limit * dump_bandwidth /
-			    (dump_bandwidth + tx_write_rate + 1));
+			    (dump_bandwidth + e->quota_use_rate + 1));
 
 	vy_quota_set_watermark(&e->quota, watermark);
 }
@@ -2307,7 +2335,8 @@ vy_env_new(const char *path, size_t memory, size_t cache, int read_threads,
 	mempool_create(&e->cursor_pool, slab_cache,
 	               sizeof(struct vy_cursor));
 	vy_quota_create(&e->quota, vy_env_quota_exceeded_cb);
-	ev_timer_init(&e->quota_timer, vy_env_quota_timer_cb, 0, 1.);
+	ev_timer_init(&e->quota_timer, vy_env_quota_timer_cb, 0,
+		      VY_QUOTA_UPDATE_INTERVAL);
 	e->quota_timer.data = e;
 	ev_timer_start(loop(), &e->quota_timer);
 	vy_cache_env_create(&e->cache_env, slab_cache, cache);
-- 
GitLab