PostgreSQL控制文件在初始化时的生成

原创
2019/08/13 16:49
阅读数 451

控制文件是在初始化时生成,记录PG运行过程中的关键信息,大致分为以下几类。

  • 初始化时自动生成,运行过程中不允许修改,例如系统标识符;
  • 允许用户在初始化时一次性定制,不再允许修改,例如WAL段尺寸;
  • 记录创建数据库的编译时信息,例如catalog版本,启动此数据库的程序也必须具有相同属性;
  • 实时信息,比如检查点记录,崩溃中重启能够知道从哪里开始恢复。

1、初始化时传递给postgres参数

这个过程这里不多讲,initdb使用 postgres --boot -x1 启动数据库程序,进入bootstrap 模式:

	if (argc > 1 && strcmp(argv[1], "--boot") == 0)
		AuxiliaryProcessMain(argc, argv);	/* does not return */

这段代码在 main(int argc, char *argv[]) 函数中,以前的文章提到过它。

AuxiliaryProcessMain 中的参数解析:

	case 'x':
		MyAuxProcType = atoi(optarg);
		break;

这里取得辅助进程的类型,其它参数遇到的时候再讲。

2、辅助进程定义

typedef enum
{
	NotAnAuxProcess = -1,
	CheckerProcess = 0,
	BootstrapProcess,
...
	NUM_AUXPROCTYPES			/* Must be last! */
} AuxProcType;

可知,initdb启动了一个 BootstrapProcess 进程。

3、初始化时自动生成参数(系统标识符)

继续往下看会看到 BootStrapXLOG 的调用(src/backend/access/transam/xlog.c),系统标识符在这里边生成并最终写入磁盘:

void
BootStrapXLOG(void)
{
...
	gettimeofday(&tv, NULL);
	sysidentifier = ((uint64) tv.tv_sec) << 32;
	sysidentifier |= ((uint64) tv.tv_usec) << 12;
	sysidentifier |= getpid() & 0xFFF;
...
  ControlFile->system_identifier = sysidentifier;
...
	WriteControlFile();
...

4、用户定制参数

initdb 有参数 --wal-segsize=SIZE,在启动时 postgres 时用 'X' 传入:

postgres —boot -x1 -X %u

这地方稍微别扭的地方是initdb和postgres两个程序的X参数含义竟然不一致,好在是内部实现,使用者并不需要知道。

启动时,参数 X 赋值给 wal_segment_size

	case 'X':
		{
			int			WalSegSz = strtoul(optarg, NULL, 0);
...
			SetConfigOption("wal_segment_size", optarg, PGC_INTERNAL,
							PGC_S_OVERRIDE);
		}
		break;

随后,在 WriteControlFile 中记入控制文件:

ControlFile->xlog_seg_size = wal_segment_size;

5、编译时选项

函数 WriteControlFile 写入控制文件

	ControlFile->pg_control_version = PG_CONTROL_VERSION;
	ControlFile->catalog_version_no = CATALOG_VERSION_NO;

	ControlFile->maxAlign = MAXIMUM_ALIGNOF;
	ControlFile->floatFormat = FLOATFORMAT_VALUE;

	ControlFile->blcksz = BLCKSZ;
	ControlFile->relseg_size = RELSEG_SIZE;
...

6、实时信息

系统在运行过程中更新 ControlFile,然后在某些节点写入磁盘(调用 UpdateControlFile),比如CheckPoint时,可以看到像系统标识符这类信息是不会变的。

7、校验

写入和更新时都会计算CRC,也写入控制文件内,

	/* Contents are protected with a CRC */
	INIT_CRC32C(ControlFile->crc);
	COMP_CRC32C(ControlFile->crc,
				(char *) ControlFile,
				offsetof(ControlFileData, crc));
	FIN_CRC32C(ControlFile->crc);

读取文件时校验它保证完整性:

	/* Now check the CRC. */
	INIT_CRC32C(crc);
	COMP_CRC32C(crc,
				(char *) ControlFile,
				offsetof(ControlFileData, crc));
	FIN_CRC32C(crc);

	if (!EQ_CRC32C(crc, ControlFile->crc))
		ereport(FATAL,
				(errmsg("incorrect checksum in control file")));

开发需要,稍微捋了一下控制文件的创建过程,有需要的时候再写更多关于它的东西。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部