/* 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. * * event 参数是一个字符串表示的事件名 * * 'key' is a Redis object representing the key name. * * key 参数是一个 Redis 对象表示的键名 * * 'dbid' is the database ID where the key lives. * * dbid 参数为键所在的数据库 */ void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) { sds chan; robj *chanobj, *eventobj; int len = -1; char buf[24]; /* If notifications for this class of events are off, return ASAP. */ // 如果服务器配置为不发送 type 类型的通知,那么直接返回 if (!(server.notify_keyspace_events & type)) return; // 事件的名字 eventobj = createStringObject(event,strlen(event)); /* __keyspace@<db>__:<key> <event> notifications. */ // 发送键空间通知 if (server.notify_keyspace_events & REDIS_NOTIFY_KEYSPACE) { // 构建频道对象 chan = sdsnewlen("__keyspace@",11); len = ll2string(buf,sizeof(buf),dbid); chan = sdscatlen(chan, buf, len); chan = sdscatlen(chan, "__:", 3); chan = sdscatsds(chan, key->ptr); chanobj = createObject(REDIS_STRING, chan); // 通过 publish 命令发送通知 pubsubPublishMessage(chanobj, eventobj); // 释放频道对象 decrRefCount(chanobj); } /* __keyevente@<db>__:<event> <key> notifications. */ // 发送键事件通知 if (server.notify_keyspace_events & REDIS_NOTIFY_KEYEVENT) { // 构建频道对象 chan = sdsnewlen("__keyevent@",11); // 如果在前面发送键空间通知的时候计算了 len ,那么它就不会是 -1 // 这可以避免计算两次 buf 的长度 if (len == -1) len = ll2string(buf,sizeof(buf),dbid); chan = sdscatlen(chan, buf, len); chan = sdscatlen(chan, "__:", 3); chan = sdscatsds(chan, eventobj->ptr); chanobj = createObject(REDIS_STRING, chan); // 通过 publish 命令发送通知 pubsubPublishMessage(chanobj, key); // 释放频道对象 decrRefCount(chanobj); } // 释放事件对象 decrRefCount(eventobj); }
static S mk_trie_dirs(const TF * const fort, void * hash, size_t hashlen, sds * path) { *path = sdsnew(fort->path); *path = sdscat(*path, "/"); char dir_node[(fort->cfg.width * 2) + 2]; uint8_t * hashb = hash; for (size_t i = 0; i < fort->cfg.depth; i++) { for (size_t j = 0; j < fort->cfg.width; j++) { char * strpos = &dir_node[j * 2]; size_t hashix = (i * fort->cfg.width) + j; snprintf(strpos, sizeof(dir_node), "%02x/", hashb[hashix]); } *path = sdscat(*path, dir_node); if (dir_exists(*path)) { continue; } else { PANIC_IF(0 != mkdir(*path, DIRMODE)); } } sds hash_str = mk_hash_str(hash, hashlen); *path = sdscatsds(*path, hash_str); sdsfree(hash_str); if (!dir_exists(*path)) { PANIC_IF(0 != mkdir(*path, DIRMODE)); } return triefort_ok; }
/* Like sdsjoin, but joins an array of SDS strings. */ sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) { sds join = sdsempty(); int j; for (j = 0; j < argc; j++) { join = sdscatsds(join, argv[j]); if (j != argc-1) join = sdscatlen(join,sep,seplen); } return join; }
void debugCommand(client *c) { if (!strcasecmp(c->argv[1]->ptr,"segfault")) { *((char*)-1) = 'x'; } else if (!strcasecmp(c->argv[1]->ptr,"oom")) { void *ptr = zmalloc(ULONG_MAX); /* Should trigger an out of memory. */ zfree(ptr); addReply(c,shared.ok); } else if (!strcasecmp(c->argv[1]->ptr,"assert")) { if (c->argc >= 3) c->argv[2] = tryObjectEncoding(c->argv[2]); serverAssertWithInfo(c,c->argv[0],1 == 2); } else if (!strcasecmp(c->argv[1]->ptr,"flushall")) { flushServerData(); addReply(c,shared.ok); } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) { flushServerData(); if (loadAppendOnlyFile(server.aof_filename) != C_OK) { addReply(c,shared.err); return; } serverLog(LL_WARNING,"Append Only File loaded by DEBUG LOADAOF"); addReply(c,shared.ok); } else if (!strcasecmp(c->argv[1]->ptr,"sleep") && c->argc == 3) { double dtime = strtod(c->argv[2]->ptr,NULL); long long utime = dtime*1000000; struct timespec tv; tv.tv_sec = utime / 1000000; tv.tv_nsec = (utime % 1000000) * 1000; nanosleep(&tv, NULL); addReply(c,shared.ok); } else if (!strcasecmp(c->argv[1]->ptr,"error") && c->argc == 3) { sds errstr = sdsnewlen("-",1); errstr = sdscatsds(errstr,c->argv[2]->ptr); errstr = sdsmapchars(errstr,"\n\r"," ",2); /* no newlines in errors. */ errstr = sdscatlen(errstr,"\r\n",2); addReplySds(c,errstr); } else if (!strcasecmp(c->argv[1]->ptr,"structsize") && c->argc == 2) { sds sizes = sdsempty(); sizes = sdscatprintf(sizes,"bits:%d ",(sizeof(void*) == 8)?64:32); sizes = sdscatprintf(sizes,"job:%d ", (int)sizeof(job)); sizes = sdscatprintf(sizes,"queue:%d ", (int)sizeof(queue)); sizes = sdscatprintf(sizes,"robj:%d ",(int)sizeof(robj)); sizes = sdscatprintf(sizes,"dictentry:%d ",(int)sizeof(dictEntry)); sizes = sdscatprintf(sizes,"sdshdr5:%d ",(int)sizeof(struct sdshdr5)); sizes = sdscatprintf(sizes,"sdshdr8:%d ",(int)sizeof(struct sdshdr8)); sizes = sdscatprintf(sizes,"sdshdr16:%d ",(int)sizeof(struct sdshdr16)); sizes = sdscatprintf(sizes,"sdshdr32:%d ",(int)sizeof(struct sdshdr32)); sizes = sdscatprintf(sizes,"sdshdr64:%d ",(int)sizeof(struct sdshdr64)); addReplyBulkSds(c,sizes); } else { addReplyErrorFormat(c, "Unknown DEBUG subcommand or wrong number of arguments for '%s'", (char*)c->argv[1]->ptr); } }
/* 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(int type, char *event, robj *key, int dbid) { sds chan; robj *chanobj, *eventobj; int len = -1; char buf[24]; /* If any modules are interested in events, notify the module system now. * This bypasses the notifications configuration, but the module engine * will only call event subscribers if the event type matches the types * they are interested in. */ moduleNotifyKeyspaceEvent(type, event, key, dbid); /* If notifications for this class of events are off, return ASAP. */ if (!(server.notify_keyspace_events & type)) return; eventobj = createStringObject(event,strlen(event)); /* __keyspace@<db>__:<key> <event> notifications. */ if (server.notify_keyspace_events & NOTIFY_KEYSPACE) { chan = sdsnewlen("__keyspace@",11); len = ll2string(buf,sizeof(buf),dbid); chan = sdscatlen(chan, buf, len); chan = sdscatlen(chan, "__:", 3); chan = sdscatsds(chan, key->ptr); chanobj = createObject(OBJ_STRING, chan); pubsubPublishMessage(chanobj, eventobj); decrRefCount(chanobj); } /* __keyevent@<db>__:<event> <key> notifications. */ if (server.notify_keyspace_events & NOTIFY_KEYEVENT) { chan = sdsnewlen("__keyevent@",11); if (len == -1) len = ll2string(buf,sizeof(buf),dbid); chan = sdscatlen(chan, buf, len); chan = sdscatlen(chan, "__:", 3); chan = sdscatsds(chan, eventobj->ptr); chanobj = createObject(OBJ_STRING, chan); pubsubPublishMessage(chanobj, key); decrRefCount(chanobj); } decrRefCount(eventobj); }
//通知键空间事件 void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) { sds chan; robj *chanobj, *eventobj; int len = -1; char buf[24]; /* If notifications for this class of events are off, return ASAP. */ if (!(server.notify_keyspace_events & type)) return; eventobj = createStringObject(event,strlen(event)); /* __keyspace@<db>__:<key> <event> notifications. */ if (server.notify_keyspace_events & REDIS_NOTIFY_KEYSPACE) { chan = sdsnewlen("__keyspace@",11); len = ll2string(buf,sizeof(buf),dbid); chan = sdscatlen(chan, buf, len); chan = sdscatlen(chan, "__:", 3); chan = sdscatsds(chan, key->ptr); chanobj = createObject(REDIS_STRING, chan); pubsubPublishMessage(chanobj, eventobj); decrRefCount(chanobj); } /* __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); chan = sdscatsds(chan, eventobj->ptr); chanobj = createObject(REDIS_STRING, chan); pubsubPublishMessage(chanobj, key); decrRefCount(chanobj); } decrRefCount(eventobj); }
/* Given the filename, return the absolute path as an SDS string, or NULL * if it fails for some reason. Note that "filename" may be an absolute path * already, this will be detected and handled correctly. * * The function does not try to normalize everything, but only the obvious * case of one or more "../" appearning at the start of "filename" * relative path. */ sds getAbsolutePath ( char *filename ) { char cwd[1024]; sds abspath; sds relpath = sdsnew (filename); relpath = sdstrim (relpath, " \r\n\t"); if ( relpath[0] == '/' ) return relpath; /* Path is already absolute. */ /* If path is relative, join cwd and relative path. */ if ( getcwd (cwd, sizeof (cwd )) == NULL ) { sdsfree (relpath); return NULL; } abspath = sdsnew (cwd); if ( sdslen (abspath) && abspath[sdslen (abspath) - 1] != '/' ) abspath = sdscat (abspath, "/"); /* At this point we have the current path always ending with "/", and * the trimmed relative path. Try to normalize the obvious case of * trailing ../ elements at the start of the path. * * For every "../" we find in the filename, we remove it and also remove * the last element of the cwd, unless the current cwd is "/". */ while ( sdslen (relpath) >= 3 && relpath[0] == '.' && relpath[1] == '.' && relpath[2] == '/' ) { sdsrange (relpath, 3, - 1); if ( sdslen (abspath) > 1 ) { char *p = abspath + sdslen (abspath) - 2; int trimlen = 1; while ( *p != '/' ) { p --; trimlen ++; } sdsrange (abspath, 0, - ( trimlen + 1 )); } } /* Finally glue the two parts together. */ abspath = sdscatsds (abspath, relpath); sdsfree (relpath); return abspath; }