Tarantool development patches archive
 help / color / mirror / Atom feed
From: Ilya Kosarev <i.kosarev@tarantool.org>
To: tarantool-patches@dev.tarantool.org
Cc: v.shpilevoy@tarantool.org
Subject: [Tarantool-patches] [PATCH v2 2/2] memtx: increase the memory quota if needed to truncate or delete
Date: Tue, 14 Jan 2020 00:31:23 +0300	[thread overview]
Message-ID: <60fbcb8d59f04632ca31976bdf537afffe8e8e5f.1578951026.git.i.kosarev@tarantool.org> (raw)
In-Reply-To: <cover.1578951026.git.i.kosarev@tarantool.org>
In-Reply-To: <cover.1578951026.git.i.kosarev@tarantool.org>

Trying to perform space:truncate() and space:delete() while reaching
memtx_memory limit we could experience slab allocator failure. This
behavior seems to be quite surprising for users. Now we are increasing
memtx quota if needed for truncation or deletion. After performing it
quota is being set back to the previous value if possible, while it
should be so for almost any case, since we are meant to free some space
during deletion or truncation.

Closes #3807
---
 src/box/blackhole.c      |  1 +
 src/box/box.cc           | 36 +++++++++++++++++++++++++++++++++++-
 src/box/engine.c         | 11 +++++++++++
 src/box/engine.h         |  9 +++++++++
 src/box/memtx_engine.c   | 20 ++++++++++++++++++++
 src/box/memtx_engine.h   |  4 ++++
 src/box/service_engine.c |  1 +
 src/box/sysview.c        |  1 +
 src/box/vinyl.c          |  1 +
 9 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/src/box/blackhole.c b/src/box/blackhole.c
index 69f1deba1..af587f434 100644
--- a/src/box/blackhole.c
+++ b/src/box/blackhole.c
@@ -194,6 +194,7 @@ static const struct engine_vtab blackhole_engine_vtab = {
 	/* .commit_checkpoint = */ generic_engine_commit_checkpoint,
 	/* .abort_checkpoint = */ generic_engine_abort_checkpoint,
 	/* .collect_garbage = */ generic_engine_collect_garbage,
+	/* .guarantee_memory = */ generic_engine_guarantee_memory,
 	/* .backup = */ generic_engine_backup,
 	/* .memory_stat = */ generic_engine_memory_stat,
 	/* .reset_stat = */ generic_engine_reset_stat,
diff --git a/src/box/box.cc b/src/box/box.cc
index 1b2b27d61..18c09ce1b 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -1250,7 +1250,27 @@ box_delete(uint32_t space_id, uint32_t index_id, const char *key,
 	request.index_id = index_id;
 	request.key = key;
 	request.key_end = key_end;
-	return box_process1(&request, result);
+
+	struct space *space = space_cache_find(space_id);
+	if (space == NULL)
+		return -1;
+	size_t total;
+	bool extended = false;
+	space->engine->vtab->guarantee_memory(space->engine,
+					      MEMTX_SLAB_SIZE,
+					      &total, &extended);
+
+	int rc = box_process1(&request, result);
+
+	if (extended) {
+		struct memtx_engine *memtx =
+			(struct memtx_engine *)space->engine;
+		size_t new_total = quota_set(&memtx->quota, total);
+		if (new_total > total)
+			quota_set(&memtx->quota, quota_used(&memtx->quota));
+	}
+
+	return rc;
 }
 
 int
@@ -1321,9 +1341,23 @@ space_truncate(struct space *space)
 	ops_buf_end = mp_encode_uint(ops_buf_end, 1);
 	assert(ops_buf_end < buf + buf_size);
 
+	size_t total;
+	bool extended = false;
+	space->engine->vtab->guarantee_memory(space->engine,
+					      MEMTX_SLAB_SIZE,
+					      &total, &extended);
+
 	if (box_upsert(BOX_TRUNCATE_ID, 0, tuple_buf, tuple_buf_end,
 		       ops_buf, ops_buf_end, 0, NULL) != 0)
 		diag_raise();
+
+	if (extended) {
+		struct memtx_engine *memtx =
+			(struct memtx_engine *)space->engine;
+		size_t new_total = quota_set(&memtx->quota, total);
+		if (new_total > total)
+			quota_set(&memtx->quota, quota_used(&memtx->quota));
+	}
 }
 
 int
