/* * File: ms_setting.c * Author: Mingqiang Zhuang * * Created on February 10, 2009 * * (c) Copyright 2009, Schooner Information Technology, Inc. * http://www.schoonerinfotech.com/ * */ #include "mem_config.h" #include #include #include #include #include #include #include #include #include "ms_setting.h" #include "ms_conn.h" #define MAX_EXEC_NUM 0x4000000000000000 /* 1 << 62 */ #define ADDR_ALIGN(addr) ((addr + 15) & ~(16 - 1)) /* 16 bytes aligned */ #define RAND_CHAR_SIZE (10 * 1024 * 1024) /* 10M character table */ #define RESERVED_RAND_CHAR_SIZE (2 * 1024 * 1024) /* reserved 2M to avoid pointer sloping over */ #define DEFAULT_CONFIG_NAME ".memslap.cnf" #define DEFAULT_THREADS_NUM 1 /* default start one thread */ #define DEFAULT_CONNS_NUM 16 /* default each thread with 16 connections */ #define DEFAULT_EXE_NUM 0 /* default execute number is 0 */ #define DEFAULT_VERIFY_RATE 0.0 /* default it doesn't do data verification */ #define DEFAULT_OVERWRITE_RATE 0.0 /* default it doesn't do overwrite */ #define DEFAULT_DIV 1 /* default it runs single get */ #define DEFAULT_RUN_TIME 600 /* default run time 10 minutes */ #define DEFAULT_WINDOW_SIZE (10 * UNIT_ITEMS_COUNT) /* default window size is 10k */ #define DEFAULT_SOCK_PER_CONN 1 /* default socks per connection is 1 */ /* Use this for string generation */ #define CHAR_COUNT 64 /* number of characters used to generate character table */ const char ALPHANUMBERICS[]= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-"; ms_setting_st ms_setting; /* store the settings specified by user */ /* read setting from configuration file */ static void ms_get_serverlist(char *str); static uint32_t ms_get_cpu_count(void); ms_conf_type_t ms_get_conf_type(char *line); static int ms_is_line_data(char *line); static int ms_read_is_data(char *line, ssize_t nread); static void ms_no_config_file(void); static void ms_parse_cfg_file(char *cfg_file); /* initialize setting structure */ static void ms_init_random_block(void); static void ms_calc_avg_size(void); static int ms_shuffle_distr(ms_distr_t *distr, int length); static void ms_build_distr(void); static void ms_print_setting(void); static void ms_setting_slapmode_init_pre(void); static void ms_setting_slapmode_init_post(void); #if !defined(HAVE_GETLINE) #include static ssize_t getline (char **line, size_t *line_size, FILE *fp) { char delim= '\n'; ssize_t result= 0; size_t cur_len= 0; if (line == NULL || line_size == NULL || fp == NULL) { errno = EINVAL; return -1; } if (*line == NULL || *line_size == 0) { char *new_line; *line_size = 120; new_line= (char *) realloc (*line, *line_size); if (new_line == NULL) { result= -1; return result; } *line= new_line; } for (;;) { int i= getc(fp); if (i == EOF) { result = -1; break; } /* Make enough space for len+1 (for final NUL) bytes. */ if (cur_len + 1 >= *line_size) { size_t needed_max= SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX; size_t needed= (2 * (*line_size)) + 1; char *new_line; if (needed_max < needed) needed= needed_max; if (cur_len + 1 >= needed) { result= -1; errno= EOVERFLOW; return result; } new_line= (char *)realloc(*line, needed); if (new_line == NULL) { result= -1; return result; } *line= new_line; *line_size= needed; } (*line)[cur_len]= (char)i; cur_len++; if (i == delim) break; } (*line)[cur_len] = '\0'; if (cur_len != 0) return (ssize_t)cur_len; return result; } #endif /** * parse the server list string, and build the servers * information structure array. this function is used to parse * the command line options specified by user. * * @param str, the string of server list */ static void ms_get_serverlist(char *str) { ms_mcd_server_t *srvs= NULL; /** * Servers list format is like this. For example: * "localhost:11108, localhost:11109" */ memcached_server_st *server_pool; server_pool = memcached_servers_parse(str); for (uint32_t loop= 0; loop < memcached_server_list_count(server_pool); loop++) { assert(ms_setting.srv_cnt < ms_setting.total_srv_cnt); strcpy(ms_setting.servers[ms_setting.srv_cnt].srv_host_name, server_pool[loop].hostname); ms_setting.servers[ms_setting.srv_cnt].srv_port= server_pool[loop].port; ms_setting.servers[ms_setting.srv_cnt].disconn_cnt= 0; ms_setting.servers[ms_setting.srv_cnt].reconn_cnt= 0; ms_setting.srv_cnt++; if (ms_setting.srv_cnt >= ms_setting.total_srv_cnt) { srvs= (ms_mcd_server_t *)realloc( ms_setting.servers, (size_t)ms_setting.total_srv_cnt * sizeof(ms_mcd_server_t) * 2); if (srvs == NULL) { fprintf(stderr, "Can't reallocate servers structure.\n"); exit(1); } ms_setting.servers= srvs; ms_setting.total_srv_cnt*= 2; } } memcached_server_free(server_pool); } /* ms_get_serverlist */ /** * used to get the CPU count of the current system * * @return return the cpu count if get, else return EXIT_FAILURE */ static uint32_t ms_get_cpu_count() { #ifdef HAVE__SC_NPROCESSORS_ONLN return sysconf(_SC_NPROCESSORS_CONF); #else # ifdef HAVE_CPU_SET_T int cpu_count= 0; cpu_set_t cpu_set; sched_getaffinity(0, sizeof(cpu_set_t), &cpu_set); for (int i= 0; i < (sizeof(cpu_set_t) * 8); i++) { if (CPU_ISSET(i, &cpu_set)) { cpu_count++; } } return cpu_count; # endif #endif /* the system with one cpu at least */ return EXIT_FAILURE; } /* ms_get_cpu_count */ /** * used to get the configure type based on the type string read * from the configuration file. * * @param line, string of one line * * @return ms_conf_type_t */ ms_conf_type_t ms_get_conf_type(char *line) { if (! memcmp(line, "key", strlen("key"))) { return CONF_KEY; } else if (! memcmp(line, "value", strlen("value"))) { return CONF_VALUE; } else if (! memcmp(line, "cmd", strlen("cmd"))) { return CONF_CMD; } else { return CONF_NULL; } } /* ms_get_conf_type */ /** * judge whether the line is a line with useful data. used to * parse the configuration file. * * @param line, string of one line * * @return if success, return EXIT_FAILURE, else return EXIT_SUCCESS */ static int ms_is_line_data(char *line) { assert(line != NULL); char *begin_ptr= line; while (isspace(*begin_ptr)) { begin_ptr++; } if ((begin_ptr[0] == '\0') || (begin_ptr[0] == '#')) return EXIT_SUCCESS; return EXIT_FAILURE; } /* ms_is_line_data */ /** * function to bypass blank line and comments * * @param line, string of one line * @param nread, length of the line * * @return if it's EOF or not line data, return EXIT_SUCCESS, else return EXIT_FAILURE */ static int ms_read_is_data(char *line, ssize_t nread) { if ((nread == EOF) || ! ms_is_line_data(line)) return EXIT_SUCCESS; return EXIT_FAILURE; } /* ms_read_is_data */ /** * if no configuration file, use this function to create the default * configuration file. */ static void ms_no_config_file() { char userpath[PATH_MAX]; struct passwd *usr= NULL; FILE *fd; usr= getpwuid(getuid()); snprintf(userpath, PATH_MAX, "%s/%s", usr->pw_dir, DEFAULT_CONFIG_NAME); if (access (userpath, F_OK | R_OK) == 0) goto exit; fd= fopen(userpath, "w+"); if (fd == NULL) { fprintf(stderr, "Could not create default configure file %s\n", userpath); perror(strerror(errno)); exit(1); } fprintf(fd, "%s", DEFAULT_CONGIF_STR); fclose(fd); exit: ms_setting.cfg_file= strdup(userpath); } /* ms_no_config_file */ /** * parse the configuration file * * @param cfg_file, the configuration file name */ static void ms_parse_cfg_file(char *cfg_file) { FILE *f; size_t start_len, end_len; double proportion; char *line= NULL; size_t read_len; ssize_t nread; int cmd_type; ms_conf_type_t conf_type; int end_of_file= 0; ms_key_distr_t *key_distr= NULL; ms_value_distr_t *val_distr= NULL; if (cfg_file == NULL) { ms_no_config_file(); cfg_file= ms_setting.cfg_file; } /*read key value configure file*/ if ((f= fopen(cfg_file, "r")) == NULL) { fprintf(stderr, "Can not open file: '%s'.\n", cfg_file); exit(1); } while (1) { if ((((nread= getline(&line, &read_len, f)) == 1) || ! ms_read_is_data(line, nread)) && (nread != EOF)) /* bypass blank line */ continue; if (nread == EOF) { fprintf(stderr, "Bad configuration file, no configuration find.\n"); exit(1); } conf_type= ms_get_conf_type(line); break; } while (! end_of_file) { switch (conf_type) { case CONF_KEY: while (1) { if ((((nread= getline(&line, &read_len, f)) == 1) || ! ms_read_is_data(line, nread)) && (nread != EOF)) /* bypass blank line */ continue; if (nread != EOF) { if (sscanf(line, "%zu %zu %lf ", &start_len, &end_len, &proportion) != 3) { conf_type= ms_get_conf_type(line); break; } ms_setting.key_distr[ms_setting.key_rng_cnt].start_len= start_len; ms_setting.key_distr[ms_setting.key_rng_cnt].end_len= end_len; ms_setting.key_distr[ms_setting.key_rng_cnt].key_prop= proportion; ms_setting.key_rng_cnt++; if (ms_setting.key_rng_cnt >= ms_setting.total_key_rng_cnt) { key_distr= (ms_key_distr_t *)realloc( ms_setting.key_distr, (size_t)ms_setting. total_key_rng_cnt * sizeof(ms_key_distr_t) * 2); if (key_distr == NULL) { fprintf(stderr, "Can't reallocate key distribution structure.\n"); exit(1); } ms_setting.key_distr= key_distr; ms_setting.total_key_rng_cnt*= 2; } continue; } end_of_file= 1; break; } break; case CONF_VALUE: while (1) { if ((((nread= getline(&line, &read_len, f)) == 1) || ! ms_read_is_data(line, nread)) && (nread != EOF)) /* bypass blank line */ continue; if (nread != EOF) { if (sscanf(line, "%zu %zu %lf", &start_len, &end_len, &proportion) != 3) { conf_type= ms_get_conf_type(line); break; } ms_setting.value_distr[ms_setting.val_rng_cnt].start_len= start_len; ms_setting.value_distr[ms_setting.val_rng_cnt].end_len= end_len; ms_setting.value_distr[ms_setting.val_rng_cnt].value_prop= proportion; ms_setting.val_rng_cnt++; if (ms_setting.val_rng_cnt >= ms_setting.total_val_rng_cnt) { val_distr= (ms_value_distr_t *)realloc( ms_setting.value_distr, (size_t)ms_setting. total_val_rng_cnt * sizeof(ms_value_distr_t) * 2); if (val_distr == NULL) { fprintf(stderr, "Can't reallocate key distribution structure.\n"); exit(1); } ms_setting.value_distr= val_distr; ms_setting.total_val_rng_cnt*= 2; } continue; } end_of_file= 1; break; } break; case CONF_CMD: while (1) { if ((((nread= getline(&line, &read_len, f)) == 1) || ! ms_read_is_data(line, nread)) && (nread != EOF)) /* bypass blank line */ continue; if (nread != EOF) { if (sscanf(line, "%d %lf", &cmd_type, &proportion) != 2) { conf_type= ms_get_conf_type(line); break; } if (cmd_type >= CMD_NULL) { continue; } ms_setting.cmd_distr[ms_setting.cmd_used_count].cmd_type= cmd_type; ms_setting.cmd_distr[ms_setting.cmd_used_count].cmd_prop= proportion; ms_setting.cmd_used_count++; continue; } end_of_file= 1; break; } case CONF_NULL: while (1) { if ((((nread= getline(&line, &read_len, f)) == 1) || ! ms_read_is_data(line, nread)) && (nread != EOF)) /* bypass blank line */ continue; if (nread != EOF) { if ((conf_type= ms_get_conf_type(line)) != CONF_NULL) { break; } continue; } end_of_file= 1; break; } break; default: assert(0); break; } /* switch */ } fclose(f); if (line != NULL) { free(line); } } /* ms_parse_cfg_file */ /* calculate the average size of key and value */ static void ms_calc_avg_size() { double avg_val_size= 0.0; double avg_key_size= 0.0; double val_pro= 0.0; double key_pro= 0.0; double averge_len= 0.0; size_t start_len= 0; size_t end_len= 0; for (int j= 0; j < ms_setting.val_rng_cnt; j++) { val_pro= ms_setting.value_distr[j].value_prop; start_len= ms_setting.value_distr[j].start_len; end_len= ms_setting.value_distr[j].end_len; averge_len= val_pro * ((double)(start_len + end_len)) / 2; avg_val_size+= averge_len; } for (int j= 0; j < ms_setting.key_rng_cnt; j++) { key_pro= ms_setting.key_distr[j].key_prop; start_len= ms_setting.key_distr[j].start_len; end_len= ms_setting.key_distr[j].end_len; averge_len= key_pro * ((double)(start_len + end_len)) / 2; avg_key_size+= averge_len; } ms_setting.avg_val_size= (size_t)avg_val_size; ms_setting.avg_key_size= (size_t)avg_key_size; } /* ms_calc_avg_size */ /** * used to shuffle key and value distribution array to ensure * (key, value) pair with different set. * * @param distr, pointer of distribution structure array * @param length, length of the array * * @return always return EXIT_SUCCESS */ static int ms_shuffle_distr(ms_distr_t *distr, int length) { int i, j; int tmp_offset; size_t tmp_size; int64_t rnd; for (i= 0; i < length; i++) { rnd= random(); j= (int)(rnd % (length - i)) + i; switch (rnd % 3) { case 0: tmp_size= distr[j].key_size; distr[j].key_size= distr[i].key_size; distr[i].key_size= tmp_size; break; case 1: tmp_offset= distr[j].key_offset; distr[j].key_offset= distr[i].key_offset; distr[i].key_offset= tmp_offset; break; case 2: tmp_size= distr[j].value_size; distr[j].value_size= distr[i].value_size; distr[i].value_size= tmp_size; break; default: break; } /* switch */ } return EXIT_SUCCESS; } /* ms_shuffle_distr */ /** * according to the key and value distribution, to build the * (key, value) pair distribution. the (key, value) pair * distribution array is global, each connection set or get * object keeping this distribution, for the final result, we * can reach the expected key and value distribution. */ static void ms_build_distr() { int offset= 0; int end= 0; int key_cnt= 0; int value_cnt= 0; size_t average_len= 0; size_t diff_len= 0; size_t start_len= 0; size_t end_len= 0; int rnd= 0; ms_distr_t *distr= NULL; int units= (int)ms_setting.win_size / UNIT_ITEMS_COUNT; /* calculate average value size and key size */ ms_calc_avg_size(); ms_setting.char_blk_size= RAND_CHAR_SIZE; int key_scope_size= (int)((ms_setting.char_blk_size - RESERVED_RAND_CHAR_SIZE) / UNIT_ITEMS_COUNT); ms_setting.distr= (ms_distr_t *)malloc( sizeof(ms_distr_t) * ms_setting.win_size); if (ms_setting.distr == NULL) { fprintf(stderr, "Can't allocate distribution array."); exit(1); } /** * character block is divided by how many different key * size, each different key size has the same size character * range. */ for (int m= 0; m < units; m++) { for (int i= 0; i < UNIT_ITEMS_COUNT; i++) { ms_setting.distr[m * UNIT_ITEMS_COUNT + i].key_offset= ADDR_ALIGN(key_scope_size * i); } } /* initialize key size distribution */ for (int m= 0; m < units; m++) { for (int j= 0; j < ms_setting.key_rng_cnt; j++) { key_cnt= (int)(UNIT_ITEMS_COUNT * ms_setting.key_distr[j].key_prop); start_len= ms_setting.key_distr[j].start_len; end_len= ms_setting.key_distr[j].end_len; if ((start_len < MIN_KEY_SIZE) || (end_len < MIN_KEY_SIZE)) { fprintf(stderr, "key length must be greater than 16 bytes.\n"); exit(1); } if (! ms_setting.binary_prot_ && ((start_len > MAX_KEY_SIZE) || (end_len > MAX_KEY_SIZE))) { fprintf(stderr, "key length must be less than 250 bytes.\n"); exit(1); } average_len= (start_len + end_len) / 2; diff_len= (end_len - start_len) / 2; for (int k= 0; k < key_cnt; k++) { if (offset >= (m + 1) * UNIT_ITEMS_COUNT) { break; } rnd= (int)random(); if (k % 2 == 0) { ms_setting.distr[offset].key_size= (diff_len == 0) ? average_len : average_len + (size_t)rnd % diff_len; } else { ms_setting.distr[offset].key_size= (diff_len == 0) ? average_len : average_len - (size_t)rnd % diff_len; } offset++; } } if (offset < (m + 1) * UNIT_ITEMS_COUNT) { end= (m + 1) * UNIT_ITEMS_COUNT - offset; for (int i= 0; i < end; i++) { ms_setting.distr[offset].key_size= ms_setting.avg_key_size; offset++; } } } offset= 0; /* initialize value distribution */ if (ms_setting.fixed_value_size != 0) { for (int i= 0; i < units * UNIT_ITEMS_COUNT; i++) { ms_setting.distr[i].value_size= ms_setting.fixed_value_size; } } else { for (int m= 0; m < units; m++) { for (int j= 0; j < ms_setting.val_rng_cnt; j++) { value_cnt= (int)(UNIT_ITEMS_COUNT * ms_setting.value_distr[j].value_prop); start_len= ms_setting.value_distr[j].start_len; end_len= ms_setting.value_distr[j].end_len; if ((start_len <= 0) || (end_len <= 0)) { fprintf(stderr, "value length must be greater than 0 bytes.\n"); exit(1); } if ((start_len > MAX_VALUE_SIZE) || (end_len > MAX_VALUE_SIZE)) { fprintf(stderr, "key length must be less than or equal to 1M.\n"); exit(1); } average_len= (start_len + end_len) / 2; diff_len= (end_len - start_len) / 2; for (int k= 0; k < value_cnt; k++) { if (offset >= (m + 1) * UNIT_ITEMS_COUNT) { break; } rnd= (int)random(); if (k % 2 == 0) { ms_setting.distr[offset].value_size= (diff_len == 0) ? average_len : average_len + (size_t)rnd % diff_len; } else { ms_setting.distr[offset].value_size= (diff_len == 0) ? average_len : average_len - (size_t)rnd % diff_len; } offset++; } } if (offset < (m + 1) * UNIT_ITEMS_COUNT) { end= (m + 1) * UNIT_ITEMS_COUNT - offset; for (int i= 0; i < end; i++) { ms_setting.distr[offset++].value_size= ms_setting.avg_val_size; } } } } /* shuffle distribution */ for (int i= 0; i < units; i++) { distr= &ms_setting.distr[i * UNIT_ITEMS_COUNT]; for (int j= 0; j < 4; j++) { ms_shuffle_distr(distr, UNIT_ITEMS_COUNT); } } } /* ms_build_distr */ /** * used to initialize the global character block. The character * block is used to generate the suffix of the key and value. we * only store a pointer in the character block for each key * suffix or value string. It can save much memory to store key * or value string. */ static void ms_init_random_block() { char *ptr= NULL; assert(ms_setting.char_blk_size > 0); ms_setting.char_block= (char *)malloc(ms_setting.char_blk_size); if (ms_setting.char_block == NULL) { fprintf(stderr, "Can't allocate global char block."); exit(1); } ptr= ms_setting.char_block; for (int i= 0; (size_t)i < ms_setting.char_blk_size; i++) { *(ptr++)= ALPHANUMBERICS[random() % CHAR_COUNT]; } } /* ms_init_random_block */ /** * after initialization, call this function to output the main * configuration user specified. */ static void ms_print_setting() { fprintf(stdout, "servers : %s\n", ms_setting.srv_str); fprintf(stdout, "threads count: %d\n", ms_setting.nthreads); fprintf(stdout, "concurrency: %d\n", ms_setting.nconns); if (ms_setting.run_time > 0) { fprintf(stdout, "run time: %ds\n", ms_setting.run_time); } else { fprintf(stdout, "execute number: %" PRId64 "\n", ms_setting.exec_num); } fprintf(stdout, "windows size: %" PRId64 "k\n", (int64_t)(ms_setting.win_size / 1024)); fprintf(stdout, "set proportion: set_prop=%.2f\n", ms_setting.cmd_distr[CMD_SET].cmd_prop); fprintf(stdout, "get proportion: get_prop=%.2f\n", ms_setting.cmd_distr[CMD_GET].cmd_prop); fflush(stdout); } /* ms_print_setting */ /** * previous part of slap mode initialization of setting structure */ static void ms_setting_slapmode_init_pre() { ms_setting.exec_num= DEFAULT_EXE_NUM; ms_setting.verify_percent= DEFAULT_VERIFY_RATE; ms_setting.exp_ver_per= DEFAULT_VERIFY_RATE; ms_setting.overwrite_percent= DEFAULT_OVERWRITE_RATE; ms_setting.mult_key_num= DEFAULT_DIV; ms_setting.fixed_value_size= 0; ms_setting.win_size= DEFAULT_WINDOW_SIZE; ms_setting.udp= false; ms_setting.reconnect= false; ms_setting.verbose= false; ms_setting.facebook_test= false; ms_setting.binary_prot_= false; ms_setting.stat_freq= 0; ms_setting.srv_str= NULL; ms_setting.cfg_file= NULL; ms_setting.sock_per_conn= DEFAULT_SOCK_PER_CONN; ms_setting.expected_tps= 0; ms_setting.rep_write_srv= 0; } /* ms_setting_slapmode_init_pre */ /** * previous part of initialization of setting structure */ void ms_setting_init_pre() { memset(&ms_setting, 0, sizeof(ms_setting)); /* common initialize */ ms_setting.ncpu= ms_get_cpu_count(); ms_setting.nthreads= DEFAULT_THREADS_NUM; ms_setting.nconns= DEFAULT_CONNS_NUM; ms_setting.run_time= DEFAULT_RUN_TIME; ms_setting.total_srv_cnt= MCD_SRVS_NUM_INIT; ms_setting.servers= (ms_mcd_server_t *)malloc( (size_t)ms_setting.total_srv_cnt * sizeof(ms_mcd_server_t)); if (ms_setting.servers == NULL) { fprintf(stderr, "Can't allocate servers structure.\n"); exit(1); } ms_setting_slapmode_init_pre(); } /* ms_setting_init_pre */ /** * post part of slap mode initialization of setting structure */ static void ms_setting_slapmode_init_post() { ms_setting.total_key_rng_cnt= KEY_RANGE_COUNT_INIT; ms_setting.key_distr= (ms_key_distr_t *)malloc((size_t)ms_setting.total_key_rng_cnt * sizeof(ms_key_distr_t)); if (ms_setting.key_distr == NULL) { fprintf(stderr, "Can't allocate key distribution structure.\n"); exit(1); } ms_setting.total_val_rng_cnt= VALUE_RANGE_COUNT_INIT; ms_setting.value_distr= (ms_value_distr_t *)malloc((size_t)ms_setting.total_val_rng_cnt * sizeof( ms_value_distr_t)); if (ms_setting.value_distr == NULL) { fprintf(stderr, "Can't allocate value distribution structure.\n"); exit(1); } ms_parse_cfg_file(ms_setting.cfg_file); /* run time mode */ if ((ms_setting.exec_num == 0) && (ms_setting.run_time != 0)) { ms_setting.exec_num= (int64_t)MAX_EXEC_NUM; } else { /* execute number mode */ ms_setting.run_time= 0; } if (ms_setting.rep_write_srv > 0) { /* for replication test, need enable reconnect feature */ ms_setting.reconnect= true; } if (ms_setting.facebook_test && (ms_setting.mult_key_num < 2)) { fprintf(stderr, "facebook test must work with multi-get, " "please specify multi-get key number " "with '--division' option.\n"); exit(1); } if (ms_setting.facebook_test && ms_setting.udp) { fprintf(stderr, "facebook test couldn't work with UDP.\n"); exit(1); } if (ms_setting.udp && (ms_setting.sock_per_conn > 1)) { fprintf(stderr, "UDP doesn't support multi-socks " "in one connection structure.\n"); exit(1); } if ((ms_setting.rep_write_srv > 0) && (ms_setting.srv_cnt < 2)) { fprintf(stderr, "Please specify 2 servers at least for replication\n"); exit(1); } if ((ms_setting.rep_write_srv > 0) && (ms_setting.srv_cnt < ms_setting.rep_write_srv)) { fprintf(stderr, "Servers to do replication writing " "is larger than the total servers\n"); exit(1); } if (ms_setting.udp && (ms_setting.rep_write_srv > 0)) { fprintf(stderr, "UDP doesn't support replication.\n"); exit(1); } if (ms_setting.facebook_test && (ms_setting.rep_write_srv > 0)) { fprintf(stderr, "facebook test couldn't work with replication.\n"); exit(1); } ms_build_distr(); /* initialize global character block */ ms_init_random_block(); ms_print_setting(); } /* ms_setting_slapmode_init_post */ /** * post part of initialization of setting structure */ void ms_setting_init_post() { ms_get_serverlist(ms_setting.srv_str); ms_setting_slapmode_init_post(); } /** * clean up the global setting structure */ void ms_setting_cleanup() { if (ms_setting.distr != NULL) { free(ms_setting.distr); } if (ms_setting.char_block != NULL) { free(ms_setting.char_block); } if (ms_setting.srv_str != NULL) { free(ms_setting.srv_str); } if (ms_setting.cfg_file != NULL) { free(ms_setting.cfg_file); } if (ms_setting.servers != NULL) { free(ms_setting.servers); } if (ms_setting.key_distr != NULL) { free(ms_setting.key_distr); } if (ms_setting.value_distr != NULL) { free(ms_setting.value_distr); } } /* ms_setting_cleanup */