int mdb_init ( size_t size ) { enum hashfunc_type hash_type = JENKINS_HASH; bool preallocate = false; bool start_lru_crawler = true; process_started = time (0); settings_init (size); init_lru_crawler (); init_lru_maintainer (); setbuf (stderr, NULL); if ( hash_init (hash_type) != 0 ) { fprintf (stderr, "Failed to initialize hash_algorithm!\n"); return - 1; } assoc_init (settings.hashpower_init); if ( enable_large_pages () == 0 ) { preallocate = true; } slabs_init (settings.maxbytes, settings.factor, preallocate); memcached_thread_init (); if ( start_assoc_maintenance_thread () == - 1 ) { return - 1; } if ( start_lru_crawler && start_lru_maintainer_thread () != 0 ) { fprintf (stderr, "Failed to enable LRU maintainer thread\n"); return - 1; } if ( settings.slab_reassign && start_slab_maintenance_thread () == - 1 ) { return - 1; } return 0; }
int main(int argc, char *argv[]) { int c; int do_daemonize= 0; int maxcore = 0; struct rlimit rlim; char unit = '\0'; int size_max = 0; int protocol_specified = 0; int tcp_specified = 0; int udp_specified = 0; char *subopts; char *subopts_value; enum { MAXCONNS_FAST = 0, HASHPOWER_INIT, SLAB_REASSIGN, SLAB_AUTOMOVE }; char *const subopts_tokens[] = { [MAXCONNS_FAST] = "maxconns_fast", [HASHPOWER_INIT]= "hashpower", [SLAB_REASSIGN] = "slab_reassign", [SLAB_AUTOMOVE] = "slab_automove", NULL }; /* init settings */ settings_init(); /* set stderr non-buffering (for running under, say, daemontools) */ setbuf(stderr, NULL); /* process arguments */ while (-1 != (c = getopt(argc, argv, "a:" /* access mask for unix socket */ "A" /* enable admin shutdown commannd */ "p:" /* TCP port number to listen on */ "s:" /* unix socket path to listen on */ "U:" /* UDP port number to listen on */ "m:" /* max memory to use for items in megabytes */ "M" /* return error on memory exhausted */ "c:" /* max simultaneous connections */ "hi" /* help, licence info */ "r" /* maximize core file limit */ "v" /* verbose */ "d" /* daemon mode */ "l:" /* interface to listen on */ "f:" /* factor? */ "n:" /* minimum space allocated for key+value+flags */ "D:" /* prefix delimiter? */ "L" /* Large memory pages */ "R:" /* max requests per event */ "C" /* Disable use of CAS */ "b:" /* backlog queue limit */ "B:" /* Binding protocol */ "I:" /* Max item size */ "S" /* Sasl ON */ "o:" /* Extended generic options */ ))) { switch (c) { case 'A': /* enables "shutdown" command */ settings.shutdown_command = 1; break; case 'a': /* access for unix domain socket, as octal mask (like chmod)*/ settings.access= strtol(optarg,NULL,8); break; case 'U': settings.udpport = atoi(optarg); udp_specified = 1; break; case 'p': settings.port = atoi(optarg); tcp_specified = 1; break; case 's': settings.socketpath = optarg; break; case 'm': settings.maxbytes = ((size_t)atoi(optarg)) * 1024 * 1024; break; case 'M': settings.evict_to_free = 0; break; case 'c': settings.maxconns = atoi(optarg); break; case 'h': usage(); exit(EXIT_SUCCESS); case 'i': usage_license(); exit(EXIT_SUCCESS); case 'v': settings.verbose++; break; case 'l': if (settings.inter != NULL) { size_t len = strlen(settings.inter) + strlen(optarg) + 2; char *p = malloc(len); if (p == NULL) { fprintf(stderr, "Failed to allocate memory\n"); return 1; } snprintf(p, len, "%s,%s", settings.inter, optarg); free(settings.inter); settings.inter = p; } else { settings.inter= strdup(optarg); } break; case 'd': do_daemonize = 1; break; case 'r': maxcore = 1; break; case 'R': settings.reqs_per_event = atoi(optarg); if (settings.reqs_per_event == 0) { fprintf(stderr, "Number of requests per event must be greater than 0\n"); return 1; } break; case 'f': if (atof(optarg) <= 1.0) { fprintf(stderr, "Factor must be greater than 1\n"); return 1; } double_int(optarg, &settings.factor_numerator, &settings.factor_denominator); break; case 'n': settings.chunk_size = atoi(optarg); if (settings.chunk_size == 0) { fprintf(stderr, "Chunk size must be greater than 0\n"); return 1; } break; case 'D': if (! optarg || ! optarg[0]) { fprintf(stderr, "No delimiter specified\n"); return 1; } settings.prefix_delimiter = optarg[0]; settings.detail_enabled = 1; break; case 'L' : if (enable_large_pages() == 0) { settings.preallocate = 1; } else { fprintf(stderr, "Cannot enable large pages on this system\n" "(There is no Linux support as of this version)\n"); return 1; } break; case 'C' : settings.use_cas = 0; break; case 'b' : settings.backlog = atoi(optarg); break; case 'B': protocol_specified = 1; if (strcmp(optarg, "auto") == 0) { settings.binding_protocol = negotiating_prot; } else if (strcmp(optarg, "binary") == 0) { settings.binding_protocol = binary_prot; } else if (strcmp(optarg, "ascii") == 0) { settings.binding_protocol = ascii_prot; } else { fprintf(stderr, "Invalid value for binding protocol: %s\n" " -- should be one of auto, binary, or ascii\n", optarg); exit(EX_USAGE); } break; case 'I': unit = optarg[strlen(optarg)-1]; if (unit == 'k' || unit == 'm' || unit == 'K' || unit == 'M') { optarg[strlen(optarg)-1] = '\0'; size_max = atoi(optarg); if (unit == 'k' || unit == 'K') size_max *= 1024; if (unit == 'm' || unit == 'M') size_max *= 1024 * 1024; settings.item_size_max = size_max; } else { settings.item_size_max = atoi(optarg); } if (settings.item_size_max < 1024) { fprintf(stderr, "Item max size cannot be less than 1024 bytes.\n"); return 1; } if (settings.item_size_max > 1024 * 1024 * 128) { fprintf(stderr, "Cannot set item size limit higher than 128 mb.\n"); return 1; } if (settings.item_size_max > 1024 * 1024) { fprintf(stderr, "WARNING: Setting item max size above 1MB is not" " recommended!\n" " Raising this limit increases the minimum memory requirements\n" " and will decrease your memory efficiency.\n" ); } break; case 'S': /* set Sasl authentication to 1. Default is 0 */ #ifndef ENABLE_SASL fprintf(stderr, "This server is not built with SASL support.\n"); exit(EX_USAGE); #endif settings.sasl = 1; break; case 'o': /* It's sub-opts time! */ subopts = optarg; while (*subopts != '\0') { switch (getsubopt(&subopts, subopts_tokens, &subopts_value)) { case MAXCONNS_FAST: settings.maxconns_fast = 1; break; case HASHPOWER_INIT: if (subopts_value == NULL) { fprintf(stderr, "Missing numeric argument for hashpower\n"); return 1; } settings.hashpower_init = atoi(subopts_value); if (settings.hashpower_init < 12) { fprintf(stderr, "Initial hashtable multiplier of %d is too low\n", settings.hashpower_init); return 1; } else if (settings.hashpower_init > 64) { fprintf(stderr, "Initial hashtable multiplier of %d is too high\n" "Choose a value based on \"STAT hash_power_level\" from a running instance\n", settings.hashpower_init); return 1; } break; case SLAB_REASSIGN: settings.slab_reassign = 1; break; case SLAB_AUTOMOVE: if (subopts_value == NULL) { settings.slab_automove = 1; break; } settings.slab_automove = atoi(subopts_value); if (settings.slab_automove < 0 || settings.slab_automove > 2) { fprintf(stderr, "slab_automove must be between 0 and 2\n"); return 1; } break; default: printf("Illegal suboption \"%s\"\n", subopts_value); return 1; } } break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); return 1; } } /* * Use one workerthread to serve each UDP port if the user specified * multiple ports */ if (settings.inter != NULL && strchr(settings.inter, ',')) { settings.num_threads_per_udp = 1; } else { settings.num_threads_per_udp = 0x7fffffff; } if (settings.sasl) { if (!protocol_specified) { settings.binding_protocol = binary_prot; } else { if (settings.binding_protocol != binary_prot) { fprintf(stderr, "ERROR: You cannot allow the ASCII protocol while using SASL.\n"); exit(EX_USAGE); } } } if (tcp_specified && !udp_specified) { settings.udpport = settings.port; } else if (udp_specified && !tcp_specified) { settings.port = settings.udpport; } if (maxcore != 0) { struct rlimit rlim_new; /* * First try raising to infinity; if that fails, try bringing * the soft limit to the hard. */ if (getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_CORE, &rlim_new)!= 0) { /* failed. try raising just to the old max */ rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max; (void)setrlimit(RLIMIT_CORE, &rlim_new); } } /* * getrlimit again to see what we ended up with. Only fail if * the soft limit ends up 0, because then no core files will be * created at all. */ if ((getrlimit(RLIMIT_CORE, &rlim) != 0) || rlim.rlim_cur == 0) { fprintf(stderr, "failed to ensure corefile creation\n"); exit(EX_OSERR); } } /* * If needed, increase rlimits to allow as many connections * as needed. */ if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { fprintf(stderr, "failed to getrlimit number of files\n"); exit(EX_OSERR); } else { rlim.rlim_cur = settings.maxconns; rlim.rlim_max = settings.maxconns; if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { fprintf(stderr, "failed to set rlimit for open files. Try starting as root or requesting smaller maxconns value.\n"); exit(EX_OSERR); } } /* lose root privileges if we have them */ if (getuid() != 0 || geteuid() != 0) { fprintf(stderr, "run as root\n"); exit(EX_USAGE); } /* Initialize Sasl if -S was specified */ if (settings.sasl) { // init_sasl(); } /* daemonize if requested */ /* if we want to ensure our ability to dump core, don't chdir to / */ if (do_daemonize) { if (sigignore(SIGHUP) == -1) { perror("Failed to ignore SIGHUP"); } if (daemonize(maxcore, settings.verbose) == -1) { fprintf(stderr, "failed to daemon() in order to daemonize\n"); exit(EXIT_FAILURE); } } main_loop(); return 0; }