广告
返回顶部
首页 > 资讯 > 数据库 >PostgreSQL源码学习--更新数据#0
  • 387
分享到

PostgreSQL源码学习--更新数据#0

PostgreSQL源码学习--更新数据#0 2017-05-20 18:05:11 387人浏览 才女
摘要

以一条update test set b = "bcd" where a = 123;的sql语句为例,跟踪更新数据的代码逻辑。(PG版本为12.2) 删除数据主要的函数是heap_update。查看调用栈: #0 heap_u

PostgreSQL源码学习--更新数据#0

以一条update test set b = "bcd" where a = 123;的sql语句为例,跟踪更新数据的代码逻辑。(PG版本为12.2)

删除数据主要的函数是heap_update。查看调用栈:

#0  heap_update (relation=0x7fbe842e9270, otid=0x7ffffcdf4eda, 
    newtup=0x244f828, cid=0, crosscheck=0x0, wait=true, tmfd=0x7ffffcdf4df0, 
    lockmode=0x7ffffcdf4dec) at heapam.c:2898
#1  0x00000000004d3c47 in heapam_tuple_update (relation=0x7fbe842e9270, 
    otid=0x7ffffcdf4eda, slot=0x244f278, cid=0, snapshot=0x2418fa0, 
    crosscheck=0x0, wait=true, tmfd=0x7ffffcdf4df0, lockmode=0x7ffffcdf4dec, 
    update_indexes=0x7ffffcdf4deb) at heapam_handler.c:332
#2  0x00000000006dacfa in table_tuple_update (rel=0x7fbe842e9270, 
    otid=0x7ffffcdf4eda, slot=0x244f278, cid=0, snapshot=0x2418fa0, 
    crosscheck=0x0, wait=true, tmfd=0x7ffffcdf4df0, lockmode=0x7ffffcdf4dec, 
    update_indexes=0x7ffffcdf4deb)
    at ../../../src/include/access/tableam.h:1275
#3  0x00000000006dcb0d in ExecUpdate (mtstate=0x244dd40, 
    tupleid=0x7ffffcdf4eda, oldtuple=0x0, slot=0x244f278, planSlot=0x244e5a0, 
    epqstate=0x244de38, estate=0x244d9c0, canSetTag=true)
    at nodeModifyTable.c:1311
#4  0x00000000006ddfc4 in ExecModifyTable (pstate=0x244dd40)
    at nodeModifyTable.c:2222

heap_update函数

//src/include/access/heapam.h

extern TM_Result heap_update(Relation relation, ItemPointer otid,
					 HeapTuple newtup,
					 CommandId cid, Snapshot crosscheck, bool wait,
					 struct TM_FailureData *tmfd, LockTupleMode *lockmode);
//src/backend/access/heap/heapam.c

TransactionId xid = GetCurrentTransactionId();

Assert(ItemPointerIsValid(otid));


if (IsInParallelMode())
	ereport(ERROR,
			(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
			 errmsg("cannot update tuples during a parallel operation")));


hot_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_ALL);
key_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_KEY);
id_attrs = RelationGetIndexAttrBitmap(relation,
					  INDEX_ATTR_BITMAP_IDENTITY_KEY);


block = ItemPointerGetBlockNumber(otid);
buffer = ReadBuffer(relation, block);
page = BufferGetPage(buffer);

interesting_attrs = NULL;


if (!PageIsFull(page))
{
	interesting_attrs = bms_add_members(interesting_attrs, hot_attrs);
	hot_attrs_checked = true;
}
interesting_attrs = bms_add_members(interesting_attrs, key_attrs);
interesting_attrs = bms_add_members(interesting_attrs, id_attrs);


if (PageIsAllVisible(page))
	visibilitymap_pin(relation, block, &vmbuffer);


LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);

lp = PageGetItemId(page, ItemPointerGetOffsetNumber(otid));
Assert(ItemIdIsNormal(lp));


oldtup.t_tableOid = RelationGetRelid(relation);
oldtup.t_data = (HeapTupleHeader) PageGetItem(page, lp);
oldtup.t_len = ItemIdGetLength(lp);
oldtup.t_self = *otid;


newtup->t_tableOid = RelationGetRelid(relation);


modified_attrs = HeapDetermineModifiedColumns(relation, interesting_attrs,
						  &oldtup, newtup);


if (!bms_overlap(modified_attrs, key_attrs))
{
	*lockmode = LockTupleNoKeyExclusive;
	mxact_status = MultiXactStatusNoKeyUpdate;
	key_intact = true;
	
	
	MultiXactIdSetOldestMember();
}
else
{
	*lockmode = LockTupleExclusive;
	mxact_status = MultiXactStatusUpdate;
	key_intact = false;
}


