IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> postgresql源码学习(十九)—— MVCC④-可见性判断 HeapTupleSatisfiesMVCC函数 -> 正文阅读

[大数据]postgresql源码学习(十九)—— MVCC④-可见性判断 HeapTupleSatisfiesMVCC函数

? ? ? ?拖了好久总算把这一节啃完了...做个记录,有一部分判断条件的案例还没想到,集齐之后可能会再加一篇案例。

一、 可见性判断

? ? ? ?回顾一下前面提到的SNAPSHOT_MVCC类型快照的可见性判断条件:

postgresql源码学习(十七)—— MVCC②-快照与隔离级别简介_Hehuyi_In的博客-CSDN博客_快照隔离级别

可见情况:

  • 在创建快照时所有已提交的事务
  • 本事务之前执行的命令

不可见情况:

  • 在创建快照时尚活跃的事务
  • 在创建快照后启动的事务
  • 当前命令造成的变化(changes made by the current command)

下面以HeapTupleSatisfiesMVCC函数为例具体学习

二、 HeapTupleSatisfiesMVCC函数

? ? ? ?判断元组对于当前给定的MVCC快照是否可见,是则返回true,否则返回false。

? ? ? ?从前面的判断规则和函数代码可以知道,这个函数是基于可重复读级别判断的。

? ? ? ?由于这个函数分支实在太多,画了一幅流程图帮助理解:不同颜色的几个分区代表核心的几个条件分支;另外其中有很多类似的判断条件,标注了相同的颜色。

? ? ? ?如果有理解错误或者画得不对的地方还请指正~

函数代码如下:

? ? ? ?首先是流程图中蓝绿色区域,这部分的前提是元组xmin尚未提交,另外根据该元组是不是本事务写入的,又展开两个主要分支(蓝色区域)。

/*
* HeapTupleSatisfiesMVCC -- 如果元组(htup参数)对于给定的MVCC快照(snapshot参数)可见,则返回true,否则返回false
*/
static bool
HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
					   Buffer buffer)
{
	HeapTupleHeader tuple = htup->t_data;

	Assert(ItemPointerIsValid(&htup->t_self));
	Assert(htup->t_tableOid != InvalidOid);

// A. xmin事务未提交(HEAP_XMIN_COMMITTED标记未设置)
	if (!HeapTupleHeaderXminCommitted(tuple))
	{
         // xmin为INVALID,通常是写入失败导致的,直接返回false
		if (HeapTupleHeaderXminInvalid(tuple))
			return false;
// A. 元组xmin对应事务未提交
         // A1. 本事务写入的元组(xmin是当前事务id)
		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
		{
/* xmin未提交,且xmin为本事务写入,说明是在同一个事务内的插入和查询命令,此时需要判断cid。同一个事务内,后面的查询可以查到当前事务之前命令插入且未删除的结果。
cid 表示在该事务中,执行当前sql之前还执行过几条sql,因此cid越大,执行顺序越靠后 */
	/* A1-1. 元组cid >= 快照cid,说明元组是在获得快照后写入的,不可见(如何模拟?) */	

			if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
				return false;	/* inserted after scan started */

// 若不符合前面,说明元组是在获得快照前写入的,继续判断其可见性
/* A1-2.元组xmax是invalid,说明没有被删除,可见 */
			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
				return true;

/* xmax在两种情况下被设置:对元组加锁;元组被删除。
A1-3.如果元组是在加锁的情况下设置了xmax,则可见 */
			if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))	/* not deleter */
				return true;

/* xmax是 MultiXactId的场景,这里仍然判断xmax的作用是加锁还是删除 */
			if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
			{
				TransactionId xmax;

				xmax = HeapTupleGetUpdateXid(tuple);

				/* not LOCKED_ONLY, so it has to have an xmax */
				Assert(TransactionIdIsValid(xmax));

				/* updating subtransaction must have aborted,执行更新的子事务必须已回滚(因为前提是xmin事务是未提交的,因此xmax必须已回滚)。 */

/* 若xmax不是当前事务id,返回可见(不是当前事务删除的,由于隔离级别是可重复读,即使其他事务删除后已提交,对本快照依然是可见的) */
				if (!TransactionIdIsCurrentTransactionId(xmax))
					return true;

/* 当前事务在获取快照后做的元组update,可见*/
				else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
					return true;	/* updated after scan started */
/* 当前事务在获取快照前做的元组update,不可见*/
else
					return false;	/* updated before scan started */
			}

// A1-4. xmax不是当前事务id 。xmax非MultiXactId,且非本事务删除的元组
if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
			{
				/* deleting subtransaction must have aborted,执行删除的子事务必须已回滚*/
/* 返回可见(不是当前事务删除的,由于隔离级别是可重复读,即使其他事务删除后已提交,对本快照依然是可见的) */

				SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
							InvalidTransactionId);
				return true;
			}

			if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
				return true;	/* deleted after scan started,A1-5. 如果是在快照后做的元组delete,则可见*/
			else
				return false;	/* deleted before scan started,A1-6. 如果是在快照前做的元组delete,则不可见*/
		}
         
         // XidInMVCCSnapshot用于判断xid对应事务是否仍在运行,若为true说明还在运行
