resowner.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 748 行 · 第 1/2 页

C
748
字号
/*------------------------------------------------------------------------- * * resowner.c *	  POSTGRES resource owner management code. * * Query-lifespan resources are tracked by associating them with * ResourceOwner objects.  This provides a simple mechanism for ensuring * that such resources are freed at the right time. * See utils/resowner/README for more info. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.14.2.2 2005/12/08 19:19:31 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "utils/resowner.h"#include "access/gistscan.h"#include "access/hash.h"#include "access/rtree.h"#include "storage/bufmgr.h"#include "storage/proc.h"#include "utils/memutils.h"#include "utils/relcache.h"/* * ResourceOwner objects look like this */typedef struct ResourceOwnerData{	ResourceOwner parent;		/* NULL if no parent (toplevel owner) */	ResourceOwner firstchild;	/* head of linked list of children */	ResourceOwner nextchild;	/* next child of same parent */	const char *name;			/* name (just for debugging) */	/* We have built-in support for remembering owned buffers */	int			nbuffers;		/* number of owned buffer pins */	Buffer	   *buffers;		/* dynamically allocated array */	int			maxbuffers;		/* currently allocated array size */	/* We have built-in support for remembering catcache references */	int			ncatrefs;		/* number of owned catcache pins */	HeapTuple  *catrefs;		/* dynamically allocated array */	int			maxcatrefs;		/* currently allocated array size */	int			ncatlistrefs;	/* number of owned catcache-list pins */	CatCList  **catlistrefs;	/* dynamically allocated array */	int			maxcatlistrefs; /* currently allocated array size */	/* We have built-in support for remembering relcache references */	int			nrelrefs;		/* number of owned relcache pins */	Relation   *relrefs;		/* dynamically allocated array */	int			maxrelrefs;		/* currently allocated array size */} ResourceOwnerData;/***************************************************************************** *	  GLOBAL MEMORY															 * *****************************************************************************/ResourceOwner CurrentResourceOwner = NULL;ResourceOwner CurTransactionResourceOwner = NULL;ResourceOwner TopTransactionResourceOwner = NULL;/* * List of add-on callbacks for resource releasing */typedef struct ResourceReleaseCallbackItem{	struct ResourceReleaseCallbackItem *next;	ResourceReleaseCallback callback;	void	   *arg;} ResourceReleaseCallbackItem;static ResourceReleaseCallbackItem *ResourceRelease_callbacks = NULL;/* Internal routines */static void ResourceOwnerReleaseInternal(ResourceOwner owner,							 ResourceReleasePhase phase,							 bool isCommit,							 bool isTopLevel);static void PrintRelCacheLeakWarning(Relation rel);/***************************************************************************** *	  EXPORTED ROUTINES														 * *****************************************************************************//* * ResourceOwnerCreate *		Create an empty ResourceOwner. * * All ResourceOwner objects are kept in TopMemoryContext, since they should * only be freed explicitly. */ResourceOwnerResourceOwnerCreate(ResourceOwner parent, const char *name){	ResourceOwner owner;	owner = (ResourceOwner) MemoryContextAllocZero(TopMemoryContext,												   sizeof(ResourceOwnerData));	owner->name = name;	if (parent)	{		owner->parent = parent;		owner->nextchild = parent->firstchild;		parent->firstchild = owner;	}	return owner;}/* * ResourceOwnerRelease *		Release all resources owned by a ResourceOwner and its descendants, *		but don't delete the owner objects themselves. * * Note that this executes just one phase of release, and so typically * must be called three times.	We do it this way because (a) we want to * do all the recursion separately for each phase, thereby preserving * the needed order of operations; and (b) xact.c may have other operations * to do between the phases. * * phase: release phase to execute * isCommit: true for successful completion of a query or transaction, *			false for unsuccessful * isTopLevel: true if completing a main transaction, else false * * isCommit is passed because some modules may expect that their resources * were all released already if the transaction or portal finished normally. * If so it is reasonable to give a warning (NOT an error) should any * unreleased resources be present.  When isCommit is false, such warnings * are generally inappropriate. * * isTopLevel is passed when we are releasing TopTransactionResourceOwner * at completion of a main transaction.  This generally means that *all* * resources will be released, and so we can optimize things a bit. */voidResourceOwnerRelease(ResourceOwner owner,					 ResourceReleasePhase phase,					 bool isCommit,					 bool isTopLevel){	/* Rather than PG_TRY at every level of recursion, set it up once */	ResourceOwner save;	save = CurrentResourceOwner;	PG_TRY();	{		ResourceOwnerReleaseInternal(owner, phase, isCommit, isTopLevel);	}	PG_CATCH();	{		CurrentResourceOwner = save;		PG_RE_THROW();	}	PG_END_TRY();	CurrentResourceOwner = save;}static voidResourceOwnerReleaseInternal(ResourceOwner owner,							 ResourceReleasePhase phase,							 bool isCommit,							 bool isTopLevel){	ResourceOwner child;	ResourceOwner save;	ResourceReleaseCallbackItem *item;	/* Recurse to handle descendants */	for (child = owner->firstchild; child != NULL; child = child->nextchild)		ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);	/*	 * Make CurrentResourceOwner point to me, so that ReleaseBuffer etc don't	 * get confused.  We needn't PG_TRY here because the outermost level will	 * fix it on error abort.	 */	save = CurrentResourceOwner;	CurrentResourceOwner = owner;	if (phase == RESOURCE_RELEASE_BEFORE_LOCKS)	{		/*		 * Release buffer pins.  Note that ReleaseBuffer will remove the		 * buffer entry from my list, so I just have to iterate till there are		 * none.		 *		 * During a commit, there shouldn't be any remaining pins --- that		 * would indicate failure to clean up the executor correctly --- so		 * issue warnings.	In the abort case, just clean up quietly.		 *		 * We are careful to do the releasing back-to-front, so as to avoid		 * O(N^2) behavior in ResourceOwnerForgetBuffer().		 */		while (owner->nbuffers > 0)		{			if (isCommit)				PrintBufferLeakWarning(owner->buffers[owner->nbuffers - 1]);			ReleaseBuffer(owner->buffers[owner->nbuffers - 1]);		}		/*		 * Release relcache references.  Note that RelationClose will remove		 * the relref entry from my list, so I just have to iterate till there		 * are none.		 *		 * As with buffer pins, warn if any are left at commit time, and		 * release back-to-front for speed.		 */		while (owner->nrelrefs > 0)		{			if (isCommit)				PrintRelCacheLeakWarning(owner->relrefs[owner->nrelrefs - 1]);			RelationClose(owner->relrefs[owner->nrelrefs - 1]);		}	}	else if (phase == RESOURCE_RELEASE_LOCKS)	{		if (isTopLevel)		{			/*			 * For a top-level xact we are going to release all locks (or at			 * least all non-session locks), so just do a single lmgr call at			 * the top of the recursion.			 */			if (owner == TopTransactionResourceOwner)				ProcReleaseLocks(isCommit);		}		else		{			/*			 * Release locks retail.  Note that if we are committing a			 * subtransaction, we do NOT release its locks yet, but transfer			 * them to the parent.			 */			Assert(owner->parent != NULL);			if (isCommit)				LockReassignCurrentOwner();			else				LockReleaseCurrentOwner();		}	}	else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)	{		/*		 * Release catcache references.  Note that ReleaseCatCache will remove		 * the catref entry from my list, so I just have to iterate till there		 * are none.  Ditto for catcache lists.		 *		 * As with buffer pins, warn if any are left at commit time, and		 * release back-to-front for speed.		 */		while (owner->ncatrefs > 0)		{			if (isCommit)				PrintCatCacheLeakWarning(owner->catrefs[owner->ncatrefs - 1]);			ReleaseCatCache(owner->catrefs[owner->ncatrefs - 1]);		}		while (owner->ncatlistrefs > 0)		{			if (isCommit)				PrintCatCacheListLeakWarning(owner->catlistrefs[owner->ncatlistrefs - 1]);			ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]);		}		/* Clean up index scans too */		ReleaseResources_gist();		ReleaseResources_hash();		ReleaseResources_rtree();	}	/* Let add-on modules get a chance too */	for (item = ResourceRelease_callbacks; item; item = item->next)		(*item->callback) (phase, isCommit, isTopLevel, item->arg);	CurrentResourceOwner = save;}/* * ResourceOwnerDelete *		Delete an owner object and its descendants. * * The caller must have already released all resources in the object tree. */voidResourceOwnerDelete(ResourceOwner owner){	/* We had better not be deleting CurrentResourceOwner ... */	Assert(owner != CurrentResourceOwner);	/* And it better not own any resources, either */	Assert(owner->nbuffers == 0);	Assert(owner->ncatrefs == 0);	Assert(owner->ncatlistrefs == 0);	Assert(owner->nrelrefs == 0);	/*	 * Delete children.  The recursive call will delink the child from me, so	 * just iterate as long as there is a child.	 */	while (owner->firstchild != NULL)		ResourceOwnerDelete(owner->firstchild);	/*	 * We delink the owner from its parent before deleting it, so that if	 * there's an error we won't have deleted/busted owners still attached to	 * the owner tree.	Better a leak than a crash.	 */	ResourceOwnerNewParent(owner, NULL);	/* And free the object. */	if (owner->buffers)		pfree(owner->buffers);	if (owner->catrefs)		pfree(owner->catrefs);	if (owner->catlistrefs)		pfree(owner->catlistrefs);	if (owner->relrefs)		pfree(owner->relrefs);	pfree(owner);}/* * Fetch parent of a ResourceOwner (returns NULL if top-level owner) */ResourceOwnerResourceOwnerGetParent(ResourceOwner owner){	return owner->parent;}/* * Reassign a ResourceOwner to have a new parent */voidResourceOwnerNewParent(ResourceOwner owner,					   ResourceOwner newparent){	ResourceOwner oldparent = owner->parent;	if (oldparent)	{		if (owner == oldparent->firstchild)			oldparent->firstchild = owner->nextchild;		else		{			ResourceOwner child;			for (child = oldparent->firstchild; child; child = child->nextchild)			{				if (owner == child->nextchild)				{					child->nextchild = owner->nextchild;					break;				}			}		}	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?