]> git.saurik.com Git - redis.git/commitdiff
Impovements for: Redis timer, hashes rehashing, keys collection.
authorantirez <antirez@gmail.com>
Sun, 13 May 2012 19:52:35 +0000 (21:52 +0200)
committerantirez <antirez@gmail.com>
Sun, 13 May 2012 19:52:35 +0000 (21:52 +0200)
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) tryResizeHashTables() is now called at every timer call, we need to
   match the number of calls we do to the expired keys colleciton cycle.

5) REDIS_HZ was raised to 100.

src/debug.c
src/redis.c
src/redis.h

index 42a73883d9d6f0f7ef3eba8511ab7f750de7428b..4687fb6c072ff17e81070da0cd8f9f699ee7138a 100644 (file)
@@ -722,6 +722,8 @@ void watchdogScheduleSignal(int period) {
 
 /* Enable the software watchdong with the specified period in milliseconds. */
 void enableWatchdog(int period) {
+    int min_period;
+
     if (server.watchdog_period == 0) {
         struct sigaction act;
 
@@ -732,7 +734,11 @@ void enableWatchdog(int period) {
         act.sa_sigaction = watchdogSignalHandler;
         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. */
     server.watchdog_period = period;
 }
index bf36c84e6168657ee20d72d8a574ec67beeacfc0..45ed36c9de13659943f89c2ffc112d1e49499622 100644 (file)
@@ -594,10 +594,16 @@ void incrementallyRehash(void) {
     int j;
 
     for (j = 0; j < server.dbnum; j++) {
+        /* Keys dictionary */
         if (dictIsRehashing(server.db[j].dict)) {
             dictRehashMilliseconds(server.db[j].dict,1);
             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... */
+        }
     }
 }
 
@@ -622,13 +628,13 @@ void updateDictResizePolicy(void) {
  * keys that can be removed from the keyspace. */
 void activeExpireCycle(void) {
     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
      * per iteration. Since this function gets called with a frequency of
      * REDIS_HZ times per second, the following is the max amount of
-     * milliseconds we can spend here: */
-    timelimit = (1000/REDIS_HZ/100)*REDIS_EXPIRELOOKUPS_TIME_PERC;
+     * microseconds we can spend in this function. */
+    timelimit = 1000000*REDIS_EXPIRELOOKUPS_TIME_PERC/REDIS_HZ/100;
     if (timelimit <= 0) timelimit = 1;
 
     for (j = 0; j < server.dbnum; j++) {
@@ -638,9 +644,16 @@ void activeExpireCycle(void) {
         /* Continue to expire if at the end of the cycle more than 25%
          * of the keys were expired. */
         do {
-            long num = dictSize(db->expires);
+            unsigned long num = dictSize(db->expires);
+            unsigned long slots = dictSlots(db->expires);
             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;
             if (num > REDIS_EXPIRELOOKUPS_PER_CRON)
                 num = REDIS_EXPIRELOOKUPS_PER_CRON;
@@ -666,7 +679,7 @@ void activeExpireCycle(void) {
              * caller waiting for the other active expire cycle. */
             iteration++;
             if ((iteration & 0xff) == 0 && /* Check once every 255 iterations */
-                (mstime()-start) > timelimit) return;
+                (ustime()-start) > timelimit) return;
         } while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/4);
     }
 }
@@ -869,7 +882,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
      * copied. */
     if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) {
-        run_with_period(1000) tryResizeHashTables();
+        tryResizeHashTables();
         if (server.activerehashing) incrementallyRehash();
     }
 
index dad8eb0c43bc74960411fa87ede09a08fce9e588..e279aab48c5b7dccb10bf46e2091a394663a4e0a 100644 (file)
@@ -38,7 +38,7 @@
 #define REDIS_ERR               -1
 
 /* 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_MAXIDLETIME       0       /* default client timeout: infinite */
 #define REDIS_DEFAULT_DBNUM     16