WIP
[m6w6/libmemcached] / contrib / bin / memaslap / ms_setting.c
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "mem_config.h"
17
18 #include "libmemcached/memcached.h"
19
20 #include <ctype.h>
21 #include <inttypes.h>
22 #include <limits.h>
23 #include <pwd.h>
24 #if HAVE_STRINGS_H
25 # include <strings.h>
26 #endif
27 #include <sys/types.h>
28 #if HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31
32 #include "ms_setting.h"
33 #include "ms_conn.h"
34
35 #define MAX_EXEC_NUM 0x4000000000000000 /* 1 << 62 */
36 #define ADDR_ALIGN(addr) ((addr + 15) & ~(16 - 1)) /* 16 bytes aligned */
37 #define RAND_CHAR_SIZE (10 * 1024 * 1024) /* 10M character table */
38 #define RESERVED_RAND_CHAR_SIZE (2 * 1024 * 1024) /* reserved 2M to avoid pointer sloping over */
39
40 #define DEFAULT_CONFIG_NAME ".memslap.cnf"
41
42 #define DEFAULT_THREADS_NUM 1 /* default start one thread */
43 #define DEFAULT_CONNS_NUM 16 /* default each thread with 16 connections */
44 #define DEFAULT_EXE_NUM 0 /* default execute number is 0 */
45 #define DEFAULT_VERIFY_RATE 0.0 /* default it doesn't do data verification */
46 #define DEFAULT_OVERWRITE_RATE 0.0 /* default it doesn't do overwrite */
47 #define DEFAULT_DIV 1 /* default it runs single get */
48 #define DEFAULT_RUN_TIME 600 /* default run time 10 minutes */
49 #define DEFAULT_WINDOW_SIZE (10 * UNIT_ITEMS_COUNT) /* default window size is 10k */
50 #define DEFAULT_SOCK_PER_CONN 1 /* default socks per connection is 1 */
51
52 /* Use this for string generation */
53 #define CHAR_COUNT 64 /* number of characters used to generate character table */
54 const char ALPHANUMBERICS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-";
55
56 ms_setting_st ms_setting; /* store the settings specified by user */
57
58 /* read setting from configuration file */
59 static void ms_get_serverlist(char *str);
60 static uint32_t ms_get_cpu_count(void);
61 ms_conf_type_t ms_get_conf_type(char *line);
62 static int ms_is_line_data(char *line);
63 static int ms_read_is_data(char *line, ssize_t nread);
64 static void ms_no_config_file(void);
65 static void ms_parse_cfg_file(char *cfg_file);
66
67 /* initialize setting structure */
68 static void ms_init_random_block(void);
69 static void ms_calc_avg_size(void);
70 static int ms_shuffle_distr(ms_distr_t *distr, int length);
71 static void ms_build_distr(void);
72 static void ms_print_setting(void);
73 static void ms_setting_slapmode_init_pre(void);
74 static void ms_setting_slapmode_init_post(void);
75
76 #if !defined(HAVE_GETLINE)
77 # include <limits.h>
78 static ssize_t getline(char **line, size_t *line_size, FILE *fp) {
79 char delim = '\n';
80 ssize_t result = 0;
81 size_t cur_len = 0;
82
83 if (line == NULL || line_size == NULL || fp == NULL) {
84 errno = EINVAL;
85 return -1;
86 }
87
88 if (*line == NULL || *line_size == 0) {
89 char *new_line;
90 *line_size = 120;
91 new_line = (char *) realloc(*line, *line_size);
92 if (new_line == NULL) {
93 result = -1;
94 return result;
95 }
96 *line = new_line;
97 }
98
99 for (;;) {
100 int i = getc(fp);
101 if (i == EOF) {
102 result = -1;
103 break;
104 }
105
106 /* Make enough space for len+1 (for final NUL) bytes. */
107 if (cur_len + 1 >= *line_size) {
108 size_t needed_max = SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
109 size_t needed = (2 * (*line_size)) + 1;
110 char *new_line;
111
112 if (needed_max < needed)
113 needed = needed_max;
114 if (cur_len + 1 >= needed) {
115 result = -1;
116 errno = EOVERFLOW;
117 return result;
118 }
119
120 new_line = (char *) realloc(*line, needed);
121 if (new_line == NULL) {
122 result = -1;
123 return result;
124 }
125
126 *line = new_line;
127 *line_size = needed;
128 }
129
130 (*line)[cur_len] = (char) i;
131 cur_len++;
132
133 if (i == delim)
134 break;
135 }
136 (*line)[cur_len] = '\0';
137 if (cur_len)
138 return (ssize_t) cur_len;
139 return result;
140 }
141 #endif
142
143 /**
144 * parse the server list string, and build the servers
145 * information structure array. this function is used to parse
146 * the command line options specified by user.
147 *
148 * @param str, the string of server list
149 */
150 static void ms_get_serverlist(char *str) {
151 ms_mcd_server_t *srvs = NULL;
152
153 /**
154 * Servers list format is like this. For example:
155 * "localhost:11108, localhost:11109"
156 */
157 memcached_server_st *server_pool;
158 server_pool = memcached_servers_parse(str);
159
160 for (uint32_t loop = 0; loop < memcached_server_list_count(server_pool); loop++) {
161 assert(ms_setting.srv_cnt < ms_setting.total_srv_cnt);
162 strcpy(ms_setting.servers[ms_setting.srv_cnt].srv_host_name, server_pool[loop].hostname);
163 ms_setting.servers[ms_setting.srv_cnt].srv_port = server_pool[loop].port;
164 ms_setting.servers[ms_setting.srv_cnt].disconn_cnt = 0;
165 ms_setting.servers[ms_setting.srv_cnt].reconn_cnt = 0;
166 ms_setting.srv_cnt++;
167
168 if (ms_setting.srv_cnt >= ms_setting.total_srv_cnt) {
169 srvs = (ms_mcd_server_t *) realloc(
170 ms_setting.servers, (size_t) ms_setting.total_srv_cnt * sizeof(ms_mcd_server_t) * 2);
171 if (srvs == NULL) {
172 fprintf(stderr, "Can't reallocate servers structure.\n");
173 exit(1);
174 }
175 ms_setting.servers = srvs;
176 ms_setting.total_srv_cnt *= 2;
177 }
178 }
179
180 memcached_server_free(server_pool);
181 } /* ms_get_serverlist */
182
183 /**
184 * used to get the CPU count of the current system
185 *
186 * @return return the cpu count if get, else return EXIT_FAILURE
187 */
188 static uint32_t ms_get_cpu_count() {
189 #ifdef HAVE__SC_NPROCESSORS_ONLN
190 return sysconf(_SC_NPROCESSORS_CONF);
191
192 #else
193 # ifdef HAVE_CPU_SET_T
194 int cpu_count = 0;
195 cpu_set_t cpu_set;
196
197 sched_getaffinity(0, sizeof(cpu_set_t), &cpu_set);
198
199 for (int i = 0; i < (sizeof(cpu_set_t) * 8); i++) {
200 if (CPU_ISSET(i, &cpu_set)) {
201 cpu_count++;
202 }
203 }
204
205 return cpu_count;
206
207 # endif
208 #endif
209
210 /* the system with one cpu at least */
211 return EXIT_FAILURE;
212 } /* ms_get_cpu_count */
213
214 /**
215 * used to get the configure type based on the type string read
216 * from the configuration file.
217 *
218 * @param line, string of one line
219 *
220 * @return ms_conf_type_t
221 */
222 ms_conf_type_t ms_get_conf_type(char *line) {
223 if (!memcmp(line, "key", strlen("key"))) {
224 return CONF_KEY;
225 } else if (!memcmp(line, "value", strlen("value"))) {
226 return CONF_VALUE;
227 } else if (!memcmp(line, "cmd", strlen("cmd"))) {
228 return CONF_CMD;
229 } else {
230 return CONF_NULL;
231 }
232 } /* ms_get_conf_type */
233
234 /**
235 * judge whether the line is a line with useful data. used to
236 * parse the configuration file.
237 *
238 * @param line, string of one line
239 *
240 * @return if success, return EXIT_FAILURE, else return EXIT_SUCCESS
241 */
242 static int ms_is_line_data(char *line) {
243 assert(line);
244
245 char *begin_ptr = line;
246
247 while (isspace(*begin_ptr)) {
248 begin_ptr++;
249 }
250 if ((begin_ptr[0] == '\0') || (begin_ptr[0] == '#'))
251 return EXIT_SUCCESS;
252
253 return EXIT_FAILURE;
254 } /* ms_is_line_data */
255
256 /**
257 * function to bypass blank line and comments
258 *
259 * @param line, string of one line
260 * @param nread, length of the line
261 *
262 * @return if it's EOF or not line data, return EXIT_SUCCESS, else return EXIT_FAILURE
263 */
264 static int ms_read_is_data(char *line, ssize_t nread) {
265 if ((nread == EOF) || !ms_is_line_data(line))
266 return EXIT_SUCCESS;
267
268 return EXIT_FAILURE;
269 } /* ms_read_is_data */
270
271 /**
272 * if no configuration file, use this function to create the default
273 * configuration file.
274 */
275 static void ms_no_config_file() {
276 char userpath[PATH_MAX];
277 struct passwd *usr = NULL;
278 FILE *fd;
279
280 usr = getpwuid(getuid());
281
282 snprintf(userpath, PATH_MAX, "%s/%s", usr->pw_dir, DEFAULT_CONFIG_NAME);
283
284 if (access(userpath, F_OK | R_OK) == 0)
285 goto exit;
286
287 fd = fopen(userpath, "w+");
288
289 if (fd == NULL) {
290 fprintf(stderr, "Could not create default configure file %s\n", userpath);
291 perror("fopen");
292 exit(1);
293 }
294 fprintf(fd, "%s", DEFAULT_CONGIF_STR);
295 fclose(fd);
296
297 exit:
298 ms_setting.cfg_file = strdup(userpath);
299 } /* ms_no_config_file */
300
301 /**
302 * parse the configuration file
303 *
304 * @param cfg_file, the configuration file name
305 */
306 static void ms_parse_cfg_file(char *cfg_file) {
307 FILE *f;
308 size_t start_len, end_len;
309 double proportion;
310 char *line = NULL;
311 size_t read_len;
312 ssize_t nread;
313 int cmd_type;
314 ms_conf_type_t conf_type;
315 int end_of_file = 0;
316 ms_key_distr_t *key_distr = NULL;
317 ms_value_distr_t *val_distr = NULL;
318
319 if (cfg_file == NULL) {
320 ms_no_config_file();
321 cfg_file = ms_setting.cfg_file;
322 }
323
324 /*read key value configure file*/
325 if ((f = fopen(cfg_file, "r")) == NULL) {
326 fprintf(stderr, "Can not open file: '%s'.\n", cfg_file);
327 exit(1);
328 }
329
330 while (1) {
331 if ((((nread = getline(&line, &read_len, f)) == 1) || !ms_read_is_data(line, nread))
332 && (nread != EOF)) /* bypass blank line */
333 continue;
334
335 if (nread == EOF) {
336 fprintf(stderr, "Bad configuration file, no configuration find.\n");
337 exit(1);
338 }
339 conf_type = ms_get_conf_type(line);
340 break;
341 }
342
343 while (!end_of_file) {
344 switch (conf_type) {
345 case CONF_KEY:
346 while (1) {
347 if ((((nread = getline(&line, &read_len, f)) == 1) || !ms_read_is_data(line, nread))
348 && (nread != EOF)) /* bypass blank line */
349 continue;
350
351 if (nread != EOF) {
352 if (sscanf(line, "%zu %zu %lf ", &start_len, &end_len, &proportion) != 3) {
353 conf_type = ms_get_conf_type(line);
354 break;
355 }
356 ms_setting.key_distr[ms_setting.key_rng_cnt].start_len = start_len;
357 ms_setting.key_distr[ms_setting.key_rng_cnt].end_len = end_len;
358 ms_setting.key_distr[ms_setting.key_rng_cnt].key_prop = proportion;
359 ms_setting.key_rng_cnt++;
360
361 if (ms_setting.key_rng_cnt >= ms_setting.total_key_rng_cnt) {
362 key_distr = (ms_key_distr_t *) realloc(ms_setting.key_distr,
363 (size_t) ms_setting.total_key_rng_cnt
364 * sizeof(ms_key_distr_t) * 2);
365 if (key_distr == NULL) {
366 fprintf(stderr, "Can't reallocate key distribution structure.\n");
367 exit(1);
368 }
369 ms_setting.key_distr = key_distr;
370 ms_setting.total_key_rng_cnt *= 2;
371 }
372 continue;
373 }
374 end_of_file = 1;
375 break;
376 }
377 break;
378
379 case CONF_VALUE:
380 while (1) {
381 if ((((nread = getline(&line, &read_len, f)) == 1) || !ms_read_is_data(line, nread))
382 && (nread != EOF)) /* bypass blank line */
383 continue;
384
385 if (nread != EOF) {
386 if (sscanf(line, "%zu %zu %lf", &start_len, &end_len, &proportion) != 3) {
387 conf_type = ms_get_conf_type(line);
388 break;
389 }
390 ms_setting.value_distr[ms_setting.val_rng_cnt].start_len = start_len;
391 ms_setting.value_distr[ms_setting.val_rng_cnt].end_len = end_len;
392 ms_setting.value_distr[ms_setting.val_rng_cnt].value_prop = proportion;
393 ms_setting.val_rng_cnt++;
394
395 if (ms_setting.val_rng_cnt >= ms_setting.total_val_rng_cnt) {
396 val_distr = (ms_value_distr_t *) realloc(ms_setting.value_distr,
397 (size_t) ms_setting.total_val_rng_cnt
398 * sizeof(ms_value_distr_t) * 2);
399 if (val_distr == NULL) {
400 fprintf(stderr, "Can't reallocate key distribution structure.\n");
401 exit(1);
402 }
403 ms_setting.value_distr = val_distr;
404 ms_setting.total_val_rng_cnt *= 2;
405 }
406 continue;
407 }
408 end_of_file = 1;
409 break;
410 }
411 break;
412
413 case CONF_CMD:
414 while (1) {
415 if ((((nread = getline(&line, &read_len, f)) == 1) || !ms_read_is_data(line, nread))
416 && (nread != EOF)) /* bypass blank line */
417 continue;
418
419 if (nread != EOF) {
420 if (sscanf(line, "%d %lf", &cmd_type, &proportion) != 2) {
421 conf_type = ms_get_conf_type(line);
422 break;
423 }
424 if (cmd_type >= CMD_NULL) {
425 continue;
426 }
427 ms_setting.cmd_distr[ms_setting.cmd_used_count].cmd_type = cmd_type;
428 ms_setting.cmd_distr[ms_setting.cmd_used_count].cmd_prop = proportion;
429 ms_setting.cmd_used_count++;
430 continue;
431 }
432 end_of_file = 1;
433 break;
434 }
435
436 case CONF_NULL:
437 while (1) {
438 if ((((nread = getline(&line, &read_len, f)) == 1) || !ms_read_is_data(line, nread))
439 && (nread != EOF)) /* bypass blank line */
440 continue;
441
442 if (nread != EOF) {
443 if ((conf_type = ms_get_conf_type(line)) != CONF_NULL) {
444 break;
445 }
446 continue;
447 }
448 end_of_file = 1;
449 break;
450 }
451 break;
452
453 default:
454 assert(0);
455 break;
456 } /* switch */
457 }
458
459 fclose(f);
460
461 if (line) {
462 free(line);
463 }
464 } /* ms_parse_cfg_file */
465
466 /* calculate the average size of key and value */
467 static void ms_calc_avg_size() {
468 double avg_val_size = 0.0;
469 double avg_key_size = 0.0;
470 double val_pro = 0.0;
471 double key_pro = 0.0;
472 double averge_len = 0.0;
473 size_t start_len = 0;
474 size_t end_len = 0;
475
476 for (int j = 0; j < ms_setting.val_rng_cnt; j++) {
477 val_pro = ms_setting.value_distr[j].value_prop;
478 start_len = ms_setting.value_distr[j].start_len;
479 end_len = ms_setting.value_distr[j].end_len;
480
481 averge_len = val_pro * ((double) (start_len + end_len)) / 2;
482 avg_val_size += averge_len;
483 }
484
485 for (int j = 0; j < ms_setting.key_rng_cnt; j++) {
486 key_pro = ms_setting.key_distr[j].key_prop;
487 start_len = ms_setting.key_distr[j].start_len;
488 end_len = ms_setting.key_distr[j].end_len;
489
490 averge_len = key_pro * ((double) (start_len + end_len)) / 2;
491 avg_key_size += averge_len;
492 }
493
494 ms_setting.avg_val_size = (size_t) avg_val_size;
495 ms_setting.avg_key_size = (size_t) avg_key_size;
496 } /* ms_calc_avg_size */
497
498 /**
499 * used to shuffle key and value distribution array to ensure
500 * (key, value) pair with different set.
501 *
502 * @param distr, pointer of distribution structure array
503 * @param length, length of the array
504 *
505 * @return always return EXIT_SUCCESS
506 */
507 static int ms_shuffle_distr(ms_distr_t *distr, int length) {
508 int i, j;
509 int tmp_offset;
510 size_t tmp_size;
511 int64_t rnd;
512
513 for (i = 0; i < length; i++) {
514 rnd = random();
515 j = (int) (rnd % (length - i)) + i;
516
517 switch (rnd % 3) {
518 case 0:
519 tmp_size = distr[j].key_size;
520 distr[j].key_size = distr[i].key_size;
521 distr[i].key_size = tmp_size;
522 break;
523
524 case 1:
525 tmp_offset = distr[j].key_offset;
526 distr[j].key_offset = distr[i].key_offset;
527 distr[i].key_offset = tmp_offset;
528 break;
529
530 case 2:
531 tmp_size = distr[j].value_size;
532 distr[j].value_size = distr[i].value_size;
533 distr[i].value_size = tmp_size;
534 break;
535
536 default:
537 break;
538 } /* switch */
539 }
540
541 return EXIT_SUCCESS;
542 } /* ms_shuffle_distr */
543
544 /**
545 * according to the key and value distribution, to build the
546 * (key, value) pair distribution. the (key, value) pair
547 * distribution array is global, each connection set or get
548 * object keeping this distribution, for the final result, we
549 * can reach the expected key and value distribution.
550 */
551 static void ms_build_distr() {
552 int offset = 0;
553 int end = 0;
554 int key_cnt = 0;
555 int value_cnt = 0;
556 size_t average_len = 0;
557 size_t diff_len = 0;
558 size_t start_len = 0;
559 size_t end_len = 0;
560 int rnd = 0;
561 ms_distr_t *distr = NULL;
562 int units = (int) ms_setting.win_size / UNIT_ITEMS_COUNT;
563
564 /* calculate average value size and key size */
565 ms_calc_avg_size();
566
567 ms_setting.char_blk_size = RAND_CHAR_SIZE;
568 int key_scope_size =
569 (int) ((ms_setting.char_blk_size - RESERVED_RAND_CHAR_SIZE) / UNIT_ITEMS_COUNT);
570
571 ms_setting.distr = (ms_distr_t *) malloc(sizeof(ms_distr_t) * ms_setting.win_size);
572 if (ms_setting.distr == NULL) {
573 fprintf(stderr, "Can't allocate distribution array.");
574 exit(1);
575 }
576
577 /**
578 * character block is divided by how many different key
579 * size, each different key size has the same size character
580 * range.
581 */
582 for (int m = 0; m < units; m++) {
583 for (int i = 0; i < UNIT_ITEMS_COUNT; i++) {
584 ms_setting.distr[m * UNIT_ITEMS_COUNT + i].key_offset = ADDR_ALIGN(key_scope_size * i);
585 }
586 }
587
588 /* initialize key size distribution */
589 for (int m = 0; m < units; m++) {
590 for (int j = 0; j < ms_setting.key_rng_cnt; j++) {
591 key_cnt = (int) (UNIT_ITEMS_COUNT * ms_setting.key_distr[j].key_prop);
592 start_len = ms_setting.key_distr[j].start_len;
593 end_len = ms_setting.key_distr[j].end_len;
594 if ((start_len < MIN_KEY_SIZE) || (end_len < MIN_KEY_SIZE)) {
595 fprintf(stderr, "key length must be greater than 16 bytes.\n");
596 exit(1);
597 }
598
599 if (!ms_setting.binary_prot_ && ((start_len > MAX_KEY_SIZE) || (end_len > MAX_KEY_SIZE))) {
600 fprintf(stderr, "key length must be less than 250 bytes.\n");
601 exit(1);
602 }
603
604 average_len = (start_len + end_len) / 2;
605 diff_len = (end_len - start_len) / 2;
606 for (int k = 0; k < key_cnt; k++) {
607 if (offset >= (m + 1) * UNIT_ITEMS_COUNT) {
608 break;
609 }
610 rnd = (int) random();
611 if (k % 2 == 0) {
612 ms_setting.distr[offset].key_size =
613 (diff_len == 0) ? average_len : average_len + (size_t) rnd % diff_len;
614 } else {
615 ms_setting.distr[offset].key_size =
616 (diff_len == 0) ? average_len : average_len - (size_t) rnd % diff_len;
617 }
618 offset++;
619 }
620 }
621
622 if (offset < (m + 1) * UNIT_ITEMS_COUNT) {
623 end = (m + 1) * UNIT_ITEMS_COUNT - offset;
624 for (int i = 0; i < end; i++) {
625 ms_setting.distr[offset].key_size = ms_setting.avg_key_size;
626 offset++;
627 }
628 }
629 }
630 offset = 0;
631
632 /* initialize value distribution */
633 if (ms_setting.fixed_value_size) {
634 for (int i = 0; i < units * UNIT_ITEMS_COUNT; i++) {
635 ms_setting.distr[i].value_size = ms_setting.fixed_value_size;
636 }
637 } else {
638 for (int m = 0; m < units; m++) {
639 for (int j = 0; j < ms_setting.val_rng_cnt; j++) {
640 value_cnt = (int) (UNIT_ITEMS_COUNT * ms_setting.value_distr[j].value_prop);
641 start_len = ms_setting.value_distr[j].start_len;
642 end_len = ms_setting.value_distr[j].end_len;
643 if ((start_len <= 0) || (end_len <= 0)) {
644 fprintf(stderr, "value length must be greater than 0 bytes.\n");
645 exit(1);
646 }
647
648 if ((start_len > MAX_VALUE_SIZE) || (end_len > MAX_VALUE_SIZE)) {
649 fprintf(stderr, "key length must be less than or equal to 1M.\n");
650 exit(1);
651 }
652
653 average_len = (start_len + end_len) / 2;
654 diff_len = (end_len - start_len) / 2;
655 for (int k = 0; k < value_cnt; k++) {
656 if (offset >= (m + 1) * UNIT_ITEMS_COUNT) {
657 break;
658 }
659 rnd = (int) random();
660 if (k % 2 == 0) {
661 ms_setting.distr[offset].value_size =
662 (diff_len == 0) ? average_len : average_len + (size_t) rnd % diff_len;
663 } else {
664 ms_setting.distr[offset].value_size =
665 (diff_len == 0) ? average_len : average_len - (size_t) rnd % diff_len;
666 }
667 offset++;
668 }
669 }
670
671 if (offset < (m + 1) * UNIT_ITEMS_COUNT) {
672 end = (m + 1) * UNIT_ITEMS_COUNT - offset;
673 for (int i = 0; i < end; i++) {
674 ms_setting.distr[offset++].value_size = ms_setting.avg_val_size;
675 }
676 }
677 }
678 }
679
680 /* shuffle distribution */
681 for (int i = 0; i < units; i++) {
682 distr = &ms_setting.distr[i * UNIT_ITEMS_COUNT];
683 for (int j = 0; j < 4; j++) {
684 ms_shuffle_distr(distr, UNIT_ITEMS_COUNT);
685 }
686 }
687 } /* ms_build_distr */
688
689 /**
690 * used to initialize the global character block. The character
691 * block is used to generate the suffix of the key and value. we
692 * only store a pointer in the character block for each key
693 * suffix or value string. It can save much memory to store key
694 * or value string.
695 */
696 static void ms_init_random_block() {
697 char *ptr = NULL;
698
699 assert(ms_setting.char_blk_size > 0);
700
701 ms_setting.char_block = (char *) malloc(ms_setting.char_blk_size);
702 if (ms_setting.char_block == NULL) {
703 fprintf(stderr, "Can't allocate global char block.");
704 exit(1);
705 }
706 ptr = ms_setting.char_block;
707
708 for (int i = 0; (size_t) i < ms_setting.char_blk_size; i++) {
709 *(ptr++) = ALPHANUMBERICS[random() % CHAR_COUNT];
710 }
711 } /* ms_init_random_block */
712
713 /**
714 * after initialization, call this function to output the main
715 * configuration user specified.
716 */
717 static void ms_print_setting() {
718 fprintf(stdout, "servers: %s\n", ms_setting.srv_str);
719 fprintf(stdout, "threads count: %d\n", ms_setting.nthreads);
720 fprintf(stdout, "concurrency: %d\n", ms_setting.nconns);
721 if (ms_setting.run_time > 0) {
722 fprintf(stdout, "run time: %ds\n", ms_setting.run_time);
723 } else {
724 fprintf(stdout, "execute number: %" PRId64 "\n", ms_setting.exec_num);
725 }
726 fprintf(stdout, "windows size: %" PRId64 "k\n", (int64_t)(ms_setting.win_size / 1024));
727 fprintf(stdout, "set proportion: set_prop=%.2f\n", ms_setting.cmd_distr[CMD_SET].cmd_prop);
728 fprintf(stdout, "get proportion: get_prop=%.2f\n", ms_setting.cmd_distr[CMD_GET].cmd_prop);
729 fflush(stdout);
730 } /* ms_print_setting */
731
732 /**
733 * previous part of slap mode initialization of setting structure
734 */
735 static void ms_setting_slapmode_init_pre() {
736 ms_setting.exec_num = DEFAULT_EXE_NUM;
737 ms_setting.verify_percent = DEFAULT_VERIFY_RATE;
738 ms_setting.exp_ver_per = DEFAULT_VERIFY_RATE;
739 ms_setting.overwrite_percent = DEFAULT_OVERWRITE_RATE;
740 ms_setting.mult_key_num = DEFAULT_DIV;
741 ms_setting.fixed_value_size = 0;
742 ms_setting.win_size = DEFAULT_WINDOW_SIZE;
743 ms_setting.udp = false;
744 ms_setting.reconnect = false;
745 ms_setting.verbose = false;
746 ms_setting.facebook_test = false;
747 ms_setting.binary_prot_ = false;
748 ms_setting.stat_freq = 0;
749 ms_setting.srv_str = NULL;
750 ms_setting.cfg_file = NULL;
751 ms_setting.sock_per_conn = DEFAULT_SOCK_PER_CONN;
752 ms_setting.expected_tps = 0;
753 ms_setting.rep_write_srv = 0;
754 } /* ms_setting_slapmode_init_pre */
755
756 /**
757 * previous part of initialization of setting structure
758 */
759 void ms_setting_init_pre() {
760 memset(&ms_setting, 0, sizeof(ms_setting));
761
762 /* common initialize */
763 ms_setting.ncpu = ms_get_cpu_count();
764 ms_setting.nthreads = DEFAULT_THREADS_NUM;
765 ms_setting.nconns = DEFAULT_CONNS_NUM;
766 ms_setting.run_time = DEFAULT_RUN_TIME;
767 ms_setting.total_srv_cnt = MCD_SRVS_NUM_INIT;
768 ms_setting.servers =
769 (ms_mcd_server_t *) malloc((size_t) ms_setting.total_srv_cnt * sizeof(ms_mcd_server_t));
770 if (ms_setting.servers == NULL) {
771 fprintf(stderr, "Can't allocate servers structure.\n");
772 exit(1);
773 }
774
775 ms_setting_slapmode_init_pre();
776 } /* ms_setting_init_pre */
777
778 /**
779 * post part of slap mode initialization of setting structure
780 */
781 static void ms_setting_slapmode_init_post() {
782 ms_setting.total_key_rng_cnt = KEY_RANGE_COUNT_INIT;
783 ms_setting.key_distr =
784 (ms_key_distr_t *) malloc((size_t) ms_setting.total_key_rng_cnt * sizeof(ms_key_distr_t));
785
786 if (ms_setting.key_distr == NULL) {
787 fprintf(stderr, "Can't allocate key distribution structure.\n");
788 exit(1);
789 }
790
791 ms_setting.total_val_rng_cnt = VALUE_RANGE_COUNT_INIT;
792
793 ms_setting.value_distr =
794 (ms_value_distr_t *) malloc((size_t) ms_setting.total_val_rng_cnt * sizeof(ms_value_distr_t));
795
796 if (ms_setting.value_distr == NULL) {
797 fprintf(stderr, "Can't allocate value distribution structure.\n");
798 exit(1);
799 }
800
801 ms_parse_cfg_file(ms_setting.cfg_file);
802
803 /* run time mode */
804 if ((ms_setting.exec_num == 0) && (ms_setting.run_time)) {
805 ms_setting.exec_num = (int64_t) MAX_EXEC_NUM;
806 } else {
807 /* execute number mode */
808 ms_setting.run_time = 0;
809 }
810
811 if (ms_setting.rep_write_srv > 0) {
812 /* for replication test, need enable reconnect feature */
813 ms_setting.reconnect = true;
814 }
815
816 if (ms_setting.facebook_test && (ms_setting.mult_key_num < 2)) {
817 fprintf(stderr,
818 "facebook test must work with multi-get, "
819 "please specify multi-get key number "
820 "with '--division' option.\n");
821 exit(1);
822 }
823
824 if (ms_setting.facebook_test && ms_setting.udp) {
825 fprintf(stderr, "facebook test couldn't work with UDP.\n");
826 exit(1);
827 }
828
829 if (ms_setting.udp && (ms_setting.sock_per_conn > 1)) {
830 fprintf(stderr,
831 "UDP doesn't support multi-socks "
832 "in one connection structure.\n");
833 exit(1);
834 }
835
836 if ((ms_setting.rep_write_srv > 0) && (ms_setting.srv_cnt < 2)) {
837 fprintf(stderr, "Please specify 2 servers at least for replication\n");
838 exit(1);
839 }
840
841 if ((ms_setting.rep_write_srv > 0) && (ms_setting.srv_cnt < ms_setting.rep_write_srv)) {
842 fprintf(stderr,
843 "Servers to do replication writing "
844 "is larger than the total servers\n");
845 exit(1);
846 }
847
848 if (ms_setting.udp && (ms_setting.rep_write_srv > 0)) {
849 fprintf(stderr, "UDP doesn't support replication.\n");
850 exit(1);
851 }
852
853 if (ms_setting.facebook_test && (ms_setting.rep_write_srv > 0)) {
854 fprintf(stderr, "facebook test couldn't work with replication.\n");
855 exit(1);
856 }
857
858 ms_build_distr();
859
860 /* initialize global character block */
861 ms_init_random_block();
862 ms_print_setting();
863 } /* ms_setting_slapmode_init_post */
864
865 /**
866 * post part of initialization of setting structure
867 */
868 void ms_setting_init_post() {
869 ms_get_serverlist(ms_setting.srv_str);
870 ms_setting_slapmode_init_post();
871 }
872
873 /**
874 * clean up the global setting structure
875 */
876 void ms_setting_cleanup() {
877 if (ms_setting.distr) {
878 free(ms_setting.distr);
879 }
880
881 if (ms_setting.char_block) {
882 free(ms_setting.char_block);
883 }
884
885 if (ms_setting.srv_str) {
886 free(ms_setting.srv_str);
887 }
888
889 if (ms_setting.cfg_file) {
890 free(ms_setting.cfg_file);
891 }
892
893 if (ms_setting.servers) {
894 free(ms_setting.servers);
895 }
896
897 if (ms_setting.key_distr) {
898 free(ms_setting.key_distr);
899 }
900
901 if (ms_setting.value_distr) {
902 free(ms_setting.value_distr);
903 }
904 } /* ms_setting_cleanup */