postgressql——事务提交会通过delayChkpt阻塞checkpoint(9)

事务提交会通过delayChkpt阻塞checkpoint

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

首先看提交堆栈

复制代码
#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

函数调用过程

关键函数如下:

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

关键流程

delayChkpt阻塞checkpoint发生位置:

  1. 事务提交配置delayChkpt

    RecordTransactionCommit
    ...
    START_CRIT_SECTION();
    MyPgXact->delayChkpt = true;
    /* 写XLOG:COMMIT /
    /
    写CLOG:内存写不刷盘 */
    MyPgXact->delayChkpt = false;
    ...

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

    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);

为什么checkpoint需要等事务提交

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

情况一:redo point在commit提交前,那么如果crash发生了,redo过程会覆盖这条xlog,不会有问题

情况二:如果没有delayChkpt,redo point可能发生在上图中的位置(然后checkpoint刷完数据后,当前事务才写clog),XLOG已经先写了,如果crash发生了,redo过程不会覆盖这条xlog,而且clog信息不存在,那么commit信息彻底丢掉了。

情况三:redo point在事务提交后,redo时xlog虽然还是做不到,但是clog一定会被刷下去,所以我们不会丢失事务提交信息。

相关推荐
小二·1 小时前
RAG + 向量数据库实战:ChromaDB / Milvus / FAISS 选型与性能横评
数据库·milvus·faiss
矜持的左手1 小时前
电子小白的枕边书:电子学(The Art of Electronics)
数据库·restful
吴声子夜歌1 小时前
Redis 5.x——布隆过滤器
数据库·redis·缓存
蓝天下的守望者2 小时前
svt_apb_if里的宏定义问题
运维·服务器·数据库
上海云盾-小余2 小时前
网站频繁遭遇 SQL 注入溯源与原生漏洞修复全流程总结
数据库·sql
数据库小学妹2 小时前
国家区域医疗中心国产化改造实战:数据库选型、跨院区数据互通与踩坑经验
数据库·国产数据库·数据库选型·医疗信息化·信创数据库·医疗信创
AllData公司负责人4 小时前
数据库同步平台|AIIData数据中台实现OceanBase、达梦数据库、OpenGauss、人大金仓、Hive、TDengine 一键接入Doris
大数据·数据库·hive·mysql·oceanbase·tdengine
2603_954708314 小时前
全维度容错设计,打造微电网安全运行屏障
服务器·网络·数据库·人工智能·分布式·安全
IvorySQL4 小时前
从双解析器到循环工程:IvorySQL 五年技术演进路线的深度观察
大数据·数据库·人工智能·postgresql·开源