Added engine stats to FUNCTION STATS command. (#10179)
Added the following statistics (per engine) to FUNCTION STATS command: * number of functions * number of libraries Output example: ``` > FUNCTION stats 1) "running_script" 2) (nil) 3) "engines" 4) 1) "LUA" 2) 1) "libraries_count" 2) (integer) 1 3) "functions_count" 4) (integer) 1 ``` To collect the stats, added a new dictionary to libraries_ctx that contains for each engine, the engine statistics representing the current libraries_ctx. Update the stats on: 1. Link library to libraries_ctx 2. Unlink library from libraries_ctx 3. Flushing libraries_ctx
This commit is contained in:
parent
d26453a3f8
commit
5a38ccc253
@ -41,13 +41,20 @@ static size_t engine_cache_memory = 0;
|
||||
|
||||
/* Forward declaration */
|
||||
static void engineFunctionDispose(dict *d, void *obj);
|
||||
static void engineStatsDispose(dict *d, void *obj);
|
||||
static void engineLibraryDispose(dict *d, void *obj);
|
||||
static int functionsVerifyName(sds name);
|
||||
|
||||
typedef struct functionsLibEngineStats {
|
||||
size_t n_lib;
|
||||
size_t n_functions;
|
||||
} functionsLibEngineStats;
|
||||
|
||||
struct functionsLibCtx {
|
||||
dict *libraries; /* Function name -> Function object that can be used to run the function */
|
||||
dict *functions; /* Function name -> Function object that can be used to run the function */
|
||||
size_t cache_memory /* Overhead memory (structs, dictionaries, ..) used by all the functions */;
|
||||
dict *libraries; /* Library name -> Library object */
|
||||
dict *functions; /* Function name -> Function object that can be used to run the function */
|
||||
size_t cache_memory; /* Overhead memory (structs, dictionaries, ..) used by all the functions */
|
||||
dict *engines_stats; /* Per engine statistics */
|
||||
};
|
||||
|
||||
dictType engineDictType = {
|
||||
@ -70,6 +77,16 @@ dictType functionDictType = {
|
||||
NULL /* allow to expand */
|
||||
};
|
||||
|
||||
dictType engineStatsDictType = {
|
||||
dictSdsCaseHash, /* hash function */
|
||||
dictSdsDup, /* key dup */
|
||||
NULL, /* val dup */
|
||||
dictSdsKeyCaseCompare,/* key compare */
|
||||
dictSdsDestructor, /* key destructor */
|
||||
engineStatsDispose, /* val destructor */
|
||||
NULL /* allow to expand */
|
||||
};
|
||||
|
||||
dictType libraryFunctionDictType = {
|
||||
dictSdsHash, /* hash function */
|
||||
dictSdsDup, /* key dup */
|
||||
@ -111,6 +128,12 @@ static size_t libraryMallocSize(functionLibInfo *li) {
|
||||
+ sdsZmallocSize(li->code);
|
||||
}
|
||||
|
||||
static void engineStatsDispose(dict *d, void *obj) {
|
||||
UNUSED(d);
|
||||
functionsLibEngineStats *stats = obj;
|
||||
zfree(stats);
|
||||
}
|
||||
|
||||
/* Dispose function memory */
|
||||
static void engineFunctionDispose(dict *d, void *obj) {
|
||||
UNUSED(d);
|
||||
@ -147,6 +170,14 @@ static void engineLibraryDispose(dict *d, void *obj) {
|
||||
void functionsLibCtxClear(functionsLibCtx *lib_ctx) {
|
||||
dictEmpty(lib_ctx->functions, NULL);
|
||||
dictEmpty(lib_ctx->libraries, NULL);
|
||||
dictIterator *iter = dictGetIterator(lib_ctx->engines_stats);
|
||||
dictEntry *entry = NULL;
|
||||
while ((entry = dictNext(iter))) {
|
||||
functionsLibEngineStats *stats = dictGetVal(entry);
|
||||
stats->n_functions = 0;
|
||||
stats->n_lib = 0;
|
||||
}
|
||||
dictReleaseIterator(iter);
|
||||
curr_functions_lib_ctx->cache_memory = 0;
|
||||
}
|
||||
|
||||
@ -165,6 +196,7 @@ void functionsLibCtxFree(functionsLibCtx *functions_lib_ctx) {
|
||||
functionsLibCtxClear(functions_lib_ctx);
|
||||
dictRelease(functions_lib_ctx->functions);
|
||||
dictRelease(functions_lib_ctx->libraries);
|
||||
dictRelease(functions_lib_ctx->engines_stats);
|
||||
zfree(functions_lib_ctx);
|
||||
}
|
||||
|
||||
@ -185,6 +217,15 @@ functionsLibCtx* functionsLibCtxCreate() {
|
||||
functionsLibCtx *ret = zmalloc(sizeof(functionsLibCtx));
|
||||
ret->libraries = dictCreate(&librariesDictType);
|
||||
ret->functions = dictCreate(&functionDictType);
|
||||
ret->engines_stats = dictCreate(&engineStatsDictType);
|
||||
dictIterator *iter = dictGetIterator(engines);
|
||||
dictEntry *entry = NULL;
|
||||
while ((entry = dictNext(iter))) {
|
||||
engineInfo *ei = dictGetVal(entry);
|
||||
functionsLibEngineStats *stats = zcalloc(sizeof(*stats));
|
||||
dictAdd(ret->engines_stats, ei->name, stats);
|
||||
}
|
||||
dictReleaseIterator(iter);
|
||||
ret->cache_memory = 0;
|
||||
return ret;
|
||||
}
|
||||
@ -250,6 +291,12 @@ static void libraryUnlink(functionsLibCtx *lib_ctx, functionLibInfo* li) {
|
||||
dictSetVal(lib_ctx->libraries, entry, NULL);
|
||||
dictFreeUnlinkedEntry(lib_ctx->libraries, entry);
|
||||
lib_ctx->cache_memory += libraryMallocSize(li);
|
||||
|
||||
/* update stats */
|
||||
functionsLibEngineStats *stats = dictFetchValue(lib_ctx->engines_stats, li->ei->name);
|
||||
serverAssert(stats);
|
||||
stats->n_lib--;
|
||||
stats->n_functions -= dictSize(li->functions);
|
||||
}
|
||||
|
||||
static void libraryLink(functionsLibCtx *lib_ctx, functionLibInfo* li) {
|
||||
@ -264,6 +311,12 @@ static void libraryLink(functionsLibCtx *lib_ctx, functionLibInfo* li) {
|
||||
|
||||
dictAdd(lib_ctx->libraries, li->name, li);
|
||||
lib_ctx->cache_memory += libraryMallocSize(li);
|
||||
|
||||
/* update stats */
|
||||
functionsLibEngineStats *stats = dictFetchValue(lib_ctx->engines_stats, li->ei->name);
|
||||
serverAssert(stats);
|
||||
stats->n_lib++;
|
||||
stats->n_functions += dictSize(li->functions);
|
||||
}
|
||||
|
||||
/* Takes all libraries from lib_ctx_src and add to lib_ctx_dst.
|
||||
@ -401,12 +454,18 @@ void functionStatsCommand(client *c) {
|
||||
}
|
||||
|
||||
addReplyBulkCString(c, "engines");
|
||||
addReplyArrayLen(c, dictSize(engines));
|
||||
addReplyMapLen(c, dictSize(engines));
|
||||
dictIterator *iter = dictGetIterator(engines);
|
||||
dictEntry *entry = NULL;
|
||||
while ((entry = dictNext(iter))) {
|
||||
engineInfo *ei = dictGetVal(entry);
|
||||
addReplyBulkCString(c, ei->name);
|
||||
addReplyMapLen(c, 2);
|
||||
functionsLibEngineStats *e_stats = dictFetchValue(curr_functions_lib_ctx->engines_stats, ei->name);
|
||||
addReplyBulkCString(c, "libraries_count");
|
||||
addReplyLongLong(c, e_stats->n_lib);
|
||||
addReplyBulkCString(c, "functions_count");
|
||||
addReplyLongLong(c, e_stats->n_functions);
|
||||
}
|
||||
dictReleaseIterator(iter);
|
||||
}
|
||||
@ -979,11 +1038,13 @@ size_t functionsLibCtxfunctionsLen(functionsLibCtx *functions_ctx) {
|
||||
* Should be called once on server initialization */
|
||||
int functionsInit() {
|
||||
engines = dictCreate(&engineDictType);
|
||||
curr_functions_lib_ctx = functionsLibCtxCreate();
|
||||
|
||||
if (luaEngineInitEngine() != C_OK) {
|
||||
return C_ERR;
|
||||
}
|
||||
|
||||
/* Must be initialized after engines initialization */
|
||||
curr_functions_lib_ctx = functionsLibCtxCreate();
|
||||
|
||||
return C_OK;
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ start_server {tags {"scripting"}} {
|
||||
after 200
|
||||
catch {r ping} e
|
||||
assert_match {BUSY*} $e
|
||||
assert_match {running_script {name test command {fcall test 0} duration_ms *} engines LUA} [r FUNCTION STATS]
|
||||
assert_match {running_script {name test command {fcall test 0} duration_ms *} engines {*}} [r FUNCTION STATS]
|
||||
r function kill
|
||||
after 200 ; # Give some time to Lua to call the hook again...
|
||||
assert_equal [r ping] "PONG"
|
||||
@ -1102,4 +1102,34 @@ start_server {tags {"scripting"}} {
|
||||
catch {[r fcall f1 0]} e
|
||||
assert_equal [r fcall get_version_v1 0] [r fcall get_version_v2 0]
|
||||
}
|
||||
|
||||
test {FUNCTION - function stats} {
|
||||
r FUNCTION FLUSH
|
||||
|
||||
r FUNCTION load lua test1 {
|
||||
redis.register_function('f1', function() return 1 end)
|
||||
redis.register_function('f2', function() return 1 end)
|
||||
}
|
||||
|
||||
r FUNCTION load lua test2 {
|
||||
redis.register_function('f3', function() return 1 end)
|
||||
}
|
||||
|
||||
r function stats
|
||||
} {running_script {} engines {LUA {libraries_count 2 functions_count 3}}}
|
||||
|
||||
test {FUNCTION - function stats reloaded correctly from rdb} {
|
||||
r debug reload
|
||||
r function stats
|
||||
} {running_script {} engines {LUA {libraries_count 2 functions_count 3}}} {needs:debug}
|
||||
|
||||
test {FUNCTION - function stats delete library} {
|
||||
r function delete test1
|
||||
r function stats
|
||||
} {running_script {} engines {LUA {libraries_count 1 functions_count 1}}}
|
||||
|
||||
test {FUNCTION - function stats cleaned after flush} {
|
||||
r function flush
|
||||
r function stats
|
||||
} {running_script {} engines {LUA {libraries_count 0 functions_count 0}}}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user