Commit a8a981a8 authored by antirez's avatar antirez
Browse files

Impovements for: Redis timer, hashes rehashing, keys collection.

A previous commit introduced REDIS_HZ define that changes the frequency
of calls to the serverCron() Redis function. This commit improves
different related things:

1) Software watchdog: now the minimal period can be set according to
REDIS_HZ. The minimal period is two times the timer period, that is:

    (1000/REDIS_HZ)*2 milliseconds

2) The incremental rehashing is now performed in the expires dictionary
as well.

3) The activeExpireCycle() function was improved in different ways:

- Now it checks if it already used too much time using microseconds
  instead of milliseconds for better precision.
- The time limit is now calculated correctly, in the previous version
  the division was performed before of the multiplication resulting in
  a timelimit of 0 if HZ was big enough.
- Databases with less than 1% of buckets fill in the hash table are
  skipped, because getting random keys is too expensive in this
  condition.

4) tryResizeHashTabl...
parent f7f2b261
...@@ -722,6 +722,8 @@ void watchdogScheduleSignal(int period) { ...@@ -722,6 +722,8 @@ void watchdogScheduleSignal(int period) {
/* Enable the software watchdong with the specified period in milliseconds. */ /* Enable the software watchdong with the specified period in milliseconds. */
void enableWatchdog(int period) { void enableWatchdog(int period) {
int min_period;
if (server.watchdog_period == 0) { if (server.watchdog_period == 0) {
struct sigaction act; struct sigaction act;
...@@ -732,7 +734,11 @@ void enableWatchdog(int period) { ...@@ -732,7 +734,11 @@ void enableWatchdog(int period) {
act.sa_sigaction = watchdogSignalHandler; act.sa_sigaction = watchdogSignalHandler;
sigaction(SIGALRM, &act, NULL); sigaction(SIGALRM, &act, NULL);
} }
if (period < 200) period = 200; /* We don't accept periods < 200 ms. */ /* If the configured period is smaller than twice the timer period, it is
* too short for the software watchdog to work reliably. Fix it now
* if needed. */
min_period = (1000/REDIS_HZ)*2;
if (period < min_period) period = min_period;
watchdogScheduleSignal(period); /* Adjust the current timer. */ watchdogScheduleSignal(period); /* Adjust the current timer. */
server.watchdog_period = period; server.watchdog_period = period;
} }
......
...@@ -581,10 +581,16 @@ void incrementallyRehash(void) { ...@@ -581,10 +581,16 @@ void incrementallyRehash(void) {
int j; int j;
for (j = 0; j < server.dbnum; j++) { for (j = 0; j < server.dbnum; j++) {
/* Keys dictionary */
if (dictIsRehashing(server.db[j].dict)) { if (dictIsRehashing(server.db[j].dict)) {
dictRehashMilliseconds(server.db[j].dict,1); dictRehashMilliseconds(server.db[j].dict,1);
break; /* already used our millisecond for this loop... */ break; /* already used our millisecond for this loop... */
} }
/* Expires */
if (dictIsRehashing(server.db[j].expires)) {
dictRehashMilliseconds(server.db[j].expires,1);
break; /* already used our millisecond for this loop... */
}
} }
} }
...@@ -609,13 +615,13 @@ void updateDictResizePolicy(void) { ...@@ -609,13 +615,13 @@ void updateDictResizePolicy(void) {
* keys that can be removed from the keyspace. */ * keys that can be removed from the keyspace. */
void activeExpireCycle(void) { void activeExpireCycle(void) {
int j; int j;
long long start = mstime(), timelimit; long long start = ustime(), timelimit;
/* 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
* REDIS_HZ times per second, the following is the max amount of * REDIS_HZ times per second, the following is the max amount of
* milliseconds we can spend here: */ * microseconds we can spend in this function. */
timelimit = (1000/REDIS_HZ/100)*REDIS_EXPIRELOOKUPS_TIME_PERC; timelimit = 1000000*REDIS_EXPIRELOOKUPS_TIME_PERC/REDIS_HZ/100;
if (timelimit <= 0) timelimit = 1; if (timelimit <= 0) timelimit = 1;
for (j = 0; j < server.dbnum; j++) { for (j = 0; j < server.dbnum; j++) {
...@@ -625,9 +631,16 @@ void activeExpireCycle(void) { ...@@ -625,9 +631,16 @@ void activeExpireCycle(void) {
/* Continue to expire if at the end of the cycle more than 25% /* Continue to expire if at the end of the cycle more than 25%
* of the keys were expired. */ * of the keys were expired. */
do { do {
long num = dictSize(db->expires); unsigned long num = dictSize(db->expires);
unsigned long slots = dictSlots(db->expires);
long long now = mstime(); long long now = mstime();
/* When there are less than 1% filled slots getting random
* keys is expensive, so stop here waiting for better times...
* The dictionary will be resized asap. */
if (num && slots > DICT_HT_INITIAL_SIZE &&
(num*100/slots < 1)) break;
expired = 0; expired = 0;
if (num > REDIS_EXPIRELOOKUPS_PER_CRON) if (num > REDIS_EXPIRELOOKUPS_PER_CRON)
num = REDIS_EXPIRELOOKUPS_PER_CRON; num = REDIS_EXPIRELOOKUPS_PER_CRON;
...@@ -653,7 +666,7 @@ void activeExpireCycle(void) { ...@@ -653,7 +666,7 @@ void activeExpireCycle(void) {
* caller waiting for the other active expire cycle. */ * caller waiting for the other active expire cycle. */
iteration++; iteration++;
if ((iteration & 0xff) == 0 && /* Check once every 255 iterations */ if ((iteration & 0xff) == 0 && /* Check once every 255 iterations */
(mstime()-start) > timelimit) return; (ustime()-start) > timelimit) return;
} while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/4); } while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/4);
} }
} }
...@@ -856,7 +869,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { ...@@ -856,7 +869,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
* a lot of memory movements in the parent will cause a lot of pages * a lot of memory movements in the parent will cause a lot of pages
* copied. */ * copied. */
if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) { if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) {
run_with_period(1000) tryResizeHashTables(); tryResizeHashTables();
if (server.activerehashing) incrementallyRehash(); if (server.activerehashing) incrementallyRehash();
} }
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#define REDIS_ERR -1 #define REDIS_ERR -1
/* Static server configuration */ /* Static server configuration */
#define REDIS_HZ 10 /* Time interrupt calls/sec. */ #define REDIS_HZ 100 /* Time interrupt calls/sec. */
#define REDIS_SERVERPORT 6379 /* TCP port */ #define REDIS_SERVERPORT 6379 /* TCP port */
#define REDIS_MAXIDLETIME 0 /* default client timeout: infinite */ #define REDIS_MAXIDLETIME 0 /* default client timeout: infinite */
#define REDIS_DEFAULT_DBNUM 16 #define REDIS_DEFAULT_DBNUM 16
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment