From d1c93ee8e19bcfa3fd19d82f809bd23c3899330d Mon Sep 17 00:00:00 2001 From: John Sully Date: Wed, 6 Mar 2019 16:29:30 -0500 Subject: [PATCH 1/2] port server.c to server.cpp Former-commit-id: 09e6a4fee09b1a61e6d2ac83a2c8fec9978474ec --- src/asciilogo.h | 2 +- src/bio.h | 8 ++++ src/config.h | 6 +++ src/latency.c | 2 +- src/latency.h | 11 ++++- src/module.c | 2 +- src/{server.c => server.cpp} | 92 ++++++++++++++++++------------------ src/server.h | 14 +++--- src/slowlog.h | 8 ++++ 9 files changed, 88 insertions(+), 57 deletions(-) rename src/{server.c => server.cpp} (98%) diff --git a/src/asciilogo.h b/src/asciilogo.h index 514902001..5264a6919 100644 --- a/src/asciilogo.h +++ b/src/asciilogo.h @@ -27,7 +27,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -char *ascii_logo = +const char *ascii_logo = " \n" " \n" " KeyDB %s (%s/%d) %s bit\n" diff --git a/src/bio.h b/src/bio.h index 4b15d1c4d..5349005b1 100644 --- a/src/bio.h +++ b/src/bio.h @@ -27,6 +27,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#ifdef __cplusplus +extern "C" { +#endif + /* Exported API */ void bioInit(void); void bioCreateBackgroundJob(int type, void *arg1, void *arg2, void *arg3); @@ -40,3 +44,7 @@ void bioKillThreads(void); #define BIO_AOF_FSYNC 1 /* Deferred AOF fsync. */ #define BIO_LAZY_FREE 2 /* Deferred objects freeing. */ #define BIO_NUM_OPS 3 + +#ifdef __cplusplus +} +#endif diff --git a/src/config.h b/src/config.h index efa9d11f2..d6bcc11d9 100644 --- a/src/config.h +++ b/src/config.h @@ -126,8 +126,14 @@ #if ((defined __linux && defined(__GLIBC__)) || defined __APPLE__) #define USE_SETPROCTITLE #define INIT_SETPROCTITLE_REPLACEMENT +#ifdef __cplusplus +extern "C" { +#endif void spt_init(int argc, char *argv[]); void setproctitle(const char *fmt, ...); +#ifdef __cplusplus +} +#endif #endif /* Byte ordering detection */ diff --git a/src/latency.c b/src/latency.c index 278ef4d29..f1e920484 100644 --- a/src/latency.c +++ b/src/latency.c @@ -95,7 +95,7 @@ void latencyMonitorInit(void) { * This function is usually called via latencyAddSampleIfNeeded(), that * is a macro that only adds the sample if the latency is higher than * server.latency_monitor_threshold. */ -void latencyAddSample(char *event, mstime_t latency) { +void latencyAddSample(const char *event, mstime_t latency) { struct latencyTimeSeries *ts = dictFetchValue(server.latency_events,event); time_t now = time(NULL); int prev; diff --git a/src/latency.h b/src/latency.h index 0fe26e0e4..e4f31b5d6 100644 --- a/src/latency.h +++ b/src/latency.h @@ -34,6 +34,10 @@ #ifndef __LATENCY_H #define __LATENCY_H +#ifdef __cplusplus +extern "C" { +#endif + #define LATENCY_TS_LEN 160 /* History length for every monitored event. */ /* Representation of a latency sample: the sampling time and the latency @@ -62,7 +66,7 @@ struct latencyStats { }; void latencyMonitorInit(void); -void latencyAddSample(char *event, mstime_t latency); +void latencyAddSample(const char *event, mstime_t latency); int THPIsEnabled(void); /* Latency monitoring macros. */ @@ -90,4 +94,9 @@ int THPIsEnabled(void); #define latencyRemoveNestedEvent(event_var,nested_var) \ event_var += nested_var; +#ifdef __cplusplus +} +#endif + #endif /* __LATENCY_H */ + diff --git a/src/module.c b/src/module.c index 7cb059b34..98a085159 100644 --- a/src/module.c +++ b/src/module.c @@ -4739,7 +4739,7 @@ void moduleUnregisterCommands(struct RedisModule *module) { if (cmd->proc == RedisModuleCommandDispatcher) { RedisModuleCommandProxy *cp = (void*)(unsigned long)cmd->getkeys_proc; - sds cmdname = cp->rediscmd->name; + sds cmdname = (sds)cp->rediscmd->name; if (cp->module == module) { dictDelete(server.commands,cmdname); dictDelete(server.orig_commands,cmdname); diff --git a/src/server.c b/src/server.cpp similarity index 98% rename from src/server.c rename to src/server.cpp index bdeff0e45..cfc7c9ced 100644 --- a/src/server.c +++ b/src/server.cpp @@ -1008,7 +1008,7 @@ struct redisCommand redisCommandTable[] = { /* We use a private localtime implementation which is fork-safe. The logging * function of Redis may be called from other threads. */ -void nolocks_localtime(struct tm *tmp, time_t t, time_t tz, int dst); +extern "C" void nolocks_localtime(struct tm *tmp, time_t t, time_t tz, int dst); /* Low level logging. To use only for very big messages, otherwise * serverLog() is to prefer. */ @@ -1133,13 +1133,13 @@ void exitFromChild(int retcode) { * keys and redis objects as values (objects can hold SDS strings, * lists, sets). */ -void dictVanillaFree(void *privdata, void *val) +extern "C" void dictVanillaFree(void *privdata, void *val) { DICT_NOTUSED(privdata); zfree(val); } -void dictListDestructor(void *privdata, void *val) +extern "C" void dictListDestructor(void *privdata, void *val) { DICT_NOTUSED(privdata); listRelease((list*)val); @@ -1159,12 +1159,12 @@ int dictSdsKeyCompare(void *privdata, const void *key1, /* A case insensitive version used for the command lookup table and other * places where case insensitive non binary-safe comparison is needed. */ -int dictSdsKeyCaseCompare(void *privdata, const void *key1, +extern "C" int dictSdsKeyCaseCompare(void *privdata, const void *key1, const void *key2) { DICT_NOTUSED(privdata); - return strcasecmp(key1, key2) == 0; + return strcasecmp((const char*)key1, (const char*)key2) == 0; } void dictObjectDestructor(void *privdata, void *val) @@ -1172,25 +1172,25 @@ void dictObjectDestructor(void *privdata, void *val) DICT_NOTUSED(privdata); if (val == NULL) return; /* Lazy freeing will set value to NULL. */ - decrRefCount(val); + decrRefCount((robj*)val); } void dictSdsDestructor(void *privdata, void *val) { DICT_NOTUSED(privdata); - sdsfree(val); + sdsfree((sds)val); } int dictObjKeyCompare(void *privdata, const void *key1, const void *key2) { - const robj *o1 = key1, *o2 = key2; + const robj *o1 = (const robj*)key1, *o2 = (const robj*)key2; return dictSdsKeyCompare(privdata,ptrFromObj(o1),ptrFromObj(o2)); } uint64_t dictObjHash(const void *key) { - const robj *o = key; + const robj *o = (const robj*)key; void *ptr = ptrFromObj(o); return dictGenHashFunction(ptr, sdslen((sds)ptr)); } @@ -1199,7 +1199,7 @@ uint64_t dictSdsHash(const void *key) { return dictGenHashFunction((unsigned char*)key, sdslen((char*)key)); } -uint64_t dictSdsCaseHash(const void *key) { +extern "C" uint64_t dictSdsCaseHash(const void *key) { return dictGenCaseHashFunction((unsigned char*)key, sdslen((char*)key)); } @@ -1662,8 +1662,8 @@ void clientsCron(int iel) { * This way if the client must be removed from the list it's the * first element and we don't incur into O(N) computation. */ listRotate(server.clients); - head = listFirst(server.clients); - c = listNodeValue(head); + head = (listNode*)listFirst(server.clients); + c = (client*)listNodeValue(head); if (c->iel == iel) { fastlock_lock(&c->lock); @@ -2144,7 +2144,7 @@ void afterSleep(struct aeEventLoop *eventLoop) { /* =========================== Server initialization ======================== */ -void createSharedObjects(void) { +extern "C" void createSharedObjects(void) { int j; shared.crlf = createObject(OBJ_STRING,sdsnew("\r\n")); @@ -2858,7 +2858,7 @@ void initServer(void) { createSharedObjects(); adjustOpenFilesLimit(); - server.db = zmalloc(sizeof(redisDb)*server.dbnum, MALLOC_LOCAL); + server.db = (redisDb*)zmalloc(sizeof(redisDb)*server.dbnum, MALLOC_LOCAL); /* Create the Redis databases, and initialize other internal state. */ for (int j = 0; j < server.dbnum; j++) { @@ -2967,7 +2967,7 @@ void initServer(void) { /* Parse the flags string description 'strflags' and set them to the * command 'c'. If the flags are all valid C_OK is returned, otherwise * C_ERR is returned (yet the recognized flags are set in the command). */ -int populateCommandTableParseFlags(struct redisCommand *c, char *strflags) { +int populateCommandTableParseFlags(struct redisCommand *c, const char *strflags) { int argc; sds *argv; @@ -3074,7 +3074,7 @@ int redisOpArrayAppend(redisOpArray *oa, struct redisCommand *cmd, int dbid, { redisOp *op; - oa->ops = zrealloc(oa->ops,sizeof(redisOp)*(oa->numops+1), MALLOC_LOCAL); + oa->ops = (redisOp*)zrealloc(oa->ops,sizeof(redisOp)*(oa->numops+1), MALLOC_LOCAL); op = oa->ops+oa->numops; op->cmd = cmd; op->dbid = dbid; @@ -3101,15 +3101,15 @@ void redisOpArrayFree(redisOpArray *oa) { /* ====================== Commands lookup and execution ===================== */ -struct redisCommand *lookupCommand(sds name) { - return dictFetchValue(server.commands, name); +extern "C" struct redisCommand *lookupCommand(sds name) { + return (struct redisCommand*)dictFetchValue(server.commands, name); } -struct redisCommand *lookupCommandByCString(char *s) { +struct redisCommand *lookupCommandByCString(const char *s) { struct redisCommand *cmd; sds name = sdsnew(s); - cmd = dictFetchValue(server.commands, name); + cmd = (struct redisCommand*)dictFetchValue(server.commands, name); sdsfree(name); return cmd; } @@ -3122,9 +3122,9 @@ struct redisCommand *lookupCommandByCString(char *s) { * rewriteClientCommandVector() in order to set client->cmd pointer * correctly even if the command was renamed. */ struct redisCommand *lookupCommandOrOriginal(sds name) { - struct redisCommand *cmd = dictFetchValue(server.commands, name); + struct redisCommand *cmd = (struct redisCommand*)dictFetchValue(server.commands, name); - if (!cmd) cmd = dictFetchValue(server.orig_commands,name); + if (!cmd) cmd = (struct redisCommand*)dictFetchValue(server.orig_commands,name); return cmd; } @@ -3169,7 +3169,7 @@ void alsoPropagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, if (server.loading) return; /* No propagation during loading. */ - argvcopy = zmalloc(sizeof(robj*)*argc, MALLOC_LOCAL); + argvcopy = (robj**)zmalloc(sizeof(robj*)*argc, MALLOC_LOCAL); for (j = 0; j < argc; j++) { argvcopy[j] = argv[j]; incrRefCount(argv[j]); @@ -3286,7 +3286,7 @@ void call(client *c, int flags) { /* Log the command into the Slow log if needed, and populate the * per-command statistics that we show in INFO commandstats. */ if (flags & CMD_CALL_SLOWLOG && c->cmd->proc != execCommand) { - char *latency_event = (c->cmd->flags & CMD_FAST) ? + const char *latency_event = (c->cmd->flags & CMD_FAST) ? "fast-command" : "command"; latencyAddSampleIfNeeded(latency_event,duration/1000); slowlogPushEntryIfNeeded(c,c->argv,c->argc,duration); @@ -3378,7 +3378,7 @@ int processCommand(client *c) { * go through checking for replication and QUIT will cause trouble * when FORCE_REPLICATION is enabled and would be implemented in * a regular command proc. */ - if (!strcasecmp(ptrFromObj(c->argv[0]),"quit")) { + if (!strcasecmp((const char*)ptrFromObj(c->argv[0]),"quit")) { addReply(c,shared.ok); c->flags |= CLIENT_CLOSE_AFTER_REPLY; return C_ERR; @@ -3389,7 +3389,7 @@ int processCommand(client *c) { /* Now lookup the command and check ASAP about trivial error conditions * such as wrong arity, bad command name and so forth. */ - c->cmd = c->lastcmd = lookupCommand(ptrFromObj(c->argv[0])); + c->cmd = c->lastcmd = lookupCommand((sds)ptrFromObj(c->argv[0])); if (!c->cmd) { flagTransaction(c); sds args = sdsempty(); @@ -3754,7 +3754,7 @@ void timeCommand(client *c) { } /* Helper function for addReplyCommand() to output flags. */ -int addReplyCommandFlag(client *c, struct redisCommand *cmd, int f, char *reply) { +int addReplyCommandFlag(client *c, struct redisCommand *cmd, int f, const char *reply) { if (cmd->flags & f) { addReplyStatus(c, reply); return 1; @@ -3808,7 +3808,7 @@ void commandCommand(client *c) { dictIterator *di; dictEntry *de; - if (c->argc == 2 && !strcasecmp(ptrFromObj(c->argv[1]),"help")) { + if (c->argc == 2 && !strcasecmp((const char*)ptrFromObj(c->argv[1]),"help")) { const char *help[] = { "(no subcommand) -- Return details about all Redis commands.", "COUNT -- Return the total number of commands in this Redis server.", @@ -3821,19 +3821,19 @@ NULL addReplyArrayLen(c, dictSize(server.commands)); di = dictGetIterator(server.commands); while ((de = dictNext(di)) != NULL) { - addReplyCommand(c, dictGetVal(de)); + addReplyCommand(c, (redisCommand*)dictGetVal(de)); } dictReleaseIterator(di); - } else if (!strcasecmp(ptrFromObj(c->argv[1]), "info")) { + } else if (!strcasecmp((const char*)ptrFromObj(c->argv[1]), "info")) { int i; addReplyArrayLen(c, c->argc-2); for (i = 2; i < c->argc; i++) { - addReplyCommand(c, dictFetchValue(server.commands, ptrFromObj(c->argv[i]))); + addReplyCommand(c, (redisCommand*)dictFetchValue(server.commands, ptrFromObj(c->argv[i]))); } - } else if (!strcasecmp(ptrFromObj(c->argv[1]), "count") && c->argc == 2) { + } else if (!strcasecmp((const char*)ptrFromObj(c->argv[1]), "count") && c->argc == 2) { addReplyLongLong(c, dictSize(server.commands)); - } else if (!strcasecmp(ptrFromObj(c->argv[1]),"getkeys") && c->argc >= 3) { - struct redisCommand *cmd = lookupCommand(ptrFromObj(c->argv[2])); + } else if (!strcasecmp((const char*)ptrFromObj(c->argv[1]),"getkeys") && c->argc >= 3) { + struct redisCommand *cmd = (redisCommand*)lookupCommand((sds)ptrFromObj(c->argv[2])); int *keys, numkeys, j; if (!cmd) { @@ -3894,7 +3894,7 @@ void bytesToHuman(char *s, unsigned long long n) { /* Create the string returned by the INFO command. This is decoupled * by the INFO command itself as we need to report the same information * on memory corruption problems. */ -sds genRedisInfoString(char *section) { +extern "C" sds genRedisInfoString(const char *section) { sds info = sdsempty(); time_t uptime = server.unixtime-server.stat_starttime; int j; @@ -3913,7 +3913,7 @@ sds genRedisInfoString(char *section) { if (allsections || defsections || !strcasecmp(section,"server")) { static int call_uname = 1; static struct utsname name; - char *mode; + const char *mode; if (server.cluster_enabled) mode = "cluster"; else if (server.sentinel_mode) mode = "sentinel"; @@ -4333,8 +4333,8 @@ sds genRedisInfoString(char *section) { listRewind(server.slaves,&li); while((ln = listNext(&li))) { - client *slave = listNodeValue(ln); - char *state = NULL; + client *slave = (client*)listNodeValue(ln); + const char *state = NULL; char ip[NET_IP_STR_LEN], *slaveip = slave->slave_ip; int port; long lag = 0; @@ -4451,7 +4451,7 @@ sds genRedisInfoString(char *section) { } void infoCommand(client *c) { - char *section = c->argc == 2 ? ptrFromObj(c->argv[1]) : "default"; + const char *section = c->argc == 2 ? (const char*)ptrFromObj(c->argv[1]) : "default"; if (c->argc > 2) { addReply(c,shared.syntaxerr); @@ -4557,8 +4557,8 @@ void usage(void) { void redisAsciiArt(void) { #include "asciilogo.h" - char *buf = zmalloc(1024*16, MALLOC_LOCAL); - char *mode; + char *buf = (char*)zmalloc(1024*16, MALLOC_LOCAL); + const char *mode; if (server.cluster_enabled) mode = "cluster"; else if (server.sentinel_mode) mode = "sentinel"; @@ -4592,7 +4592,7 @@ void redisAsciiArt(void) { } static void sigShutdownHandler(int sig) { - char *msg; + const char *msg; switch (sig) { case SIGINT: @@ -4644,7 +4644,7 @@ void setupSignalHandlers(void) { return; } -void memtest(size_t megabytes, int passes); +extern "C" void memtest(size_t megabytes, int passes); /* Returns 1 if there is --sentinel among the arguments or if * argv[0] contains "keydb-sentinel". */ @@ -4701,7 +4701,7 @@ void redisOutOfMemoryHandler(size_t allocation_size) { void redisSetProcTitle(char *title) { #ifdef USE_SETPROCTITLE - char *server_mode = ""; + const char *server_mode = ""; if (server.cluster_enabled) server_mode = " [cluster]"; else if (server.sentinel_mode) server_mode = " [sentinel]"; @@ -4768,7 +4768,7 @@ int redisSupervisedSystemd(void) { su.sun_path[0] = '\0'; memset(&iov, 0, sizeof(iov)); - iov.iov_base = "READY=1"; + iov.iov_base = (void*)"READY=1"; iov.iov_len = strlen("READY=1"); memset(&hdr, 0, sizeof(hdr)); @@ -4890,7 +4890,7 @@ int main(int argc, char **argv) { /* Store the executable path and arguments in a safe place in order * to be able to restart the server later. */ server.executable = getAbsolutePath(argv[0]); - server.exec_argv = zmalloc(sizeof(char*)*(argc+1), MALLOC_LOCAL); + server.exec_argv = (char**)zmalloc(sizeof(char*)*(argc+1), MALLOC_LOCAL); server.exec_argv[argc] = NULL; for (j = 0; j < argc; j++) server.exec_argv[j] = zstrdup(argv[j]); diff --git a/src/server.h b/src/server.h index 9e64e8915..4fdaa4979 100644 --- a/src/server.h +++ b/src/server.h @@ -1429,10 +1429,10 @@ typedef struct pubsubPattern { typedef void redisCommandProc(client *c); typedef int *redisGetKeysProc(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); struct redisCommand { - char *name; + const char *name; redisCommandProc *proc; int arity; - char *sflags; /* Flags as string representation, one char per flag. */ + const char *sflags; /* Flags as string representation, one char per flag. */ uint64_t flags; /* The actual flags, obtained from the 'sflags' field. */ /* Use a function to determine keys arguments in a command line. * Used for Redis Cluster redirect. */ @@ -1908,7 +1908,7 @@ int freeMemoryIfNeededAndSafe(void); int processCommand(client *c); void setupSignalHandlers(void); struct redisCommand *lookupCommand(sds name); -struct redisCommand *lookupCommandByCString(char *s); +struct redisCommand *lookupCommandByCString(const char *s); struct redisCommand *lookupCommandOrOriginal(sds name); void call(client *c, int flags); void propagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, int flags); @@ -1917,7 +1917,7 @@ void forceCommandPropagation(client *c, int flags); void preventCommandPropagation(client *c); void preventCommandAOF(client *c); void preventCommandReplication(client *c); -int prepareForShutdown(); +int prepareForShutdown(int flags); #ifdef __GNUC__ void serverLog(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3))); @@ -2342,7 +2342,7 @@ void _serverPanic(const char *file, int line, const char *msg, ...); void bugReportStart(void); void serverLogObjectDebugInfo(const robj *o); void sigsegvHandler(int sig, siginfo_t *info, void *secret); -sds genRedisInfoString(char *section); +sds genRedisInfoString(const char *section); void enableWatchdog(int period); void disableWatchdog(void); void watchdogScheduleSignal(int period); @@ -2350,7 +2350,7 @@ void serverLogHexDump(int level, char *descr, void *value, size_t len); int memtest_preserving_test(unsigned long *m, size_t bytes, int passes); void mixDigest(unsigned char *digest, void *ptr, size_t len); void xorDigest(unsigned char *digest, void *ptr, size_t len); -int populateCommandTableParseFlags(struct redisCommand *c, char *strflags); +int populateCommandTableParseFlags(struct redisCommand *c, const char *strflags); inline int ielFromEventLoop(const aeEventLoop *eventLoop) { @@ -2379,4 +2379,4 @@ inline int FCorrectThread(client *c) } #endif -#endif \ No newline at end of file +#endif diff --git a/src/slowlog.h b/src/slowlog.h index 655fb25f4..9cdbd7721 100644 --- a/src/slowlog.h +++ b/src/slowlog.h @@ -30,6 +30,10 @@ #define SLOWLOG_ENTRY_MAX_ARGC 32 #define SLOWLOG_ENTRY_MAX_STRING 128 +#ifdef __cplusplus +extern "C" { +#endif + /* This structure defines an entry inside the slow log list */ typedef struct slowlogEntry { robj **argv; @@ -47,3 +51,7 @@ void slowlogPushEntryIfNeeded(client *c, robj **argv, int argc, long long durati /* Exported commands */ void slowlogCommand(client *c); + +#ifdef __cplusplus +} +#endif From 2d1931991545912a1d4ab8b82a5748f9ab25ae41 Mon Sep 17 00:00:00 2001 From: John Sully Date: Wed, 6 Mar 2019 16:39:02 -0500 Subject: [PATCH 2/2] Limit server-threads to cores in the machine Former-commit-id: be3ba1d53eb070719fd84c7573f665277a35b6f4 --- src/server.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/server.cpp b/src/server.cpp index cfc7c9ced..da2895664 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -35,7 +35,7 @@ #include "latency.h" #include "atomicvar.h" #include "storage.h" - +#include #include #include #include @@ -4986,11 +4986,17 @@ int main(int argc, char **argv) { (int)getpid()); if (argc == 1) { - serverLog(LL_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/%s.conf", argv[0], server.sentinel_mode ? "sentinel" : "redis"); + serverLog(LL_WARNING, "WARNING: no config file specified, using the default config. In order to specify a config file use %s /path/to/%s.conf", argv[0], server.sentinel_mode ? "sentinel" : "redis"); } else { serverLog(LL_WARNING, "Configuration loaded"); } + if (server.cthreads > (int)std::thread::hardware_concurrency()) { + serverLog(LL_WARNING, "WARNING: server-threads is greater than this machine's core count. Truncating to %u threads", std::thread::hardware_concurrency()); + server.cthreads = (int)std::thread::hardware_concurrency(); + server.cthreads = std::max(server.cthreads, 1); // in case of any weird sign overflows + } + server.supervised = redisIsSupervised(server.supervised_mode); int background = server.daemonize && !server.supervised; if (background) daemonize();