Compiles.
[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 uint32_t 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 uint32_t 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 char *line= NULL;
346 size_t read_len;
347 ssize_t nread;
348 int cmd_type;
349 ms_conf_type_t conf_type;
350 int end_of_file= 0;
351 ms_key_distr_t *key_distr= NULL;
352 ms_value_distr_t *val_distr= NULL;
353
354 if (cfg_file == NULL)
355 {
356 ms_no_config_file();
357 cfg_file= ms_setting.cfg_file;
358 }
359
360 /*read key value configure file*/
361 if ((f= fopen(cfg_file, "r")) == NULL)
362 {
363 fprintf(stderr, "Can not open file: '%s'.\n", cfg_file);
364 exit(1);
365 }
366
367 while (1)
368 {
369 if ((((nread= getline(&line, &read_len, f)) == 1)
370 || ! ms_read_is_data(line, nread)) && (nread != EOF)) /* bypass blank line */
371 continue;
372
373 if (nread == EOF)
374 {
375 fprintf(stderr, "Bad configuration file, no configuration find.\n");
376 exit(1);
377 }
378 conf_type= ms_get_conf_type(line);
379 break;
380 }
381
382 while (! end_of_file)
383 {
384 switch (conf_type)
385 {
386 case CONF_KEY:
387 while (1)
388 {
389 if ((((nread= getline(&line, &read_len, f)) == 1)
390 || ! ms_read_is_data(line, nread)) && (nread != EOF)) /* bypass blank line */
391 continue;
392
393 if (nread != EOF)
394 {
395 if (sscanf(line, "%zu %zu %lf ", &start_len,
396 &end_len, &proportion) != 3)
397 {
398 conf_type= ms_get_conf_type(line);
399 break;
400 }
401 ms_setting.key_distr[ms_setting.key_rng_cnt].start_len= start_len;
402 ms_setting.key_distr[ms_setting.key_rng_cnt].end_len= end_len;
403 ms_setting.key_distr[ms_setting.key_rng_cnt].key_prop= proportion;
404 ms_setting.key_rng_cnt++;
405
406 if (ms_setting.key_rng_cnt >= ms_setting.total_key_rng_cnt)
407 {
408 key_distr= (ms_key_distr_t *)realloc(
409 ms_setting.key_distr,
410 (size_t)ms_setting.
411 total_key_rng_cnt * sizeof(ms_key_distr_t) * 2);
412 if (key_distr == NULL)
413 {
414 fprintf(stderr,
415 "Can't reallocate key distribution structure.\n");
416 exit(1);
417 }
418 ms_setting.key_distr= key_distr;
419 ms_setting.total_key_rng_cnt*= 2;
420 }
421 continue;
422 }
423 end_of_file= 1;
424 break;
425 }
426 break;
427
428 case CONF_VALUE:
429 while (1)
430 {
431 if ((((nread= getline(&line, &read_len, f)) == 1)
432 || ! ms_read_is_data(line, nread)) && (nread != EOF)) /* bypass blank line */
433 continue;
434
435 if (nread != EOF)
436 {
437 if (sscanf(line, "%zu %zu %lf", &start_len, &end_len,
438 &proportion) != 3)
439 {
440 conf_type= ms_get_conf_type(line);
441 break;
442 }
443 ms_setting.value_distr[ms_setting.val_rng_cnt].start_len=
444 start_len;
445 ms_setting.value_distr[ms_setting.val_rng_cnt].end_len= end_len;
446 ms_setting.value_distr[ms_setting.val_rng_cnt].value_prop=
447 proportion;
448 ms_setting.val_rng_cnt++;
449
450 if (ms_setting.val_rng_cnt >= ms_setting.total_val_rng_cnt)
451 {
452 val_distr= (ms_value_distr_t *)realloc(
453 ms_setting.value_distr,
454 (size_t)ms_setting.
455 total_val_rng_cnt * sizeof(ms_value_distr_t) * 2);
456 if (val_distr == NULL)
457 {
458 fprintf(stderr,
459 "Can't reallocate key distribution structure.\n");
460 exit(1);
461 }
462 ms_setting.value_distr= val_distr;
463 ms_setting.total_val_rng_cnt*= 2;
464 }
465 continue;
466 }
467 end_of_file= 1;
468 break;
469 }
470 break;
471
472 case CONF_CMD:
473 while (1)
474 {
475 if ((((nread= getline(&line, &read_len, f)) == 1)
476 || ! ms_read_is_data(line, nread)) && (nread != EOF)) /* bypass blank line */
477 continue;
478
479 if (nread != EOF)
480 {
481 if (sscanf(line, "%d %lf", &cmd_type, &proportion) != 2)
482 {
483 conf_type= ms_get_conf_type(line);
484 break;
485 }
486 if (cmd_type >= CMD_NULL)
487 {
488 continue;
489 }
490 ms_setting.cmd_distr[ms_setting.cmd_used_count].cmd_type=
491 cmd_type;
492 ms_setting.cmd_distr[ms_setting.cmd_used_count].cmd_prop=
493 proportion;
494 ms_setting.cmd_used_count++;
495 continue;
496 }
497 end_of_file= 1;
498 break;
499 }
500
501 case CONF_NULL:
502 while (1)
503 {
504 if ((((nread= getline(&line, &read_len, f)) == 1)
505 || ! ms_read_is_data(line, nread)) && (nread != EOF)) /* bypass blank line */
506 continue;
507
508 if (nread != EOF)
509 {
510 if ((conf_type= ms_get_conf_type(line)) != CONF_NULL)
511 {
512 break;
513 }
514 continue;
515 }
516 end_of_file= 1;
517 break;
518 }
519 break;
520
521 default:
522 assert(0);
523 break;
524 } /* switch */
525 }
526
527 fclose(f);
528
529 if (line != NULL)
530 {
531 free(line);
532 }
533 } /* ms_parse_cfg_file */
534
535
536 /* calculate the average size of key and value */
537 static void ms_calc_avg_size()
538 {
539 double avg_val_size= 0.0;
540 double avg_key_size= 0.0;
541 double val_pro= 0.0;
542 double key_pro= 0.0;
543 double averge_len= 0.0;
544 size_t start_len= 0;
545 size_t end_len= 0;
546
547 for (int j= 0; j < ms_setting.val_rng_cnt; j++)
548 {
549 val_pro= ms_setting.value_distr[j].value_prop;
550 start_len= ms_setting.value_distr[j].start_len;
551 end_len= ms_setting.value_distr[j].end_len;
552
553 averge_len= val_pro * ((double)(start_len + end_len)) / 2;
554 avg_val_size+= averge_len;
555 }
556
557 for (int j= 0; j < ms_setting.key_rng_cnt; j++)
558 {
559 key_pro= ms_setting.key_distr[j].key_prop;
560 start_len= ms_setting.key_distr[j].start_len;
561 end_len= ms_setting.key_distr[j].end_len;
562
563 averge_len= key_pro * ((double)(start_len + end_len)) / 2;
564 avg_key_size+= averge_len;
565 }
566
567 ms_setting.avg_val_size= (size_t)avg_val_size;
568 ms_setting.avg_key_size= (size_t)avg_key_size;
569 } /* ms_calc_avg_size */
570
571
572 /**
573 * used to shuffle key and value distribution array to ensure
574 * (key, value) pair with different set.
575 *
576 * @param distr, pointer of distribution structure array
577 * @param length, length of the array
578 *
579 * @return always return 0
580 */
581 static int ms_shuffle_distr(ms_distr_t *distr, int length)
582 {
583 int i, j;
584 int tmp_offset;
585 size_t tmp_size;
586 int64_t rnd;
587
588 for (i= 0; i < length; i++)
589 {
590 rnd= random();
591 j= (int)(rnd % (length - i)) + i;
592
593 switch (rnd % 3)
594 {
595 case 0:
596 tmp_size= distr[j].key_size;
597 distr[j].key_size= distr[i].key_size;
598 distr[i].key_size= tmp_size;
599 break;
600
601 case 1:
602 tmp_offset= distr[j].key_offset;
603 distr[j].key_offset= distr[i].key_offset;
604 distr[i].key_offset= tmp_offset;
605 break;
606
607 case 2:
608 tmp_size= distr[j].value_size;
609 distr[j].value_size= distr[i].value_size;
610 distr[i].value_size= tmp_size;
611 break;
612
613 default:
614 break;
615 } /* switch */
616 }
617
618 return 0;
619 } /* ms_shuffle_distr */
620
621
622 /**
623 * according to the key and value distribution, to build the
624 * (key, value) pair distribution. the (key, value) pair
625 * distribution array is global, each connection set or get
626 * object keeping this distribution, for the final result, we
627 * can reach the expected key and value distribution.
628 */
629 static void ms_build_distr()
630 {
631 int offset= 0;
632 int end= 0;
633 int key_cnt= 0;
634 int value_cnt= 0;
635 size_t average_len= 0;
636 size_t diff_len= 0;
637 size_t start_len= 0;
638 size_t end_len= 0;
639 int rnd= 0;
640 ms_distr_t *distr= NULL;
641 int units= (int)ms_setting.win_size / UNIT_ITEMS_COUNT;
642
643 /* calculate average value size and key size */
644 ms_calc_avg_size();
645
646 ms_setting.char_blk_size= RAND_CHAR_SIZE;
647 int key_scope_size=
648 (int)((ms_setting.char_blk_size - RESERVED_RAND_CHAR_SIZE)
649 / UNIT_ITEMS_COUNT);
650
651 ms_setting.distr= (ms_distr_t *)malloc(
652 sizeof(ms_distr_t) * ms_setting.win_size);
653 if (ms_setting.distr == NULL)
654 {
655 fprintf(stderr, "Can't allocate distribution array.");
656 exit(1);
657 }
658
659 /**
660 * character block is divided by how many different key
661 * size, each different key size has the same size character
662 * range.
663 */
664 for (int m= 0; m < units; m++)
665 {
666 for (int i= 0; i < UNIT_ITEMS_COUNT; i++)
667 {
668 ms_setting.distr[m * UNIT_ITEMS_COUNT + i].key_offset=
669 ADDR_ALIGN(key_scope_size * i);
670 }
671 }
672
673 /* initialize key size distribution */
674 for (int m= 0; m < units; m++)
675 {
676 for (int j= 0; j < ms_setting.key_rng_cnt; j++)
677 {
678 key_cnt= (int)(UNIT_ITEMS_COUNT * ms_setting.key_distr[j].key_prop);
679 start_len= ms_setting.key_distr[j].start_len;
680 end_len= ms_setting.key_distr[j].end_len;
681 if ((start_len < MIN_KEY_SIZE) || (end_len < MIN_KEY_SIZE))
682 {
683 fprintf(stderr, "key length must be greater than 16 bytes.\n");
684 exit(1);
685 }
686
687 if (! ms_setting.binary_prot
688 && ((start_len > MAX_KEY_SIZE) || (end_len > MAX_KEY_SIZE)))
689 {
690 fprintf(stderr, "key length must be less than 250 bytes.\n");
691 exit(1);
692 }
693
694 average_len= (start_len + end_len) / 2;
695 diff_len= (end_len - start_len) / 2;
696 for (int k= 0; k < key_cnt; k++)
697 {
698 if (offset >= (m + 1) * UNIT_ITEMS_COUNT)
699 {
700 break;
701 }
702 rnd= (int)random();
703 if (k % 2 == 0)
704 {
705 ms_setting.distr[offset].key_size=
706 (diff_len == 0) ? average_len :
707 average_len + (size_t)rnd
708 % diff_len;
709 }
710 else
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 offset++;
718 }
719 }
720
721 if (offset < (m + 1) * UNIT_ITEMS_COUNT)
722 {
723 end= (m + 1) * UNIT_ITEMS_COUNT - offset;
724 for (int i= 0; i < end; i++)
725 {
726 ms_setting.distr[offset].key_size= ms_setting.avg_key_size;
727 offset++;
728 }
729 }
730 }
731 offset= 0;
732
733 /* initialize value distribution */
734 if (ms_setting.fixed_value_size != 0)
735 {
736 for (int i= 0; i < units * UNIT_ITEMS_COUNT; i++)
737 {
738 ms_setting.distr[i].value_size= ms_setting.fixed_value_size;
739 }
740 }
741 else
742 {
743 for (int m= 0; m < units; m++)
744 {
745 for (int j= 0; j < ms_setting.val_rng_cnt; j++)
746 {
747 value_cnt=
748 (int)(UNIT_ITEMS_COUNT * ms_setting.value_distr[j].value_prop);
749 start_len= ms_setting.value_distr[j].start_len;
750 end_len= ms_setting.value_distr[j].end_len;
751 if ((start_len <= 0) || (end_len <= 0))
752 {
753 fprintf(stderr, "value length must be greater than 0 bytes.\n");
754 exit(1);
755 }
756
757 if ((start_len > MAX_VALUE_SIZE) || (end_len > MAX_VALUE_SIZE))
758 {
759 fprintf(stderr, "key length must be less than or equal to 1M.\n");
760 exit(1);
761 }
762
763 average_len= (start_len + end_len) / 2;
764 diff_len= (end_len - start_len) / 2;
765 for (int k= 0; k < value_cnt; k++)
766 {
767 if (offset >= (m + 1) * UNIT_ITEMS_COUNT)
768 {
769 break;
770 }
771 rnd= (int)random();
772 if (k % 2 == 0)
773 {
774 ms_setting.distr[offset].value_size=
775 (diff_len == 0) ? average_len :
776 average_len
777 + (size_t)rnd % diff_len;
778 }
779 else
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 offset++;
787 }
788 }
789
790 if (offset < (m + 1) * UNIT_ITEMS_COUNT)
791 {
792 end= (m + 1) * UNIT_ITEMS_COUNT - offset;
793 for (int i= 0; i < end; i++)
794 {
795 ms_setting.distr[offset++].value_size= ms_setting.avg_val_size;
796 }
797 }
798 }
799 }
800
801 /* shuffle distribution */
802 for (int i= 0; i < units; i++)
803 {
804 distr= &ms_setting.distr[i * UNIT_ITEMS_COUNT];
805 for (int j= 0; j < 4; j++)
806 {
807 ms_shuffle_distr(distr, UNIT_ITEMS_COUNT);
808 }
809 }
810 } /* ms_build_distr */
811
812
813 /**
814 * used to initialize the global character block. The character
815 * block is used to generate the suffix of the key and value. we
816 * only store a pointer in the character block for each key
817 * suffix or value string. It can save much memory to store key
818 * or value string.
819 */
820 static void ms_init_random_block()
821 {
822 char *ptr= NULL;
823
824 assert(ms_setting.char_blk_size > 0);
825
826 ms_setting.char_block= (char *)malloc(ms_setting.char_blk_size);
827 if (ms_setting.char_block == NULL)
828 {
829 fprintf(stderr, "Can't allocate global char block.");
830 exit(1);
831 }
832 ptr= ms_setting.char_block;
833
834 for (int i= 0; (size_t)i < ms_setting.char_blk_size; i++)
835 {
836 *(ptr++)= ALPHANUMBERICS[random() % CHAR_COUNT];
837 }
838 } /* ms_init_random_block */
839
840
841 /**
842 * after initialization, call this function to output the main
843 * configuration user specified.
844 */
845 static void ms_print_setting()
846 {
847 fprintf(stdout, "servers : %s\n", ms_setting.srv_str);
848 fprintf(stdout, "threads count: %d\n", ms_setting.nthreads);
849 fprintf(stdout, "concurrency: %d\n", ms_setting.nconns);
850 if (ms_setting.run_time > 0)
851 {
852 fprintf(stdout, "run time: %ds\n", ms_setting.run_time);
853 }
854 else
855 {
856 fprintf(stdout, "execute number: %" PRId64 "\n", ms_setting.exec_num);
857 }
858 fprintf(stdout, "windows size: %" PRId64 "k\n",
859 (int64_t)(ms_setting.win_size / 1024));
860 fprintf(stdout, "set proportion: set_prop=%.2f\n",
861 ms_setting.cmd_distr[CMD_SET].cmd_prop);
862 fprintf(stdout, "get proportion: get_prop=%.2f\n",
863 ms_setting.cmd_distr[CMD_GET].cmd_prop);
864 fflush(stdout);
865 } /* ms_print_setting */
866
867
868 /**
869 * previous part of slap mode initialization of setting structure
870 */
871 static void ms_setting_slapmode_init_pre()
872 {
873 ms_setting.exec_num= DEFAULT_EXE_NUM;
874 ms_setting.verify_percent= DEFAULT_VERIFY_RATE;
875 ms_setting.exp_ver_per= DEFAULT_VERIFY_RATE;
876 ms_setting.overwrite_percent= DEFAULT_OVERWRITE_RATE;
877 ms_setting.mult_key_num= DEFAULT_DIV;
878 ms_setting.fixed_value_size= 0;
879 ms_setting.win_size= DEFAULT_WINDOW_SIZE;
880 ms_setting.udp= false;
881 ms_setting.reconnect= false;
882 ms_setting.verbose= false;
883 ms_setting.facebook_test= false;
884 ms_setting.binary_prot= false;
885 ms_setting.stat_freq= 0;
886 ms_setting.srv_str= NULL;
887 ms_setting.cfg_file= NULL;
888 ms_setting.sock_per_conn= DEFAULT_SOCK_PER_CONN;
889 ms_setting.expected_tps= 0;
890 ms_setting.rep_write_srv= 0;
891 } /* ms_setting_slapmode_init_pre */
892
893
894 /**
895 * previous part of initialization of setting structure
896 */
897 void ms_setting_init_pre()
898 {
899 memset(&ms_setting, 0, sizeof(ms_setting));
900
901 /* common initialize */
902 ms_setting.ncpu= ms_get_cpu_count();
903 ms_setting.nthreads= DEFAULT_THREADS_NUM;
904 ms_setting.nconns= DEFAULT_CONNS_NUM;
905 ms_setting.run_time= DEFAULT_RUN_TIME;
906 ms_setting.total_srv_cnt= MCD_SRVS_NUM_INIT;
907 ms_setting.servers= (ms_mcd_server_t *)malloc(
908 (size_t)ms_setting.total_srv_cnt
909 * sizeof(ms_mcd_server_t));
910 if (ms_setting.servers == NULL)
911 {
912 fprintf(stderr, "Can't allocate servers structure.\n");
913 exit(1);
914 }
915
916 ms_setting_slapmode_init_pre();
917 } /* ms_setting_init_pre */
918
919
920 /**
921 * post part of slap mode initialization of setting structure
922 */
923 static void ms_setting_slapmode_init_post()
924 {
925 ms_setting.total_key_rng_cnt= KEY_RANGE_COUNT_INIT;
926 ms_setting.key_distr=
927 (ms_key_distr_t *)malloc((size_t)ms_setting.total_key_rng_cnt * sizeof(ms_key_distr_t));
928
929 if (ms_setting.key_distr == NULL)
930 {
931 fprintf(stderr, "Can't allocate key distribution structure.\n");
932 exit(1);
933 }
934
935 ms_setting.total_val_rng_cnt= VALUE_RANGE_COUNT_INIT;
936
937 ms_setting.value_distr=
938 (ms_value_distr_t *)malloc((size_t)ms_setting.total_val_rng_cnt * sizeof( ms_value_distr_t));
939
940 if (ms_setting.value_distr == NULL)
941 {
942 fprintf(stderr, "Can't allocate value distribution structure.\n");
943 exit(1);
944 }
945
946 ms_parse_cfg_file(ms_setting.cfg_file);
947
948 /* run time mode */
949 if ((ms_setting.exec_num == 0) && (ms_setting.run_time != 0))
950 {
951 ms_setting.exec_num= (int64_t)MAX_EXEC_NUM;
952 }
953 else
954 {
955 /* execute number mode */
956 ms_setting.run_time= 0;
957 }
958
959 if (ms_setting.rep_write_srv > 0)
960 {
961 /* for replication test, need enable reconnect feature */
962 ms_setting.reconnect= true;
963 }
964
965 if (ms_setting.facebook_test && (ms_setting.mult_key_num < 2))
966 {
967 fprintf(stderr, "facebook test must work with multi-get, "
968 "please specify multi-get key number "
969 "with '--division' option.\n");
970 exit(1);
971 }
972
973 if (ms_setting.facebook_test && ms_setting.udp)
974 {
975 fprintf(stderr, "facebook test couldn't work with UDP.\n");
976 exit(1);
977 }
978
979 if (ms_setting.udp && (ms_setting.sock_per_conn > 1))
980 {
981 fprintf(stderr, "UDP doesn't support multi-socks "
982 "in one connection structure.\n");
983 exit(1);
984 }
985
986 if ((ms_setting.rep_write_srv > 0) && (ms_setting.srv_cnt < 2))
987 {
988 fprintf(stderr, "Please specify 2 servers at least for replication\n");
989 exit(1);
990 }
991
992 if ((ms_setting.rep_write_srv > 0)
993 && (ms_setting.srv_cnt < ms_setting.rep_write_srv))
994 {
995 fprintf(stderr, "Servers to do replication writing "
996 "is larger than the total servers\n");
997 exit(1);
998 }
999
1000 if (ms_setting.udp && (ms_setting.rep_write_srv > 0))
1001 {
1002 fprintf(stderr, "UDP doesn't support replication.\n");
1003 exit(1);
1004 }
1005
1006 if (ms_setting.facebook_test && (ms_setting.rep_write_srv > 0))
1007 {
1008 fprintf(stderr, "facebook test couldn't work with replication.\n");
1009 exit(1);
1010 }
1011
1012 ms_build_distr();
1013
1014 /* initialize global character block */
1015 ms_init_random_block();
1016 ms_print_setting();
1017 } /* ms_setting_slapmode_init_post */
1018
1019
1020 /**
1021 * post part of initialization of setting structure
1022 */
1023 void ms_setting_init_post()
1024 {
1025 ms_get_serverlist(ms_setting.srv_str);
1026 ms_setting_slapmode_init_post();
1027 }
1028
1029
1030 /**
1031 * clean up the global setting structure
1032 */
1033 void ms_setting_cleanup()
1034 {
1035 if (ms_setting.distr != NULL)
1036 {
1037 free(ms_setting.distr);
1038 }
1039
1040 if (ms_setting.char_block != NULL)
1041 {
1042 free(ms_setting.char_block);
1043 }
1044
1045 if (ms_setting.srv_str != NULL)
1046 {
1047 free(ms_setting.srv_str);
1048 }
1049
1050 if (ms_setting.cfg_file != NULL)
1051 {
1052 free(ms_setting.cfg_file);
1053 }
1054
1055 if (ms_setting.servers != NULL)
1056 {
1057 free(ms_setting.servers);
1058 }
1059
1060 if (ms_setting.key_distr != NULL)
1061 {
1062 free(ms_setting.key_distr);
1063 }
1064
1065 if (ms_setting.value_distr != NULL)
1066 {
1067 free(ms_setting.value_distr);
1068 }
1069 } /* ms_setting_cleanup */