Keyspace events notification API.

This commit is contained in:
antirez 2013-01-23 16:23:33 +01:00
parent 61853a9c75
commit 4cdbce341e
7 changed files with 108 additions and 3 deletions

View File

@ -464,6 +464,23 @@ slowlog-log-slower-than 10000
# You can reclaim memory used by the slow log with SLOWLOG RESET.
slowlog-max-len 128
############################# Event notification ##############################
# Redis can notify Pub/Sub clients about events happening in the key space.
# This feature is documented at http://redis.io/topics/keyspace-events
#
# For instance if keyspace events notification is enabled, and a client
# performs a DEL operation on key "foo" stored in the Database 0, two
# messages will be published via Pub/Sub:
#
# 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
############################### ADVANCED CONFIG ###############################
# Hashes are encoded using a memory efficient data structure when they have a

View File

@ -99,7 +99,7 @@ endif
REDIS_SERVER_NAME= redis-server
REDIS_SENTINEL_NAME= redis-sentinel
REDIS_SERVER_OBJ= adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o
REDIS_SERVER_OBJ= adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o
REDIS_CLI_NAME= redis-cli
REDIS_CLI_OBJ= anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o
REDIS_BENCHMARK_NAME= redis-benchmark

View File

@ -43,6 +43,9 @@ networking.o: networking.c redis.h fmacros.h config.h \
../deps/lua/src/lua.h ../deps/lua/src/luaconf.h ae.h sds.h dict.h \
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h \
rio.h
notify.o: notify.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
object.o: object.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h

View File

@ -391,6 +391,10 @@ 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;
}
} else if (!strcasecmp(argv[0],"sentinel")) {
/* argc == 1 is handled by main() as we need to enter the sentinel
* mode ASAP. */
@ -709,11 +713,11 @@ void configSetCommand(redisClient *c) {
if (yn == -1) goto badfmt;
server.rdb_compression = yn;
} else if (!strcasecmp(c->argv[2]->ptr,"rdbchecksum")) {
} else if (!strcasecmp(c->argv[2]->ptr,"notify-keyspace-events")) {
int yn = yesnotoi(o->ptr);
if (yn == -1) goto badfmt;
server.rdb_checksum = yn;
server.notify_keyspace_events = yn;
} else if (!strcasecmp(c->argv[2]->ptr,"slave-priority")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
ll <= 0) goto badfmt;
@ -823,6 +827,7 @@ 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. */

77
src/notify.c Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2013, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "redis.h"
/* This file implements keyspace events notification via Pub/Sub ad
* described at http://redis.io/topics/keyspace-events.
*
* 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;
char buf[24];
robj *chan1, *chan2, *eventobj;
/* 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));
/* 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(keyspace_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(keyspace_chan);
decrRefCount(keyevent_chan);
}

View File

@ -1158,6 +1158,7 @@ void initServerConfig() {
server.rdb_compression = 1;
server.rdb_checksum = 1;
server.activerehashing = 1;
server.notify_keyspace_events = 0;
server.maxclients = REDIS_MAX_CLIENTS;
server.bpop_blocked_clients = 0;
server.maxmemory = 0;

View File

@ -776,6 +776,7 @@ 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. */
/* Cluster */
int cluster_enabled; /* Is cluster enabled? */
clusterState cluster; /* State of the cluster */
@ -1134,6 +1135,7 @@ 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);
/* Configuration */
void loadServerConfig(char *filename, char *options);