Files
openGauss-server/src/bin/initdb/ss_initdb.cpp
2024-06-27 14:05:55 +08:00

443 lines
14 KiB
C++

/*
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* 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.
* ---------------------------------------------------------------------------------------
*
* ss_initdb.cpp
*
*
* IDENTIFICATION
* src/bin/initdb/ss_initdb.cpp
*
* ---------------------------------------------------------------------------------------
*/
#include "postgres_fe.h"
#include <cipher.h>
#include "access/ustore/undo/knl_uundoapi.h"
#include "access/ustore/undo/knl_uundotxn.h"
#include "libpq/pqsignal.h"
#include "mb/pg_wchar.h"
#include "getaddrinfo.h"
#include "getopt_long.h"
#include "miscadmin.h"
#include "bin/elog.h"
#include "ss_initdb.h"
#include "storage/file/fio_device.h"
static const char* ss_clusterdirs[] = {"+global",
"+base",
"+base/1",
"+pg_tblspc",
"+pg_clog",
"+pg_csnlog",
"+pg_multixact",
"+pg_multixact/members",
"+pg_multixact/offsets",
"+pg_twophase",
"+pg_serial",
"+pg_replslot"};
static const char* ss_instancedirs[] = {"+pg_xlog",
"+pg_doublewrite"
};
static const char* ss_instanceowndirs[] = {"base",
"base/1",
"global",
"pg_xlog",
"pg_xlog/archive_status",
"undo",
"pg_stat_tmp",
"pg_errorinfo",
"pg_logical",
"pg_llog",
"pg_llog/snapshots",
"pg_llog/mappings",
"pg_clog",
"pg_notify",
"pg_csnlog",
"pg_multixact",
"pg_multixact/members",
"pg_multixact/offsets",
"pg_snapshots"};
static const char* ss_xlogsubdirs[] = {"archive_status"};
/* for ss dorado replication */
static const char* ss_specialdirs[] = {"+pg_replication"};
/* num of every directory type */
#define SS_CLUSTERDIRS_NUM ARRAY_NUM(ss_clusterdirs)
#define SS_INSTANCEDIRS_NUM ARRAY_NUM(ss_instancedirs)
#define SS_INSTANCEOENDIRS_NUM ARRAY_NUM(ss_instanceowndirs)
#define SS_XLOGSUBIRS_NUM ARRAY_NUM(ss_xlogsubdirs)
#define SS_SPECIALDIRS_NUM ARRAY_NUM(ss_specialdirs)
char *ss_nodedatainfo = NULL;
int32 ss_nodeid = INVALID_INSTANCEID;
bool ss_issharedstorage = false;
bool ss_need_mkclusterdir = true;
bool ss_need_mkspecialdir = false;
static const char *ss_progname = "ss_initdb";
/*
* pg_ltoa: converts a signed 32-bit integer to its string representation
*
* Caller must ensure that 'a' points to enough memory to hold the result
* (at least 12 bytes, counting a leading sign and trailing NUL).
*/
void pg_ltoa(int32 value, char *a)
{
char *start = a;
bool neg = false;
errno_t ss_rc;
if (a == NULL) {
return;
}
/*
* Avoid problems with the most negative integer not being representable
* as a positive integer.
*/
if (value == (-2147483647 - 1)) {
const int a_len = 12;
ss_rc = memcpy_s(a, a_len, "-2147483648", a_len);
securec_check(ss_rc, "\0", "\0");
return;
} else if (value < 0) {
value = -value;
neg = true;
}
/* Compute the result string backwards. */
do {
int32 remainder;
int32 oldval = value;
value /= 10;
remainder = oldval - value * 10;
*a++ = (char)('0' + remainder);
} while (value != 0);
if (neg) {
*a++ = '-';
}
/* Add trailing NUL byte, and back up 'a' to the last character. */
*a-- = '\0';
/* Reverse string. */
while (start < a) {
char swap = *start;
*start++ = *a;
*a-- = swap;
}
}
static char *ss_concat_path(int32 node_id, const char *parent_dir, const char *dir)
{
char *path = NULL;
char *prepath = NULL;
char nodeid_str[MAXPGPATH];
size_t len = strlen(parent_dir) + 2 + strlen(dir);
/* prepared path by connecting vgname and subdir */
prepath = (char *)pg_malloc(len);
errno_t sret = sprintf_s(prepath, len, "%s/%s", parent_dir, dir + 1);
securec_check_ss_c(sret, prepath, "\0");
if (node_id != INVALID_INSTANCEID) {
pg_ltoa(node_id, nodeid_str);
len = len + strlen(nodeid_str);
path = (char *)pg_malloc(len);
/* full path by connecting prepared path and node id */
sret = sprintf_s(path, len, "%s%d", prepath, node_id);
securec_check_ss_c(sret, path, "\0");
} else {
path = (char *)pg_malloc(len);
sret = sprintf_s(path, len, "%s", prepath);
securec_check_ss_c(sret, path, "\0");
}
FREE_AND_RESET(prepath);
return path;
}
/* check dms url when gs_initdb */
bool ss_check_nodedatainfo(bool enable_dss)
{
bool issharedstorage = false;
if (!enable_dss) {
if (ss_nodeid != INVALID_INSTANCEID || ss_nodedatainfo != NULL) {
fprintf(stderr, _("ss_nodeid is valid or nodedatainfo exist without enable-dss.\n"));
exit(1);
}
return issharedstorage;
}
if ((ss_nodeid == INVALID_INSTANCEID || ss_nodedatainfo == NULL)) {
fprintf(stderr, _("ss_nodeid is invalid or nodedatainfo not exist or nodedatainfo is empty with enable-dss.\n"));
exit(1);
}
if (ss_nodeid != INVALID_INSTANCEID && ss_nodedatainfo != NULL) {
issharedstorage = true;
}
return issharedstorage;
}
int ss_check_existdir(const char *path, int node_id, const char **subdir)
{
char *subpath = NULL;
struct stat statbuf;
int existnum = 0;
int totalnum = (int)ARRAY_NUM(subdir);
for (int i = 0; i < totalnum; i++) {
subpath = ss_concat_path(node_id, path, subdir[i]);
if (lstat(subpath, &statbuf) == 0) {
existnum++;
}
FREE_AND_RESET(subpath);
}
if (existnum == 0) {
return 0; // subdir do not exists
} else if (existnum < totalnum) {
return 1; // subdir exists but not complete
}
return 2; // subdir exists and complete
}
bool ss_check_exist_specialdir(char *path)
{
for (uint32_t i = 0; i < SS_SPECIALDIRS_NUM; ++i) {
if (strcmp(ss_specialdirs[i] + 1, path) == 0) {
return true;
}
}
return false;
}
bool ss_check_specialdir(char *path)
{
char *datadir = path;
DIR *pgdatadir = NULL;
struct dirent *file = NULL;
if ((pgdatadir = opendir(datadir)) != NULL) {
while ((file = readdir(pgdatadir)) != NULL) {
if (strcmp(".", file->d_name) == 0 || strcmp("..", file->d_name) == 0) {
/* skip this and parent directory */
continue;
}
if (ss_check_exist_specialdir(file->d_name)) {
(void)closedir(pgdatadir);
return true;
}
}
(void)closedir(pgdatadir);
}
return false;
}
int ss_check_shareddir(char *path, int node_id, bool *need_mkclusterdir)
{
int ret = 0;
*need_mkclusterdir = false;
// step1: check cluster dir, must exists when instance id is not 0
switch (ss_check_existdir(path, INVALID_INSTANCEID, ss_clusterdirs)) {
case 0:
*need_mkclusterdir = true;
break;
case 1:
ret |= ERROR_CLUSTERDIR_INCOMPLETE; // cluster dir exists but not complete
break;
case 2:
*need_mkclusterdir = false;
break;
default:
fprintf(stderr, _("unkown state for ss_clusterdirs.\n"));
}
// node 0 must be primary in initdb
if (node_id != 0 && (*need_mkclusterdir)) {
ret |= ERROR_CLUSTERDIR_NO_EXISTS_BY_STANDBY;
}
if (node_id == 0 && !(*need_mkclusterdir)) {
ret |= ERROR_CLUSTERDIR_EXISTS_BY_PRIMARY;
}
// step2: check instancedir dir, do not allow exists
switch (ss_check_existdir(path, node_id, ss_instancedirs)) {
case 0:
break;
case 1:
case 2:
ret |= ERROR_INSTANCEDIR_EXISTS;
fprintf(stderr, _("instancedir already exists.\n"));
break;
default:
fprintf(stderr, _("unkown state for ss_instancedirs.\n"));
}
return ret;
}
void ss_mkdirdir(int32 node_id, const char *pg_data, const char *vgdata_dir, const char *vglog_dir,
bool need_mkclusterdir, bool need_specialdir)
{
/* Create required subdirectories */
printf(_("creating subdirectories ... in shared storage mode ... "));
(void)fflush(stdout);
/* unshared and instance one copy */
ss_createdir(ss_instanceowndirs, SS_INSTANCEOENDIRS_NUM, INVALID_INSTANCEID, pg_data, vgdata_dir, vglog_dir);
/* shared and instance one copy */
ss_createdir(ss_instancedirs, SS_INSTANCEDIRS_NUM, node_id, pg_data, vgdata_dir, vglog_dir);
/* shared and cluster one copy */
if (need_mkclusterdir) {
ss_createdir(ss_clusterdirs, SS_CLUSTERDIRS_NUM, INVALID_INSTANCEID, pg_data, vgdata_dir, vglog_dir);
}
if (need_specialdir) {
ss_createdir(ss_specialdirs, SS_SPECIALDIRS_NUM, INVALID_INSTANCEID, pg_data, vgdata_dir, vglog_dir);
}
}
void ss_makedirectory(char *path)
{
/*
* The parent directory already exists, so we only need mkdir() not
* pg_mkdir_p() here, which avoids some failure modes; cf bug #13853.
*/
if (mkdir(path, S_IRWXU) < 0) {
char errBuffer[ERROR_LIMIT_LEN];
fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"), ss_progname, path,
pqStrerror(errno, errBuffer, ERROR_LIMIT_LEN));
(void)fflush(stdout);
exit_nicely();
}
}
void ss_makesubdir(char *path, const char **subdir, uint num)
{
size_t len = 0;
errno_t sret = 0;
for (int i = 0; (unsigned int)i < num; i++) {
len = strlen(path) + strlen(subdir[i]) + 1 + 1;
char *subpath = NULL;
subpath = (char *)pg_malloc(len);
sret = sprintf_s(subpath, len, "%s/%s", path, subdir[i]);
securec_check_ss_c(sret, subpath, "\0");
ss_makedirectory(subpath);
FREE_AND_RESET(subpath);
}
}
void ss_createdir(const char **ss_dirs, int32 num, int32 node_id, const char *pg_data, const char *vgdata_dir,
const char *vglog_dir)
{
int i;
for (i = 0; i < num; i++) {
char *path = NULL;
errno_t sret = 0;
size_t len = 0;
bool is_dss = is_dss_file(ss_dirs[i]);
bool is_xlog = false;
char *link_path = NULL;
if (vglog_dir[0] != '\0' && (pg_strcasecmp(ss_dirs[i], "+pg_xlog") == 0 ||
pg_strcasecmp(ss_dirs[i], "+pg_notify") == 0 ||
pg_strcasecmp(ss_dirs[i], "+pg_snapshots") == 0 ||
pg_strcasecmp(ss_dirs[i], "+pg_replication") == 0)) {
is_xlog = true;
}
if (is_dss) {
if (is_xlog) {
path = ss_concat_path(node_id, vglog_dir, ss_dirs[i]);
link_path = ss_concat_path(node_id, vgdata_dir, ss_dirs[i]);
} else {
path = ss_concat_path(node_id, vgdata_dir, ss_dirs[i]);
}
} else {
len = strlen(pg_data) + strlen(ss_dirs[i]) + 1 + 1;
path = (char *)pg_malloc(len);
sret = sprintf_s(path, len, "%s/%s", pg_data, ss_dirs[i]);
securec_check_ss_c(sret, path, "\0");
}
ss_makedirectory(path);
if (is_xlog) {
symlink(path, link_path);
}
/* create suddirectory of pg_xlog/pg_multixact/pg_llog */
if (is_dss && pg_strcasecmp(ss_dirs[i] + 1, "pg_xlog") == 0) {
ss_makesubdir(path, ss_xlogsubdirs, SS_XLOGSUBIRS_NUM);
}
FREE_AND_RESET(path);
FREE_AND_RESET(link_path);
}
}
/* ss_addnodeparmater
* function: add the extra parameter for share storage for dms during gs_Initdb
* input: conflines char** parameter of postgresql.conf had been added previuosly
* output: conflines char** parameter of postgresql.conf to be added in this function
*/
char **ss_addnodeparmater(char **conflines)
{
if (!ss_issharedstorage) {
return conflines;
}
int nRet = 0;
char repltok[TZ_STRLEN_MAX + 100];
fputs(_("adding dms parameters to configuration files ... "), stdout);
(void)fflush(stdout);
nRet = sprintf_s(repltok, sizeof(repltok), "ss_instance_id = %d", ss_nodeid);
securec_check_ss_c(nRet, "\0", "\0");
conflines = replace_token(conflines, "#ss_instance_id = 0", repltok);
nRet = strcpy_s(repltok, sizeof(repltok), "ss_enable_dms = on");
securec_check_ss_c(nRet, "\0", "\0");
conflines = replace_token(conflines, "#ss_enable_dms = off", repltok);
nRet = sprintf_s(repltok, sizeof(repltok), "ss_interconnect_url = '%s'", ss_nodedatainfo);
securec_check_ss_c(nRet, "\0", "\0");
conflines = replace_token(conflines, "#ss_interconnect_url = '0:127.0.0.1:1611'", repltok);
return conflines;
}