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] Allow to increase box.cfg.vinyl_memory and memtx_memory at runtime
Date: Wed, 30 May 2018 15:55:13 +0300	[thread overview]
Message-ID: <5c833e39a3337fdf832ebd745ad89d901cf4c92e.1527684463.git.vdavydov.dev@gmail.com> (raw)

Slab arena can grow dynamically so all we need to do is increase the
quota limit. Decreasing the limits is still explicitly prohibited,
because slab arena never unmaps slabs.

Closes #2634
---
https://github.com/tarantool/tarantool/issues/2634
https://github.com/tarantool/tarantool/commits/gh-2634-allow-to-increase-memory-size

 src/box/box.cc                    | 18 +++++++++
 src/box/box.h                     |  2 +
 src/box/lua/cfg.cc                | 24 ++++++++++++
 src/box/lua/load_cfg.lua          |  4 ++
 src/box/memtx_engine.c            | 12 ++++++
 src/box/memtx_engine.h            | 10 +++++
 src/box/vinyl.c                   | 12 ++++++
 src/box/vinyl.h                   | 13 +++++++
 src/box/vy_quota.h                |  1 +
 test/box/lua/cfg_memory.lua       |  9 +++++
 test/box/reconfigure.result       | 80 ++++++++++++++++++++++++++++++++++++++-
 test/box/reconfigure.test.lua     | 31 +++++++++++++++
 test/vinyl/quota.result           | 77 +++++++++++++++++++++++++++++++++++++
 test/vinyl/quota.test.lua         | 33 ++++++++++++++++
 test/vinyl/quota_timeout.result   | 30 ++++++++++++++-
 test/vinyl/quota_timeout.test.lua | 12 ++++++
 16 files changed, 365 insertions(+), 3 deletions(-)
 create mode 100644 test/box/lua/cfg_memory.lua

diff --git a/src/box/box.cc b/src/box/box.cc
index c728a4c5..9edf8224 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -701,6 +701,15 @@ box_set_snap_io_rate_limit(void)
 }
 
 void
+box_set_memtx_memory(void)
+{
+	struct memtx_engine *memtx;
+	memtx = (struct memtx_engine *)engine_by_name("memtx");
+	assert(memtx != NULL);
+	memtx_engine_set_memory_xc(memtx, cfg_geti("memtx_memory"));
+}
+
+void
 box_set_memtx_max_tuple_size(void)
 {
 	struct memtx_engine *memtx;
@@ -738,6 +747,15 @@ box_set_checkpoint_count(void)
 }
 
 void
+box_set_vinyl_memory(void)
+{
+	struct vinyl_engine *vinyl;
+	vinyl = (struct vinyl_engine *)engine_by_name("vinyl");
+	assert(vinyl != NULL);
+	vinyl_engine_set_memory_xc(vinyl, cfg_geti("vinyl_memory"));
+}
+
+void
 box_set_vinyl_max_tuple_size(void)
 {
 	struct vinyl_engine *vinyl;
diff --git a/src/box/box.h b/src/box/box.h
index d1a227e3..e94c48cc 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -175,7 +175,9 @@ void box_set_snap_io_rate_limit(void);
 void box_set_too_long_threshold(void);
 void box_set_readahead(void);
 void box_set_checkpoint_count(void);
+void box_set_memtx_memory(void);
 void box_set_memtx_max_tuple_size(void);
+void box_set_vinyl_memory(void);
 void box_set_vinyl_max_tuple_size(void);
 void box_set_vinyl_cache(void);
 void box_set_vinyl_timeout(void);
diff --git a/src/box/lua/cfg.cc b/src/box/lua/cfg.cc
index a20df6b8..5afebc94 100644
--- a/src/box/lua/cfg.cc
+++ b/src/box/lua/cfg.cc
@@ -177,6 +177,17 @@ lbox_cfg_set_read_only(struct lua_State *L)
 }
 
 static int
