Commit a67957ed authored by Viktor Söderqvist's avatar Viktor Söderqvist
Browse files

Let active expire cycle use dictScan instead of messing with internals

parent c84248b5
...@@ -110,6 +110,33 @@ int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) { ...@@ -110,6 +110,33 @@ int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
#define ACTIVE_EXPIRE_CYCLE_ACCEPTABLE_STALE 10 /* % of stale keys after which #define ACTIVE_EXPIRE_CYCLE_ACCEPTABLE_STALE 10 /* % of stale keys after which
we do extra efforts. */ we do extra efforts. */
/* Data used by the expire dict scan callback. */
typedef struct {
redisDb *db;
long long now;
unsigned long sampled; /* num keys checked */
unsigned long expired; /* num keys expired */
long long ttl_sum; /* sum of ttl for key with ttl not yet expired */
int ttl_samples; /* num keys with ttl not yet expired */
} expireScanData;
void expireScanCallback(void *privdata, const dictEntry *const_de) {
dictEntry *de = (dictEntry *)const_de;
expireScanData *data = privdata;
long long ttl = dictGetSignedIntegerVal(de) - data->now;
if (activeExpireCycleTryExpire(data->db, de, data->now)) {
data->expired++;
/* Propagate the DEL command */
postExecutionUnitOperations();
}
if (ttl > 0) {
/* We want the average TTL of keys yet not expired. */
data->ttl_sum += ttl;
data->ttl_samples++;
}
data->sampled++;
}
void activeExpireCycle(int type) { void activeExpireCycle(int type) {
/* Adjust the running parameters according to the configured expire /* Adjust the running parameters according to the configured expire
* effort. The default effort is 1, and the maximum configurable effort * effort. The default effort is 1, and the maximum configurable effort
...@@ -186,10 +213,11 @@ void activeExpireCycle(int type) { ...@@ -186,10 +213,11 @@ void activeExpireCycle(int type) {
serverAssert(server.also_propagate.numops == 0); serverAssert(server.also_propagate.numops == 0);
for (j = 0; j < dbs_per_call && timelimit_exit == 0; j++) { for (j = 0; j < dbs_per_call && timelimit_exit == 0; j++) {
/* Expired and checked in a single loop. */ /* Scan callback data including expired and checked count per iteration. */
unsigned long expired, sampled; expireScanData data;
redisDb *db = server.db+(current_db % server.dbnum); redisDb *db = server.db+(current_db % server.dbnum);
data.db = db;
/* Increment the DB now so we are sure if we run out of time /* Increment the DB now so we are sure if we run out of time
* in the current DB we'll restart from the next. This allows to * in the current DB we'll restart from the next. This allows to
...@@ -202,8 +230,6 @@ void activeExpireCycle(int type) { ...@@ -202,8 +230,6 @@ void activeExpireCycle(int type) {
* is not fixed, but depends on the Redis configured "expire effort". */ * is not fixed, but depends on the Redis configured "expire effort". */
do { do {
unsigned long num, slots; unsigned long num, slots;
long long now, ttl_sum;
int ttl_samples;
iteration++; iteration++;
/* If there is nothing to expire try next DB ASAP. */ /* If there is nothing to expire try next DB ASAP. */
...@@ -212,7 +238,7 @@ void activeExpireCycle(int type) { ...@@ -212,7 +238,7 @@ void activeExpireCycle(int type) {
break; break;
} }
slots = dictSlots(db->expires); slots = dictSlots(db->expires);
now = mstime(); data.now = mstime();
/* When there are less than 1% filled slots, sampling the key /* When there are less than 1% filled slots, sampling the key
* space is expensive, so stop here waiting for better times... * space is expensive, so stop here waiting for better times...
...@@ -220,12 +246,12 @@ void activeExpireCycle(int type) { ...@@ -220,12 +246,12 @@ void activeExpireCycle(int type) {
if (slots > DICT_HT_INITIAL_SIZE && if (slots > DICT_HT_INITIAL_SIZE &&
(num*100/slots < 1)) break; (num*100/slots < 1)) break;
/* The main collection cycle. Sample random keys among keys /* The main collection cycle. Scan through keys among keys
* with an expire set, checking for expired ones. */ * with an expire set, checking for expired ones. */
expired = 0; data.sampled = 0;
sampled = 0; data.expired = 0;
ttl_sum = 0; data.ttl_sum = 0;
ttl_samples = 0; data.ttl_samples = 0;
if (num > config_keys_per_loop) if (num > config_keys_per_loop)
num = config_keys_per_loop; num = config_keys_per_loop;
...@@ -243,46 +269,17 @@ void activeExpireCycle(int type) { ...@@ -243,46 +269,17 @@ void activeExpireCycle(int type) {
long max_buckets = num*20; long max_buckets = num*20;
long checked_buckets = 0; long checked_buckets = 0;
while (sampled < num && checked_buckets < max_buckets) { while (data.sampled < num && checked_buckets < max_buckets) {
for (int table = 0; table < 2; table++) { db->expires_cursor = dictScan(db->expires, db->expires_cursor,
if (table == 1 && !dictIsRehashing(db->expires)) break; expireScanCallback, NULL, &data);
checked_buckets++;
unsigned long idx = db->expires_cursor;
idx &= DICTHT_SIZE_MASK(db->expires->ht_size_exp[table]);
dictEntry *de = db->expires->ht_table[table][idx];
long long ttl;
/* Scan the current bucket of the current table. */
checked_buckets++;
while(de) {
/* Get the next entry now since this entry may get
* deleted. */
dictEntry *e = de;
de = dictGetNext(de);
ttl = dictGetSignedIntegerVal(e)-now;
if (activeExpireCycleTryExpire(db,e,now)) {
expired++;
/* Propagate the DEL command */
postExecutionUnitOperations();
}
if (ttl > 0) {
/* We want the average TTL of keys yet
* not expired. */
ttl_sum += ttl;
ttl_samples++;
}
sampled++;
}
}
db->expires_cursor++;
} }
total_expired += expired; total_expired += data.expired;
total_sampled += sampled; total_sampled += data.sampled;
/* Update the average TTL stats for this database. */ /* Update the average TTL stats for this database. */
if (ttl_samples) { if (data.ttl_samples) {
long long avg_ttl = ttl_sum/ttl_samples; long long avg_ttl = data.ttl_sum / data.ttl_samples;
/* Do a simple running average with a few samples. /* Do a simple running average with a few samples.
* We just use the current estimate with a weight of 2% * We just use the current estimate with a weight of 2%
...@@ -305,8 +302,8 @@ void activeExpireCycle(int type) { ...@@ -305,8 +302,8 @@ void activeExpireCycle(int type) {
/* We don't repeat the cycle for the current database if there are /* We don't repeat the cycle for the current database if there are
* an acceptable amount of stale keys (logically expired but yet * an acceptable amount of stale keys (logically expired but yet
* not reclaimed). */ * not reclaimed). */
} while (sampled == 0 || } while (data.sampled == 0 ||
(expired*100/sampled) > config_cycle_acceptable_stale); (data.expired * 100 / data.sampled) > config_cycle_acceptable_stale);
} }
elapsed = ustime()-start; elapsed = ustime()-start;
......
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