443 lines
14 KiB
C++
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;
|
|
}
|