diff --git a/changelogs/unreleased/gh-8485-vy-tuple-stat.md b/changelogs/unreleased/gh-8485-vy-tuple-stat.md new file mode 100644 index 0000000000000000000000000000000000000000..eeaff6c89a28786358dbf1d4ca02f3c7af307b62 --- /dev/null +++ b/changelogs/unreleased/gh-8485-vy-tuple-stat.md @@ -0,0 +1,5 @@ +## feature/vinyl + +* Introduced the `memory.tuple` statistic for `box.stat.vinyl()` that shows + the total size of memory occupied by all tuples allocated by the Vinyl engine + (gh-8485). diff --git a/src/box/vinyl.c b/src/box/vinyl.c index 2cb41a222d8d5e87b8bc93e393f57ea9e6253e46..fc3201042d3a94c26b01f4f1910bdc7b3a9295c4 100644 --- a/src/box/vinyl.c +++ b/src/box/vinyl.c @@ -296,6 +296,7 @@ vy_info_append_memory(struct vy_env *env, struct info_handler *h) info_table_begin(h, "memory"); info_append_int(h, "tx", vy_tx_manager_mem_used(env->xm)); info_append_int(h, "level0", lsregion_used(&env->mem_env.allocator)); + info_append_int(h, "tuple", env->stmt_env.sum_tuple_size); info_append_int(h, "tuple_cache", env->cache_env.mem_used); info_append_int(h, "page_index", env->lsm_env.page_index_size); info_append_int(h, "bloom_filter", env->lsm_env.bloom_size); diff --git a/src/box/vy_stmt.c b/src/box/vy_stmt.c index 4105b82d0362bcb426ab26efe564cfbb2afcd5b5..a6659082b4c25eddbea2680a0d231d0a7c1f3e67 100644 --- a/src/box/vy_stmt.c +++ b/src/box/vy_stmt.c @@ -98,6 +98,8 @@ vy_tuple_new(struct tuple_format *format, const char *data, const char *end) static void vy_tuple_delete(struct tuple_format *format, struct tuple *tuple) { + struct vy_stmt_env *env = format->engine; + size_t size = tuple_size(tuple); say_debug("%s(%p)", __func__, tuple); assert(tuple_is_unreferenced(tuple)); /* @@ -105,10 +107,15 @@ vy_tuple_delete(struct tuple_format *format, struct tuple *tuple) * multithread unsafe modifications of a reference * counter. */ - if (cord_is_main()) + if (cord_is_main()) { + if (format != env->key_format) { + assert(env->sum_tuple_size >= size); + env->sum_tuple_size -= size; + } tuple_format_unref(format); + } #ifndef NDEBUG - memset(tuple, '#', tuple_size(tuple)); /* fail early */ + memset(tuple, '#', size); /* fail early */ #endif free(tuple); } @@ -119,6 +126,7 @@ vy_stmt_env_create(struct vy_stmt_env *env) env->tuple_format_vtab.tuple_new = vy_tuple_new; env->tuple_format_vtab.tuple_delete = vy_tuple_delete; env->max_tuple_size = 1024 * 1024; + env->sum_tuple_size = 0; env->key_format = vy_simple_stmt_format_new(env, NULL, 0); if (env->key_format == NULL) panic("failed to create vinyl key format"); @@ -185,8 +193,11 @@ vy_stmt_alloc(struct tuple_format *format, uint32_t data_offset, uint32_t bsize) format->id, data_offset, bsize, tuple); tuple_create(tuple, 1, tuple_format_id(format), data_offset, bsize, false); - if (cord_is_main()) + if (cord_is_main()) { + if (format != env->key_format) + env->sum_tuple_size += total_size; tuple_format_ref(format); + } vy_stmt_set_lsn(tuple, 0); vy_stmt_set_type(tuple, 0); vy_stmt_set_flags(tuple, 0); diff --git a/src/box/vy_stmt.h b/src/box/vy_stmt.h index 3938c5a2af7066da034f543e8343c4c461616c80..771f26bbce0496f27eee78182783fd836a8cede4 100644 --- a/src/box/vy_stmt.h +++ b/src/box/vy_stmt.h @@ -74,6 +74,13 @@ struct vy_stmt_env { * @see box.cfg.vinyl_max_tuple_size */ size_t max_tuple_size; + /** + * Size of memory occupied by all vinyl tuples allocated + * in the main thread. Note, this doesn't include keys, + * which should be fine because keys shouldn't stay in + * memory for long. + */ + size_t sum_tuple_size; /** * Tuple format used for creating key statements (e.g. * statements read from secondary index runs). It doesn't diff --git a/test/vinyl-luatest/gh_8485_tuple_stat_test.lua b/test/vinyl-luatest/gh_8485_tuple_stat_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..4df1b7a22c0248728d43468f73148d0efaf4dcc6 --- /dev/null +++ b/test/vinyl-luatest/gh_8485_tuple_stat_test.lua @@ -0,0 +1,61 @@ +local server = require('luatest.server') +local t = require('luatest') + +local g = t.group() + +g.before_all(function(cg) + cg.server = server:new() + cg.server:start() + cg.server:exec(function() + box.schema.create_space('test', {engine = 'vinyl'}) + box.space.test:create_index('primary', { + parts = {1, 'unsigned'}, + }) + box.space.test:create_index('secondary', { + parts = {2, 'string'}, unique = false, + }) + for i = 1, 10 do + box.space.test:insert({i, string.rep('x', 1000)}) + if i == 5 then + box.snapshot() + end + end + collectgarbage() + end) +end) + +g.after_all(function(cg) + cg.server:drop() +end) + +g.test_tuple_stat = function(cg) + cg.server:exec(function() + local function gc() + box.tuple.new() -- drop blessed tuple ref + collectgarbage() + end + -- Initial value is 0. + gc() + t.assert_equals(box.stat.vinyl().memory.tuple, 0) + + -- Tuples pinned by Lua. + box.cfg({vinyl_cache = 0}) + local ret = box.space.test:select() + t.assert_equals(#ret, 10) + t.assert_almost_equals(box.stat.vinyl().memory.tuple, 10 * 1000, 1000) + ret = nil -- luacheck: ignore + gc() + t.assert_equals(box.stat.vinyl().memory.tuple, 0) + + -- Tuples pinned by cache. + box.cfg({vinyl_cache = 100 * 1000}) + ret = box.space.test:select() + t.assert_equals(#ret, 10) + t.assert_almost_equals(box.stat.vinyl().memory.tuple, 10 * 1000, 1000) + ret = nil -- luacheck: ignore + gc() + t.assert_almost_equals(box.stat.vinyl().memory.tuple, 10 * 1000, 1000) + box.cfg({vinyl_cache = 0}) + t.assert_equals(box.stat.vinyl().memory.tuple, 0) + end) +end diff --git a/test/vinyl/stat.result b/test/vinyl/stat.result index c4dc9af394e672a988d6e521213ca4b62ae3198c..909b6039c07274a0d5e85b51c2d945f36c48baaf 100644 --- a/test/vinyl/stat.result +++ b/test/vinyl/stat.result @@ -256,8 +256,9 @@ gstat() tuple_cache: 0 tx: 0 level0: 0 - page_index: 0 bloom_filter: 0 + page_index: 0 + tuple: 0 disk: data_compacted: 0 data: 0 @@ -1007,6 +1008,13 @@ stat_diff(gstat(), st, 'tx') --- - commit: 1 ... +-- free tuples pinned by Lua +_ = nil +--- +... +_ = collectgarbage() +--- +... -- box.stat.reset box.stat.reset() --- @@ -1140,8 +1148,9 @@ gstat() tuple_cache: 14313 tx: 0 level0: 261562 - page_index: 1250 bloom_filter: 140 + page_index: 1250 + tuple: 13689 disk: data_compacted: 104299 data: 104299 diff --git a/test/vinyl/stat.test.lua b/test/vinyl/stat.test.lua index a8657ccf4998149d7a4a1305a6ee249b6f3a991b..83c595509cd63e50885848b722e2200908f4d2ac 100644 --- a/test/vinyl/stat.test.lua +++ b/test/vinyl/stat.test.lua @@ -323,6 +323,10 @@ stat_diff(gstat(), st, 'tx') box.commit() stat_diff(gstat(), st, 'tx') +-- free tuples pinned by Lua +_ = nil +_ = collectgarbage() + -- box.stat.reset box.stat.reset() istat()