diff options
Diffstat (limited to 'examples/redis-unstable/src/notify.c')
| -rw-r--r-- | examples/redis-unstable/src/notify.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/examples/redis-unstable/src/notify.c b/examples/redis-unstable/src/notify.c new file mode 100644 index 0000000..84cd855 --- /dev/null +++ b/examples/redis-unstable/src/notify.c | |||
| @@ -0,0 +1,129 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2013-Present, Redis Ltd. | ||
| 3 | * All rights reserved. | ||
| 4 | * | ||
| 5 | * Licensed under your choice of (a) the Redis Source Available License 2.0 | ||
| 6 | * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the | ||
| 7 | * GNU Affero General Public License v3 (AGPLv3). | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include "server.h" | ||
| 11 | |||
| 12 | /* This file implements keyspace events notification via Pub/Sub and | ||
| 13 | * described at https://redis.io/docs/latest/develop/use/keyspace-notifications/. */ | ||
| 14 | |||
| 15 | /* Turn a string representing notification classes into an integer | ||
| 16 | * representing notification classes flags xored. | ||
| 17 | * | ||
| 18 | * The function returns -1 if the input contains characters not mapping to | ||
| 19 | * any class. */ | ||
| 20 | int keyspaceEventsStringToFlags(char *classes) { | ||
| 21 | char *p = classes; | ||
| 22 | int c, flags = 0; | ||
| 23 | |||
| 24 | while((c = *p++) != '\0') { | ||
| 25 | switch(c) { | ||
| 26 | case 'A': flags |= NOTIFY_ALL; break; | ||
| 27 | case 'g': flags |= NOTIFY_GENERIC; break; | ||
| 28 | case '$': flags |= NOTIFY_STRING; break; | ||
| 29 | case 'l': flags |= NOTIFY_LIST; break; | ||
| 30 | case 's': flags |= NOTIFY_SET; break; | ||
| 31 | case 'h': flags |= NOTIFY_HASH; break; | ||
| 32 | case 'z': flags |= NOTIFY_ZSET; break; | ||
| 33 | case 'x': flags |= NOTIFY_EXPIRED; break; | ||
| 34 | case 'e': flags |= NOTIFY_EVICTED; break; | ||
| 35 | case 'K': flags |= NOTIFY_KEYSPACE; break; | ||
| 36 | case 'E': flags |= NOTIFY_KEYEVENT; break; | ||
| 37 | case 't': flags |= NOTIFY_STREAM; break; | ||
| 38 | case 'm': flags |= NOTIFY_KEY_MISS; break; | ||
| 39 | case 'd': flags |= NOTIFY_MODULE; break; | ||
| 40 | case 'n': flags |= NOTIFY_NEW; break; | ||
| 41 | case 'o': flags |= NOTIFY_OVERWRITTEN; break; | ||
| 42 | case 'c': flags |= NOTIFY_TYPE_CHANGED; break; | ||
| 43 | default: return -1; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | return flags; | ||
| 47 | } | ||
| 48 | |||
| 49 | /* This function does exactly the reverse of the function above: it gets | ||
| 50 | * as input an integer with the xored flags and returns a string representing | ||
| 51 | * the selected classes. The string returned is an sds string that needs to | ||
| 52 | * be released with sdsfree(). */ | ||
| 53 | sds keyspaceEventsFlagsToString(int flags) { | ||
| 54 | sds res; | ||
| 55 | |||
| 56 | res = sdsempty(); | ||
| 57 | if ((flags & NOTIFY_ALL) == NOTIFY_ALL) { | ||
| 58 | res = sdscatlen(res,"A",1); | ||
| 59 | } else { | ||
| 60 | if (flags & NOTIFY_GENERIC) res = sdscatlen(res,"g",1); | ||
| 61 | if (flags & NOTIFY_STRING) res = sdscatlen(res,"$",1); | ||
| 62 | if (flags & NOTIFY_LIST) res = sdscatlen(res,"l",1); | ||
| 63 | if (flags & NOTIFY_SET) res = sdscatlen(res,"s",1); | ||
| 64 | if (flags & NOTIFY_HASH) res = sdscatlen(res,"h",1); | ||
| 65 | if (flags & NOTIFY_ZSET) res = sdscatlen(res,"z",1); | ||
| 66 | if (flags & NOTIFY_EXPIRED) res = sdscatlen(res,"x",1); | ||
| 67 | if (flags & NOTIFY_EVICTED) res = sdscatlen(res,"e",1); | ||
| 68 | if (flags & NOTIFY_STREAM) res = sdscatlen(res,"t",1); | ||
| 69 | if (flags & NOTIFY_MODULE) res = sdscatlen(res,"d",1); | ||
| 70 | if (flags & NOTIFY_NEW) res = sdscatlen(res,"n",1); | ||
| 71 | if (flags & NOTIFY_OVERWRITTEN) res = sdscatlen(res,"o",1); | ||
| 72 | if (flags & NOTIFY_TYPE_CHANGED) res = sdscatlen(res,"c",1); | ||
| 73 | } | ||
| 74 | if (flags & NOTIFY_KEYSPACE) res = sdscatlen(res,"K",1); | ||
| 75 | if (flags & NOTIFY_KEYEVENT) res = sdscatlen(res,"E",1); | ||
| 76 | if (flags & NOTIFY_KEY_MISS) res = sdscatlen(res,"m",1); | ||
| 77 | return res; | ||
| 78 | } | ||
| 79 | |||
| 80 | /* The API provided to the rest of the Redis core is a simple function: | ||
| 81 | * | ||
| 82 | * notifyKeyspaceEvent(int type, char *event, robj *key, int dbid); | ||
| 83 | * | ||
| 84 | * 'type' is the notification class we define in `server.h`. | ||
| 85 | * 'event' is a C string representing the event name. | ||
| 86 | * 'key' is a Redis object representing the key name. | ||
| 87 | * 'dbid' is the database ID where the key lives. */ | ||
| 88 | void notifyKeyspaceEvent(int type, const char *event, robj *key, int dbid) { | ||
| 89 | sds chan; | ||
| 90 | robj *chanobj, *eventobj; | ||
| 91 | int len = -1; | ||
| 92 | char buf[24]; | ||
| 93 | |||
| 94 | /* If any modules are interested in events, notify the module system now. | ||
| 95 | * This bypasses the notifications configuration, but the module engine | ||
| 96 | * will only call event subscribers if the event type matches the types | ||
| 97 | * they are interested in. */ | ||
| 98 | moduleNotifyKeyspaceEvent(type, event, key, dbid); | ||
| 99 | |||
| 100 | /* If notifications for this class of events are off, return ASAP. */ | ||
| 101 | if (!(server.notify_keyspace_events & type)) return; | ||
| 102 | |||
| 103 | eventobj = createStringObject(event,strlen(event)); | ||
| 104 | |||
| 105 | /* __keyspace@<db>__:<key> <event> notifications. */ | ||
| 106 | if (server.notify_keyspace_events & NOTIFY_KEYSPACE) { | ||
| 107 | chan = sdsnewlen("__keyspace@",11); | ||
| 108 | len = ll2string(buf,sizeof(buf),dbid); | ||
| 109 | chan = sdscatlen(chan, buf, len); | ||
| 110 | chan = sdscatlen(chan, "__:", 3); | ||
| 111 | chan = sdscatsds(chan, key->ptr); | ||
| 112 | chanobj = createObject(OBJ_STRING, chan); | ||
| 113 | pubsubPublishMessage(chanobj, eventobj, 0); | ||
| 114 | decrRefCount(chanobj); | ||
| 115 | } | ||
| 116 | |||
| 117 | /* __keyevent@<db>__:<event> <key> notifications. */ | ||
| 118 | if (server.notify_keyspace_events & NOTIFY_KEYEVENT) { | ||
| 119 | chan = sdsnewlen("__keyevent@",11); | ||
| 120 | if (len == -1) len = ll2string(buf,sizeof(buf),dbid); | ||
| 121 | chan = sdscatlen(chan, buf, len); | ||
| 122 | chan = sdscatlen(chan, "__:", 3); | ||
| 123 | chan = sdscatsds(chan, eventobj->ptr); | ||
| 124 | chanobj = createObject(OBJ_STRING, chan); | ||
| 125 | pubsubPublishMessage(chanobj, key, 0); | ||
| 126 | decrRefCount(chanobj); | ||
| 127 | } | ||
| 128 | decrRefCount(eventobj); | ||
| 129 | } | ||
