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