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