l2:
checked_lockers = false;
locker_remains = false;
result = HeapTupleSatisfiesUpdate(&oldtup, cid, buffer);


Assert(result != TM_BeingModified || wait);


if (result == TM_Invisible)
{
	UnlockReleaseBuffer(buffer);
	ereport(ERROR,
			(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
			 errmsg("attempted to update invisible tuple")));
}

else if (result == TM_BeingModified && wait)
{
	bool		can_continue = false;
	
	
	xwait = HeapTupleHeaderGetRawXmax(oldtup.t_data);
	infomask = oldtup.t_data->t_infomask;
	
	
	if (infomask & HEAP_XMAX_IS_MULTI)
	{
		bool		current_is_member = false;
		
		
		if (DoesMultiXactIdConflict((MultiXactId) xwait, infomask,
						*lockmode, ¤t_is_member))
		{
			
			LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
			
			
			if (!current_is_member)
				heap_acquire_tuplock(relation, &(oldtup.t_self), *lockmode,
							 LockWaitBlock, &have_tuple_lock);
			
			
			MultiXactIdWait((MultiXactId) xwait, mxact_status, infomask,
						relation, &oldtup.t_self, XLTW_Update,
						&remain);
			checked_lockers = true;
			locker_remains = remain != 0;
			LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
			
			
			if (xmax_infomask_changed(oldtup.t_data->t_infomask,
						  infomask) ||
				!TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data),
									 xwait))
				goto l2;
		}
		
		if (!HEAP_XMAX_IS_LOCKED_ONLY(oldtup.t_data->t_infomask))
			update_xact = HeapTupleGetUpdateXid(oldtup.t_data);
		else
			update_xact = InvalidTransactionId;
		
		if (!TransactionIdIsValid(update_xact) ||
			TransactionIdDidAbort(update_xact))
			can_continue = true;
	}
	
	else if (TransactionIdIsCurrentTransactionId(xwait))
	{
		checked_lockers = true;
		locker_remains = true;
		can_continue = true;
	}
	
	else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask) && key_intact)
	{
		checked_lockers = true;
		locker_remains = true;
		can_continue = true;
	}
	
	else
	{
		
		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
		heap_acquire_tuplock(relation, &(oldtup.t_self), *lockmode,
							 LockWaitBlock, &have_tuple_lock);
		XactLockTableWait(xwait, relation, &oldtup.t_self,
						  XLTW_Update);
		checked_lockers = true;
		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
		
		
		if (xmax_infomask_changed(oldtup.t_data->t_infomask, infomask) ||
			!TransactionIdEquals(xwait,
							 HeapTupleHeaderGetRawXmax(oldtup.t_data)))
			goto l2;
		
		
		UpdateXmaxHintBits(oldtup.t_data, buffer, xwait);
		if (oldtup.t_data->t_infomask & HEAP_XMAX_INVALID)
			can_continue = true;
	}
	
	
	if (can_continue)
		result = TM_Ok;
	
	else if (!ItemPointerEquals(&oldtup.t_self, &oldtup.t_data->t_ctid) ||
			 HeapTupleHeaderIndicatesMovedPartitions(oldtup.t_data))
		result = TM_Updated;
	
	else
		result = TM_Deleted;
}


if (crosscheck != InvalidSnapshot && result == TM_Ok)
{
	if (!HeapTupleSatisfiesVisibility(&oldtup, crosscheck, buffer))
	{
		result = TM_Updated;
		Assert(!ItemPointerEquals(&oldtup.t_self, &oldtup.t_data->t_ctid));
	}
}


if (result != TM_Ok)
{
	Assert(result == TM_SelfModified ||
		   result == TM_Updated ||
		   result == TM_Deleted ||
		   result == TM_BeingModified);
	Assert(!(oldtup.t_data->t_infomask & HEAP_XMAX_INVALID));
	Assert(result != TM_Updated ||
		   !ItemPointerEquals(&oldtup.t_self, &oldtup.t_data->t_ctid));
	tmfd->ctid = oldtup.t_data->t_ctid;
	tmfd->xmax = HeapTupleHeaderGetUpdateXid(oldtup.t_data);
	if (result == TM_SelfModified)
		tmfd->cmax = HeapTupleHeaderGetCmax(oldtup.t_data);
	else
		tmfd->cmax = InvalidCommandId;
	UnlockReleaseBuffer(buffer);
	if (have_tuple_lock)
		UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode);
	if (vmbuffer != InvalidBuffer)
		ReleaseBuffer(vmbuffer);
	bms_free(hot_attrs);
	bms_free(key_attrs);
	bms_free(id_attrs);
	bms_free(modified_attrs);
	bms_free(interesting_attrs);
	return result;
}


if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
{
	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
	visibilitymap_pin(relation, block, &vmbuffer);
	LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
	goto l2;
}


