PostgreSQL之精妙的数据库导入导出工具架构 (三)

来源:互联网 发布:二进制转中文 Java 编辑:程序博客网 时间:2024/04/29 11:30
(三)导出文件的格式与函数指针的使用

海翔语:
本节所描述的,是很精妙的设计。利用函数指针,实现多种文件格式的方便定制。

1 文件格式
PostgreSQL提供四种导出文件格式,具体如下:

1)custom(pg_backup_custom.c):二进制格式的备份文件。有文件头、文件体;文件体是一个链表,各个可备份对象在这个链表上存在;每一个可备份对象都有一套统一的结构标识。支持压缩(压缩功能依赖于系统编译选项和pg_config.h文件中的宏定义开关)。
2)plain(pg_backup_null.c):文本文件格式,默认方式。备份的文件内容是SQL脚本。。
3)file(pg_backup_files.c):备份一个主文件和一些辅助文件;主文件方式类似于custom的文件格式,辅助文件是数据文件,每一个辅助文件对应备份对象中的一个表。
4)tar(pg_backup_tar.c):文件备份基本类似“file”方式,但是,最后备份的所有文件都要归档到一个tar文件中。文件最大大小为8GB(受限于tar file format)。

说明:对于file格式建议如下:
This format is for demonstration purposes; it is not intended for
normal use. Files will be written in the current working directory.


2 函数指针的使用

在pg_backup_archiver.h文件中,定义有大量的函数指针,如:
......
typedef void (*ClosePtr) (struct _archiveHandle * AH);
typedef void (*ReopenPtr) (struct _archiveHandle * AH);
typedef void (*ArchiveEntryPtr) (struct _archiveHandle * AH, struct _tocEntry * te);

......

这些函数指针,被用到了如下文件中
2.1 文件->被调用的函数
pg_backup_custom.c->InitArchiveFmt_Custom(ArchiveHandle *AH)
pg_backup_null.c->InitArchiveFmt_Null(ArchiveHandle *AH)
pg_backup_files.c->InitArchiveFmt_Files(ArchiveHandle *AH)
pg_backup_tar.c->InitArchiveFmt_Tar(ArchiveHandle *AH)

2.2 具体实例
pg_backup_custom.c文件中有如下函数InitArchiveFmt_Custom:
/*
 *    Init routine required by ALL formats. This is a global routine
 *    and should be declared in pg_backup_archiver.h
 *
 *    It's task is to create any extra archive context (using AH->formatData),
 *    and to initialize the supported function pointers.
 *
 *    It should also prepare whatever it's input source is for reading/writing,
 *    and in the case of a read mode connection, it should load the Header & TOC.
 */
void
InitArchiveFmt_Custom(ArchiveHandle *AH)
{
    lclContext *ctx;

    /* Assuming static functions, this can be copied for each format. */
    AH->ArchiveEntryPtr = _ArchiveEntry;
    AH->StartDataPtr = _StartData;
    AH->WriteDataPtr = _WriteData;
    AH->EndDataPtr = _EndData;
    AH->WriteBytePtr = _WriteByte;
    AH->ReadBytePtr = _ReadByte;
    AH->WriteBufPtr = _WriteBuf;
    AH->ReadBufPtr = _ReadBuf;
    AH->ClosePtr = _CloseArchive;
    AH->ReopenPtr = _ReopenArchive;
    AH->PrintTocDataPtr = _PrintTocData;
    AH->ReadExtraTocPtr = _ReadExtraToc;
    AH->WriteExtraTocPtr = _WriteExtraToc;
    AH->PrintExtraTocPtr = _PrintExtraToc;

    AH->StartBlobsPtr = _StartBlobs;
    AH->StartBlobPtr = _StartBlob;
    AH->EndBlobPtr = _EndBlob;
    AH->EndBlobsPtr = _EndBlobs;
    AH->ClonePtr = _Clone;
    AH->DeClonePtr = _DeClone;
  ......
}

剖析:
  在ArchiveHandle结构中,使用了大量的函数指针,目的,是为了在初始化不同文件格式函数中,可以调用各自的函数(有点其他语言中的“接口”的味道)。
  在其他格式文件的所有函数指针指向的函数中,具体实现了不同格式所要求的函数功能(有点其他语言中的“继承”的味道)。
  这样,在pg_dump.c中,只要根据用户指定的文件格式的参数,决定使用什么格式的文件即可,代码如下:
    /* open the output file */
    if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    {
        /* This is used by pg_dumpall, and is not documented */
        plainText = 1;
        g_fout = CreateArchive(filename, archNull, 0, archModeAppend);
    }
    else if (pg_strcasecmp(format, "c") == 0 || pg_strcasecmp(format, "custom") == 0)
        g_fout = CreateArchive(filename, archCustom, compressLevel, archModeWrite);
    else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
    {
        /*
         * Dump files into the current directory; for demonstration only, not
         * documented.
         */
        g_fout = CreateArchive(filename, archFiles, compressLevel, archModeWrite);
    }
    else if (pg_strcasecmp(format, "p") == 0 || pg_strcasecmp(format, "plain") == 0)
    {
        plainText = 1;
        g_fout = CreateArchive(filename, archNull, 0, archModeWrite);
    }
    else if (pg_strcasecmp(format, "t") == 0 || pg_strcasecmp(format, "tar") == 0)
        g_fout = CreateArchive(filename, archTar, compressLevel, archModeWrite);
    else
    {
        write_msg(NULL, "invalid output format \"%s\" specified\n", format);
        exit(1);
    }

    
    InitArchiveFmt_Custom函数的调用关系图如下(dump文件格式调用关系.JPG):
PoatgresSQL之精妙的数据库导入导出工具架构 (三) - 那海蓝蓝 - 那海蓝蓝的博客

     根据调用关系,可以看出函数指针的初始化情况。
    
    在具体的使用中,如:导出大对象,则可以调用函数指针,直接导出大对象,但实际调用的,是初始化时,根据具体文件格式、为函数指针赋值的本格式的函数。
    
  如果想品味其精妙处,建议循着如下调用关系仔细看看不同格式的文件导出,是如何进行的?【dumpTableData->ArchiveEntry->_ArchiveEntry(pg_backup_custom.c,二进制格式,调用方式如:(*AH->ArchiveEntryPtr) (AH, newToc))】
原创粉丝点击