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