[PATCH 1/3] vinyl: allow to resize cache online

Vladimir Davydov vdavydov.dev at gmail.com
Mon Feb 26 20:47:10 MSK 2018


Make box.cfg.vinyl_cache option dynamically configured. If the new
value is less than the current cache usage, it will block until it
reclaims enough cache entries to fit in the new limit.
---
 src/box/box.cc                  | 11 +++++++++-
 src/box/box.h                   |  1 +
 src/box/lua/cfg.cc              | 12 +++++++++++
 src/box/lua/load_cfg.lua        |  1 +
 src/box/vinyl.c                 | 14 +++++++++----
 src/box/vinyl.h                 | 12 ++++++++---
 src/box/vy_cache.c              | 16 ++++++++++++---
 src/box/vy_cache.h              | 15 +++++++++++---
 test/unit/vy_iterators_helper.c |  3 ++-
 test/unit/vy_point_lookup.c     |  3 ++-
 test/vinyl/cache.result         | 45 +++++++++++++++++++++++++++++++++++++++++
 test/vinyl/cache.test.lua       | 17 ++++++++++++++++
 12 files changed, 134 insertions(+), 16 deletions(-)

diff --git a/src/box/box.cc b/src/box/box.cc
index 32b08e36..cf7b7ea2 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -742,6 +742,15 @@ box_set_vinyl_max_tuple_size(void)
 }
 
 void
+box_set_vinyl_cache(void)
+{
+	struct vinyl_engine *vinyl;
+	vinyl = (struct vinyl_engine *)engine_by_name("vinyl");
+	assert(vinyl != NULL);
+	vinyl_engine_set_cache(vinyl, cfg_geti("vinyl_cache"));
+}
+
+void
 box_set_vinyl_timeout(void)
 {
 	struct vinyl_engine *vinyl;
@@ -1539,12 +1548,12 @@ engine_init()
 	struct vinyl_engine *vinyl;
 	vinyl = vinyl_engine_new_xc(cfg_gets("vinyl_dir"),
 				    cfg_geti64("vinyl_memory"),
-				    cfg_geti64("vinyl_cache"),
 				    cfg_geti("vinyl_read_threads"),
 				    cfg_geti("vinyl_write_threads"),
 				    cfg_geti("force_recovery"));
 	engine_register((struct engine *)vinyl);
 	box_set_vinyl_max_tuple_size();
+	box_set_vinyl_cache();
 	box_set_vinyl_timeout();
 }
 
diff --git a/src/box/box.h b/src/box/box.h
index 5c87da9d..baddcf73 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -171,6 +171,7 @@ void box_set_readahead(void);
 void box_set_checkpoint_count(void);
 void box_set_memtx_max_tuple_size(void);
 void box_set_vinyl_max_tuple_size(void);
+void box_set_vinyl_cache(void);
 void box_set_vinyl_timeout(void);
 void box_set_replication_timeout(void);
 void box_set_replication_connect_quorum(void);
diff --git a/src/box/lua/cfg.cc b/src/box/lua/cfg.cc
index be7c4692..5e88ca34 100644
--- a/src/box/lua/cfg.cc
+++ b/src/box/lua/cfg.cc
@@ -199,6 +199,17 @@ lbox_cfg_set_vinyl_max_tuple_size(struct lua_State *L)
 }
 
 static int
