426 lines
9.2 KiB
C++
426 lines
9.2 KiB
C++
/*-------------------------------------------------------------------------
|
|
*
|
|
* varibales.c
|
|
*
|
|
* Variable haneling module of Postgres-XC configuration and operation tool.
|
|
*
|
|
*
|
|
* Copyright (c) 2013 Postgres-XC Development Group
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "variables.h"
|
|
#include "utils.h"
|
|
#include "pgxc_ctl_log.h"
|
|
|
|
pgxc_ctl_var* var_head = NULL;
|
|
pgxc_ctl_var* var_tail = NULL;
|
|
|
|
static void clear_var(pgxc_ctl_var* var);
|
|
/*
|
|
* Hash bucket size is up to 256
|
|
*/
|
|
static int hash_val(char* name)
|
|
{
|
|
unsigned char* name_u = (unsigned char*)name;
|
|
unsigned char v;
|
|
|
|
for (v = 0; *name_u; name_u++)
|
|
v += *name_u;
|
|
return (v % NUM_HASH_BUCKET);
|
|
}
|
|
|
|
#define LIMIT_TO_DOUBLE 128
|
|
#define INCR_OVER_DOUBLE 10
|
|
static int next_size(int sz)
|
|
{
|
|
if (sz <= 0)
|
|
return 1;
|
|
if (sz <= LIMIT_TO_DOUBLE)
|
|
return sz * 2;
|
|
else
|
|
return sz + INCR_OVER_DOUBLE;
|
|
}
|
|
|
|
void init_var_hash()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_HASH_BUCKET; i++) {
|
|
var_hash[i].el_size = 1;
|
|
var_hash[i].el_used = 0;
|
|
var_hash[i].el = (pgxc_ctl_var**)Malloc(sizeof(pgxc_ctl_var*));
|
|
var_hash[i].el[0] = NULL;
|
|
}
|
|
}
|
|
|
|
static void remove_from_hash(pgxc_ctl_var* var)
|
|
{
|
|
int hash_v = hash_val(var->varname);
|
|
int ii, jj;
|
|
|
|
for (ii = 0; var_hash[hash_v].el[ii]; ii++) {
|
|
if (var_hash[hash_v].el[ii] != var)
|
|
continue;
|
|
else {
|
|
for (jj = ii; var_hash[hash_v].el[jj]; jj++)
|
|
var_hash[hash_v].el[jj] = var_hash[hash_v].el[jj + 1];
|
|
var_hash[hash_v].el_used--;
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void add_var_hash(pgxc_ctl_var* var)
|
|
{
|
|
int hash_v = hash_val(var->varname);
|
|
if (var_hash[hash_v].el_used + 1 >= var_hash[hash_v].el_size) {
|
|
var_hash[hash_v].el_size = next_size(var_hash[hash_v].el_size);
|
|
var_hash[hash_v].el =
|
|
(pgxc_ctl_var**)Realloc(var_hash[hash_v].el, sizeof(pgxc_ctl_var*) * var_hash[hash_v].el_size);
|
|
}
|
|
var_hash[hash_v].el[var_hash[hash_v].el_used++] = var;
|
|
var_hash[hash_v].el[var_hash[hash_v].el_used] = NULL;
|
|
}
|
|
|
|
pgxc_ctl_var* new_var(char* name)
|
|
{
|
|
pgxc_ctl_var* newv = NULL;
|
|
|
|
if (find_var(name)) {
|
|
elog(ERROR, "ERROR: Variable %s already defined. Check your configuration.\n", name);
|
|
return NULL;
|
|
}
|
|
|
|
newv = (pgxc_ctl_var*)Malloc(sizeof(pgxc_ctl_var));
|
|
if (var_head == NULL) {
|
|
var_head = var_tail = newv;
|
|
newv->prev = NULL;
|
|
} else {
|
|
newv->prev = var_tail;
|
|
var_tail->next = newv;
|
|
var_tail = newv;
|
|
}
|
|
newv->next = NULL;
|
|
newv->varname = Strdup(name);
|
|
newv->val_size = 1;
|
|
newv->val_used = 0;
|
|
newv->val = (char**)Malloc(sizeof(char*));
|
|
newv->val[0] = NULL;
|
|
add_var_hash(newv);
|
|
return (newv);
|
|
}
|
|
|
|
void remove_var(pgxc_ctl_var* var)
|
|
{
|
|
if ((var_head == var_tail) && (var_head == var))
|
|
var_head = var_tail = NULL;
|
|
else if (var_head == var) {
|
|
var_head = var_head->next;
|
|
var_head->prev = NULL;
|
|
} else if (var_tail == var) {
|
|
var_tail->next = NULL;
|
|
var_tail = var_tail->prev;
|
|
} else {
|
|
var->prev->next = var->next;
|
|
var->next->prev = var->prev;
|
|
}
|
|
clear_var(var);
|
|
}
|
|
|
|
static void clear_var(pgxc_ctl_var* var)
|
|
{
|
|
int ii;
|
|
|
|
remove_from_hash(var);
|
|
for (ii = 0; var->val[ii]; ii++)
|
|
free(var->val[ii]);
|
|
free(var->varname);
|
|
free(var);
|
|
}
|
|
|
|
void add_val(pgxc_ctl_var* var, char* val)
|
|
{
|
|
if (var->val_size <= var->val_used + 1) {
|
|
var->val_size = next_size(var->val_size);
|
|
var->val = (char**)Realloc(var->val, sizeof(char*) * var->val_size);
|
|
}
|
|
var->val[var->val_used++] = Strdup(val);
|
|
var->val[var->val_used] = NULL;
|
|
}
|
|
|
|
void add_val_name(char* name, char* val)
|
|
{
|
|
pgxc_ctl_var* var = NULL;
|
|
if (!(var = find_var(name)))
|
|
return;
|
|
add_val(var, name);
|
|
return;
|
|
}
|
|
|
|
pgxc_ctl_var* find_var(char* name)
|
|
{
|
|
pgxc_var_hash* hash = &var_hash[hash_val(name)];
|
|
int i;
|
|
|
|
for (i = 0; i < hash->el_used; i++) {
|
|
if (strcmp(hash->el[i]->varname, name) == 0)
|
|
return hash->el[i];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
char* sval(char* name)
|
|
{
|
|
pgxc_ctl_var* var = find_var(name);
|
|
if (!var)
|
|
return NULL;
|
|
return var->val[0];
|
|
}
|
|
|
|
char** aval(char* name)
|
|
{
|
|
pgxc_ctl_var* var = find_var(name);
|
|
if (!var)
|
|
return NULL;
|
|
return var->val;
|
|
}
|
|
|
|
void reset_value(pgxc_ctl_var* var)
|
|
{
|
|
int i;
|
|
for (i = 0; var->val[i]; i++) {
|
|
Free(var->val[i]);
|
|
var->val[i] = NULL;
|
|
}
|
|
var->val_used = 0;
|
|
}
|
|
|
|
void assign_val(char* destName, char* srcName)
|
|
{
|
|
pgxc_ctl_var* dest = find_var(destName);
|
|
pgxc_ctl_var* src = find_var(srcName);
|
|
int ii;
|
|
|
|
reset_value(dest);
|
|
for (ii = 0; ii < src->val_used; ii++)
|
|
add_val(dest, src->val[ii]);
|
|
}
|
|
|
|
void assign_sval(char* destName, char* val)
|
|
{
|
|
pgxc_ctl_var* dest = find_var(destName);
|
|
|
|
reset_value(dest);
|
|
add_val(dest, val);
|
|
}
|
|
|
|
void reset_var(char* name)
|
|
{
|
|
confirm_var(name);
|
|
reset_value(find_var(name));
|
|
}
|
|
|
|
void reset_var_val(char* name, char* val)
|
|
{
|
|
reset_var(name);
|
|
add_val(find_var(name), val);
|
|
}
|
|
|
|
pgxc_ctl_var* confirm_var(char* name)
|
|
{
|
|
pgxc_ctl_var* rc = NULL;
|
|
if ((rc = find_var(name)))
|
|
return rc;
|
|
return new_var(name);
|
|
}
|
|
|
|
void print_vars(void)
|
|
{
|
|
pgxc_ctl_var* cur = NULL;
|
|
|
|
lockLogFile();
|
|
for (cur = var_head; cur; cur = cur->next)
|
|
print_var(cur->varname);
|
|
unlockLogFile();
|
|
}
|
|
|
|
void print_var(char* vname)
|
|
{
|
|
pgxc_ctl_var* var = NULL;
|
|
char outBuf[MAXLINE + 1];
|
|
|
|
outBuf[0] = 0;
|
|
if ((var = find_var(vname)) == NULL) {
|
|
elog(ERROR, "ERROR: Variable %s not found.\n", vname);
|
|
return;
|
|
} else {
|
|
char** curv;
|
|
char editbuf[MAXPATH];
|
|
|
|
snprintf(editbuf, MAXPATH, "%s (", vname);
|
|
strncat(outBuf, editbuf, MAXLINE);
|
|
for (curv = var->val; *curv; curv++) {
|
|
snprintf(editbuf, MAXPATH, " \"%s\" ", *curv);
|
|
strncat(outBuf, editbuf, MAXLINE);
|
|
}
|
|
strncat(outBuf, ")", MAXLINE);
|
|
elog(NOTICE, "%s\n", outBuf);
|
|
}
|
|
}
|
|
|
|
void log_var(char* varname)
|
|
{
|
|
if (logFile)
|
|
print_var(varname);
|
|
}
|
|
|
|
int arraySizeName(char* name)
|
|
{
|
|
pgxc_ctl_var* var = NULL;
|
|
|
|
if ((var = find_var(name)) == NULL)
|
|
return -1;
|
|
return (arraySize(var));
|
|
}
|
|
|
|
int arraySize(pgxc_ctl_var* var)
|
|
{
|
|
return var->val_used;
|
|
}
|
|
|
|
char** add_member(char** array, char* val)
|
|
{
|
|
char** rv;
|
|
int ii;
|
|
|
|
for (ii = 0; array[ii]; ii++)
|
|
;
|
|
rv = Realloc(array, sizeof(char*) * (ii + 2));
|
|
rv[ii] = Strdup(val);
|
|
rv[ii + 1] = NULL;
|
|
return (rv);
|
|
}
|
|
|
|
void clean_array(char** array)
|
|
{
|
|
int ii;
|
|
if (array) {
|
|
for (ii = 0; array[ii]; ii++)
|
|
Free(array[ii]);
|
|
Free(array);
|
|
}
|
|
}
|
|
|
|
void var_assign(char** dest, char* src)
|
|
{
|
|
Free(*dest);
|
|
*dest = src;
|
|
}
|
|
|
|
char* listValue(char* name)
|
|
{
|
|
pgxc_ctl_var* dest = NULL;
|
|
int ii;
|
|
char* buf = NULL;
|
|
|
|
if ((dest = find_var(name)) == NULL)
|
|
return Strdup("");
|
|
buf = Malloc(MAXLINE + 1);
|
|
buf[0] = 0;
|
|
for (ii = 0; ii < dest->val_used; ii++) {
|
|
strncat(buf, dest->val[ii], MAXLINE);
|
|
strncat(buf, " ", MAXLINE);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
int ifExists(char* name, char* value)
|
|
{
|
|
pgxc_ctl_var* var = find_var(name);
|
|
int ii;
|
|
|
|
if (!var)
|
|
return FALSE;
|
|
for (ii = 0; ii < var->val_used; ii++)
|
|
if (strcmp((var->val)[ii], value) == 0)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
int IfExists(char* name, char* value)
|
|
{
|
|
pgxc_ctl_var* var = find_var(name);
|
|
int ii;
|
|
|
|
if (!var)
|
|
return FALSE;
|
|
for (ii = 0; ii < var->val_used; ii++)
|
|
if (strcasecmp((var->val)[ii], value) == 0)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
int extendVar(char* name, int newSize, char* def_value)
|
|
{
|
|
pgxc_ctl_var* target = NULL;
|
|
char** old_val;
|
|
int old_size;
|
|
int ii;
|
|
|
|
if ((target = find_var(name)) == NULL)
|
|
return -1;
|
|
if (def_value == NULL)
|
|
def_value = "none";
|
|
if (target->val_size < newSize) {
|
|
old_val = target->val;
|
|
old_size = target->val_size;
|
|
target->val = Malloc0(sizeof(char*) * (newSize + 1));
|
|
memcpy(target->val, old_val, sizeof(char*) * old_size);
|
|
target->val_size = newSize;
|
|
Free(old_val);
|
|
for (ii = target->val_used; ii < newSize; ii++)
|
|
(target->val)[ii] = Strdup(def_value);
|
|
target->val_used = newSize;
|
|
} else if (target->val_used < newSize) {
|
|
for (ii = target->val_used; ii < newSize; ii++)
|
|
(target->val)[ii] = Strdup(def_value);
|
|
target->val_used = newSize;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* If pad is NULL, then "none" will be padded.
|
|
* Returns *val if success, NULL if failed
|
|
*/
|
|
void assign_arrayEl(char* name, int idx, char* val, char* pad)
|
|
{
|
|
pgxc_ctl_var* var = confirm_var(name);
|
|
|
|
if (pad == NULL)
|
|
pad = "none";
|
|
/*
|
|
* Pad if needed
|
|
*/
|
|
extendVar(name, idx + 1, pad);
|
|
Free(var->val[idx]);
|
|
var->val[idx] = Strdup(val);
|
|
}
|
|
|
|
int doesExist(char* name, int idx)
|
|
{
|
|
pgxc_ctl_var* var = NULL;
|
|
|
|
if (name == NULL)
|
|
return 0;
|
|
if ((var = find_var(name)) == NULL)
|
|
return 0;
|
|
if (var->val_used <= idx)
|
|
return 0;
|
|
return 1;
|
|
}
|