-
Notifications
You must be signed in to change notification settings - Fork 24.5k
Enabled background and reply time tracking on blocked on keys/blocked on background work clients #7491
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enabled background and reply time tracking on blocked on keys/blocked on background work clients #7491
Changes from all commits
bf3607f
ef5f268
00492ae
e50dd24
12a7788
cd726c8
a82f627
dfc0d4f
bc11a38
1d8498f
1e0fc66
a702ce0
a1f4c6d
83c4dd4
ee77cfd
2289e12
6a70eea
b452dee
97f55ec
6a7b334
d2bd4b2
fd93a06
73da9d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,7 +29,9 @@ | |
|
|
||
| #include "server.h" | ||
| #include "cluster.h" | ||
| #include "slowlog.h" | ||
| #include "rdb.h" | ||
| #include "monotonic.h" | ||
| #include <dlfcn.h> | ||
| #include <sys/stat.h> | ||
| #include <sys/wait.h> | ||
|
|
@@ -252,6 +254,9 @@ typedef struct RedisModuleBlockedClient { | |
| int dbid; /* Database number selected by the original client. */ | ||
| int blocked_on_keys; /* If blocked via RM_BlockClientOnKeys(). */ | ||
| int unblocked; /* Already on the moduleUnblocked list. */ | ||
| monotime background_timer; /* Timer tracking the start of background work */ | ||
| uint64_t background_duration; /* Current command background time duration. | ||
| Used for measuring latency of blocking cmds */ | ||
| } RedisModuleBlockedClient; | ||
|
|
||
| static pthread_mutex_t moduleUnblockedClientsMutex = PTHREAD_MUTEX_INITIALIZER; | ||
|
|
@@ -900,6 +905,30 @@ long long RM_Milliseconds(void) { | |
| return mstime(); | ||
| } | ||
|
|
||
| /* Mark a point in time that will be used as the start time to calculate | ||
| * the elapsed execution time when RM_BlockedClientMeasureTimeEnd() is called. | ||
| * Within the same command, you can call multiple times | ||
| * RM_BlockedClientMeasureTimeStart() and RM_BlockedClientMeasureTimeEnd() | ||
| * to accummulate indepedent time intervals to the background duration. | ||
| * This method always return REDISMODULE_OK. */ | ||
| int RM_BlockedClientMeasureTimeStart(RedisModuleBlockedClient *bc) { | ||
| elapsedStart(&(bc->background_timer)); | ||
| return REDISMODULE_OK; | ||
| } | ||
|
|
||
| /* Mark a point in time that will be used as the end time | ||
| * to calculate the elapsed execution time. | ||
| * On success REDISMODULE_OK is returned. | ||
| * This method only returns REDISMODULE_ERR if no start time was | ||
| * previously defined ( meaning RM_BlockedClientMeasureTimeStart was not called ). */ | ||
| int RM_BlockedClientMeasureTimeEnd(RedisModuleBlockedClient *bc) { | ||
| // If the counter is 0 then we haven't called RM_BlockedClientMeasureTimeStart | ||
| if (!bc->background_timer) | ||
| return REDISMODULE_ERR; | ||
| bc->background_duration += elapsedUs(bc->background_timer); | ||
| return REDISMODULE_OK; | ||
| } | ||
|
|
||
| /* Set flags defining capabilities or behavior bit flags. | ||
| * | ||
| * REDISMODULE_OPTIONS_HANDLE_IO_ERRORS: | ||
|
|
@@ -4573,6 +4602,7 @@ RedisModuleBlockedClient *moduleBlockClient(RedisModuleCtx *ctx, RedisModuleCmdF | |
| bc->dbid = c->db->id; | ||
| bc->blocked_on_keys = keys != NULL; | ||
| bc->unblocked = 0; | ||
| bc->background_duration = 0; | ||
| c->bpop.timeout = timeout; | ||
|
|
||
| if (islua || ismulti) { | ||
|
|
@@ -4646,6 +4676,11 @@ int moduleTryServeClientBlockedOnKey(client *c, robj *key) { | |
| * | ||
| * In these cases, a call to RedisModule_BlockClient() will **not** block the | ||
| * client, but instead produce a specific error reply. | ||
| * | ||
| * Measuring background time: By default the time spent in the blocked command | ||
| * is not account for the total command duration. To include such time you should | ||
| * use RM_BlockedClientMeasureTimeStart() and RM_BlockedClientMeasureTimeEnd() one, | ||
| * or multiple times within the blocking command background work. | ||
| */ | ||
| RedisModuleBlockedClient *RM_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms) { | ||
| return moduleBlockClient(ctx,reply_callback,timeout_callback,free_privdata,timeout_ms, NULL,0,NULL); | ||
|
|
@@ -4840,6 +4875,7 @@ void moduleHandleBlockedClients(void) { | |
| * was blocked on keys (RM_BlockClientOnKeys()), because we already | ||
| * called such callback in moduleTryServeClientBlockedOnKey() when | ||
| * the key was signaled as ready. */ | ||
| uint64_t reply_us = 0; | ||
| if (c && !bc->blocked_on_keys && bc->reply_callback) { | ||
| RedisModuleCtx ctx = REDISMODULE_CTX_INIT; | ||
| ctx.flags |= REDISMODULE_CTX_BLOCKED_REPLY; | ||
|
|
@@ -4848,9 +4884,19 @@ void moduleHandleBlockedClients(void) { | |
| ctx.module = bc->module; | ||
| ctx.client = bc->client; | ||
| ctx.blocked_client = bc; | ||
| monotime replyTimer; | ||
| elapsedStart(&replyTimer); | ||
| bc->reply_callback(&ctx,(void**)c->argv,c->argc); | ||
| reply_us = elapsedUs(replyTimer); | ||
| moduleFreeContext(&ctx); | ||
| } | ||
| /* Update stats now that we've finished the blocking operation. | ||
| * This needs to be out of the reply callback above given that a | ||
| * module might not define any callback and still do blocking ops. | ||
| */ | ||
| if (c && !bc->blocked_on_keys) { | ||
| updateStatsOnUnblock(c, bc->background_duration, reply_us); | ||
| } | ||
|
|
||
| /* Free privdata if any. */ | ||
| if (bc->privdata && bc->free_privdata) { | ||
|
|
@@ -4914,6 +4960,9 @@ void moduleBlockedClientTimedOut(client *c) { | |
| ctx.blocked_privdata = bc->privdata; | ||
| bc->timeout_callback(&ctx,(void**)c->argv,c->argc); | ||
| moduleFreeContext(&ctx); | ||
| if (!bc->blocked_on_keys) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @madolson added the background time tracking on timeout as well for modules (tested on test named "check blocked command that uses RedisModule_MeasureTimeStart() is tracking background time even in timeout" ). |
||
| updateStatsOnUnblock(c, bc->background_duration, 0); | ||
| } | ||
| /* For timeout events, we do not want to call the disconnect callback, | ||
| * because the blocked client will be automatically disconnected in | ||
| * this case, and the user can still hook using the timeout callback. */ | ||
|
|
@@ -8552,6 +8601,8 @@ void moduleRegisterCoreAPI(void) { | |
| REGISTER_API(GetBlockedClientPrivateData); | ||
| REGISTER_API(AbortBlock); | ||
| REGISTER_API(Milliseconds); | ||
| REGISTER_API(BlockedClientMeasureTimeStart); | ||
| REGISTER_API(BlockedClientMeasureTimeEnd); | ||
| REGISTER_API(GetThreadSafeContext); | ||
| REGISTER_API(GetDetachedThreadSafeContext); | ||
| REGISTER_API(FreeThreadSafeContext); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.