#include "db_config.h"
#include "db_int.h"
#include "dbinc/lock.h"
#include "dbinc/log.h"
#include "dbinc/mp.h"
#include "dbinc/txn.h"
#include "dbinc/db_page.h"
#include "dbinc_auto/db_ext.h"
typedef enum {
CFG_INT,
CFG_LONG,
CFG_UINT,
CFG_2INT,
CFG_2UINT,
CFG_STRING
} __db_config_type;
typedef struct __db_config_desc {
char *name;
__db_config_type type;
int (*func)();
} CFG_DESC;
typedef int (*CFG_FUNC_STRING) __P((DB_ENV *, const char *));
typedef int (*CFG_FUNC_INT) __P((DB_ENV *, int));
typedef int (*CFG_FUNC_LONG) __P((DB_ENV *, long));
typedef int (*CFG_FUNC_UINT) __P((DB_ENV *, u_int32_t));
typedef int (*CFG_FUNC_2INT) __P((DB_ENV *, int, int));
typedef int (*CFG_FUNC_2UINT) __P((DB_ENV *, u_int32_t, u_int32_t));
static const CFG_DESC config_descs[] = {
{ "add_data_dir", CFG_STRING, __env_add_data_dir },
{ "db_data_dir", CFG_STRING, __env_set_data_dir },
{ "db_log_dir", CFG_STRING, __log_set_lg_dir },
{ "db_tmp_dir", CFG_STRING, __env_set_tmp_dir },
{ "mutex_set_align", CFG_UINT, __mutex_set_align },
{ "mutex_set_increment", CFG_UINT, __mutex_set_increment },
{ "mutex_set_init", CFG_UINT, __mutex_set_init },
{ "mutex_set_max", CFG_UINT, __mutex_set_max },
{ "mutex_set_tas_spins", CFG_UINT, __mutex_set_tas_spins },
{ "rep_set_clockskew", CFG_2UINT, __rep_set_clockskew },
{ "rep_set_limit", CFG_2UINT, __rep_set_limit },
{ "rep_set_nsites", CFG_UINT, __rep_set_nsites_pp },
{ "rep_set_priority", CFG_UINT, __rep_set_priority },
{ "rep_set_request", CFG_2UINT, __rep_set_request },
{ "set_cache_max", CFG_2UINT, __memp_set_cache_max },
{ "set_create_dir", CFG_STRING, __env_set_create_dir },
{ "set_data_dir", CFG_STRING, __env_set_data_dir },
{ "set_data_len", CFG_UINT, __env_set_data_len },
{ "set_intermediate_dir_mode",CFG_STRING, __env_set_intermediate_dir_mode },
{ "set_lg_bsize", CFG_UINT, __log_set_lg_bsize },
{ "set_lg_dir", CFG_STRING, __log_set_lg_dir },
{ "set_lg_filemode", CFG_INT, __log_set_lg_filemode },
{ "set_lg_max", CFG_UINT, __log_set_lg_max },
{ "set_lg_regionmax", CFG_UINT, __log_set_lg_regionmax },
{ "set_lk_max_lockers", CFG_UINT, __lock_set_lk_max_lockers },
{ "set_lk_max_locks", CFG_UINT, __lock_set_lk_max_locks },
{ "set_lk_max_objects", CFG_UINT, __lock_set_lk_max_objects },
{ "set_lk_partitions", CFG_UINT, __lock_set_lk_partitions },
{ "set_lk_tablesize", CFG_UINT, __lock_set_lk_tablesize },
{ "set_memory_max", CFG_2UINT, __env_set_memory_max },
{ "set_metadata_dir", CFG_STRING, __env_set_metadata_dir },
{ "set_mp_max_openfd", CFG_INT, __memp_set_mp_max_openfd },
{ "set_mp_max_write", CFG_2INT, __memp_set_mp_max_write },
{ "set_mp_mmapsize", CFG_UINT, __memp_set_mp_mmapsize },
{ "set_mp_mtxcount", CFG_UINT, __memp_set_mp_mtxcount },
{ "set_mp_pagesize", CFG_UINT, __memp_set_mp_pagesize },
{ "set_shm_key", CFG_LONG, __env_set_shm_key },
{ "set_tas_spins", CFG_UINT, __mutex_set_tas_spins },
{ "set_thread_count", CFG_UINT, __env_set_thread_count },
{ "set_tmp_dir", CFG_STRING, __env_set_tmp_dir },
{ "set_tx_max", CFG_UINT, __txn_set_tx_max }
};
static const FN config_mem_init[] = {
{ (u_int32_t) DB_MEM_LOCK, "DB_MEM_LOCK" },
{ (u_int32_t) DB_MEM_LOCKER, "DB_MEM_LOCKER" },
{ (u_int32_t) DB_MEM_LOCKOBJECT, "DB_MEM_LOCKOBJECT" },
{ (u_int32_t) DB_MEM_TRANSACTION, "DB_MEM_TRANSACTION" },
{ (u_int32_t) DB_MEM_THREAD, "DB_MEM_THREAD" },
{ (u_int32_t) DB_MEM_LOGID, "DB_MEM_LOGID" },
{ 0, NULL }
};
static const FN config_rep_config[] = {
{ DB_REP_CONF_AUTOINIT, "db_rep_conf_autoinit" },
{ DB_REP_CONF_AUTOROLLBACK, "db_rep_conf_autorollback" },
{ DB_REP_CONF_BULK, "db_rep_conf_bulk" },
{ DB_REP_CONF_DELAYCLIENT, "db_rep_conf_delayclient" },
{ DB_REP_CONF_INMEM, "db_rep_conf_inmem" },
{ DB_REP_CONF_LEASE, "db_rep_conf_lease" },
{ DB_REP_CONF_NOWAIT, "db_rep_conf_nowait" },
{ DB_REPMGR_CONF_2SITE_STRICT, "db_repmgr_conf_2site_strict" },
{ DB_REPMGR_CONF_ELECTIONS, "db_repmgr_conf_elections" },
{ 0, NULL }
};
static const FN config_rep_timeout[] = {
{ DB_REP_ACK_TIMEOUT, "db_rep_ack_timeout" },
{ DB_REP_CHECKPOINT_DELAY, "db_rep_checkpoint_delay" },
{ DB_REP_CONNECTION_RETRY, "db_rep_connection_retry" },
{ DB_REP_ELECTION_TIMEOUT, "db_rep_election_timeout" },
{ DB_REP_ELECTION_RETRY, "db_rep_election_retry" },
{ DB_REP_FULL_ELECTION_TIMEOUT, "db_rep_full_election_timeout" },
{ DB_REP_HEARTBEAT_MONITOR, "db_rep_heartbeat_monitor" },
{ DB_REP_HEARTBEAT_SEND, "db_rep_heartbeat_send" },
{ DB_REP_LEASE_TIMEOUT, "db_rep_lease_timeout" },
{ 0, NULL }
};
static const FN config_repmgr_ack_policy[] = {
{ DB_REPMGR_ACKS_ALL, "db_repmgr_acks_all" },
{ DB_REPMGR_ACKS_ALL_AVAILABLE, "db_repmgr_acks_all_available" },
{ DB_REPMGR_ACKS_ALL_PEERS, "db_repmgr_acks_all_peers" },
{ DB_REPMGR_ACKS_NONE, "db_repmgr_acks_none" },
{ DB_REPMGR_ACKS_ONE, "db_repmgr_acks_one" },
{ DB_REPMGR_ACKS_ONE_PEER, "db_repmgr_acks_one_peer" },
{ DB_REPMGR_ACKS_QUORUM, "db_repmgr_acks_quorum" },
{ 0, NULL }
};
static const FN config_repmgr_site[] = {
{ DB_BOOTSTRAP_HELPER, "db_bootstrap_helper" },
{ DB_GROUP_CREATOR, "db_group_creator" },
{ DB_LEGACY, "db_legacy" },
{ DB_LOCAL_SITE, "db_local_site" },
{ DB_REPMGR_PEER, "db_repmgr_peer" },
{ 0, NULL }
};
static const FN config_set_flags[] = {
{ DB_AUTO_COMMIT, "db_auto_commit" },
{ DB_CDB_ALLDB, "db_cdb_alldb" },
{ DB_DIRECT_DB, "db_direct_db" },
{ DB_DSYNC_DB, "db_dsync_db" },
{ DB_MULTIVERSION, "db_multiversion" },
{ DB_NOLOCKING, "db_nolocking" },
{ DB_NOMMAP, "db_nommap" },
{ DB_NOPANIC, "db_nopanic" },
{ DB_OVERWRITE, "db_overwrite" },
{ DB_REGION_INIT, "db_region_init" },
{ DB_TIME_NOTGRANTED, "db_time_notgranted" },
{ DB_TXN_NOSYNC, "db_txn_nosync" },
{ DB_TXN_NOWAIT, "db_txn_nowait" },
{ DB_TXN_SNAPSHOT, "db_txn_snapshot" },
{ DB_TXN_WRITE_NOSYNC, "db_txn_write_nosync" },
{ DB_YIELDCPU, "db_yieldcpu" },
{ 0, NULL }
};
static const FN config_set_flags_forlog[] = {
{ DB_LOG_DIRECT, "db_direct_log" },
{ DB_LOG_DSYNC, "db_dsync_log" },
{ DB_LOG_AUTO_REMOVE, "db_log_autoremove" },
{ DB_LOG_IN_MEMORY, "db_log_inmemory" },
{ 0, NULL }
};
static const FN config_log_set_config[] = {
{ DB_LOG_DIRECT, "db_log_direct" },
{ DB_LOG_DSYNC, "db_log_dsync" },
{ DB_LOG_AUTO_REMOVE, "db_log_auto_remove" },
{ DB_LOG_IN_MEMORY, "db_log_in_memory" },
{ DB_LOG_ZERO, "db_log_zero" },
{ 0, NULL }
};
static const FN config_set_lk_detect[] = {
{ DB_LOCK_DEFAULT, "db_lock_default" },
{ DB_LOCK_EXPIRE, "db_lock_expire" },
{ DB_LOCK_MAXLOCKS, "db_lock_maxlocks" },
{ DB_LOCK_MAXWRITE, "db_lock_maxwrite" },
{ DB_LOCK_MINLOCKS, "db_lock_minlocks" },
{ DB_LOCK_MINWRITE, "db_lock_minwrite" },
{ DB_LOCK_OLDEST, "db_lock_oldest" },
{ DB_LOCK_RANDOM, "db_lock_random" },
{ DB_LOCK_YOUNGEST, "db_lock_youngest" },
{ 0, NULL }
};
static const FN config_set_open_flags[] = {
{ DB_INIT_REP, "db_init_rep" },
{ DB_PRIVATE, "db_private" },
{ DB_REGISTER, "db_register" },
{ DB_THREAD, "db_thread" },
{ 0, NULL }
};
static const FN config_set_verbose[] = {
{ DB_VERB_BACKUP, "db_verb_backup" },
{ DB_VERB_DEADLOCK, "db_verb_deadlock" },
{ DB_VERB_FILEOPS, "db_verb_fileops" },
{ DB_VERB_FILEOPS_ALL, "db_verb_fileops_all" },
{ DB_VERB_RECOVERY, "db_verb_recovery" },
{ DB_VERB_REGISTER, "db_verb_register" },
{ DB_VERB_REPLICATION, "db_verb_replication" },
{ DB_VERB_REP_ELECT, "db_verb_rep_elect" },
{ DB_VERB_REP_LEASE, "db_verb_rep_lease" },
{ DB_VERB_REP_MISC, "db_verb_rep_misc" },
{ DB_VERB_REP_MSGS, "db_verb_rep_msgs" },
{ DB_VERB_REP_SYNC, "db_verb_rep_sync" },
{ DB_VERB_REP_SYSTEM, "db_verb_rep_system" },
{ DB_VERB_REP_TEST, "db_verb_rep_test" },
{ DB_VERB_REPMGR_CONNFAIL, "db_verb_repmgr_connfail" },
{ DB_VERB_REPMGR_MISC, "db_verb_repmgr_misc" },
{ DB_VERB_WAITSFOR, "db_verb_waitsfor" },
{ 0, NULL}
};
static int __config_parse __P((ENV *, char *, int));
static int __config_scan __P((char *, char **, const CFG_DESC **));
static int cmp_cfg_name __P((const void *, const void *element));
int
__env_read_db_config(env)
ENV *env;
{
FILE *fp;
int lc, ret;
char *p, buf[256];
p = NULL;
if ((ret = __db_appname(env,
DB_APP_NONE, "DB_CONFIG", NULL, &p)) != 0)
return (ret);
if (p == NULL)
fp = NULL;
else {
fp = fopen(p, "r");
__os_free(env, p);
}
if (fp == NULL)
return (0);
for (lc = 1; fgets(buf, sizeof(buf), fp) != NULL; ++lc) {
if ((p = strchr(buf, '\n')) == NULL)
p = buf + strlen(buf);
if (p > buf && p[-1] == '\r')
--p;
*p = '\0';
for (p = buf; *p != '\0' && isspace((int)*p); ++p)
;
if (*p == '\0' || *p == '#')
continue;
if ((ret = __config_parse(env, p, lc)) != 0)
break;
}
(void)fclose(fp);
return (ret);
}
#undef CFG_GET_INT
#define CFG_GET_INT(s, vp) do { \
int __ret; \
if ((__ret = \
__db_getlong(env->dbenv, NULL, s, 0, INT_MAX, vp)) != 0) \
return (__ret); \
} while (0)
#undef CFG_GET_LONG
#define CFG_GET_LONG(s, vp) do { \
int __ret; \
if ((__ret = \
__db_getlong(env->dbenv, NULL, s, 0, LONG_MAX, vp)) != 0) \
return (__ret); \
} while (0)
#undef CFG_GET_UINT
#define CFG_GET_UINT(s, vp) do { \
int __ret; \
if ((__ret = \
__db_getulong(env->dbenv, NULL, s, 0, UINT_MAX, vp)) != 0) \
return (__ret); \
} while (0)
#undef CFG_GET_UINT32
#define CFG_GET_UINT32(s, vp) do { \
if (__db_getulong(env->dbenv, NULL, s, 0, UINT32_MAX, vp) != 0) \
return (EINVAL); \
} while (0)
#undef CFG_SLOTS
#define CFG_SLOTS 10
static int
__config_parse(env, s, lc)
ENV *env;
char *s;
int lc;
{
DB_ENV *dbenv;
DB_SITE *site;
u_long uv1, uv2;
long lv1, lv2;
u_int port;
int i, nf, onoff, bad, ret, t_ret;
char *argv[CFG_SLOTS];
const CFG_DESC *desc;
bad = 0;
dbenv = env->dbenv;
if ((nf = __config_scan(s, argv, &desc)) < 2) {
format: __db_errx(env, DB_STR_A("1584",
"line %d: %s: incorrect name-value pair", "%d %s"),
lc, argv[0]);
return (EINVAL);
}
if (desc != NULL) {
ret = 0;
switch (desc->type) {
case CFG_INT:
if (nf != 2)
goto format;
CFG_GET_INT(argv[1], &lv1);
ret = ((CFG_FUNC_INT)desc->func)(dbenv, (int) lv1);
break;
case CFG_LONG:
if (nf != 2)
goto format;
CFG_GET_LONG(argv[1], &lv1);
ret = ((CFG_FUNC_LONG)desc->func)(dbenv, lv1);
break;
case CFG_UINT:
if (nf != 2)
goto format;
CFG_GET_UINT(argv[1], &uv1);
ret = ((CFG_FUNC_UINT)desc->func)
(dbenv, (u_int32_t) uv1);
break;
case CFG_2INT:
if (nf != 3)
goto format;
CFG_GET_INT(argv[1], &lv1);
CFG_GET_INT(argv[2], &lv2);
ret = ((CFG_FUNC_2INT)desc->func)
(dbenv, (int) lv1, (int) lv2);
break;
case CFG_2UINT:
if (nf != 3)
goto format;
CFG_GET_UINT(argv[1], &uv1);
CFG_GET_UINT(argv[2], &uv2);
ret = ((CFG_FUNC_2UINT)desc->func)
(dbenv, (u_int32_t) uv1, (u_int32_t) uv2);
break;
case CFG_STRING:
ret = ((CFG_FUNC_STRING) desc->func)(dbenv, argv[1]);
break;
}
return (ret);
}
if (strcasecmp(argv[0], "set_memory_init") == 0) {
if (nf != 3)
goto format;
if ((lv1 = __db_name_to_val(config_mem_init, argv[1])) == -1)
goto format;
CFG_GET_UINT32(argv[2], &uv2);
return (__env_set_memory_init(dbenv,
(DB_MEM_CONFIG) lv1, (u_int32_t)uv2));
}
if (strcasecmp(argv[0], "rep_set_config") == 0) {
if (nf != 2 && nf != 3)
goto format;
onoff = 1;
if (nf == 3) {
if (strcasecmp(argv[2], "off") == 0)
onoff = 0;
else if (strcasecmp(argv[2], "on") != 0)
goto format;
}
if ((lv1 = __db_name_to_val(config_rep_config, argv[1])) == -1)
goto format;
return (__rep_set_config(dbenv, (u_int32_t)lv1, onoff));
}
if (strcasecmp(argv[0], "rep_set_timeout") == 0) {
if (nf != 3)
goto format;
if ((lv1 = __db_name_to_val(config_rep_timeout, argv[1])) == -1)
goto format;
CFG_GET_UINT32(argv[2], &uv2);
return (__rep_set_timeout(dbenv, lv1, (db_timeout_t)uv2));
}
if (strcasecmp(argv[0], "repmgr_set_ack_policy") == 0) {
if (nf != 2)
goto format;
if ((lv1 =
__db_name_to_val(config_repmgr_ack_policy, argv[1])) == -1)
goto format;
return (__repmgr_set_ack_policy(dbenv, lv1));
}
if (strcasecmp(argv[0], "repmgr_site") == 0) {
if (nf < 3 || (nf % 2) == 0)
goto format;
CFG_GET_UINT(argv[2], &uv2);
port = (u_int)uv2;
if ((ret = __repmgr_site(dbenv, argv[1], port, &site, 0)) != 0)
return (ret);
#ifdef HAVE_REPLICATION_THREADS
for (i = 3; i < nf; i += 2) {
if ((lv1 = __db_name_to_val(
config_repmgr_site, argv[i])) == -1) {
bad = 1;
break;
}
if (strcasecmp(argv[i + 1], "on") == 0)
uv2 = 1;
else if (strcasecmp(argv[i + 1], "off") == 0)
uv2 = 0;
else
CFG_GET_UINT32(argv[i + 1], &uv2);
if ((ret = __repmgr_site_config(site,
(u_int32_t)lv1, (u_int32_t)uv2)) != 0)
break;
}
if ((t_ret = __repmgr_site_close(site)) != 0 && ret == 0)
ret = t_ret;
if (bad)
goto format;
#else
COMPQUIET(i, 0);
COMPQUIET(t_ret, 0);
DB_ASSERT(env, 0);
#endif
return (ret);
}
if (strcasecmp(argv[0], "set_cachesize") == 0) {
if (nf != 4)
goto format;
CFG_GET_UINT32(argv[1], &uv1);
CFG_GET_UINT32(argv[2], &uv2);
CFG_GET_INT(argv[3], &lv1);
return (__memp_set_cachesize(
dbenv, (u_int32_t)uv1, (u_int32_t)uv2, (int)lv1));
}
if (strcasecmp(argv[0], "set_intermediate_dir") == 0) {
if (nf != 2)
goto format;
CFG_GET_INT(argv[1], &lv1);
if (lv1 <= 0)
goto format;
env->dir_mode = (int)lv1;
return (0);
}
if (strcasecmp(argv[0], "set_flags") == 0) {
if (nf != 2 && nf != 3)
goto format;
onoff = 1;
if (nf == 3) {
if (strcasecmp(argv[2], "off") == 0)
onoff = 0;
else if (strcasecmp(argv[2], "on") != 0)
goto format;
}
if ((lv1 = __db_name_to_val(config_set_flags, argv[1])) != -1)
return (__env_set_flags(dbenv, (u_int32_t)lv1, onoff));
else if ((lv1 =
__db_name_to_val(config_set_flags_forlog, argv[1])) != -1)
return (__log_set_config(dbenv, (u_int32_t)lv1, onoff));
goto format;
}
if (strcasecmp(argv[0], "log_set_config") == 0) {
if (nf != 2 && nf != 3)
goto format;
onoff = 1;
if (nf == 3) {
if (strcasecmp(argv[2], "off") == 0)
onoff = 0;
else if (strcasecmp(argv[2], "on") != 0)
goto format;
}
if ((lv1 =
__db_name_to_val(config_log_set_config, argv[1])) == -1)
goto format;
return (__log_set_config(dbenv, (u_int32_t)lv1, onoff));
}
if (strcasecmp(argv[0], "set_lk_detect") == 0) {
if (nf != 2)
goto format;
if ((lv1 =
__db_name_to_val(config_set_lk_detect, argv[1])) == -1)
goto format;
return (__lock_set_lk_detect(dbenv, (u_int32_t)lv1));
}
if (strcasecmp(argv[0], "set_lock_timeout") == 0) {
if (nf != 2)
goto format;
CFG_GET_UINT32(argv[1], &uv1);
return (__lock_set_env_timeout(
dbenv, (u_int32_t)uv1, DB_SET_LOCK_TIMEOUT));
}
if (strcasecmp(argv[0], "set_open_flags") == 0) {
if (nf != 2 && nf != 3)
goto format;
onoff = 1;
if (nf == 3) {
if (strcasecmp(argv[2], "off") == 0)
onoff = 0;
else if (strcasecmp(argv[2], "on") != 0)
goto format;
}
if ((lv1 =
__db_name_to_val(config_set_open_flags, argv[1])) == -1)
goto format;
if (onoff == 1)
FLD_SET(env->open_flags, (u_int32_t)lv1);
else
FLD_CLR(env->open_flags, (u_int32_t)lv1);
return (0);
}
if (strcasecmp(argv[0], "set_region_init") == 0) {
if (nf != 2)
goto format;
CFG_GET_INT(argv[1], &lv1);
if (lv1 != 0 && lv1 != 1)
goto format;
return (__env_set_flags(
dbenv, DB_REGION_INIT, lv1 == 0 ? 0 : 1));
}
if (strcasecmp(argv[0], "set_reg_timeout") == 0) {
if (nf != 2)
goto format;
CFG_GET_UINT32(argv[1], &uv1);
return (__env_set_timeout(
dbenv, (u_int32_t)uv1, DB_SET_REG_TIMEOUT));
}
if (strcasecmp(argv[0], "set_txn_timeout") == 0) {
if (nf != 2)
goto format;
CFG_GET_UINT32(argv[1], &uv1);
return (__lock_set_env_timeout(
dbenv, (u_int32_t)uv1, DB_SET_TXN_TIMEOUT));
}
if (strcasecmp(argv[0], "set_verbose") == 0) {
if (nf != 2 && nf != 3)
goto format;
onoff = 1;
if (nf == 3) {
if (strcasecmp(argv[2], "off") == 0)
onoff = 0;
else if (strcasecmp(argv[2], "on") != 0)
goto format;
}
if ((lv1 = __db_name_to_val(config_set_verbose, argv[1])) == -1)
goto format;
return (__env_set_verbose(dbenv, (u_int32_t)lv1, onoff));
}
__db_errx(env,
DB_STR_A("1585", "unrecognized name-value pair: %s", "%s"), s);
return (EINVAL);
}
static int
cmp_cfg_name(sought, element)
const void *sought;
const void *element;
{
return
(strcmp((const char *) sought, ((const CFG_DESC *) element)->name));
}
static int
__config_scan(input, argv, descptr)
char *input, *argv[CFG_SLOTS];
const CFG_DESC **descptr;
{
size_t tablecount;
int count;
char **ap;
tablecount = sizeof(config_descs) / sizeof(config_descs[0]);
*descptr = NULL;
for (count = 0, ap = argv; (*ap = strsep(&input, " \t\n")) != NULL;) {
if (**ap == '\0')
continue;
count++;
ap++;
if (count == 1) {
*descptr = bsearch(argv[0], config_descs,
tablecount, sizeof(config_descs[0]), cmp_cfg_name);
if (*descptr != NULL &&
(*descptr)->type == CFG_STRING) {
count++;
while (isspace(*input))
input++;
*ap++ = input;
break;
}
}
if (count >= CFG_SLOTS)
break;
}
return (count);
}