compute_new_xmax_infomask(HeapTupleHeaderGetRawXmax(oldtup.t_data),
					  oldtup.t_data->t_infomask,
					  oldtup.t_data->t_infomask2,
					  xid, *lockmode, true,
					  &xmax_old_tuple, &infomask_old_tuple,
					  &infomask2_old_tuple);


if ((oldtup.t_data->t_infomask & HEAP_XMAX_INVALID) ||
	HEAP_LOCKED_UPGRADED(oldtup.t_data->t_infomask) ||
	(checked_lockers && !locker_remains))
	xmax_new_tuple = InvalidTransactionId;
else
	xmax_new_tuple = HeapTupleHeaderGetRawXmax(oldtup.t_data);


if (!TransactionIdIsValid(xmax_new_tuple))
{
	infomask_new_tuple = HEAP_XMAX_INVALID;
	infomask2_new_tuple = 0;
}
else
{
	if (oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI)
	{
		GetMultiXactIdHintBits(xmax_new_tuple, &infomask_new_tuple,
							   &infomask2_new_tuple);
	}
	else
	{
		infomask_new_tuple = HEAP_XMAX_KEYSHR_LOCK | HEAP_XMAX_LOCK_ONLY;
		infomask2_new_tuple = 0;
	}
}


newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
newtup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
HeapTupleHeaderSetXmin(newtup->t_data, xid);
HeapTupleHeaderSetCmin(newtup->t_data, cid);
newtup->t_data->t_infomask |= HEAP_UPDATED | infomask_new_tuple;
newtup->t_data->t_infomask2 |= infomask2_new_tuple;
HeapTupleHeaderSetXmax(newtup->t_data, xmax_new_tuple);


HeapTupleHeaderAdjustCmax(oldtup.t_data, &cid, &iscombo);


if (relation->rd_rel->relkind != RELKIND_RELATION &&
	relation->rd_rel->relkind != RELKIND_MATVIEW)
{
	
	Assert(!HeapTupleHasExternal(&oldtup));
	Assert(!HeapTupleHasExternal(newtup));
	need_toast = false;
}
else
	need_toast = (HeapTupleHasExternal(&oldtup) ||
			  HeapTupleHasExternal(newtup) ||
			  newtup->t_len > TOAST_TUPLE_THRESHOLD);

pagefree = PageGetHeapFreeSpace(page);

newtupsize = MAXALIGN(newtup->t_len);


if (need_toast || newtupsize > pagefree)
{
	bool		cleared_all_frozen = false;
	
	
	compute_new_xmax_infomask(HeapTupleHeaderGetRawXmax(oldtup.t_data),
						  oldtup.t_data->t_infomask,
						  oldtup.t_data->t_infomask2,
						  xid, *lockmode, false,
						  &xmax_lock_old_tuple, &infomask_lock_old_tuple,
						  &infomask2_lock_old_tuple);

	Assert(HEAP_XMAX_IS_LOCKED_ONLY(infomask_lock_old_tuple));
	
	START_CRIT_SECTION();
	
	
	oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
	oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
	HeapTupleClearHotUpdated(&oldtup);
	
	Assert(TransactionIdIsValid(xmax_lock_old_tuple));
	HeapTupleHeaderSetXmax(oldtup.t_data, xmax_lock_old_tuple);
	oldtup.t_data->t_infomask |= infomask_lock_old_tuple;
	oldtup.t_data->t_infomask2 |= infomask2_lock_old_tuple;
	HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo);
	
	
	oldtup.t_data->t_ctid = oldtup.t_self;
	
	
	if (PageIsAllVisible(BufferGetPage(buffer)) &&
		visibilitymap_clear(relation, block, vmbuffer,
					VISIBILITYMAP_ALL_FROZEN))
		cleared_all_frozen = true;
	
	
	MarkBufferDirty(buffer);
	
	
	if (RelationNeedsWAL(relation))
	{
		xl_heap_lock xlrec;
		XLogRecPtr	recptr;

		XLogBeginInsert();
		XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);

		xlrec.offnum = ItemPointerGetOffsetNumber(&oldtup.t_self);
		xlrec.locking_xid = xmax_lock_old_tuple;
		xlrec.infobits_set = compute_infobits(oldtup.t_data->t_infomask,
							  oldtup.t_data->t_infomask2);
		xlrec.flags =
			cleared_all_frozen ? XLH_LOCK_ALL_FROZEN_CLEARED : 0;
		XLogRegisterData((char *) &xlrec, SizeOfHeapLock);
		recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_LOCK);
		PageSetLSN(page, recptr);
	}
	
	END_CRIT_SECTION();

	
	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
	
	
	if (need_toast)
	{
		heaptup = toast_insert_or_update(relation, newtup, &oldtup, 0);
		newtupsize = MAXALIGN(heaptup->t_len);
	}
	else
		heaptup = newtup;
	
	if (newtupsize > pagefree)
	{
		newbuf = RelationGetBufferForTuple(relation, heaptup->t_len,
							   buffer, 0, NULL,
							   &vmbuffer_new, &vmbuffer);
	}
	else
	{
		
		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
		
		pagefree = PageGetHeapFreeSpace(page)
		if (newtupsize > pagefree)
		{
			LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
			newbuf = RelationGetBufferForTuple(relation, heaptup->t_len,
							   buffer, 0, NULL,
							   &vmbuffer_new, &vmbuffer);
		}
		else
		{
			newbuf = buffer;
		}
	}
}

