/*
    +--------------------------------------------------------------------+
    | libmemcached-awesome - C/C++ Client Library for memcached          |
    +--------------------------------------------------------------------+
    | Redistribution and use in source and binary forms, with or without |
    | modification, are permitted under the terms of the BSD license.    |
    | You should have received a copy of the license in a bundled file   |
    | named LICENSE; in case you did not receive a copy you can review   |
    | the terms online at: https://opensource.org/licenses/BSD-3-Clause  |
    +--------------------------------------------------------------------+
    | Copyright (c) 2006-2014 Brian Aker   https://datadifferential.com/ |
    | Copyright (c) 2020 Michael Wallner   <mike@php.net>                |
    +--------------------------------------------------------------------+
*/

#ifndef MS_SETTING_H
#define MS_SETTING_H

#include "ms_memslap.h"

#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

#define MCD_SRVS_NUM_INIT      8
#define MCD_HOST_LENGTH        64
#define KEY_RANGE_COUNT_INIT   8
#define VALUE_RANGE_COUNT_INIT 8
#define PROP_ERROR             0.001

#define MIN_KEY_SIZE   16
#define MAX_KEY_SIZE   250
#define MAX_VALUE_SIZE (1024 * 1024)

/* the content of the configuration file for memslap running without configuration file */
#define DEFAULT_CONGIF_STR \
  "key\n" \
  "64 64 1\n" \
  "value\n" \
  "1024 1024 1\n" \
  "cmd\n" \
  "0 0.1\n" \
  "1 0.9"

/* Used to parse the value length return by server and path string */
typedef struct token_s {
  char *value;
  size_t length;
} token_t;

#define MAX_TOKENS 10

/* server information */
typedef struct mcd_server {
  char srv_host_name[MCD_HOST_LENGTH]; /* host name of server */
  int srv_port;                        /* server port */

  /* for calculating how long the server disconnects */
  ATOMIC uint32_t disconn_cnt; /* number of disconnections count */
  ATOMIC uint32_t reconn_cnt;  /* number of reconnections count */
  struct timeval disconn_time; /* start time of disconnection */
  struct timeval reconn_time;  /* end time of reconnection */
} ms_mcd_server_t;

/* information of an item distribution including key and value */
typedef struct distr {
  size_t key_size;   /* size of key */
  int key_offset;    /* offset of one key in character block */
  size_t value_size; /* size of value */
} ms_distr_t;

/* information of key distribution */
typedef struct key_distr {
  size_t start_len; /* start of the key length range */
  size_t end_len;   /* end of the key length range */
  double key_prop;  /* key proportion */
} ms_key_distr_t;

/* information of value distribution */
typedef struct value_distr {
  size_t start_len;  /* start of the value length range */
  size_t end_len;    /* end of the value length range */
  double value_prop; /* value proportion */
} ms_value_distr_t;

/* memcached command types */
typedef enum cmd_type { CMD_SET, CMD_GET, CMD_NULL } ms_cmd_type_t;

/* types in the configuration file */
typedef enum conf_type { CONF_KEY, CONF_VALUE, CONF_CMD, CONF_NULL } ms_conf_type_t;

/* information of command distribution */
typedef struct cmd_distr {
  ms_cmd_type_t cmd_type; /* command type */
  double cmd_prop;        /* proportion of the command */
} ms_cmd_distr_t;

/* global setting structure */
typedef struct setting {
  uint32_t ncpu;     /* cpu count of this system */
  uint32_t nthreads; /* total thread count, must equal or less than cpu cores */
  uint32_t nconns;   /* total conn count, must multiply by total thread count */
  int64_t exec_num;  /* total execute number */
  int run_time;      /* total run time */

  uint32_t char_blk_size; /* global character block size */
  char *char_block;       /* global character block with random character */
  ms_distr_t *distr;      /* distribution from configure file */

  char *srv_str;  /* string includes servers information */
  char *cfg_file; /* configure file name */

  ms_mcd_server_t *servers; /* servers array */
  uint32_t total_srv_cnt;   /* total servers count of the servers array */
  uint32_t srv_cnt;         /* servers count */

  ms_key_distr_t *key_distr; /* array of key distribution */
  int total_key_rng_cnt;     /* total key range count of the array */
  int key_rng_cnt;           /* actual key range count */

  ms_value_distr_t *value_distr; /* array of value distribution */
  int total_val_rng_cnt;         /* total value range count of the array */
  int val_rng_cnt;               /* actual value range count */

  ms_cmd_distr_t cmd_distr[CMD_NULL]; /* total we have CMD_NULL commands */
  int cmd_used_count;                 /* supported command count */

  size_t fixed_value_size; /* fixed value size */
  size_t avg_val_size;     /* average value size */
  size_t avg_key_size;     /* average value size */

  double verify_percent;    /* percent of data verification */
  double exp_ver_per;       /* percent of data verification with expire time */
  double overwrite_percent; /* percent of overwrite */
  int mult_key_num;         /* number of keys used by multi-get once */
  size_t win_size;          /* item window size per connection */
  bool udp;                 /* whether or not use UDP */
  int stat_freq;            /* statistic frequency second */
  bool reconnect;           /* whether it reconnect when connection close */
  bool verbose;             /* whether it outputs detailed information when verification */
  bool facebook_test;       /* facebook test, TCP set and multi-get with UDP */
  uint32_t sock_per_conn;   /* number of socks per connection structure */
  bool binary_prot_;        /* whether it use binary protocol */
  int expected_tps;         /* expected throughput */
  uint32_t rep_write_srv;   /* which servers are used to do replication writing */
} ms_setting_st;

extern ms_setting_st ms_setting;

/* previous part of initialization of setting structure */
void ms_setting_init_pre(void);

/* post part of initialization of setting structure */
void ms_setting_init_post(void);

/* clean up the global setting structure */
void ms_setting_cleanup(void);

#define UNUSED_ARGUMENT(x) (void) x

#ifdef __cplusplus
}
#endif

#endif /* end of MS_SETTING_H */
