mirror of https://mirror.osredm.com/root/redis.git
Match REDISMODULE_OPEN_KEY_* flags to LOOKUP_* flags (#11772)
The PR adds support for the following flags on RedisModule_OpenKey: * REDISMODULE_OPEN_KEY_NONOTIFY - Don't trigger keyspace event on key misses. * REDISMODULE_OPEN_KEY_NOSTATS - Don't update keyspace hits/misses counters. * REDISMODULE_OPEN_KEY_NOEXPIRE - Avoid deleting lazy expired keys. * REDISMODULE_OPEN_KEY_NOEFFECTS - Avoid any effects from fetching the key In addition, added `RM_GetOpenKeyModesAll`, which returns the mask of all supported OpenKey modes. This allows the module to check, in runtime, which OpenKey modes are supported by the current Redis instance.
This commit is contained in:
parent
66bed3f220
commit
5c3938d5cc
|
@ -544,7 +544,7 @@ static void handleClientsBlockedOnKey(readyList *rl) {
|
||||||
|
|
||||||
while((ln = listNext(&li))) {
|
while((ln = listNext(&li))) {
|
||||||
client *receiver = listNodeValue(ln);
|
client *receiver = listNodeValue(ln);
|
||||||
robj *o = lookupKeyReadWithFlags(rl->db, rl->key, LOKKUP_NOEFFECTS);
|
robj *o = lookupKeyReadWithFlags(rl->db, rl->key, LOOKUP_NOEFFECTS);
|
||||||
/* 1. In case new key was added/touched we need to verify it satisfy the
|
/* 1. In case new key was added/touched we need to verify it satisfy the
|
||||||
* blocked type, since we might process the wrong key type.
|
* blocked type, since we might process the wrong key type.
|
||||||
* 2. We want to serve clients blocked on module keys
|
* 2. We want to serve clients blocked on module keys
|
||||||
|
|
38
src/module.c
38
src/module.c
|
@ -3783,17 +3783,29 @@ static void moduleInitKeyTypeSpecific(RedisModuleKey *key) {
|
||||||
* The return value is the handle representing the key, that must be
|
* The return value is the handle representing the key, that must be
|
||||||
* closed with RM_CloseKey().
|
* closed with RM_CloseKey().
|
||||||
*
|
*
|
||||||
* If the key does not exist and WRITE mode is requested, the handle
|
* If the key does not exist and REDISMODULE_WRITE mode is requested, the handle
|
||||||
* is still returned, since it is possible to perform operations on
|
* is still returned, since it is possible to perform operations on
|
||||||
* a yet not existing key (that will be created, for example, after
|
* a yet not existing key (that will be created, for example, after
|
||||||
* a list push operation). If the mode is just READ instead, and the
|
* a list push operation). If the mode is just REDISMODULE_READ instead, and the
|
||||||
* key does not exist, NULL is returned. However it is still safe to
|
* key does not exist, NULL is returned. However it is still safe to
|
||||||
* call RedisModule_CloseKey() and RedisModule_KeyType() on a NULL
|
* call RedisModule_CloseKey() and RedisModule_KeyType() on a NULL
|
||||||
* value. */
|
* value.
|
||||||
|
*
|
||||||
|
* Extra flags that can be pass to the API under the mode argument:
|
||||||
|
* * REDISMODULE_OPEN_KEY_NOTOUCH - Avoid touching the LRU/LFU of the key when opened.
|
||||||
|
* * REDISMODULE_OPEN_KEY_NONOTIFY - Don't trigger keyspace event on key misses.
|
||||||
|
* * REDISMODULE_OPEN_KEY_NOSTATS - Don't update keyspace hits/misses counters.
|
||||||
|
* * REDISMODULE_OPEN_KEY_NOEXPIRE - Avoid deleting lazy expired keys.
|
||||||
|
* * REDISMODULE_OPEN_KEY_NOEFFECTS - Avoid any effects from fetching the key. */
|
||||||
RedisModuleKey *RM_OpenKey(RedisModuleCtx *ctx, robj *keyname, int mode) {
|
RedisModuleKey *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;
|
int flags = 0;
|
||||||
|
flags |= (mode & REDISMODULE_OPEN_KEY_NOTOUCH? LOOKUP_NOTOUCH: 0);
|
||||||
|
flags |= (mode & REDISMODULE_OPEN_KEY_NONOTIFY? LOOKUP_NONOTIFY: 0);
|
||||||
|
flags |= (mode & REDISMODULE_OPEN_KEY_NOSTATS? LOOKUP_NOSTATS: 0);
|
||||||
|
flags |= (mode & REDISMODULE_OPEN_KEY_NOEXPIRE? LOOKUP_NOEXPIRE: 0);
|
||||||
|
flags |= (mode & REDISMODULE_OPEN_KEY_NOEFFECTS? LOOKUP_NOEFFECTS: 0);
|
||||||
|
|
||||||
if (mode & REDISMODULE_WRITE) {
|
if (mode & REDISMODULE_WRITE) {
|
||||||
value = lookupKeyWriteWithFlags(ctx->client->db,keyname, flags);
|
value = lookupKeyWriteWithFlags(ctx->client->db,keyname, flags);
|
||||||
|
@ -3811,6 +3823,23 @@ RedisModuleKey *RM_OpenKey(RedisModuleCtx *ctx, robj *keyname, int mode) {
|
||||||
return kp;
|
return kp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the full OpenKey modes mask, using the return value
|
||||||
|
* the module can check if a certain set of OpenKey modes are supported
|
||||||
|
* by the redis server version in use.
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* int supportedMode = RM_GetOpenKeyModesAll();
|
||||||
|
* if (supportedMode & REDISMODULE_OPEN_KEY_NOTOUCH) {
|
||||||
|
* // REDISMODULE_OPEN_KEY_NOTOUCH is supported
|
||||||
|
* } else{
|
||||||
|
* // REDISMODULE_OPEN_KEY_NOTOUCH is not supported
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
int RM_GetOpenKeyModesAll() {
|
||||||
|
return _REDISMODULE_OPEN_KEY_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Destroy a RedisModuleKey struct (freeing is the responsibility of the caller). */
|
/* Destroy a RedisModuleKey struct (freeing is the responsibility of the caller). */
|
||||||
static void moduleCloseKey(RedisModuleKey *key) {
|
static void moduleCloseKey(RedisModuleKey *key) {
|
||||||
int signal = SHOULD_SIGNAL_MODIFIED_KEYS(key->ctx);
|
int signal = SHOULD_SIGNAL_MODIFIED_KEYS(key->ctx);
|
||||||
|
@ -12809,6 +12838,7 @@ void moduleRegisterCoreAPI(void) {
|
||||||
REGISTER_API(SelectDb);
|
REGISTER_API(SelectDb);
|
||||||
REGISTER_API(KeyExists);
|
REGISTER_API(KeyExists);
|
||||||
REGISTER_API(OpenKey);
|
REGISTER_API(OpenKey);
|
||||||
|
REGISTER_API(GetOpenKeyModesAll);
|
||||||
REGISTER_API(CloseKey);
|
REGISTER_API(CloseKey);
|
||||||
REGISTER_API(KeyType);
|
REGISTER_API(KeyType);
|
||||||
REGISTER_API(ValueLength);
|
REGISTER_API(ValueLength);
|
||||||
|
|
|
@ -48,6 +48,18 @@ typedef long long ustime_t;
|
||||||
/* RedisModule_OpenKey extra flags for the 'mode' argument.
|
/* RedisModule_OpenKey extra flags for the 'mode' argument.
|
||||||
* Avoid touching the LRU/LFU of the key when opened. */
|
* Avoid touching the LRU/LFU of the key when opened. */
|
||||||
#define REDISMODULE_OPEN_KEY_NOTOUCH (1<<16)
|
#define REDISMODULE_OPEN_KEY_NOTOUCH (1<<16)
|
||||||
|
/* Don't trigger keyspace event on key misses. */
|
||||||
|
#define REDISMODULE_OPEN_KEY_NONOTIFY (1<<17)
|
||||||
|
/* Don't update keyspace hits/misses counters. */
|
||||||
|
#define REDISMODULE_OPEN_KEY_NOSTATS (1<<18)
|
||||||
|
/* Avoid deleting lazy expired keys. */
|
||||||
|
#define REDISMODULE_OPEN_KEY_NOEXPIRE (1<<19)
|
||||||
|
/* Avoid any effects from fetching the key */
|
||||||
|
#define REDISMODULE_OPEN_KEY_NOEFFECTS (1<<20)
|
||||||
|
/* Mask of all REDISMODULE_OPEN_KEY_* values. Any new mode should be added to this list.
|
||||||
|
* Should not be used directly by the module, use RM_GetOpenKeyModesAll instead.
|
||||||
|
* Located here so when we will add new modes we will not forget to update it. */
|
||||||
|
#define _REDISMODULE_OPEN_KEY_ALL REDISMODULE_READ | REDISMODULE_WRITE | REDISMODULE_OPEN_KEY_NOTOUCH | REDISMODULE_OPEN_KEY_NONOTIFY | REDISMODULE_OPEN_KEY_NOSTATS | REDISMODULE_OPEN_KEY_NOEXPIRE | REDISMODULE_OPEN_KEY_NOEFFECTS
|
||||||
|
|
||||||
/* List push and pop */
|
/* List push and pop */
|
||||||
#define REDISMODULE_LIST_HEAD 0
|
#define REDISMODULE_LIST_HEAD 0
|
||||||
|
@ -955,6 +967,7 @@ REDISMODULE_API int (*RedisModule_GetSelectedDb)(RedisModuleCtx *ctx) REDISMODUL
|
||||||
REDISMODULE_API int (*RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid) REDISMODULE_ATTR;
|
REDISMODULE_API int (*RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid) REDISMODULE_ATTR;
|
||||||
REDISMODULE_API int (*RedisModule_KeyExists)(RedisModuleCtx *ctx, RedisModuleString *keyname) REDISMODULE_ATTR;
|
REDISMODULE_API int (*RedisModule_KeyExists)(RedisModuleCtx *ctx, RedisModuleString *keyname) REDISMODULE_ATTR;
|
||||||
REDISMODULE_API RedisModuleKey * (*RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode) REDISMODULE_ATTR;
|
REDISMODULE_API RedisModuleKey * (*RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode) REDISMODULE_ATTR;
|
||||||
|
REDISMODULE_API int (*RedisModule_GetOpenKeyModesAll)() REDISMODULE_ATTR;
|
||||||
REDISMODULE_API void (*RedisModule_CloseKey)(RedisModuleKey *kp) REDISMODULE_ATTR;
|
REDISMODULE_API void (*RedisModule_CloseKey)(RedisModuleKey *kp) REDISMODULE_ATTR;
|
||||||
REDISMODULE_API int (*RedisModule_KeyType)(RedisModuleKey *kp) REDISMODULE_ATTR;
|
REDISMODULE_API int (*RedisModule_KeyType)(RedisModuleKey *kp) REDISMODULE_ATTR;
|
||||||
REDISMODULE_API size_t (*RedisModule_ValueLength)(RedisModuleKey *kp) REDISMODULE_ATTR;
|
REDISMODULE_API size_t (*RedisModule_ValueLength)(RedisModuleKey *kp) REDISMODULE_ATTR;
|
||||||
|
@ -1326,6 +1339,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
|
||||||
REDISMODULE_GET_API(SelectDb);
|
REDISMODULE_GET_API(SelectDb);
|
||||||
REDISMODULE_GET_API(KeyExists);
|
REDISMODULE_GET_API(KeyExists);
|
||||||
REDISMODULE_GET_API(OpenKey);
|
REDISMODULE_GET_API(OpenKey);
|
||||||
|
REDISMODULE_GET_API(GetOpenKeyModesAll);
|
||||||
REDISMODULE_GET_API(CloseKey);
|
REDISMODULE_GET_API(CloseKey);
|
||||||
REDISMODULE_GET_API(KeyType);
|
REDISMODULE_GET_API(KeyType);
|
||||||
REDISMODULE_GET_API(ValueLength);
|
REDISMODULE_GET_API(ValueLength);
|
||||||
|
|
|
@ -3155,7 +3155,7 @@ int objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle,
|
||||||
#define LOOKUP_NOSTATS (1<<2) /* Don't update keyspace hits/misses counters. */
|
#define LOOKUP_NOSTATS (1<<2) /* Don't update keyspace hits/misses counters. */
|
||||||
#define LOOKUP_WRITE (1<<3) /* Delete expired keys even in replicas. */
|
#define LOOKUP_WRITE (1<<3) /* Delete expired keys even in replicas. */
|
||||||
#define LOOKUP_NOEXPIRE (1<<4) /* Avoid deleting lazy expired keys. */
|
#define LOOKUP_NOEXPIRE (1<<4) /* Avoid deleting lazy expired keys. */
|
||||||
#define LOKKUP_NOEFFECTS (LOOKUP_NONOTIFY | LOOKUP_NOSTATS | LOOKUP_NOTOUCH | LOOKUP_NOEXPIRE) /* Avoid any effects from fetching the key */
|
#define LOOKUP_NOEFFECTS (LOOKUP_NONOTIFY | LOOKUP_NOSTATS | LOOKUP_NOTOUCH | LOOKUP_NOEXPIRE) /* Avoid any effects from fetching the key */
|
||||||
|
|
||||||
void dbAdd(redisDb *db, robj *key, robj *val);
|
void dbAdd(redisDb *db, robj *key, robj *val);
|
||||||
int dbAddRDBLoad(redisDb *db, sds key, robj *val);
|
int dbAddRDBLoad(redisDb *db, sds key, robj *val);
|
||||||
|
|
|
@ -8,6 +8,55 @@
|
||||||
|
|
||||||
#define UNUSED(x) (void)(x)
|
#define UNUSED(x) (void)(x)
|
||||||
|
|
||||||
|
static int n_events = 0;
|
||||||
|
|
||||||
|
static int KeySpace_NotificationModuleKeyMissExpired(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) {
|
||||||
|
UNUSED(ctx);
|
||||||
|
UNUSED(type);
|
||||||
|
UNUSED(event);
|
||||||
|
UNUSED(key);
|
||||||
|
n_events++;
|
||||||
|
return REDISMODULE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_clear_n_events(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||||
|
UNUSED(argv);
|
||||||
|
UNUSED(argc);
|
||||||
|
n_events = 0;
|
||||||
|
RedisModule_ReplyWithSimpleString(ctx, "OK");
|
||||||
|
return REDISMODULE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_get_n_events(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||||
|
UNUSED(argv);
|
||||||
|
UNUSED(argc);
|
||||||
|
RedisModule_ReplyWithLongLong(ctx, n_events);
|
||||||
|
return REDISMODULE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_open_key_no_effects(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||||
|
if (argc<2) {
|
||||||
|
RedisModule_WrongArity(ctx);
|
||||||
|
return REDISMODULE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int supportedMode = RedisModule_GetOpenKeyModesAll();
|
||||||
|
if (!(supportedMode & REDISMODULE_READ) || !(supportedMode & REDISMODULE_OPEN_KEY_NOEFFECTS)) {
|
||||||
|
RedisModule_ReplyWithError(ctx, "OpenKey modes are not supported");
|
||||||
|
return REDISMODULE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_OPEN_KEY_NOEFFECTS);
|
||||||
|
if (!key) {
|
||||||
|
RedisModule_ReplyWithError(ctx, "key not found");
|
||||||
|
return REDISMODULE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
RedisModule_CloseKey(key);
|
||||||
|
RedisModule_ReplyWithSimpleString(ctx, "OK");
|
||||||
|
return REDISMODULE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
int test_call_generic(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
int test_call_generic(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||||
{
|
{
|
||||||
if (argc<2) {
|
if (argc<2) {
|
||||||
|
@ -460,6 +509,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||||
if (RedisModule_Init(ctx,"misc",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR)
|
if (RedisModule_Init(ctx,"misc",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR)
|
||||||
return REDISMODULE_ERR;
|
return REDISMODULE_ERR;
|
||||||
|
|
||||||
|
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_KEY_MISS | REDISMODULE_NOTIFY_EXPIRED, KeySpace_NotificationModuleKeyMissExpired) != REDISMODULE_OK){
|
||||||
|
return REDISMODULE_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
if (RedisModule_CreateCommand(ctx,"test.call_generic", test_call_generic,"",0,0,0) == REDISMODULE_ERR)
|
if (RedisModule_CreateCommand(ctx,"test.call_generic", test_call_generic,"",0,0,0) == REDISMODULE_ERR)
|
||||||
return REDISMODULE_ERR;
|
return REDISMODULE_ERR;
|
||||||
if (RedisModule_CreateCommand(ctx,"test.call_info", test_call_info,"",0,0,0) == REDISMODULE_ERR)
|
if (RedisModule_CreateCommand(ctx,"test.call_info", test_call_info,"",0,0,0) == REDISMODULE_ERR)
|
||||||
|
@ -507,6 +560,12 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||||
return REDISMODULE_ERR;
|
return REDISMODULE_ERR;
|
||||||
if (RedisModule_CreateCommand(ctx, "test.rm_call_replicate", test_rm_call_replicate,"allow-stale", 0, 0, 0) == REDISMODULE_ERR)
|
if (RedisModule_CreateCommand(ctx, "test.rm_call_replicate", test_rm_call_replicate,"allow-stale", 0, 0, 0) == REDISMODULE_ERR)
|
||||||
return REDISMODULE_ERR;
|
return REDISMODULE_ERR;
|
||||||
|
if (RedisModule_CreateCommand(ctx, "test.silent_open_key", test_open_key_no_effects,"", 0, 0, 0) == REDISMODULE_ERR)
|
||||||
|
return REDISMODULE_ERR;
|
||||||
|
if (RedisModule_CreateCommand(ctx, "test.get_n_events", test_get_n_events,"", 0, 0, 0) == REDISMODULE_ERR)
|
||||||
|
return REDISMODULE_ERR;
|
||||||
|
if (RedisModule_CreateCommand(ctx, "test.clear_n_events", test_clear_n_events,"", 0, 0, 0) == REDISMODULE_ERR)
|
||||||
|
return REDISMODULE_ERR;
|
||||||
|
|
||||||
return REDISMODULE_OK;
|
return REDISMODULE_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -485,6 +485,16 @@ start_server {tags {"modules"}} {
|
||||||
assert_equal [r get x] $x
|
assert_equal [r get x] $x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test {test silent open key} {
|
||||||
|
r debug set-active-expire 0
|
||||||
|
r test.clear_n_events
|
||||||
|
r set x 1 PX 10
|
||||||
|
after 1000
|
||||||
|
# now the key has been expired, open it silently and make sure not event were fired.
|
||||||
|
assert_error {key not found} {r test.silent_open_key x}
|
||||||
|
assert_equal {0} [r test.get_n_events]
|
||||||
|
}
|
||||||
|
|
||||||
test "Unload the module - misc" {
|
test "Unload the module - misc" {
|
||||||
assert_equal {OK} [r module unload misc]
|
assert_equal {OK} [r module unload misc]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue