mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
Merge pull request #5945 from dvirsky/miss_notification
Added keyspace miss notifications support
This commit is contained in:
commit
122f42844a
7
src/db.c
7
src/db.c
@ -83,6 +83,7 @@ robj *lookupKey(redisDb *db, robj *key, int flags) {
|
|||||||
* 1. A key gets expired if it reached it's TTL.
|
* 1. A key gets expired if it reached it's TTL.
|
||||||
* 2. The key last access time is updated.
|
* 2. The key last access time is updated.
|
||||||
* 3. The global keys hits/misses stats are updated (reported in INFO).
|
* 3. The global keys hits/misses stats are updated (reported in INFO).
|
||||||
|
* 4. If keyspace notifications are enabled, a "keymiss" notification is fired.
|
||||||
*
|
*
|
||||||
* This API should not be used when we write to the key after obtaining
|
* This API should not be used when we write to the key after obtaining
|
||||||
* the object linked to the key, but only for read only operations.
|
* the object linked to the key, but only for read only operations.
|
||||||
@ -106,6 +107,7 @@ robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
|
|||||||
* to return NULL ASAP. */
|
* to return NULL ASAP. */
|
||||||
if (server.masterhost == NULL) {
|
if (server.masterhost == NULL) {
|
||||||
server.stat_keyspace_misses++;
|
server.stat_keyspace_misses++;
|
||||||
|
notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,12 +129,15 @@ robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
|
|||||||
server.current_client->cmd->flags & CMD_READONLY)
|
server.current_client->cmd->flags & CMD_READONLY)
|
||||||
{
|
{
|
||||||
server.stat_keyspace_misses++;
|
server.stat_keyspace_misses++;
|
||||||
|
notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val = lookupKey(db,key,flags);
|
val = lookupKey(db,key,flags);
|
||||||
if (val == NULL)
|
if (val == NULL) {
|
||||||
server.stat_keyspace_misses++;
|
server.stat_keyspace_misses++;
|
||||||
|
notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
server.stat_keyspace_hits++;
|
server.stat_keyspace_hits++;
|
||||||
return val;
|
return val;
|
||||||
|
@ -109,9 +109,9 @@ int TestStringPrintf(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
|||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
return RedisModule_WrongArity(ctx);
|
return RedisModule_WrongArity(ctx);
|
||||||
}
|
}
|
||||||
RedisModuleString *s = RedisModule_CreateStringPrintf(ctx,
|
RedisModuleString *s = RedisModule_CreateStringPrintf(ctx,
|
||||||
"Got %d args. argv[1]: %s, argv[2]: %s",
|
"Got %d args. argv[1]: %s, argv[2]: %s",
|
||||||
argc,
|
argc,
|
||||||
RedisModule_StringPtrLen(argv[1], NULL),
|
RedisModule_StringPtrLen(argv[1], NULL),
|
||||||
RedisModule_StringPtrLen(argv[2], NULL)
|
RedisModule_StringPtrLen(argv[2], NULL)
|
||||||
);
|
);
|
||||||
@ -133,7 +133,7 @@ int TestUnlink(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
|||||||
|
|
||||||
RedisModuleKey *k = RedisModule_OpenKey(ctx, RedisModule_CreateStringPrintf(ctx, "unlinked"), REDISMODULE_WRITE | REDISMODULE_READ);
|
RedisModuleKey *k = RedisModule_OpenKey(ctx, RedisModule_CreateStringPrintf(ctx, "unlinked"), REDISMODULE_WRITE | REDISMODULE_READ);
|
||||||
if (!k) return failTest(ctx, "Could not create key");
|
if (!k) return failTest(ctx, "Could not create key");
|
||||||
|
|
||||||
if (REDISMODULE_ERR == RedisModule_StringSet(k, RedisModule_CreateStringPrintf(ctx, "Foobar"))) {
|
if (REDISMODULE_ERR == RedisModule_StringSet(k, RedisModule_CreateStringPrintf(ctx, "Foobar"))) {
|
||||||
return failTest(ctx, "Could not set string value");
|
return failTest(ctx, "Could not set string value");
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ int TestUnlink(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
|||||||
return failTest(ctx, "Could not verify key to be unlinked");
|
return failTest(ctx, "Could not verify key to be unlinked");
|
||||||
}
|
}
|
||||||
return RedisModule_ReplyWithSimpleString(ctx, "OK");
|
return RedisModule_ReplyWithSimpleString(ctx, "OK");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int NotifyCallback(RedisModuleCtx *ctx, int type, const char *event,
|
int NotifyCallback(RedisModuleCtx *ctx, int type, const char *event,
|
||||||
@ -188,6 +188,10 @@ int TestNotifications(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
|||||||
RedisModule_Call(ctx, "LPUSH", "cc", "l", "y");
|
RedisModule_Call(ctx, "LPUSH", "cc", "l", "y");
|
||||||
RedisModule_Call(ctx, "LPUSH", "cc", "l", "y");
|
RedisModule_Call(ctx, "LPUSH", "cc", "l", "y");
|
||||||
|
|
||||||
|
/* Miss some keys intentionally so we will get a "keymiss" notification. */
|
||||||
|
RedisModule_Call(ctx, "GET", "c", "nosuchkey");
|
||||||
|
RedisModule_Call(ctx, "SMEMBERS", "c", "nosuchkey");
|
||||||
|
|
||||||
size_t sz;
|
size_t sz;
|
||||||
const char *rep;
|
const char *rep;
|
||||||
RedisModuleCallReply *r = RedisModule_Call(ctx, "HGET", "cc", "notifications", "foo");
|
RedisModuleCallReply *r = RedisModule_Call(ctx, "HGET", "cc", "notifications", "foo");
|
||||||
@ -225,6 +229,16 @@ int TestNotifications(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
|||||||
FAIL("Wrong reply for l");
|
FAIL("Wrong reply for l");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = RedisModule_Call(ctx, "HGET", "cc", "notifications", "nosuchkey");
|
||||||
|
if (r == NULL || RedisModule_CallReplyType(r) != REDISMODULE_REPLY_STRING) {
|
||||||
|
FAIL("Wrong or no reply for nosuchkey");
|
||||||
|
} else {
|
||||||
|
rep = RedisModule_CallReplyStringPtr(r, &sz);
|
||||||
|
if (sz != 1 || *rep != '2') {
|
||||||
|
FAIL("Got reply '%.*s'. expected '2'", sz, rep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RedisModule_Call(ctx, "FLUSHDB", "");
|
RedisModule_Call(ctx, "FLUSHDB", "");
|
||||||
|
|
||||||
return RedisModule_ReplyWithSimpleString(ctx, "OK");
|
return RedisModule_ReplyWithSimpleString(ctx, "OK");
|
||||||
@ -423,7 +437,7 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
|||||||
if (RedisModule_CreateCommand(ctx,"test.ctxflags",
|
if (RedisModule_CreateCommand(ctx,"test.ctxflags",
|
||||||
TestCtxFlags,"readonly",1,1,1) == REDISMODULE_ERR)
|
TestCtxFlags,"readonly",1,1,1) == REDISMODULE_ERR)
|
||||||
return REDISMODULE_ERR;
|
return REDISMODULE_ERR;
|
||||||
|
|
||||||
if (RedisModule_CreateCommand(ctx,"test.unlink",
|
if (RedisModule_CreateCommand(ctx,"test.unlink",
|
||||||
TestUnlink,"write deny-oom",1,1,1) == REDISMODULE_ERR)
|
TestUnlink,"write deny-oom",1,1,1) == REDISMODULE_ERR)
|
||||||
return REDISMODULE_ERR;
|
return REDISMODULE_ERR;
|
||||||
@ -435,7 +449,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
|||||||
RedisModule_SubscribeToKeyspaceEvents(ctx,
|
RedisModule_SubscribeToKeyspaceEvents(ctx,
|
||||||
REDISMODULE_NOTIFY_HASH |
|
REDISMODULE_NOTIFY_HASH |
|
||||||
REDISMODULE_NOTIFY_SET |
|
REDISMODULE_NOTIFY_SET |
|
||||||
REDISMODULE_NOTIFY_STRING,
|
REDISMODULE_NOTIFY_STRING |
|
||||||
|
REDISMODULE_NOTIFY_KEY_MISS,
|
||||||
NotifyCallback);
|
NotifyCallback);
|
||||||
if (RedisModule_CreateCommand(ctx,"test.notify",
|
if (RedisModule_CreateCommand(ctx,"test.notify",
|
||||||
TestNotifications,"write deny-oom",1,1,1) == REDISMODULE_ERR)
|
TestNotifications,"write deny-oom",1,1,1) == REDISMODULE_ERR)
|
||||||
|
@ -55,6 +55,7 @@ int keyspaceEventsStringToFlags(char *classes) {
|
|||||||
case 'K': flags |= NOTIFY_KEYSPACE; break;
|
case 'K': flags |= NOTIFY_KEYSPACE; break;
|
||||||
case 'E': flags |= NOTIFY_KEYEVENT; break;
|
case 'E': flags |= NOTIFY_KEYEVENT; break;
|
||||||
case 't': flags |= NOTIFY_STREAM; break;
|
case 't': flags |= NOTIFY_STREAM; break;
|
||||||
|
case 'm': flags |= NOTIFY_KEY_MISS; break;
|
||||||
default: return -1;
|
default: return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,6 +82,7 @@ sds keyspaceEventsFlagsToString(int flags) {
|
|||||||
if (flags & NOTIFY_EXPIRED) res = sdscatlen(res,"x",1);
|
if (flags & NOTIFY_EXPIRED) res = sdscatlen(res,"x",1);
|
||||||
if (flags & NOTIFY_EVICTED) res = sdscatlen(res,"e",1);
|
if (flags & NOTIFY_EVICTED) res = sdscatlen(res,"e",1);
|
||||||
if (flags & NOTIFY_STREAM) res = sdscatlen(res,"t",1);
|
if (flags & NOTIFY_STREAM) res = sdscatlen(res,"t",1);
|
||||||
|
if (flags & NOTIFY_KEY_MISS) res = sdscatlen(res,"m",1);
|
||||||
}
|
}
|
||||||
if (flags & NOTIFY_KEYSPACE) res = sdscatlen(res,"K",1);
|
if (flags & NOTIFY_KEYSPACE) res = sdscatlen(res,"K",1);
|
||||||
if (flags & NOTIFY_KEYEVENT) res = sdscatlen(res,"E",1);
|
if (flags & NOTIFY_KEYEVENT) res = sdscatlen(res,"E",1);
|
||||||
@ -100,12 +102,12 @@ void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) {
|
|||||||
int len = -1;
|
int len = -1;
|
||||||
char buf[24];
|
char buf[24];
|
||||||
|
|
||||||
/* If any modules are interested in events, notify the module system now.
|
/* If any modules are interested in events, notify the module system now.
|
||||||
* This bypasses the notifications configuration, but the module engine
|
* This bypasses the notifications configuration, but the module engine
|
||||||
* will only call event subscribers if the event type matches the types
|
* will only call event subscribers if the event type matches the types
|
||||||
* they are interested in. */
|
* they are interested in. */
|
||||||
moduleNotifyKeyspaceEvent(type, event, key, dbid);
|
moduleNotifyKeyspaceEvent(type, event, key, dbid);
|
||||||
|
|
||||||
/* If notifications for this class of events are off, return ASAP. */
|
/* If notifications for this class of events are off, return ASAP. */
|
||||||
if (!(server.notify_keyspace_events & type)) return;
|
if (!(server.notify_keyspace_events & type)) return;
|
||||||
|
|
||||||
|
@ -98,7 +98,8 @@
|
|||||||
#define REDISMODULE_NOTIFY_EXPIRED (1<<8) /* x */
|
#define REDISMODULE_NOTIFY_EXPIRED (1<<8) /* x */
|
||||||
#define REDISMODULE_NOTIFY_EVICTED (1<<9) /* e */
|
#define REDISMODULE_NOTIFY_EVICTED (1<<9) /* e */
|
||||||
#define REDISMODULE_NOTIFY_STREAM (1<<10) /* t */
|
#define REDISMODULE_NOTIFY_STREAM (1<<10) /* t */
|
||||||
#define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED | REDISMODULE_NOTIFY_STREAM) /* A */
|
#define REDISMODULE_NOTIFY_KEY_MISS (1<<11) /* m */
|
||||||
|
#define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED | REDISMODULE_NOTIFY_STREAM | REDISMODULE_NOTIFY_KEY_MISS) /* A */
|
||||||
|
|
||||||
|
|
||||||
/* A special pointer that we can use between the core and the module to signal
|
/* A special pointer that we can use between the core and the module to signal
|
||||||
|
@ -468,7 +468,8 @@ typedef long long mstime_t; /* millisecond time type. */
|
|||||||
#define NOTIFY_EXPIRED (1<<8) /* x */
|
#define NOTIFY_EXPIRED (1<<8) /* x */
|
||||||
#define NOTIFY_EVICTED (1<<9) /* e */
|
#define NOTIFY_EVICTED (1<<9) /* e */
|
||||||
#define NOTIFY_STREAM (1<<10) /* t */
|
#define NOTIFY_STREAM (1<<10) /* t */
|
||||||
#define NOTIFY_ALL (NOTIFY_GENERIC | NOTIFY_STRING | NOTIFY_LIST | NOTIFY_SET | NOTIFY_HASH | NOTIFY_ZSET | NOTIFY_EXPIRED | NOTIFY_EVICTED | NOTIFY_STREAM) /* A flag */
|
#define NOTIFY_KEY_MISS (1<<11) /* m */
|
||||||
|
#define NOTIFY_ALL (NOTIFY_GENERIC | NOTIFY_STRING | NOTIFY_LIST | NOTIFY_SET | NOTIFY_HASH | NOTIFY_ZSET | NOTIFY_EXPIRED | NOTIFY_EVICTED | NOTIFY_STREAM | NOTIFY_KEY_MISS) /* A flag */
|
||||||
|
|
||||||
/* Get the first bind addr or NULL */
|
/* Get the first bind addr or NULL */
|
||||||
#define NET_FIRST_BIND_ADDR (server.bindaddr_count ? server.bindaddr[0] : NULL)
|
#define NET_FIRST_BIND_ADDR (server.bindaddr_count ? server.bindaddr[0] : NULL)
|
||||||
|
Loading…
Reference in New Issue
Block a user