Skip to content

Commit 45f9759

Browse files
Gumixalyapunov
authored andcommitted
box: introduce space:stat()
See the doc bot request for the description. Benchmark results: NO_WRAP $ taskset 0x2 compare.py benchmarks ./memtx.perftest.old ./memtx.perftest.new \ --benchmark_min_warmup_time=10 \ --benchmark_repetitions=30 \ --benchmark_report_aggregates_only=true \ --benchmark_filter=TreeReplaceRandomExistingKeys [...] Comparing ./memtx.perftest.old to ./memtx.perftest.new Benchmark Time CPU Time Old Time New CPU Old CPU New ------------------------------------------------------------------------------------------------------------------------------------------------ MemtxFixture/TreeReplaceRandomExistingKeys_mean +0.0097 +0.0097 1073 1084 1073 1084 MemtxFixture/TreeReplaceRandomExistingKeys_median +0.0075 +0.0075 1062 1070 1062 1070 MemtxFixture/TreeReplaceRandomExistingKeys_stddev -0.1207 -0.1208 56 49 56 49 MemtxFixture/TreeReplaceRandomExistingKeys_cv -0.1291 -0.1292 0 0 0 0 NO_WRAP Closes #6762 @TarantoolBot document Title: Document `space:stat()` Product: Tarantool Since: 3.0 Root document: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/ space_object:stat() - Get statistics on the memory usage Returns a table with the cumulative statistics on the memory usage by tuples in the space. The statistics is grouped by arena types: "memtx" or "malloc". For a detailed description of each field see `tuple_object:info()`. Note: The statistics is collected only for memtx storage engine. For other types of spaces, an empty table is returned. Example: ``` tarantool> box.space.test:stat() --- - tuple: memtx: data_size: 5100699 header_size: 96 field_map_size: 40 waste_size: 143093 malloc: data_size: 18850077 header_size: 70 field_map_size: 28 waste_size: 0 ... ```
1 parent ab24dfb commit 45f9759

File tree

9 files changed

+238
-33
lines changed

9 files changed

+238
-33
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
## feature/core
2+
3+
* Introduced new methods `tuple:info()` and `space:stat()` with the detailed
4+
information on memory consumed by data (gh-6762).

src/box/lua/schema.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2709,6 +2709,7 @@ space_mt.run_triggers = function(space, yesno)
27092709
builtin.space_run_triggers(s, yesno)
27102710
end
27112711
space_mt.frommap = box.internal.space.frommap
2712+
space_mt.stat = box.internal.space.stat
27122713
space_mt.__index = space_mt
27132714

27142715
box.schema.index_mt = base_index_mt

src/box/lua/space.cc

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ extern "C" {
4747
#include "box/func.h"
4848
#include "box/func_def.h"
4949
#include "box/space.h"
50+
#include "box/memtx_space.h"
5051
#include "box/schema.h"
5152
#include "box/user_def.h"
5253
#include "box/tuple.h"
@@ -746,6 +747,59 @@ lbox_space_frommap(struct lua_State *L)
746747
return luaL_error(L, "Usage: space:frommap(map, opts)");
747748
}
748749

