diff --git a/redis.conf b/redis.conf index 385b45ef..ff096cea 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@__ prefix. +# E Keyevent events, published with __keyevent@__ 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 cda3adc7..f2d03f9b 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 7c298a19..f994dd65 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 10e61824..220503c3 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 da1d4d89..f8e01829 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; + /* If notifications for this class of events are off, return ASAP. */ + if (!(server.notify_keyspace_events & type)) 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. */ + /* __keyspace@__: notifications. */ + if (server.notify_keyspace_events & REDIS_NOTIFY_KEYSPACE) { + robj *eventobj; - eventobj = createStringObject(event,strlen(event)); + 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); + } - /* 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); - - /* Finally publish the two notifications. */ - pubsubPublishMessage(chan1, eventobj); - pubsubPublishMessage(chan2, key); - - /* Release objects. */ - decrRefCount(eventobj); - decrRefCount(chan1); - decrRefCount(chan2); + /* __keyevente@__: 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 e6835c1e..789969a3 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 97d49d51..46f2be8b 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 a0971473..4b504025 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 e395ee26..959c9ca8 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 ea5f4718..0413dc69 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 70052a55..a22bbb67 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 ed784046..1d25e5ad 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 4a9383c1..b458f88a 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 5d7ef95c..6ecfaebe 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.