本篇內容主要講解“PostgreSQL的備份工具pg_basebackup源碼中的主函數分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“PostgreSQL的備份工具pg_basebackup源碼中的主函數分析”吧!
option
使用工具時存儲選項的數據結構
#ifndef HAVE_STRUCT_OPTION
//工具軟件選項
struct option
{
const char *name;//名稱
int has_arg;//是否包含參數,no_argument/required_argument/optional_argument
int *flag;//標記
int val;//參數值
};
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#endif
/*
* On OpenBSD and some versions of Solaris, opterr and friends are defined in
* core libc rather than in a separate getopt module. Define these variables
* only if configure found they aren't there by default; otherwise, this
* module and its callers will just use libc's variables. (We assume that
* testing opterr is sufficient for all of these.)
*/
#ifndef HAVE_INT_OPTERR
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt; /* character checked for validity */
char *optarg; /* argument associated with option */
#endif
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""pg_basebackup主函數,源碼較為簡單,獲取選項,校驗,調用BaseBackup()函數進行備份.
int
main(int argc, char **argv)
{
static struct option long_options[] = {
{"help", no_argument, NULL, '?'},
{"version", no_argument, NULL, 'V'},
{"pgdata", required_argument, NULL, 'D'},
{"format", required_argument, NULL, 'F'},
{"checkpoint", required_argument, NULL, 'c'},
{"create-slot", no_argument, NULL, 'C'},
{"max-rate", required_argument, NULL, 'r'},
{"write-recovery-conf", no_argument, NULL, 'R'},
{"slot", required_argument, NULL, 'S'},
{"tablespace-mapping", required_argument, NULL, 'T'},
{"wal-method", required_argument, NULL, 'X'},
{"gzip", no_argument, NULL, 'z'},
{"compress", required_argument, NULL, 'Z'},
{"label", required_argument, NULL, 'l'},
{"no-clean", no_argument, NULL, 'n'},
{"no-sync", no_argument, NULL, 'N'},
{"dbname", required_argument, NULL, 'd'},
{"host", required_argument, NULL, 'h'},
{"port", required_argument, NULL, 'p'},
{"username", required_argument, NULL, 'U'},
{"no-password", no_argument, NULL, 'w'},
{"password", no_argument, NULL, 'W'},
{"status-interval", required_argument, NULL, 's'},
{"verbose", no_argument, NULL, 'v'},
{"progress", no_argument, NULL, 'P'},
{"waldir", required_argument, NULL, 1},
{"no-slot", no_argument, NULL, 2},
{"no-verify-checksums", no_argument, NULL, 3},
{NULL, 0, NULL, 0}
};//(完整)選項
//選項的ASCII值
int c;
//選項索引編號
int option_index;
//程序名稱
progname = get_progname(argv[0]);
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
if (argc > 1)
{
//顯示幫助信息
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
{
usage();
exit(0);
}
else if (strcmp(argv[1], "-V") == 0
|| strcmp(argv[1], "--version") == 0)
{
//顯示版本信息
puts("pg_basebackup (PostgreSQL) " PG_VERSION);
exit(0);
}
}
atexit(cleanup_directories_atexit);
//getopt_long --> 獲取選項
while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
long_options, &option_index)) != -1)
{
switch (c)//根據選項設置參數
{
case 'C':
create_slot = true;
break;
case 'D':
basedir = pg_strdup(optarg);
break;
case 'F':
if (strcmp(optarg, "p") == 0 || strcmp(optarg, "plain") == 0)
format = 'p';//不壓縮
else if (strcmp(optarg, "t") == 0 || strcmp(optarg, "tar") == 0)
format = 't';//tar包
else
{
fprintf(stderr,
_("%s: invalid output format \"%s\", must be \"plain\" or \"tar\"\n"),
progname, optarg);
exit(1);
}
break;
case 'r':
maxrate = parse_max_rate(optarg);
break;
case 'R':
writerecoveryconf = true;
break;
case 'S':
/*
* When specifying replication slot name, use a permanent
* slot.
* 指定復制槽名稱,則使用持久化槽
*/
replication_slot = pg_strdup(optarg);
temp_replication_slot = false;
break;
case 2:
no_slot = true;
break;
case 'T':
tablespace_list_append(optarg);
break;
case 'X':
if (strcmp(optarg, "n") == 0 ||
strcmp(optarg, "none") == 0)
{
includewal = NO_WAL;
}
else if (strcmp(optarg, "f") == 0 ||
strcmp(optarg, "fetch") == 0)
{
includewal = FETCH_WAL;
}
else if (strcmp(optarg, "s") == 0 ||
strcmp(optarg, "stream") == 0)
{
includewal = STREAM_WAL;
}
else
{
fprintf(stderr,
_("%s: invalid wal-method option \"%s\", must be \"fetch\", \"stream\", or \"none\"\n"),
progname, optarg);
exit(1);
}
break;
case 1:
xlog_dir = pg_strdup(optarg);
break;
case 'l':
label = pg_strdup(optarg);
break;
case 'n':
noclean = true;
break;
case 'N':
do_sync = false;
break;
case 'z':
#ifdef HAVE_LIBZ
compresslevel = Z_DEFAULT_COMPRESSION;
#else
compresslevel = 1; /* will be rejected below */
#endif
break;
case 'Z':
compresslevel = atoi(optarg);
if (compresslevel < 0 || compresslevel > 9)
{
fprintf(stderr, _("%s: invalid compression level \"%s\"\n"),
progname, optarg);
exit(1);
}
break;
case 'c':
if (pg_strcasecmp(optarg, "fast") == 0)
fastcheckpoint = true;
else if (pg_strcasecmp(optarg, "spread") == 0)
fastcheckpoint = false;
else
{
fprintf(stderr, _("%s: invalid checkpoint argument \"%s\", must be \"fast\" or \"spread\"\n"),
progname, optarg);
exit(1);
}
break;
case 'd':
connection_string = pg_strdup(optarg);
break;
case 'h':
dbhost = pg_strdup(optarg);
break;
case 'p':
dbport = pg_strdup(optarg);
break;
case 'U':
dbuser = pg_strdup(optarg);
break;
case 'w':
dbgetpassword = -1;
break;
case 'W':
dbgetpassword = 1;
break;
case 's':
standby_message_timeout = atoi(optarg) * 1000;
if (standby_message_timeout < 0)
{
fprintf(stderr, _("%s: invalid status interval \"%s\"\n"),
progname, optarg);
exit(1);
}
break;
case 'v':
verbose++;
break;
case 'P':
showprogress = true;
break;
case 3:
verify_checksums = false;
break;
default:
/*
* getopt_long already emitted a complaint
* 非法參數
*/
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
}
/*
* Any non-option arguments?
* 不識別的參數
*/
if (optind < argc)
{
fprintf(stderr,
_("%s: too many command-line arguments (first is \"%s\")\n"),
progname, argv[optind]);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
/*
* Required arguments
* 必須的參數
*/
if (basedir == NULL)
{
fprintf(stderr, _("%s: no target directory specified\n"), progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
/*
* Mutually exclusive arguments
* 互斥的參數
*/
if (format == 'p' && compresslevel != 0)
{
fprintf(stderr,
_("%s: only tar mode backups can be compressed\n"),
progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
if (format == 't' && includewal == STREAM_WAL && strcmp(basedir, "-") == 0)
{
fprintf(stderr,
_("%s: cannot stream write-ahead logs in tar mode to stdout\n"),
progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
if (replication_slot && includewal != STREAM_WAL)
{
fprintf(stderr,
_("%s: replication slots can only be used with WAL streaming\n"),
progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
if (no_slot)
{
if (replication_slot)
{
fprintf(stderr,
_("%s: --no-slot cannot be used with slot name\n"),
progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
temp_replication_slot = false;
}
if (create_slot)
{
if (!replication_slot)
{
fprintf(stderr,
_("%s: %s needs a slot to be specified using --slot\n"),
progname, "--create-slot");
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
if (no_slot)
{
fprintf(stderr,
_("%s: --create-slot and --no-slot are incompatible options\n"),
progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
}
if (xlog_dir)
{
if (format != 'p')
{
fprintf(stderr,
_("%s: WAL directory location can only be specified in plain mode\n"),
progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
/* clean up xlog directory name, check it's absolute */
canonicalize_path(xlog_dir);
if (!is_absolute_path(xlog_dir))
{
fprintf(stderr, _("%s: WAL directory location must be "
"an absolute path\n"), progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
}
#ifndef HAVE_LIBZ
if (compresslevel != 0)
{
fprintf(stderr,
_("%s: this build does not support compression\n"),
progname);
exit(1);
}
#endif
/* connection in replication mode to server */
//以復制模式連接到數據庫
conn = GetConnection();
if (!conn)
{
/* Error message already written in GetConnection() */
//連接不成功
exit(1);
}
atexit(disconnect_atexit);
/*
* Set umask so that directories/files are created with the same
* permissions as directories/files in the source data directory.
* 設置umask以便目錄/文件可以源數據目錄的相同的權限創建
*
* pg_mode_mask is set to owner-only by default and then updated in
* GetConnection() where we get the mode from the server-side with
* RetrieveDataDirCreatePerm() and then call SetDataDirectoryCreatePerm().
* pg_mode_mask默認設置為owner-only,在GetConnection()更新,
* 在該函數中通過RetrieveDataDirCreatePerm()獲得服務器端的模式,
* 然后調用SetDataDirectoryCreatePerm()函數.
*/
umask(pg_mode_mask);
/*
* Verify that the target directory exists, or create it. For plaintext
* backups, always require the directory. For tar backups, require it
* unless we are writing to stdout.
* 驗證目標目錄是否存在,如不存在則創建該目錄.
* 對于普通的備份,通常需要目錄.
* 對于tar備份,除非寫入到stdout,也需要目錄.
*/
if (format == 'p' || strcmp(basedir, "-") != 0)
verify_dir_is_empty_or_create(basedir, &made_new_pgdata, &found_existing_pgdata);
/* determine remote server's xlog segment size */
//確定遠程服務器的xlog segment大小
if (!RetrieveWalSegSize(conn))
exit(1);
/* Create pg_wal symlink, if required */
//如需要,創建pg_wal目錄鏈接
if (xlog_dir)
{
char *linkloc;
//
verify_dir_is_empty_or_create(xlog_dir, &made_new_xlogdir, &found_existing_xlogdir);
/*
* Form name of the place where the symlink must go. pg_xlog has been
* renamed to pg_wal in post-10 clusters.
* pg_xlog在PG 10+后已重命名為pg_wal
*/
linkloc = psprintf("%s/%s", basedir,
PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ?
"pg_xlog" : "pg_wal");
#ifdef HAVE_SYMLINK
if (symlink(xlog_dir, linkloc) != 0)
{
fprintf(stderr, _("%s: could not create symbolic link \"%s\": %s\n"),
progname, linkloc, strerror(errno));
exit(1);
}
#else
fprintf(stderr, _("%s: symlinks are not supported on this platform\n"), progname);
exit(1);
#endif
free(linkloc);
}
//執行備份
BaseBackup();
//成功標記
success = true;
return 0;
}
/*
* set_pglocale_pgservice
*
* Set application-specific locale and service directory
* 設置應用相關的locale和service目錄
*
* This function takes the value of argv[0] rather than a full path.
* 該函數只提取argv[0]的值而不是全路徑
*
* (You may be wondering why this is in exec.c. It requires this module's
* services and doesn't introduce any new dependencies, so this seems as
* good as anyplace.)
* (你可能會感覺疑惑:該函數在exec.c文件中)
* 這需要該模塊中的服務,而不需要介紹其他新的依賴,因此看起來與其他地方沒有什么區別.
*/
void
set_pglocale_pgservice(const char *argv0, const char *app)
{
char path[MAXPGPATH];
char my_exec_path[MAXPGPATH];
char env_path[MAXPGPATH + sizeof("PGSYSCONFDIR=")]; /* longer than
* PGLOCALEDIR */
char *dup_path;
/* don't set LC_ALL in the backend */
//不要在后臺進程中設置LC_ALL
if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0)
{
setlocale(LC_ALL, "");
/*
* One could make a case for reproducing here PostmasterMain()'s test
* for whether the process is multithreaded. Unlike the postmaster,
* no frontend program calls sigprocmask() or otherwise provides for
* mutual exclusion between signal handlers. While frontends using
* fork(), if multithreaded, are formally exposed to undefined
* behavior, we have not witnessed a concrete bug. Therefore,
* complaining about multithreading here may be mere pedantry.
* 在這里可以重新執行PostmasterMain()的測試,檢查進程是否多線程.
* 與postmaster不同,沒有前臺程序調用sigprocmask(),
* 否則的話需要為多個信號控制器提供mutual exclusion.
* 如為多線程方式,則前臺程序使用fork(),會導致不可預測的行為,我們不會有這種嚴重的bug.
* 因此,在這里對于多線程方式報錯是多余的.
*/
}
if (find_my_exec(argv0, my_exec_path) < 0)
return;
#ifdef ENABLE_NLS
get_locale_path(my_exec_path, path);
bindtextdomain(app, path);
textdomain(app);
if (getenv("PGLOCALEDIR") == NULL)
{
//------ PGLOCALEDIR
/* set for libpq to use */
//設置libpq
snprintf(env_path, sizeof(env_path), "PGLOCALEDIR=%s", path);
canonicalize_path(env_path + 12);
dup_path = strdup(env_path);
if (dup_path)
putenv(dup_path);
}
#endif
if (getenv("PGSYSCONFDIR") == NULL)
{
//---- PGSYSCONFDIR
get_etc_path(my_exec_path, path);
/* set for libpq to use */
snprintf(env_path, sizeof(env_path), "PGSYSCONFDIR=%s", path);
canonicalize_path(env_path + 13);
dup_path = strdup(env_path);
if (dup_path)
putenv(dup_path);
}
}到此,相信大家對“PostgreSQL的備份工具pg_basebackup源碼中的主函數分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。