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