温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

PostgreSQL的备份工具pg_basebackup源码中的主函数分析

发布时间:2021-11-09 15:21:46 来源:亿速云 阅读:300 作者:iii 栏目:关系型数据库

本篇内容主要讲解“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源码中的主函数分析”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI