@@ -133,6 +133,24 @@ enum try_read_result {
133133 READ_MEMORY_ERROR /** failed to allocate more memory */
134134};
135135
136+ typedef struct {
137+ bool *daemonize;
138+ bool *maxcore;
139+ char **username;
140+ bool *lock_memory;
141+ char **pid_file;
142+ char *protocol;
143+ char **engine;
144+ const char **engine_config;
145+ bool *preallocate;
146+ #ifdef ENABLE_ZK_INTEGRATION
147+ int *arcus_zk_to;
148+ #endif
149+ #ifdef PROXY_SUPPORT
150+ char **arcus_proxy_cfg;
151+ #endif
152+ } config_opt_t;
153+
136154static enum try_read_result try_read_network(conn *c);
137155static enum try_read_result try_read_udp(conn *c);
138156
@@ -163,6 +181,7 @@ static void write_and_free(conn *c, char *buf, int bytes);
163181static int ensure_iov_space(conn *c);
164182static int add_iov(conn *c, const void *buf, int len);
165183static int add_msghdr(conn *c);
184+ static int try_load_config_file(const char *path, config_opt_t *opt);
166185
167186enum transmit_result {
168187 TRANSMIT_COMPLETE, /** All done writing. */
@@ -15804,6 +15823,104 @@ static bool sanitycheck(void)
1580415823 return true;
1580515824}
1580615825
15826+ static int try_load_config_file(const char *path, config_opt_t *opt)
15827+ {
15828+ char *access_mask_str = NULL;
15829+ char *protocol_str = NULL;
15830+ char *extension_path[5] = {NULL,};
15831+
15832+ struct config_item main_config_items[] = {
15833+ { .key = "port", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.port },
15834+ { .key = "udpport", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.udpport },
15835+ { .key = "socketpath", .datatype = DT_STRING, .value.dt_string = &settings.socketpath },
15836+ { .key = "access", .datatype = DT_STRING, .value.dt_string = &access_mask_str },
15837+ { .key = "listen", .datatype = DT_STRING, .value.dt_string = &settings.inter },
15838+ { .key = "daemonize", .datatype = DT_BOOL, .value.dt_bool = opt->daemonize },
15839+ { .key = "maxcore", .datatype = DT_BOOL, .value.dt_bool = opt->maxcore },
15840+ { .key = "username", .datatype = DT_STRING, .value.dt_string = opt->username },
15841+ { .key = "maxconns", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.maxconns },
15842+ { .key = "lock_memory", .datatype = DT_BOOL, .value.dt_bool = opt->lock_memory },
15843+ { .key = "verbosity", .datatype = DT_SIZE, .value.dt_size = (size_t*)&settings.verbose },
15844+ { .key = "pid_file", .datatype = DT_STRING, .value.dt_string = opt->pid_file },
15845+ { .key = "threads", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.num_threads },
15846+ { .key = "reqs_per_event", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.reqs_per_event },
15847+ { .key = "backlog", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.backlog },
15848+ { .key = "protocol", .datatype = DT_STRING, .value.dt_string = &protocol_str },
15849+ { .key = "engine_path", .datatype = DT_STRING, .value.dt_string = opt->engine },
15850+
15851+ { .key = "memory_limit", .datatype = DT_SIZE, .value.dt_size = &settings.maxbytes },
15852+ { .key = "eviction", .datatype = DT_BOOL, .value.dt_bool = (bool*)&settings.evict_to_free },
15853+ { .key = "sticky_limit", .datatype = DT_SIZE, .value.dt_size = &settings.sticky_limit },
15854+ { .key = "factor", .datatype = DT_FLOAT, .value.dt_float = (float*)&settings.factor },
15855+ { .key = "chunk_size", .datatype = DT_SIZE, .value.dt_size = (size_t*)&settings.chunk_size },
15856+ { .key = "prefix_delimiter", .datatype = DT_CHAR, .value.dt_char = &settings.prefix_delimiter},
15857+ { .key = "use_cas", .datatype = DT_BOOL, .value.dt_bool = &settings.use_cas },
15858+ { .key = "item_size_max", .datatype = DT_SIZE, .value.dt_size = &settings.item_size_max },
15859+ { .key = "engine_config", .datatype = DT_STRING, .value.dt_string = (char**)opt->engine_config },
15860+ { .key = "preallocate", .datatype = DT_BOOL, .value.dt_bool = opt->preallocate },
15861+ { .key = "extension1", .datatype = DT_STRING, .value.dt_string = &extension_path[0] },
15862+ { .key = "extension2", .datatype = DT_STRING, .value.dt_string = &extension_path[1] },
15863+ { .key = "extension3", .datatype = DT_STRING, .value.dt_string = &extension_path[2] },
15864+ { .key = "extension4", .datatype = DT_STRING, .value.dt_string = &extension_path[3] },
15865+ { .key = "extension5", .datatype = DT_STRING, .value.dt_string = &extension_path[4] },
15866+ #ifdef ENABLE_ZK_INTEGRATION
15867+ { .key = "zookeeper", .datatype = DT_STRING, .value.dt_string = (char**)&arcus_zk_cfg },
15868+ { .key = "zk_timeout", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)opt->arcus_zk_to },
15869+ #ifdef PROXY_SUPPORT
15870+ { .key = "proxy_config", .datatype = DT_STRING, .value.dt_string = opt->arcus_proxy_cfg },
15871+ #endif
15872+ #endif
15873+
15874+ #ifdef SASL_ENABLED
15875+ { .key = "require_sasl", .datatype = DT_BOOL, .value.dt_bool = &settings.require_sasl },
15876+ #endif
15877+ { .key = NULL}
15878+ };
15879+
15880+ if (read_config_file(path, main_config_items, stderr) == -1) {
15881+ fprintf(stderr, "Error parsing config file. Aborting.\n");
15882+ return -1;
15883+ }
15884+
15885+ if (access_mask_str != NULL) {
15886+ settings.access = strtol(access_mask_str, NULL, 8);
15887+ free(access_mask_str);
15888+ }
15889+ if (protocol_str != NULL) {
15890+ if (strcmp(protocol_str, "auto") == 0) {
15891+ settings.binding_protocol = negotiating_prot;
15892+ } else if (strcmp(protocol_str, "binary") == 0) {
15893+ settings.binding_protocol = binary_prot;
15894+ } else if (strcmp(protocol_str, "ascii") == 0) {
15895+ settings.binding_protocol = ascii_prot;
15896+ } else {
15897+ fprintf(stderr, "Invalid value for binding protocol in config file: %s\n", protocol_str);
15898+ free(protocol_str);
15899+ return -1;
15900+ }
15901+ free(protocol_str);
15902+ }
15903+
15904+ for (int i = 0; i < 5; i++) {
15905+ if (extension_path[i] != NULL) {
15906+ char *ptr = strchr(extension_path[i], ',');
15907+ if (ptr != NULL) {
15908+ *ptr = '\0';
15909+ ptr++;
15910+ }
15911+ if (!load_extension(extension_path[i], ptr)) {
15912+ fprintf(stderr, "Failed to load extension: %s\n", extension_path[i]);
15913+ for (int j = 0; j < 5; j++)
15914+ if (extension_path[j]) free(extension_path[j]);
15915+ return -1;
15916+ }
15917+ free(extension_path[i]);
15918+ }
15919+ }
15920+
15921+ return 0;
15922+ }
15923+
1580715924static void settings_reload_engine_config(void)
1580815925{
1580915926 ENGINE_ERROR_CODE ret;
@@ -15898,6 +16015,34 @@ int main (int argc, char **argv)
1589816015 return EX_OSERR;
1589916016 }
1590016017
16018+ /* parse config file */
16019+ if (argc > 1 && argv[1][0] != '-') {
16020+ const char *config_file = argv[1];
16021+ config_opt_t opt = {
16022+ .daemonize = &do_daemonize,
16023+ .maxcore = (bool*)&maxcore,
16024+ .username = &username,
16025+ .lock_memory = &lock_memory,
16026+ .pid_file = &pid_file,
16027+ .engine = (char**)&engine,
16028+ .engine_config = &engine_config,
16029+ .preallocate = &preallocate,
16030+ #ifdef ENABLE_ZK_INTEGRATION
16031+ .arcus_zk_to = &arcus_zk_to,
16032+ #ifdef PROXY_SUPPORT
16033+ .arcus_proxy_cfg = &arcus_proxy_cfg,
16034+ #endif
16035+ #endif
16036+ };
16037+ if (try_load_config_file(config_file, &opt) != 0) {
16038+ fprintf(stderr, "Error parsing config file '%s'.", config_file);
16039+ exit(EXIT_FAILURE);
16040+ }
16041+ optind = 2;
16042+ } else {
16043+ optind = 1;
16044+ }
16045+
1590116046 /* process arguments */
1590216047 while (-1 != (c = getopt(argc, argv,
1590316048 "a:" /* access mask for unix socket */
@@ -16173,6 +16318,36 @@ int main (int argc, char **argv)
1617316318 return 1;
1617416319 }
1617516320 }
16321+
16322+ if (settings.maxbytes <= 0) {
16323+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
16324+ "The value of memory limit must be greater than 0.\n");
16325+ }
16326+ if (settings.sticky_limit > 0 && settings.maxbytes < settings.sticky_limit) {
16327+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
16328+ "The value of memory limit cannot be smaller than sticky_limit.\n");
16329+ }
16330+ if (settings.item_size_max < 1024 * 20) {
16331+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
16332+ "Item max size cannot be less than 20KB.\n");
16333+ }
16334+ if (settings.item_size_max > 1024 * 1024 * 128) {
16335+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
16336+ "Cannot set item size limit higher than 128 mb.\n");
16337+ }
16338+ if (settings.factor <= 1.0) {
16339+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
16340+ "Factor must be greater than 1\n");
16341+ }
16342+ if (settings.chunk_size <= 0) {
16343+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
16344+ "Chunk size must be greater than 0\n");
16345+ }
16346+ if (settings.num_threads <= 0) {
16347+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
16348+ "Number of threads must be greater than 0\n");
16349+ }
16350+
1617616351 old_opts += sprintf(old_opts, "num_threads=%lu;", (unsigned long)settings.num_threads);
1617716352 old_opts += sprintf(old_opts, "cache_size=%llu;", (unsigned long long)settings.maxbytes);
1617816353 if (settings.evict_to_free == 0) {
0 commit comments