summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2013-01-25 13:19:08 +0100
committerantirez <antirez@gmail.com>2013-01-28 13:15:12 +0100
commitfce016d31bc11ff19de1f1ff216e4a0588fea3ac (patch)
treef183f0c98139b5b44e2561daf9fe47398c258add
parent1c0c551776bf2afae9314373012985db9b19bb03 (diff)
downloadredis-fce016d31bc11ff19de1f1ff216e4a0588fea3ac.tar.gz
Keyspace events: it is now possible to select subclasses of events.
When keyspace events are enabled, the overhead is not sever but noticeable, so this commit introduces the ability to select subclasses of events in order to avoid to generate events the user is not interested in. The events can be selected using redis.conf or CONFIG SET / GET.
-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.