PostgreSQL的备份工具pg_basebackup源码中的主函数分析
本篇内容主要讲解“PostgreSQL的备份工具pg_basebackup源码中的主函数分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL的备份工具pg_basebackup源码中的主函数分析”吧!
一、数据结构option
使用工具时存储选项的数据结构
#ifndefHAVE_STRUCT_OPTION//工具软件选项structoption{constchar*name;//名称inthas_arg;//是否包含参数,no_argument/required_argument/optional_argumentint*flag;//标记intval;//参数值};#defineno_argument0#definerequired_argument1#defineoptional_argument2#endif/**OnOpenBSDandsomeversionsofSolaris,opterrandfriendsaredefinedin*corelibcratherthaninaseparategetoptmodule.Definethesevariables*onlyifconfigurefoundtheyaren'ttherebydefault;otherwise,this*moduleanditscallerswilljustuselibc'svariables.(Weassumethat*testingopterrissufficientforallofthese.)*/#ifndefHAVE_INT_OPTERRintopterr=1,/*iferrormessageshouldbeprinted*/optind=1,/*indexintoparentargvvector*/optopt;/*charactercheckedforvalidity*/char*optarg;/*argumentassociatedwithoption*/#endif#defineBADCH(int)'?'#defineBADARG(int)':'#defineEMSG""二、源码解读
pg_basebackup主函数,源码较为简单,获取选项,校验,调用BaseBackup()函数进行备份.
intmain(intargc,char**argv){staticstructoptionlong_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值intc;//选项索引编号intoption_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);}elseif(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';//不压缩elseif(strcmp(optarg,"t")==0||strcmp(optarg,"tar")==0)format='t';//tar包else{fprintf(stderr,_("%s:invalidoutputformat\"%s\",mustbe\"plain\"or\"tar\"\n"),progname,optarg);exit(1);}break;case'r':maxrate=parse_max_rate(optarg);break;case'R':writerecoveryconf=true;break;case'S':/**Whenspecifyingreplicationslotname,useapermanent*slot.*指定复制槽名称,则使用持久化槽*/replication_slot=pg_strdup(optarg);temp_replication_slot=false;break;case2: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;}elseif(strcmp(optarg,"f")==0||strcmp(optarg,"fetch")==0){includewal=FETCH_WAL;}elseif(strcmp(optarg,"s")==0||strcmp(optarg,"stream")==0){includewal=STREAM_WAL;}else{fprintf(stderr,_("%s:invalidwal-methodoption\"%s\",mustbe\"fetch\",\"stream\",or\"none\"\n"),progname,optarg);exit(1);}break;case1: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':#ifdefHAVE_LIBZcompresslevel=Z_DEFAULT_COMPRESSION;#elsecompresslevel=1;/*willberejectedbelow*/#endifbreak;case'Z':compresslevel=atoi(optarg);if(compresslevel<0||compresslevel>9){fprintf(stderr,_("%s:invalidcompressionlevel\"%s\"\n"),progname,optarg);exit(1);}break;case'c':if(pg_strcasecmp(optarg,"fast")==0)fastcheckpoint=true;elseif(pg_strcasecmp(optarg,"spread")==0)fastcheckpoint=false;else{fprintf(stderr,_("%s:invalidcheckpointargument\"%s\",mustbe\"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:invalidstatusinterval\"%s\"\n"),progname,optarg);exit(1);}break;case'v':verbose++;break;case'P':showprogress=true;break;case3:verify_checksums=false;break;default:/**getopt_longalreadyemittedacomplaint*非法参数*/fprintf(stderr,_("Try\"%s--help\"formoreinformation.\n"),progname);exit(1);}}/**Anynon-optionarguments?*不识别的参数*/if(optind<argc){fprintf(stderr,_("%s:toomanycommand-linearguments(firstis\"%s\")\n"),progname,argv[optind]);fprintf(stderr,_("Try\"%s--help\"formoreinformation.\n"),progname);exit(1);}/**Requiredarguments*必须的参数*/if(basedir==NULL){fprintf(stderr,_("%s:notargetdirectoryspecified\n"),progname);fprintf(stderr,_("Try\"%s--help\"formoreinformation.\n"),progname);exit(1);}/**Mutuallyexclusivearguments*互斥的参数*/if(format=='p'&&compresslevel!=0){fprintf(stderr,_("%s:onlytarmodebackupscanbecompressed\n"),progname);fprintf(stderr,_("Try\"%s--help\"formoreinformation.\n"),progname);exit(1);}if(format=='t'&&includewal==STREAM_WAL&&strcmp(basedir,"-")==0){fprintf(stderr,_("%s:cannotstreamwrite-aheadlogsintarmodetostdout\n"),progname);fprintf(stderr,_("Try\"%s--help\"formoreinformation.\n"),progname);exit(1);}if(replication_slot&&includewal!=STREAM_WAL){fprintf(stderr,_("%s:replicationslotscanonlybeusedwithWALstreaming\n"),progname);fprintf(stderr,_("Try\"%s--help\"formoreinformation.\n"),progname);exit(1);}if(no_slot){if(replication_slot){fprintf(stderr,_("%s:--no-slotcannotbeusedwithslotname\n"),progname);fprintf(stderr,_("Try\"%s--help\"formoreinformation.\n"),progname);exit(1);}temp_replication_slot=false;}if(create_slot){if(!replication_slot){fprintf(stderr,_("%s:%sneedsaslottobespecifiedusing--slot\n"),progname,"--create-slot");fprintf(stderr,_("Try\"%s--help\"formoreinformation.\n"),progname);exit(1);}if(no_slot){fprintf(stderr,_("%s:--create-slotand--no-slotareincompatibleoptions\n"),progname);fprintf(stderr,_("Try\"%s--help\"formoreinformation.\n"),progname);exit(1);}}if(xlog_dir){if(format!='p'){fprintf(stderr,_("%s:WALdirectorylocationcanonlybespecifiedinplainmode\n"),progname);fprintf(stderr,_("Try\"%s--help\"formoreinformation.\n"),progname);exit(1);}/*cleanupxlogdirectoryname,checkit'sabsolute*/canonicalize_path(xlog_dir);if(!is_absolute_path(xlog_dir)){fprintf(stderr,_("%s:WALdirectorylocationmustbe""anabsolutepath\n"),progname);fprintf(stderr,_("Try\"%s--help\"formoreinformation.\n"),progname);exit(1);}}#ifndefHAVE_LIBZif(compresslevel!=0){fprintf(stderr,_("%s:thisbuilddoesnotsupportcompression\n"),progname);exit(1);}#endif/*connectioninreplicationmodetoserver*///以复制模式连接到数据库conn=GetConnection();if(!conn){/*ErrormessagealreadywritteninGetConnection()*///连接不成功exit(1);}atexit(disconnect_atexit);/**Setumasksothatdirectories/filesarecreatedwiththesame*permissionsasdirectories/filesinthesourcedatadirectory.*设置umask以便目录/文件可以源数据目录的相同的权限创建**pg_mode_maskissettoowner-onlybydefaultandthenupdatedin*GetConnection()wherewegetthemodefromtheserver-sidewith*RetrieveDataDirCreatePerm()andthencallSetDataDirectoryCreatePerm().*pg_mode_mask默认设置为owner-only,在GetConnection()更新,*在该函数中通过RetrieveDataDirCreatePerm()获得服务器端的模式,*然后调用SetDataDirectoryCreatePerm()函数.*/umask(pg_mode_mask);/**Verifythatthetargetdirectoryexists,orcreateit.Forplaintext*backups,alwaysrequirethedirectory.Fortarbackups,requireit*unlesswearewritingtostdout.*验证目标目录是否存在,如不存在则创建该目录.*对于普通的备份,通常需要目录.*对于tar备份,除非写入到stdout,也需要目录.*/if(format=='p'||strcmp(basedir,"-")!=0)verify_dir_is_empty_or_create(basedir,&made_new_pgdata,&found_existing_pgdata);/*determineremoteserver'sxlogsegmentsize*///确定远程服务器的xlogsegment大小if(!RetrieveWalSegSize(conn))exit(1);/*Createpg_walsymlink,ifrequired*///如需要,创建pg_wal目录链接if(xlog_dir){char*linkloc;//verify_dir_is_empty_or_create(xlog_dir,&made_new_xlogdir,&found_existing_xlogdir);/**Formnameoftheplacewherethesymlinkmustgo.pg_xloghasbeen*renamedtopg_walinpost-10clusters.*pg_xlog在PG10+后已重命名为pg_wal*/linkloc=psprintf("%s/%s",basedir,PQserverVersion(conn)<MINIMUM_VERSION_FOR_PG_WAL?"pg_xlog":"pg_wal");#ifdefHAVE_SYMLINKif(symlink(xlog_dir,linkloc)!=0){fprintf(stderr,_("%s:couldnotcreatesymboliclink\"%s\":%s\n"),progname,linkloc,strerror(errno));exit(1);}#elsefprintf(stderr,_("%s:symlinksarenotsupportedonthisplatform\n"),progname);exit(1);#endiffree(linkloc);}//执行备份BaseBackup();//成功标记success=true;return0;}/**set_pglocale_pgservice**Setapplication-specificlocaleandservicedirectory*设置应用相关的locale和service目录**Thisfunctiontakesthevalueofargv[0]ratherthanafullpath.*该函数只提取argv[0]的值而不是全路径**(Youmaybewonderingwhythisisinexec.c.Itrequiresthismodule's*servicesanddoesn'tintroduceanynewdependencies,sothisseemsas*goodasanyplace.)*(你可能会感觉疑惑:该函数在exec.c文件中)*这需要该模块中的服务,而不需要介绍其他新的依赖,因此看起来与其他地方没有什么区别.*/voidset_pglocale_pgservice(constchar*argv0,constchar*app){charpath[MAXPGPATH];charmy_exec_path[MAXPGPATH];charenv_path[MAXPGPATH+sizeof("PGSYSCONFDIR=")];/*longerthan*PGLOCALEDIR*/char*dup_path;/*don'tsetLC_ALLinthebackend*///不要在后台进程中设置LC_ALLif(strcmp(app,PG_TEXTDOMAIN("postgres"))!=0){setlocale(LC_ALL,"");/**OnecouldmakeacaseforreproducingherePostmasterMain()'stest*forwhethertheprocessismultithreaded.Unlikethepostmaster,*nofrontendprogramcallssigprocmask()orotherwiseprovidesfor*mutualexclusionbetweensignalhandlers.Whilefrontendsusing*fork(),ifmultithreaded,areformallyexposedtoundefined*behavior,wehavenotwitnessedaconcretebug.Therefore,*complainingaboutmultithreadingheremaybemerepedantry.*在这里可以重新执行PostmasterMain()的测试,检查进程是否多线程.*与postmaster不同,没有前台程序调用sigprocmask(),*否则的话需要为多个信号控制器提供mutualexclusion.*如为多线程方式,则前台程序使用fork(),会导致不可预测的行为,我们不会有这种严重的bug.*因此,在这里对于多线程方式报错是多余的.*/}if(find_my_exec(argv0,my_exec_path)<0)return;#ifdefENABLE_NLSget_locale_path(my_exec_path,path);bindtextdomain(app,path);textdomain(app);if(getenv("PGLOCALEDIR")==NULL){//------PGLOCALEDIR/*setforlibpqtouse*///设置libpqsnprintf(env_path,sizeof(env_path),"PGLOCALEDIR=%s",path);canonicalize_path(env_path+12);dup_path=strdup(env_path);if(dup_path)putenv(dup_path);}#endifif(getenv("PGSYSCONFDIR")==NULL){//----PGSYSCONFDIRget_etc_path(my_exec_path,path);/*setforlibpqtouse*/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源码中的主函数分析”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。