summaryrefslogtreecommitdiff
path: root/src/notify.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/notify.c')
-rw-r--r--src/notify.c117
1 files changed, 82 insertions, 35 deletions
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);
+ }
}