mirror of
https://github.com/redis/redis.git
synced 2026-05-28 04:02:46 -04:00
Merge dd97d59744 into 138263a1b4
This commit is contained in:
commit
1e93c4cbce
3 changed files with 56 additions and 2 deletions
33
src/dict.c
33
src/dict.c
|
|
@ -44,6 +44,18 @@
|
|||
static dictResizeEnable dict_can_resize = DICT_RESIZE_ENABLE;
|
||||
static unsigned int dict_force_resize_ratio = 4;
|
||||
|
||||
/* Accumulator of microseconds spent in incremental rehash steps performed
|
||||
* inside dict lookup/insert/delete operations. Read and reset by higher
|
||||
* layers (server.c call()) to attribute per-command rehash cost. */
|
||||
uint64_t dictRehashStepElapsedUs = 0;
|
||||
|
||||
/* Non-zero when latency monitoring is active
|
||||
* (server.latency_monitor_threshold != 0). Set by server.c at the outermost
|
||||
* call() entry and cleared at the outermost call() exit. While zero, the
|
||||
* rehash timing path is skipped entirely: no clock reads, no accumulator
|
||||
* writes - just one predictable branch. */
|
||||
int dictRehashStepTiming = 0;
|
||||
|
||||
/* -------------------------- types ----------------------------------------- */
|
||||
struct dictEntry {
|
||||
struct dictEntry *next; /* Must be first */
|
||||
|
|
@ -466,7 +478,19 @@ int dictRehashMicroseconds(dict *d, uint64_t us) {
|
|||
* dictionary so that the hash table automatically migrates from H1 to H2
|
||||
* while it is actively used. */
|
||||
static void _dictRehashStep(dict *d) {
|
||||
if (d->pauserehash == 0) dictRehash(d,1);
|
||||
if (d->pauserehash == 0) {
|
||||
/* Skip the timing path when latency monitoring is off, and also
|
||||
* when getMonotonicUs is still NULL during early startup (core
|
||||
* module registration runs dictAdd before monotonicInit). */
|
||||
if (!dictRehashStepTiming || getMonotonicUs == NULL) {
|
||||
dictRehash(d,1);
|
||||
return;
|
||||
}
|
||||
monotime t;
|
||||
elapsedStart(&t);
|
||||
dictRehash(d,1);
|
||||
dictRehashStepElapsedUs += elapsedUs(t);
|
||||
}
|
||||
}
|
||||
|
||||
/* Performs rehashing on a single bucket. */
|
||||
|
|
@ -1705,6 +1729,12 @@ static void _dictShrinkIfNeeded(dict *d)
|
|||
static void _dictRehashStepIfNeeded(dict *d, uint64_t visitedIdx) {
|
||||
if ((!dictIsRehashing(d)) || (d->pauserehash != 0))
|
||||
return;
|
||||
/* Skip the timing path when latency monitoring is off, and also when
|
||||
* getMonotonicUs is still NULL during early startup (core module
|
||||
* registration runs dictAdd before monotonicInit). */
|
||||
const int time_it = dictRehashStepTiming && (getMonotonicUs != NULL);
|
||||
monotime t;
|
||||
if (time_it) elapsedStart(&t);
|
||||
/* rehashing not in progress if rehashidx == -1 */
|
||||
if ((long)visitedIdx >= d->rehashidx && d->ht_table[0][visitedIdx]) {
|
||||
/* If we have a valid hash entry at `idx` in ht0, we perform
|
||||
|
|
@ -1715,6 +1745,7 @@ static void _dictRehashStepIfNeeded(dict *d, uint64_t visitedIdx) {
|
|||
* on the rehashidx (not CPU cache friendly). */
|
||||
dictRehash(d,1);
|
||||
}
|
||||
if (time_it) dictRehashStepElapsedUs += elapsedUs(t);
|
||||
}
|
||||
|
||||
/* Our hash table capability is a power of two */
|
||||
|
|
|
|||
|
|
@ -292,6 +292,8 @@ void dictEmpty(dict *d, void(callback)(dict*));
|
|||
void dictSetResizeEnabled(dictResizeEnable enable);
|
||||
int dictRehash(dict *d, int n);
|
||||
int dictRehashMicroseconds(dict *d, uint64_t us);
|
||||
extern uint64_t dictRehashStepElapsedUs;
|
||||
extern int dictRehashStepTiming;
|
||||
void dictSetHashFunctionSeed(uint8_t *seed);
|
||||
unsigned long dictScan(dict *d, unsigned long v, dictScanFunction *fn, void *privdata);
|
||||
unsigned long dictScanDefrag(dict *d, unsigned long v, dictScanFunction *fn, dictDefragFunctions *defragfns, void *privdata);
|
||||
|
|
|
|||
23
src/server.c
23
src/server.c
|
|
@ -3983,6 +3983,17 @@ void call(client *c, int flags) {
|
|||
/* Pass current server.ustime to avoid ustime() call if monotonic clock is used
|
||||
* and time will be updated before command execution based on monotonic clock. */
|
||||
const long long call_timer = use_hw_clock ? server.ustime : ustime();
|
||||
/* Arm dict-rehash attribution at the outermost call() only. The
|
||||
* accumulator starts at zero so that only rehash work performed during
|
||||
* this top-level command's proc is attributed to it, and the timing
|
||||
* flag is set so that the dict-side path starts collecting samples
|
||||
* while this command runs. When the feature is disabled
|
||||
* (latency_monitor_threshold == 0), the flag stays 0 and the entire
|
||||
* timing path is a single predictable branch. */
|
||||
if (server.execution_nesting == 0) {
|
||||
dictRehashStepElapsedUs = 0;
|
||||
dictRehashStepTiming = (server.latency_monitor_threshold != 0);
|
||||
}
|
||||
enterExecutionUnit(1, call_timer);
|
||||
|
||||
/* setting the CLIENT_EXECUTING_COMMAND flag so we will avoid
|
||||
|
|
@ -4039,10 +4050,20 @@ void call(client *c, int flags) {
|
|||
char *latency_event = (real_cmd->flags & CMD_FAST) ?
|
||||
"fast-command" : "command";
|
||||
latencyAddSampleIfNeeded(latency_event,duration/1000);
|
||||
if (server.execution_nesting == 0)
|
||||
if (server.execution_nesting == 0) {
|
||||
durationAddSample(EL_DURATION_TYPE_CMD, duration);
|
||||
latencyAddSampleIfNeeded("dict-rehash-during-command",
|
||||
(long long)(dictRehashStepElapsedUs/1000));
|
||||
}
|
||||
}
|
||||
|
||||
/* Disarm the dict-rehash timing path unconditionally at outermost call()
|
||||
* exit, so cron work between commands does not pay the timing cost. This
|
||||
* must run regardless of update_command_stats (e.g. during AOF loading)
|
||||
* so the flag cannot stay armed across paths that skip the stats block. */
|
||||
if (server.execution_nesting == 0)
|
||||
dictRehashStepTiming = 0;
|
||||
|
||||
/* Log the command into the Slow log if needed.
|
||||
* If the client is blocked we will handle slowlog when it is unblocked. */
|
||||
if (update_command_stats && !(c->flags & CLIENT_BLOCKED))
|
||||
|
|
|
|||
Loading…
Reference in a new issue