* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* ---------------------------------------------------------------------------------------
*
* cluster_guc.cpp
* Interfaces for analysis manager of PDK tool.
*
* Function List: execute_guc_command_in_remote_node
* form_commandline_options
* get_instance_type
* process_cluster_guc_option
* validate_cluster_guc_options
*
* IDENTIFICATION
* src/bin/gs_guc/cluster_guc.cpp
*
* ---------------------------------------------------------------------------------------
*/
#include "postgres_fe.h"
#include "libpq/libpq-fe.h"
#include "bin/elog.h"
#include "pg_config.h"
#include "common/config/cm_config.h"
#include <limits.h>
#include <fcntl.h>
#include <sys/sysinfo.h>
const int CLUSTER_CONFIG_SUCCESS = 0;
const int CLUSTER_CONFIG_ERROR = 1;
#define LOOP_COUNT 3
#define DOUBLE_PRECISE 0.000000001
#define MAX_HOST_NAME_LENGTH 255
#define LARGE_INSTANCE_NUM 2
#define CM_NODE_NAME_LEN 64
#define STATIC_CONFIG_FILE "cluster_static_config"
#define SSH_OPTIONS \
"-o BatchMode=yes -o TCPKeepAlive=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=4 -o ConnectTimeout=5 -o " \
"ConnectionAttempts=6"
#define GS_FREE(ptr) \
do { \
if (NULL != (ptr)) { \
free((char*)(ptr)); \
ptr = NULL; \
} \
} while (0)
#define PROCESS_STATUS(status) \
do { \
if (status == OUT_OF_MEMORY) { \
write_stderr("Failed: out of memory\n"); \
exit(1); \
} \
if (status == OPEN_FILE_ERROR) { \
write_stderr("Failed: cannot find the expected data dir\n"); \
exit(1); \
} \
} while (0)
const int GTM_INSTANCE_LEN = 3;
const int CN_INSTANCE_LEN = 7;
const int DN_INSTANCE_LEN = 12;
extern char** config_param;
extern char** config_value;
extern int config_param_number;
extern bool is_hba_conf;
extern int node_type_number;
extern bool g_need_changed;
extern char* g_local_instance_path;
typedef struct {
char** nodename_array;
char** gucinfo_array;
char** paramname_array;
char** paramvalue_array;
uint32 nodename_num;
uint32 gucinfo_num;
uint32 paramname_num;
uint32 paramvalue_num;
} gucInfo;
typedef struct {
char** nodename_array;
uint32 num;
} nodeInfo;
#define MAX_P_READ_BUF 1024
typedef struct tag_pcommand {
FILE* pfp;
char readbuf[MAX_P_READ_BUF];
int cur_buf_loc;
char* nodename;
int retvalue;
} PARALLEL_COMMAND_S;
PARALLEL_COMMAND_S* g_parallel_command_cxt = NULL;
static int g_max_commands_parallel = 0;
static int g_cur_commands_parallel = 0;
extern gucInfo* g_real_gucInfo;
extern gucInfo* g_expect_gucInfo;
extern char gucconf_file[MAXPGPATH];
extern int config_param_number;
extern char** config_param;
extern char** config_value;
extern int config_param_number;
extern int cndn_param_number;
extern int cmserver_param_number;
extern int cmagent_param_number;
extern int gtm_param_number;
extern int lc_param_number;
extern int config_value_number;
extern int node_type_number;
extern int arraysize;
extern char** cndn_param;
extern char** gtm_param;
extern char** cmserver_param;
extern char** cmagent_param;
extern char** lc_param;
extern char** cndn_guc_info;
extern char** cmserver_guc_info;
extern char** cmagent_guc_info;
extern char** gtm_guc_info;
extern char** lc_guc_info;
extern const char* progname;
extern bool g_remote_connection_signal;
extern unsigned int g_remote_command_result;
extern nodeInfo* g_incorrect_nodeInfo;
extern nodeInfo* g_ignore_nodeInfo;
typedef enum {
NO_COMMAND = 0,
SET_CONF_COMMAND,
RELOAD_CONF_COMMAND,
ENCRYPT_KEY_COMMAND,
CHECK_CONF_COMMAND
} CtlCommand;
extern CtlCommand ctl_command;
typedef enum {
INSTANCE_ANY,
INSTANCE_DATANODE,
INSTANCE_COORDINATOR,
INSTANCE_GTM,
INSTANCE_GTM_PROXY,
INSTANCE_CMAGENT,
INSTANCE_CMSERVER,
} NodeType;
const int KB_PER_MB = 1024;
#define KB_PER_GB (1024 * 1024)
const int MB_PER_GB = 1024;
#define MS_PER_S 1000
#define MS_PER_MIN (1000 * 60)
#define MS_PER_H (1000 * 60 * 60)
#define MS_PER_D (1000 * 60 * 60 * 24)
#define S_PER_MIN 60
#define S_PER_H (60 * 60)
#define S_PER_D (60 * 60 * 24)
#define MIN_PER_H 60
#define MIN_PER_D (60 * 24)
#define H_PER_D 24
#define SUCCESS 0
#define FAILURE 1
#define MAX_LINE_LEN 8192
#define MAX_MESG_LEN 4096
#define MAX_PARAM_LEN 1024
#define MAX_VALUE_LEN 1024
#define MAX_UNIT_LEN 8
#define MAX_INSTANCENAME_LEN 128
#define MIN_QUOTED_VALUE_LEN 2
#define DECIMAL_BASE 10
#define DMS_SHM_UB_CPU_BIND_EXPAND_CAP 256
#define DMS_SHM_UB_CPU_BIND_INNER_MAX 512
#define GUC_OPT_CONF_FILE "cluster_guc.conf"
bool is_disable_log_directory = false;
type about all guc options
*/
typedef enum { GUC_ERROR = -1, GUC_NAME, GUC_TYPE, GUC_VALUE, GUC_MESG } OptType;
*********************************************
parameters value support units
*********************************************
* type_name units_type numbers
*********************************************
* real units_d 3
* integer units_kB 26
* integer units_MB 3
* integer units_ms 9
* integer units_s 19
* integer units_min 4
* integer units_d 1
*********************************************
*/
typedef enum { UNIT_ERROR = -1, UNIT_KB, UNIT_MB, UNIT_GB, UNIT_MS, UNIT_S, UNIT_MIN, UNIT_H, UNIT_D } UnitType;
typedef enum {
GUC_PARA_ERROR = -1,
GUC_PARA_BOOL,
GUC_PARA_ENUM,
GUC_PARA_INT,
GUC_PARA_INT64,
GUC_PARA_REAL,
GUC_PARA_STRING
} GucParaType;
struct guc_config_enum_entry {
char guc_name[MAX_PARAM_LEN];
GucParaType type;
char guc_value[MAX_VALUE_LEN];
char guc_unit[MAX_UNIT_LEN];
char message[MAX_MESG_LEN];
};
struct guc_minmax_value {
char min_val_str[MAX_VALUE_LEN];
char max_val_str[MAX_VALUE_LEN];
};
const char* guc_bool_valuelist[] = {
"true",
"false",
"on",
"off",
"yes",
"no",
"0",
"1",
};
const char *value_type_list[] = {
"boolean",
"enum",
"integer",
"real",
"string",
};
const char* unit_eight_kB_parameter_list[] = {
"backwrite_quantity",
"effective_cache_size",
"pca_shared_buffers",
"prefetch_quantity",
"segment_size",
"shared_buffers",
"clog_buffers",
"csnlog_buffers",
"temp_buffers",
"wal_buffers",
"wal_segment_size",
"huge_page_size",
"heap_bulk_read_size",
"vacuum_bulk_read_size",
"max_smb_memory"
};
#define PAGE_SIZE 8
int process_guc_command(const char* datadir);
void do_checkvalidate(int type);
void get_instance_configfile(const char* datadir);
char* get_ctl_command_type();
void* pg_malloc(size_t size);
void* pg_malloc_zero(size_t size);
#ifdef __cplusplus
extern "C" {
#endif
int execute_guc_command_in_remote_node(int idx, char* command);
static char* form_commandline_options(const char* instance_name, const char* indatadir, bool local_mode);
uint32 get_num_nodes();
uint32 get_local_num_datanode();
bool is_local_nodeid(uint32 nodeid);
bool is_local_node(char* nodename);
int32 get_nodeidx_by_name(char* nodename);
int get_local_dbpath_by_instancename(const char* instancename, int* type, char* dbpath);
int init_gauss_cluster_config(void);
extern NodeType nodetype;
char* getnodename(uint32 nodeidx);
bool get_hostname_or_ip(char* out_name, size_t name_len);
int32 get_local_instancename_by_dbpath(char* dbpath, char* instancename);
char* xstrdup(const char* s);
char** readfile(const char* path, int reserve_num_lines);
void freefile(char** lines);
bool get_env_value(const char* env_var, char* output_env_value, size_t env_var_value_len);
int get_all_datanode_num();
int get_all_coordinator_num();
int get_all_cmserver_num();
int get_all_cmagent_num();
int get_all_cndn_num();
int get_all_gtm_num();
char* get_AZ_value(const char* value, const char* data_dir);
char* get_AZname_by_nodename(char* nodename);
void make_string_tolower(const char* source, char* dest, const int destlen);
void save_expect_instance_info(const char* datadir);
void save_remote_instance_info(
const char* result_file, const char* nodename, char* command, gucInfo* guc_info, bool isRealGucInfo);
void do_local_instance(int type, char* instance_name, char* indatadir);
void do_remote_instance(char* nodename, const char* instance_name, const char* indatadir);
void do_all_nodes_instance(const char* instance_name, const char* indatadir);
void check_env_value(const char* input_env_value);
GucParaType get_guc_type(const char* type);
UnitType get_guc_unit(const char* unit);
int do_local_para_value_change(int type, char* datadir);
int do_local_guc_command(int type, char* temp_datadir);
char** get_guc_option();
int do_gucopt_parse(const char* guc_opt, struct guc_config_enum_entry& guc_variable_list);
int check_parameter(int type);
int check_parameter_value(
const char* paraname, GucParaType type, char* guc_list_value, const char* guc_list_unit, const char* value);
int check_parameter_name(char** guc_opt, int type);
bool check_parameter_is_valid(int type);
int parse_value(const char* paraname, const char* value, const char* guc_list_unit, int64* result_int,
double* result_double, bool isInt);
int get_guc_minmax_value(const char* guc_list_val, struct guc_minmax_value& value_list);
int check_int_real_type_value(
const char* paraname, const char* guc_list_value, const char* guc_list_unit, const char* value, bool isInt);
int check_enum_type_value(const char* paraname, char* guc_list_value, const char* value);
int check_bool_type_value(const char* value);
int check_string_type_value(const char* paraname, const char* value);
void do_command_for_cn_gtm(int type, char* indatadir, bool isCoordinator);
void do_command_for_dn(int type, char* indatadir);
void do_command_for_cm(int type, char* indatadir);
void do_command_for_cndn(int type, char* indatadir);
char *get_cm_real_path(int type);
void create_tmp_dir(const char* pathdir);
void remove_tmp_dir(const char* pathdir);
bool is_record(int type, char* flag_str);
bool compare_str(char* src_str, char* start_str, char* end_str);
void do_command_with_instance_name_option_local(int type, char* instance_name);
void do_remote_instance_local(char* nodename, const char* instance_name, const char* indatadir);
void do_all_nodes_instance_local(const char* instance_name, const char* indatadir);
void do_all_nodes_instance_local_in_serial(const char* instance_name, const char* indatadir);
void do_all_nodes_instance_local_in_parallel(const char* instance_name, const char* indatadir);
char** get_guc_line_info(const char** line);
static char* GetEnvStr(const char* env);
static void executePopenCommandsParallel(const char* cmd, int idx, bool is_local_node);
static void readPopenOutputParallel(const char* cmd, bool if_for_all_instance);
static void SleepInMilliSec(uint32_t sleepMs);
static void init_global_command();
static void reset_global_command();
static void do_all_nodes_instance_local_in_parallel_loop(const char* instance_name, const char* indatadir);
Function : xstrdup
Description :
Input :
Output : src string
Return : dest string
*****************************************************************************
*/
char* xstrdup(const char* s)
{
char* result = NULL;
result = strdup(s);
if (NULL == result) {
(void)write_stderr(_("%s: out of memory\n"), "gs_guc");
exit(1);
}
return result;
}
******************************************************************************
Function : make_string_tolower
Description : copy source to dest, and make all alpha about dest to lower.
Input : source -- source string
dest -- dest string
Output : void
Return : void
*****************************************************************************
*/
void make_string_tolower(const char* source, char* dest, const int destlen)
{
int i = 0;
int len = (int)strlen(source);
if (len > destlen) {
len = destlen;
}
for (i = 0; i < len; i++)
dest[i] = tolower(source[i]);
dest[i] = '\0';
}
******************************************************************************
Function : get_instance_type
Description :
Input :
Output : None
Return : None
******************************************************************************
*/
const char* get_instance_type()
{
char* type = NULL;
switch (nodetype) {
case INSTANCE_COORDINATOR: {
type = "-Z coordinator";
break;
}
case INSTANCE_DATANODE: {
#ifdef ENABLE_MULTIPLE_NODES
type = "-Z datanode";
#else
type = "";
#endif
break;
}
case INSTANCE_CMSERVER: {
type = "-Z cmserver";
break;
}
case INSTANCE_CMAGENT: {
type = "-Z cmagent";
break;
}
case INSTANCE_GTM: {
type = "-Z gtm";
break;
}
default: {
type = "";
break;
}
}
return (const char*)type;
}
******************************************************************************
Function : modify_parameter_value
Description : If parameter value have the special character '$', when do remote setting
we should changed the parameter value first.
Input : value parameter value
: localMode do it on local node
Return : char *
Warning : this function will malloc a buffer for returned value, and won't free in this function.
so the caller should free this buffer after use this function's returned value.
******************************************************************************
*/
char* modify_parameter_value(const char* value, bool localMode)
{
int i = 0;
int j = 0;
int k = 0;
int backslash_num = 0;
const int local_backslash_num = 1;
const int remote_backslash_num = 3;
char* buffer = (char*)pg_malloc_zero(MAX_VALUE_LEN * sizeof(char));
for (i = 0, j = 0; i < (int)strlen(value) && j < MAX_VALUE_LEN; i++, j++) {
if (value[i] == '$') {
* If value have the special character '$', adding backslash before '$' is different between local
* command and remote command. when do remote setting, the commands like this: remote command: ssh -n
* nodename "gs_guc set -Z datanode -I all -c \"dynamic_library_path='\\\$libdir/xxx'\"" local command:
* gs_guc set -Z datanode -I all -c \"dynamic_library_path='\$libdir/xxx'\""
*/
backslash_num = localMode ? local_backslash_num : remote_backslash_num;
for (k = 0; k < backslash_num && j < MAX_VALUE_LEN; k++) {
buffer[j] = '\\';
j++;
}
if (j >= MAX_VALUE_LEN) {
write_stderr(_("%s: out of memory\n"), progname);
exit(1);
}
buffer[j] = value[i];
} else {
buffer[j] = value[i];
}
}
return buffer;
}
******************************************************************************
Function : form_commandline_options
Description : Generate the complete guc command
Input : instance_name - the instance name
indatadir - the path of instance
local_mode - local mode or not
Output : None
Return : None
******************************************************************************
*/
static char* form_commandline_options(const char* instance_name, const char* indatadir, bool local_mode)
{
char* buffer = NULL;
int buflen = 0;
int curlen = 0;
int i = 0;
int nRet = 0;
char* new_value = NULL;
#define MIN_COMMAND_LEN 256
#define ALLIG_POSTGRES_CONF_LEN 20
#define ALLIG_HBA_CONF_LEN 10
buflen = MIN_COMMAND_LEN;
if (instance_name != NULL) {
buflen += strlen(instance_name);
} else {
buflen += strlen(indatadir);
}
for (i = 0; i < config_param_number; i++) {
if (!is_hba_conf) {
buflen += (int)(ALLIG_POSTGRES_CONF_LEN + strlen(config_param[i]));
if (config_value[i] != NULL) {
buflen += strlen(config_value[i]);
}
} else {
buflen += ALLIG_HBA_CONF_LEN;
if (config_value[i] != NULL) {
buflen += strlen(config_value[i]);
}
}
}
buffer = (char*)pg_malloc_zero(buflen);
curlen = snprintf_s(
buffer, buflen, buflen - 1, "gs_guc %s %s ", get_ctl_command_type(), get_instance_type());
securec_check_ss_c(curlen, buffer, "\0");
if (nodetype == INSTANCE_CMAGENT ||
nodetype == INSTANCE_CMSERVER) {
nRet = snprintf_s(buffer + curlen, (buflen - curlen), (buflen - curlen - 1), "-D \"cm_instance_data_path\"");
} else {
if (NULL != instance_name) {
nRet = snprintf_s(buffer + curlen , (buflen - curlen), (buflen - curlen - 1), "-I %s",
instance_name);
} else {
nRet = snprintf_s(buffer + curlen, (buflen - curlen), (buflen - curlen - 1), "-D \"%s\"",
indatadir);
}
}
securec_check_ss_c(nRet, buffer, "\0");
curlen = curlen + nRet;
for (i = 0; i < config_param_number; i++) {
if (!is_hba_conf) {
* So We need to give attention to the parameter value.
*/
if (config_value[i] != NULL) {
new_value = modify_parameter_value(config_value[i], local_mode);
if (local_mode) {
nRet = snprintf_s(buffer + curlen,
(buflen - curlen),
(buflen - curlen - 1),
" -c %c%s=%s%c",
'"',
config_param[i],
new_value,
'"');
} else {
nRet = snprintf_s(buffer + curlen,
(buflen - curlen),
(buflen - curlen - 1),
" -c \\\"%s=%s\\\"",
config_param[i],
new_value);
}
GS_FREE(new_value);
} else {
nRet = snprintf_s(buffer + curlen, (buflen - curlen), (buflen - curlen - 1), " -c %s", config_param[i]);
}
securec_check_ss_c(nRet, buffer, "\0");
curlen = curlen + nRet;
} else {
if (local_mode) {
nRet = snprintf_s(
buffer + curlen, (buflen - curlen), (buflen - curlen - 1), " -h %c%s%c", '"', config_value[i], '"');
} else {
nRet = snprintf_s(
buffer + curlen, (buflen - curlen), (buflen - curlen - 1), " -h \\\"%s\\\"", config_value[i]);
}
securec_check_ss_c(nRet, buffer, "\0");
curlen = curlen + nRet;
}
}
return buffer;
}
******************************************************************************
Function : get_nodeidx_by_HA
Description : get the node index by HA ip/port
Input : HAIp - HA ipaddr
: HAPort HA port
Output : None
Return : int - node id index
*******************************************************************************
*/
uint32 get_nodeidx_by_HA(const char* HAIp, uint32 HAPort)
{
uint32 i = 0;
uint32 j = 0;
for (i = 0; i < g_node_num; i++) {
for (j = 0; j < g_node[i].datanodeCount; j++) {
if ((0 == strncmp(g_node[i].datanode[j].datanodeLocalHAIP[0], HAIp, strlen(HAIp))) &&
(0 == g_node[i].datanode[j].datanodeLocalHAPort - HAPort))
return i;
}
}
return 0;
}
******************************************************************************
Function : get_instance_id
Description : get_instance_id by data path and HA ip/port. First, get node index by HA ip/port;
then get instance id by data path
Input : dataPath - datanode instance path
: HAIp - HA ipaddr
: HAPort - HA port
Output : None
Return : int - datanode instance id
******************************************************************************
*/
uint32 get_instance_id(const char* dataPath, const char* HAIp, uint32 HAPort)
{
uint32 i = 0;
uint32 nodeidx = 0;
nodeidx = get_nodeidx_by_HA(HAIp, HAPort);
for (i = 0; i < g_node[nodeidx].datanodeCount; i++) {
if (0 == strncmp(g_node[nodeidx].datanode[i].datanodeLocalDataPath, dataPath, strlen(dataPath)))
return g_node[nodeidx].datanode[i].datanodeId;
}
return 0;
}
******************************************************************************
Function : is_instance_level_correct
Description : check whether the instance is in same safety ring by data path , HA ip/port and the level. First, get
node index by HA ip/port; then check the level Input : dataPath - datanode instance path : HAIp - HA ipaddr :
HAPort - HA port : level - the instance level Output : None Return : True/False
******************************************************************************
*/
bool is_instance_level_correct(const char* dataPath, const char* HAIp, uint32 HAPort, uint32 level)
{
uint32 i = 0;
uint32 nodeidx = 0;
nodeidx = get_nodeidx_by_HA(HAIp, HAPort);
for (i = 0; i < g_node[nodeidx].datanodeCount; i++) {
if ((0 == strncmp(g_node[nodeidx].datanode[i].datanodeLocalDataPath, dataPath, strlen(dataPath))) &&
(level == g_node[nodeidx].datanode[i].datanodeRole))
return true;
}
return false;
}
******************************************************************************
GetPgxcNodeNameForMasterDnInstance
get the pgxc_node_name on single primary mutile standby cluster, by node index and datanode instance index
Input: nodeidx -> node index(it comes from static_config_file)
instanceidx -> node index(it comes from static_config_file)
******************************************************************************
*/
char* GetPgxcNodeNameForMasterDnInstance(int32 nodeidx, int32 instanceidx)
{
char* pgxcNodeName = (char*)pg_malloc_zero(sizeof(char) * MAXPGPATH);
int ret = 0;
* get all standby dn instance id arry.
* name dn_6001_6002_6003 -> 6001 must be primary DN instance
*/
uint32 instance_id_arry[CM_NODE_MAXNUM] = {0};
ret = snprintf_s(pgxcNodeName, MAXPGPATH, MAXPGPATH - 1, "dn_%u", g_node[nodeidx].datanode[instanceidx].datanodeId);
securec_check_ss_c(ret, "\0", "\0");
if (g_dn_replication_num == 0) {
write_stderr("ERROR: Failed to get dn instance in the partition.\n");
exit(1);
}
for (uint32 dnId = 0; dnId < g_dn_replication_num - 1; dnId++) {
char tmp_command[MAXPGPATH] = {0};
* The instance must be standby. So use datanodePeerHAIP replace datanodePeer2HAIP
*/
instance_id_arry[dnId] =
get_instance_id(g_node[nodeidx].datanode[instanceidx].peerDatanodes[dnId].datanodePeerDataPath,
g_node[nodeidx].datanode[instanceidx].peerDatanodes[dnId].datanodePeerHAIP[0],
g_node[nodeidx].datanode[instanceidx].peerDatanodes[dnId].datanodePeerHAPort);
ret = memset_s(tmp_command, MAXPGPATH, '\0', MAXPGPATH);
securec_check_c(ret, "\0", "\0");
ret = snprintf_s(tmp_command, MAXPGPATH, MAXPGPATH - 1, "_%u", instance_id_arry[dnId]);
securec_check_ss_c(ret, "\0", "\0");
ret = strncat_s(pgxcNodeName, MAXPGPATH, tmp_command, strlen(tmp_command));
securec_check_ss_c(ret, "\0", "\0");
}
return pgxcNodeName;
}
******************************************************************************
CheckInstanceNameForSinglePrimaryMutilStandby
check the instance_name, whether it is in single primary mutile standby cluster or not
instance Type info: consist with OM
PRIMARY_DN 0
STANDBY_DN 1
DUMMY_STANDBY_DN 2
******************************************************************************
*/
bool CheckInstanceNameForSinglePrimaryMutilStandby(int32 nodeidx, const char* instance_name)
{
uint32 i = 0;
uint32 j = 0;
int ret = 0;
uint32 nameLen = 0;
char* pgxcNodeName = NULL;
for (i = 0; i < g_node[nodeidx].datanodeCount; i++) {
if (g_node[nodeidx].datanode[i].datanodeRole == 0) {
pgxcNodeName = GetPgxcNodeNameForMasterDnInstance(nodeidx, i);
nameLen = strlen(instance_name) > strlen(pgxcNodeName) ? strlen(instance_name) : strlen(pgxcNodeName);
ret = strncmp(pgxcNodeName, instance_name, nameLen);
GS_FREE(pgxcNodeName);
if (ret == 0) {
return true;
}
} else {
* The pgxc_node_name of the primary and standby instances are the same, So get it by primary DN instance
* get the master instance first
* nodeIndex -> primary DN node index
* instanceidx -> primary DN instance index
* dataPath -> primary DN data path
*/
uint32 nodeIndex = 0;
uint32 instanceidx = 0;
char dataPath[MAXPGPATH] = {0};
size_t dataPathLen = 0;
ret = memset_s(dataPath, MAXPGPATH, '\0', MAXPGPATH);
securec_check_c(ret, "\0", "\0");
* Each data ring must have a primary instance. So get the node index and data path.
*/
for (uint32 dnId = 0; dnId < g_dn_replication_num - 1; dnId++) {
if (0 == g_node[nodeidx].datanode[i].peerDatanodes[dnId].datanodePeerRole) {
nodeIndex = get_nodeidx_by_HA(g_node[nodeidx].datanode[i].peerDatanodes[dnId].datanodePeerHAIP[0],
g_node[nodeidx].datanode[i].peerDatanodes[dnId].datanodePeerHAPort);
ret = snprintf_s(dataPath,
MAXPGPATH,
MAXPGPATH - 1,
"%s",
g_node[nodeidx].datanode[i].peerDatanodes[dnId].datanodePeerDataPath);
securec_check_ss_c(ret, "\0", "\0");
break;
}
}
* Check the result to ensure that the nodeIndex and instance data path of primary instance is found.
*/
if (dataPath[0] == '\0') {
fprintf(stderr, _("ERROR: Failed to get primary DN instance information.\n"));
exit(1);
}
* get the primary DN instance index by node index and data path
*/
for (j = 0; j < g_node[nodeIndex].datanodeCount; j++) {
if (g_node[nodeIndex].datanode[i].datanodeRole == 0) {
dataPathLen = strlen(g_node[nodeIndex].datanode[j].datanodeLocalDataPath);
if (0 == strncmp(g_node[nodeIndex].datanode[j].datanodeLocalDataPath,
dataPath,
dataPathLen > strlen(dataPath) ? dataPathLen : strlen(dataPath))) {
instanceidx = j;
break;
}
}
}
pgxcNodeName = GetPgxcNodeNameForMasterDnInstance(nodeIndex, instanceidx);
nameLen = strlen(instance_name) > strlen(pgxcNodeName) ? strlen(instance_name) : strlen(pgxcNodeName);
ret = strncmp(pgxcNodeName, instance_name, nameLen);
GS_FREE(pgxcNodeName);
if (0 == ret) {
return true;
}
}
}
return false;
}
******************************************************************************
Function : validate_instance_name_for_DN
Description : validate the DN instance name.
Input : nodeidx - node id index
instance_name - instance name
Return : bool
******************************************************************************
*/
bool validate_instance_name_for_DN(int32 nodeidx, const char* instance_name)
{
bool isCorrect = false;
uint32 i = 0;
uint32 instance_id = 0;
char temp_instance_name[MAXPGPATH];
int rc = 0;
rc = memset_s(temp_instance_name, MAXPGPATH, '\0', MAXPGPATH);
securec_check_c(rc, "\0", "\0");
if ((int)strlen(instance_name) < DN_INSTANCE_LEN) {
return false;
}
if (g_multi_az_cluster) {
isCorrect = CheckInstanceNameForSinglePrimaryMutilStandby(nodeidx, instance_name);
} else {
if ((int)strlen(instance_name) != DN_INSTANCE_LEN)
return false;
for (i = 0; i < g_node[nodeidx].datanodeCount; i++) {
if (g_node[nodeidx].datanode[i].datanodeRole == 0) {
if (is_instance_level_correct(g_node[nodeidx].datanode[i].datanodePeerDataPath,
g_node[nodeidx].datanode[i].datanodePeerHAIP[0],
g_node[nodeidx].datanode[i].datanodePeerHAPort,
1))
instance_id = get_instance_id(g_node[nodeidx].datanode[i].datanodePeerDataPath,
g_node[nodeidx].datanode[i].datanodePeerHAIP[0],
g_node[nodeidx].datanode[i].datanodePeerHAPort);
else
instance_id = get_instance_id(g_node[nodeidx].datanode[i].datanodePeer2DataPath,
g_node[nodeidx].datanode[i].datanodePeer2HAIP[0],
g_node[nodeidx].datanode[i].datanodePeer2HAPort);
rc = snprintf_s(temp_instance_name,
MAXPGPATH,
MAXPGPATH - 1,
"dn_%d_%d",
(int)g_node[nodeidx].datanode[i].datanodeId,
(int)instance_id);
} else {
if (is_instance_level_correct(g_node[nodeidx].datanode[i].datanodePeerDataPath,
g_node[nodeidx].datanode[i].datanodePeerHAIP[0],
g_node[nodeidx].datanode[i].datanodePeerHAPort,
0))
instance_id = get_instance_id(g_node[nodeidx].datanode[i].datanodePeerDataPath,
g_node[nodeidx].datanode[i].datanodePeerHAIP[0],
g_node[nodeidx].datanode[i].datanodePeerHAPort);
else
instance_id = get_instance_id(g_node[nodeidx].datanode[i].datanodePeer2DataPath,
g_node[nodeidx].datanode[i].datanodePeer2HAIP[0],
g_node[nodeidx].datanode[i].datanodePeer2HAPort);
rc = snprintf_s(temp_instance_name,
MAXPGPATH,
MAXPGPATH - 1,
"dn_%d_%d",
(int)instance_id,
(int)g_node[nodeidx].datanode[i].datanodeId);
}
securec_check_ss_c(rc, "\0", "\0");
if (strncmp(temp_instance_name, instance_name, strlen(instance_name)) == 0) {
isCorrect = true;
break;
}
rc = memset_s(temp_instance_name, MAXPGPATH, '\0', MAXPGPATH);
securec_check_c(rc, "\0", "\0");
}
}
return isCorrect;
}
******************************************************************************
Function : validate_remote_instance_name
Description : validate remote instance name.
The gs_guc commands like this: "-I instance_name -N nodename".
The instance name type like this:
INSTANCE_COORDINATOR -> cn_instanceId
INSTANCE_GTM -> one
INSTANCE_DATANODE -> dn_masterId_slaveId, dn_masterId_dummyslaveId
Input : nodename - node name
type - instance type
instance_name - instance name
Return : int
******************************************************************************
*/
int validate_remote_instance_name(char* nodename, int type, char* instance_name)
{
int32 nodeidx = 0;
char temp_instance_name[MAXPGPATH];
int rc = 0;
bool isCorrect = false;
rc = memset_s(temp_instance_name, MAXPGPATH, '\0', MAXPGPATH);
securec_check_c(rc, "\0", "\0");
nodeidx = get_nodeidx_by_name(nodename);
if (nodeidx < 0) {
write_stderr("ERROR: Node %s is not found in static config file.\n", nodename);
return 1;
}
* INSTANCE_COORDINATOR -> cn_instanceId
* INSTANCE_GTM -> one
* INSTANCE_DATANODE -> dn_masterId_slaveId, dn_masterId_dummyslaveId
*/
if (type == INSTANCE_COORDINATOR) {
rc = snprintf_s(temp_instance_name, MAXPGPATH, MAXPGPATH - 1, "cn_%d", (int)g_node[nodeidx].coordinateId);
securec_check_ss_c(rc, "\0", "\0");
if ((CN_INSTANCE_LEN == (int)strlen(instance_name)) &&
(0 == strncmp(temp_instance_name, instance_name, strlen(instance_name))))
isCorrect = true;
} else if (type == INSTANCE_GTM) {
if ((0 != g_node[nodeidx].gtmId) && (GTM_INSTANCE_LEN == (int)strlen(instance_name)) &&
(0 == strncmp(instance_name, "one", strlen("one"))))
isCorrect = true;
} else {
isCorrect = validate_instance_name_for_DN(nodeidx, instance_name);
}
if (isCorrect) {
return 0;
} else {
write_stderr("ERROR: Instance name %s is incorrect.\n", instance_name);
return 1;
}
}
******************************************************************************
Function : validate_nodename
Description : validate the node name. If the node name is not all, makesure it is
in the cluster static config file.
Input : nodename - node name
Return : int
******************************************************************************
*/
int validate_nodename(char* nodename)
{
int32 nodeidx = 0;
if ((NULL != nodename) && (0 != strncmp(nodename, "all", sizeof("all")))) {
nodeidx = get_nodeidx_by_name(nodename);
if (nodeidx < 0) {
write_stderr("ERROR: Node %s is not found in static config file.\n", nodename);
return 1;
}
}
return 0;
}
******************************************************************************
Function : check_instance_name
Description : check instance name. We known that the node name and instance name are both not 'NULL' and not 'all'.
Input : nodename - node name
type - instance type
instance_name - instance name
Return : int
******************************************************************************
*/
int check_instance_name(char* nodename, int type, char* instance_name)
{
char temp_datadir[MAXPGPATH];
int rc = 0;
rc = memset_s(temp_datadir, MAXPGPATH, '\0', MAXPGPATH);
securec_check_c(rc, "\0", "\0");
if ((0 != strncmp(nodename, "all", sizeof("all"))) && (0 != strncmp(instance_name, "all", sizeof("all")))) {
if (is_local_node(nodename)) {
if (get_local_dbpath_by_instancename(instance_name, &type, temp_datadir) == CLUSTER_CONFIG_ERROR) {
write_stderr("ERROR: Instance name %s is incorrect.\n", instance_name);
return 1;
}
} else {
if (0 != validate_remote_instance_name(nodename, type, instance_name))
return 1;
}
}
return 0;
}
******************************************************************************
Function : validate_node_instance_name
Description : validate the node name and instance name
Input : nodename - node name
type - instance type
instance_name - instance name
Output : None
Return : int
******************************************************************************
*/
int validate_node_instance_name(char* nodename, int type, char* instance_name)
{
char temp_datadir[MAXPGPATH];
int rc = 0;
rc = memset_s(temp_datadir, MAXPGPATH, '\0', MAXPGPATH);
securec_check_c(rc, "\0", "\0");
if (0 != validate_nodename(nodename))
return 1;
if ((NULL == nodename) && (NULL != instance_name)) {
if ((0 != strncmp(instance_name, "all", sizeof("all"))) &&
(get_local_dbpath_by_instancename(instance_name, &type, temp_datadir) == CLUSTER_CONFIG_ERROR)) {
write_stderr("ERROR: Instance name %s is incorrect.\n", instance_name);
return 1;
}
}
if ((NULL != nodename) && (NULL != instance_name)) {
if (type != INSTANCE_DATANODE) {
if ((strncmp(nodename, "all", sizeof("all")) == 0) && (strncmp(instance_name, "all", sizeof("all")) != 0)) {
write_stderr(
"ERROR: Instance name %s is incorrect. When -N is 'all', -I must be the same.\n", instance_name);
return 1;
}
}
if (0 != check_instance_name(nodename, type, instance_name))
return 1;
}
return 0;
}
#ifndef ENABLE_MULTIPLE_NODES
******************************************************************************
Function : gsguc_precheck_forbid_parameters
Description : Forbid reload/set/check GUC parameters in list for ALL node type
Input : nodename(indicates node name)
Output : none
Return : bool
******************************************************************************
*/
char *gsguc_forbid_list_reload[] = {
"listen_addresses",
NULL
};
bool gsguc_precheck_forbid_parameters(char *nodename)
{
if (is_hba_conf) {
return true;
}
switch (ctl_command) {
case SET_CONF_COMMAND:
break;
case RELOAD_CONF_COMMAND:
if (strncmp(nodename, "all", strlen("all")) != 0) {
break;
}
for (int i = 0; i < config_param_number && config_param[i] != NULL; i++) {
for (int j = 0; gsguc_forbid_list_reload[j] != NULL; j++) {
if (strcmp(config_param[i], gsguc_forbid_list_reload[j]) == 0) {
write_stderr(_("ERROR: \"%s\" can not \"%s\" with \"%s\" method.\n"),
gsguc_forbid_list_reload[j],
get_ctl_command_type(),
nodename);
return false;
}
}
}
break;
case CHECK_CONF_COMMAND:
break;
default:
break;
}
return true;
}
#endif
******************************************************************************
Function : validate_cluster_guc_options
Description : check the -N, -I and -D parameter
Input : nodename - node name
type - node type
instance_name - instance name
indatadir - instance data directory
Output : None
Return : int
******************************************************************************
*/
int validate_cluster_guc_options(char* nodename, int type, char* instance_name, char* indatadir)
{
if ((NULL != nodename) || (NULL != instance_name)) {
if (0 != init_gauss_cluster_config()) {
(void)write_stderr("ERROR: Failed to get cluster information from static configuration file.\n");
return 1;
}
}
if ((NULL == instance_name) && (NULL == indatadir)) {
if (type == INSTANCE_CMAGENT || type == INSTANCE_CMSERVER) {
write_stderr("ERROR: -I all are mandatory for executing gs_guc.\n");
} else {
write_stderr("ERROR: -D or -I are mandatory for executing gs_guc.\n");
}
return 1;
} else if ((NULL != instance_name) && (NULL != indatadir)) {
write_stderr("ERROR: -D or -I only need one for executing gs_guc.\n");
return 1;
}
if (node_type_number == LARGE_INSTANCE_NUM && (NULL != instance_name) &&
(0 != strncmp(instance_name, "all", sizeof("all")))) {
write_stderr("ERROR: when -Z is coordinator and datanode, the -I must be 'all'.\n");
return 1;
}
if (0 != validate_node_instance_name(nodename, type, instance_name))
return 1;
do_checkvalidate(type);
return 0;
}
******************************************************************************
Function : save_expect_instance_info
Description : save expect instance information into global parameter.
node name and instance guc configure file
Input : datadir (the directory about instance)
Output : "expected instance path: %s\n", gucconf_file
Return : void
******************************************************************************
*/
void save_expect_instance_info(const char* datadir)
{
int i = 0;
if (NULL == datadir || '\0' == datadir[0]) {
(void)write_stderr("instance data directory is NULL.\n");
return;
}
get_instance_configfile(datadir);
if (CHECK_CONF_COMMAND == ctl_command) {
for (i = 0; i < config_param_number; i++) {
g_expect_gucInfo->nodename_array[g_expect_gucInfo->nodename_num++] = xstrdup(g_local_node_name);
g_expect_gucInfo->gucinfo_array[g_expect_gucInfo->gucinfo_num++] = xstrdup(gucconf_file);
g_expect_gucInfo->paramname_array[g_expect_gucInfo->paramname_num++] = xstrdup(config_param[i]);
g_expect_gucInfo->paramvalue_array[g_expect_gucInfo->paramvalue_num++] = xstrdup("NULL");
(void)write_stderr(
"expected guc information: %s: %s=NULL: [%s]\n", g_local_node_name, config_param[i], gucconf_file);
}
} else {
g_expect_gucInfo->nodename_array[g_expect_gucInfo->nodename_num++] = xstrdup(g_local_node_name);
g_expect_gucInfo->gucinfo_array[g_expect_gucInfo->gucinfo_num++] = xstrdup(gucconf_file);
(void)write_stderr("expected instance path: [%s]\n", gucconf_file);
}
}
void check_env_value(const char* input_env_value)
{
const char* danger_character_list[] = {"|",
";",
"&",
"$",
"<",
">",
"`",
"\\",
"'",
"\"",
"{",
"}",
"(",
")",
"[",
"]",
"~",
"*",
"?",
"!",
"\n",
NULL};
int i = 0;
for (i = 0; danger_character_list[i] != NULL; i++) {
if (strstr(input_env_value, danger_character_list[i]) != NULL) {
fprintf(stderr,
_("ERROR: Failed to check environment value: invalid token \"%s\".\n"),
danger_character_list[i]);
exit(1);
}
}
}
******************************************************************************
Function : get_env_value
Description : get environment variable value.
Input : env_var (environment variable name) ,output_env_value
Output :
Return : bool
******************************************************************************
*/
bool get_env_value(const char* env_var, char* output_env_value, size_t env_var_value_len)
{
char* env_value = NULL;
errno_t rc = 0;
if (NULL == env_var)
return false;
env_value = getenv(env_var);
if ((NULL == env_value) || ('\0' == env_value[0])) {
write_stderr(
"ERROR: Failed to obtain environment variable \"%s\". Please check and makesure it is set.\n", env_var);
return false;
}
if (env_var_value_len <= strlen(env_value)) {
write_stderr("ERROR: The value of environment variable \"%s\" is too long.\n", env_var);
return false;
}
rc = strcpy_s(output_env_value, env_var_value_len, env_value);
securec_check_c(rc, "\0", "\0");
return true;
}
******************************************************************************
Function : process_cluster_guc_option
Description :
Input : nodename -
type -
instance_name -
indatadir -
Output : None
Return : void
******************************************************************************
*/
void process_cluster_guc_option(char* nodename, int type, char* instance_name, char* indatadir)
{
uint32 idx = 0;
int instance_nums = 0;
int nRet = 0;
char local_name[MAX_HOST_NAME_LENGTH];
int malloc_num = 1;
char *cmpath = NULL;
g_remote_connection_signal = true;
g_remote_command_result = 0;
g_real_gucInfo = (gucInfo*)pg_malloc(sizeof(gucInfo));
g_expect_gucInfo = (gucInfo*)pg_malloc(sizeof(gucInfo));
if (NULL != indatadir && NULL == nodename) {
nRet = memset_s(local_name, MAX_HOST_NAME_LENGTH, '\0', MAX_HOST_NAME_LENGTH);
securec_check_c(nRet, "\0", "\0");
if (get_hostname_or_ip(local_name, MAX_HOST_NAME_LENGTH) == false) {
exit(1);
}
g_local_node_name = xstrdup(local_name);
if (has_static_config() && 0 == init_gauss_cluster_config()) {
for (idx = 0; idx < get_num_nodes(); idx++) {
if (is_local_nodeid(g_node[idx].node)) {
g_local_node_idx = idx;
}
}
}
malloc_num = 1;
} else {
if (0 != init_gauss_cluster_config())
return;
for (idx = 0; idx < get_num_nodes(); idx++) {
if (is_local_nodeid(g_node[idx].node)) {
g_local_node_idx = idx;
}
}
g_local_node_name = getnodename(g_local_node_idx);
if (node_type_number == LARGE_INSTANCE_NUM) {
instance_nums = get_all_cndn_num();
} else if (type == INSTANCE_DATANODE) {
instance_nums = get_all_datanode_num();
} else if (type == INSTANCE_COORDINATOR) {
instance_nums = get_all_coordinator_num();
} else if (type == INSTANCE_CMSERVER) {
instance_nums = get_all_cmserver_num();
} else if (type == INSTANCE_CMAGENT) {
instance_nums = get_all_cmagent_num();
} else {
instance_nums = get_all_gtm_num();
}
g_incorrect_nodeInfo = (nodeInfo*)pg_malloc(sizeof(nodeInfo));
g_incorrect_nodeInfo->nodename_array = (char**)pg_malloc_zero(get_num_nodes() * sizeof(char*));
g_incorrect_nodeInfo->num = 0;
malloc_num = instance_nums + 1;
}
if (NULL == g_local_node_name || '\0' == g_local_node_name[0]) {
(void)write_stderr("ERROR: Failed to obtain local host name.\n");
exit(1);
}
if (CHECK_CONF_COMMAND == ctl_command || type == INSTANCE_CMSERVER || type == INSTANCE_CMAGENT) {
malloc_num = malloc_num * config_param_number;
}
g_real_gucInfo->nodename_array = (char**)pg_malloc_zero(sizeof(char*) * malloc_num);
g_real_gucInfo->gucinfo_array = (char**)pg_malloc_zero(sizeof(char*) * malloc_num);
g_expect_gucInfo->nodename_array = (char**)pg_malloc_zero(sizeof(char*) * malloc_num);
g_expect_gucInfo->gucinfo_array = (char**)pg_malloc_zero(sizeof(char*) * malloc_num);
g_real_gucInfo->nodename_num = 0;
g_real_gucInfo->gucinfo_num = 0;
g_expect_gucInfo->nodename_num = 0;
g_expect_gucInfo->gucinfo_num = 0;
if (CHECK_CONF_COMMAND == ctl_command) {
g_real_gucInfo->paramname_array = (char**)pg_malloc_zero(sizeof(char*) * malloc_num);
g_real_gucInfo->paramvalue_array = (char**)pg_malloc_zero(sizeof(char*) * malloc_num);
g_expect_gucInfo->paramname_array = (char**)pg_malloc_zero(sizeof(char*) * malloc_num);
g_expect_gucInfo->paramvalue_array = (char**)pg_malloc_zero(sizeof(char*) * malloc_num);
g_real_gucInfo->paramname_num = 0;
g_real_gucInfo->paramvalue_num = 0;
g_expect_gucInfo->paramname_num = 0;
g_expect_gucInfo->paramvalue_num = 0;
}
if (NULL == nodename)
{
if ((INSTANCE_CMSERVER == type) || (INSTANCE_CMAGENT == type)) {
cmpath = get_cm_real_path(type);
do_local_instance(type, instance_name, cmpath);
GS_FREE(cmpath);
} else {
do_local_instance(type, instance_name, indatadir);
}
}
else
{
if (0 == strncmp(nodename, "all", strlen("all"))) {
#ifndef ENABLE_MULTIPLE_NODES
if (!gsguc_precheck_forbid_parameters(nodename)) {
exit(1);
}
#endif
do_all_nodes_instance(instance_name, indatadir);
} else {
do_remote_instance(nodename, instance_name, indatadir);
}
}
}
* the ssh return value:
* 0 : The connection is successful, the command was successful
* 1 : The connection is successful, the command fails
* 127 : The connection is successful, the command fails
* 255 : Connection failed
*/
void
printExecErrorMesg(const char* fcmd, const char *nodename)
{
if (g_remote_command_result == 127) {
write_stderr(_("ERROR: Failed to execute gs_guc command: %s on node \"%s\", error code is %u, "
"please ensure that gs_guc exists.\n"), fcmd, nodename, g_remote_command_result);
} else if (g_remote_command_result == 255) {
write_stderr(_("ERROR: Failed to execute gs_guc command: %s on node \"%s\", error code is %u, "
"Failed to connect node \"%s\".\n"), fcmd, nodename, g_remote_command_result, nodename);
} else if (g_remote_command_result != 0) {
write_stderr(_("ERROR: Failed to execute gs_guc command: %s on node \"%s\", error code is %u, "
"please get more details from current node path \"$GAUSSLOG/bin/gs_guc\".\n"),
fcmd, nodename, g_remote_command_result);
}
}
******************************************************************************
Function : is_changed_default_value_failed
Description : Modify the default value for parameter "log_directory" and "audit_directory".
Input :type instance type
datadir instance data directory
param_name_str parameter name
index parameter name index
gausslog defaul value
return :true failed to change the default values
false Successfully set default values
******************************************************************************
*/
bool is_changed_default_value_failed(int type, char* datadir, char* param_name_str, int index, const char* gausslog)
{
char local_inst_name[MAX_INSTANCENAME_LEN] = {0};
char log_dir[MAX_VALUE_LEN] = {0};
int32 retval;
int nRet = 0;
retval = get_local_instancename_by_dbpath(datadir, local_inst_name);
if (retval == CLUSTER_CONFIG_ERROR) {
(void)write_stderr("ERROR: Failed to obtain instance name by data directory \"%s\".\n", datadir);
return true;
}
if (type == INSTANCE_COORDINATOR || type == INSTANCE_DATANODE) {
if (0 == strncmp(param_name_str, "log_directory", strlen("log_directory")))
nRet = snprintf_s(log_dir, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "'%s/pg_log/%s'", gausslog, local_inst_name);
else
nRet = snprintf_s(log_dir, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "'%s/pg_audit/%s'", gausslog, local_inst_name);
securec_check_ss_c(nRet, "\0", "\0");
} else {
if (0 == strncmp(param_name_str, "log_directory", strlen("log_directory"))) {
nRet = snprintf_s(log_dir, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "'%s/pg_log/gtm'", gausslog);
securec_check_ss_c(nRet, "\0", "\0");
} else {
(void)write_stderr("ERROR: The parameter \"%s\" don't support gtm instance.\n", param_name_str);
return true;
}
}
config_value[index] = xstrdup(log_dir);
is_disable_log_directory = true;
return false;
}
******************************************************************************
Function : check_AZ_value
Description : check the input azName.
Input :AZValue az name
return :true input az name is correct
false input az name is incorrect
******************************************************************************
*/
bool check_AZ_value(const char* AZValue)
{
if (strlen(AZValue) > (CM_AZ_NAME - 1)) {
return false;
}
return true;
}
******************************************************************************
Function : parse_AZ_result
Description : parse AZ string into the node name list .
Input :AZValue az name
return :NULL input az name is incorrect
other the real result
******************************************************************************
*/
char* parse_AZ_result(char* AZStr, const char* data_dir)
{
int nRet = 0;
char* vptr = NULL;
char* vouter_ptr = NULL;
char* p = NULL;
char delims[] = ",";
char tmp[MAX_VALUE_LEN] = {0};
int i = 0;
char azList[3][MAX_INSTANCENAME_LEN] = {0};
char tmpAzName[MAX_INSTANCENAME_LEN] = {0};
char** array = NULL;
char* buffer = NULL;
int curlen = 0;
char* azName = NULL;
size_t len = 0;
int ind = -1;
const int az1_index = 0;
const int az2_index = 1;
const int az3_index = 2;
int resultStatus = 0;
nRet = memset_s(tmp, MAX_VALUE_LEN, '\0', MAX_VALUE_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = snprintf_s(tmp, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", AZStr);
securec_check_ss_c(nRet, "\0", "\0");
for (i = 0; i < 3; i++) {
nRet = memset_s(azList[i], MAX_INSTANCENAME_LEN, '\0', MAX_INSTANCENAME_LEN);
securec_check_c(nRet, "\0", "\0");
}
vptr = strtok_r(tmp, delims, &vouter_ptr);
while (NULL != vptr) {
p = vptr;
while (isspace((unsigned char)*p))
p++;
size_t azNameLength = strlen(p);
if (check_AZ_value(p)) {
if (azList[az1_index][0] == '\0') {
nRet = strncpy_s(azList[az1_index], MAX_INSTANCENAME_LEN, p, azNameLength);
securec_check_c(nRet, "\0", "\0");
} else if (azList[az2_index][0] == '\0') {
if (azNameLength != strlen(azList[az1_index]) ||
strncmp(p, azList[az1_index], strlen(azList[az1_index])) != 0) {
nRet = strncpy_s(azList[az2_index], MAX_INSTANCENAME_LEN, p, azNameLength);
securec_check_c(nRet, "\0", "\0");
}
} else if (azList[az3_index][0] == '\0') {
if ((azNameLength != strlen(azList[az1_index]) ||
strncmp(p, azList[az1_index], strlen(azList[az1_index])) != 0) &&
(azNameLength != strlen(azList[az2_index]) ||
strncmp(p, azList[az2_index], strlen(azList[az2_index])) != 0)) {
nRet = strncpy_s(azList[az3_index], MAX_INSTANCENAME_LEN, p, azNameLength);
securec_check_c(nRet, "\0", "\0");
}
} else {
}
vptr = strtok_r(NULL, delims, &vouter_ptr);
} else {
(void)write_stderr("Notice: azName value check failed.\n");
return NULL;
}
}
if ('\0' == azList[0][0]) {
return NULL;
}
azName = get_AZname_by_nodename(g_local_node_name);
if (NULL == azName) {
(void)write_stderr("ERROR: Failed to obtain AZ name by local node.\n");
return NULL;
}
for (i = 0; i < 3; i++) {
if (0 == strncmp(azList[i], azName, strlen(azList[i]) > strlen(azName) ? strlen(azList[i]) : strlen(azName))) {
ind = i;
}
}
if (ind > 0) {
nRet = memset_s(tmpAzName, MAX_INSTANCENAME_LEN, '\0', MAX_INSTANCENAME_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = strncpy_s(tmpAzName, MAX_INSTANCENAME_LEN, azList[0], strlen(azList[0]));
securec_check_c(nRet, "\0", "\0");
nRet = memset_s(azList[0], MAX_INSTANCENAME_LEN, '\0', MAX_INSTANCENAME_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = strncpy_s(azList[0], MAX_INSTANCENAME_LEN, azList[ind], strlen(azList[ind]));
securec_check_c(nRet, "\0", "\0");
nRet = memset_s(azList[ind], MAX_INSTANCENAME_LEN, '\0', MAX_INSTANCENAME_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = strncpy_s(azList[ind], MAX_INSTANCENAME_LEN, tmpAzName, strlen(tmpAzName));
securec_check_c(nRet, "\0", "\0");
}
GS_FREE(azName);
array = (char**)pg_malloc(3 * sizeof(char*));
array[0] = NULL;
array[1] = NULL;
array[2] = NULL;
resultStatus = get_nodename_list_by_AZ(azList[0], data_dir, &array[0]);
PROCESS_STATUS(resultStatus);
if (NULL == array[0]) {
(void)write_log("ERROR: The AZ name \"%s\" does not be found on cluster. please makesure the AZ string "
"\"%s\" is correct.\n",
azList[0],
AZStr);
goto failed;
}
len += strlen(array[0]) + 1;
if ('\0' != azList[1][0]) {
resultStatus = get_nodename_list_by_AZ(azList[1], data_dir, &array[1]);
PROCESS_STATUS(resultStatus);
if (NULL == array[1]) {
(void)write_log("ERROR: The AZ name \"%s\" does not be found on cluster. please makesure the AZ string "
"\"%s\" is correct.\n",
azList[1],
AZStr);
goto failed;
}
len += strlen(array[1]) + 1;
}
if ('\0' != azList[2][0]) {
resultStatus = get_nodename_list_by_AZ(azList[2], data_dir, &array[2]);
PROCESS_STATUS(resultStatus);
if (NULL == array[2]) {
(void)write_log("ERROR: The AZ name \"%s\" does not be found on cluster. please makesure the AZ string "
"\"%s\" is correct.\n",
azList[2],
AZStr);
goto failed;
}
len += strlen(array[2]) + 1;
}
buffer = (char*)pg_malloc_zero((len + 1) * sizeof(char));
for (i = 0; i < 3; i++) {
if (NULL != array[i] && strlen(array[i]) > 0) {
nRet = snprintf_s(buffer + curlen, (len + 1 - curlen), (len - curlen), "%s,", array[i]);
securec_check_ss_c(nRet, buffer, "\0");
curlen = curlen + nRet;
}
}
if (strlen(buffer) >= 2) {
buffer[strlen(buffer) - 1] = '\0';
} else {
(void)write_stderr(
"ERROR: There is no standby node, please makesure the AZ string \"%s\" is correct.\n", AZStr);
goto failed;
}
GS_FREE(array[0]);
GS_FREE(array[1]);
GS_FREE(array[2]);
GS_FREE(array);
return buffer;
failed:
GS_FREE(array[0]);
GS_FREE(array[1]);
GS_FREE(array[2]);
GS_FREE(array);
GS_FREE(buffer);
return NULL;
}
******************************************************************************
Function : get_nodename_number_from_nodelist
Description : get the number of nodenames in the nodename string. String is split with ','
Input :AZValue namelist
return :int the nodename number
******************************************************************************
*/
int get_nodename_number_from_nodelist(const char* namelist)
{
char* ptr = NULL;
char* outer_ptr = NULL;
char delims[] = ",";
size_t len = 0;
int count = 0;
char* buffer = NULL;
int nRet = 0;
len = strlen(namelist) + 1;
buffer = (char*)pg_malloc_zero(len * sizeof(char));
nRet = snprintf_s(buffer, len, len - 1, "%s", namelist);
securec_check_ss_c(nRet, buffer, "\0");
ptr = strtok_r(buffer, delims, &outer_ptr);
while (NULL != ptr) {
count++;
ptr = strtok_r(NULL, delims, &outer_ptr);
}
GS_FREE(buffer);
return count;
}
******************************************************************************
Function : parse_datanodename_result
Description : check data node name.
Input :datanodenamelist data node name
return :NULL input data node name is incorrect
other the real result
******************************************************************************
*/
char *ParseDatanameResult(const char *datanodeNameList, const char *dataDir)
{
int nRet;
char *vptr = NULL;
char *vouterPtr = NULL;
char *p = NULL;
char delims[] = ",";
char tmp[MAX_VALUE_LEN] = {0};
char *buffer = NULL;
size_t len;
nRet = memset_s(tmp, MAX_VALUE_LEN, '\0', MAX_VALUE_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = snprintf_s(tmp, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", datanodeNameList);
securec_check_ss_c(nRet, "\0", "\0");
vptr = strtok_r(tmp, delims, &vouterPtr);
while (vptr != NULL) {
p = vptr;
while (isspace((unsigned char)*p)) {
p++;
}
if (CheckDataNameValue(p, dataDir)) {
vptr = strtok_r(NULL, delims, &vouterPtr);
} else {
write_stderr("Notice: datanodename value check failed.(datanodename=%s)\n", p);
return NULL;
}
}
len = strlen(datanodeNameList) + 1;
buffer = (char *)pg_malloc_zero(len * sizeof(char));
nRet = snprintf_s(buffer, len, (len - 1), "%s", datanodeNameList);
securec_check_ss_c(nRet, buffer, "\0");
return buffer;
}
******************************************************************************
Function : get_AZ_value
Description : parse AZ string into the node name list .
Input :value the parameter value from input
******************************************************************************
*/
char* get_AZ_value(const char* value, const char* data_dir)
{
size_t minLen = 0;
int nRet = 0;
char tmp[MAX_VALUE_LEN] = {0};
char* p = NULL;
char* q = NULL;
char* s = NULL;
char preStr[16] = {0};
char level[4] = {0};
int i = 0;
int j = 0;
int count = 0;
char* nodenameList = NULL;
char* result = NULL;
size_t len = 0;
char* az1 = getAZNamebyPriority(g_az_master);
char* vouter_ptr = NULL;
char delims[] = ",";
char* vptr = NULL;
char emptyvalue[] = "''";
bool isNodeName = false;
if (az1 != NULL) {
minLen = strlen("ANY X()") + strlen(az1);
} else {
(void)write_stderr("ERROR: can not find AZ_MASTER Name, current az_master priority=%u.\n", g_az_master);
return NULL;
}
nRet = memset_s(preStr, sizeof(preStr) / sizeof(char), '\0', sizeof(preStr) / sizeof(char));
securec_check_c(nRet, "\0", "\0");
nRet = memset_s(level, sizeof(level) / sizeof(char), '\0', sizeof(level) / sizeof(char));
securec_check_c(nRet, "\0", "\0");
nRet = memset_s(tmp, MAX_VALUE_LEN, '\0', MAX_VALUE_LEN);
securec_check_c(nRet, "\0", "\0");
i = 0;
j = 1;
while (j < (int)strlen(value) - 1) {
if (!isspace(value[j])) {
tmp[i] = value[j];
i++;
j++;
} else {
j++;
}
}
if (strlen(value) > MAX_VALUE_LEN) {
(void)write_stderr("ERROR: The value of pamameter synchronous_standby_names is incorrect.\n");
return NULL;
}
p = tmp;
if (strlen(p) == 0 || *p == '*') {
len = strlen(emptyvalue) + strlen(p) + 1;
result = (char*)pg_malloc_zero(len * sizeof(char));
nRet = snprintf_s(result, len, len - 1, "'%s'", p);
securec_check_ss_c(nRet, "\0", "\0");
return result;
}
if (0 == strncmp(p, "FIRST", strlen("FIRST"))) {
nRet = strncpy_s(preStr, sizeof(preStr) / sizeof(char), "FIRST ", strlen("FIRST "));
securec_check_c(nRet, "\0", "\0");
p = p + strlen("FIRST");
}
if (0 == strncmp(p, "ANY", strlen("ANY"))) {
nRet = strncpy_s(preStr, sizeof(preStr) / sizeof(char), "ANY ", strlen("ANY "));
securec_check_c(nRet, "\0", "\0");
p = p + strlen("ANY");
}
if (strncmp(p, "NODE", strlen("NODE")) == 0) {
isNodeName = true;
p = p + strlen("NODE");
}
if (isdigit((unsigned char)*p)) {
nRet = snprintf_s(level, sizeof(level) / sizeof(char),
sizeof(level) / sizeof(char) - 1, "%c", (unsigned char)*p);
securec_check_ss_c(nRet, "\0", "\0");
if (atoi(level) < 1 || atoi(level) > 7) {
goto failed;
}
if (strchr(p, '(') && strrchr(p, ')')) {
q = strchr(p, '(');
q++;
s = strrchr(p, ')');
s[0] = '\0';
} else {
goto failed;
}
} else {
q = p;
}
if (*q == '\0' || *q == '*') {
goto failed;
}
if (isNodeName) {
nodenameList = ParseDatanameResult(q, data_dir);
} else {
nodenameList = parse_AZ_result(q, data_dir);
}
if (NULL == nodenameList) {
len = strlen(q) + 1;
s = (char *)pg_malloc_zero(len * sizeof(char));
nRet = snprintf_s(s, len, len - 1, "%s", q);
securec_check_ss_c(nRet, s, "\0");
vptr = strtok_r(s, delims, &vouter_ptr);
while (vptr != NULL) {
p = vptr;
if (CheckDataNameValue(p, data_dir) == false) {
GS_FREE(s);
goto failed;
}
vptr = strtok_r(NULL, delims, &vouter_ptr);
}
GS_FREE(s);
nodenameList = (char *)pg_malloc_zero(len * sizeof(char));
nRet = snprintf_s(nodenameList, len, len - 1, "%s", q);
securec_check_ss_c(nRet, nodenameList, "\0");
} else if ('\0' == nodenameList[0]) {
(void)write_stderr("ERROR: There is no standby node name. Please make sure the value of "
"synchronous_standby_names is correct.\n");
GS_FREE(nodenameList);
return NULL;
}
count = get_nodename_number_from_nodelist(nodenameList);
if (atoi(level) > count) {
(void)write_stderr("ERROR: The sync number(%d) must less or equals to the number of standby node names(%d). "
"Please make sure the value of synchronous_standby_names is correct.\n",
atoi(level), count);
GS_FREE(nodenameList);
return NULL;
}
if (atoi(level) >= 1) {
len = strlen(preStr) + 6 + strlen(nodenameList);
result = (char*)pg_malloc_zero(len * sizeof(char));
nRet = snprintf_s(result, len, len - 1, "'%s%s(%s)'", preStr, level, nodenameList);
securec_check_ss_c(nRet, "\0", "\0");
} else {
len = 3 + strlen(nodenameList);
result = (char*)pg_malloc_zero(len * sizeof(char));
nRet = snprintf_s(result, len, len - 1, "'%s'", nodenameList);
securec_check_ss_c(nRet, "\0", "\0");
}
GS_FREE(nodenameList);
return result;
failed:
GS_FREE(nodenameList);
GS_FREE(result);
(void)write_stderr("ERROR: The value of pamameter synchronous_standby_names is incorrect.\n");
return NULL;
}
******************************************************************************
Function : do_local_para_value_change
Description : only support parameter "log_directory" and "audit_directory".
If we want to disable "log_directory", using the default value "$GAUSSLOG/pg_log/instance_name"
If we want to disable "audit_directory", using the default value "$GAUSSLOG/pg_audit/instance_name"
******************************************************************************
*/
int do_local_para_value_change(int type, char* datadir)
{
bool is_failed = false;
int i = 0;
char gausslog[MAXPGPATH] = {0};
char staticfile[MAXPGPATH] = {0};
char gausshome[MAXPGPATH] = {0};
int nRet = 0;
struct stat statbuf;
if (type != INSTANCE_COORDINATOR && type != INSTANCE_DATANODE && type != INSTANCE_CMSERVER &&
type != INSTANCE_CMAGENT && type != INSTANCE_GTM) {
(void)write_stderr("ERROR: The instance type is incorrect.\n");
return FAILURE;
}
for (i = 0; i < config_param_number; i++) {
if (0 == strncmp(config_param[i],
"synchronous_standby_names",
strlen(config_param[i]) > strlen("synchronous_standby_names")
? strlen(config_param[i])
: strlen("synchronous_standby_names"))) {
if (type != INSTANCE_DATANODE) {
(void)write_stderr(
"ERROR: The pamameter synchronous_standby_names only can be used for datanode type.\n");
return FAILURE;
}
if (!get_env_value("GAUSSHOME", gausshome, sizeof(gausshome) / sizeof(char))) {
g_need_changed = false;
} else {
check_env_value(gausshome);
nRet = snprintf_s(staticfile, MAXPGPATH, MAXPGPATH - 1, "%s/bin/%s", gausshome, STATIC_CONFIG_FILE);
securec_check_ss_c(nRet, "\0", "\0");
if (lstat(staticfile, &statbuf) != 0) {
g_need_changed = false;
} else {
if (0 != init_gauss_cluster_config()) {
(void)write_stderr(
"ERROR: Failed to get cluster information from static configuration file.\n");
return FAILURE;
}
}
}
if (NULL == g_local_instance_path) {
g_local_instance_path = xstrdup(datadir);
}
}
if (NULL == config_value[i] || is_disable_log_directory) {
if (0 == strncmp(config_param[i], "log_directory", strlen("log_directory")) ||
0 == strncmp(config_param[i], "audit_directory", strlen("audit_directory"))) {
if (!get_env_value("GAUSSLOG", gausslog, sizeof(gausslog) / sizeof(char)))
return FAILURE;
check_env_value(gausslog);
is_failed = is_changed_default_value_failed(type, datadir, config_param[i], i, gausslog);
}
}
}
if (is_failed)
return FAILURE;
return SUCCESS;
}
int do_local_guc_command(int type, char* temp_datadir)
{
if ('\0' != temp_datadir[0]) {
* When do check, do_local_para_value_change is not be used.
*/
if ((type != INSTANCE_CMAGENT) && (type != INSTANCE_CMSERVER)) {
if ((CHECK_CONF_COMMAND != ctl_command) && (FAILURE == do_local_para_value_change(type, temp_datadir)))
return FAILURE;
}
if (0 != process_guc_command(temp_datadir))
return FAILURE;
}
return SUCCESS;
}
******************************************************************************
Function : do_command_in_local_node
Description : set/reload guc parameter in local node
Input : type (instance type)
indatadir (the instance data path)
Output : None
Return : void
******************************************************************************
*/
void do_command_in_local_node(int type, char* indatadir)
{
char datadir[MAXPGPATH] = {0};
if (NULL == indatadir) {
char* envvar = NULL;
if ((INSTANCE_COORDINATOR == type) || (INSTANCE_DATANODE == type))
envvar = "PGDATA";
else if (INSTANCE_GTM == type)
envvar = "GTMDATA";
else
return;
if (!get_env_value(envvar, datadir, sizeof(datadir) / sizeof(char)))
return;
if (NULL != datadir) {
check_env_value(datadir);
}
if (checkPath(datadir) != 0) {
write_stderr(_("realpath(%s) failed : %s!\n"), datadir, strerror(errno));
}
save_expect_instance_info(datadir);
if (FAILURE == do_local_guc_command(type, datadir))
return;
} else {
if (checkPath(indatadir) != 0) {
write_stderr(_("realpath(%s) failed : %s!\n"), indatadir, strerror(errno));
}
save_expect_instance_info(indatadir);
if (FAILURE == do_local_guc_command(type, indatadir))
return;
}
}
******************************************************************************
Function : do_command_with_all_option
Description : set/reload guc parameter using "-I all" option
Input : type (instance type)
indatadir (the instance data path)
Output : None
Return : void
******************************************************************************
*/
void do_command_with_all_option(int type, char* indatadir)
{
if (node_type_number == LARGE_INSTANCE_NUM)
do_command_for_cndn(type, indatadir);
else if (type == INSTANCE_COORDINATOR)
do_command_for_cn_gtm(type, indatadir, true);
else if (type == INSTANCE_GTM)
do_command_for_cn_gtm(type, indatadir, false);
else if (type == INSTANCE_DATANODE)
do_command_for_dn(type, indatadir);
else if ((type == INSTANCE_CMAGENT) || (type == INSTANCE_CMSERVER))
do_command_for_cm(type, indatadir);
else
return;
}
******************************************************************************
Function : do_command_for_cn
Description :
Input : type (instance type)
indatadir (the instance data path)
isCoordinator if true is Coordinator, else is gtm
Output : None
Return : void
******************************************************************************
*/
void do_command_for_cn_gtm(int type, char* indatadir, bool isCoordinator)
{
char temp_datadir[MAXPGPATH] = {0};
errno_t rc = 0;
if (isCoordinator)
rc = memcpy_s(temp_datadir, sizeof(temp_datadir) / sizeof(char), g_currentNode->DataPath, sizeof(temp_datadir) / sizeof(char));
else
rc = memcpy_s(temp_datadir, sizeof(temp_datadir) / sizeof(char), g_currentNode->gtmLocalDataPath, sizeof(temp_datadir) / sizeof(char));
securec_check_c(rc, "\0", "\0");
save_expect_instance_info(temp_datadir);
if (FAILURE == do_local_guc_command(type, temp_datadir))
return;
}
******************************************************************************
Function : do_command_for_dn
Description :
Input : type (instance type)
indatadir (the instance data path)
Output : None
Return : void
******************************************************************************
*/
void do_command_for_dn(int type, char* indatadir)
{
char temp_datadir[MAXPGPATH] = {0};
uint32 i = 0;
errno_t rc = 0;
for (i = 0; i < get_local_num_datanode(); i++) {
rc = memcpy_s(temp_datadir, sizeof(temp_datadir) / sizeof(char), g_currentNode->datanode[i].datanodeLocalDataPath, sizeof(temp_datadir) / sizeof(char));
securec_check_c(rc, "\0", "\0");
save_expect_instance_info(temp_datadir);
}
for (i = 0; i < get_local_num_datanode(); i++) {
rc = memcpy_s(temp_datadir, sizeof(temp_datadir) / sizeof(char), g_currentNode->datanode[i].datanodeLocalDataPath, sizeof(temp_datadir) / sizeof(char));
securec_check_c(rc, "\0", "\0");
if (FAILURE == do_local_guc_command(type, temp_datadir)) {
return;
}
}
}
******************************************************************************
Function : do_command_for_cm
Description :
Input : type (instance type)
indatadir (the instance data path)
isCmserver (if true is cmserver and pathname is "cm_server", else is cmagent and pathname is
"cm_agent") Output : None Return : void
******************************************************************************
*/
void
do_command_for_cm(int type, char* indatadir)
{
char temp_datadir[MAXPGPATH] = {0};
char cm_dir[MAXPGPATH] = {0};
int nRet = 0;
errno_t rc = 0;
rc = memcpy_s(cm_dir, sizeof(cm_dir)/sizeof(char), g_currentNode->cmDataPath, sizeof(cm_dir)/sizeof(char));
securec_check_c(rc, "\0", "\0");
if (cm_dir[0] == '\0') {
write_stderr("Failed to get cm base datapath from static config file.");
return;
}
if (type == INSTANCE_CMAGENT) {
nRet = snprintf_s(temp_datadir, sizeof(temp_datadir)/sizeof(char),
sizeof(temp_datadir)/sizeof(char) -1, "%s/cm_agent", cm_dir);
securec_check_ss_c(nRet, "\0", "\0");
} else {
if (g_currentNode->cmServerLevel == 1) {
nRet = snprintf_s(temp_datadir, sizeof(temp_datadir)/sizeof(char),
sizeof(temp_datadir)/sizeof(char) -1, "%s/cm_server", cm_dir);
securec_check_ss_c(nRet, "\0", "\0");
} else {
return;
}
}
save_expect_instance_info(temp_datadir);
if (FAILURE == do_local_guc_command(type, temp_datadir))
return;
}
******************************************************************************
Function : do_command_for_datainstance
Description :
Input : type (instance type)
indatadir (the instance data path)
Output : None
Return : void
******************************************************************************
*/
void do_command_for_cndn(int type, char* indatadir)
{
do_command_for_cn_gtm(INSTANCE_COORDINATOR, indatadir, true);
do_command_for_dn(INSTANCE_DATANODE, indatadir);
}
******************************************************************************
Function : do_command_with_instance_name_option
Description : set/reload guc parameter using "-I instance_name" option
Input : type (instance type)
indatadir (the instance data path)
Output : None
Return : void
******************************************************************************
*/
void do_command_with_instance_name_option(int type, char* instance_name)
{
if (node_type_number == LARGE_INSTANCE_NUM) {
do_command_with_instance_name_option_local(INSTANCE_COORDINATOR, instance_name);
do_command_with_instance_name_option_local(INSTANCE_DATANODE, instance_name);
} else {
do_command_with_instance_name_option_local(type, instance_name);
}
}
char *
get_cm_real_path(int type)
{
char *cmpath = NULL;
if (INSTANCE_CMSERVER == type) {
if (1 == g_node[g_local_node_idx].cmServerLevel && g_node[g_local_node_idx].cmDataPath[0] != '\0') {
cmpath = xstrdup(g_node[g_local_node_idx].cmDataPath);
} else {
write_stderr("ERROR: Failed to get cmserver instance path.\n");
exit(1);
}
} else if (INSTANCE_CMAGENT == type) {
if (g_node[g_local_node_idx].cmDataPath[0] != '\0') {
cmpath = xstrdup(g_node[g_local_node_idx].cmDataPath);
} else {
write_stderr("ERROR: Failed to get cmagent instance path.\n");
exit(1);
}
} else {
write_stderr("ERROR: the instance type is incorrect.\n");
exit(1);
}
return cmpath;
}
void do_command_with_instance_name_option_local(int type, char* instance_name)
{
char temp_datadir[MAXPGPATH];
int rc = 0;
rc = memset_s(temp_datadir, MAXPGPATH, '\0', MAXPGPATH);
securec_check_c(rc, "\0", "\0");
if (get_local_dbpath_by_instancename(instance_name, &type, temp_datadir) == CLUSTER_CONFIG_SUCCESS) {
save_expect_instance_info(temp_datadir);
if (FAILURE == do_local_guc_command(type, temp_datadir))
return;
} else {
write_stderr("ERROR: Instance name %s is incorrect.\n", instance_name);
exit(1);
}
}
******************************************************************************
Function : do_local_instance
Description : set/reload guc parameter for local node.
1. -N and -I are NULL, Only specify -D parameter
2. -N is NULL, -I is "all", specify -D parameter
3. -N is NULL, specify -D or -I parameter
Input : type (instance type)
instance_name (instance name)
indatadir (the instance data path)
Output : None
Return : void
******************************************************************************
*/
void
do_local_instance(int type, char* instance_name, char* indatadir)
{
if (NULL == instance_name) {
do_command_in_local_node(type, indatadir);
} else if (0 == strncmp(instance_name, "all", sizeof("all"))) {
do_command_with_all_option(type, indatadir);
} else {
do_command_with_instance_name_option(type, instance_name);
}
}
******************************************************************************
Function : do_remote_instance
Description : set/reload guc parameter for remote node
Input : nodename (node name)
instance_name (instance name)
indatadir (the instance data path)
Output : None
Return : void
******************************************************************************
*/
void do_remote_instance(char* nodename, const char* instance_name, const char* indatadir)
{
if (node_type_number == LARGE_INSTANCE_NUM) {
nodetype = INSTANCE_COORDINATOR;
do_remote_instance_local(nodename, instance_name, indatadir);
nodetype = INSTANCE_DATANODE;
do_remote_instance_local(nodename, instance_name, indatadir);
} else {
do_remote_instance_local(nodename, instance_name, indatadir);
}
}
void do_remote_instance_local(char* nodename, const char* instance_name, const char* indatadir)
{
char* command = NULL;
int32 nodeidx;
bool local_mode = !strncmp(g_local_node_name,
nodename,
strlen(g_local_node_name) > strlen(nodename) ? strlen(g_local_node_name) : strlen(nodename));
command = form_commandline_options(instance_name, indatadir, local_mode);
nodeidx = get_nodeidx_by_name(nodename);
if (nodeidx < 0) {
write_stderr("ERROR: Node %s not found in static config file\n", nodename);
GS_FREE(command);
exit(1);
}
(void)execute_guc_command_in_remote_node(nodeidx, command);
GS_FREE(command);
}
******************************************************************************
Function : do_all_nodes_instance
Description : set/reload guc parameter for all cluster node
Input : instance_name (instance name)
indatadir (the instance data path)
Output : None
Return : void
******************************************************************************
*/
void do_all_nodes_instance(const char* instance_name, const char* indatadir)
{
if (node_type_number == LARGE_INSTANCE_NUM) {
nodetype = INSTANCE_COORDINATOR;
do_all_nodes_instance_local(instance_name, indatadir);
nodetype = INSTANCE_DATANODE;
do_all_nodes_instance_local(instance_name, indatadir);
} else {
do_all_nodes_instance_local(instance_name, indatadir);
}
}
******************************************************************************
Function : do_all_nodes_instance_local
Description : do_all_nodes_instance_local. When do check in serial, do set/reload in parallel
Input : instance_name, indatadir
Output : void
Return : void
******************************************************************************
*/
void do_all_nodes_instance_local(const char* instance_name, const char* indatadir)
{
if (CHECK_CONF_COMMAND == ctl_command) {
do_all_nodes_instance_local_in_serial(instance_name, indatadir);
} else {
do_all_nodes_instance_local_in_parallel_loop(instance_name, indatadir);
}
}
void do_all_nodes_instance_local_in_serial(const char* instance_name, const char* indatadir)
{
uint32 idx = 0;
for (idx = 0; idx < get_num_nodes(); idx++) {
char* nodename = getnodename(idx);
bool local_mode = !strncmp(g_local_node_name,
nodename,
strlen(g_local_node_name) > strlen(nodename) ? strlen(g_local_node_name) : strlen(nodename));
char* command = form_commandline_options(instance_name, indatadir, local_mode);
(void)execute_guc_command_in_remote_node(idx, command);
GS_FREE(command);
}
}
static void init_global_command()
{
int i;
int rc = 0;
PARALLEL_COMMAND_S* curr_cxt = NULL;
g_max_commands_parallel = get_num_nodes();
g_parallel_command_cxt = (PARALLEL_COMMAND_S*)pg_malloc(g_max_commands_parallel * sizeof(PARALLEL_COMMAND_S));
rc = memset_s(g_parallel_command_cxt,
g_max_commands_parallel * sizeof(PARALLEL_COMMAND_S),
'\0',
g_max_commands_parallel * sizeof(PARALLEL_COMMAND_S));
securec_check_c(rc, "\0", "\0");
g_cur_commands_parallel = 0;
for (i = 0; i < g_max_commands_parallel; i++) {
curr_cxt = &g_parallel_command_cxt[i];
curr_cxt->cur_buf_loc = 0;
rc = memset_s(curr_cxt->readbuf, sizeof(curr_cxt->readbuf), '\0', sizeof(curr_cxt->readbuf));
securec_check_c(rc, "\0", "\0");
curr_cxt->pfp = NULL;
curr_cxt->nodename = xstrdup(getnodename((uint32)i));
}
}
static void reset_global_command()
{
int i;
for (i = 0; i < (int)g_incorrect_nodeInfo->num; i++) {
GS_FREE(g_incorrect_nodeInfo->nodename_array[i]);
}
g_incorrect_nodeInfo->num = 0;
g_cur_commands_parallel = 0;
}
static void do_all_nodes_instance_local_in_parallel_loop(const char* instance_name, const char* indatadir)
{
int i;
init_global_command();
write_stderr("Begin to perform the total nodes: %d.\n", g_max_commands_parallel);
for (i = 0; i < LOOP_COUNT; i++) {
do_all_nodes_instance_local_in_parallel(instance_name, indatadir);
if (g_incorrect_nodeInfo->num == 0 || i == LOOP_COUNT - 1) {
break;
}
write_stderr("Retry to perform the failed nodes: %d.\n", (int32)g_incorrect_nodeInfo->num);
reset_global_command();
(void)SleepInMilliSec(100);
}
for (i = 0; i < g_max_commands_parallel; i++) {
GS_FREE(g_parallel_command_cxt[i].nodename);
}
GS_FREE(g_parallel_command_cxt);
if (g_incorrect_nodeInfo->num == 0) {
(void)write_stderr("ALL: Success to perform gs_guc!\n\n");
}
else {
(void)write_stderr("ALL: Failure to perform gs_guc!\n\n");
exit(1);
}
}
static bool needPassNode(const char* nodename)
{
int cmpLen = 0;
char* ignoreNode = NULL;
for (uint32 i = 0; i < g_ignore_nodeInfo->num; i++) {
ignoreNode = g_ignore_nodeInfo->nodename_array[i];
cmpLen = (strlen(ignoreNode) > strlen(nodename)) ? strlen(ignoreNode) : strlen(nodename);
if (strncmp(ignoreNode, nodename, cmpLen) == 0) {
return true;
}
}
return false;
}
void do_all_nodes_instance_local_in_parallel(const char* instance_name, const char* indatadir)
{
int idx = 0;
char* nodename = NULL;
int buf_len = 0;
bool if_for_all_instance = true;
int open_count = 0;
bool is_local_node = false;
char* command_local = form_commandline_options(instance_name, indatadir, true);
char* command_remote = form_commandline_options(instance_name, indatadir, false);
if ((instance_name != NULL) && (strncmp(instance_name, "all", sizeof("all")) != 0)) {
if_for_all_instance = false;
}
for (idx = 0; idx < g_max_commands_parallel; idx++) {
if (if_for_all_instance == false && validate_instance_name_for_DN(idx, instance_name) == false) {
continue;
}
* When instance type is INSTANCE_CMSERVER, only the nodes that contain the cm_server instance are setting.
* When instance type is INSTANCE_GTM/INSTANCE_COORDINATOR/INSTANCE_DATANODE, only the nodes that contain the gtm instance are setting.
*/
if ((nodetype == INSTANCE_CMSERVER && 1 != g_node[idx].cmServerLevel) ||
(nodetype == INSTANCE_GTM && 1 != g_node[idx].gtm) ||
(nodetype == INSTANCE_COORDINATOR && 1 != g_node[idx].coordinate) ||
(nodetype == INSTANCE_DATANODE && 0 == g_node[idx].datanodeCount)) {
continue;
}
if (NULL == g_parallel_command_cxt[idx].nodename) {
continue;
}
nodename = g_parallel_command_cxt[idx].nodename;
if ((g_ignore_nodeInfo != NULL) && needPassNode(nodename)) {
continue;
}
open_count++;
buf_len = (strlen(g_local_node_name) > strlen(nodename)) ? strlen(g_local_node_name) : strlen(nodename);
is_local_node = (0 == strncmp(g_local_node_name, nodename, buf_len)) ? true : false;
is_local_node ? executePopenCommandsParallel(command_local, idx, is_local_node) :
executePopenCommandsParallel(command_remote, idx, is_local_node);
}
write_stderr("Popen count is %d, Popen success count is %d, Popen failure count is %d.\n",
open_count, g_cur_commands_parallel, (int)g_incorrect_nodeInfo->num);
readPopenOutputParallel(command_local, if_for_all_instance);
GS_FREE(command_local);
GS_FREE(command_remote);
}
* Execute commands in parallel
*/
static void executePopenCommandsParallel(const char* cmd, int idx, bool is_local_node)
{
int rc = 0;
PARALLEL_COMMAND_S* curr_cxt = NULL;
char* fcmd = NULL;
char* mpprvFile = NULL;
int nRet = 0;
size_t len_fcmd = 0;
char* nodename = NULL;
char gausshome[MAXPGPATH] = {0};
curr_cxt = &g_parallel_command_cxt[idx];
nodename = g_parallel_command_cxt[idx].nodename;
curr_cxt->cur_buf_loc = 0;
rc = memset_s(curr_cxt->readbuf, sizeof(curr_cxt->readbuf), '\0', sizeof(curr_cxt->readbuf));
securec_check_c(rc, "\0", "\0");
len_fcmd = strlen(cmd) + strlen(nodename) + NAMEDATALEN + MAXPGPATH;
if (!get_env_value("GAUSSHOME", gausshome, sizeof(gausshome) / sizeof(char))) {
return;
}
check_env_value(gausshome);
mpprvFile = GetEnvStr("MPPDB_ENV_SEPARATE_PATH");
if (mpprvFile == NULL) {
fcmd = (char*)pg_malloc_zero(len_fcmd);
nRet = is_local_node ? snprintf_s(fcmd, len_fcmd, len_fcmd - 1, "%s 2>&1", cmd) :
snprintf_s(fcmd, len_fcmd, len_fcmd - 1, "pssh -s -H %s \"%s\" 2>&1", nodename, cmd);
} else {
if (MAXPGPATH <= strlen(mpprvFile)) {
write_stderr("ERROR: The value of environment variable \"MPPDB_ENV_SEPARATE_PATH\" is too long.");
GS_FREE(mpprvFile);
return;
}
check_env_value(mpprvFile);
len_fcmd = len_fcmd + (int)strlen(mpprvFile);
fcmd = (char*)pg_malloc_zero(len_fcmd);
nRet = is_local_node ? snprintf_s(fcmd, len_fcmd, len_fcmd - 1, "source %s; %s 2>&1", mpprvFile, cmd) :
snprintf_s(fcmd, len_fcmd, len_fcmd - 1, "pssh -s -H %s \"source %s; %s\" 2>&1", nodename, mpprvFile, cmd);
}
securec_check_ss_c(nRet, fcmd, "\0");
curr_cxt->pfp = popen(fcmd, "r");
GS_FREE(fcmd);
GS_FREE(mpprvFile);
if (NULL != curr_cxt->pfp) {
g_cur_commands_parallel++;
uint32 flags;
int fd = fileno(curr_cxt->pfp);
flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
(void)fcntl(fd, F_SETFL, flags);
}
else {
g_incorrect_nodeInfo->nodename_array[g_incorrect_nodeInfo->num++] = xstrdup(curr_cxt->nodename);
}
return;
}
* read popen output parallel
*/
static void readPopenOutputParallel(const char* cmd, bool if_for_all_instance)
{
int rc = 0;
int idx = 0;
bool read_pending = true;
char* result = NULL;
PARALLEL_COMMAND_S* curr_cxt = g_parallel_command_cxt;
int i = 0;
char* endsp = NULL;
int successNumber = 0;
int failedNumber = 0;
int instance_nums = 0;
uint32 ret = 0;
if (nodetype == INSTANCE_COORDINATOR) {
instance_nums = get_all_coordinator_num();
write_stderr("Begin to perform gs_guc for coordinators.\n");
} else if (nodetype == INSTANCE_DATANODE) {
instance_nums = get_all_datanode_num();
write_stderr("Begin to perform gs_guc for datanodes.\n");
} else if (nodetype == INSTANCE_CMSERVER) {
instance_nums = get_all_cmserver_num();
write_stderr("Begin to perform gs_guc for cm_servers.\n");
} else if (nodetype == INSTANCE_CMAGENT) {
instance_nums = get_all_cmagent_num();
write_stderr("Begin to perform gs_guc for cm_agents.\n");
} else {
instance_nums = get_all_gtm_num();
write_stderr("Begin to perform gs_guc for gtms.\n");
}
result = (char*)pg_malloc_zero(MAX_P_READ_BUF + 1);
while (true == read_pending) {
read_pending = false;
for (idx = 0; idx < g_max_commands_parallel; idx++) {
curr_cxt = g_parallel_command_cxt + idx;
if (NULL == curr_cxt->pfp) {
continue;
}
if (NULL == curr_cxt->nodename) {
continue;
}
errno = 0;
if (fgets(result, MAX_P_READ_BUF - 1, curr_cxt->pfp) != NULL) {
int len = strlen(result);
int hasnewline = false;
read_pending = true;
if (len > 1 && result[len - 1] == '\n') {
hasnewline = true;
} else if ((curr_cxt->cur_buf_loc + len + 1) < (int)sizeof(curr_cxt->readbuf)) {
rc = strncpy_s(curr_cxt->readbuf + curr_cxt->cur_buf_loc,
sizeof(curr_cxt->readbuf) - curr_cxt->cur_buf_loc,
result,
len + 1);
securec_check_c(rc, "\0", "\0");
curr_cxt->cur_buf_loc += len;
continue;
}
curr_cxt->readbuf[0] = '\0';
curr_cxt->cur_buf_loc = 0;
endsp = strstr(result, "WARNING");
if (NULL != endsp) {
(void)write_stderr("%s", result);
}
endsp = strstr(result, "Success to perform gs_guc");
if (NULL != endsp) {
successNumber++;
if (NULL != curr_cxt->pfp) {
curr_cxt->retvalue = pclose(curr_cxt->pfp);
curr_cxt->pfp = NULL;
GS_FREE(curr_cxt->nodename);
curr_cxt->nodename = NULL;
}
}
endsp = strstr(result, "Failure to perform gs_guc");
if (NULL != endsp) {
failedNumber++;
g_incorrect_nodeInfo->nodename_array[g_incorrect_nodeInfo->num++] = xstrdup(curr_cxt->nodename);
if (NULL != curr_cxt->pfp) {
curr_cxt->retvalue = pclose(curr_cxt->pfp);
curr_cxt->pfp = NULL;
ret = (uint32)curr_cxt->retvalue;
g_remote_command_result = WEXITSTATUS(ret);
printExecErrorMesg(cmd, curr_cxt->nodename);
}
}
}
else if (errno == EAGAIN) {
read_pending = true;
(void)SleepInMilliSec(100);
continue;
}
else {
curr_cxt->retvalue = pclose(curr_cxt->pfp);
curr_cxt->pfp = NULL;
failedNumber++;
g_incorrect_nodeInfo->nodename_array[g_incorrect_nodeInfo->num++] = xstrdup(curr_cxt->nodename);
if (curr_cxt->retvalue != 0) {
ret = (uint32)curr_cxt->retvalue;
g_remote_command_result = WEXITSTATUS(ret);
printExecErrorMesg(cmd, curr_cxt->nodename);
}
else {
(void)write_stderr("Exception: Failed to get the result from the node %s.\n", curr_cxt->nodename);
}
}
}
if ((successNumber + failedNumber - g_cur_commands_parallel) >= 0) {
break;
}
if (!read_pending) {
(void)write_stderr("Exception: There are some nodes not executed. %d %d %d\n",
successNumber, failedNumber, g_cur_commands_parallel);
}
(void)SleepInMilliSec(100);
}
(void)write_stderr("Command count is %d, Command success count is %d, Command failure count is %d.\n",
g_cur_commands_parallel, successNumber, failedNumber);
if (0 != failedNumber) {
for (idx = 0; idx < g_max_commands_parallel; idx++) {
curr_cxt = g_parallel_command_cxt + idx;
if (NULL == curr_cxt->pfp) {
continue;
}
* Wait for other nodes to complete, otherwise there will be residual processes.
*/
curr_cxt->retvalue = pclose(curr_cxt->pfp);
}
GS_FREE(result);
if (if_for_all_instance == false) {
(void)write_stderr("\nTotal nodes: %d. Effective nodes: %d. Failed nodes: %u.\n",
g_cur_commands_parallel,
successNumber + failedNumber,
g_incorrect_nodeInfo->num);
} else {
(void)write_stderr(
"\nTotal nodes: %d. Failed nodes: %u.\n", g_max_commands_parallel, g_incorrect_nodeInfo->num);
}
(void)write_stderr("Failed node names:\n");
for (i = 0; i < (int32)g_incorrect_nodeInfo->num; i++) {
(void)write_stderr(" [%s]\n", g_incorrect_nodeInfo->nodename_array[i]);
}
}
GS_FREE(result);
if (g_incorrect_nodeInfo->num == 0) {
if (if_for_all_instance == false) {
(void)write_stderr("\nTotal nodes: %d. Effective nodes: %d. Failed nodes: %u.\n",
g_max_commands_parallel,
successNumber + failedNumber,
g_incorrect_nodeInfo->num);
} else {
(void)write_stderr("\nTotal instances: %d. Failed instances: 0.\n", instance_nums);
}
}
}
static void SleepInMilliSec(uint32_t sleepMs)
{
struct timespec ts;
ts.tv_sec = (sleepMs - (sleepMs % 1000)) / 1000;
ts.tv_nsec = (sleepMs % 1000) * 1000;
(void)nanosleep(&ts, NULL);
}
******************************************************************************
Function : create_tmp_dir
Description : create a temp directory
Input : pathdir (dirctory name)
Output : None
Return : void
******************************************************************************
*/
void create_tmp_dir(const char* pathdir)
{
if (NULL == pathdir) {
(void)write_stderr(_("ERROR: failed to create a temp directory: invalid path <NULL>. \n"));
exit(1);
}
if (-1 == access(pathdir, F_OK)) {
if (mkdir(pathdir, 0700) < 0) {
(void)write_stderr(_("ERROR: could not create directory \"%s\": %s.\n"), pathdir, strerror(errno));
exit(1);
}
}
if (-1 == access(pathdir, R_OK | W_OK)) {
(void)write_stderr(_("ERROR: Could not access the specified log path: %s\n"), pathdir);
exit(1);
}
}
******************************************************************************
Function : remove_tmp_dir
Description : remove the temp directory
Input : pathdir (dirctory name)
Output : None
Return : void
******************************************************************************
*/
void remove_tmp_dir(const char* pathdir)
{
char cmd[MAXPGPATH] = {0};
int nRet = 0;
if (-1 != access(pathdir, R_OK | W_OK)) {
nRet = snprintf_s(cmd, sizeof(cmd), sizeof(cmd) - 1, "rm -rf %s", pathdir);
securec_check_ss_c(nRet, "", "");
nRet = gs_system(cmd);
if (nRet != 0) {
(void)write_stderr(_("ERROR: Could not delete directory \"%s\": %s\n"), pathdir, strerror(errno));
exit(1);
}
}
}
******************************************************************************
Function : execute_guc_command_in_remote_node
Description :
Input : idx - node id index
command - gs_guc execute command
Output : None
Return : None
******************************************************************************
*/
int execute_guc_command_in_remote_node(int idx, char* command)
{
char* nodename = getnodename(idx);
char* fcmd = NULL;
char* mpprvFile = NULL;
size_t len_fcmd = strlen(command) + strlen(nodename) + NAMEDATALEN + MAXPGPATH;
int nRet = 0;
uint32 ret = 0;
char gausshome[MAXPGPATH] = {0};
char sshlogpathdir[MAXPGPATH] = {0};
char result_file[MAXPGPATH] = {0};
int pid = 0;
time_t tick;
if (!get_env_value("GAUSSHOME", gausshome, sizeof(gausshome) / sizeof(char)))
return 1;
check_env_value(gausshome);
pid = getpid();
tick = time(NULL);
nRet = snprintf_s(sshlogpathdir, MAXPGPATH, MAXPGPATH - 1, "%s/gs_guc_psshlog_%d_%d", gausshome, (int)tick, pid);
securec_check_ss_c(nRet, "", "");
create_tmp_dir((const char*)sshlogpathdir);
nRet = snprintf_s(result_file, MAXPGPATH, MAXPGPATH - 1, "%s/%s", sshlogpathdir, nodename);
securec_check_ss_c(nRet, "", "");
mpprvFile = GetEnvStr("MPPDB_ENV_SEPARATE_PATH");
if (mpprvFile == NULL) {
fcmd = (char*)pg_malloc_zero(len_fcmd);
if (0 != strncmp(g_local_node_name,
nodename,
strlen(g_local_node_name) > strlen(nodename) ? strlen(g_local_node_name) : strlen(nodename))) {
nRet = snprintf_s(
fcmd, len_fcmd, len_fcmd - 1, "pssh -s -H %s \"%s\" >%s 2>&1", nodename, command, result_file);
} else {
nRet = snprintf_s(fcmd, len_fcmd, len_fcmd - 1, "%s >%s 2>&1", command, result_file);
}
} else {
if (MAXPGPATH <= strlen(mpprvFile)) {
write_stderr("ERROR: The value of environment variable \"MPPDB_ENV_SEPARATE_PATH\" is too long.");
GS_FREE(mpprvFile);
return 1;
}
check_env_value(mpprvFile);
len_fcmd = len_fcmd + (int)strlen(mpprvFile);
fcmd = (char*)pg_malloc_zero(len_fcmd);
if (0 != strncmp(g_local_node_name,
nodename,
strlen(g_local_node_name) > strlen(nodename) ? strlen(g_local_node_name) : strlen(nodename))) {
nRet = snprintf_s(fcmd,
len_fcmd,
len_fcmd - 1,
"pssh -s -H %s \"source %s; %s\" >%s 2>&1",
nodename,
mpprvFile,
command,
result_file);
} else {
nRet = snprintf_s(fcmd, len_fcmd, len_fcmd - 1, "source %s; %s >%s 2>&1", mpprvFile, command, result_file);
}
}
securec_check_ss_c(nRet, fcmd, "\0");
ret = (uint32)gs_system(fcmd);
g_remote_command_result = WEXITSTATUS(ret);
printExecErrorMesg(fcmd, nodename);
GS_FREE(fcmd);
GS_FREE(mpprvFile);
if (g_remote_command_result == 255 || g_remote_command_result == 127) {
g_remote_connection_signal = false;
g_incorrect_nodeInfo->nodename_array[g_incorrect_nodeInfo->num++] = xstrdup(nodename);
remove_tmp_dir(sshlogpathdir);
return 1;
}
if (g_remote_command_result == 1) {
save_remote_instance_info(result_file, nodename, command, g_expect_gucInfo, false);
} else {
save_remote_instance_info(result_file, nodename, command, g_expect_gucInfo, false);
save_remote_instance_info(result_file, nodename, command, g_real_gucInfo, true);
}
remove_tmp_dir(sshlogpathdir);
return 0;
}
******************************************************************************
Function : is_information_exists
Description : check the instance information whether have been storaged or not
Input : nodename - node name
gucfile - the instance guc config file
Output : None
Return : true the information has been in global parameter
false the information doesn't not in global parameter
******************************************************************************
*/
bool is_information_exists(const char* nodename, const char* gucfile)
{
uint32 i = 0;
for (i = 0; i < g_real_gucInfo->nodename_num; i++) {
if (NULL != g_real_gucInfo->nodename_array[i] && NULL != g_real_gucInfo->gucinfo_array[i]) {
if ((0 == strcmp(g_real_gucInfo->nodename_array[i], nodename)) &&
(0 == strcmp(g_real_gucInfo->gucinfo_array[i], gucfile)))
return true;
}
}
return false;
}
******************************************************************************
Function : get_keywords
Description : get keywords from the command, the information is used for analysis gs_guc
Input : command
Output : None
Return : keywords
******************************************************************************
*/
char* get_keywords(char* command)
{
char* keywords = NULL;
if (!is_hba_conf) {
if (strstr(command, " set ") != NULL)
keywords = xstrdup("gs_guc set:");
else if (strstr(command, " reload ") != NULL)
keywords = xstrdup("gs_guc reload:");
else
keywords = xstrdup("gs_guc check:");
} else {
if (strstr(command, " set ") != NULL)
keywords = xstrdup("gs_guc sethba:");
else
keywords = xstrdup("gs_guc reloadhba:");
}
return keywords;
}
void save_parameter_info(char* buffer, gucInfo* guc_info)
{
char* p1 = NULL;
char* p = NULL;
char* tmp_str = NULL;
char* ptr = NULL;
char* outer_ptr = NULL;
* The result type of check
* expected guc information: NodeName: max_connections=NULL: [$PATH]
* gs_guc check: NodeName: pamameter=value: [$PATH]
*/
p1 = strstr(buffer, ":");
if (NULL == p1)
return;
p1++;
p = strstr(p1, ":");
if (NULL == p)
return;
p++;
while (isspace((unsigned char)*p))
p++;
tmp_str = xstrdup(p);
* split with ':', get the result information "parameter=value"
* split with '=', get parameter and value
* both this two, we can makesure the point ptr is not NULL.
*/
ptr = strrchr(tmp_str, ':');
if (NULL == ptr) {
GS_FREE(tmp_str);
return;
}
*ptr = '\0';
ptr = strtok_r(tmp_str, "=", &outer_ptr);
if (NULL == ptr) {
GS_FREE(tmp_str);
return;
}
guc_info->paramname_array[guc_info->paramname_num++] = xstrdup(ptr);
guc_info->paramvalue_array[guc_info->paramvalue_num++] = xstrdup(outer_ptr);
GS_FREE(tmp_str);
}
******************************************************************************
Function : save_remote_instance_info
Description : save the instance information which parse from the result file that
do remote gs_guc set/reload into global parameter
Input : nodename - node name
result_file - the instance guc config file
command - the execute commands
gucInfo - struct of guc information
isRealGucInfo - the struct kind
Output : None
Return : void
******************************************************************************
*/
void save_remote_instance_info(
const char* result_file, const char* nodename, char* command, gucInfo* guc_info, bool isRealGucInfo)
{
char** all_lines = NULL;
char** line = NULL;
char gucfile[MAXPGPATH] = {0};
char* keywords = NULL;
char* p = NULL;
char* tmp_str = NULL;
bool is_found = false;
int nRet = 0;
all_lines = readfile(result_file, 0);
if (NULL == all_lines) {
write_stderr(_("Failed to read file %s. ERROR: %s\n"), result_file, strerror(errno));
exit(1);
}
if (isRealGucInfo)
keywords = get_keywords(command);
else
keywords = xstrdup("expected ");
if (NULL == keywords) {
write_stderr(_("Failed to get key words.\n"));
exit(1);
}
line = all_lines;
while (*line != NULL) {
if (strstr(*line, keywords) != NULL) {
p = *line;
is_found = false;
if ((int)strlen(p) > MAX_VALUE_LEN) {
(void)write_stderr(_("ERROR: The content of line is too long. Please check and make sure it is "
"correct.\nThe content is \"%s\".\n"), p);
exit(1);
}
* If we want to parse the result, we must find the position of '['
* The result type of set/reload
* expected instance path: [$PATH]
* gs_guc set: pamameter=value: [$PATH]
* The result type of check
* expected guc information: NodeName: max_connections=NULL: [$PATH]
* gs_guc check: NodeName: pamameter=value: [$PATH]
*/
while (*p && !(*p == '\n' || *p == '[')) {
if (*p == '\'') {
while (*(++p) && !(*p == '\n' || *p == '\''));
}
p++;
}
if (*p == '[') {
is_found = true;
p++;
}
while (isspace((unsigned char)*p))
p++;
if (is_found && *p == '/') {
if (0 == strncmp(p, "/postgresql.conf", strlen("/postgresql.conf")) ||
0 == strncmp(p, "/pg_hba.conf", strlen("/pg_hba.conf")) ||
0 == strncmp(p, "/cm_server.conf", strlen("/cm_server.conf")) ||
0 == strncmp(p, "/cm_agent.conf", strlen("/cm_agent.conf")) ||
0 == strncmp(p, "/gtm.conf", strlen("/gtm.conf")))
continue;
nRet = strncpy_s(gucfile, sizeof(gucfile) / sizeof(char), p, ((int)strlen(p) - 2));
securec_check_c(nRet, "\0", "\0");
if (CHECK_CONF_COMMAND == ctl_command) {
guc_info->nodename_array[guc_info->nodename_num++] = xstrdup(nodename);
guc_info->gucinfo_array[guc_info->gucinfo_num++] = xstrdup(gucfile);
tmp_str = xstrdup(*line);
(void)save_parameter_info(tmp_str, guc_info);
GS_FREE(tmp_str);
} else {
if (!is_information_exists(nodename, gucfile)) {
guc_info->nodename_array[guc_info->nodename_num++] = xstrdup(nodename);
guc_info->gucinfo_array[guc_info->gucinfo_num++] = xstrdup(gucfile);
}
}
}
}
line++;
}
GS_FREE(keywords);
freefile(all_lines);
}
******************************************************************************
Function : get_guc_option
Description : write guc option informations into guc_opt
******************************************************************************
*/
char** get_guc_option()
{
char** guc_line_info = NULL;
if (nodetype == INSTANCE_COORDINATOR) {
guc_line_info = get_guc_line_info((const char**)cndn_guc_info);
} else if (nodetype == INSTANCE_DATANODE) {
if (NULL != g_lcname) {
guc_line_info = get_guc_line_info((const char**)lc_guc_info);
} else {
guc_line_info = get_guc_line_info((const char**)cndn_guc_info);
}
} else if (nodetype == INSTANCE_CMSERVER) {
guc_line_info = get_guc_line_info((const char**)cmserver_guc_info);
} else if (nodetype == INSTANCE_CMAGENT) {
guc_line_info = get_guc_line_info((const char**)cmagent_guc_info);
} else if (nodetype == INSTANCE_GTM) {
guc_line_info = get_guc_line_info((const char**)gtm_guc_info);
} else {
write_stderr(_("%s: unrecognized -Z parameter.\n"), progname);
exit(1);
}
return guc_line_info;
}
************************************************************************************
Function: get_guc_line_info
Desc : get guc parameter infomation
************************************************************************************
*/
char** get_guc_line_info(const char** optlines)
{
int nRet = 0;
int i = 0;
int j = 0;
char* p = NULL;
char* q = NULL;
char tmp_paraname[MAX_PARAM_LEN] = {0};
char new_paraname[MAX_PARAM_LEN] = {0};
int paramlen = 0;
char** guc_opt = NULL;
guc_opt = (char**)pg_malloc_zero(config_param_number * sizeof(char*));
for (i = 0; i < config_param_number; i++) {
guc_opt[i] = (char*)pg_malloc_zero(MAX_LINE_LEN * sizeof(char));
}
if (NULL == optlines) {
(void)write_stderr("ERROR: Faile to read file \"%s\".\n", "cluster_guc.conf");
for (i = 0; i < config_param_number; i++) {
GS_FREE(guc_opt[i]);
}
GS_FREE(guc_opt);
return NULL;
}
for (i = 0; optlines[i] != NULL; i++) {
p = (char*)optlines[i];
while (isspace((unsigned char)*p))
p++;
q = p;
if (*p == '#' || *p == '[')
continue;
for (j = 0; j < config_param_number; j++) {
nRet = memset_s(tmp_paraname, MAX_PARAM_LEN, '\0', MAX_PARAM_LEN);
securec_check_c(nRet, "\0", "\0");
make_string_tolower(config_param[j], tmp_paraname, sizeof(tmp_paraname) / sizeof(char));
nRet = snprintf_s(new_paraname, MAX_PARAM_LEN, MAX_PARAM_LEN - 1, "%s|", tmp_paraname);
securec_check_ss_c(nRet, "\0", "\0");
paramlen = strnlen(new_paraname, MAX_PARAM_LEN);
if (0 != strncmp(p, new_paraname, paramlen))
continue;
nRet = snprintf_s(guc_opt[j], MAX_LINE_LEN, MAX_LINE_LEN - 1, "%s", q);
securec_check_ss_c(nRet, "\0", "\0");
}
}
return guc_opt;
}
************************************************************************************
Function: get_guc_type
Desc : get guc parameter type
Return : UnitType
************************************************************************************
*/
GucParaType get_guc_type(const char* type)
{
if (0 == strncmp(type, "bool", strlen("bool")))
return GUC_PARA_BOOL;
else if (0 == strncmp(type, "real", strlen("real")))
return GUC_PARA_REAL;
else if (0 == strncmp(type, "int", strlen("int")))
return GUC_PARA_INT;
else if (0 == strncmp(type, "enum", strlen("enum")))
return GUC_PARA_ENUM;
else if (0 == strncmp(type, "string", strlen("string")))
return GUC_PARA_STRING;
else if (0 == strncmp(type, "int64", strlen("int64")))
return GUC_PARA_INT64;
else
return GUC_PARA_ERROR;
}
************************************************************************************
Function: get_guc_unit
Desc : get guc parameter unit
Return : UnitType
************************************************************************************
*/
UnitType get_guc_unit(const char* unit)
{
if (0 == strncmp(unit, "kB", strlen("kB")))
return UNIT_KB;
else if (0 == strncmp(unit, "MB", strlen("MB")))
return UNIT_MB;
else if (0 == strncmp(unit, "GB", strlen("GB")))
return UNIT_GB;
else if (0 == strncmp(unit, "ms", strlen("ms")))
return UNIT_MS;
else if (0 == strncmp(unit, "s", strlen("s")))
return UNIT_S;
else if (0 == strncmp(unit, "min", strlen("min")))
return UNIT_MIN;
else if (0 == strncmp(unit, "h", strlen("h")))
return UNIT_H;
else if (0 == strncmp(unit, "d", strlen("d")))
return UNIT_D;
else
return UNIT_ERROR;
}
************************************************************************************
Function: do_gucopt_parse
Desc : according to guc option line information, parse them into struct
guc_config_enum_entry
Return : SUCCESS
FAILURE
************************************************************************************
*/
int do_gucopt_parse(const char* guc_opt, struct guc_config_enum_entry& guc_variable_list)
{
char opts[MAX_LINE_LEN];
int nRet = 0;
char* ptr = NULL;
char* outer_ptr = NULL;
char delims[] = "|";
GucParaType type_val = GUC_PARA_ERROR;
nRet = memset_s(opts, MAX_LINE_LEN, '\0', MAX_LINE_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = snprintf_s(opts, MAX_LINE_LEN, MAX_LINE_LEN - 1, "%s", guc_opt);
securec_check_ss_c(nRet, "\0", "\0");
ptr = strtok_r(opts, delims, &outer_ptr);
if (NULL != ptr) {
nRet = snprintf_s(guc_variable_list.guc_name, MAX_PARAM_LEN, MAX_PARAM_LEN - 1, "%s", ptr);
securec_check_ss_c(nRet, "\0", "\0");
}
ptr = strtok_r(NULL, delims, &outer_ptr);
if (NULL != ptr) {
type_val = get_guc_type(ptr);
if (GUC_PARA_ERROR == type_val) {
(void)write_stderr("ERROR: Failed to parse the guc \"%s\" option. The type \"%s\" is incorrect.\n",
guc_variable_list.guc_name,
ptr);
return FAILURE;
}
guc_variable_list.type = type_val;
}
ptr = strtok_r(NULL, delims, &outer_ptr);
if (NULL != ptr) {
nRet = snprintf_s(guc_variable_list.guc_value, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", ptr);
securec_check_ss_c(nRet, "\0", "\0");
} else {
(void)write_stderr(
"ERROR: Failed to parse the guc \"%s\" option. The value range information \"%s\" is incorrect.\n",
guc_variable_list.guc_name,
ptr);
return FAILURE;
}
ptr = strtok_r(NULL, delims, &outer_ptr);
if (NULL != ptr) {
if (0 == strncmp(ptr, "NULL", strlen("NULL"))) {
nRet = memset_s(guc_variable_list.guc_unit, MAX_UNIT_LEN, '\0', MAX_UNIT_LEN);
securec_check_c(nRet, "\0", "\0");
} else {
nRet = snprintf_s(guc_variable_list.guc_unit, MAX_UNIT_LEN, MAX_UNIT_LEN - 1, "%s", ptr);
securec_check_ss_c(nRet, "\0", "\0");
}
} else {
(void)write_stderr("ERROR: Failed to parse the guc \"%s\" option. The parameter unit is incorrect.\n",
guc_variable_list.guc_name);
return FAILURE;
}
ptr = strtok_r(NULL, delims, &outer_ptr);
if (NULL != ptr) {
if (0 == strncmp(ptr, "NULL", strlen("NULL"))) {
nRet = memset_s(guc_variable_list.message, MAX_MESG_LEN, '\0', MAX_MESG_LEN);
securec_check_c(nRet, "\0", "\0");
} else {
nRet = snprintf_s(guc_variable_list.message, MAX_MESG_LEN, MAX_MESG_LEN - 1, "%s", ptr);
securec_check_ss_c(nRet, "\0", "\0");
}
} else {
(void)write_stderr(
"ERROR: Failed to parse the guc \"%s\" option. The parameter relation message is incorrect.\n",
guc_variable_list.guc_name);
return FAILURE;
}
ptr = strtok_r(NULL, delims, &outer_ptr);
if (NULL != ptr && '\n' != ptr[0]) {
(void)write_stderr("ERROR: The guc \"%s\" options is incorrect.\n", guc_variable_list.guc_name);
return FAILURE;
}
return SUCCESS;
}
************************************************************************************
Function: check_parameter_name
Desc : according to guc option line information, check the parameter name
guc_opt guc information list
Return : SUCCESS
FAILURE
************************************************************************************
*/
int check_parameter_name(char** guc_opt, int type)
{
int i = 0;
bool is_failed = false;
if (false == check_parameter_is_valid(type))
return FAILURE;
else
return SUCCESS;
for (i = 0; i < config_param_number; i++) {
if (NULL == guc_opt[i] || '\0' == guc_opt[i][0]) {
is_failed = true;
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect. Please check if the parameters are "
"within the required range.\n",
config_param[i]);
}
}
if (is_failed)
return FAILURE;
else
return SUCCESS;
}
************************************************************************************
Function: check_parameter_is_valid
Desc : according to guc option line information, check the parameter name
guc_opt guc information list
Return : SUCCESS
FAILURE
************************************************************************************
*/
bool check_cn_dn_parameter_is_valid()
{
int para_num = 0;
bool is_valid = false;
bool all_valid = true;
int len = 0;
char tmp[MAX_PARAM_LEN] = {0};
int nRet = 0;
for (para_num = 0; para_num < config_param_number; para_num++) {
nRet = memset_s(tmp, MAX_PARAM_LEN, '\0', MAX_PARAM_LEN);
securec_check_c(nRet, "\0", "\0");
make_string_tolower(config_param[para_num], tmp, sizeof(tmp) / sizeof(char));
is_valid = false;
if (NULL != g_lcname) {
for (int i = 0; i < lc_param_number; i++) {
len = strlen(tmp) > strlen(lc_param[i]) ? strlen(tmp) : strlen(lc_param[i]);
if (0 == strncmp(tmp, lc_param[i], len)) {
is_valid = true;
break;
}
}
if (is_valid == false) {
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect. It is not within the logical "
"cluster support parameters.\n",
config_param[para_num]);
all_valid = false;
}
} else {
for (int i = 0; i < cndn_param_number; i++) {
len = strlen(tmp) > strlen(cndn_param[i]) ? strlen(tmp) : strlen(cndn_param[i]);
if (0 == strncmp(tmp, cndn_param[i], len)) {
is_valid = true;
break;
}
}
if (is_valid == false) {
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect. It is not within the CN/DN "
"support parameters or it is a read only parameter.\n",
config_param[para_num]);
all_valid = false;
} else if (strncmp(tmp, "enableseparationofduty", strlen("enableseparationofduty")) == 0) {
(void)write_stderr("WARNING: please take care of the actual privileges of the users "
"while changing enableSeparationOfDuty.\n");
}
#ifndef USE_ASSERT_CHECKING
char* distribute_test_param = "distribute_test_param";
len = strlen(tmp) > strlen(distribute_test_param) ? strlen(tmp) : strlen(distribute_test_param);
if (0 == strncmp(tmp, distribute_test_param, len)) {
all_valid = false;
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect."
"not work on this mode.\n",
config_param[para_num]);
}
char* segmentTestParam = "segment_test_param";
len = (strlen(tmp) > strlen(segmentTestParam)) ? strlen(tmp) : strlen(segmentTestParam);
if (strncmp(tmp, segmentTestParam, len) == 0) {
all_valid = false;
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect."
"not work on this mode.\n",
config_param[para_num]);
}
char* memCtxCheckParam = "enable_memory_context_check_debug";
len = (strlen(tmp) > strlen(memCtxCheckParam)) ? strlen(tmp) : strlen(memCtxCheckParam);
if (strncmp(tmp, memCtxCheckParam, len) == 0) {
all_valid = false;
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect."
"not work on this mode.\n",
config_param[para_num]);
}
#endif
#ifdef ENABLE_FINANCE_MODE
char* enableUstore = "enable_ustore";
len = strlen(tmp) > strlen(enableUstore) ? strlen(tmp) : strlen(enableUstore);
if (0 == strncmp(tmp, enableUstore, len)) {
all_valid = false;
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect. "
"not work on finance mode.\n",
config_param[para_num]);
}
char* enableTde = "enable_tde";
len = (strlen(tmp) > strlen(enableTde)) ? strlen(tmp) : strlen(enableTde);
if (strncmp(tmp, enableTde, len) == 0) {
all_valid = false;
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect. "
"not work on finance mode.\n",
config_param[para_num]);
}
char* queryDop = "query_dop";
len = (strlen(tmp) > strlen(queryDop)) ? strlen(tmp) : strlen(queryDop);
if (strncmp(tmp, queryDop, len) == 0) {
all_valid = false;
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect. "
"not work on finance mode.\n",
config_param[para_num]);
}
char* enableDcf = "enable_dcf";
len = (strlen(tmp) > strlen(enableDcf)) ? strlen(tmp) : strlen(enableDcf);
if (strncmp(tmp, enableDcf, len) == 0) {
all_valid = false;
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect. "
"not work on finance mode.\n",
config_param[para_num]);
}
char* vectorEngineStrategy = "try_vector_engine_strategy";
len = (strlen(tmp) > strlen(vectorEngineStrategy)) ? strlen(tmp) : strlen(vectorEngineStrategy);
if (strncmp(tmp, vectorEngineStrategy, len) == 0) {
all_valid = false;
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect. "
"not work on finance mode.\n",
config_param[para_num]);
}
#endif
}
}
return all_valid;
}
bool check_gtm_parameter_is_valid()
{
int para_num = 0;
bool is_valid = false;
bool all_valid = true;
int len = 0;
char tmp[MAX_PARAM_LEN] = {0};
int nRet = 0;
for (para_num = 0; para_num < config_param_number; para_num++) {
nRet = memset_s(tmp, MAX_PARAM_LEN, '\0', MAX_PARAM_LEN);
securec_check_c(nRet, "\0", "\0");
make_string_tolower(config_param[para_num], tmp, sizeof(tmp) / sizeof(char));
is_valid = false;
for (int i = 0; i < gtm_param_number; i++) {
len = strlen(tmp) > strlen(gtm_param[i]) ? strlen(tmp) : strlen(gtm_param[i]);
if (0 == strncmp(tmp, gtm_param[i], len)) {
is_valid = true;
break;
}
}
if (is_valid == false) {
(void)write_stderr(
"ERROR: The name of parameter \"%s\" is incorrect. It is not in the GTM parameter range\n",
config_param[para_num]);
all_valid = false;
}
#ifndef USE_ASSERT_CHECKING
char* gtm_distribute_test_param = "distribute_test_param";
len = strlen(tmp) > strlen(gtm_distribute_test_param) ? strlen(tmp) : strlen(gtm_distribute_test_param);
if (0 == strncmp(tmp, gtm_distribute_test_param, len)) {
all_valid = false;
(void)write_stderr("ERROR: The name of parameter \"%s\" is incorrect."
"not work on this mode.\n",
config_param[para_num]);
}
#endif
}
return all_valid;
}
bool check_cm_server_parameter_is_valid()
{
int para_num = 0;
bool is_valid = false;
bool all_valid = true;
int len = 0;
char tmp[MAX_PARAM_LEN] = {0};
int nRet = 0;
for (para_num = 0; para_num < config_param_number; para_num++) {
nRet = memset_s(tmp, MAX_PARAM_LEN, '\0', MAX_PARAM_LEN);
securec_check_c(nRet, "\0", "\0");
make_string_tolower(config_param[para_num], tmp, sizeof(tmp) / sizeof(char));
is_valid = false;
for (int i = 0; i < cmserver_param_number; i++) {
len = strlen(tmp) > strlen(cmserver_param[i]) ? strlen(tmp) : strlen(cmserver_param[i]);
if (0 == strncmp(tmp, cmserver_param[i], len)) {
is_valid = true;
break;
}
}
if (is_valid == false) {
(void)write_stderr(
"ERROR: The name of parameter \"%s\" is incorrect. It is not in the CMSERVER parameter range\n",
config_param[para_num]);
all_valid = false;
}
}
return all_valid;
}
bool check_cm_agent_parameter_is_valid()
{
int para_num = 0;
bool is_valid = false;
bool all_valid = true;
int len = 0;
char tmp[MAX_PARAM_LEN] = {0};
int nRet = 0;
for (para_num = 0; para_num < config_param_number; para_num++) {
nRet = memset_s(tmp, MAX_PARAM_LEN, '\0', MAX_PARAM_LEN);
securec_check_c(nRet, "\0", "\0");
make_string_tolower(config_param[para_num], tmp, sizeof(tmp) / sizeof(char));
is_valid = false;
for (int i = 0; i < cmagent_param_number; i++) {
len = strlen(tmp) > strlen(cmagent_param[i]) ? strlen(tmp) : strlen(cmagent_param[i]);
if (0 == strncmp(tmp, cmagent_param[i], len)) {
is_valid = true;
break;
}
}
if (is_valid == false) {
(void)write_stderr(
"ERROR: The name of parameter \"%s\" is incorrect. It is not in the CMAGENT parameter range\n",
config_param[para_num]);
all_valid = false;
}
}
return all_valid;
}
bool check_parameter_is_valid(int type)
{
bool is_valid = true;
if (type == INSTANCE_COORDINATOR || type == INSTANCE_DATANODE) {
is_valid = check_cn_dn_parameter_is_valid();
} else if (type == INSTANCE_GTM) {
is_valid = check_gtm_parameter_is_valid();
} else if (type == INSTANCE_CMSERVER) {
is_valid = check_cm_server_parameter_is_valid();
} else if (type == INSTANCE_CMAGENT) {
is_valid = check_cm_agent_parameter_is_valid();
} else {
is_valid = false;
(void)write_stderr("ERROR: Node type is not correct.\n");
}
return is_valid;
}
************************************************************************************
Function: is_parameter_value_error
Desc : check the parameter value.
guc_opt_str guc information string
config_value_str parameter value string
config_param_str parameter name string
Return : false the parameter name is incorrect
true the parameter name is correct
************************************************************************************
*/
bool is_parameter_value_error(const char* guc_opt_str, char* config_value_str, char* config_param_str)
{
struct guc_config_enum_entry guc_variable_list;
int nRet = 0;
int rc = 0;
int j = 0;
int k = 0;
int len = 0;
bool is_failed = false;
char newvalue[MAX_VALUE_LEN];
char* ch_position = NULL;
guc_variable_list.type = GUC_PARA_ERROR;
nRet = memset_s(guc_variable_list.guc_name, MAX_PARAM_LEN, '\0', MAX_PARAM_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = memset_s(guc_variable_list.guc_value, MAX_VALUE_LEN, '\0', MAX_VALUE_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = memset_s(guc_variable_list.guc_unit, MAX_UNIT_LEN, '\0', MAX_UNIT_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = memset_s(guc_variable_list.message, MAX_MESG_LEN, '\0', MAX_MESG_LEN);
securec_check_c(nRet, "\0", "\0");
if (FAILURE == do_gucopt_parse(guc_opt_str, guc_variable_list)) {
is_failed = true;
} else {
if ('\0' != guc_variable_list.message[0])
(void)write_stderr("NOTICE: %s\n", guc_variable_list.message);
if (0 == strncmp(guc_variable_list.guc_name, "comm_tcp_mode", strlen("comm_tcp_mode")))
(void)write_stderr(
"WARNING: If the cluster was not restarted, it can not communicate properly after dilatation.\n");
nRet = memset_s(newvalue, MAX_VALUE_LEN, '\0', MAX_VALUE_LEN);
securec_check_c(nRet, "\0", "\0");
len = (int)strlen(config_value_str);
if (guc_variable_list.type == GUC_PARA_ENUM) {
ch_position = strchr(config_value_str,',');
if (ch_position != NULL) {
if (!((config_value_str[0] == '\'' || config_value_str[0] == '"') &&
config_value_str[0] == config_value_str[len - 1])) {
(void)write_stderr("ERROR: The value \"%s\" for parameter \"%s\" is incorrect. Please do it like this "
"\"parameter = \'value\'\".\n",
config_value_str,
config_param_str);
exit(1);
}
}
}
if (guc_variable_list.type == GUC_PARA_INT || guc_variable_list.type == GUC_PARA_REAL ||
guc_variable_list.type == GUC_PARA_ENUM || guc_variable_list.type == GUC_PARA_BOOL) {
if ((config_value_str[0] == '\'' || config_value_str[0] == '"') &&
config_value_str[0] == config_value_str[len - 1]) {
for (j = 1, k = 0; j < len - 1 && k < MAX_VALUE_LEN; j++, k++)
newvalue[k] = config_value_str[j];
} else {
rc = snprintf_s(newvalue, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", config_value_str);
securec_check_ss_c(rc, "\0", "\0");
}
} else {
if ((config_value_str[0] == '\'' || config_value_str[0] == '"') &&
config_value_str[0] == config_value_str[len - 1]) {
rc = snprintf_s(newvalue, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", config_value_str);
securec_check_ss_c(rc, "\0", "\0");
} else {
(void)write_stderr("ERROR: The value \"%s\" for parameter \"%s\" is incorrect. Please do it like this "
"\"parameter = \'value\'\".\n",
config_value_str,
config_param_str);
exit(1);
}
}
if (FAILURE == check_parameter_value(config_param_str,
guc_variable_list.type,
guc_variable_list.guc_value,
guc_variable_list.guc_unit,
newvalue)) {
is_failed = true;
if (guc_variable_list.type >= 0 &&
guc_variable_list.type < (GucParaType)(sizeof(value_type_list) / sizeof(value_type_list[0]))) {
(void) write_stderr("ERROR: The value \"%s\" for parameter \"%s\" is incorrect, requires a %s value\n",
config_value_str, config_param_str, value_type_list[guc_variable_list.type]);
} else {
(void) write_stderr("ERROR: The value \"%s\" for parameter \"%s\" is incorrect.\n", config_value_str,
config_param_str);
}
}
}
return is_failed;
}
************************************************************************************
Function: check_parameter
Desc : a interface that do patameter name and value checking.
if value is NULL, it means that we will disable the parameter
Return : SUCCESS
FAILURE
************************************************************************************
*/
int check_parameter(int type)
{
char** guc_opt = NULL;
bool is_failed = false;
int i = 0;
guc_opt = get_guc_option();
if (NULL == guc_opt)
return FAILURE;
if (FAILURE == check_parameter_name(guc_opt, type)) {
for (i = 0; i < config_param_number; i++) {
GS_FREE(guc_opt[i]);
}
GS_FREE(guc_opt);
return FAILURE;
}
for (i = 0; i < config_param_number; i++) {
if (NULL != config_value[i] && is_parameter_value_error(guc_opt[i], config_value[i], config_param[i]))
is_failed = true;
}
for (i = 0; i < config_param_number; i++) {
GS_FREE(guc_opt[i]);
}
GS_FREE(guc_opt);
if (is_failed)
return FAILURE;
else
return SUCCESS;
}
************************************************************************************
Function: check_parameter_value
Desc : do parameter value checking
Input : paraname paraname
type paratype
guc_list_value
guc_list_unit
value
Return : SUCCESS
FAILURE
************************************************************************************
*/
int check_parameter_value(
const char* paraname, GucParaType type, char* guc_list_value, const char* guc_list_unit, const char* value)
{
if (type == GUC_PARA_INT)
return check_int_real_type_value(paraname, guc_list_value, guc_list_unit, value, true);
else if (type == GUC_PARA_REAL)
return check_int_real_type_value(paraname, guc_list_value, guc_list_unit, value, false);
else if (type == GUC_PARA_ENUM)
return check_enum_type_value(paraname, guc_list_value, value);
else if (type == GUC_PARA_BOOL)
return check_bool_type_value(value);
else if (type == GUC_PARA_STRING) {
return check_string_type_value(paraname, value);
}
else
return FAILURE;
}
************************************************************************************
Function: get_guc_minmax_value
Desc : get min and max value from guc config
Input : guc_list_value value from guc config
guc_minmax_value a struct that storage min and max value string
Return : SUCCESS
FAILURE
************************************************************************************
*/
int get_guc_minmax_value(const char* guc_list_val, struct guc_minmax_value& value_list)
{
char guc_val[MAX_VALUE_LEN];
int nRet = 0;
char* ptr = NULL;
char* outer_ptr = NULL;
char delims[] = ",";
nRet = memset_s(guc_val, MAX_VALUE_LEN, '\0', MAX_VALUE_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = snprintf_s(guc_val, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", guc_list_val);
securec_check_ss_c(nRet, "\0", "\0");
ptr = strtok_r(guc_val, delims, &outer_ptr);
if (NULL != ptr) {
nRet = snprintf_s(value_list.min_val_str, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", ptr);
securec_check_ss_c(nRet, "\0", "\0");
} else {
(void)write_stderr("ERROR: The minimum value information is incorrect.\n");
return FAILURE;
}
ptr = strtok_r(NULL, delims, &outer_ptr);
if (NULL != ptr) {
nRet = snprintf_s(value_list.max_val_str, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", ptr);
securec_check_ss_c(nRet, "\0", "\0");
} else {
(void)write_stderr("ERROR: The maximum value information is incorrect.\n");
return FAILURE;
}
ptr = strtok_r(NULL, delims, &outer_ptr);
if (NULL != ptr) {
(void)write_stderr("ERROR: The minmax information for parameter is incorrect.\n");
return FAILURE;
}
return SUCCESS;
}
************************************************************************************
Function: is_alpha_in_string
Desc : judge the string contains alpha or not
Input : str
Return : true the string contains alpha
false the string does not contain alpha
************************************************************************************
*/
bool is_alpha_in_string(const char* str)
{
const char* p = str;
while ('\0' != *p) {
if (isalpha(*p))
return true;
p++;
}
return false;
}
************************************************************************************
Function: is_string_in_list
Desc : judge the string in list or not
Input : str string name
str_list string name list
list_nums the length of str list
Return : true the string is in value_list
false the string is not in value_list
************************************************************************************
*/
bool is_string_in_list(const char* str, const char** str_list, int list_nums)
{
int i = 0;
char tmp[MAX_PARAM_LEN];
int nRet = 0;
nRet = memset_s(tmp, MAX_PARAM_LEN, '\0', MAX_PARAM_LEN);
securec_check_c(nRet, "\0", "\0");
make_string_tolower(str, tmp, sizeof(tmp) / sizeof(char));
for (i = 0; i < list_nums; i++) {
if (0 == strcmp(str_list[i], tmp))
return true;
}
return false;
}
************************************************************************************
Function: check_int_value
Desc : check the int parameter value
Input : paraname parameter name
guc_list_value value from guc config
value parameter value string, including unit
int_newval the parameter value, only including number
int_min_val the min parameter value
int_max_val the max parameter value
Return : SUCCESS
FAILURE
************************************************************************************
*/
int check_int_value(const char* paraname, const struct guc_minmax_value& value_list, const char* value,
int64 int_newval, int64 int_min_val, int64 int_max_val)
{
bool is_in_list = false;
bool is_exists_alpha = false;
if ((FAILURE == parse_value(paraname, value_list.min_val_str, NULL, &int_min_val, NULL, true)) ||
(FAILURE == parse_value(paraname, value_list.max_val_str, NULL, &int_max_val, NULL, true))) {
(void)write_stderr("ERROR: The minmax value of parameter \"%s\" requires an integer value.\n", paraname);
return FAILURE;
}
if the unit is incorrect, when do parse_value by config_value, it will print error messages and exit.
So, we can makesure the unit is correct, if it is exists
*/
is_in_list = is_string_in_list(paraname, unit_eight_kB_parameter_list, lengthof(unit_eight_kB_parameter_list));
is_exists_alpha = is_alpha_in_string(value);
if (is_in_list && is_exists_alpha) {
int_newval = int_newval / PAGE_SIZE;
}
if (int_newval < int_min_val || int_newval > int_max_val) {
if (is_in_list && is_exists_alpha) {
(void)write_stderr(
"Notice: The default unit for parameter \"%s\" is disk page and each page is usually %dkB.\n",
paraname,
PAGE_SIZE);
(void)write_stderr("ERROR: The value \"%s\" is outside the valid range for parameter \"%s\" (" INT64_FORMAT
" .. " INT64_FORMAT ").\n",
value,
paraname,
int_min_val,
int_max_val);
} else {
(void)write_stderr("ERROR: The value " INT64_FORMAT
" is outside the valid range for parameter \"%s\" (" INT64_FORMAT " .. " INT64_FORMAT
").\n",
int_newval,
paraname,
int_min_val,
int_max_val);
}
return FAILURE;
}
return SUCCESS;
}
************************************************************************************
Function: check_real_value
Desc : check the real parameter value
Input : paraname parameter name
guc_list_value value from guc config
double_newval the parameter value
double_min_val the min parameter value
double_max_val the max parameter value
Return : SUCCESS
FAILURE
************************************************************************************
*/
int check_real_value(const char* paraname, const struct guc_minmax_value& value_list, double double_newval,
double double_min_val, double double_max_val)
{
if ((FAILURE == parse_value(paraname, value_list.min_val_str, NULL, NULL, &double_min_val, false)) ||
(FAILURE == parse_value(paraname, value_list.max_val_str, NULL, NULL, &double_max_val, false))) {
(void)write_stderr("ERROR: The minmax value of parameter \"%s\" requires a numeric value.\n", paraname);
return FAILURE;
}
* error message */
if (double_newval < double_min_val - DOUBLE_PRECISE || double_newval > double_max_val + DOUBLE_PRECISE) {
(void)write_stderr("ERROR: The value %g is outside the valid range for parameter \"%s\" (%g .. %g).\n",
double_newval,
paraname,
double_min_val,
double_max_val);
return FAILURE;
}
return SUCCESS;
}
************************************************************************************
Function: check_int_real_type_value
Desc : check the int/real parameter value
Input : paraname parameter name
guc_list_value value from guc config
value parameter value
isInt true is int, false is real
Return : SUCCESS
FAILURE
************************************************************************************
*/
int check_int_real_type_value(
const char* paraname, const char* guc_list_value, const char* guc_list_unit, const char* value, bool isInt)
{
int64 int_newval = INT_MIN;
int64 int_min_val = LLONG_MIN;
int64 int_max_val = LLONG_MAX;
double double_newval = LLONG_MIN;
double double_min_val = LLONG_MIN;
double double_max_val = LLONG_MIN;
struct guc_minmax_value value_list;
int nRet = 0;
nRet = memset_s(value_list.min_val_str, MAX_VALUE_LEN, '\0', MAX_VALUE_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = memset_s(value_list.max_val_str, MAX_VALUE_LEN, '\0', MAX_VALUE_LEN);
securec_check_c(nRet, "\0", "\0");
if (FAILURE == parse_value(paraname, value, guc_list_unit, &int_newval, &double_newval, isInt)) {
if (isInt)
(void)write_stderr("ERROR: The parameter \"%s\" requires an integer value.\n", paraname);
else
(void)write_stderr("ERROR: The parameter \"%s\" requires a numeric value.\n", paraname);
return FAILURE;
}
if (FAILURE == get_guc_minmax_value(guc_list_value, value_list))
return FAILURE;
if ('\0' == value_list.min_val_str[0] || '\0' == value_list.max_val_str[0]) {
(void)write_stderr("ERROR: The minmax information for parameter \"%s\" is incorrect.\n", paraname);
return FAILURE;
}
if (isInt)
return check_int_value(paraname, value_list, value, int_newval, int_min_val, int_max_val);
else
return check_real_value(paraname, value_list, double_newval, double_min_val, double_max_val);
}
************************************************************************************
Function: parse_value
Desc : parese value from guc config file.
paraname parameter name
value parameter value
guc_list_unit the unit of parameter from guc config file
result_int the parse result about int
result_double the parse result about double
isInt true is int, false is real
Return : SUCCESS
FAILURE
************************************************************************************
*/
int parse_value(const char* paraname, const char* value, const char* guc_list_unit, int64* result_int,
double* result_double, bool isInt)
{
int64 int_val = INT_MIN;
double double_val;
long double tmp_double_val;
char* endptr = NULL;
UnitType unitval = UNIT_ERROR;
bool contain_space = false;
if (NULL != result_int)
*result_int = 0;
if (NULL != result_double)
*result_double = 0;
errno = 0;
if (isInt) {
int_val = strtoll(value, &endptr, 0);
if (endptr == value || errno == ERANGE)
return FAILURE;
tmp_double_val = (long double)int_val;
} else {
double_val = strtod(value, &endptr);
if (endptr == value || errno == ERANGE)
return FAILURE;
tmp_double_val = (long double)double_val;
}
while (isspace((unsigned char)*endptr)) {
endptr++;
contain_space = true;
}
if ('\0' != *endptr) {
if (NULL == guc_list_unit || '\0' == guc_list_unit[0])
return FAILURE;
if (contain_space) {
(void)write_stderr("ERROR: There should not hava space between value and unit.\n");
return FAILURE;
}
unitval = get_guc_unit(guc_list_unit);
if (UNIT_ERROR == unitval) {
(void)write_stderr("ERROR: Invalid units for this parameter \"%s\".\n", paraname);
return FAILURE;
} else if (UNIT_KB == unitval) {
if (strncmp(endptr, "kB", 2) == 0) {
endptr += 2;
} else if (strncmp(endptr, "MB", 2) == 0) {
endptr += 2;
tmp_double_val *= KB_PER_MB;
} else if (strncmp(endptr, "GB", 2) == 0) {
endptr += 2;
tmp_double_val *= KB_PER_GB;
} else {
(void)write_stderr(
"ERROR: Valid units for this parameter \"%s\" are \"kB\", \"MB\" and \"GB\".\n", paraname);
return FAILURE;
}
} else if (UNIT_MB == unitval) {
if (strncmp(endptr, "MB", 2) == 0) {
endptr += 2;
} else if (strncmp(endptr, "GB", 2) == 0) {
endptr += 2;
tmp_double_val *= MB_PER_GB;
} else {
(void)write_stderr("ERROR: Valid units for this parameter \"%s\" are \"MB\" and \"GB\".\n", paraname);
return FAILURE;
}
} else if (UNIT_GB == unitval) {
if (strncmp(endptr, "GB", 2) == 0) {
endptr += 2;
} else {
(void)write_stderr("ERROR: Valid units for this parameter \"%s\" is \"GB\".\n", paraname);
return FAILURE;
}
} else if (UNIT_MS == unitval) {
if (strncmp(endptr, "ms", 2) == 0) {
endptr += 2;
} else if (strncmp(endptr, "s", 1) == 0) {
endptr += 1;
tmp_double_val *= MS_PER_S;
} else if (strncmp(endptr, "min", 3) == 0) {
endptr += 3;
tmp_double_val *= MS_PER_MIN;
} else if (strncmp(endptr, "h", 1) == 0) {
endptr += 1;
tmp_double_val *= MS_PER_H;
} else if (strncmp(endptr, "d", 1) == 0) {
endptr += 1;
tmp_double_val *= MS_PER_D;
} else {
(void)write_stderr(
"ERROR: Valid units for this parameter \"%s\" are \"ms\", \"s\", \"min\", \"h\", and \"d\".\n",
paraname);
return FAILURE;
}
} else if (UNIT_S == unitval) {
if (strncmp(endptr, "s", 1) == 0) {
endptr += 1;
} else if (strncmp(endptr, "min", 3) == 0) {
endptr += 3;
tmp_double_val *= S_PER_MIN;
} else if (strncmp(endptr, "h", 1) == 0) {
endptr += 1;
tmp_double_val *= S_PER_H;
} else if (strncmp(endptr, "d", 1) == 0) {
endptr += 1;
tmp_double_val *= S_PER_D;
} else {
(void)write_stderr(
"ERROR: Valid units for this parameter \"%s\" are \"s\", \"min\", \"h\", and \"d\".\n", paraname);
return FAILURE;
}
} else if (UNIT_MIN == unitval) {
if (strncmp(endptr, "min", 3) == 0) {
endptr += 3;
} else if (strncmp(endptr, "h", 1) == 0) {
endptr += 1;
tmp_double_val *= MIN_PER_H;
} else if (strncmp(endptr, "d", 1) == 0) {
endptr += 1;
tmp_double_val *= MIN_PER_D;
} else {
(void)write_stderr(
"ERROR: Valid units for this parameter \"%s\" are \"min\", \"h\", and \"d\".\n", paraname);
return FAILURE;
}
} else if (UNIT_H == unitval) {
if (strncmp(endptr, "h", 1) == 0) {
endptr += 1;
} else if (strncmp(endptr, "d", 1) == 0) {
endptr += 1;
tmp_double_val *= H_PER_D;
} else {
(void)write_stderr(
"ERROR: Valid units for this parameter \"%s\" are \"min\", \"h\", and \"d\".\n", paraname);
return FAILURE;
}
} else if (UNIT_D == unitval) {
if (strncmp(endptr, "d", 1) == 0) {
endptr += 1;
} else {
(void)write_stderr("ERROR: Valid units for this parameter \"%s\" is \"d\".\n", paraname);
return FAILURE;
}
} else {
return FAILURE;
}
}
while (isspace((unsigned char)*endptr))
endptr++;
if (*endptr != '\0')
return FAILURE;
if (isInt) {
if (tmp_double_val > LLONG_MAX || tmp_double_val < LLONG_MIN)
return FAILURE;
if (NULL != result_int)
*result_int = (int64)tmp_double_val;
} else {
if (NULL != result_double)
*result_double = (double)tmp_double_val;
}
return SUCCESS;
}
int is_value_in_range(const char* guc_list_value, const char* value)
{
char* ptr = NULL;
char* outer_ptr = NULL;
char delims[] = ",";
char guc_val[MAX_VALUE_LEN] = {0};
int nRet = 0;
nRet = memset_s(guc_val, MAX_VALUE_LEN, '\0', MAX_VALUE_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = snprintf_s(guc_val, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", guc_list_value);
securec_check_ss_c(nRet, "\0", "\0");
ptr = strtok_r(guc_val, delims, &outer_ptr);
while (NULL != ptr) {
if (0 == strcmp(ptr, value))
return SUCCESS;
else
ptr = strtok_r(NULL, delims, &outer_ptr);
}
return FAILURE;
}
Function: check_enum_type_value
Desc : check the parameter value of enum type.
Input : paraname parameter name
guc_list_value the string from config file
value parameter value
Return : SUCCESS
FAILURE
*************************************************************************************/
int check_enum_type_value(const char* paraname, char* guc_list_value, const char* value)
{
char guc_val[MAX_VALUE_LEN] = {0};
int nRet = 0;
const char* vptr = NULL;
char* vouter_ptr = NULL;
const char* p = NULL;
char delims[] = ",";
char tmp_paraname[MAX_PARAM_LEN];
nRet = memset_s(guc_val, MAX_VALUE_LEN, '\0', MAX_VALUE_LEN);
securec_check_c(nRet, "\0", "\0");
nRet = snprintf_s(guc_val, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", guc_list_value);
securec_check_ss_c(nRet, "\0", "\0");
nRet = memset_s(tmp_paraname, MAX_PARAM_LEN, '\0', MAX_PARAM_LEN);
securec_check_c(nRet, "\0", "\0");
if (NULL == guc_list_value || '\0' == guc_list_value[0]) {
(void)write_stderr("ERROR: Failed to obtain the range information of parameter \"%s\".\n", paraname);
return FAILURE;
}
make_string_tolower(value, tmp_paraname, sizeof(tmp_paraname) / sizeof(char));
if (tmp_paraname != NULL && strlen(tmp_paraname) > 0) {
vptr = strtok_r(tmp_paraname, delims, &vouter_ptr);
} else {
vptr = "";
}
while (NULL != vptr) {
p = vptr;
while (isspace((unsigned char)*p))
p++;
if (SUCCESS == is_value_in_range(guc_val, p)) {
vptr = strtok_r(NULL, delims, &vouter_ptr);
} else {
(void)write_stderr("ERROR: The value \"%s\" is outside the valid range(%s) for parameter \"%s\".\n",
value,
guc_list_value,
paraname);
return FAILURE;
}
}
return SUCCESS;
}
************************************************************************************
Function: check_bool_type_value
Desc : check the parameter value of bool type.
GUC_PARA_BOOL - in bool value list
Return : SUCCESS
FAILURE
************************************************************************************
*/
int check_bool_type_value(const char* value)
{
int list_nums = lengthof(guc_bool_valuelist);
if (is_string_in_list(value, guc_bool_valuelist, list_nums))
return SUCCESS;
else
return FAILURE;
}
static bool check_datestyle_gs_guc(const char* paraname, const char* value)
{
const char* dateStyleList = "iso,sql,postgres,german";
const char* dateOrderList = "ymd,dmy,euro,european,mdy,us,noneuro,noneuropean,default";
char* rawstring = NULL;
const char delims[] = ",";
char* vptr = NULL;
char* vouter_ptr = NULL;
char* p = NULL;
bool hasDateStyle = false;
bool hasDateOrder = false;
bool hasConflict = false;
char* pname = xstrdup(paraname);
make_string_tolower(paraname, pname, (int)strlen(pname));
if (strcmp(pname, "datestyle") != 0) {
free(pname);
return true;
}
rawstring = xstrdup(value);
make_string_tolower(value, rawstring, (int)strlen(rawstring));
p = rawstring + strlen(rawstring) - 1;
while (isspace((unsigned char)*p) || *p == '\'') {
*p = '\0';
p--;
}
vptr = strtok_r(rawstring, delims, &vouter_ptr);
while (vptr != NULL) {
p = vptr;
while (isspace((unsigned char)*p) || *p == '\'')
p++;
if (is_value_in_range(dateStyleList, p) == SUCCESS) {
if (!hasDateStyle) {
hasDateStyle = true;
} else {
hasConflict = true;
break;
}
vptr = strtok_r(NULL, delims, &vouter_ptr);
} else if (is_value_in_range(dateOrderList, p) == SUCCESS) {
if (!hasDateOrder) {
hasDateOrder = true;
} else {
hasConflict = true;
break;
}
vptr = strtok_r(NULL, delims, &vouter_ptr);
} else {
write_stderr("ERROR: The value \"%s\" is invalid for parameter datestyle.\n", value);
free(rawstring);
free(pname);
return false;
}
}
free(rawstring);
free(pname);
if (hasConflict) {
write_stderr("ERROR: The value \"%s\" have conflict options for parameter datestyle.\n", value);
}
return hasConflict ? false : true;
}
static bool CheckSsInterconnectTypeGsGuc(const char* paraname, const char* value)
{
char rawstring[MAX_VALUE_LEN] = {0};
int rc = 0;
size_t len = 0;
if (paraname == NULL || value == NULL || pg_strcasecmp(paraname, "ss_interconnect_type") != 0) {
return true;
}
rc = snprintf_s(rawstring, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", value);
securec_check_ss_c(rc, "\0", "\0");
len = strlen(rawstring);
if (len >= MIN_QUOTED_VALUE_LEN && (rawstring[0] == '\'' || rawstring[0] == '"') &&
rawstring[0] == rawstring[len - 1]) {
rawstring[len - 1] = '\0';
value = rawstring + 1;
} else {
value = rawstring;
}
if (strcmp(value, "TCP") == 0 || strcmp(value, "RDMA") == 0 || strcmp(value, "UBC") == 0 ||
strcmp(value, "SHM") == 0) {
return true;
}
write_stderr("ERROR: The value \"%s\" is invalid for parameter ss_interconnect_type. "
"Valid values are \"TCP\", \"RDMA\", \"UBC\" and \"SHM\".\n",
value);
return false;
}
static const char* SkipShmUbCpuBindSpace(const char* p)
{
while (p != NULL && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) {
p++;
}
return p;
}
static bool ParseShmUbCpuBindInt(const char* tok, long* out)
{
const char* p = SkipShmUbCpuBindSpace(tok);
char* end = NULL;
long v = 0;
errno = 0;
v = strtol(p, &end, DECIMAL_BASE);
if (end == p || errno == ERANGE || v < INT_MIN || v > INT_MAX) {
return false;
}
end = (char*)SkipShmUbCpuBindSpace(end);
if (*end != '\0') {
return false;
}
*out = v;
return true;
}
static bool AppendShmUbCpuBindRange(long lo, long hi, int* count)
{
int ncpus = get_nprocs_conf();
if (lo > hi) {
return false;
}
for (long id = lo; id <= hi; id++) {
if (id < 0 || id >= (long)ncpus || *count >= DMS_SHM_UB_CPU_BIND_EXPAND_CAP) {
return false;
}
(*count)++;
}
return true;
}
static bool ParseShmUbCpuBindToken(char* tok, int* count)
{
char* tilde = strchr(tok, '~');
long lo = 0;
long hi = 0;
long v = 0;
int ncpus = get_nprocs_conf();
if (tilde == NULL) {
if (!ParseShmUbCpuBindInt(tok, &v)) {
return false;
}
if (v != -1L && (v < 0 || v >= (long)ncpus)) {
return false;
}
if (*count >= DMS_SHM_UB_CPU_BIND_EXPAND_CAP) {
return false;
}
(*count)++;
return true;
}
if (strchr(tilde + 1, '~') != NULL) {
return false;
}
*tilde = '\0';
if (!ParseShmUbCpuBindInt(tok, &lo) || !ParseShmUbCpuBindInt(tilde + 1, &hi)) {
return false;
}
return AppendShmUbCpuBindRange(lo, hi, count);
}
static bool HasShmUbCpuBindEmptyToken(const char* start, const char* end)
{
const char* tokenStart = start;
if (start == end) {
return false;
}
while (tokenStart <= end) {
const char* tokenEnd = (const char*)memchr(tokenStart, ',', (size_t)(end - tokenStart));
if (tokenEnd == NULL) {
tokenEnd = end;
}
const char* left = SkipShmUbCpuBindSpace(tokenStart);
const char* right = tokenEnd;
while (right > left && (*(right - 1) == ' ' || *(right - 1) == '\t' ||
*(right - 1) == '\n' || *(right - 1) == '\r')) {
right--;
}
if (left == right) {
return true;
}
if (tokenEnd == end) {
break;
}
tokenStart = tokenEnd + 1;
}
return false;
}
static bool ParseShmUbCpuBindValue(const char* raw)
{
char buf[DMS_SHM_UB_CPU_BIND_INNER_MAX] = {0};
const char* p = SkipShmUbCpuBindSpace(raw);
const char* rb = NULL;
char* saveptr = NULL;
int count = 0;
errno_t rc = 0;
if (raw == NULL || raw[0] == '\0') {
return true;
}
if (*p != '[') {
return false;
}
p++;
rb = strchr(p, ']');
if (rb == NULL || (size_t)(rb - p) >= DMS_SHM_UB_CPU_BIND_INNER_MAX) {
return false;
}
if (HasShmUbCpuBindEmptyToken(p, rb)) {
return false;
}
rc = memcpy_s(buf, sizeof(buf), p, (size_t)(rb - p));
securec_check_c(rc, "\0", "\0");
rb = SkipShmUbCpuBindSpace(rb + 1);
if (*rb != '\0') {
return false;
}
for (char* tok = strtok_r(buf, ",", &saveptr); tok != NULL; tok = strtok_r(NULL, ",", &saveptr)) {
if (!ParseShmUbCpuBindToken(tok, &count)) {
return false;
}
}
return true;
}
static bool CheckSsShmUbCommCpuBindGsGuc(const char* paraname, const char* value)
{
char rawstring[MAX_VALUE_LEN] = {0};
int rc = 0;
size_t len = 0;
if (paraname == NULL || value == NULL || pg_strcasecmp(paraname, "ss_shm_ub_comm_cpu_bind") != 0) {
return true;
}
rc = snprintf_s(rawstring, MAX_VALUE_LEN, MAX_VALUE_LEN - 1, "%s", value);
securec_check_ss_c(rc, "\0", "\0");
len = strlen(rawstring);
if (len >= MIN_QUOTED_VALUE_LEN && (rawstring[0] == '\'' || rawstring[0] == '"') &&
rawstring[0] == rawstring[len - 1]) {
rawstring[len - 1] = '\0';
value = rawstring + 1;
} else {
value = rawstring;
}
if (ParseShmUbCpuBindValue(value)) {
return true;
}
write_stderr("ERROR: The value \"%s\" is invalid for parameter ss_shm_ub_comm_cpu_bind. "
"Valid format is \"[id,id,...]\" or \"[lo~hi]\".\n",
value);
return false;
}
Function: IsShellCommandParam
Desc : check whether the parameter is a shell-command type that legitimately
contains metacharacters (e.g. archive_command, restore_command).
Return : true - is a shell command param (skip security check)
false - normal string param (apply security check)
*************************************************************************************/
static bool IsShellCommandParam(const char* paraname)
{
if (paraname == NULL) {
return false;
}
const char* shellCommandParams[] = {
"archive_command",
"restore_command",
"archive_cleanup_command",
"recovery_end_command",
NULL
};
for (int i = 0; shellCommandParams[i] != NULL; i++) {
if (strcmp(paraname, shellCommandParams[i]) == 0) {
return true;
}
}
return false;
}
Function: CheckStringValueForSecurity
Desc : reject shell metacharacters that could lead to command injection
when the value is later interpolated into a popen() command line.
Return : true - safe
false - contains dangerous character
*************************************************************************************/
static bool CheckStringValueForSecurity(const char* value)
{
typedef struct {
const char* token;
const char* display;
} DangerChar;
const DangerChar dangerCharacters[] = {
{"`", "`"}, {";", ";"}, {"|", "|"}, {"&", "&"},
{"<", "<"}, {">", ">"}, {"\n", "\\n"}, {NULL, NULL}
};
for (int i = 0; dangerCharacters[i].token != NULL; i++) {
if (strstr(value, dangerCharacters[i].token) != NULL) {
write_stderr("ERROR: Invalid character '%s' found in parameter value. "
"Shell metacharacters are not allowed.\n",
dangerCharacters[i].display);
return false;
}
}
return true;
}
Function: check_string_type_value
Desc : check the paraname value of string type.
GUC_PARA_STRING - length(str) > 0
Return : SUCCESS
FAILURE
*************************************************************************************/
int check_string_type_value(const char* paraname, const char* value)
{
bool result = ((int)strlen(value) > 0) ? true : false;
if (result && !IsShellCommandParam(paraname) && !CheckStringValueForSecurity(value)) {
return FAILURE;
}
if (result && paraname != NULL) {
result = check_datestyle_gs_guc(paraname, value);
result = result && CheckSsInterconnectTypeGsGuc(paraname, value);
result = result && CheckSsShmUbCommCpuBindGsGuc(paraname, value);
}
return result ? SUCCESS : FAILURE;
}
* GetEnvStr
*
* Note: malloc space for get the return of getenv() function, then return the malloc space.
* so, this space need be free.
*/
static char* GetEnvStr(const char* env)
{
char* tmpvar = NULL;
const char* temp = getenv(env);
errno_t rc = 0;
if (temp != NULL) {
size_t len = strlen(temp);
if (0 == len)
return NULL;
tmpvar = (char*)malloc(len + 1);
if (tmpvar != NULL) {
rc = strcpy_s(tmpvar, len + 1, temp);
securec_check_c(rc, "\0", "\0");
return tmpvar;
}
}
return NULL;
}
#ifdef __cplusplus
}
#endif