海山数据库(He3DB)源码详解:海山PG 表和元组的组织方式(2)

海山数据库(He3DB)源码详解:海山PG 表和元组的组织方式(2)

一、页的操作

1、页面初始化

访问Page时会先将它加载到内存,所以Page可以仅用一个char *类型的指针来表示,指向内存中该Page的起始位置。由于Page的大小是已知的,通过Page指针和Page的大小即可表示并访问一个Page。在构建一个Page时,会调用PageInit函数进行初始化。

void
PageInit(Page page, Size pageSize, Size specialSize)
{
   
    // p指向Page的头部的起始位置,也是整个Page的起始位置
    PageHeader  p = (PageHeader) page; 

    // 对special区域的大小进行对齐
    specialSize = MAXALIGN(specialSize);

    // Page的大小应该为常量BLCKSZ(默认是8192)
    Assert(pageSize == BLCKSZ);
    // 除了头部和special区域外,Page内还应该有可用空间
    Assert(pageSize > specialSize + SizeOfPageHeaderData);

    // 将整个Page的内容填充为0
    MemSet(p, 0, pageSize);

    // 初始化Page头部的一些字段
    p->pd_flags = 0;
    p->pd_lower = SizeOfPageHeaderData;
    p->pd_upper = pageSize - specialSize;
    p->pd_special = pageSize - specialSize;
    PageSetPageSizeAndVersion(page, pageSize, PG_PAGE_LAYOUT_VERSION);
    /* p->pd_prune_xid = InvalidTransactionId;      done by above MemSet */
}
  • 页面初始化函数:流程首先判断参数是否正确,即pageSize是否等于BLCKSZ8KB),之后对specialSize的大小做判断
  • 初始化页面头部信息中的字段,如pd->flagspd->lowerpd->upperpd->special以及pd->pagesize_version等标志位

2、检验页面有效性

bool
PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags)
{
   
	PageHeader	p = (PageHeader) page;
	size_t *pagebytes = NULL;
	int i = 0;
	bool		checksum_failure = false;
	bool		header_sane = false;
	bool		all_zeroes = false;
	uint16		checksum = 0;

	if (!PageIsNew(page))
	{
   
		if (DataChecksumsEnabled())
		{
   
			checksum = pg_checksum_page((char *) page, blkno);

			if (checksum != p->pd_checksum) {
   
				checksum_failure = true;
			}
		}

		if ((p->pd_flags & ~PD_VALID_FLAG_BITS) == 0 && p->pd_lower <= p->pd_upper && p->pd_upper <= p->pd_special && p->pd_special <= BLCKSZ && p->pd_special == MAXALIGN(p->pd_special)) {
   
			header_sane = true;
		}
		if (header_sane && !checksum_failure) {
   
			LOG_FUNCTION_EXIT();
			return true;
		}
	}

	all_zeroes = true;
	pagebytes = (size_t *) page;
	for (i = 0; i < (BLCKSZ / sizeof(size_t)); i++)
	{
   
		if (pagebytes[i] != 0)
		{
   
			all_zeroes = false;
			break;
		}
	}

	if (all_zeroes) {
   
		LOG_FUNCTION_EXIT();
		return true;
	}

	if (checksum_failure)
	{
   
		if ((flags & PIV_LOG_WARNING) != 0) {
   
			ereport(WARNING,
				(errcode(ERRCODE_DATA_CORRUPTED), errmsg("page verification failed, calculated checksum %u but expected %u", checksum, p->pd_checksum)));
		}

		if ((flags & PIV_REPORT_STAT) != 0) {
   
			pgstat_report_checksum_failure();
		}

		if (header_sane && ignore_checksum_failure) {
   
			LOG_FUNCTION_EXIT();
			return true;
		}
	}
	return false;
}
  • 函数的作用是检查页面头部信息和检验和是否有效
  • 首先判断页面的校验和功能是否开启,如果开启,使用pg_checksum_page()函数计算页面的校验和并和页面头部信息中存储的校验和做对比
  • 计算页面头部信息的那些字段是否符合常理
  • 为了效率上的优化,不对全零页面做检测

二、表的操作

在这里插入图片描述

表的打开并不是物理的打开文件,而是返回表的RelationData结构体,核心就是两个函数:

1、relation_open

根据表的OIDlockmode来获得表的RealtionData结构体并加锁,返回relationData。如果是第一次打开,会在RelCache中创建一个新的RelationData结构体。

Relation
relation_open(Oid relationId, LOCKMODE lockmode)
{
   
	Relation	r;

	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
	
	if (lockmode != NoLock) {
   
		LockRelationOid(relationId, lockmode);
	}

	r = RelationIdGetRelation(relationId);

	if (!RelationIsValid(r)) {
   
		elog(ERROR, "could not open relation with OID %u", relationId);
	}

	Assert(lockmode != NoLock ||
		   IsBootstrapProcessingMode() ||
		   CheckRelationLockedByMe(r, AccessShareLock, true));

	if (RelationUsesLocalBuffers(r)) {
   
		MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
	}<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值