Tarantool development patches archive
 help / color / mirror / Atom feed
* [PATCH] Allow to increase box.cfg.vinyl_memory and memtx_memory at runtime
@ 2018-05-30 12:55 Vladimir Davydov
  2018-05-30 15:41 ` Konstantin Osipov
  0 siblings, 1 reply; 6+ messages in thread
From: Vladimir Davydov @ 2018-05-30 12:55 UTC (permalink / raw)
  To: kostja; +Cc: tarantool-patches

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-06-01 18:48 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-30 12:55 [PATCH] Allow to increase box.cfg.vinyl_memory and memtx_memory at runtime Vladimir Davydov
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

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