// A.xmin事务未提交;
// A2.xmin事务仍在运行,不可见
		else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
			return false;

// A.xmin事务未提交;
	    // A3. xmin事务已提交,这里只设一个标记位,留到后面处理
		else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
						HeapTupleHeaderGetRawXmin(tuple));

// A4. 以上情况都不符合,说明xmin事务是异常终止的,则设置xmin为INVALID状态,返回不可见
		else
		{
			/* it must have aborted or crashed */
			SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
						InvalidTransactionId);
			return false;
		}
	}
    
    // xmin事务已提交
	else
	{
		/* B. 即使xmin已提交,如果不是本事务写入的元组,由于隔离级别是可重复读,即使其他事务插入后已提交,对本快照依然不可见 */
		if (!HeapTupleHeaderXminFrozen(tuple) &&
			XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
			return false;		/* treat as still in progress */
	}

? ? ? ?下面开始对应黄色区域,其前提都是xmin对应事务已提交(从指向黄色区域的两条线也可以看出),另外这部分的判断条件跟前面非常类似,可以对照流程图中相同颜色部分学习。

/* by here, the inserting transaction has committed,下面部分,插入的事务已提交,判断跟前面很类似 */

//C. xmin事务已提交
//C1.xmax无效,元组未被删除,可见
	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted,未被删除,可见 */
		return true;
// C2. xmax的作用是锁标记,可见
	if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
		return true;
// xmax是MultiXactId
	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
	{
		TransactionId xmax;

		/* already checked above,再次检查 */
		Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));

		/* 获取删除元组的事务id */
		xmax = HeapTupleGetUpdateXid(tuple);

		/* not LOCKED_ONLY, so it has to have an xmax,不是仅作为锁标记,所以必须有xmax */
		Assert(TransactionIdIsValid(xmax));

/* 若删除元组的是当前事务(xmax是当前事务id) */
		if (TransactionIdIsCurrentTransactionId(xmax))
		{
/* 当前事务在获取快照后做的元组删除,可见*/
			if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
				return true;	/* deleted after scan started */
/* 当前事务在获取快照前做的元组删除,不可见*/
			else
				return false;	/* deleted before scan started */
		}

/* 若删除元组的不是当前事务,则检查它是否是快照中的活跃事务,如果是,则这个操作尚未提交,可见 */
		if (XidInMVCCSnapshot(xmax, snapshot))
			return true;
/* updating transaction committed,更新操作已提交,不可见 */
		if (TransactionIdDidCommit(xmax))
			return false;		
		/* it must have aborted or crashed,更新元组的事务异常终止,更新被回滚,元组仍可见 */
		return true;
	}

// C3. xmax非MultiXactId,且元组xmax未设置提交标记,需要判断可见性。	
if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
	{
// C3-1. 本事务删除的元组(xmax是当前事务id)
		if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
		{
			if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
				return true;	/* deleted after scan started,如果是在快照后做的元组delete,则可见 */
			else
				return false;	/* deleted before scan started,如果是在快照前做的元组delete,则不可见 */
		}

        // C3-2. 非本事务删除
// xmax事务仍在运行中,可见
		if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
			return true;
// C3-3.xmax事务未提交,说明已回滚或者崩溃了,可见
		if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
		{
			/* it must have aborted or crashed */
			SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
						InvalidTransactionId);
			return true;
		}

		/* xmax transaction committed,以上判断均不成立,说明xmax对应事务已提交,可见 */
		SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
					HeapTupleHeaderGetRawXmax(tuple));
	}
// 否则,说明xmax已设置提交标记
	else
	{
		/* xmax is committed, but maybe not according to our snapshot
C4. 同样由于可重复读隔离级别,非本事务修改的,即使xmax已提交也可以看到修改前的值 */
		if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
			return true;		/* treat as still in progress */
	}

	/* xmax transaction committed,C5. xmax已提交,则不可见 */

	return false;
}

参考

PostgreSQL技术内幕:事务处理深度探索》第3章

PostgreSQL 源码解读(118)- MVCC#3(Tuple可见性判断)_ITPUB博客

openGauss事务机制中MVCC技术的实现分析_胡正策的博客-CSDN博客

https://developer.aliyun.com/article/281215

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:41:08  更:2022-10-17 12:45:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年3日历 -2025/3/4 7:31:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码