From 8e219224b9c9112806ecc868156fdc0b5e0b6d80 Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 11 Mar 2015 16:59:56 +0100 Subject: [PATCH] CONFIG refactoring: configEnum abstraction. Still many things to convert inside config.c in the next commits. Some const safety in String objects creation and addReply() family functions. --- src/config.c | 157 ++++++++++++++++++++++++++--------------------- src/networking.c | 18 +++--- src/object.c | 6 +- src/redis.c | 2 +- src/redis.h | 18 +++--- 5 files changed, 108 insertions(+), 93 deletions(-) diff --git a/src/config.c b/src/config.c index 7240d4a0..bfdc63a8 100644 --- a/src/config.c +++ b/src/config.c @@ -34,10 +34,26 @@ #include #include -static struct { - const char *name; - const int value; -} validSyslogFacilities[] = { +/*----------------------------------------------------------------------------- + * Config file name-value maps. + *----------------------------------------------------------------------------*/ + +typedef struct configEnum { + const char *name; + const int val; +} configEnum; + +configEnum maxmemory_policy_enum[] = { + {"volatile-lru", REDIS_MAXMEMORY_VOLATILE_LRU}, + {"volatile-random",REDIS_MAXMEMORY_VOLATILE_RANDOM}, + {"volatile-ttl",REDIS_MAXMEMORY_VOLATILE_TTL}, + {"allkeys-lru",REDIS_MAXMEMORY_ALLKEYS_LRU}, + {"allkeys-random",REDIS_MAXMEMORY_ALLKEYS_RANDOM}, + {"noeviction",REDIS_MAXMEMORY_NO_EVICTION}, + {NULL, 0} +}; + +configEnum syslog_facility_enum[] = { {"user", LOG_USER}, {"local0", LOG_LOCAL0}, {"local1", LOG_LOCAL1}, @@ -50,12 +66,47 @@ static struct { {NULL, 0} }; +/* Output buffer limits presets. */ clientBufferLimitsConfig clientBufferLimitsDefaults[REDIS_CLIENT_TYPE_COUNT] = { {0, 0, 0}, /* normal */ {1024*1024*256, 1024*1024*64, 60}, /* slave */ {1024*1024*32, 1024*1024*8, 60} /* pubsub */ }; +/*----------------------------------------------------------------------------- + * Enum access functions + *----------------------------------------------------------------------------*/ + +/* Get enum value from name. If there is no match INT_MIN is returned. */ +int configEnumGetValue(configEnum *ce, char *name) { + while(ce->name != NULL) { + if (!strcasecmp(ce->name,name)) return ce->val; + ce++; + } + return INT_MIN; +} + +/* Get enum name from value. If no match is found NULL is returned. */ +const char *configEnumGetName(configEnum *ce, int val) { + while(ce->name != NULL) { + if (ce->val == val) return ce->name; + ce++; + } + return NULL; +} + +/* Wrapper for configEnumGetName() returning "unknown" insetad of NULL if + * there is no match. */ +const char *configEnumGetNameOrUnknown(configEnum *ce, int val) { + const char *name = configEnumGetName(ce,val); + return name ? name : "unknown"; +} + +/* Used for INFO generation. */ +const char *maxmemoryToString(void) { + return configEnumGetNameOrUnknown(maxmemory_policy_enum,server.maxmemory); +} + /*----------------------------------------------------------------------------- * Config file parsing *----------------------------------------------------------------------------*/ @@ -201,16 +252,9 @@ void loadServerConfigFromString(char *config) { if (server.syslog_ident) zfree(server.syslog_ident); server.syslog_ident = zstrdup(argv[1]); } else if (!strcasecmp(argv[0],"syslog-facility") && argc == 2) { - int i; - - for (i = 0; validSyslogFacilities[i].name; i++) { - if (!strcasecmp(validSyslogFacilities[i].name, argv[1])) { - server.syslog_facility = validSyslogFacilities[i].value; - break; - } - } - - if (!validSyslogFacilities[i].name) { + server.syslog_facility = + configEnumGetValue(syslog_facility_enum,argv[1]); + if (server.syslog_facility == INT_MIN) { err = "Invalid log facility. Must be one of USER or between LOCAL0-LOCAL7"; goto loaderr; } @@ -229,19 +273,9 @@ void loadServerConfigFromString(char *config) { } else if (!strcasecmp(argv[0],"maxmemory") && argc == 2) { server.maxmemory = memtoll(argv[1],NULL); } else if (!strcasecmp(argv[0],"maxmemory-policy") && argc == 2) { - if (!strcasecmp(argv[1],"volatile-lru")) { - server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU; - } else if (!strcasecmp(argv[1],"volatile-random")) { - server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_RANDOM; - } else if (!strcasecmp(argv[1],"volatile-ttl")) { - server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_TTL; - } else if (!strcasecmp(argv[1],"allkeys-lru")) { - server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_LRU; - } else if (!strcasecmp(argv[1],"allkeys-random")) { - server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_RANDOM; - } else if (!strcasecmp(argv[1],"noeviction")) { - server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION; - } else { + server.maxmemory_policy = + configEnumGetValue(maxmemory_policy_enum,argv[1]); + if (server.maxmemory_policy == INT_MIN) { err = "Invalid maxmemory policy"; goto loaderr; } @@ -640,6 +674,12 @@ void loadServerConfig(char *filename, char *options) { if (err || ll < 0) goto badfmt; \ _var = ll; +#define config_set_enum_field(_name,_var,_enumvar) \ + } else if (!strcasecmp(c->argv[2]->ptr,_name)) { \ + int enumval = configEnumGetValue(_enumvar,o->ptr); \ + if (enumval == INT_MIN) goto badfmt; \ + _var = enumval; + #define config_set_special_field(_name) \ } else if (!strcasecmp(c->argv[2]->ptr,_name)) { @@ -694,22 +734,8 @@ void configSetCommand(redisClient *c) { } } } - } config_set_special_field("maxmemory-policy") { - if (!strcasecmp(o->ptr,"volatile-lru")) { - server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU; - } else if (!strcasecmp(o->ptr,"volatile-random")) { - server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_RANDOM; - } else if (!strcasecmp(o->ptr,"volatile-ttl")) { - server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_TTL; - } else if (!strcasecmp(o->ptr,"allkeys-lru")) { - server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_LRU; - } else if (!strcasecmp(o->ptr,"allkeys-random")) { - server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_RANDOM; - } else if (!strcasecmp(o->ptr,"noeviction")) { - server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION; - } else { - goto badfmt; - } + } config_set_enum_field( + "maxmemory-policy",server.maxmemory_policy,maxmemory_policy_enum) { } config_set_special_field("appendfsync") { if (!strcasecmp(o->ptr,"no")) { server.aof_fsync = AOF_FSYNC_NO; @@ -988,19 +1014,13 @@ badfmt: /* Bad format errors */ } \ } while(0); -char *maxmemoryToString() { - char *s; - switch(server.maxmemory_policy) { - case REDIS_MAXMEMORY_VOLATILE_LRU: s = "volatile-lru"; break; - case REDIS_MAXMEMORY_VOLATILE_TTL: s = "volatile-ttl"; break; - case REDIS_MAXMEMORY_VOLATILE_RANDOM: s = "volatile-random"; break; - case REDIS_MAXMEMORY_ALLKEYS_LRU: s = "allkeys-lru"; break; - case REDIS_MAXMEMORY_ALLKEYS_RANDOM: s = "allkeys-random"; break; - case REDIS_MAXMEMORY_NO_EVICTION: s = "noeviction"; break; - default: s = "unknown"; break; - } - return s; -} +#define config_get_enum_field(_name,_var,_enumvar) do { \ + if (stringmatch(pattern,_name,0)) { \ + addReplyBulkCString(c,_name); \ + addReplyBulkCString(c,configEnumGetNameOrUnknown(_enumvar,_var)); \ + matches++; \ + } \ +} while(0); int supervisedToMode(const char *str) { int mode; @@ -1029,6 +1049,7 @@ char *supervisedToString(void) { } return s; } + void configGetCommand(redisClient *c) { robj *o = c->argv[2]; void *replylen = addDeferredMultiBulkLength(c); @@ -1119,6 +1140,10 @@ void configGetCommand(redisClient *c) { config_get_bool_field("aof-load-truncated", server.aof_load_truncated); + /* Enum values */ + config_get_enum_field("maxmemory-policy", + server.maxmemory_policy,maxmemory_policy_enum); + /* Everything we can't handle with macros follows. */ if (stringmatch(pattern,"appendonly",0)) { @@ -1136,11 +1161,6 @@ void configGetCommand(redisClient *c) { addReplyBulkCString(c,buf); matches++; } - if (stringmatch(pattern,"maxmemory-policy",0)) { - addReplyBulkCString(c,"maxmemory-policy"); - addReplyBulkCString(c,maxmemoryToString()); - matches++; - } if (stringmatch(pattern,"appendfsync",0)) { char *policy; @@ -1313,7 +1333,7 @@ void rewriteConfigAddLineNumberToOption(struct rewriteConfigState *state, sds op * This is useful as only unused lines of processed options will be blanked * in the config file, while options the rewrite process does not understand * remain untouched. */ -void rewriteConfigMarkAsProcessed(struct rewriteConfigState *state, char *option) { +void rewriteConfigMarkAsProcessed(struct rewriteConfigState *state, const char *option) { sds opt = sdsnew(option); if (dictAdd(state->rewritten,opt,NULL) != DICT_OK) sdsfree(opt); @@ -1397,7 +1417,7 @@ struct rewriteConfigState *rewriteConfigReadOldFile(char *path) { * * "line" is either used, or freed, so the caller does not need to free it * in any way. */ -void rewriteConfigRewriteLine(struct rewriteConfigState *state, char *option, sds line, int force) { +void rewriteConfigRewriteLine(struct rewriteConfigState *state, const char *option, sds line, int force) { sds o = sdsnew(option); list *l = dictFetchValue(state->option_to_line,o); @@ -1536,17 +1556,12 @@ void rewriteConfigEnumOption(struct rewriteConfigState *state, char *option, int /* Rewrite the syslog-facility option. */ void rewriteConfigSyslogfacilityOption(struct rewriteConfigState *state) { - int value = server.syslog_facility, j; + int value = server.syslog_facility; int force = value != LOG_LOCAL0; - char *name = NULL, *option = "syslog-facility"; + const char *name = NULL, *option = "syslog-facility"; sds line; - for (j = 0; validSyslogFacilities[j].name; j++) { - if (validSyslogFacilities[j].value == value) { - name = (char*) validSyslogFacilities[j].name; - break; - } - } + name = configEnumGetNameOrUnknown(syslog_facility_enum,value); line = sdscatprintf(sdsempty(),"%s %s",option,name); rewriteConfigRewriteLine(state,option,line,force); } diff --git a/src/networking.c b/src/networking.c index 58275a21..1125b86f 100644 --- a/src/networking.c +++ b/src/networking.c @@ -175,7 +175,7 @@ robj *dupLastObjectIfNeeded(list *reply) { * Low level functions to add more data to output buffers. * -------------------------------------------------------------------------- */ -int _addReplyToBuffer(redisClient *c, char *s, size_t len) { +int _addReplyToBuffer(redisClient *c, const char *s, size_t len) { size_t available = sizeof(c->buf)-c->bufpos; if (c->flags & REDIS_CLOSE_AFTER_REPLY) return REDIS_OK; @@ -255,7 +255,7 @@ void _addReplySdsToList(redisClient *c, sds s) { asyncCloseClientOnOutputBufferLimitReached(c); } -void _addReplyStringToList(redisClient *c, char *s, size_t len) { +void _addReplyStringToList(redisClient *c, const char *s, size_t len) { robj *tail; if (c->flags & REDIS_CLOSE_AFTER_REPLY) return; @@ -341,19 +341,19 @@ void addReplySds(redisClient *c, sds s) { } } -void addReplyString(redisClient *c, char *s, size_t len) { +void addReplyString(redisClient *c, const char *s, size_t len) { if (prepareClientToWrite(c) != REDIS_OK) return; if (_addReplyToBuffer(c,s,len) != REDIS_OK) _addReplyStringToList(c,s,len); } -void addReplyErrorLength(redisClient *c, char *s, size_t len) { +void addReplyErrorLength(redisClient *c, const char *s, size_t len) { addReplyString(c,"-ERR ",5); addReplyString(c,s,len); addReplyString(c,"\r\n",2); } -void addReplyError(redisClient *c, char *err) { +void addReplyError(redisClient *c, const char *err) { addReplyErrorLength(c,err,strlen(err)); } @@ -373,13 +373,13 @@ void addReplyErrorFormat(redisClient *c, const char *fmt, ...) { sdsfree(s); } -void addReplyStatusLength(redisClient *c, char *s, size_t len) { +void addReplyStatusLength(redisClient *c, const char *s, size_t len) { addReplyString(c,"+",1); addReplyString(c,s,len); addReplyString(c,"\r\n",2); } -void addReplyStatus(redisClient *c, char *status) { +void addReplyStatus(redisClient *c, const char *status) { addReplyStatusLength(c,status,strlen(status)); } @@ -519,7 +519,7 @@ void addReplyBulk(redisClient *c, robj *obj) { } /* Add a C buffer as bulk reply */ -void addReplyBulkCBuffer(redisClient *c, void *p, size_t len) { +void addReplyBulkCBuffer(redisClient *c, const void *p, size_t len) { addReplyLongLongWithPrefix(c,len,'$'); addReplyString(c,p,len); addReply(c,shared.crlf); @@ -534,7 +534,7 @@ void addReplyBulkSds(redisClient *c, sds s) { } /* Add a C nul term string as bulk reply */ -void addReplyBulkCString(redisClient *c, char *s) { +void addReplyBulkCString(redisClient *c, const char *s) { if (s == NULL) { addReply(c,shared.nullbulk); } else { diff --git a/src/object.c b/src/object.c index 8905db18..dcd89691 100644 --- a/src/object.c +++ b/src/object.c @@ -50,14 +50,14 @@ robj *createObject(int type, void *ptr) { /* Create a string object with encoding REDIS_ENCODING_RAW, that is a plain * string object where o->ptr points to a proper sds string. */ -robj *createRawStringObject(char *ptr, size_t len) { +robj *createRawStringObject(const char *ptr, size_t len) { return createObject(REDIS_STRING,sdsnewlen(ptr,len)); } /* Create a string object with encoding REDIS_ENCODING_EMBSTR, that is * an object where the sds string is actually an unmodifiable string * allocated in the same chunk as the object itself. */ -robj *createEmbeddedStringObject(char *ptr, size_t len) { +robj *createEmbeddedStringObject(const char *ptr, size_t len) { robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr)+len+1); struct sdshdr *sh = (void*)(o+1); @@ -85,7 +85,7 @@ robj *createEmbeddedStringObject(char *ptr, size_t len) { * The current limit of 39 is chosen so that the biggest string object * we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */ #define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 39 -robj *createStringObject(char *ptr, size_t len) { +robj *createStringObject(const char *ptr, size_t len) { if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT) return createEmbeddedStringObject(ptr,len); else diff --git a/src/redis.c b/src/redis.c index 86b5a9eb..7c9ec902 100644 --- a/src/redis.c +++ b/src/redis.c @@ -2742,7 +2742,7 @@ sds genRedisInfoString(char *section) { char maxmemory_hmem[64]; size_t zmalloc_used = zmalloc_used_memory(); size_t total_system_mem = server.system_memory_size; - char *evict_policy = maxmemoryToString(); + const char *evict_policy = maxmemoryToString(); long long memory_lua = (long long)lua_gc(server.lua,LUA_GCCOUNT,0)*1024; /* Peak memory is updated from time to time by serverCron() so it diff --git a/src/redis.h b/src/redis.h index 232ada5e..34d8b0a4 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1053,14 +1053,14 @@ void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask); void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask); void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask); void addReplyBulk(redisClient *c, robj *obj); -void addReplyBulkCString(redisClient *c, char *s); -void addReplyBulkCBuffer(redisClient *c, void *p, size_t len); +void addReplyBulkCString(redisClient *c, const char *s); +void addReplyBulkCBuffer(redisClient *c, const void *p, size_t len); void addReplyBulkLongLong(redisClient *c, long long ll); void addReply(redisClient *c, robj *obj); void addReplySds(redisClient *c, sds s); void addReplyBulkSds(redisClient *c, sds s); -void addReplyError(redisClient *c, char *err); -void addReplyStatus(redisClient *c, char *status); +void addReplyError(redisClient *c, const char *err); +void addReplyStatus(redisClient *c, const char *status); void addReplyDouble(redisClient *c, double d); void addReplyLongLong(redisClient *c, long long ll); void addReplyMultiBulkLen(redisClient *c, long length); @@ -1136,9 +1136,9 @@ void freeSetObject(robj *o); void freeZsetObject(robj *o); void freeHashObject(robj *o); robj *createObject(int type, void *ptr); -robj *createStringObject(char *ptr, size_t len); -robj *createRawStringObject(char *ptr, size_t len); -robj *createEmbeddedStringObject(char *ptr, size_t len); +robj *createStringObject(const char *ptr, size_t len); +robj *createRawStringObject(const char *ptr, size_t len); +robj *createEmbeddedStringObject(const char *ptr, size_t len); robj *dupStringObject(robj *o); int isObjectRepresentableAsLongLong(robj *o, long long *llongval); robj *tryObjectEncoding(robj *o); @@ -1274,7 +1274,7 @@ void closeListeningSockets(int unlink_unix_socket); void updateCachedTime(void); void resetServerStats(void); unsigned int getLRUClock(void); -char *maxmemoryToString(void); +const char *maxmemoryToString(void); /* Set data type */ robj *setTypeCreate(robj *value); @@ -1327,7 +1327,7 @@ void loadServerConfig(char *filename, char *options); void appendServerSaveParams(time_t seconds, int changes); void resetServerSaveParams(void); struct rewriteConfigState; /* Forward declaration to export API. */ -void rewriteConfigRewriteLine(struct rewriteConfigState *state, char *option, sds line, int force); +void rewriteConfigRewriteLine(struct rewriteConfigState *state, const char *option, sds line, int force); int rewriteConfig(char *path); /* db.c -- Keyspace access API */