/*------------------------------------------------------------------------- * * varibales.c * * Variable haneling module of Postgres-XC configuration and operation tool. * * * Copyright (c) 2013 Postgres-XC Development Group * *------------------------------------------------------------------------- */ #include #include #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; 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; 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; if ((rc = find_var(name))) return rc; return new_var(name); } void print_vars(void) { pgxc_ctl_var *cur; lockLogFile(); for(cur = var_head; cur; cur=cur->next) print_var(cur->varname); unlockLogFile(); } void print_var(char *vname) { pgxc_ctl_var *var; 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; 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; int ii; char *buf; 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; } /* * Extend the variable values array to newSize (plus 1 for store the * end-of-array marker */ int extendVar(char *name, int newSize, char *def_value) { pgxc_ctl_var *target; char **old_val; int old_size; int ii; if ((target = find_var(name)) == NULL) return -1; if (def_value == NULL) def_value = "none"; /* * If the allocated array is not already big enough to store newSize + 1 * elements, we must extend it newSize + 1 */ 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 + 1; Free(old_val); } for (ii = target->val_used; ii < newSize; ii++) (target->val)[ii] = Strdup(def_value); /* Store NULL in the last element to mark the end-of-array */ (target->val)[newSize] = NULL; if (target->val_used < newSize) 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_internal(char *name, int idx, char *val, char *pad, int extend) { pgxc_ctl_var *var = confirm_var(name); if (pad == NULL) pad = "none"; /* * Pad if needed */ if (extend) extendVar(name, idx+1, pad); Free(var->val[idx]); var->val[idx] = Strdup(val); } void assign_arrayEl(char *name, int idx, char *val, char *pad) { return assign_arrayEl_internal(name, idx, val, pad, TRUE); } void replace_arrayEl(char *name, int idx, char *val, char *pad) { return assign_arrayEl_internal(name, idx, val, pad, FALSE); } int doesExist(char *name, int idx) { pgxc_ctl_var *var; if (name == NULL) return 0; if ((var = find_var(name)) == NULL) return 0; if (var->val_used <= idx) return 0; return 1; }