Keyspace events notification API.
This commit is contained in:
parent
61853a9c75
commit
4cdbce341e
17
redis.conf
17
redis.conf
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
77
src/notify.c
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user