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