PostgreSQL逻辑备份pg_dump使用及其原理浅析

栏目: 数据库 · PostgreSQL · 发布时间: 4年前

内容简介:一、原理分析1、循环调用getopt_long解析命令行参数,将参数保存到static DumpOptions dopt;中2、判断参数是否相容,不相容则退出:

一、原理分析

1、循环调用getopt_long解析命令行参数,将参数保存到static DumpOptions dopt;中

2、判断参数是否相容,不相容则退出:

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是一个重要的全局变量

5、调用ConnectDatabase连接数据库

6、调用setup_connection,在连接上执行一些 SQL 语句:

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、为兼容低版本,根据服务器版本号决定一些变量取值

8、调用tblinfo = getSchemaData(fout, &numTables);决定导出哪些数据库对象。本函数又调用如下函数,值得关注哦。为了存储每个对象的元数据,这些函数会malloc申请空间,直到pg_dump进程结束才释放。

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, extinfo, numExtensions);

flagInhTables(tblinfo, numTables, inhinfo, numInherits);

getTableAttrs(fout, tblinfo, numTables);

flagInhAttrs(fout->dopt, tblinfo, numTables);

getIndexes(fout, tblinfo, numTables);

getExtendedStatistics(fout);

getConstraints(fout, tblinfo, numTables);

getTriggers(fout, tblinfo, numTables);

getRules(fout, &numRules);

getPolicies(fout, tblinfo, numTables);

getPublications(fout);

getPublicationTables(fout, tblinfo, 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链表上,真正导出时导出数据,不会占用大量内存空间,但是针对这些元数据,当表特别多的时候,由于不到进程退出不释放内存,占用内存还是非常可观的。

该函数调用makeTableDataInfo:

1)view、外部表、分区表字表(从父表导出)和unlogged permanent table不用导出

2)判断该表是否制定导出时被排除

3)malloc一个TableDataInfo,保存表信息

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数组

10、如果需要导出大对虾,调用getBlobs,同上也是保存到数组,并没有真正导出数据

11、调用getDependencies重新整理每个对象的依赖关系。

12、getDumpableObjects从dumpIdMap数组中获取dump对象

13、sortDumpableObjectsByTypeName、sortDataAndIndexObjectsBySize(如果是并行dump,需要按表大小排序)、sortDumpableObjects把所有对象重新排列:不同类型对象导出优先级依赖于dbObjectTypePriority数组;相同类型按名称排序

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'

16、遍历所有对象,对于每个对象调用dumpDumpableObject,本函数用一堆诸如dumpNamespace、dumpExtension等,将其插入循环链表。

for (i = 0; i < numObjs; i++)

dumpDumpableObject(fout, dobjs[i]);

--------------------------以上所有导出,不真正导出数据----------------------------

17、遍历链表标记哪些对象Toc entry需要导出:ProcessArchiveRestoreOptions

18、如果导出格式时plain,则调用RestoreArchive,输出到文件显示的是SQL语句,不再是不可识别的二进制文件

19、关闭句柄释放资源CloseArchive,根据函数指针调用不同文件类型的_CloseArchive

二、不同格式的处理函数

-F, --format=c|d|t|p  output file format (custom, directory, tar,plain text (default))

目前,pg_dump支持4种导出格式:

custum(pg_backup_custum.c):导出二进制格式的文件。包括文件头和文件体。文件体是一个链表,保存每个备份对象,每个可备份对象都有一套统一的结构表示,支持压缩

plain(pg_backup_null.c):把SQL脚本内容输出到标准输出,默认方式

file(pg_backup_file.c):导出包括备份一个主文件和一些辅助文件,主文件方式类似于custom文件格式,辅助文件是数据文件,每个辅助文件对应备份��象中的一个表,需要和-f一起使用

tar(pg_backup_tar.c):文件备份基本类似“file”方式,但最后备份的所有文件都要归档到一个tar文件。文件最大大小为8GB(受限于tar file format)

PostgreSQL通过函数指针来实现这四种导出格式。在pg_backup_archive.h文件中有诸如下面的大量函数指针:

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步。

概况的说,pg_dump导出的内容可以分为数据库对象的定义和数据。数据库对象的定义导出时通过查询系统表把对应元数据信息读取出来后,把该对象的各类信息置于一个链表上包括其依赖对象的oid。而具体的数据,也就是每个数据包的数据也被抽象为一个数据库对象,保存在此链表中。通过调节导出顺序把数据库对象的定义导出然后导出数据,置于通过链表中对应数据对象节点的信息,执行相应的SQL语句,从表中读出数据然后导出写出去。所以,在内存中只是链表上对象的定义,数据是边读边写出的,可以使用流式读出。

三、使用方法

1)以目录格式导出,需要和-f一起使用。toc.dat保存所有可导出对象的信息(表定义等),其他文件是数据,以表的oid为命名,test是目录。

[postgres@localhost ~]$ pg_dump --format=d yzs -f test

[postgres@localhost ~]$ cd test

[postgres@localhost 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中

[postgres@localhost ~]$ pg_dump --format=p yzs -f test.sql

3)以二进制格式输出

[postgres@localhost ~]$ pg_dump --format=c -f test yzs

4)以tar格式输出。与d格式不同在于多了一个restore.sql文件(plain格式文件),并将所有文件打包成一个文件

[postgres@localhost ~]$ pg_dump --format=t -f test yzs

[postgres@localhost ~]$ 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

Linux公社的RSS地址https://www.linuxidc.com/rssFeed.aspx

本文永久更新链接地址: https://www.linuxidc.com/Linux/2019-04/158142.htm


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

黑客秘笈

黑客秘笈

[美]彼得·基姆 / 徐文博、成明遥 / 人民邮电出版社 / 2015-7-1 / 45.00

所谓的渗透测试,就是借助各种漏洞扫描工具,通过模拟黑客的攻击方法,来对网络安全进行评估。 本书采用大量真实案例和集邮帮助的建议讲解了在渗透测试期间会面临的一些障碍,以及相应的解决方法。本书共分为10章,其内容涵盖了本书所涉的攻击机器/工具的安装配置,网络扫描,漏洞利用,人工地查找和搜索Web应用程序的漏洞,攻陷系统后如何获取更重要的信息,社工方面的技巧,物理访问攻击,规避杀毒软件的方法,破解......一起来看看 《黑客秘笈》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换