Merge pull request #6486 from oranagra/module_lru_lfu

Module API for controlling LRU and LFU, and OpenKey without TOUCH
This commit is contained in:
Salvatore Sanfilippo 2019-11-04 11:05:08 +01:00 committed by GitHub
commit 720d1fd3bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 6 deletions

View File

@ -151,9 +151,13 @@ robj *lookupKeyRead(redisDb *db, robj *key) {
* *
* Returns the linked value object if the key exists or NULL if the key * Returns the linked value object if the key exists or NULL if the key
* does not exist in the specified DB. */ * does not exist in the specified DB. */
robj *lookupKeyWrite(redisDb *db, robj *key) { robj *lookupKeyWriteWithFlags(redisDb *db, robj *key, int flags) {
expireIfNeeded(db,key); expireIfNeeded(db,key);
return lookupKey(db,key,LOOKUP_NONE); return lookupKey(db,key,flags);
}
robj *lookupKeyWrite(redisDb *db, robj *key) {
return lookupKeyWriteWithFlags(db, key, LOOKUP_NONE);
} }
robj *lookupKeyReadOrReply(client *c, robj *key, robj *reply) { robj *lookupKeyReadOrReply(client *c, robj *key, robj *reply) {

View File

@ -1865,11 +1865,12 @@ int RM_SelectDb(RedisModuleCtx *ctx, int newid) {
void *RM_OpenKey(RedisModuleCtx *ctx, robj *keyname, int mode) { void *RM_OpenKey(RedisModuleCtx *ctx, robj *keyname, int mode) {
RedisModuleKey *kp; RedisModuleKey *kp;
robj *value; robj *value;
int flags = mode & REDISMODULE_OPEN_KEY_NOTOUCH? LOOKUP_NOTOUCH: 0;
if (mode & REDISMODULE_WRITE) { if (mode & REDISMODULE_WRITE) {
value = lookupKeyWrite(ctx->client->db,keyname); value = lookupKeyWriteWithFlags(ctx->client->db,keyname, flags);
} else { } else {
value = lookupKeyRead(ctx->client->db,keyname); value = lookupKeyReadWithFlags(ctx->client->db,keyname, flags);
if (value == NULL) { if (value == NULL) {
return NULL; return NULL;
} }
@ -6710,6 +6711,38 @@ size_t moduleCount(void) {
return dictSize(modules); return dictSize(modules);
} }
/* Set the key LRU/LFU depending on server.maxmemory_policy.
* The lru_idle arg is idle time in seconds, and is only relevant if the
* eviction policy is LRU based.
* The lfu_freq arg is a logarithmic counter that provides an indication of
* the access frequencyonly (must be <= 255) and is only relevant if the
* eviction policy is LFU based.
* Either or both of them may be <0, in that case, nothing is set. */
/* return value is an indication if the lru field was updated or not. */
int RM_SetLRUOrLFU(RedisModuleKey *key, long long lfu_freq, long long lru_idle) {
if (!key->value)
return REDISMODULE_ERR;
if (objectSetLRUOrLFU(key->value, lfu_freq, lru_idle, lru_idle>=0 ? LRU_CLOCK() : 0))
return REDISMODULE_OK;
return REDISMODULE_ERR;
}
/* Gets the key LRU or LFU (depending on the current eviction policy).
* One will be set to the appropiate return value, and the other will be set to -1.
* see RedisModule_SetLRUOrLFU for units and ranges.
* return value is an indication of success. */
int RM_GetLRUOrLFU(RedisModuleKey *key, long long *lfu_freq, long long *lru_idle) {
*lru_idle = *lfu_freq = -1;
if (!key->value)
return REDISMODULE_ERR;
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
*lfu_freq = LFUDecrAndReturn(key->value);
} else {
*lru_idle = estimateObjectIdleTime(key->value)/1000;
}
return REDISMODULE_OK;
}
/* Register all the APIs we export. Keep this function at the end of the /* Register all the APIs we export. Keep this function at the end of the
* file so that's easy to seek it to add new entries. */ * file so that's easy to seek it to add new entries. */
void moduleRegisterCoreAPI(void) { void moduleRegisterCoreAPI(void) {
@ -6906,6 +6939,8 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(GetClientInfoById); REGISTER_API(GetClientInfoById);
REGISTER_API(PublishMessage); REGISTER_API(PublishMessage);
REGISTER_API(SubscribeToServerEvent); REGISTER_API(SubscribeToServerEvent);
REGISTER_API(SetLRUOrLFU);
REGISTER_API(GetLRUOrLFU);
REGISTER_API(BlockClientOnKeys); REGISTER_API(BlockClientOnKeys);
REGISTER_API(SignalKeyAsReady); REGISTER_API(SignalKeyAsReady);
REGISTER_API(GetBlockedClientReadyKey); REGISTER_API(GetBlockedClientReadyKey);

View File

@ -1209,12 +1209,13 @@ sds getMemoryDoctorReport(void) {
* The lru_idle and lru_clock args are only relevant if policy * The lru_idle and lru_clock args are only relevant if policy
* is MAXMEMORY_FLAG_LRU. * is MAXMEMORY_FLAG_LRU.
* Either or both of them may be <0, in that case, nothing is set. */ * Either or both of them may be <0, in that case, nothing is set. */
void objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle, int objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle,
long long lru_clock) { long long lru_clock) {
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) { if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
if (lfu_freq >= 0) { if (lfu_freq >= 0) {
serverAssert(lfu_freq <= 255); serverAssert(lfu_freq <= 255);
val->lru = (LFUGetTimeInMinutes()<<8) | lfu_freq; val->lru = (LFUGetTimeInMinutes()<<8) | lfu_freq;
return 1;
} }
} else if (lru_idle >= 0) { } else if (lru_idle >= 0) {
/* Provided LRU idle time is in seconds. Scale /* Provided LRU idle time is in seconds. Scale
@ -1231,7 +1232,9 @@ void objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle,
if (lru_abs < 0) if (lru_abs < 0)
lru_abs = (lru_clock+(LRU_CLOCK_MAX/2)) % LRU_CLOCK_MAX; lru_abs = (lru_clock+(LRU_CLOCK_MAX/2)) % LRU_CLOCK_MAX;
val->lru = lru_abs; val->lru = lru_abs;
return 1;
} }
return 0;
} }
/* ======================= The OBJECT and MEMORY commands =================== */ /* ======================= The OBJECT and MEMORY commands =================== */

View File

@ -18,6 +18,10 @@
#define REDISMODULE_READ (1<<0) #define REDISMODULE_READ (1<<0)
#define REDISMODULE_WRITE (1<<1) #define REDISMODULE_WRITE (1<<1)
/* RedisModule_OpenKey extra flags for the 'mode' argument.
* Avoid touching the LRU/LFU of the key when opened. */
#define REDISMODULE_OPEN_KEY_NOTOUCH (1<<16)
#define REDISMODULE_LIST_HEAD 0 #define REDISMODULE_LIST_HEAD 0
#define REDISMODULE_LIST_TAIL 1 #define REDISMODULE_LIST_TAIL 1
@ -577,6 +581,8 @@ int REDISMODULE_API_FUNC(RedisModule_InfoAddFieldDouble)(RedisModuleInfoCtx *ctx
int REDISMODULE_API_FUNC(RedisModule_InfoAddFieldLongLong)(RedisModuleInfoCtx *ctx, char *field, long long value); int REDISMODULE_API_FUNC(RedisModule_InfoAddFieldLongLong)(RedisModuleInfoCtx *ctx, char *field, long long value);
int REDISMODULE_API_FUNC(RedisModule_InfoAddFieldULongLong)(RedisModuleInfoCtx *ctx, char *field, unsigned long long value); int REDISMODULE_API_FUNC(RedisModule_InfoAddFieldULongLong)(RedisModuleInfoCtx *ctx, char *field, unsigned long long value);
int REDISMODULE_API_FUNC(RedisModule_SubscribeToServerEvent)(RedisModuleCtx *ctx, RedisModuleEvent event, RedisModuleEventCallback callback); int REDISMODULE_API_FUNC(RedisModule_SubscribeToServerEvent)(RedisModuleCtx *ctx, RedisModuleEvent event, RedisModuleEventCallback callback);
int REDISMODULE_API_FUNC(RedisModule_SetLRUOrLFU)(RedisModuleKey *key, long long lfu_freq, long long lru_idle);
int REDISMODULE_API_FUNC(RedisModule_GetLRUOrLFU)(RedisModuleKey *key, long long *lfu_freq, long long *lru_idle);
RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClientOnKeys)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms, RedisModuleString **keys, int numkeys, void *privdata); RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClientOnKeys)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms, RedisModuleString **keys, int numkeys, void *privdata);
void REDISMODULE_API_FUNC(RedisModule_SignalKeyAsReady)(RedisModuleCtx *ctx, RedisModuleString *key); void REDISMODULE_API_FUNC(RedisModule_SignalKeyAsReady)(RedisModuleCtx *ctx, RedisModuleString *key);
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientReadyKey)(RedisModuleCtx *ctx); RedisModuleString *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientReadyKey)(RedisModuleCtx *ctx);
@ -784,6 +790,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(GetClientInfoById); REDISMODULE_GET_API(GetClientInfoById);
REDISMODULE_GET_API(PublishMessage); REDISMODULE_GET_API(PublishMessage);
REDISMODULE_GET_API(SubscribeToServerEvent); REDISMODULE_GET_API(SubscribeToServerEvent);
REDISMODULE_GET_API(SetLRUOrLFU);
REDISMODULE_GET_API(GetLRUOrLFU);
REDISMODULE_GET_API(BlockClientOnKeys); REDISMODULE_GET_API(BlockClientOnKeys);
REDISMODULE_GET_API(SignalKeyAsReady); REDISMODULE_GET_API(SignalKeyAsReady);
REDISMODULE_GET_API(GetBlockedClientReadyKey); REDISMODULE_GET_API(GetBlockedClientReadyKey);

View File

@ -2085,9 +2085,10 @@ robj *lookupKeyWrite(redisDb *db, robj *key);
robj *lookupKeyReadOrReply(client *c, robj *key, robj *reply); robj *lookupKeyReadOrReply(client *c, robj *key, robj *reply);
robj *lookupKeyWriteOrReply(client *c, robj *key, robj *reply); robj *lookupKeyWriteOrReply(client *c, robj *key, robj *reply);
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags); robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags);
robj *lookupKeyWriteWithFlags(redisDb *db, robj *key, int flags);
robj *objectCommandLookup(client *c, robj *key); robj *objectCommandLookup(client *c, robj *key);
robj *objectCommandLookupOrReply(client *c, robj *key, robj *reply); robj *objectCommandLookupOrReply(client *c, robj *key, robj *reply);
void objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle, int objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle,
long long lru_clock); long long lru_clock);
#define LOOKUP_NONE 0 #define LOOKUP_NONE 0
#define LOOKUP_NOTOUCH (1<<0) #define LOOKUP_NOTOUCH (1<<0)