学习目的
使用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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




