本文主要是介绍漫话Redis源码之七十二,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
这里主要是枚举和配置相关的:
configEnum syslog_facility_enum[] = {{"user", LOG_USER},{"local0", LOG_LOCAL0},{"local1", LOG_LOCAL1},{"local2", LOG_LOCAL2},{"local3", LOG_LOCAL3},{"local4", LOG_LOCAL4},{"local5", LOG_LOCAL5},{"local6", LOG_LOCAL6},{"local7", LOG_LOCAL7},{NULL, 0}
};configEnum loglevel_enum[] = {{"debug", LL_DEBUG},{"verbose", LL_VERBOSE},{"notice", LL_NOTICE},{"warning", LL_WARNING},{NULL,0}
};configEnum supervised_mode_enum[] = {{"upstart", SUPERVISED_UPSTART},{"systemd", SUPERVISED_SYSTEMD},{"auto", SUPERVISED_AUTODETECT},{"no", SUPERVISED_NONE},{NULL, 0}
};configEnum aof_fsync_enum[] = {{"everysec", AOF_FSYNC_EVERYSEC},{"always", AOF_FSYNC_ALWAYS},{"no", AOF_FSYNC_NO},{NULL, 0}
};configEnum repl_diskless_load_enum[] = {{"disabled", REPL_DISKLESS_LOAD_DISABLED},{"on-empty-db", REPL_DISKLESS_LOAD_WHEN_DB_EMPTY},{"swapdb", REPL_DISKLESS_LOAD_SWAPDB},{NULL, 0}
};configEnum tls_auth_clients_enum[] = {{"no", TLS_CLIENT_AUTH_NO},{"yes", TLS_CLIENT_AUTH_YES},{"optional", TLS_CLIENT_AUTH_OPTIONAL},{NULL, 0}
};configEnum oom_score_adj_enum[] = {{"no", OOM_SCORE_ADJ_NO},{"yes", OOM_SCORE_RELATIVE},{"relative", OOM_SCORE_RELATIVE},{"absolute", OOM_SCORE_ADJ_ABSOLUTE},{NULL, 0}
};configEnum acl_pubsub_default_enum[] = {{"allchannels", USER_FLAG_ALLCHANNELS},{"resetchannels", 0},{NULL, 0}
};configEnum sanitize_dump_payload_enum[] = {{"no", SANITIZE_DUMP_NO},{"yes", SANITIZE_DUMP_YES},{"clients", SANITIZE_DUMP_CLIENTS},{NULL, 0}
};/* Output buffer limits presets. */
clientBufferLimitsConfig clientBufferLimitsDefaults[CLIENT_TYPE_OBUF_COUNT] = {{0, 0, 0}, /* normal */{1024*1024*256, 1024*1024*64, 60}, /* slave */{1024*1024*32, 1024*1024*8, 60} /* pubsub */
};/* OOM Score defaults */
int configOOMScoreAdjValuesDefaults[CONFIG_OOM_COUNT] = { 0, 200, 800 };/* Generic config infrastructure function pointers* int is_valid_fn(val, err)* Return 1 when val is valid, and 0 when invalid.* Optionally set err to a static error string.* int update_fn(val, prev, err)* This function is called only for CONFIG SET command (not at config file parsing)* It is called after the actual config is applied,* Return 1 for success, and 0 for failure.* Optionally set err to a static error string.* On failure the config change will be reverted.*//* Configuration values that require no special handling to set, get, load or* rewrite. */
typedef struct boolConfigData {int *config; /* The pointer to the server config this value is stored in */const int default_value; /* The default value of the config on rewrite */int (*is_valid_fn)(int val, const char **err); /* Optional function to check validity of new value (generic doc above) */int (*update_fn)(int val, int prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */
} boolConfigData;typedef struct stringConfigData {char **config; /* Pointer to the server config this value is stored in. */const char *default_value; /* Default value of the config on rewrite. */int (*is_valid_fn)(char* val, const char **err); /* Optional function to check validity of new value (generic doc above) */int (*update_fn)(char* val, char* prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */int convert_empty_to_null; /* Boolean indicating if empty strings shouldbe stored as a NULL value. */
} stringConfigData;typedef struct sdsConfigData {sds *config; /* Pointer to the server config this value is stored in. */const char *default_value; /* Default value of the config on rewrite. */int (*is_valid_fn)(sds val, const char **err); /* Optional function to check validity of new value (generic doc above) */int (*update_fn)(sds val, sds prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */int convert_empty_to_null; /* Boolean indicating if empty SDS strings shouldbe stored as a NULL value. */
} sdsConfigData;typedef struct enumConfigData {int *config; /* The pointer to the server config this value is stored in */configEnum *enum_value; /* The underlying enum type this data represents */const int default_value; /* The default value of the config on rewrite */int (*is_valid_fn)(int val, const char **err); /* Optional function to check validity of new value (generic doc above) */int (*update_fn)(int val, int prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */
} enumConfigData;typedef enum numericType {NUMERIC_TYPE_INT,NUMERIC_TYPE_UINT,NUMERIC_TYPE_LONG,NUMERIC_TYPE_ULONG,NUMERIC_TYPE_LONG_LONG,NUMERIC_TYPE_ULONG_LONG,NUMERIC_TYPE_SIZE_T,NUMERIC_TYPE_SSIZE_T,NUMERIC_TYPE_OFF_T,NUMERIC_TYPE_TIME_T,
} numericType;typedef struct numericConfigData {union {int *i;unsigned int *ui;long *l;unsigned long *ul;long long *ll;unsigned long long *ull;size_t *st;ssize_t *sst;off_t *ot;time_t *tt;} config; /* The pointer to the numeric config this value is stored in */int is_memory; /* Indicates if this value can be loaded as a memory value */numericType numeric_type; /* An enum indicating the type of this value */long long lower_bound; /* The lower bound of this numeric value */long long upper_bound; /* The upper bound of this numeric value */const long long default_value; /* The default value of the config on rewrite */int (*is_valid_fn)(long long val, const char **err); /* Optional function to check validity of new value (generic doc above) */int (*update_fn)(long long val, long long prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */
} numericConfigData;typedef union typeData {boolConfigData yesno;stringConfigData string;sdsConfigData sds;enumConfigData enumd;numericConfigData numeric;
} typeData;typedef struct typeInterface {/* Called on server start, to init the server with default value */void (*init)(typeData data);/* Called on server startup and CONFIG SET, returns 1 on success, 0 on error* and can set a verbose err string, update is true when called from CONFIG SET */int (*set)(typeData data, sds value, int update, const char **err);/* Called on CONFIG GET, required to add output to the client */void (*get)(client *c, typeData data);/* Called on CONFIG REWRITE, required to rewrite the config state */void (*rewrite)(typeData data, const char *name, struct rewriteConfigState *state);
} typeInterface;typedef struct standardConfig {const char *name; /* The user visible name of this config */const char *alias; /* An alias that can also be used for this config */const unsigned int flags; /* Flags for this specific config */typeInterface interface; /* The function pointers that define the type interface */typeData data; /* The type specific data exposed used by the interface */
} standardConfig;#define MODIFIABLE_CONFIG 0 /* This is the implied default for a standard * config, which is mutable. */
#define IMMUTABLE_CONFIG (1ULL<<0) /* Can this value only be set at startup? */
#define SENSITIVE_CONFIG (1ULL<<1) /* Does this value contain sensitive information */standardConfig configs[];/*-----------------------------------------------------------------------------* 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" instead 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 *evictPolicyToString(void) {return configEnumGetNameOrUnknown(maxmemory_policy_enum,server.maxmemory_policy);
}/*-----------------------------------------------------------------------------* Config file parsing*----------------------------------------------------------------------------*/int yesnotoi(char *s) {if (!strcasecmp(s,"yes")) return 1;else if (!strcasecmp(s,"no")) return 0;else return -1;
}void appendServerSaveParams(time_t seconds, int changes) {server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));server.saveparams[server.saveparamslen].seconds = seconds;server.saveparams[server.saveparamslen].changes = changes;server.saveparamslen++;
}void resetServerSaveParams(void) {zfree(server.saveparams);server.saveparams = NULL;server.saveparamslen = 0;
}void queueLoadModule(sds path, sds *argv, int argc) {int i;struct moduleLoadQueueEntry *loadmod;loadmod = zmalloc(sizeof(struct moduleLoadQueueEntry));loadmod->argv = zmalloc(sizeof(robj*)*argc);loadmod->path = sdsnew(path);loadmod->argc = argc;for (i = 0; i < argc; i++) {loadmod->argv[i] = createRawStringObject(argv[i],sdslen(argv[i]));}listAddNodeTail(server.loadmodule_queue,loadmod);
}/* Parse an array of CONFIG_OOM_COUNT sds strings, validate and populate* server.oom_score_adj_values if valid.*/static int updateOOMScoreAdjValues(sds *args, const char **err, int apply) {int i;int values[CONFIG_OOM_COUNT];for (i = 0; i < CONFIG_OOM_COUNT; i++) {char *eptr;long long val = strtoll(args[i], &eptr, 10);if (*eptr != '\0' || val < -2000 || val > 2000) {if (err) *err = "Invalid oom-score-adj-values, elements must be between -2000 and 2000.";return C_ERR;}values[i] = val;}/* Verify that the values make sense. If they don't omit a warning but* keep the configuration, which may still be valid for privileged processes.*/if (values[CONFIG_OOM_REPLICA] < values[CONFIG_OOM_MASTER] ||values[CONFIG_OOM_BGCHILD] < values[CONFIG_OOM_REPLICA]) {serverLog(LOG_WARNING,"The oom-score-adj-values configuration may not work for non-privileged processes! ""Please consult the documentation.");}/* Store values, retain previous config for rollback in case we fail. */int old_values[CONFIG_OOM_COUNT];for (i = 0; i < CONFIG_OOM_COUNT; i++) {old_values[i] = server.oom_score_adj_values[i];server.oom_score_adj_values[i] = values[i];}/* When parsing the config file, we want to apply only when all is done. */if (!apply)return C_OK;/* Update */if (setOOMScoreAdj(-1) == C_ERR) {/* Roll back */for (i = 0; i < CONFIG_OOM_COUNT; i++)server.oom_score_adj_values[i] = old_values[i];if (err)*err = "Failed to apply oom-score-adj-values configuration, check server logs.";return C_ERR;}return C_OK;
}void initConfigValues() {for (standardConfig *config = configs; config->name != NULL; config++) {config->interface.init(config->data);}
}void loadServerConfigFromString(char *config) {const char *err = NULL;int linenum = 0, totlines, i;int slaveof_linenum = 0;sds *lines;int save_loaded = 0;lines = sdssplitlen(config,strlen(config),"\n",1,&totlines);for (i = 0; i < totlines; i++) {sds *argv;int argc;linenum = i+1;lines[i] = sdstrim(lines[i]," \t\r\n");/* Skip comments and blank lines */if (lines[i][0] == '#' || lines[i][0] == '\0') continue;/* Split into arguments */argv = sdssplitargs(lines[i],&argc);if (argv == NULL) {err = "Unbalanced quotes in configuration line";goto loaderr;}/* Skip this line if the resulting command vector is empty. */if (argc == 0) {sdsfreesplitres(argv,argc);continue;}sdstolower(argv[0]);/* Iterate the configs that are standard */int match = 0;for (standardConfig *config = configs; config->name != NULL; config++) {if ((!strcasecmp(argv[0],config->name) ||(config->alias && !strcasecmp(argv[0],config->alias)))){if (argc != 2) {err = "wrong number of arguments";goto loaderr;}if (!config->interface.set(config->data, argv[1], 0, &err)) {goto loaderr;}match = 1;break;}}if (match) {sdsfreesplitres(argv,argc);continue;}/* Execute config directives */if (!strcasecmp(argv[0],"bind") && argc >= 2) {int j, addresses = argc-1;if (addresses > CONFIG_BINDADDR_MAX) {err = "Too many bind addresses specified"; goto loaderr;}/* Free old bind addresses */for (j = 0; j < server.bindaddr_count; j++) {zfree(server.bindaddr[j]);}for (j = 0; j < addresses; j++)server.bindaddr[j] = zstrdup(argv[j+1]);server.bindaddr_count = addresses;} else if (!strcasecmp(argv[0],"unixsocketperm") && argc == 2) {errno = 0;server.unixsocketperm = (mode_t)strtol(argv[1], NULL, 8);if (errno || server.unixsocketperm > 0777) {err = "Invalid socket file permissions"; goto loaderr;}} else if (!strcasecmp(argv[0],"save")) {/* We don't reset save params before loading, because if they're not part* of the file the defaults should be used.*/if (!save_loaded) {save_loaded = 1;resetServerSaveParams();}if (argc == 3) {int seconds = atoi(argv[1]);int changes = atoi(argv[2]);if (seconds < 1 || changes < 0) {err = "Invalid save parameters"; goto loaderr;}appendServerSaveParams(seconds,changes);} else if (argc == 2 && !strcasecmp(argv[1],"")) {resetServerSaveParams();}} else if (!strcasecmp(argv[0],"dir") && argc == 2) {if (chdir(argv[1]) == -1) {serverLog(LL_WARNING,"Can't chdir to '%s': %s",argv[1], strerror(errno));exit(1);}} else if (!strcasecmp(argv[0],"logfile") && argc == 2) {FILE *logfp;zfree(server.logfile);server.logfile = zstrdup(argv[1]);if (server.logfile[0] != '\0') {/* Test if we are able to open the file. The server will not* be able to abort just for this problem later... */logfp = fopen(server.logfile,"a");if (logfp == NULL) {err = sdscatprintf(sdsempty(),"Can't open the log file: %s", strerror(errno));goto loaderr;}fclose(logfp);}} else if (!strcasecmp(argv[0],"include") && argc == 2) {loadServerConfig(argv[1], 0, NULL);} else if ((!strcasecmp(argv[0],"slaveof") ||!strcasecmp(argv[0],"replicaof")) && argc == 3) {slaveof_linenum = linenum;sdsfree(server.masterhost);if (!strcasecmp(argv[1], "no") && !strcasecmp(argv[2], "one")) {server.masterhost = NULL;continue;}server.masterhost = sdsnew(argv[1]);char *ptr;server.masterport = strtol(argv[2], &ptr, 10);if (server.masterport < 0 || server.masterport > 65535 || *ptr != '\0') {err = "Invalid master port"; goto loaderr;}server.repl_state = REPL_STATE_CONNECT;} else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){/* DEAD OPTION */} else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) {/* DEAD OPTION */} else if (!strcasecmp(argv[0],"rename-command") && argc == 3) {struct redisCommand *cmd = lookupCommand(argv[1]);int retval;if (!cmd) {err = "No such command in rename-command";goto loaderr;}/* If the target command name is the empty string we just* remove it from the command table. */retval = dictDelete(server.commands, argv[1]);serverAssert(retval == DICT_OK);/* Otherwise we re-add the command under a different name. */if (sdslen(argv[2]) != 0) {sds copy = sdsdup(argv[2]);retval = dictAdd(server.commands, copy, cmd);if (retval != DICT_OK) {sdsfree(copy);err = "Target command name already exists"; goto loaderr;}}} else if (!strcasecmp(argv[0],"cluster-config-file") && argc == 2) {zfree(server.cluster_configfile);server.cluster_configfile = zstrdup(argv[1]);} else if (!strcasecmp(argv[0],"client-output-buffer-limit") &&argc == 5){int class = getClientTypeByName(argv[1]);unsigned long long hard, soft;int soft_seconds;if (class == -1 || class == CLIENT_TYPE_MASTER) {err = "Unrecognized client limit class: the user specified ""an invalid one, or 'master' which has no buffer limits.";goto loaderr;}hard = memtoll(argv[2],NULL);soft = memtoll(argv[3],NULL);soft_seconds = atoi(argv[4]);if (soft_seconds < 0) {err = "Negative number of seconds in soft limit is invalid";goto loaderr;}server.client_obuf_limits[class].hard_limit_bytes = hard;server.client_obuf_limits[class].soft_limit_bytes = soft;server.client_obuf_limits[class].soft_limit_seconds = soft_seconds;} else if (!strcasecmp(argv[0],"oom-score-adj-values") && argc == 1 + CONFIG_OOM_COUNT) {if (updateOOMScoreAdjValues(&argv[1], &err, 0) == C_ERR) goto loaderr;} else if (!strcasecmp(argv[0],"notify-keyspace-events") && argc == 2) {int flags = keyspaceEventsStringToFlags(argv[1]);if (flags == -1) {err = "Invalid event class character. Use 'g$lshzxeA'.";goto loaderr;}server.notify_keyspace_events = flags;} else if (!strcasecmp(argv[0],"user") && argc >= 2) {int argc_err;if (ACLAppendUserForLoading(argv,argc,&argc_err) == C_ERR) {char buf[1024];const char *errmsg = ACLSetUserStringError();snprintf(buf,sizeof(buf),"Error in user declaration '%s': %s",argv[argc_err],errmsg);err = buf;goto loaderr;}} else if (!strcasecmp(argv[0],"loadmodule") && argc >= 2) {queueLoadModule(argv[1],&argv[2],argc-2);} else if (!strcasecmp(argv[0],"sentinel")) {/* argc == 1 is handled by main() as we need to enter the sentinel* mode ASAP. */if (argc != 1) {if (!server.sentinel_mode) {err = "sentinel directive while not in sentinel mode";goto loaderr;}queueSentinelConfig(argv+1,argc-1,linenum,lines[i]);}} else {err = "Bad directive or wrong number of arguments"; goto loaderr;}sdsfreesplitres(argv,argc);}/* Sanity checks. */if (server.cluster_enabled && server.masterhost) {linenum = slaveof_linenum;i = linenum-1;err = "replicaof directive not allowed in cluster mode";goto loaderr;}/* To ensure backward compatibility and work while hz is out of range */if (server.config_hz < CONFIG_MIN_HZ) server.config_hz = CONFIG_MIN_HZ;if (server.config_hz > CONFIG_MAX_HZ) server.config_hz = CONFIG_MAX_HZ;sdsfreesplitres(lines,totlines);return;loaderr:fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR (Redis %s) ***\n",REDIS_VERSION);fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);fprintf(stderr, ">>> '%s'\n", lines[i]);fprintf(stderr, "%s\n", err);exit(1);
}/* Load the server configuration from the specified filename.* The function appends the additional configuration directives stored* in the 'options' string to the config file before loading.** Both filename and options can be NULL, in such a case are considered* empty. This way loadServerConfig can be used to just load a file or* just load a string. */
void loadServerConfig(char *filename, char config_from_stdin, char *options) {sds config = sdsempty();char buf[CONFIG_MAX_LINE+1];FILE *fp;/* Load the file content */if (filename) {if ((fp = fopen(filename,"r")) == NULL) {serverLog(LL_WARNING,"Fatal error, can't open config file '%s': %s",filename, strerror(errno));exit(1);}while(fgets(buf,CONFIG_MAX_LINE+1,fp) != NULL)config = sdscat(config,buf);fclose(fp);}/* Append content from stdin */if (config_from_stdin) {serverLog(LL_WARNING,"Reading config from stdin");fp = stdin;while(fgets(buf,CONFIG_MAX_LINE+1,fp) != NULL)config = sdscat(config,buf);}/* Append the additional options */if (options) {config = sdscat(config,"\n");config = sdscat(config,options);}loadServerConfigFromString(config);sdsfree(config);
}
这篇关于漫话Redis源码之七十二的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!