diff options
Diffstat (limited to 'src/notify.c')
-rw-r--r-- | src/notify.c | 117 |
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); + } } |