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
Changes in v2:
- Tune the tests to make them less cpu intensive.
- Use wal_mode=none in memtx test to speed it up.
- Add a test case checking that setting the limit to
the same value works.
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/cfg.result | 6 +++
test/box/cfg.test.lua | 3 ++
test/box/lua/cfg_memory.lua | 10 +++++
test/box/reconfigure.result | 83 ++++++++++++++++++++++++++++++++++++++-
test/box/reconfigure.test.lua | 32 +++++++++++++++
test/vinyl/quota.result | 77 ++++++++++++++++++++++++++++++++++++
test/vinyl/quota.test.lua | 33 ++++++++++++++++
test/vinyl/quota_timeout.result | 30 +++++++++++++-
test/vinyl/quota_timeout.test.lua | 12 ++++++
18 files changed, 379 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/cfg.result b/test/box/cfg.result
index 66080795..ff208f9c 100644
--- a/test/box/cfg.result
+++ b/test/box/cfg.result
@@ -260,6 +260,12 @@ box.cfg{replicaset_uuid =
'12345678-0123-5678-1234-abcdefabcdef'}
---
- error: Can't set option 'replicaset_uuid' dynamically
...
+box.cfg{memtx_memory = box.cfg.memtx_memory}
+---
+...
+box.cfg{vinyl_memory = box.cfg.vinyl_memory}
+---
+...
--------------------------------------------------------------------------------
-- Test of default cfg options
--------------------------------------------------------------------------------
diff --git a/test/box/cfg.test.lua b/test/box/cfg.test.lua
index 52808960..8bed7083 100644
--- a/test/box/cfg.test.lua
+++ b/test/box/cfg.test.lua
@@ -33,6 +33,9 @@ box.cfg{instance_uuid =
'12345678-0123-5678-1234-abcdefabcdef'}
box.cfg{replicaset_uuid = box.info.cluster.uuid}
box.cfg{replicaset_uuid = '12345678-0123-5678-1234-abcdefabcdef'}
+box.cfg{memtx_memory = box.cfg.memtx_memory}
+box.cfg{vinyl_memory = box.cfg.vinyl_memory}
+
--------------------------------------------------------------------------------
-- Test of default cfg options
--------------------------------------------------------------------------------
diff --git a/test/box/lua/cfg_memory.lua b/test/box/lua/cfg_memory.lua
new file mode 100644
index 00000000..816b8342
--- /dev/null
+++ b/test/box/lua/cfg_memory.lua
@@ -0,0 +1,10 @@
+#!/usr/bin/env tarantool
+
+local LIMIT = tonumber(arg[1])
+
+box.cfg{
+ wal_mode = 'none',
+ memtx_memory = LIMIT,
+}
+
+require('console').listen(os.getenv('ADMIN'))
diff --git a/test/box/reconfigure.result b/test/box/reconfigure.result
index ad054db7..9ed1864e 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,80 @@ 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'", 48 * 1024 *
1024))
+---
+- true
+...
+test_run:cmd("switch test")
+---
+- true
+...
+box.slab.info().quota_size
+---
+- 50331648
+...
+s = box.schema.space.create('test')
+---
+...
+_ = s:create_index('pk')
+---
+...
+count = 200
+---
+...
+pad = string.rep('x', 100 * 1024)
+---
+...
+for i = 1, count do s:replace{i, pad} end -- error: not enough memory
+---
+- error: Failed to allocate 102424 bytes in slab allocator for memtx_tuple
+...
+s:count() < count
+---
+- true
+...
+box.cfg{memtx_memory = 64 * 1024 * 1024}
+---
+...
+box.slab.info().quota_size
+---
+- 67108864
+...
+for i = s:count() + 1, count do s:replace{i, pad} end -- ok
+---
+...
+s:count() == count
+---
+- true
+...
+s:drop()
+---
+...
+box.cfg{memtx_memory = 48 * 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
+---
+- 67108864
+...
+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..4db29eef 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,33 @@ 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'", 48 * 1024 *
1024))
+test_run:cmd("switch test")
+
+box.slab.info().quota_size
+
+s = box.schema.space.create('test')
+_ = s:create_index('pk')
+count = 200
+pad = string.rep('x', 100 * 1024)
+for i = 1, count do s:replace{i, pad} end -- error: not enough memory
+s:count() < count
+
+box.cfg{memtx_memory = 64 * 1024 * 1024}
+box.slab.info().quota_size
+
+for i = s:count() + 1, count do s:replace{i, pad} end -- ok
+s:count() == count
+s:drop()
+
+box.cfg{memtx_memory = 48 * 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..359efe8b 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 = 8 * 1024 * 1024}
+---
+...
+box.info.vinyl().quota.limit
+---
+- 8388608
+...
+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 = 4 * 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
+---
+- 8388608
+...
+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..7f7b4ec3 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 = 8 * 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 = 4 * 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