Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladimir Davydov <vdavydov.dev@gmail.com>
To: kostja@tarantool.org
Cc: tarantool-patches@freelists.org
Subject: [PATCH v2 03/11] vinyl: minor refactoring of quota methods
Date: Fri, 28 Sep 2018 20:40:01 +0300	[thread overview]
Message-ID: <aab16fa614d125d9c8a8c44d490c2e9473e7e683.1538155645.git.vdavydov.dev@gmail.com> (raw)
In-Reply-To: <cover.1538155645.git.vdavydov.dev@gmail.com>
In-Reply-To: <cover.1538155645.git.vdavydov.dev@gmail.com>

The refactoring is targeted at facilitating introduction of rate
limiting within the quota class. It moves code blocks around, factors
out some blocks in functions, and improves comments. No functional
changes.

Needed for #1862
---
 src/box/vy_quota.c | 131 +++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 91 insertions(+), 40 deletions(-)

diff --git a/src/box/vy_quota.c b/src/box/vy_quota.c
index e6d22348..64ce56c0 100644
--- a/src/box/vy_quota.c
+++ b/src/box/vy_quota.c
@@ -31,6 +31,7 @@
 #include "vy_quota.h"
 
 #include <assert.h>
+#include <stdbool.h>
 #include <stddef.h>
 #include <tarantool_ev.h>
 
@@ -40,13 +41,55 @@
 #include "trivia/util.h"
 
 /**
- * Returns true if the quota limit is exceeded and so consumers
- * have to wait.
+ * Return true if the requested amount of memory may be consumed
+ * right now, false if consumers have to wait.
  */
 static inline bool
-vy_quota_is_exceeded(struct vy_quota *q)
+vy_quota_may_use(struct vy_quota *q, size_t size)
 {
-	return q->used > q->limit;
+	if (q->used + size > q->limit)
+		return false;
+	return true;
+}
+
+/**
+ * Consume the given amount of memory without checking the limit.
+ */
+static inline void
+vy_quota_do_use(struct vy_quota *q, size_t size)
+{
+	q->used += size;
+}
+
+/**
+ * Return the given amount of memory without waking blocked fibers.
+ * This function is an exact opposite of vy_quota_do_use().
+ */
+static inline void
+vy_quota_do_unuse(struct vy_quota *q, size_t size)
+{
+	assert(q->used >= size);
+	q->used -= size;
+}
+
+/**
+ * Invoke the registered callback in case memory usage exceeds
+ * the configured limit.
+ */
+static inline void
+vy_quota_check_limit(struct vy_quota *q)
+{
+	if (q->used > q->limit)
+		q->quota_exceeded_cb(q);
+}
+
+/**
+ * Wake up the first consumer in the line waiting for quota.
+ */
+static void
+vy_quota_signal(struct vy_quota *q)
+{
+	fiber_cond_signal(&q->cond);
 }
 
 void
