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