+lbox_cfg_set_vinyl_cache(struct lua_State *L)
+{
+	try {
+		box_set_vinyl_cache();
+	} catch (Exception *) {
+		luaT_error(L);
+	}
+	return 0;
+}
+
+static int
 lbox_cfg_set_vinyl_timeout(struct lua_State *L)
 {
 	try {
@@ -259,6 +270,7 @@ box_lua_cfg_init(struct lua_State *L)
 		{"cfg_set_read_only", lbox_cfg_set_read_only},
 		{"cfg_set_memtx_max_tuple_size", lbox_cfg_set_memtx_max_tuple_size},
 		{"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},
 		{"cfg_set_replication_timeout", lbox_cfg_set_replication_timeout},
 		{"cfg_set_replication_connect_quorum",
diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua
index 891d819d..d4f2128d 100644
--- a/src/box/lua/load_cfg.lua
+++ b/src/box/lua/load_cfg.lua
@@ -170,6 +170,7 @@ local dynamic_cfg = {
     read_only               = private.cfg_set_read_only,
     memtx_max_tuple_size    = private.cfg_set_memtx_max_tuple_size,
     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,
     checkpoint_count        = private.cfg_set_checkpoint_count,
     checkpoint_interval     = private.checkpoint_daemon.set_checkpoint_interval,
diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index df518fcc..03a54670 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -2625,7 +2625,7 @@ vy_squash_schedule(struct vy_index *index, struct tuple *stmt,
 		   void /* struct vy_env */ *arg);
 
 static struct vy_env *
-vy_env_new(const char *path, size_t memory, size_t cache,
+vy_env_new(const char *path, size_t memory,
 	   int read_threads, int write_threads, bool force_recovery)
 {
 	enum { KB = 1000, MB = 1000 * 1000 };
@@ -2700,7 +2700,7 @@ vy_env_new(const char *path, size_t memory, size_t cache,
 		      VY_QUOTA_UPDATE_INTERVAL);
 	e->quota_timer.data = e;
 	ev_timer_start(loop(), &e->quota_timer);
-	vy_cache_env_create(&e->cache_env, slab_cache, cache);
+	vy_cache_env_create(&e->cache_env, slab_cache);
 	vy_run_env_create(&e->run_env);
 	vy_log_init(e->path);
 	return e;
@@ -2742,7 +2742,7 @@ vy_env_delete(struct vy_env *e)
 }
 
 struct vinyl_engine *
-vinyl_engine_new(const char *dir, size_t memory, size_t cache,
+vinyl_engine_new(const char *dir, size_t memory,
 		 int read_threads, int write_threads, bool force_recovery)
 {
 	struct vinyl_engine *vinyl = calloc(1, sizeof(*vinyl));
@@ -2752,7 +2752,7 @@ vinyl_engine_new(const char *dir, size_t memory, size_t cache,
 		return NULL;
 	}
 
-	vinyl->env = vy_env_new(dir, memory, cache, read_threads,
+	vinyl->env = vy_env_new(dir, memory, read_threads,
 				write_threads, force_recovery);
 	if (vinyl->env == NULL) {
 		free(vinyl);
@@ -2773,6 +2773,12 @@ vinyl_engine_shutdown(struct engine *engine)
 }
 
 void
+vinyl_engine_set_cache(struct vinyl_engine *vinyl, size_t quota)
+{
+	vy_cache_env_set_quota(&vinyl->env->cache_env, quota);
+}
+
+void
 vinyl_engine_set_max_tuple_size(struct vinyl_engine *vinyl, size_t max_size)
 {
 	(void)vinyl;
diff --git a/src/box/vinyl.h b/src/box/vinyl.h
index 63add146..ac7afefb 100644
--- a/src/box/vinyl.h
+++ b/src/box/vinyl.h
@@ -42,7 +42,7 @@ struct info_handler;
 struct vinyl_engine;
 
 struct vinyl_engine *
-vinyl_engine_new(const char *dir, size_t memory, size_t cache,
+vinyl_engine_new(const char *dir, size_t memory,
 		 int read_threads, int write_threads, bool force_recovery);
 
 /**
@@ -52,6 +52,12 @@ void
 vinyl_engine_info(struct vinyl_engine *vinyl, struct info_handler *handler);
 
 /**
+ * Update vinyl cache size.
+ */
+void
+vinyl_engine_set_cache(struct vinyl_engine *vinyl, size_t quota);
+
+/**
  * Update max tuple size.
  */
 void
@@ -76,11 +82,11 @@ vinyl_engine_set_too_long_threshold(struct vinyl_engine *vinyl,
 #include "diag.h"
 
 static inline struct vinyl_engine *
-vinyl_engine_new_xc(const char *dir, size_t memory, size_t cache,
+vinyl_engine_new_xc(const char *dir, size_t memory,
 		    int read_threads, int write_threads, bool force_recovery)
 {
 	struct vinyl_engine *vinyl;
-	vinyl = vinyl_engine_new(dir, memory, cache, read_threads,
+	vinyl = vinyl_engine_new(dir, memory, read_threads,
 				 write_threads, force_recovery);
 	if (vinyl == NULL)
 		diag_raise();
diff --git a/src/box/vy_cache.c b/src/box/vy_cache.c
index 6bededc1..8a6c53f7 100644
--- a/src/box/vy_cache.c
+++ b/src/box/vy_cache.c
@@ -30,6 +30,7 @@
  */
 #include "vy_cache.h"
 #include "diag.h"
+#include "fiber.h"
 #include "schema_def.h"
 
 #ifndef CT_ASSERT_G
@@ -51,12 +52,11 @@ enum {
 };
 
 void
-vy_cache_env_create(struct vy_cache_env *e, struct slab_cache *slab_cache,
-		    size_t mem_quota)
+vy_cache_env_create(struct vy_cache_env *e, struct slab_cache *slab_cache)
 {
 	rlist_create(&e->cache_lru);
 	e->mem_used = 0;
-	e->mem_quota = mem_quota;
+	e->mem_quota = 0;
 	mempool_create(&e->cache_entry_mempool, slab_cache,
 		       sizeof(struct vy_cache_entry));
 }
@@ -203,6 +203,16 @@ vy_cache_gc(struct vy_cache_env *env)
 }
 
 void
+vy_cache_env_set_quota(struct vy_cache_env *env, size_t quota)
+{
+	env->mem_quota = quota;
+	while (env->mem_used > env->mem_quota) {
+		vy_cache_gc(env);
+		fiber_sleep(0);
+	}
+}
+
+void
 vy_cache_add(struct vy_cache *cache, struct tuple *stmt,
 	     struct tuple *prev_stmt, const struct tuple *key,
 	     enum iterator_type order)
diff --git a/src/box/vy_cache.h b/src/box/vy_cache.h
index d4e213db..fceda5a2 100644
--- a/src/box/vy_cache.h
+++ b/src/box/vy_cache.h
@@ -127,11 +127,9 @@ struct vy_cache_env {
  * Initialize common cache environment.
  * @param e - the environment.
  * @param slab_cache - source of memory.
- * @param mem_quota - memory limit for the cache.
  */
 void
-vy_cache_env_create(struct vy_cache_env *env, struct slab_cache *slab_cache,
-		    size_t mem_quota);
+vy_cache_env_create(struct vy_cache_env *env, struct slab_cache *slab_cache);
 
 /**
  * Destroy and free resources of cache environment.
@@ -141,6 +139,17 @@ void
 vy_cache_env_destroy(struct vy_cache_env *e);
 
 /**
+ * Set memory limit for the cache.
+ * @param e - the environment.
+ * @param quota - memory limit for the cache.
+ *
+ * This function blocks until it manages to free enough memory
+ * to fit in the new limit.
+ */
+void
+vy_cache_env_set_quota(struct vy_cache_env *e, size_t quota);
+
+/**
  * Tuple cache (of one particular index)
  */
 struct vy_cache {
diff --git a/test/unit/vy_iterators_helper.c b/test/unit/vy_iterators_helper.c
index a35f4ef9..0e41de4b 100644
--- a/test/unit/vy_iterators_helper.c
+++ b/test/unit/vy_iterators_helper.c
@@ -19,7 +19,8 @@ vy_iterator_C_test_init(size_t cache_size)
 	memory_init();
 	fiber_init(fiber_c_invoke);
 	tuple_init(NULL);
-	vy_cache_env_create(&cache_env, cord_slab_cache(), cache_size);
+	vy_cache_env_create(&cache_env, cord_slab_cache());
+	vy_cache_env_set_quota(&cache_env, cache_size);
 	vy_key_format = tuple_format_new(&vy_tuple_format_vtab, NULL, 0, 0,
 					 NULL, 0, NULL);
 	tuple_format_ref(vy_key_format);
diff --git a/test/unit/vy_point_lookup.c b/test/unit/vy_point_lookup.c
index d360b3b4..8217db39 100644
--- a/test/unit/vy_point_lookup.c
+++ b/test/unit/vy_point_lookup.c
@@ -36,7 +36,8 @@ test_basic()
 	vy_run_env_create(&run_env);
 
 	struct vy_cache_env cache_env;
-	vy_cache_env_create(&cache_env, slab_cache, QUOTA);
+	vy_cache_env_create(&cache_env, slab_cache);
+	vy_cache_env_set_quota(&cache_env, QUOTA);
 
 	struct vy_cache cache;
 	uint32_t fields[] = { 0 };
diff --git a/test/vinyl/cache.result b/test/vinyl/cache.result
index 117eff05..3ed4d0f9 100644
--- a/test/vinyl/cache.result
+++ b/test/vinyl/cache.result
@@ -1012,3 +1012,48 @@ pk:info().disk.iterator.lookup
 s:drop()
 ---
 ...
+--
+-- Cache resize
+--
+vinyl_cache = box.cfg.vinyl_cache
+---
+...
+box.cfg{vinyl_cache = 1000 * 1000}
+---
+...
+s = box.schema.space.create('test', {engine = 'vinyl'})
+---
+...
+_ = s:create_index('pk')
+---
+...
+for i = 1, 100 do s:replace{i, string.rep('x', 1000)} end
+---
+...
+for i = 1, 100 do s:get{i} end
+---
+...
+box.info.vinyl().cache.used
+---
+- 107700
+...
+box.cfg{vinyl_cache = 50 * 1000}
+---
+...
+box.info.vinyl().cache.used
+---
+- 49542
+...
+box.cfg{vinyl_cache = 0}
+---
+...
+box.info.vinyl().cache.used
+---
+- 0
+...
+s:drop()
+---
+...
+box.cfg{vinyl_cache = vinyl_cache}
+---
+...
diff --git a/test/vinyl/cache.test.lua b/test/vinyl/cache.test.lua
index 9478a442..40d55abf 100644
--- a/test/vinyl/cache.test.lua
+++ b/test/vinyl/cache.test.lua
@@ -358,3 +358,20 @@ info.lookup
 info.get.rows
 pk:info().disk.iterator.lookup
 s:drop()
+
+--
+-- Cache resize
+--
+vinyl_cache = box.cfg.vinyl_cache
+box.cfg{vinyl_cache = 1000 * 1000}
+s = box.schema.space.create('test', {engine = 'vinyl'})
+_ = s:create_index('pk')
+for i = 1, 100 do s:replace{i, string.rep('x', 1000)} end
+for i = 1, 100 do s:get{i} end
+box.info.vinyl().cache.used
+box.cfg{vinyl_cache = 50 * 1000}
+box.info.vinyl().cache.used
+box.cfg{vinyl_cache = 0}
+box.info.vinyl().cache.used
+s:drop()
+box.cfg{vinyl_cache = vinyl_cache}
-- 
2.11.0




More information about the Tarantool-patches mailing list