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