summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--redis.conf37
-rw-r--r--src/bitops.c6
-rw-r--r--src/config.c24
-rw-r--r--src/db.c13
-rw-r--r--src/notify.c117
-rw-r--r--src/redis.c6
-rw-r--r--src/redis.h23
-rw-r--r--src/sort.c5
-rw-r--r--src/t_hash.c16
-rw-r--r--src/t_list.c33
-rw-r--r--src/t_set.c23
-rw-r--r--src/t_string.c18
-rw-r--r--src/t_zset.c22
-rw-r--r--tests/assets/default.conf2
14 files changed, 237 insertions, 108 deletions
diff --git a/redis.conf b/redis.conf
index 385b45efc..ff096ceae 100644
--- a/redis.conf
+++ b/redis.conf
@@ -476,10 +476,39 @@ slowlog-max-len 128
# PUBLISH __keyspace@0__:foo del
# PUBLISH __keyevent@0__:del foo
#
-# While the overhead of this feature is relatively small most users don't
-# need it so it is disabled by default. You can enable it setting the
-# following configuration option to yes.
-notify-keyspace-events no
+# It is possible to select the events that Redis will notify among a set
+# of classes. Every class is identified by a single character:
+#
+# K Keyspace events, published with __keyspace@<db>__ prefix.
+# E Keyevent events, published with __keyevent@<db>__ prefix.
+# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
+# $ String commands
+# l List commands
+# s Set commands
+# h Hash commands
+# z Sorted set commands
+# x Expired events (events generated every time a key expires)
+# e Evicted events (events generated when a key is evicted for maxmemory)
+# A Alias for g$lshzxe, so that the "AKE" string means all the events.
+#
+# The "notify-keyspace-events" takes as argument a string that is composed
+# by zero or multiple characters. The empty string means that notifications
+# are disabled at all.
+#
+# Example: to enable list and generic events, from the point of view of the
+# event name, use:
+#
+# notify-keyspace-events Elg
+#
+# Example 2: to get the stream of the expired keys subscribing to channel
+# name __keyevent@0__:expired use:
+#
+# notify-keyspace-events Ex
+#
+# By default all notifications are disabled because most users don't need
+# this feature and the feature has some overhead. Note that if you don't
+# specify at least one of K or E, no events will be delivered.
+notify-keyspace-events ""
############################### ADVANCED CONFIG ###############################
diff --git a/src/bitops.c b/src/bitops.c
index cda3adc7d..f2d03f9b0 100644
--- a/src/bitops.c
+++ b/src/bitops.c
@@ -153,7 +153,7 @@ void setbitCommand(redisClient *c) {
byteval |= ((on & 0x1) << bit);
((uint8_t*)o->ptr)[byte] = byteval;
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("setbit",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"setbit",c->argv[1],c->db->id);
server.dirty++;
addReply(c, bitval ? shared.cone : shared.czero);
}
@@ -347,11 +347,11 @@ void bitopCommand(redisClient *c) {
if (maxlen) {
o = createObject(REDIS_STRING,res);
setKey(c->db,targetkey,o);
- notifyKeyspaceEvent("set",targetkey,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"set",targetkey,c->db->id);
decrRefCount(o);
} else if (dbDelete(c->db,targetkey)) {
signalModifiedKey(c->db,targetkey);
- notifyKeyspaceEvent("del",targetkey,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",targetkey,c->db->id);
}
server.dirty++;
addReplyLongLong(c,maxlen); /* Return the output string length in bytes. */
diff --git a/src/config.c b/src/config.c
index 7c298a19e..f994dd657 100644
--- a/src/config.c
+++ b/src/config.c
@@ -392,9 +392,13 @@ void loadServerConfigFromString(char *config) {
} else if (!strcasecmp(argv[0],"slave-priority") && argc == 2) {
server.slave_priority = atoi(argv[1]);
} else if (!strcasecmp(argv[0],"notify-keyspace-events") && argc == 2) {
- if ((server.notify_keyspace_events = yesnotoi(argv[1])) == -1) {
- err = "argument must be 'yes' or 'no'"; goto loaderr;
+ int flags = keyspaceEventsStringToFlags(argv[1]);
+
+ if (flags == -1) {
+ err = "Invalid event class character. Use 'g$lshzxeA'.";
+ goto loaderr;
}
+ server.notify_keyspace_events = flags;
} else if (!strcasecmp(argv[0],"sentinel")) {
/* argc == 1 is handled by main() as we need to enter the sentinel
* mode ASAP. */
@@ -714,10 +718,10 @@ void configSetCommand(redisClient *c) {
if (yn == -1) goto badfmt;
server.rdb_compression = yn;
} else if (!strcasecmp(c->argv[2]->ptr,"notify-keyspace-events")) {
- int yn = yesnotoi(o->ptr);
+ int flags = keyspaceEventsStringToFlags(o->ptr);
- if (yn == -1) goto badfmt;
- server.notify_keyspace_events = yn;
+ if (flags == -1) goto badfmt;
+ server.notify_keyspace_events = flags;
} else if (!strcasecmp(c->argv[2]->ptr,"slave-priority")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
ll <= 0) goto badfmt;
@@ -827,7 +831,6 @@ void configGetCommand(redisClient *c) {
config_get_bool_field("rdbcompression", server.rdb_compression);
config_get_bool_field("rdbchecksum", server.rdb_checksum);
config_get_bool_field("activerehashing", server.activerehashing);
- config_get_bool_field("notify-keyspace-events", server.notify_keyspace_events);
/* Everything we can't handle with macros follows. */
@@ -942,6 +945,15 @@ void configGetCommand(redisClient *c) {
addReplyBulkCString(c,buf);
matches++;
}
+ if (stringmatch(pattern,"notify-keyspace-events",0)) {
+ robj *flagsobj = createObject(REDIS_STRING,
+ keyspaceEventsFlagsToString(server.notify_keyspace_events));
+
+ addReplyBulkCString(c,"notify-keyspace-events");
+ addReplyBulk(c,flagsobj);
+ decrRefCount(flagsobj);
+ matches++;
+ }
setDeferredMultiBulkLength(c,replylen,matches*2);
}
diff --git a/src/db.c b/src/db.c
index 10e618246..220503c35 100644
--- a/src/db.c
+++ b/src/db.c
@@ -240,7 +240,8 @@ void delCommand(redisClient *c) {
for (j = 1; j < c->argc; j++) {
if (dbDelete(c->db,c->argv[j])) {
signalModifiedKey(c->db,c->argv[j]);
- notifyKeyspaceEvent("del",c->argv[j],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,
+ "del",c->argv[j],c->db->id);
server.dirty++;
deleted++;
}
@@ -392,8 +393,10 @@ void renameGenericCommand(redisClient *c, int nx) {
dbDelete(c->db,c->argv[1]);
signalModifiedKey(c->db,c->argv[1]);
signalModifiedKey(c->db,c->argv[2]);
- notifyKeyspaceEvent("rename_from",c->argv[1],c->db->id);
- notifyKeyspaceEvent("rename_to",c->argv[2],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"rename_from",
+ c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"rename_to",
+ c->argv[2],c->db->id);
server.dirty++;
addReply(c,nx ? shared.cone : shared.ok);
}
@@ -587,14 +590,14 @@ void expireGenericCommand(redisClient *c, long long basetime, int unit) {
rewriteClientCommandVector(c,2,aux,key);
decrRefCount(aux);
signalModifiedKey(c->db,key);
- notifyKeyspaceEvent("del",key,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",key,c->db->id);
addReply(c, shared.cone);
return;
} else {
setExpire(c->db,key,when);
addReply(c,shared.cone);
signalModifiedKey(c->db,key);
- notifyKeyspaceEvent("expire",key,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"expire",key,c->db->id);
server.dirty++;
return;
}
diff --git a/src/notify.c b/src/notify.c
index da1d4d894..f8e018295 100644
--- a/src/notify.c
+++ b/src/notify.c
@@ -30,50 +30,97 @@
#include "redis.h"
/* This file implements keyspace events notification via Pub/Sub ad
- * described at http://redis.io/topics/keyspace-events.
+ * described at http://redis.io/topics/keyspace-events. */
+
+/* Turn a string representing notification classes into an integer
+ * representing notification classes flags xored.
*
- * The API provided to the rest of the Redis core is a simple function:
+ * The function returns -1 if the input contains characters not mapping to
+ * any class. */
+int keyspaceEventsStringToFlags(char *classes) {
+ char *p = classes;
+ int c, flags = 0;
+
+ while((c = *p++) != '\0') {
+ switch(c) {
+ case 'A': flags |= REDIS_NOTIFY_ALL; break;
+ case 'g': flags |= REDIS_NOTIFY_GENERIC; break;
+ case '$': flags |= REDIS_NOTIFY_STRING; break;
+ case 'l': flags |= REDIS_NOTIFY_LIST; break;
+ case 's': flags |= REDIS_NOTIFY_SET; break;
+ case 'h': flags |= REDIS_NOTIFY_HASH; break;
+ case 'z': flags |= REDIS_NOTIFY_ZSET; break;
+ case 'x': flags |= REDIS_NOTIFY_EXPIRED; break;
+ case 'e': flags |= REDIS_NOTIFY_EVICTED; break;
+ case 'K': flags |= REDIS_NOTIFY_KEYSPACE; break;
+ case 'E': flags |= REDIS_NOTIFY_KEYEVENT; break;
+ default: return -1;
+ }
+ }
+ return flags;
+}
+
+/* This function does exactly the revese of the function above: it gets
+ * as input an integer with the xored flags and returns a string representing
+ * the selected classes. The string returned is an sds string that needs to
+ * be released with sdsfree(). */
+sds keyspaceEventsFlagsToString(int flags) {
+ sds res;
+
+ if ((flags & REDIS_NOTIFY_ALL) == REDIS_NOTIFY_ALL)
+ return sdsnew("A");
+ res = sdsempty();
+ if (flags & REDIS_NOTIFY_GENERIC) res = sdscatlen(res,"g",1);
+ if (flags & REDIS_NOTIFY_STRING) res = sdscatlen(res,"$",1);
+ if (flags & REDIS_NOTIFY_LIST) res = sdscatlen(res,"l",1);
+ if (flags & REDIS_NOTIFY_SET) res = sdscatlen(res,"s",1);
+ if (flags & REDIS_NOTIFY_HASH) res = sdscatlen(res,"h",1);
+ if (flags & REDIS_NOTIFY_ZSET) res = sdscatlen(res,"z",1);
+ if (flags & REDIS_NOTIFY_EXPIRED) res = sdscatlen(res,"x",1);
+ if (flags & REDIS_NOTIFY_EVICTED) res = sdscatlen(res,"e",1);
+ if (flags & REDIS_NOTIFY_KEYSPACE) res = sdscatlen(res,"K",1);
+ if (flags & REDIS_NOTIFY_KEYEVENT) res = sdscatlen(res,"E",1);
+ return res;
+}
+
+/* The API provided to the rest of the Redis core is a simple function:
*
* notifyKeyspaceEvent(char *event, robj *key, int dbid);
*
* 'event' is a C string representing the event name.
* 'key' is a Redis object representing the key name.
- * 'dbid' is the database ID where the key lives.
- */
-
-void notifyKeyspaceEvent(char *event, robj *key, int dbid) {
- sds keyspace_chan, keyevent_chan;
- int len;
+ * 'dbid' is the database ID where the key lives. */
+void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) {
+ sds chan;
+ robj *chanobj;
+ int len = -1;
char buf[24];
- robj *chan1, *chan2, *eventobj;
-
- if (!server.notify_keyspace_events) return;
-
- /* The prefix of the two channels is identical if not for
- * 'keyspace' that is 'keyevent' in the event channel name, so
- * we build a single prefix and overwrite 'event' with 'space'. */
- keyspace_chan = sdsnewlen("__keyspace@",11);
- len = ll2string(buf,sizeof(buf),dbid);
- keyspace_chan = sdscatlen(keyspace_chan, buf, len);
- keyspace_chan = sdscatlen(keyspace_chan, "__:", 3);
- keyevent_chan = sdsdup(keyspace_chan); /* Dup the prefix. */
- memcpy(keyevent_chan+5,"event",5); /* Fix it. */
- eventobj = createStringObject(event,strlen(event));
+ /* If notifications for this class of events are off, return ASAP. */
+ if (!(server.notify_keyspace_events & type)) return;
- /* The keyspace channel name has a trailing key name, while
- * the keyevent channel name has a trailing event name. */
- keyspace_chan = sdscatsds(keyspace_chan, key->ptr);
- keyevent_chan = sdscatsds(keyevent_chan, eventobj->ptr);
- chan1 = createObject(REDIS_STRING, keyspace_chan);
- chan2 = createObject(REDIS_STRING, keyevent_chan);
+ /* __keyspace@<db>__:<key> <event> notifications. */
+ if (server.notify_keyspace_events & REDIS_NOTIFY_KEYSPACE) {
+ robj *eventobj;
- /* Finally publish the two notifications. */
- pubsubPublishMessage(chan1, eventobj);
- pubsubPublishMessage(chan2, key);
+ chan = sdsnewlen("__keyspace@",11);
+ len = ll2string(buf,sizeof(buf),dbid);
+ chan = sdscatlen(chan, buf, len);
+ chan = sdscatlen(chan, "__:", 3);
+ eventobj = createStringObject(event,strlen(event));
+ chanobj = createObject(REDIS_STRING, chan);
+ pubsubPublishMessage(chanobj, eventobj);
+ decrRefCount(chanobj);
+ }
- /* Release objects. */
- decrRefCount(eventobj);
- decrRefCount(chan1);
- decrRefCount(chan2);
+ /* __keyevente@<db>__:<event> <key> notifications. */
+ if (server.notify_keyspace_events & REDIS_NOTIFY_KEYEVENT) {
+ chan = sdsnewlen("__keyevent@",11);
+ if (len == -1) len = ll2string(buf,sizeof(buf),dbid);
+ chan = sdscatlen(chan, buf, len);
+ chan = sdscatlen(chan, "__:", 3);
+ chanobj = createObject(REDIS_STRING, chan);
+ pubsubPublishMessage(chanobj, key);
+ decrRefCount(chanobj);
+ }
}
diff --git a/src/redis.c b/src/redis.c
index e6835c1ea..789969a3f 100644
--- a/src/redis.c
+++ b/src/redis.c
@@ -689,7 +689,8 @@ void activeExpireCycle(void) {
propagateExpire(db,keyobj);
dbDelete(db,keyobj);
- notifyKeyspaceEvent("expired",keyobj,db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_EXPIRED,
+ "expired",keyobj,db->id);
decrRefCount(keyobj);
expired++;
server.stat_expiredkeys++;
@@ -2432,7 +2433,8 @@ int freeMemoryIfNeeded(void) {
delta -= (long long) zmalloc_used_memory();
mem_freed += delta;
server.stat_evictedkeys++;
- notifyKeyspaceEvent("evicted",keyobj,db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_EVICTED, "evicted",
+ keyobj, db->id);
decrRefCount(keyobj);
keys_freed++;
diff --git a/src/redis.h b/src/redis.h
index 97d49d511..46f2be8b2 100644
--- a/src/redis.h
+++ b/src/redis.h
@@ -291,6 +291,20 @@
#define REDIS_PROPAGATE_AOF 1
#define REDIS_PROPAGATE_REPL 2
+/* Keyspace changes notification classes. Every class is associated with a
+ * character for configuration purposes. */
+#define REDIS_NOTIFY_KEYSPACE (1<<0) /* K */
+#define REDIS_NOTIFY_KEYEVENT (1<<1) /* E */
+#define REDIS_NOTIFY_GENERIC (1<<2) /* g */
+#define REDIS_NOTIFY_STRING (1<<3) /* $ */
+#define REDIS_NOTIFY_LIST (1<<4) /* l */
+#define REDIS_NOTIFY_SET (1<<5) /* s */
+#define REDIS_NOTIFY_HASH (1<<6) /* h */
+#define REDIS_NOTIFY_ZSET (1<<7) /* z */
+#define REDIS_NOTIFY_EXPIRED (1<<8) /* x */
+#define REDIS_NOTIFY_EVICTED (1<<9) /* e */
+#define REDIS_NOTIFY_ALL (REDIS_NOTIFY_GENERIC | REDIS_NOTIFY_STRING | REDIS_NOTIFY_LIST | REDIS_NOTIFY_SET | REDIS_NOTIFY_HASH | REDIS_NOTIFY_ZSET | REDIS_NOTIFY_EXPIRED | REDIS_NOTIFY_EVICTED) /* A */
+
/* Using the following macro you can run code inside serverCron() with the
* specified period, specified in milliseconds.
* The actual resolution depends on server.hz. */
@@ -776,7 +790,8 @@ struct redisServer {
/* Pubsub */
dict *pubsub_channels; /* Map channels to list of subscribed clients */
list *pubsub_patterns; /* A list of pubsub_patterns */
- int notify_keyspace_events; /* Propagate keyspace events via Pub/Sub. */
+ int notify_keyspace_events; /* Events to propagate via Pub/Sub. This is an
+ xor of REDIS_NOTIFY... flags. */
/* Cluster */
int cluster_enabled; /* Is cluster enabled? */
clusterState cluster; /* State of the cluster */
@@ -1136,7 +1151,11 @@ int pubsubUnsubscribeAllPatterns(redisClient *c, int notify);
void freePubsubPattern(void *p);
int listMatchPubsubPattern(void *a, void *b);
int pubsubPublishMessage(robj *channel, robj *message);
-void notifyKeyspaceEvent(char *event, robj *key, int dbid);
+
+/* Keyspace events notification */
+void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid);
+int keyspaceEventsStringToFlags(char *classes);
+sds keyspaceEventsFlagsToString(int flags);
/* Configuration */
void loadServerConfig(char *filename, char *options);
diff --git a/src/sort.c b/src/sort.c
index a0971473d..4b5040250 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -504,11 +504,12 @@ void sortCommand(redisClient *c) {
}
if (outputlen) {
setKey(c->db,storekey,sobj);
- notifyKeyspaceEvent("sortstore",storekey,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_LIST,"sortstore",storekey,
+ c->db->id);
server.dirty += outputlen;
} else if (dbDelete(c->db,storekey)) {
signalModifiedKey(c->db,storekey);
- notifyKeyspaceEvent("del",storekey,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",storekey,c->db->id);
server.dirty++;
}
decrRefCount(sobj);
diff --git a/src/t_hash.c b/src/t_hash.c
index e395ee265..959c9ca81 100644
--- a/src/t_hash.c
+++ b/src/t_hash.c
@@ -474,7 +474,7 @@ void hsetCommand(redisClient *c) {
update = hashTypeSet(o,c->argv[2],c->argv[3]);
addReply(c, update ? shared.czero : shared.cone);
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("hset",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_HASH,"hset",c->argv[1],c->db->id);
server.dirty++;
}
@@ -490,7 +490,7 @@ void hsetnxCommand(redisClient *c) {
hashTypeSet(o,c->argv[2],c->argv[3]);
addReply(c, shared.cone);
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("hset",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_HASH,"hset",c->argv[1],c->db->id);
server.dirty++;
}
}
@@ -512,7 +512,7 @@ void hmsetCommand(redisClient *c) {
}
addReply(c, shared.ok);
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("hset",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_HASH,"hset",c->argv[1],c->db->id);
server.dirty++;
}
@@ -546,7 +546,7 @@ void hincrbyCommand(redisClient *c) {
decrRefCount(new);
addReplyLongLong(c,value);
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("hincrby",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_HASH,"hincrby",c->argv[1],c->db->id);
server.dirty++;
}
@@ -573,7 +573,7 @@ void hincrbyfloatCommand(redisClient *c) {
hashTypeSet(o,c->argv[2],new);
addReplyBulk(c,new);
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("hincrbyfloat",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_HASH,"hincrbyfloat",c->argv[1],c->db->id);
server.dirty++;
/* Always replicate HINCRBYFLOAT as an HSET command with the final value
@@ -671,8 +671,10 @@ void hdelCommand(redisClient *c) {
}
if (deleted) {
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("hdel",c->argv[1],c->db->id);
- if (keyremoved) notifyKeyspaceEvent("del",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_HASH,"hdel",c->argv[1],c->db->id);
+ if (keyremoved)
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",c->argv[1],
+ c->db->id);
server.dirty += deleted;
}
addReplyLongLong(c,deleted);
diff --git a/src/t_list.c b/src/t_list.c
index ea5f4718d..0413dc69b 100644
--- a/src/t_list.c
+++ b/src/t_list.c
@@ -320,7 +320,7 @@ void pushGenericCommand(redisClient *c, int where) {
char *event = (where == REDIS_HEAD) ? "lpush" : "rpush";
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent(event,c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_LIST,event,c->argv[1],c->db->id);
}
server.dirty += pushed;
}
@@ -367,7 +367,8 @@ void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int where) {
ziplistLen(subject->ptr) > server.list_max_ziplist_entries)
listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST);
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("linsert",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_LIST,"linsert",
+ c->argv[1],c->db->id);
server.dirty++;
} else {
/* Notify client of a failed insert */
@@ -379,7 +380,7 @@ void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int where) {
listTypePush(subject,val,where);
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent(event,c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_LIST,event,c->argv[1],c->db->id);
server.dirty++;
}
@@ -474,7 +475,7 @@ void lsetCommand(redisClient *c) {
decrRefCount(value);
addReply(c,shared.ok);
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("lset",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_LIST,"lset",c->argv[1],c->db->id);
server.dirty++;
}
} else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
@@ -487,7 +488,7 @@ void lsetCommand(redisClient *c) {
incrRefCount(value);
addReply(c,shared.ok);
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("lset",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_LIST,"lset",c->argv[1],c->db->id);
server.dirty++;
}
} else {
@@ -507,9 +508,10 @@ void popGenericCommand(redisClient *c, int where) {
addReplyBulk(c,value);
decrRefCount(value);
- notifyKeyspaceEvent(event,c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_LIST,event,c->argv[1],c->db->id);
if (listTypeLength(o) == 0) {
- notifyKeyspaceEvent("del",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",
+ c->argv[1],c->db->id);
dbDelete(c->db,c->argv[1]);
}
signalModifiedKey(c->db,c->argv[1]);
@@ -632,10 +634,10 @@ void ltrimCommand(redisClient *c) {
redisPanic("Unknown list encoding");
}
- notifyKeyspaceEvent("ltrim",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_LIST,"ltrim",c->argv[1],c->db->id);
if (listTypeLength(o) == 0) {
dbDelete(c->db,c->argv[1]);
- notifyKeyspaceEvent("del",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",c->argv[1],c->db->id);
}
signalModifiedKey(c->db,c->argv[1]);
server.dirty++;
@@ -711,7 +713,7 @@ void rpoplpushHandlePush(redisClient *c, robj *dstkey, robj *dstobj, robj *value
}
signalModifiedKey(c->db,dstkey);
listTypePush(dstobj,value,REDIS_HEAD);
- notifyKeyspaceEvent("lpush",dstkey,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_LIST,"lpush",dstkey,c->db->id);
/* Always send the pushed value to the client. */
addReplyBulk(c,value);
}
@@ -741,10 +743,11 @@ void rpoplpushCommand(redisClient *c) {
decrRefCount(value);
/* Delete the source list when it is empty */
- notifyKeyspaceEvent("rpop",touchedkey,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_LIST,"rpop",touchedkey,c->db->id);
if (listTypeLength(sobj) == 0) {
dbDelete(c->db,touchedkey);
- notifyKeyspaceEvent("del",touchedkey,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",
+ touchedkey,c->db->id);
}
signalModifiedKey(c->db,touchedkey);
decrRefCount(touchedkey);
@@ -1077,10 +1080,12 @@ void blockingPopGenericCommand(redisClient *c, int where) {
addReplyBulk(c,c->argv[j]);
addReplyBulk(c,value);
decrRefCount(value);
- notifyKeyspaceEvent(event,c->argv[j],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_LIST,event,
+ c->argv[j],c->db->id);
if (listTypeLength(o) == 0) {
dbDelete(c->db,c->argv[j]);
- notifyKeyspaceEvent("del",c->argv[j],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",
+ c->argv[j],c->db->id);
}
signalModifiedKey(c->db,c->argv[j]);
server.dirty++;
diff --git a/src/t_set.c b/src/t_set.c
index 70052a55e..a22bbb67b 100644
--- a/src/t_set.c
+++ b/src/t_set.c
@@ -268,7 +268,7 @@ void saddCommand(redisClient *c) {
}
if (added) {
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("sadd",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_SET,"sadd",c->argv[1],c->db->id);
}
server.dirty += added;
addReplyLongLong(c,added);
@@ -293,8 +293,10 @@ void sremCommand(redisClient *c) {
}
if (deleted) {
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("srem",c->argv[1],c->db->id);
- if (keyremoved) notifyKeyspaceEvent("del",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_SET,"srem",c->argv[1],c->db->id);
+ if (keyremoved)
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",c->argv[1],
+ c->db->id);
server.dirty += deleted;
}
addReplyLongLong(c,deleted);
@@ -328,12 +330,12 @@ void smoveCommand(redisClient *c) {
addReply(c,shared.czero);
return;
}
- notifyKeyspaceEvent("srem",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_SET,"srem",c->argv[1],c->db->id);
/* Remove the src set from the database when empty */
if (setTypeSize(srcset) == 0) {
dbDelete(c->db,c->argv[1]);
- notifyKeyspaceEvent("del",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",c->argv[1],c->db->id);
}
signalModifiedKey(c->db,c->argv[1]);
signalModifiedKey(c->db,c->argv[2]);
@@ -348,7 +350,7 @@ void smoveCommand(redisClient *c) {
/* An extra key has changed when ele was successfully added to dstset */
if (setTypeAdd(dstset,ele)) {
server.dirty++;
- notifyKeyspaceEvent("sadd",c->argv[2],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_SET,"sadd",c->argv[2],c->db->id);
}
addReply(c,shared.cone);
}
@@ -391,7 +393,7 @@ void spopCommand(redisClient *c) {
incrRefCount(ele);
setTypeRemove(set,ele);
}
- notifyKeyspaceEvent("spop",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_SET,"spop",c->argv[1],c->db->id);
/* Replicate/AOF this command as an SREM operation */
aux = createStringObject("SREM",4);
@@ -402,7 +404,7 @@ void spopCommand(redisClient *c) {
addReplyBulk(c,ele);
if (setTypeSize(set) == 0) {
dbDelete(c->db,c->argv[1]);
- notifyKeyspaceEvent("del",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",c->argv[1],c->db->id);
}
signalModifiedKey(c->db,c->argv[1]);
server.dirty++;
@@ -708,7 +710,8 @@ void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum,
if (setTypeSize(dstset) > 0) {
dbAdd(c->db,dstkey,dstset);
addReplyLongLong(c,setTypeSize(dstset));
- notifyKeyspaceEvent("sinterstore",dstkey,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_SET,"sinterstore",
+ dstkey,c->db->id);
} else {
decrRefCount(dstset);
addReply(c,shared.czero);
@@ -874,7 +877,7 @@ void sunionDiffGenericCommand(redisClient *c, robj **setkeys, int setnum, robj *
if (setTypeSize(dstset) > 0) {
dbAdd(c->db,dstkey,dstset);
addReplyLongLong(c,setTypeSize(dstset));
- notifyKeyspaceEvent(
+ notifyKeyspaceEvent(REDIS_NOTIFY_SET,
op == REDIS_OP_UNION ? "sunionstore" : "sdiffstore",
dstkey,c->db->id);
} else {
diff --git a/src/t_string.c b/src/t_string.c
index ed7840467..1d25e5ad1 100644
--- a/src/t_string.c
+++ b/src/t_string.c
@@ -62,8 +62,9 @@ void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expir
setKey(c->db,key,val);
server.dirty++;
if (expire) setExpire(c->db,key,mstime()+milliseconds);
- notifyKeyspaceEvent("set",key,c->db->id);
- if (expire) notifyKeyspaceEvent("expire",key,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"set",key,c->db->id);
+ if (expire) notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,
+ "expire",key,c->db->id);
addReply(c, nx ? shared.cone : shared.ok);
}
@@ -110,7 +111,7 @@ void getsetCommand(redisClient *c) {
if (getGenericCommand(c) == REDIS_ERR) return;
c->argv[2] = tryObjectEncoding(c->argv[2]);
setKey(c->db,c->argv[1],c->argv[2]);
- notifyKeyspaceEvent("set",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"set",c->argv[1],c->db->id);
server.dirty++;
}
@@ -172,7 +173,8 @@ void setrangeCommand(redisClient *c) {
o->ptr = sdsgrowzero(o->ptr,offset+sdslen(value));
memcpy((char*)o->ptr+offset,value,sdslen(value));
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("setrange",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_STRING,
+ "setrange",c->argv[1],c->db->id);
server.dirty++;
}
addReplyLongLong(c,sdslen(o->ptr));
@@ -257,7 +259,7 @@ void msetGenericCommand(redisClient *c, int nx) {
for (j = 1; j < c->argc; j += 2) {
c->argv[j+1] = tryObjectEncoding(c->argv[j+1]);
setKey(c->db,c->argv[j],c->argv[j+1]);
- notifyKeyspaceEvent("set",c->argv[j],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"set",c->argv[j],c->db->id);
}
server.dirty += (c->argc-1)/2;
addReply(c, nx ? shared.cone : shared.ok);
@@ -292,7 +294,7 @@ void incrDecrCommand(redisClient *c, long long incr) {
else
dbAdd(c->db,c->argv[1],new);
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("incrby",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"incrby",c->argv[1],c->db->id);
server.dirty++;
addReply(c,shared.colon);
addReply(c,new);
@@ -342,7 +344,7 @@ void incrbyfloatCommand(redisClient *c) {
else
dbAdd(c->db,c->argv[1],new);
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("incrbyfloat",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"incrbyfloat",c->argv[1],c->db->id);
server.dirty++;
addReplyBulk(c,new);
@@ -390,7 +392,7 @@ void appendCommand(redisClient *c) {
totlen = sdslen(o->ptr);
}
signalModifiedKey(c->db,c->argv[1]);
- notifyKeyspaceEvent("append",c->argv[1],c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"append",c->argv[1],c->db->id);
server.dirty++;
addReplyLongLong(c,totlen);
}
diff --git a/src/t_zset.c b/src/t_zset.c
index 4a9383c12..b458f88a1 100644
--- a/src/t_zset.c
+++ b/src/t_zset.c
@@ -968,7 +968,8 @@ cleanup:
zfree(scores);
if (added || updated) {
signalModifiedKey(c->db,key);
- notifyKeyspaceEvent(incr ? "zincr" : "zadd", key, c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,
+ incr ? "zincr" : "zadd", key, c->db->id);
}
}
@@ -1029,8 +1030,9 @@ void zremCommand(redisClient *c) {
}
if (deleted) {
- notifyKeyspaceEvent("zrem",key,c->db->id);
- if (keyremoved) notifyKeyspaceEvent("del",key,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,"zrem",key,c->db->id);
+ if (keyremoved)
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",key,c->db->id);
signalModifiedKey(c->db,key);
server.dirty += deleted;
}
@@ -1073,8 +1075,9 @@ void zremrangebyscoreCommand(redisClient *c) {
if (deleted) {
signalModifiedKey(c->db,key);
- notifyKeyspaceEvent("zrembyscore",key,c->db->id);
- if (keyremoved) notifyKeyspaceEvent("del",key,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,"zrembyscore",key,c->db->id);
+ if (keyremoved)
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",key,c->db->id);
}
server.dirty += deleted;
addReplyLongLong(c,deleted);
@@ -1132,8 +1135,9 @@ void zremrangebyrankCommand(redisClient *c) {
if (deleted) {
signalModifiedKey(c->db,key);
- notifyKeyspaceEvent("zrembyrank",key,c->db->id);
- if (keyremoved) notifyKeyspaceEvent("del",key,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,"zrembyrank",key,c->db->id);
+ if (keyremoved)
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",key,c->db->id);
}
server.dirty += deleted;
addReplyLongLong(c,deleted);
@@ -1676,7 +1680,7 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
if (dbDelete(c->db,dstkey)) {
signalModifiedKey(c->db,dstkey);
- notifyKeyspaceEvent("del",dstkey,c->db->id);
+ notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",dstkey,c->db->id);
touched = 1;
server.dirty++;
}
@@ -1689,7 +1693,7 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
dbAdd(c->db,dstkey,dstobj);
addReplyLongLong(c,zsetLength(dstobj));
if (!touched) signalModifiedKey(c->db,dstkey);
- notifyKeyspaceEvent(
+ notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,
(op == REDIS_OP_UNION) ? "zunionstore" : "zinterstore",
dstkey,c->db->id);
server.dirty++;
diff --git a/tests/assets/default.conf b/tests/assets/default.conf
index 5d7ef95cd..6ecfaebe7 100644
--- a/tests/assets/default.conf
+++ b/tests/assets/default.conf
@@ -13,7 +13,7 @@
# units are case insensitive so 1GB 1Gb 1gB are all the same.
# Enable keyspace events notification for testing so that we cover more code.
-notify-keyspace-events yes
+notify-keyspace-events A
# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.