PostgreSQL的备份工具pg_basebackup源码中的主函数分析
发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,本篇内容主要讲解"PostgreSQL的备份工具pg_basebackup源码中的主函数分析",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"PostgreS
千家信息网最后更新 2026年11月03日PostgreSQL的备份工具pg_basebackup源码中的主函数分析
本篇内容主要讲解"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_OPTERRint 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()函数进行备份.
intmain(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文件中) * 这需要该模块中的服务,而不需要介绍其他新的依赖,因此看起来与其他地方没有什么区别. */voidset_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源码中的主函数分析"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
函数
目录
备份
参数
工具
源码
数据
备份工具
分析
名称
程序
线程
服务
成功
信息
内容
前台
数据结构
文件
方式
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
手磨咖啡
互联网络科技
新华互联网科技
互联网科技工作委员会
互联网最新的科技有限公司
互联网金融与金融科技
平安科技 互联网
万达互联网科技
互联网科技视频素材
科技类的互联网平台
富国互联网科技创新基金
成都玖崟互联网科技有限公司乐商圈怎么样
欧洲十大科技互联网公司
重庆威客帮互联网科技
现代互联网科技股
互联网公司科技股
厦门千工互联网科技有限公司
开一家科技互联网公司需要多少钱
广州梦谷互联网科技有限公司领导
陕西彩京云互联网科技有限公司
美国互联网保险保险科技
科技股互联网
互联网与未来科技
融势互联网科技
互联网养老 桔豆科技
海南科技产业互联网平台
互联网时代科技改变生活
启辰互联网科技
城市宝互联网科技有限公司
上海创道互联网络科技有限公司