暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

postgresql之命令pg_checksums启动研究源代码

SmallDB 2025-03-14
16

 

学习目的

使用pg_checksums
功能检查数据完整性,确保没有损坏。这一检查可以定期进行,以防止潜在的数据丢失和损坏。但是这玩意目前我知道的有几个前提条件,一是关于关闭数据库,二是启用Data page checksum version这个参数(pg_controldata的这个参数下输出Data page checksum version: 1),才可以

开户

root@BJ-015908:/usr/local/pgsqldebug/bin# ./pg_checksums -D usr/local/pgsqldebug/data/ -e
Checksum operation completed
Files scanned:  1237
Blocks scanned: 4124
pg_checksums: syncing data directory
pg_checksums: updating control file
Checksums enabled in cluster

复制
 /usr/local/pgBuild/bin/pg_controldata -D usr/local/pgdh/data
Data page checksum version:           1

复制

关闭

postgres@BJ-015908:~$ /usr/local/pgBuild/bin/pg_checksums -D /usr/local/pgdh/data -d
pg_checksums: syncing data directory
pg_checksums: updating control file
Checksums disabled in cluster
postgres@BJ-015908:~$

复制
 /usr/local/pgBuild/bin/pg_controldata -D /usr/local/pgdh/data
Data page checksum version:           0

复制
实践
前提条件

必须关闭集群

postgres@BJ-015908:~$ /usr/local/pgBuild/bin/pg_checksums -D /usr/local/pgdh/data
pg_checksums: error: cluster must be shut down
postgres@BJ-015908:~$

复制

必须 Data page checksum version的参数为1,启动状态

root@BJ-015908:/usr/local/pgsqldebug/bin# ./pg_checksums -D /usr/local/pgsqldebug/data/
pg_checksums: error: data checksums are not enabled in cluster
root@BJ-015908:/usr/local/pgsqldebug/bin#

复制
函数调用

请出我们今天的主角GDB工具入场

postgres@BJ-015908:~$ gdb --args /usr/local/pgBuild/bin/pg_checksums -D /usr/local/pgdh/data
复制

打入断点调试

b 451
复制

如图

传入数据目录并分配变量

            case 'D':
                DataDir = optarg;
                break;

复制

数据目录设置

    if (DataDir == NULL)
    {
        if (optind < argc)
            DataDir = argv[optind++];
        else
            DataDir = getenv("PGDATA");

复制

读取%s/global/pg_control
文件

    ControlFile = get_controlfile(DataDir, &crc_ok);
复制

限制条件,CRC校验,版本校验,block size校验,数据库状态为DB_SHUTDOWNED模式或者DB_SHUTDOWNED_IN_RECOVERY模式,等等情况

/* Read the control file and check compatibility */
    ControlFile = get_controlfile(DataDir, &crc_ok);
    if (!crc_ok)
    {
        pg_log_error("pg_control CRC value is incorrect");
        exit(1);
    }

    if (ControlFile->pg_control_version != PG_CONTROL_VERSION)
    {
        pg_log_error("cluster is not compatible with this version of pg_checksums");
        exit(1);
    }

    if (ControlFile->blcksz != BLCKSZ)
    {
        pg_log_error("database cluster is not compatible");
        fprintf(stderr, _("The database cluster was initialized with block size %u, but pg_checksums was compiled with block size %u.\n"),
                ControlFile->blcksz, BLCKSZ);
        exit(1);
    }

    /*
     * Check if cluster is running.  A clean shutdown is required to avoid
     * random checksum failures caused by torn pages.  Note that this doesn't
     * guard against someone starting the cluster concurrently.
     */

    if (ControlFile->state != DB_SHUTDOWNED &&
        ControlFile->state != DB_SHUTDOWNED_IN_RECOVERY)
    {
        pg_log_error("cluster must be shut down");
        exit(1);
    }

    if (ControlFile->data_checksum_version == 0 &&
        mode == PG_MODE_CHECK)
    {
        pg_log_error("data checksums are not enabled in cluster");
        exit(1);
    }

    if (ControlFile->data_checksum_version == 0 &&
        mode == PG_MODE_DISABLE)
    {
        pg_log_error("data checksums are already disabled in cluster");
        exit(1);
    }

    if (ControlFile->data_checksum_version > 0 &&
        mode == PG_MODE_ENABLE)
    {
        pg_log_error("data checksums are already enabled in cluster");
        exit(1);
    }

复制

打工人登场,其中files与blocks在其它函数中有调用,算出来的

/* Operate on all files if checking or enabling checksums */
    if (mode == PG_MODE_CHECK || mode == PG_MODE_ENABLE)
    {
        /*
         * If progress status information is requested, we need to scan the
         * directory tree twice: once to know how much total data needs to be
         * processed and once to do the real work.
         */

        if (showprogress)
        {
            total_size = scan_directory(DataDir, "global"true);
            total_size += scan_directory(DataDir, "base"true);
            total_size += scan_directory(DataDir, "pg_tblspc"true);
        }

        (void) scan_directory(DataDir, "global"false);
        (void) scan_directory(DataDir, "base"false);
        (void) scan_directory(DataDir, "pg_tblspc"false);

        if (showprogress)
            progress_report(true);

        printf(_("Checksum operation completed\n"));
        printf(_("Files scanned:  %s\n"), psprintf(INT64_FORMAT, files));
        printf(_("Blocks scanned: %s\n"), psprintf(INT64_FORMAT, blocks));
        if (mode == PG_MODE_CHECK)
        {
            printf(_("Bad checksums:  %s\n"), psprintf(INT64_FORMAT, badblocks));
            printf(_("Data checksum version: %u\n"), ControlFile->data_checksum_version);

            if (badblocks > 0)
                exit(1);
        }
    }

复制

files与blocks是在scan_file部分函数代码

static void
scan_file(const char *fn, BlockNumber segmentno)
{
    PGAlignedBlock buf;
    PageHeader    header = (PageHeader) buf.data;
    int            f;
    BlockNumber blockno;
    int            flags;

    Assert(mode == PG_MODE_ENABLE ||
           mode == PG_MODE_CHECK);

    flags = (mode == PG_MODE_ENABLE) ? O_RDWR : O_RDONLY;
    f = open(fn, PG_BINARY | flags, 0);

    if (f < 0)
    {
        pg_log_error("could not open file \"%s\": %m", fn);
        exit(1);
    }

    files++;

    for (blockno = 0;; blockno++)
    {
        uint16        csum;
        int            r = read(f, buf.data, BLCKSZ);

        if (r == 0)
            break;
        if (r != BLCKSZ)
        {
            if (r < 0)
                pg_log_error("could not read block %u in file \"%s\": %m",
                             blockno, fn);
            else
                pg_log_error("could not read block %u in file \"%s\": read %d of %d",
                             blockno, fn, r, BLCKSZ);
            exit(1);
        }
        blocks++;

复制
总结

我其实就是想知道它是怎么来的,贴近原理部分,这样的理解力能增加,不要只知道结果,不要过程,其它没了,just for fun

 


文章转载自SmallDB,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论