Obtain LRU clock in a resolution dependent way.

For testing purposes it is handy to have a very high resolution of the
LRU clock, so that it is possible to experiment with scripts running in
just a few seconds how the eviction algorithms works.

This commit allows Redis to use the cached LRU clock, or a value
computed on demand, depending on the resolution. So normally we have the
good performance of a precomputed value, and a clock that wraps in many
days using the normal resolution, but if needed, changing a define will
switch behavior to an high resolution LRU clock.
This commit is contained in:
antirez 2014-03-20 11:47:12 +01:00
parent 1faf82663f
commit ad6b0f70b2
4 changed files with 25 additions and 19 deletions

View File

@ -50,7 +50,7 @@ robj *lookupKey(redisDb *db, robj *key) {
* Don't do it if we have a saving child, as this will trigger * Don't do it if we have a saving child, as this will trigger
* a copy on write madness. */ * a copy on write madness. */
if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) if (server.rdb_child_pid == -1 && server.aof_child_pid == -1)
val->lru = server.lruclock; val->lru = LRU_CLOCK();
return val; return val;
} else { } else {
return NULL; return NULL;

View File

@ -651,10 +651,11 @@ char *strEncoding(int encoding) {
/* Given an object returns the min number of seconds the object was never /* Given an object returns the min number of seconds the object was never
* requested, using an approximated LRU algorithm. */ * requested, using an approximated LRU algorithm. */
unsigned long long estimateObjectIdleTime(robj *o) { unsigned long long estimateObjectIdleTime(robj *o) {
if (server.lruclock >= o->lru) { unsigned long long lruclock = LRU_CLOCK();
return (server.lruclock - o->lru) * REDIS_LRU_CLOCK_RESOLUTION; if (lruclock >= o->lru) {
return (lruclock - o->lru) * REDIS_LRU_CLOCK_RESOLUTION;
} else { } else {
return ((REDIS_LRU_CLOCK_MAX - o->lru) + server.lruclock) * return (lruclock + (REDIS_LRU_CLOCK_MAX - o->lru)) *
REDIS_LRU_CLOCK_RESOLUTION; REDIS_LRU_CLOCK_RESOLUTION;
} }
} }

View File

@ -843,9 +843,8 @@ void activeExpireCycle(int type) {
} }
} }
void updateLRUClock(void) { unsigned int getLRUClock(void) {
server.lruclock = (mstime()/REDIS_LRU_CLOCK_RESOLUTION) & return (mstime()/REDIS_LRU_CLOCK_RESOLUTION) & REDIS_LRU_CLOCK_MAX;
REDIS_LRU_CLOCK_MAX;
} }
/* Add a sample to the operations per second array of samples. */ /* Add a sample to the operations per second array of samples. */
@ -1044,19 +1043,18 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
run_with_period(100) trackOperationsPerSecond(); run_with_period(100) trackOperationsPerSecond();
/* We have just 22 bits per object for LRU information. /* We have just REDIS_LRU_BITS bits per object for LRU information.
* So we use an (eventually wrapping) LRU clock with 10 seconds resolution. * So we use an (eventually wrapping) LRU clock.
* 2^22 bits with 10 seconds resolution is more or less 1.5 years.
* *
* Note that even if this will wrap after 1.5 years it's not a problem, * Note that even if the counter wraps it's not a big problem,
* everything will still work but just some object will appear younger * everything will still work but some object will appear younger
* to Redis. But for this to happen a given object should never be touched * to Redis. However for this to happen a given object should never be
* for 1.5 years. * touched for all the time needed to the counter to wrap, which is
* not likely.
* *
* Note that you can change the resolution altering the * Note that you can change the resolution altering the
* REDIS_LRU_CLOCK_RESOLUTION define. * REDIS_LRU_CLOCK_RESOLUTION define. */
*/ server.lruclock = getLRUClock();
updateLRUClock();
/* Record the max memory used since the server was started. */ /* Record the max memory used since the server was started. */
if (zmalloc_used_memory() > server.stat_peak_memory) if (zmalloc_used_memory() > server.stat_peak_memory)
@ -1421,7 +1419,7 @@ void initServerConfig() {
server.migrate_cached_sockets = dictCreate(&migrateCacheDictType,NULL); server.migrate_cached_sockets = dictCreate(&migrateCacheDictType,NULL);
server.loading_process_events_interval_bytes = (1024*1024*2); server.loading_process_events_interval_bytes = (1024*1024*2);
updateLRUClock(); server.lruclock = getLRUClock();
resetServerSaveParams(); resetServerSaveParams();
appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */ appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */

View File

@ -394,6 +394,12 @@ typedef struct redisObject {
void *ptr; void *ptr;
} robj; } robj;
/* Macro used to obtain the current LRU clock.
* If the current resolution is lower than the frequency we refresh the
* LRU clock (as it should be in production servers) we return the
* precomputed value, otherwise we need to resort to a function call. */
#define LRU_CLOCK() ((1000/server.hz <= REDIS_LRU_CLOCK_RESOLUTION) ? server.lruclock : getLRUClock())
/* Macro used to initialize a Redis object allocated on the stack. /* Macro used to initialize a Redis object allocated on the stack.
* Note that this macro is taken near the structure definition to make sure * Note that this macro is taken near the structure definition to make sure
* we'll update it when the structure is changed, to avoid bugs like * we'll update it when the structure is changed, to avoid bugs like
@ -1055,7 +1061,7 @@ char *strEncoding(int encoding);
int compareStringObjects(robj *a, robj *b); int compareStringObjects(robj *a, robj *b);
int collateStringObjects(robj *a, robj *b); int collateStringObjects(robj *a, robj *b);
int equalStringObjects(robj *a, robj *b); int equalStringObjects(robj *a, robj *b);
unsigned long estimateObjectIdleTime(robj *o); unsigned long long estimateObjectIdleTime(robj *o);
#define sdsEncodedObject(objptr) (objptr->encoding == REDIS_ENCODING_RAW || objptr->encoding == REDIS_ENCODING_EMBSTR) #define sdsEncodedObject(objptr) (objptr->encoding == REDIS_ENCODING_RAW || objptr->encoding == REDIS_ENCODING_EMBSTR)
/* Synchronous I/O with timeout */ /* Synchronous I/O with timeout */
@ -1156,6 +1162,7 @@ void adjustOpenFilesLimit(void);
void closeListeningSockets(int unlink_unix_socket); void closeListeningSockets(int unlink_unix_socket);
void updateCachedTime(void); void updateCachedTime(void);
void resetServerStats(void); void resetServerStats(void);
unsigned int getLRUClock(void);
/* Set data type */ /* Set data type */
robj *setTypeCreate(robj *value); robj *setTypeCreate(robj *value);