750+
/**
751+
* Push to Lua stack a table with the statistics on the memory usage by tuples
752+
* of the space.
753+
*/
754+
static int
755+
lbox_space_stat(struct lua_State *L)
756+
{
757+
int argc = lua_gettop(L);
758+
if (argc != 1 || !lua_istable(L, 1))
759+
luaL_error(L, "Usage: space:stat()");
760+
761+
lua_getfield(L, 1, "id");
762+
uint32_t id = (int)lua_tointeger(L, -1);
763+
struct space *space = space_by_id(id);
764+
if (space == NULL) {
765+
lua_pushnil(L);
766+
lua_pushfstring(L, "Space with id '%d' doesn't exist", id);
767+
return 2;
768+
}
769+
770+
if (!space_is_memtx(space)) {
771+
lua_newtable(L);
772+
return 1;
773+
}
774+
struct memtx_space *memtx_space = (struct memtx_space *)space;
775+
776+
lua_newtable(L); /* Result table. */
777+
lua_newtable(L); /* result.tuple */
778+
779+
for (int i = TUPLE_ARENA_MEMTX; i <= TUPLE_ARENA_MALLOC; i++) {
780+
enum tuple_arena_type type = (enum tuple_arena_type)i;
781+
struct tuple_info *stat = &memtx_space->tuple_stat[type];
782+
lua_newtable(L);
783+
784+
lua_pushnumber(L, stat->data_size);
785+
lua_setfield(L, -2, "data_size");
786+
787+
lua_pushnumber(L, stat->header_size);
788+
lua_setfield(L, -2, "header_size");
789+
790+
lua_pushnumber(L, stat->field_map_size);
791+
lua_setfield(L, -2, "field_map_size");
792+
793+
lua_pushnumber(L, stat->waste_size);
794+
lua_setfield(L, -2, "waste_size");
795+
796+
lua_setfield(L, -2, tuple_arena_type_strs[i]);
797+
}
798+
lua_setfield(L, -2, "tuple");
799+
800+
return 1;
801+
}
802+
749803
void
750804
box_lua_space_init(struct lua_State *L)
751805
{
@@ -849,6 +903,7 @@ box_lua_space_init(struct lua_State *L)
849903

850904
static const struct luaL_Reg space_internal_lib[] = {
851905
{"frommap", lbox_space_frommap},
906+
{"stat", lbox_space_stat},
852907
{NULL, NULL}
853908
};
854909
luaL_findtable(L, LUA_GLOBALSINDEX, "box.internal.space", 0);

src/box/memtx_engine.cc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -617,10 +617,7 @@ memtx_engine_commit(struct engine *engine, struct txn *txn)
617617
stailq_foreach_entry(stmt, &txn->stmts, next) {
618618
if (memtx_tx_manager_use_mvcc_engine) {
619619
assert(stmt->space->engine == engine);
620-
struct memtx_space *mspace =
621-
(struct memtx_space *)stmt->space;
622-
size_t *bsize = &mspace->bsize;
623-
memtx_tx_history_commit_stmt(stmt, bsize);
620+
memtx_tx_history_commit_stmt(stmt);
624621
}
625622
if (stmt->engine_savepoint != NULL) {
626623
struct space *space = stmt->space;
@@ -679,7 +676,7 @@ memtx_engine_rollback_statement(struct engine *engine, struct txn *txn,
679676
}
680677
}
681678

682-
memtx_space_update_bsize(space, new_tuple, old_tuple);
679+
memtx_space_update_tuple_stat(space, new_tuple, old_tuple);
683680
if (old_tuple != NULL)
684681
tuple_ref(old_tuple);
685682
if (new_tuple != NULL)

src/box/memtx_space.c

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,21 +75,56 @@ static size_t
7575
memtx_space_bsize(struct space *space)
7676
{
7777
struct memtx_space *memtx_space = (struct memtx_space *)space;
78-
return memtx_space->bsize;
78+
return memtx_space->tuple_stat[TUPLE_ARENA_MEMTX].data_size +
79+
memtx_space->tuple_stat[TUPLE_ARENA_MALLOC].data_size;
7980
}
8081

8182
/* {{{ DML */
8283

8384
void
84-
memtx_space_update_bsize(struct space *space, struct tuple *old_tuple,
85-
struct tuple *new_tuple)
85+
memtx_space_update_tuple_stat(struct space *space, struct tuple *old_tuple,
86+
struct tuple *new_tuple)
8687
{
8788
assert(space->vtab->destroy == &memtx_space_destroy);
8889
struct memtx_space *memtx_space = (struct memtx_space *)space;
89-
ssize_t old_bsize = old_tuple ? box_tuple_bsize(old_tuple) : 0;
90-
ssize_t new_bsize = new_tuple ? box_tuple_bsize(new_tuple) : 0;
91-
assert((ssize_t)memtx_space->bsize + new_bsize - old_bsize >= 0);
92-
memtx_space->bsize += new_bsize - old_bsize;
90+
struct tuple_info info, *stat;
91+
92+
if (new_tuple != NULL) {
93+
tuple_info(new_tuple, &info);
94+
95+
assert(info.arena_type == TUPLE_ARENA_MEMTX ||
96+
info.arena_type == TUPLE_ARENA_MALLOC);
97+
stat = &memtx_space->tuple_stat[info.arena_type];
98+
99+
stat->data_size += info.data_size;
100+
stat->header_size += info.header_size;
101+
stat->field_map_size += info.field_map_size;
102+
stat->waste_size += info.waste_size;
103+
}
104+
105+
if (old_tuple != NULL) {
106+
tuple_info(old_tuple, &info);
107+
108+
assert(info.arena_type == TUPLE_ARENA_MEMTX ||
109+
info.arena_type == TUPLE_ARENA_MALLOC);
110+
stat = &memtx_space->tuple_stat[info.arena_type];
111+
112+
assert(stat->data_size >= info.data_size);
113+
assert(stat->header_size >= info.header_size);
114+
assert(stat->field_map_size >= info.field_map_size);
115+
116+
stat->data_size -= info.data_size;
117+
stat->header_size -= info.header_size;
118+
stat->field_map_size -= info.field_map_size;
119+
/*
120+
* Avoid negative values, since waste_size is calculated
121+
* imprecisely.
122+
*/
123+
if (stat->waste_size > info.waste_size)
124+
stat->waste_size -= info.waste_size;
125+
else
126+
stat->waste_size = 0;
127+
}
93128
}
94129

95130
/**
@@ -142,7 +177,7 @@ memtx_space_replace_build_next(struct space *space, struct tuple *old_tuple,
142177
}
143178
if (index_build_next(space->index[0], new_tuple) != 0)
144179
return -1;
145-
memtx_space_update_bsize(space, NULL, new_tuple);
180+
memtx_space_update_tuple_stat(space, NULL, new_tuple);
146181
tuple_ref(new_tuple);
147182
return 0;
148183
}
@@ -161,7 +196,7 @@ memtx_space_replace_primary_key(struct space *space, struct tuple *old_tuple,
161196
if (index_replace(space->index[0], old_tuple,
162197
new_tuple, mode, &old_tuple, &successor) != 0)
163198
return -1;
164-
memtx_space_update_bsize(space, old_tuple, new_tuple);
199+
memtx_space_update_tuple_stat(space, old_tuple, new_tuple);
165200
if (new_tuple != NULL)
166201
tuple_ref(new_tuple);
167202
*result = old_tuple;
@@ -313,7 +348,7 @@ memtx_space_replace_all_keys(struct space *space, struct tuple *old_tuple,
313348
goto rollback;
314349
}
315350

316-
memtx_space_update_bsize(space, old_tuple, new_tuple);
351+
memtx_space_update_tuple_stat(space, old_tuple, new_tuple);
317352
if (new_tuple != NULL)
318353
tuple_ref(new_tuple);
319354
*result = old_tuple;
@@ -1366,7 +1401,7 @@ memtx_space_prepare_alter(struct space *old_space, struct space *new_space)
13661401
struct memtx_space *old_memtx_space = (struct memtx_space *)old_space;
13671402
struct memtx_space *new_memtx_space = (struct memtx_space *)new_space;
13681403

1369-
if (old_memtx_space->bsize != 0 &&
1404+
if (memtx_space_bsize(old_space) != 0 &&
13701405
space_is_data_temporary(old_space) !=
13711406
space_is_data_temporary(new_space)) {
13721407
diag_set(ClientError, ER_ALTER_SPACE, old_space->def->name,
@@ -1380,9 +1415,9 @@ memtx_space_prepare_alter(struct space *old_space, struct space *new_space)
13801415
}
13811416

13821417
/**
1383-
* Copy bsize to the newly altered space from the old space.
1418+
* Copy memory usage statistics to the newly altered space from the old space.
13841419
* In case of DropIndex or TruncateIndex alter operations, the new space will be
1385-
* empty, and bsize must not be copied.
1420+
* empty, and tuple statistics must not be copied.
13861421
*/
13871422
static void
13881423
memtx_space_finish_alter(struct space *old_space, struct space *new_space)
@@ -1392,8 +1427,12 @@ memtx_space_finish_alter(struct space *old_space, struct space *new_space)
13921427

13931428
bool is_empty = new_space->index_count == 0 ||
13941429
index_size(new_space->index[0]) == 0;
1395-
if (!is_empty)
1396-
new_memtx_space->bsize = old_memtx_space->bsize;
1430+
if (!is_empty) {
1431+
new_memtx_space->tuple_stat[TUPLE_ARENA_MEMTX] =
1432+
old_memtx_space->tuple_stat[TUPLE_ARENA_MEMTX];
1433+
new_memtx_space->tuple_stat[TUPLE_ARENA_MALLOC] =
1434+
old_memtx_space->tuple_stat[TUPLE_ARENA_MALLOC];
1435+
}
13971436
}
13981437

13991438
/* }}} DDL */
@@ -1458,7 +1497,7 @@ memtx_space_new(struct memtx_engine *memtx,
14581497
/* Format is now referenced by the space. */
14591498
tuple_format_unref(format);
14601499

1461-
memtx_space->bsize = 0;
1500+
memset(&memtx_space->tuple_stat, 0, sizeof(memtx_space->tuple_stat));
14621501
memtx_space->rowid = 0;
14631502
memtx_space->replace = memtx_space_replace_no_keys;
14641503
return (struct space *)memtx_space;

src/box/memtx_space.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
* SUCH DAMAGE.
3232
*/
3333
#include "space.h"
34+
#include "tuple.h"
3435
#include "memtx_engine.h"
3536

3637
#if defined(__cplusplus)
@@ -41,8 +42,13 @@ struct memtx_engine;
4142

4243
struct memtx_space {
4344
struct space base;
44-
/* Number of bytes used in memory by tuples in the space. */
45-
size_t bsize;
45+
/**
46+
* Cumulative statistics on the memory usage by tuples in the space,
47+
* grouped by the following arena types:
48+
* 0 - TUPLE_ARENA_MEMTX;
49+
* 1 - TUPLE_ARENA_MALLOC.
50+
*/
51+
struct tuple_info tuple_stat[2];
4652
/**
4753
* This counter is used to generate unique ids for
4854
* ephemeral spaces. Mostly used by SQL: values of this
@@ -59,17 +65,17 @@ struct memtx_space {
5965
};
6066

6167
/**
62-
* Change binary size of a space subtracting old tuple's size and
63-
* adding new tuple's size. Used also for rollback by swaping old
64-
* and new tuple.
68+
* Update memory usage statistics of a space by subtracting old tuple's sizes
69+
* and adding new tuple's sizes. Used also for rollback by swapping old and new
70+
* tuples.
6571
*
6672
* @param space Instance of memtx space.
6773
* @param old_tuple Old tuple (replaced or deleted).
6874
* @param new_tuple New tuple (inserted).
6975
*/
7076
void
71-
memtx_space_update_bsize(struct space *space, struct tuple *old_tuple,
72-
struct tuple *new_tuple);
77+
memtx_space_update_tuple_stat(struct space *space, struct tuple *old_tuple,
78+
struct tuple *new_tuple);
7379

7480
int
7581
memtx_space_replace_no_keys(struct space *, struct tuple *, struct tuple *,

src/box/memtx_tx.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* SUCH DAMAGE.
3030
*/
3131
#include "memtx_tx.h"
32+
#include "memtx_space.h"
3233

3334
#include <assert.h>
3435
#include <limits.h>
@@ -2722,16 +2723,19 @@ memtx_tx_prepare_finalize(struct txn *txn)
27222723
}
27232724

27242725
void
2725-
memtx_tx_history_commit_stmt(struct txn_stmt *stmt, size_t *bsize)
2726+
memtx_tx_history_commit_stmt(struct txn_stmt *stmt)
27262727
{
2728+
struct tuple *old_tuple, *new_tuple;
2729+
old_tuple = stmt->del_story == NULL ? NULL : stmt->del_story->tuple;
2730+
new_tuple = stmt->add_story == NULL ? NULL : stmt->add_story->tuple;
2731+
memtx_space_update_tuple_stat(stmt->space, old_tuple, new_tuple);
2732+
27272733
if (stmt->add_story != NULL) {
27282734
assert(stmt->add_story->add_stmt == stmt);
2729-
*bsize += tuple_bsize(stmt->add_story->tuple);
27302735
memtx_tx_story_unlink_added_by(stmt->add_story, stmt);
27312736
}
27322737
if (stmt->del_story != NULL) {
27332738
assert(stmt->del_story->del_stmt == stmt);
2734-
*bsize -= tuple_bsize(stmt->del_story->tuple);
27352739
memtx_tx_story_unlink_deleted_by(stmt->del_story, stmt);
27362740
}
27372741
memtx_tx_story_gc();

src/box/memtx_tx.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,9 @@ memtx_tx_prepare_finalize(struct txn *txn);
251251
* NB: can trigger story garbage collection.
252252
*
253253
* @param stmt current statement.
254-
* @param bsize the space bsize.
255254
*/
256255
void
257-
memtx_tx_history_commit_stmt(struct txn_stmt *stmt, size_t *bsize);
256+
memtx_tx_history_commit_stmt(struct txn_stmt *stmt);
258257

259258
/** Helper of memtx_tx_tuple_clarify */
260259
struct tuple *

0 commit comments

Comments
 (0)