diff --git a/src/box/engine.c b/src/box/engine.c
index 8dc0df1d0..f393a2629 100644
--- a/src/box/engine.c
+++ b/src/box/engine.c
@@ -412,6 +412,17 @@ generic_engine_memory_stat(struct engine *engine,
 	(void)stat;
 }
 
+void
+generic_engine_guarantee_memory(struct engine *engine,
+				size_t request, size_t *old_total,
+				bool *extended)
+{
+	(void)engine;
+	(void)request;
+	*old_total = 0;
+	*extended = false;
+}
+
 void
 generic_engine_reset_stat(struct engine *engine)
 {
diff --git a/src/box/engine.h b/src/box/engine.h
index 07d7fac9b..d1e3e998f 100644
--- a/src/box/engine.h
+++ b/src/box/engine.h
@@ -185,6 +185,14 @@ struct engine_vtab {
 	 */
 	void (*collect_garbage)(struct engine *engine,
 				const struct vclock *vclock);
+	/**
+	 * Performing space:truncate() or space:delete() while reaching
+	 * memory limit might lead to slab allocator failure. To avoid
+	 * it, we temporally increase memory quota using this function.
+	 */
+        void (*guarantee_memory)(struct engine *engine,
+                                  size_t request, size_t *old_total,
+                                  bool *extended);
 	/**
 	 * Backup callback. It is supposed to call @cb for each file
 	 * that needs to be backed up in order to restore from the
@@ -404,6 +412,7 @@ void generic_engine_collect_garbage(struct engine *, const struct vclock *);
 int generic_engine_backup(struct engine *, const struct vclock *,
 			  engine_backup_cb, void *);
 void generic_engine_memory_stat(struct engine *, struct engine_memory_stat *);
+void generic_engine_guarantee_memory(struct engine *engine, size_t request, size_t *old_total, bool *extended);
 void generic_engine_reset_stat(struct engine *);
 int generic_engine_check_space_def(struct space_def *);
 
diff --git a/src/box/memtx_engine.c b/src/box/memtx_engine.c
index 23ccc4703..6c80b5919 100644
--- a/src/box/memtx_engine.c
+++ b/src/box/memtx_engine.c
@@ -927,6 +927,7 @@ static const struct engine_vtab memtx_engine_vtab = {
 	/* .commit_checkpoint = */ memtx_engine_commit_checkpoint,
 	/* .abort_checkpoint = */ memtx_engine_abort_checkpoint,
 	/* .collect_garbage = */ memtx_engine_collect_garbage,
+	/* .guarantee_memory = */ memtx_engine_guarantee_memory,
 	/* .backup = */ memtx_engine_backup,
 	/* .memory_stat = */ memtx_engine_memory_stat,
 	/* .reset_stat = */ generic_engine_reset_stat,
@@ -1090,6 +1091,25 @@ memtx_engine_set_memory(struct memtx_engine *memtx, size_t size)
 	return 0;
 }
 
+void
+memtx_engine_guarantee_memory(struct engine *engine,
+			      size_t request, size_t *old_total,
+			      bool *extended)
+{
+	struct quota *memtx_quota =
+		&((struct memtx_engine *)engine)->quota;
+	size_t total, used;
+	quota_get_total_and_used(memtx_quota, &total, &used);
+	*old_total = total;
+	if (total - used < request) {
+		quota_set(memtx_quota,
+			  total + request - (total - used));
+		*extended = true;
+		return;
+	}
+	*extended = false;
+}
+
 void
 memtx_engine_set_max_tuple_size(struct memtx_engine *memtx, size_t max_size)
 {
diff --git a/src/box/memtx_engine.h b/src/box/memtx_engine.h
index f562c66df..b8489fffe 100644
--- a/src/box/memtx_engine.h
+++ b/src/box/memtx_engine.h
@@ -213,6 +213,10 @@ memtx_engine_set_snap_io_rate_limit(struct memtx_engine *memtx, double limit);
 int
 memtx_engine_set_memory(struct memtx_engine *memtx, size_t size);
 
+void
+memtx_engine_guarantee_memory(struct engine *engine, size_t request,
+			      size_t *old_total, bool *extended);
+
 void
 memtx_engine_set_max_tuple_size(struct memtx_engine *memtx, size_t max_size);
 
diff --git a/src/box/service_engine.c b/src/box/service_engine.c
index 5a33a735a..cfbd4ee60 100644
--- a/src/box/service_engine.c
+++ b/src/box/service_engine.c
@@ -112,6 +112,7 @@ static const struct engine_vtab service_engine_vtab = {
 	/* .commit_checkpoint = */ generic_engine_commit_checkpoint,
 	/* .abort_checkpoint = */ generic_engine_abort_checkpoint,
 	/* .collect_garbage = */ generic_engine_collect_garbage,
+	/* .guarantee_memory = */ generic_engine_guarantee_memory,
 	/* .backup = */ generic_engine_backup,
 	/* .memory_stat = */ generic_engine_memory_stat,
 	/* .reset_stat = */ generic_engine_reset_stat,
diff --git a/src/box/sysview.c b/src/box/sysview.c
index 00c320b6f..bfc7bd1dd 100644
--- a/src/box/sysview.c
+++ b/src/box/sysview.c
@@ -584,6 +584,7 @@ static const struct engine_vtab sysview_engine_vtab = {
 	/* .commit_checkpoint = */ generic_engine_commit_checkpoint,
 	/* .abort_checkpoint = */ generic_engine_abort_checkpoint,
 	/* .collect_garbage = */ generic_engine_collect_garbage,
+	/* .guarantee_memory = */ generic_engine_guarantee_memory,
 	/* .backup = */ generic_engine_backup,
 	/* .memory_stat = */ generic_engine_memory_stat,
 	/* .reset_stat = */ generic_engine_reset_stat,
diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 5f169f09b..9343423c5 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -4489,6 +4489,7 @@ static const struct engine_vtab vinyl_engine_vtab = {
 	/* .commit_checkpoint = */ vinyl_engine_commit_checkpoint,
 	/* .abort_checkpoint = */ vinyl_engine_abort_checkpoint,
 	/* .collect_garbage = */ vinyl_engine_collect_garbage,
+	/* .guarantee_memory = */ generic_engine_guarantee_memory,
 	/* .backup = */ vinyl_engine_backup,
 	/* .memory_stat = */ vinyl_engine_memory_stat,
 	/* .reset_stat = */ vinyl_engine_reset_stat,
-- 
2.17.1

  parent reply	other threads:[~2020-01-13 21:31 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-13 21:31 [Tarantool-patches] [PATCH v2 0/2] Safe truncation and deletion Ilya Kosarev
2020-01-13 21:31 ` [Tarantool-patches] [PATCH v2 1/2] b-tree: return NULL on matras_alloc fail Ilya Kosarev
2020-01-14 21:00   ` Vladislav Shpilevoy
2020-01-20 18:13     ` Ilya Kosarev
2020-01-13 21:31 ` Ilya Kosarev [this message]
2020-01-14 21:00   ` [Tarantool-patches] [PATCH v2 2/2] memtx: increase the memory quota if needed to truncate or delete Vladislav Shpilevoy
2020-01-20 18:13     ` Ilya Kosarev
2020-01-24 11:21     ` Konstantin Osipov
  -- strict thread matches above, loose matches on Subject: below --
2020-01-10  0:36 [Tarantool-patches] [PATCH v2 0/2] Safe truncation and deletion Ilya Kosarev
2020-01-10  0:36 ` [Tarantool-patches] [PATCH v2 2/2] memtx: increase the memory quota if needed to truncate or delete Ilya Kosarev

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=60fbcb8d59f04632ca31976bdf537afffe8e8e5f.1578951026.git.i.kosarev@tarantool.org \
    --to=i.kosarev@tarantool.org \
    --cc=tarantool-patches@dev.tarantool.org \
    --cc=v.shpilevoy@tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH v2 2/2] memtx: increase the memory quota if needed to truncate or delete' \
    /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