else
{
	newbuf = buffer;
	heaptup = newtup;
}


CheckForSerializableConflictIn(relation, &oldtup, buffer);


if (newbuf == buffer)
{
	if (hot_attrs_checked && !bms_overlap(modified_attrs, hot_attrs))
		use_hot_update = true;
}

else
{
	PageSetFull(page);
}


old_key_tuple = ExtractReplicaIdentity(relation, &oldtup,
					   bms_overlap(modified_attrs, id_attrs),
					   &old_key_copied);

START_CRIT_SECTION();


PageSetPrunable(page, xid);


if (use_hot_update)
{
	HeapTupleSetHotUpdated(&oldtup);
	HeapTupleSetHeapOnly(heaptup);
	HeapTupleSetHeapOnly(newtup);
}

else
{
	HeapTupleClearHotUpdated(&oldtup);
	HeapTupleClearHeapOnly(heaptup);
	HeapTupleClearHeapOnly(newtup);
}


RelationPutHeapTuple(relation, newbuf, heaptup, false);


oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;

Assert(TransactionIdIsValid(xmax_old_tuple));
HeapTupleHeaderSetXmax(oldtup.t_data, xmax_old_tuple);
oldtup.t_data->t_infomask |= infomask_old_tuple;
oldtup.t_data->t_infomask2 |= infomask2_old_tuple;
HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo);


oldtup.t_data->t_ctid = heaptup->t_self;


if (PageIsAllVisible(BufferGetPage(buffer)))
{
	all_visible_cleared = true;
	PageClearAllVisible(BufferGetPage(buffer));
	visibilitymap_clear(relation, BufferGetBlockNumber(buffer),
						vmbuffer, VISIBILITYMAP_VALID_BITS);
}
if (newbuf != buffer && PageIsAllVisible(BufferGetPage(newbuf)))
{
	all_visible_cleared_new = true;
	PageClearAllVisible(BufferGetPage(newbuf));
	visibilitymap_clear(relation, BufferGetBlockNumber(newbuf),
						vmbuffer_new, VISIBILITYMAP_VALID_BITS);
}


if (newbuf != buffer)
	MarkBufferDirty(newbuf);
MarkBufferDirty(buffer);


if (RelationNeedsWAL(relation))
{
	
	if (RelationIsAccessibleInLogicalDecoding(relation))
	{
		log_heap_new_cid(relation, &oldtup);
		log_heap_new_cid(relation, heaptup);
	}

	recptr = log_heap_update(relation, buffer,
					 newbuf, &oldtup, heaptup,
					 old_key_tuple,
					 all_visible_cleared,
					 all_visible_cleared_new);
	if (newbuf != buffer)
	{
		PageSetLSN(BufferGetPage(newbuf), recptr);
	}
	PageSetLSN(BufferGetPage(buffer), recptr);
}

END_CRIT_SECTION();


if (newbuf != buffer)
	LockBuffer(newbuf, BUFFER_LOCK_UNLOCK);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);


CacheInvalidateHeapTuple(relation, &oldtup, heaptup);


if (newbuf != buffer)
	ReleaseBuffer(newbuf);
ReleaseBuffer(buffer);
if (BufferIsValid(vmbuffer_new))
	ReleaseBuffer(vmbuffer_new);
if (BufferIsValid(vmbuffer))
	ReleaseBuffer(vmbuffer);


if (have_tuple_lock)
	UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode);


pgstat_count_heap_update(relation, use_hot_update);


if (heaptup != newtup)
{
	newtup->t_self = heaptup->t_self;
	heap_freetuple(heaptup);
}

if (old_key_tuple != NULL && old_key_copied)
	heap_freetuple(old_key_tuple);

bms_free(hot_attrs);
bms_free(key_attrs);
bms_free(id_attrs);
bms_free(modified_attrs);
bms_free(interesting_attrs);

return TM_Ok;
您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL源码学习--更新数据#0

本文链接: https://www.lsjlt.com/news/6601.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作