+lbox_cfg_set_memtx_memory(struct lua_State *L)
+{
+	try {
+		box_set_memtx_memory();
+	} catch (Exception *) {
+		luaT_error(L);
+	}
+	return 0;
+}
+
+static int
 lbox_cfg_set_memtx_max_tuple_size(struct lua_State *L)
 {
 	try {
@@ -188,6 +199,17 @@ lbox_cfg_set_memtx_max_tuple_size(struct lua_State *L)
 }
 
 static int
+lbox_cfg_set_vinyl_memory(struct lua_State *L)
+{
+	try {
+		box_set_vinyl_memory();
+	} catch (Exception *) {
+		luaT_error(L);
+	}
+	return 0;
+}
+
+static int
 lbox_cfg_set_vinyl_max_tuple_size(struct lua_State *L)
 {
 	try {
@@ -298,7 +320,9 @@ box_lua_cfg_init(struct lua_State *L)
 		{"cfg_set_snap_io_rate_limit", lbox_cfg_set_snap_io_rate_limit},
 		{"cfg_set_checkpoint_count", lbox_cfg_set_checkpoint_count},
 		{"cfg_set_read_only", lbox_cfg_set_read_only},
+		{"cfg_set_memtx_memory", lbox_cfg_set_memtx_memory},
 		{"cfg_set_memtx_max_tuple_size", lbox_cfg_set_memtx_max_tuple_size},
+		{"cfg_set_vinyl_memory", lbox_cfg_set_vinyl_memory},
 		{"cfg_set_vinyl_max_tuple_size", lbox_cfg_set_vinyl_max_tuple_size},
 		{"cfg_set_vinyl_cache", lbox_cfg_set_vinyl_cache},
 		{"cfg_set_vinyl_timeout", lbox_cfg_set_vinyl_timeout},
diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua
index cebc42fe..0b668cdc 100644
--- a/src/box/lua/load_cfg.lua
+++ b/src/box/lua/load_cfg.lua
@@ -191,7 +191,9 @@ local dynamic_cfg = {
     too_long_threshold      = private.cfg_set_too_long_threshold,
     snap_io_rate_limit      = private.cfg_set_snap_io_rate_limit,
     read_only               = private.cfg_set_read_only,
+    memtx_memory            = private.cfg_set_memtx_memory,
     memtx_max_tuple_size    = private.cfg_set_memtx_max_tuple_size,
+    vinyl_memory            = private.cfg_set_vinyl_memory,
     vinyl_max_tuple_size    = private.cfg_set_vinyl_max_tuple_size,
     vinyl_cache             = private.cfg_set_vinyl_cache,
     vinyl_timeout           = private.cfg_set_vinyl_timeout,
@@ -219,6 +221,8 @@ local dynamic_cfg = {
 local dynamic_cfg_skip_at_load = {
     wal_mode                = true,
     listen                  = true,
+    memtx_memory            = true,
+    vinyl_memory            = true,
     replication             = true,
     replication_timeout     = true,
     replication_connect_timeout = true,
diff --git a/src/box/memtx_engine.c b/src/box/memtx_engine.c
index 1d3d4943..89863e0f 100644
--- a/src/box/memtx_engine.c
+++ b/src/box/memtx_engine.c
@@ -1044,6 +1044,18 @@ memtx_engine_set_snap_io_rate_limit(struct memtx_engine *memtx, double limit)
 	memtx->snap_io_rate_limit = limit * 1024 * 1024;
 }
 
+int
+memtx_engine_set_memory(struct memtx_engine *memtx, size_t size)
+{
+	if (size < quota_total(&memtx->quota)) {
+		diag_set(ClientError, ER_CFG, "memtx_memory",
+			 "cannot decrease memory size at runtime");
+		return -1;
+	}
+	quota_set(&memtx->quota, size);
+	return 0;
+}
+
 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 97dba177..0f8e92ee 100644
--- a/src/box/memtx_engine.h
+++ b/src/box/memtx_engine.h
@@ -190,6 +190,9 @@ memtx_engine_recover_snapshot(struct memtx_engine *memtx,
 void
 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_set_max_tuple_size(struct memtx_engine *memtx, size_t max_size);
 
@@ -258,6 +261,13 @@ memtx_engine_new_xc(const char *snap_dirname, bool force_recovery,
 }
 
 static inline void
+memtx_engine_set_memory_xc(struct memtx_engine *memtx, size_t size)
+{
+	if (memtx_engine_set_memory(memtx, size) != 0)
+		diag_raise();
+}
+
+static inline void
 memtx_engine_recover_snapshot_xc(struct memtx_engine *memtx,
 				 const struct vclock *vclock)
 {
diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index f0d26874..4734670b 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -2766,6 +2766,18 @@ vinyl_engine_set_cache(struct vinyl_engine *vinyl, size_t quota)
 	vy_cache_env_set_quota(&vinyl->env->cache_env, quota);
 }
 
+int
+vinyl_engine_set_memory(struct vinyl_engine *vinyl, size_t size)
+{
+	if (size < vinyl->env->quota.limit) {
+		diag_set(ClientError, ER_CFG, "vinyl_memory",
+			 "cannot decrease memory size at runtime");
+		return -1;
+	}
+	vy_quota_set_limit(&vinyl->env->quota, size);
+	return 0;
+}
+
 void
 vinyl_engine_set_max_tuple_size(struct vinyl_engine *vinyl, size_t max_size)
 {
diff --git a/src/box/vinyl.h b/src/box/vinyl.h
index ac7afefb..4e9f91f0 100644
--- a/src/box/vinyl.h
+++ b/src/box/vinyl.h
@@ -58,6 +58,12 @@ void
 vinyl_engine_set_cache(struct vinyl_engine *vinyl, size_t quota);
 
 /**
+ * Update vinyl memory size.
+ */
+int
+vinyl_engine_set_memory(struct vinyl_engine *vinyl, size_t size);
+
+/**
  * Update max tuple size.
  */
 void
@@ -93,6 +99,13 @@ vinyl_engine_new_xc(const char *dir, size_t memory,
 	return vinyl;
 }
 
+static inline void
+vinyl_engine_set_memory_xc(struct vinyl_engine *vinyl, size_t size)
+{
+	if (vinyl_engine_set_memory(vinyl, size) != 0)
+		diag_raise();
+}
+
 #endif /* defined(__plusplus) */
 
 #endif /* INCLUDES_TARANTOOL_BOX_VINYL_H */
diff --git a/src/box/vy_quota.h b/src/box/vy_quota.h
index 89f88bdc..4788b0c9 100644
--- a/src/box/vy_quota.h
+++ b/src/box/vy_quota.h
@@ -110,6 +110,7 @@ vy_quota_set_limit(struct vy_quota *q, size_t limit)
 	q->limit = q->watermark = limit;
 	if (q->used >= limit)
 		q->quota_exceeded_cb(q);
+	fiber_cond_broadcast(&q->cond);
 }
 
 /**
diff --git a/test/box/lua/cfg_memory.lua b/test/box/lua/cfg_memory.lua
new file mode 100644
index 00000000..e3e89393
--- /dev/null
+++ b/test/box/lua/cfg_memory.lua
@@ -0,0 +1,9 @@
+#!/usr/bin/env tarantool
+
+local LIMIT = tonumber(arg[1])
+
+box.cfg{
+    memtx_memory = LIMIT,
+}
+
+require('console').listen(os.getenv('ADMIN'))
diff --git a/test/box/reconfigure.result b/test/box/reconfigure.result
index ad054db7..a70db07d 100644
--- a/test/box/reconfigure.result
+++ b/test/box/reconfigure.result
@@ -1,3 +1,6 @@
+test_run = require('test_run').new()
+---
+...
 too_long_threshold_default = box.cfg.too_long_threshold
 ---
 ...
@@ -95,7 +98,8 @@ box.cfg{log="new logger"}
 -- bad1
 box.cfg{memtx_memory=53687091}
 ---
-- error: Can't set option 'memtx_memory' dynamically
+- error: 'Incorrect value for option ''memtx_memory'': cannot decrease memory size
+    at runtime'
 ...
 box.cfg.memtx_memory
 ---
@@ -125,3 +129,77 @@ box.cfg { too_long_threshold = too_long_threshold_default }
 box.cfg { io_collect_interval = io_collect_interval_default }
 ---
 ...
+--
+-- gh-2634: check that box.cfg.memtx_memory can be increased
+--
+test_run:cmd("create server test with script='box/lua/cfg_memory.lua'")
+---
+- true
+...
+test_run:cmd(string.format("start server test with args='%d'", 64 * 1024 * 1024))
+---
+- true
+...
+test_run:cmd("switch test")
+---
+- true
+...
+box.slab.info().quota_size
+---
+- 67108864
+...
+s = box.schema.space.create('test')
+---
+...
+_ = s:create_index('pk')
+---
+...
+pad = string.rep('x', 100 * 1024)
+---
+...
+for i = 1, 1000 do s:replace{i, pad} end -- error: not enough memory
+---
+- error: Failed to allocate 102425 bytes in slab allocator for memtx_tuple
+...
+s:count() < 1000
+---
+- true
+...
+box.cfg{memtx_memory = 256 * 1024 * 1024}
+---
+...
+box.slab.info().quota_size
+---
+- 268435456
+...
+for i = 1, 1000 do s:replace{i, pad} end -- ok
+---
+...
+s:count() == 1000
+---
+- true
+...
+s:drop()
+---
+...
+box.cfg{memtx_memory = 64 * 1024 * 1024} -- error: decreasing memtx_memory is not allowed
+---
+- error: 'Incorrect value for option ''memtx_memory'': cannot decrease memory size
+    at runtime'
+...
+box.slab.info().quota_size
+---
+- 268435456
+...
+test_run:cmd("switch default")
+---
+- true
+...
+test_run:cmd("stop server test")
+---
+- true
+...
+test_run:cmd("cleanup server test")
+---
+- true
+...
diff --git a/test/box/reconfigure.test.lua b/test/box/reconfigure.test.lua
index 1af99f6b..f8619296 100644
--- a/test/box/reconfigure.test.lua
+++ b/test/box/reconfigure.test.lua
@@ -1,3 +1,5 @@
+test_run = require('test_run').new()
+
 too_long_threshold_default = box.cfg.too_long_threshold
 io_collect_interval_default = box.cfg.io_collect_interval
 
@@ -49,3 +51,32 @@ box.cfg.io_collect_interval = nil
 
 box.cfg { too_long_threshold = too_long_threshold_default }
 box.cfg { io_collect_interval = io_collect_interval_default }
+
+--
+-- gh-2634: check that box.cfg.memtx_memory can be increased
+--
+test_run:cmd("create server test with script='box/lua/cfg_memory.lua'")
+test_run:cmd(string.format("start server test with args='%d'", 64 * 1024 * 1024))
+test_run:cmd("switch test")
+
+box.slab.info().quota_size
+
+s = box.schema.space.create('test')
+_ = s:create_index('pk')
+pad = string.rep('x', 100 * 1024)
+for i = 1, 1000 do s:replace{i, pad} end -- error: not enough memory
+s:count() < 1000
+
+box.cfg{memtx_memory = 256 * 1024 * 1024}
+box.slab.info().quota_size
+
+for i = 1, 1000 do s:replace{i, pad} end -- ok
+s:count() == 1000
+s:drop()
+
+box.cfg{memtx_memory = 64 * 1024 * 1024} -- error: decreasing memtx_memory is not allowed
+box.slab.info().quota_size
+
+test_run:cmd("switch default")
+test_run:cmd("stop server test")
+test_run:cmd("cleanup server test")
diff --git a/test/vinyl/quota.result b/test/vinyl/quota.result
index 1fa773dd..d4b44c72 100644
--- a/test/vinyl/quota.result
+++ b/test/vinyl/quota.result
@@ -94,3 +94,80 @@ box.info.vinyl().quota.used
 space:drop()
 ---
 ...
+--
+-- gh-2634: check that box.cfg.vinyl_memory can be increased
+--
+test_run:cmd("create server test with script='vinyl/low_quota.lua'")
+---
+- true
+...
+test_run:cmd(string.format("start server test with args='%d'", 1024 * 1024))
+---
+- true
+...
+test_run:cmd('switch test')
+---
+- true
+...
+s = box.schema.space.create('test', {engine = 'vinyl'})
+---
+...
+_ = s:create_index('pk')
+---
+...
+count = 20
+---
+...
+pad = string.rep('x', 100 * 1024)
+---
+...
+box.info.vinyl().quota.limit
+---
+- 1048576
+...
+for i = 1, count do s:replace{i, pad} end -- triggers dump
+---
+...
+box.info.vinyl().quota.used < count * pad:len()
+---
+- true
+...
+box.snapshot()
+---
+- ok
+...
+box.cfg{vinyl_memory = 16 * 1024 * 1024}
+---
+...
+box.info.vinyl().quota.limit
+---
+- 16777216
+...
+for i = 1, count do s:replace{i, pad} end -- does not trigger dump
+---
+...
+box.info.vinyl().quota.used > count * pad:len()
+---
+- true
+...
+box.cfg{vinyl_memory = 8 * 1024 * 1024} -- error: decreasing vinyl_memory is not allowed
+---
+- error: 'Incorrect value for option ''vinyl_memory'': cannot decrease memory size
+    at runtime'
+...
+box.info.vinyl().quota.limit
+---
+- 16777216
+...
+test_run:cmd('switch default')
+---
+- true
+...
+test_run:cmd("stop server test")
+---
+- true
+...
+test_run:cmd("cleanup server test")
+---
+- true
+...
diff --git a/test/vinyl/quota.test.lua b/test/vinyl/quota.test.lua
index c4cea8fb..b9d21eb7 100644
--- a/test/vinyl/quota.test.lua
+++ b/test/vinyl/quota.test.lua
@@ -49,3 +49,36 @@ _ = space:replace{1, 1, string.rep('a', 1024 * 1024 * 5)}
 box.info.vinyl().quota.used
 
 space:drop()
+
+--
+-- gh-2634: check that box.cfg.vinyl_memory can be increased
+--
+test_run:cmd("create server test with script='vinyl/low_quota.lua'")
+test_run:cmd(string.format("start server test with args='%d'", 1024 * 1024))
+test_run:cmd('switch test')
+
+s = box.schema.space.create('test', {engine = 'vinyl'})
+_ = s:create_index('pk')
+
+count = 20
+pad = string.rep('x', 100 * 1024)
+
+box.info.vinyl().quota.limit
+
+for i = 1, count do s:replace{i, pad} end -- triggers dump
+box.info.vinyl().quota.used < count * pad:len()
+
+box.snapshot()
+
+box.cfg{vinyl_memory = 16 * 1024 * 1024}
+box.info.vinyl().quota.limit
+
+for i = 1, count do s:replace{i, pad} end -- does not trigger dump
+box.info.vinyl().quota.used > count * pad:len()
+
+box.cfg{vinyl_memory = 8 * 1024 * 1024} -- error: decreasing vinyl_memory is not allowed
+box.info.vinyl().quota.limit
+
+test_run:cmd('switch default')
+test_run:cmd("stop server test")
+test_run:cmd("cleanup server test")
diff --git a/test/vinyl/quota_timeout.result b/test/vinyl/quota_timeout.result
index e4bced02..e977fb52 100644
--- a/test/vinyl/quota_timeout.result
+++ b/test/vinyl/quota_timeout.result
@@ -65,6 +65,29 @@ box.info.vinyl().quota.used
 ---
 - 748241
 ...
+--
+-- Check that increasing box.cfg.vinyl_memory wakes up fibers
+-- waiting for memory.
+--
+box.cfg{vinyl_timeout=5}
+---
+...
+c = fiber.channel(1)
+---
+...
+_ = fiber.create(function() local ok = pcall(s.auto_increment, s, {pad}) c:put(ok) end)
+---
+...
+fiber.sleep(0.01)
+---
+...
+box.cfg{vinyl_memory = 3 * box.cfg.vinyl_memory / 2}
+---
+...
+c:get(1)
+---
+- true
+...
 box.error.injection.set('ERRINJ_VY_RUN_WRITE', false)
 ---
 - ok
@@ -86,6 +109,9 @@ box.cfg{vinyl_timeout=60}
 box.cfg{too_long_threshold=0.01}
 ---
 ...
+pad = string.rep('x', 2 * box.cfg.vinyl_memory / 3)
+---
+...
 _ = s:auto_increment{pad}
 ---
 ...
@@ -98,7 +124,7 @@ test_run:cmd("push filter '[0-9.]+ sec' to '<sec> sec'")
 ...
 test_run:grep_log('test', 'waited for .* quota for too long.*')
 ---
-- 'waited for 699089 bytes of vinyl memory quota for too long: <sec> sec'
+- 'waited for 1048615 bytes of vinyl memory quota for too long: <sec> sec'
 ...
 test_run:cmd("clear filter")
 ---
@@ -134,7 +160,7 @@ pad = string.rep('x', box.cfg.vinyl_memory)
 ...
 _ = s:auto_increment{pad}
 ---
-- error: Failed to allocate 1048615 bytes in lsregion for vinyl transaction
+- error: Failed to allocate 1572903 bytes in lsregion for vinyl transaction
 ...
 s:drop()
 ---
diff --git a/test/vinyl/quota_timeout.test.lua b/test/vinyl/quota_timeout.test.lua
index c3d17b44..6ea6d677 100644
--- a/test/vinyl/quota_timeout.test.lua
+++ b/test/vinyl/quota_timeout.test.lua
@@ -29,6 +29,17 @@ _ = s:auto_increment{pad}
 s:count()
 box.info.vinyl().quota.used
 
+--
+-- Check that increasing box.cfg.vinyl_memory wakes up fibers
+-- waiting for memory.
+--
+box.cfg{vinyl_timeout=5}
+c = fiber.channel(1)
+_ = fiber.create(function() local ok = pcall(s.auto_increment, s, {pad}) c:put(ok) end)
+fiber.sleep(0.01)
+box.cfg{vinyl_memory = 3 * box.cfg.vinyl_memory / 2}
+c:get(1)
+
 box.error.injection.set('ERRINJ_VY_RUN_WRITE', false)
 fiber.sleep(0.01) -- wait for scheduler to unthrottle
 
@@ -41,6 +52,7 @@ box.error.injection.set('ERRINJ_VY_RUN_WRITE_TIMEOUT', 0.01)
 box.cfg{vinyl_timeout=60}
 box.cfg{too_long_threshold=0.01}
 
+pad = string.rep('x', 2 * box.cfg.vinyl_memory / 3)
 _ = s:auto_increment{pad}
 _ = s:auto_increment{pad}
 
-- 
2.11.0

             reply	other threads:[~2018-05-30 12:55 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-30 12:55 Vladimir Davydov [this message]
2018-05-30 15:41 ` Konstantin Osipov
2018-05-30 16:08   ` Vladimir Davydov
2018-05-30 16:43     ` [PATCH v2] " Vladimir Davydov
2018-05-30 17:23       ` Konstantin Osipov
2018-06-01 18:48       ` Konstantin Osipov

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=5c833e39a3337fdf832ebd745ad89d901cf4c92e.1527684463.git.vdavydov.dev@gmail.com \
    --to=vdavydov.dev@gmail.com \
    --cc=kostja@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --subject='Re: [PATCH] Allow to increase box.cfg.vinyl_memory and memtx_memory at runtime' \
    /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