前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Postgresql源码(27)为什么事务提交会通过delayChkpt阻塞checkpoint

Postgresql源码(27)为什么事务提交会通过delayChkpt阻塞checkpoint

作者头像
mingjie
发布2022-07-14 13:43:54
3430
发布2022-07-14 13:43:54
举报

Postgresql事务在事务提交时(执行commit的最后阶段)会通过加锁阻塞checkpoint的执行,尽管时间非常短,下面分析为什么需要这样做? 不这样做会有什么问题。

1 提交堆栈

看一下事务提交堆栈

代码语言:javascript
复制
#1  0x0000000000539175 in CommitTransaction () at xact.c:2079
#2  0x0000000000539e04 in CommitTransactionCommand () at xact.c:2824
#3  0x000000000087d1ea in finish_xact_command () at postgres.c:2482
#4  0x000000000087af27 in exec_simple_query (query_string=0x24050e0 "insert into t1 values (1,1);") at postgres.c:1154

2 函数调用过程

关键流程

代码语言:javascript
复制
CommitTransaction
    ...
    latestXid = RecordTransactionCommit();
    ...
        BufmgrCommit()
        START_CRIT_SECTION()
        【关键流程】
        END_CRIT_SECTION()
        latestXid = TransactionIdLatest(xid, nchildren, children);
        SyncRepWaitForLSN(XactLastRecEnd, true);
        return latestXid;
    ...
    ProcArrayEndTransaction(MyProc, latestXid);
    
    ...
    // clean ...

3 关键流程

delayChkpt阻塞checkpoint发生位置:

1 事务提交配置delayChkpt

代码语言:javascript
复制
RecordTransactionCommit
  ...
  START_CRIT_SECTION();
  MyPgXact->delayChkpt = true;
  /* 写XLOG:COMMIT */
  /* 写CLOG:内存写不刷盘 */
  MyPgXact->delayChkpt = false;
  ...

2 CreateCheckPoint等待delayChkpt

联动CreateCheckPoint,会在【2】等在所有Xact的delayChkpt为false才能继续

代码语言:javascript
复制
CreateCheckPoint
  // 【1】计算位置(重要)
  WALInsertLockAcquireExclusive();
  curInsert = XLogBytePosToRecPtr(Insert->CurrBytePos);
  freespace = INSERT_FREESPACE(curInsert);
	if (freespace == 0)
	{
		if (curInsert % XLogSegSize == 0)
			curInsert += SizeOfXLogLongPHD;
		else
			curInsert += SizeOfXLogShortPHD;
	}
	checkPoint.redo = curInsert;
	RedoRecPtr = XLogCtl->Insert.RedoRecPtr = checkPoint.redo;
	WALInsertLockRelease();
  
	// 【2】通过delayChkpt等其他所有正在提交中、正在写日志的事务
	vxids = GetVirtualXIDsDelayingChkpt(&nvxids);
	if (nvxids > 0)
	{
		do
		{
			pg_usleep(10000L);	/* wait for 10 msec */
		} while (HaveVirtualXIDsDelayingChkpt(vxids, nvxids));
	}
	pfree(vxids);
  
  // 【3】刷数据
	CheckPointGuts(checkPoint.redo, flags);
  // 【4】记chkpt日志
	XLogBeginInsert();
	XLogRegisterData((char *) (&checkPoint), sizeof(checkPoint));
	recptr = XLogInsert(RM_XLOG_ID,
						shutdown ? XLOG_CHECKPOINT_SHUTDOWN :
						XLOG_CHECKPOINT_ONLINE);

	XLogFlush(recptr);

3 为什么checkpoint需要等事务提交?

原因:情况二的分析。

确定REDO位点是在createCheckpoint的函数前面执行的,checkpoint和事务提交并发会有下面三种情况发生(假设没有delayChkpt会有情况二发生)

在这里插入图片描述
在这里插入图片描述
  • 情况一:redo point在commit提交前,那么如果crash发生了,redo过程会覆盖这条xlog,不会有问题
  • 情况二:如果没有delayChkpt,redo point可能发生在上图中的位置(然后checkpoint刷完数据后,当前事务才写clog),XLOG已经先写了,如果crash发生了,redo过程不会覆盖这条xlog,而且clog信息不存在,那么commit信息彻底丢掉了。 20220704补充:检查点redo位点是先拿的,然后刷数据。问题场景是检查点拿了个redo位点,并发事务X的commit日志在位点前面,所以后面的redo不会做这条日志。然后呢,检查点拿了redo位点之后刷数据包括clog,但是数据都刷完了,事务X的clog才写下去。如果这会crash发生了,那redo过程既不会做X事务的commit日志,也不能查到X事务的clog事务信息。结果这个事务状态就永远丢掉了。
  • 情况三:redo point在事务提交后,redo时xlog虽然还是做不到,但是clog一定会被刷下去,所以我们不会丢失事务提交信息。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-07-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 提交堆栈
  • 2 函数调用过程
  • 3 关键流程
    • 1 事务提交配置delayChkpt
      • 2 CreateCheckPoint等待delayChkpt
      • 3 为什么checkpoint需要等事务提交?
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档