前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Postgresql源码(16)数据库快照数据结构与获取

Postgresql源码(16)数据库快照数据结构与获取

作者头像
mingjie
发布2022-07-14 13:39:25
4870
发布2022-07-14 13:39:25
举报

postgresql 13.5

1 数据结构

  • 快照类型有很多,但使用通用结构来管理,SnapshotSatisfiesFunc是负责处理该快照的函数。
  • 快照主要记录 全局活跃事物列表中的 最小事务ID、最大事务ID、当前活跃事务列表、当前事务commandid
代码语言:javascript
复制
typedef struct SnapshotData
{
    /* 处理当前快照的函数 */
	SnapshotSatisfiesFunc satisfies;	/* tuple test function */

	/* 多版本控制 */
	TransactionId xmin;			/* all XID < xmin are visible to me */
	TransactionId xmax;			/* all XID >= xmax are invisible to me */
    /* 活跃事务列表 */
	TransactionId *xip;
	/* 活跃事务数量 */
	uint32		xcnt;			/* # of xact ids in xip[] */

	/* 活跃子事务 */
	TransactionId *subxip;
	int32		subxcnt;		/* # of xact ids in subxip[] */
	bool		suboverflowed;	/* has the subxip array overflowed? */

	bool		takenDuringRecovery;	/* recovery-shaped snapshot? */
	bool		copied;			/* false if it's a static snapshot */

    /* 事务中的command id 一个语句加1 */
	CommandId	curcid;			/* in my xact, CID < curcid are visible */

	/*
	 * An extra return value for HeapTupleSatisfiesDirty, not used in MVCC
	 * snapshots.
	 */
	uint32		speculativeToken;

	/*
	 * Book-keeping information, used by the snapshot manager
	 */
	uint32		active_count;	/* refcount on ActiveSnapshot stack */
	uint32		regd_count;		/* refcount on RegisteredSnapshots */
	pairingheap_node ph_node;	/* link in the RegisteredSnapshots heap */

    /* 快照生成的时间 */
	TimestampTz whenTaken;		/* timestamp when snapshot was taken */
	/* 快照生成时的lsn */
	XLogRecPtr	lsn;			/* position in the WAL stream when taken */
} SnapshotData;

xmin、xmax、xip记录了整个系统事务状态。

  • xmin:当前所有活跃事务的最小事务ID, 如果有一个事务小于这个ID,说明这个事务已经提交或终止了。
  • xmax:当前活跃的最大事务,这个值从latestCompletedXid拿到的,xmax=latestCompletedXid+1;当事务提交时,如果事务ID比latestCompletedXid大,需要更新latestCompletedXid为当前事务ID。也就是说大于等于xmax的事务一定是活跃的。
代码语言:javascript
复制
GetSnapshotData(Snapshot snapshot) 
{
    ...
	/* xmax is always latestCompletedXid + 1 */
	xmax = ShmemVariableCache->latestCompletedXid;
    ...
}

小于xmin的一定结束了,大于xmax的一定是活跃的,那中间的事务需要查看xip活跃事务列表。不在xip中的事务一定已经结束了。

2 快照处理函数

有了上述信息就可以判断元组的可见性了,判断会用到一批函数记录在SnapshotData->satisfies中(PG10)

在这里插入图片描述
在这里插入图片描述

PG13更新了函数指向方式:

代码语言:javascript
复制
typedef struct SnapshotData
{
	SnapshotType snapshot_type; /* type of snapshot */
...

每种类型对应不同的处理函数

  • SNAPSHOT_MVCC
    • 使用快照判断MVCC可见、本事务写入可见
  • SNAPSHOT_SELF
    • 如果元组记录的事务已经提交,可见
    • 如果元组记录的事务正在运行,且是当前事务,可见
  • SNAPSHOT_ANY
    • 总是可见
  • SNAPSHOT_TOAST
    • toast可见性依赖表上元组
  • SNAPSHOT_DIRTY
    • 如果元组是当前事务写入的 或 写入的事务已经提交或终止,则可见性和SELF一致
    • 如果写入的事务还在运行,和SELF不同,收集当前元组的版本信息保存到快照中
  • SNAPSHOT_HISTORIC_MVCC
    • 逻辑复制中逻辑解码的可见性判断
  • SNAPSHOT_NON_VACUUMABLE
    • false表示元组已经对所有人不可见

3 快照获取

生成快照需要遍历PGPROC和PGXACT结构,查询正在运行的所有事务信息。

  • 对于RC级别的事务,每次操作都需要重新获取快照。
  • 对于RR、S级别的事务,只使用第一次获取的快照。

快照获取:GetTransactionSnapshot 快照生成:GetSnapshotData

代码语言:javascript
复制
Snapshot
GetTransactionSnapshot(void)
{
// 逻辑解码直接拿HistoricSnapshot
	if (HistoricSnapshotActive())
	{
		Assert(!FirstSnapshotSet);
		return HistoricSnapshot;
	}

// 第一次的事务拿快照会进这个分支,FirstSnapshotSet初始化=false
	if (!FirstSnapshotSet)
	{
// catalog的快照不能比事务快照旧,失效掉后面重新拿
		InvalidateCatalogSnapshot();

...

// 如果隔离级别>=XACT_REPEATABLE_READ:可重复读或可串行化
		if (IsolationUsesXactSnapshot())
		{
// 初始化可串行化的控制结构
			if (IsolationIsSerializable())
				CurrentSnapshot = GetSerializableTransactionSnapshot(&CurrentSnapshotData);
			else
// 可重复读直接获取当前快照
				CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
			/* Make a saved copy */
// 复制一份保存起来
			CurrentSnapshot = CopySnapshot(CurrentSnapshot);
			FirstXactSnapshot = CurrentSnapshot;
			/* Mark it as "registered" in FirstXactSnapshot */
			FirstXactSnapshot->regd_count++;
			pairingheap_add(&RegisteredSnapshots, &FirstXactSnapshot->ph_node);
		}
// 如果隔离级别是RC,直接获取一个当前快照
		else
			CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

// 下次进来不走这个分支
		FirstSnapshotSet = true;
		return CurrentSnapshot;
	}

// 不是第一次调用了、而且隔离界别>=RR
	if (IsolationUsesXactSnapshot())
		return CurrentSnapshot;

	/* Don't allow catalog snapshot to be older than xact snapshot. */
	InvalidateCatalogSnapshot();


// RC级别、不是第一次拿快照:重新拿快照
	CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

	return CurrentSnapshot;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-11-26,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 数据结构
  • 2 快照处理函数
  • 3 快照获取
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档