@@ -70,55 +113,63 @@ void
 vy_quota_set_limit(struct vy_quota *q, size_t limit)
 {
 	q->limit = limit;
-	if (q->used >= limit)
-		q->quota_exceeded_cb(q);
-	fiber_cond_signal(&q->cond);
+	vy_quota_check_limit(q);
+	vy_quota_signal(q);
 }
 
 void
 vy_quota_force_use(struct vy_quota *q, size_t size)
 {
-	q->used += size;
-	if (q->used >= q->limit)
-		q->quota_exceeded_cb(q);
+	vy_quota_do_use(q, size);
+	vy_quota_check_limit(q);
 }
 
 void
 vy_quota_release(struct vy_quota *q, size_t size)
 {
-	assert(q->used >= size);
-	q->used -= size;
-	fiber_cond_signal(&q->cond);
+	vy_quota_do_unuse(q, size);
+	vy_quota_signal(q);
 }
 
 int
 vy_quota_use(struct vy_quota *q, size_t size, double timeout)
 {
-	q->used += size;
-	if (vy_quota_is_exceeded(q)) {
-		/* Wait for quota. */
-		double start_time = ev_monotonic_now(loop());
-		double deadline = start_time + timeout;
+	if (vy_quota_may_use(q, size)) {
+		vy_quota_do_use(q, size);
+		return 0;
+	}
 
-		do {
-			q->quota_exceeded_cb(q);
-			q->used -= size;
-			if (fiber_cond_wait_deadline(&q->cond, deadline) != 0)
-				return -1; /* timed out */
-			q->used += size;
-		} while (vy_quota_is_exceeded(q));
-
-		double wait_time = ev_monotonic_now(loop()) - start_time;
-		if (wait_time > q->too_long_threshold) {
-			say_warn("waited for %zu bytes of vinyl memory quota "
-				 "for too long: %.3f sec", size, wait_time);
-		}
+	/* Wait for quota. */
+	double wait_start = ev_monotonic_now(loop());
+	double deadline = wait_start + timeout;
+
+	do {
 		/*
-		 * Wake up the next fiber in the line waiting
-		 * for quota.
+		 * If the requested amount of memory cannot be
+		 * consumed due to the configured limit, notify
+		 * the caller before going to sleep so that it
+		 * can start memory reclaim immediately.
 		 */
-		fiber_cond_signal(&q->cond);
+		if (q->used + size > q->limit)
+			q->quota_exceeded_cb(q);
+		if (fiber_cond_wait_deadline(&q->cond, deadline) != 0)
+			return -1; /* timed out */
+	} while (!vy_quota_may_use(q, size));
+
+	double wait_time = ev_monotonic_now(loop()) - wait_start;
+	if (wait_time > q->too_long_threshold) {
+		say_warn("waited for %zu bytes of vinyl memory quota "
+			 "for too long: %.3f sec", size, wait_time);
 	}
+
+	vy_quota_do_use(q, size);
+	/*
+	 * Blocked consumers are awaken one by one to preserve
+	 * the order they were put to sleep. It's a responsibility
+	 * of a consumer that managed to acquire the requested
+	 * amount of quota to wake up the next one in the line.
+	 */
+	vy_quota_signal(q);
 	return 0;
 }
 
@@ -126,11 +177,11 @@ void
 vy_quota_adjust(struct vy_quota *q, size_t reserved, size_t used)
 {
 	if (reserved > used) {
-		size_t excess = reserved - used;
-		assert(q->used >= excess);
-		q->used -= excess;
-		fiber_cond_signal(&q->cond);
+		vy_quota_do_unuse(q, reserved - used);
+		vy_quota_signal(q);
+	}
+	if (reserved < used) {
+		vy_quota_do_use(q, used - reserved);
+		vy_quota_check_limit(q);
 	}
-	if (reserved < used)
-		vy_quota_force_use(q, used - reserved);
 }
-- 
2.11.0

  parent reply	other threads:[~2018-09-28 17:40 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-28 17:39 [PATCH v2 00/11] vinyl: transaction throttling infrastructure Vladimir Davydov
2018-09-28 17:39 ` [PATCH v2 01/11] vinyl: add helper to start scheduler and enable quota on startup Vladimir Davydov
2018-09-29  4:37   ` [tarantool-patches] " Konstantin Osipov
2018-09-28 17:40 ` [PATCH v2 02/11] vinyl: factor load regulator out of quota Vladimir Davydov
2018-09-29  5:00   ` [tarantool-patches] " Konstantin Osipov
2018-09-29 11:36     ` Vladimir Davydov
     [not found]       ` <20180929114308.GA19162@chai>
2018-10-01 10:27         ` Vladimir Davydov
2018-10-01 10:31   ` Vladimir Davydov
2018-10-02 18:16   ` [tarantool-patches] " Konstantin Osipov
2018-10-03  8:49     ` Vladimir Davydov
2018-09-28 17:40 ` Vladimir Davydov [this message]
2018-09-29  5:01   ` [tarantool-patches] Re: [PATCH v2 03/11] vinyl: minor refactoring of quota methods Konstantin Osipov
2018-09-28 17:40 ` [PATCH v2 04/11] vinyl: move transaction size sanity check to quota Vladimir Davydov
2018-09-29  5:02   ` [tarantool-patches] " Konstantin Osipov
2018-09-28 17:40 ` [PATCH v2 05/11] vinyl: implement quota wait queue without fiber_cond Vladimir Davydov
2018-09-29  5:05   ` [tarantool-patches] " Konstantin Osipov
2018-09-29 11:44     ` Vladimir Davydov
2018-09-28 17:40 ` [PATCH v2 06/11] vinyl: enable quota upon recovery completion explicitly Vladimir Davydov
2018-09-29  5:06   ` [tarantool-patches] " Konstantin Osipov
2018-09-28 17:40 ` [PATCH v2 07/11] vinyl: zap vy_env::memory, read_threads, and write_threads Vladimir Davydov
2018-09-29  5:06   ` [tarantool-patches] " Konstantin Osipov
2018-09-28 17:40 ` [PATCH v2 08/11] vinyl: do not try to trigger dump in regulator if already in progress Vladimir Davydov
2018-09-28 17:40 ` [PATCH v2 09/11] vinyl: do not account zero dump bandwidth Vladimir Davydov
2018-10-12 13:27   ` Vladimir Davydov
2018-10-16 18:25     ` [tarantool-patches] " Konstantin Osipov
2018-10-17  8:44       ` Vladimir Davydov
2018-10-23  7:02         ` Konstantin Osipov
2018-09-28 17:40 ` [PATCH v2 10/11] vinyl: implement basic transaction throttling Vladimir Davydov
2018-09-28 17:40 ` [PATCH v2 11/11] vinyl: introduce quota consumer priorities Vladimir Davydov
2018-10-06 13:24   ` Konstantin Osipov
2018-10-08 11:10     ` Vladimir Davydov
2018-10-09 13:25       ` Vladimir Davydov
2018-10-11  7:02       ` Konstantin Osipov
2018-10-11  8:29         ` Vladimir Davydov
2018-10-03  9:06 ` [PATCH v2 00/11] vinyl: transaction throttling infrastructure Vladimir Davydov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aab16fa614d125d9c8a8c44d490c2e9473e7e683.1538155645.git.vdavydov.dev@gmail.com \
    --to=vdavydov.dev@gmail.com \
    --cc=kostja@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --subject='Re: [PATCH v2 03/11] vinyl: minor refactoring of quota methods' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox