Disarm dict-rehash timing unconditionally at top-level call() exit

The disarm of dictRehashStepTiming was inside the if (update_command_stats)
block, which is skipped during AOF loading and other contexts where command
stats are suppressed. Across those paths the flag stayed armed, so every
incremental rehash step continued to pay the getMonotonicUs() cost and wrote
into the accumulator that was never read back.

The arm/disarm pair is state-machine cleanup, not a stats emission. Move the
disarm out of the stats block, guarded only by execution_nesting == 0, so it
runs on every outermost call() exit. Emission remains where it was: inside
the stats block, adjacent to durationAddSample.

Restores the "zero-cost when latency monitoring is disabled" invariant on
all code paths through call(), including AOF replay.
This commit is contained in:
Henry Filgueiras 2026-04-20 15:56:28 -07:00
parent 5b38d54ca7
commit dd97d59744

View file

@ -4020,14 +4020,16 @@ void call(client *c, int flags) {
durationAddSample(EL_DURATION_TYPE_CMD, duration);
latencyAddSampleIfNeeded("dict-rehash-during-command",
(long long)(dictRehashStepElapsedUs/1000));
/* Disarm the dict-rehash timing path between top-level calls so
* any rehash work done in cron (e.g. via active expire) does not
* pay the timing cost. The accumulator is zeroed again at the
* next top-level entry. */
dictRehashStepTiming = 0;
}
}
/* 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))