PostgreSQL逻辑备份pg_dump使用及其原理解析
一、原理分析
1、循环调用getopt_long解析命令行参数,将参数保存到static DumpOptions dopt;中 options -s/--schema-only and -a/--data-only cannot be used together options -c/--clean and -a/--data-only cannot be used together options --inserts/--column-inserts and -o/--oids cannot be used together option --if-exists requires option -c/--clean 3、调用CreateArchive打开输出文件,输出流为fout。该函数使用4个文件封装了4种不同dump文件格式,增加新文件可以增加新的导出文件类型各自封装,独立易于维护。 CreateArchive->_allocAH: switch (AH->format){ case archCustom: InitArchiveFmt_Custom(AH); break; case archNull: InitArchiveFmt_Null(AH); break; case archDirectory: InitArchiveFmt_Directory(AH); break; case archTar: InitArchiveFmt_Tar(AH); break; default: exit_horribly(modulename,"unrecognized file format "%d"n",fmt); } 4、fout是一个重要的全局变量 SELECT pg_catalog.set_config(‘search_path‘,‘‘,false); set client_encoding to ‘%s‘//pg_dump -E指定 SET ROLE %s// SET DATESTYLE = ISO; SET INTERVALSTYLE = POSTGRES; SET extra_float_digits TO 3; SET synchronize_seqscans TO off; SET statement_timeout = 0; SET lock_timeout = 0; SET idle_in_transaction_session_timeout = 0; SET row_security = off; BEGIN; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ,READ ONLY; 7、为兼容低版本,根据服务器版本号决定一些变量取值 extinfo = getExtensions(fout,&numExtensions); extinfoindex = buildIndexArray(extinfo,numExtensions,sizeof(ExtensionInfo)); getExtensionMembership(fout,extinfo,numExtensions); nspinfo = getNamespaces(fout,&numNamespaces); nspinfoindex = buildIndexArray(nspinfo,numNamespaces,sizeof(NamespaceInfo)); tblinfo = getTables(fout,&numTables); tblinfoindex = buildIndexArray(tblinfo,numTables,sizeof(TableInfo)); getOwnedSeqs(fout,tblinfo,numTables); funinfo = getFuncs(fout,&numFuncs); funinfoindex = buildIndexArray(funinfo,numFuncs,sizeof(FuncInfo)); typinfo = getTypes(fout,&numTypes); typinfoindex = buildIndexArray(typinfo,numTypes,sizeof(TypeInfo)); getProcLangs(fout,&numProcLangs); getAggregates(fout,&numAggregates); oprinfo = getOperators(fout,&numOperators); oprinfoindex = buildIndexArray(oprinfo,numOperators,sizeof(OprInfo)); getAccessMethods(fout,&numAccessMethods); getOpclasses(fout,&numOpclasses); getOpfamilies(fout,&numOpfamilies); getTSParsers(fout,&numTSParsers); getTSTemplates(fout,&numTSTemplates); getTSDictionaries(fout,&numTSDicts); getTSConfigurations(fout,&numTSConfigs); getForeignDataWrappers(fout,&numForeignDataWrappers); getForeignServers(fout,&numForeignServers); getDefaultACLs(fout,&numDefaultACLs); collinfo = getCollations(fout,&numCollations); collinfoindex = buildIndexArray(collinfo,numCollations,sizeof(CollInfo)); getConversions(fout,&numConversions); getCasts(fout,&numCasts); getTransforms(fout,&numTransforms); inhinfo = getInherits(fout,&numInherits); getEventTriggers(fout,&numEventTriggers); processExtensionTables(fout,numExtensions); flagInhTables(tblinfo,inhinfo,numInherits); getTableAttrs(fout,numTables); flagInhAttrs(fout->dopt,numTables); getIndexes(fout,numTables); getExtendedStatistics(fout); getConstraints(fout,numTables); getTriggers(fout,numTables); getRules(fout,&numRules); getPolicies(fout,numTables); getPublications(fout); getPublicationTables(fout,numTables); getSubscriptions(fout); 对于每个getXXXs函数都将执行下面流程,以getTables为例: 1)根据服务器版本号查询系统表,读出对象的元数据信息 2)malloc内存空间并将查询结果存放到对象的数据结构中,TableInfo 3)对于每条元数据信息,调用selectDumpableTable标记需要导出的表,如果-t指定导出表,遍历该列表,得到对应表并标记:DUMP_COMPONENT_ALL;-T指定删除表,标记tbinfo->dobj.dump = DUMP_COMPONENT_NONE 4)dumpIdMap[dobj->dumpId] = dobj;将导出表的元数据存放到dumpIdMap数组中 5)在导出表上执行LOCK TABLE %s IN ACCESS SHARE MODE 6)将所有元数据信息保存后,执行SET statement_timeout = 0保证语句不超时,能够一直执行下去 9、调用getTableData函数,获取表对应的数据。实际上,并不是表真正数据,而是为表数据建立一个“导出对象”,将来导出时,依据导出对象获取真是的数据再导出。虽然先把导出对象放到AH->toc链表上,真正导出时导出数据,不会占用大量内存空间,但是针对这些元数据,当表特别多的时候,由于不到进程退出不释放内存,占用内存还是非常可观的。 typedef struct _tableDataInfo { DumpableObject dobj; TableInfo *tdtable; /* link to table to dump */ bool oids; /* include OIDs in data? */ char *filtercond; /* WHERE condition to limit rows dumped */ } TableDataInfo; 4)tdinfo->dobj.catId.tableoid、tdinfo->dobj.catId.oid、tdinfo->dobj.name、tdinfo->dobj.namespace 信息,并将dobj保存到dumpIdMap数组 static const int dbObjectTypePriority[] = { 1,/* DO_NAMESPACE */ 4,/* DO_EXTENSION */ 5,/* DO_TYPE */ 5,/* DO_SHELL_TYPE */ 6,/* DO_FUNC */ 7,/* DO_AGG */ 8,/* DO_OPERATOR */ 8,/* DO_ACCESS_METHOD */ 9,/* DO_OPCLASS */ 9,/* DO_OPFAMILY */ 3,/* DO_COLLATION */ 11,/* DO_CONVERSION */ 18,/* DO_TABLE */ 20,/* DO_ATTRDEF */ 28,/* DO_INDEX */ 29,/* DO_STATSEXT */ 30,/* DO_RULE */ 31,/* DO_TRIGGER */ 27,/* DO_CONSTRAINT */ 32,/* DO_FK_CONSTRAINT */ 2,/* DO_PROCLANG */ 10,/* DO_CAST */ 23,/* DO_TABLE_DATA */ 24,/* DO_SEQUENCE_SET */ 19,/* DO_DUMMY_TYPE */ 12,/* DO_TSPARSER */ 14,/* DO_TSDICT */ 13,/* DO_TSTEMPLATE */ 15,/* DO_TSCONFIG */ 16,/* DO_FDW */ 17,/* DO_FOREIGN_SERVER */ 32,/* DO_DEFAULT_ACL */ 3,/* DO_TRANSFORM */ 21,/* DO_BLOB */ 25,/* DO_BLOB_DATA */ 22,/* DO_PRE_DATA_BOUNDARY */ 26,/* DO_POST_DATA_BOUNDARY */ 33,/* DO_EVENT_TRIGGER */ 38,/* DO_REFRESH_MATVIEW */ 34,/* DO_POLICY */ 35,/* DO_PUBLICATION */ 36,/* DO_PUBLICATION_REL */ 37 /* DO_SUBSCRIPTION */ }; 14、dumpEncoding、dumpStdStrings、dumpSearchPath导出编码信息,使用双向链表TOCEntry保存导出对象。例如: newToc->defn:"SET client_encoding=‘UTF8‘;n" SET standard_conforming_string=‘on‘; SELECT pg_catalog.set_config(‘search_path‘,false);n 15、dumpDatabase导出本链接对应的目的数据库信息,同样是newToc,newToc->defn:CREATE DATABASE yzs WITH TEMPLATE=template0 ENCODING=‘UTF8‘ LC_COLLATE=‘zh_CN.UTF-8‘ LC_CTYPE=‘zh_CN.UTF-8‘ for (i = 0; i < numObjs; i++) dumpDumpableObject(fout,dobjs[i]); --------------------------以上所有导出,不真正导出数据---------------------------- 二、不同格式的处理函数-F,--format=c|d|t|p output file format (custom,directory,tar,plain text (default)) typedef void (*ClosePtrType) (ArchiveHandle *AH); typedef void (*ReopenPtrType) (ArchiveHandle *AH); typedef void (*ArchiveEntryPtrType) (ArchiveHandle *AH,TocEntry *te); 这些函数指针,在下面文件里分别初始化: pg_backup_custum.c->InitArchiveFmt_Custom(ArchiveHandle *AH) pg_backup_null.c->InitArchiveFmt_Null(ArchiveHandle *AH) pg_backup_file.c->InitArchiveFmt_Directory(ArchiveHandle *AH) pg_backup_tar->InitArchiveFmt_Tar(ArchiveHandle *AH) 在数据结构ArchiveHandle中使用了大量函数指针,是的在初始化不同导出文件格式的Archive结构时,能为处理函数赋值为各自不同的处理函数。这样在pg_dump.c中只需要根据用户指定的文件格式的参数,就可以调用相应的处理函数。见第一部分的第3步。 三、使用方法1)以目录格式导出,需要和-f一起使用。toc.dat保存所有可导出对象的信息(表定义等),其他文件是数据,以表的oid为命名,test是目录。 [[email?protected] ~]$ pg_dump --format=d yzs -f test [[email?protected] ~]$ cd test [[email?protected] test]$ ll total 8 -rw-rw-r--. 1 postgres postgres 31 Mar 23 06:07 3010.dat.gz -rw-rw-r--. 1 postgres postgres 2124 Mar 23 06:07 toc.dat 2)导出SQL语句到test.sql中 [[email?protected] ~]$ pg_dump --format=p yzs -f test.sql 3)以二进制格式输出 [[email?protected] ~]$ pg_dump --format=c -f test yzs 4)以tar格式输出。与d格式不同在于多了一个restore.sql文件(plain格式文件),并将所有文件打包成一个文件 [[email?protected] ~]$ pg_dump --format=t -f test yzs [[email?protected] ~]$ tar -xvf test toc.dat 3010.dat restore.sql 5)仅导出数据库结构(不指定库,默认是postgres) pg_dump -s yzs -f 1.sql 6)导出时导出drop database和create database语句。需注意,导入时如有用户连接这该库,则drop语句执行失败 pg_dump -s yzs -C -c -f 1.txt 7、-t指定导出某些表,只导出item开头的表等对象 pg_dump -t temp* -f 1.txt yzs 8、-n只导出指定的schema,可以多个-n;-N指定不导出的schema (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |