PostgreSQL的备份工具pg_basebackup源码中的主函数分析
发表于:2025-11-14 作者:千家信息网编辑
千家信息网最后更新 2025年11月14日,本篇内容主要讲解"PostgreSQL的备份工具pg_basebackup源码中的主函数分析",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"PostgreS
千家信息网最后更新 2025年11月14日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安全错误
数据库的锁怎样保障安全
金华脏脏网络技术有限公司
服务器租凭费入什么科目
数据库安装什么环境
网络安全线下
软件开发都包括哪些内容
中小型企业如何选择云服务器的呢
邮政储蓄银行合肥软件开发
贵州专业软件开发厂家现货
4g网络技术比3g网络的优势
颜色革命 网络安全
留学机构的网络技术
数据库备份与恢复
定制app软件开发舟山
理光 文件服务器
pi数据库征点
怎么样才能保证网络安全
网络安全认证需要什么资料
上海推广网络技术来电咨询
互联网生物科技医疗康养中心
做饭吧网络技术有限公司
黄山网络安全公司
云存储 数据库
美句数据库
武汉网络安全学院全景
怎么使用数据库的索引
外文数据库资源
t3连接数据库选多个实例
杨浦区品牌软件开发推荐咨询
怎么看mt4服务器有几个
苹果电脑软件开发学什么语言