mirror of
https://github.com/fluencelabs/redis
synced 2025-03-19 17:10:50 +00:00
activeExpireCycle() smarter with many DBs and under expire pressure.
activeExpireCycle() tries to test just a few DBs per iteration so that it scales if there are many configured DBs in the Redis instance. However this commit makes it a bit smarter when one a few of those DBs are under expiration pressure and there are many many keys to expire. What we do is to remember if in the last iteration had to return because we ran out of time. In that case the next iteration we'll test all the configured DBs so that we are sure we'll test again the DB under pressure. Before of this commit after some mass-expire in a given DB the function tested just a few of the next DBs, possibly empty, a few per iteration, so it took a long time for the function to reach again the DB under pressure. This resulted in a lot of memory being used by already expired keys and never accessed by clients.
This commit is contained in:
parent
08b107e405
commit
2d851333a6
24
src/redis.c
24
src/redis.c
@ -648,19 +648,31 @@ void updateDictResizePolicy(void) {
|
|||||||
* No more than REDIS_DBCRON_DBS_PER_CALL databases are tested at every
|
* No more than REDIS_DBCRON_DBS_PER_CALL databases are tested at every
|
||||||
* iteration. */
|
* iteration. */
|
||||||
void activeExpireCycle(void) {
|
void activeExpireCycle(void) {
|
||||||
static unsigned int current_db = 0;
|
/* This function has some global state in order to continue the work
|
||||||
|
* incrementally across calls. */
|
||||||
|
static unsigned int current_db = 0; /* Last DB tested. */
|
||||||
|
static int timelimit_exit = 0; /* Time limit hit in previous call? */
|
||||||
|
|
||||||
unsigned int j, iteration = 0;
|
unsigned int j, iteration = 0;
|
||||||
unsigned int dbs_per_call = REDIS_DBCRON_DBS_PER_CALL;
|
unsigned int dbs_per_call = REDIS_DBCRON_DBS_PER_CALL;
|
||||||
long long start = ustime(), timelimit;
|
long long start = ustime(), timelimit;
|
||||||
|
|
||||||
/* Don't test more DBs than we have. */
|
/* We usually should test REDIS_DBCRON_DBS_PER_CALL per iteration, with
|
||||||
if (dbs_per_call > server.dbnum) dbs_per_call = server.dbnum;
|
* two exceptions:
|
||||||
|
*
|
||||||
|
* 1) Don't test more DBs than we have.
|
||||||
|
* 2) If last time we hit the time limit, we want to scan all DBs
|
||||||
|
* in this iteration, as there is work to do in some DB and we don't want
|
||||||
|
* expired keys to use memory for too much time. */
|
||||||
|
if (dbs_per_call > server.dbnum || timelimit_exit)
|
||||||
|
dbs_per_call = server.dbnum;
|
||||||
|
|
||||||
/* We can use at max REDIS_EXPIRELOOKUPS_TIME_PERC percentage of CPU time
|
/* We can use at max REDIS_EXPIRELOOKUPS_TIME_PERC percentage of CPU time
|
||||||
* per iteration. Since this function gets called with a frequency of
|
* per iteration. Since this function gets called with a frequency of
|
||||||
* server.hz times per second, the following is the max amount of
|
* server.hz times per second, the following is the max amount of
|
||||||
* microseconds we can spend in this function. */
|
* microseconds we can spend in this function. */
|
||||||
timelimit = 1000000*REDIS_EXPIRELOOKUPS_TIME_PERC/server.hz/100;
|
timelimit = 1000000*REDIS_EXPIRELOOKUPS_TIME_PERC/server.hz/100;
|
||||||
|
timelimit_exit = 0;
|
||||||
if (timelimit <= 0) timelimit = 1;
|
if (timelimit <= 0) timelimit = 1;
|
||||||
|
|
||||||
for (j = 0; j < dbs_per_call; j++) {
|
for (j = 0; j < dbs_per_call; j++) {
|
||||||
@ -718,7 +730,11 @@ void activeExpireCycle(void) {
|
|||||||
* caller waiting for the other active expire cycle. */
|
* caller waiting for the other active expire cycle. */
|
||||||
iteration++;
|
iteration++;
|
||||||
if ((iteration & 0xf) == 0 && /* check once every 16 iterations. */
|
if ((iteration & 0xf) == 0 && /* check once every 16 iterations. */
|
||||||
(ustime()-start) > timelimit) return;
|
(ustime()-start) > timelimit)
|
||||||
|
{
|
||||||
|
timelimit_exit = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
} while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/4);
|
} while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user