mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
First phase of plan-invalidation project: create a plan cache management
module and teach PREPARE and protocol-level prepared statements to use it. In service of this, rearrange utility-statement processing so that parse analysis does not assume table schemas can't change before execution for utility statements (necessary because we don't attempt to re-acquire locks for utility statements when reusing a stored plan). This requires some refactoring of the ProcessUtility API, but it ends up cleaner anyway, for instance we can get rid of the QueryContext global. Still to do: fix up SPI and related code to use the plan cache; I'm tempted to try to make SQL functions use it too. Also, there are at least some aspects of system state that we want to ensure remain the same during a replan as in the original processing; search_path certainly ought to behave that way for instance, and perhaps there are others.
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
$PostgreSQL: pgsql/src/backend/utils/resowner/README,v 1.4 2006/06/16 18:42:23 tgl Exp $
|
||||
$PostgreSQL: pgsql/src/backend/utils/resowner/README,v 1.5 2007/03/13 00:33:42 tgl Exp $
|
||||
|
||||
Notes about resource owners
|
||||
---------------------------
|
||||
@ -60,12 +60,13 @@ subtransaction or portal. Therefore, the "release" operation on a child
|
||||
ResourceOwner transfers lock ownership to the parent instead of actually
|
||||
releasing the lock, if isCommit is true.
|
||||
|
||||
Currently, ResourceOwners contain direct support for recording ownership
|
||||
of buffer pins, lmgr locks, and catcache, relcache, and tupdesc references.
|
||||
Other objects can be associated with a ResourceOwner by recording the address
|
||||
of the owning ResourceOwner in such an object. There is an API for other
|
||||
modules to get control during ResourceOwner release, so that they can scan
|
||||
their own data structures to find the objects that need to be deleted.
|
||||
Currently, ResourceOwners contain direct support for recording ownership of
|
||||
buffer pins, lmgr locks, and catcache, relcache, plancache, and tupdesc
|
||||
references. Other objects can be associated with a ResourceOwner by recording
|
||||
the address of the owning ResourceOwner in such an object. There is an API
|
||||
for other modules to get control during ResourceOwner release, so that they
|
||||
can scan their own data structures to find the objects that need to be
|
||||
deleted.
|
||||
|
||||
Whenever we are inside a transaction, the global variable
|
||||
CurrentResourceOwner shows which resource owner should be assigned
|
||||
|
@ -14,7 +14,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.23 2007/01/05 22:19:47 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.24 2007/03/13 00:33:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -56,6 +56,11 @@ typedef struct ResourceOwnerData
|
||||
Relation *relrefs; /* dynamically allocated array */
|
||||
int maxrelrefs; /* currently allocated array size */
|
||||
|
||||
/* We have built-in support for remembering plancache references */
|
||||
int nplanrefs; /* number of owned plancache pins */
|
||||
CachedPlan **planrefs; /* dynamically allocated array */
|
||||
int maxplanrefs; /* currently allocated array size */
|
||||
|
||||
/* We have built-in support for remembering tupdesc references */
|
||||
int ntupdescs; /* number of owned tupdesc references */
|
||||
TupleDesc *tupdescs; /* dynamically allocated array */
|
||||
@ -90,6 +95,7 @@ static void ResourceOwnerReleaseInternal(ResourceOwner owner,
|
||||
bool isCommit,
|
||||
bool isTopLevel);
|
||||
static void PrintRelCacheLeakWarning(Relation rel);
|
||||
static void PrintPlanCacheLeakWarning(CachedPlan *plan);
|
||||
static void PrintTupleDescLeakWarning(TupleDesc tupdesc);
|
||||
|
||||
|
||||
@ -280,6 +286,13 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
|
||||
PrintCatCacheListLeakWarning(owner->catlistrefs[owner->ncatlistrefs - 1]);
|
||||
ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]);
|
||||
}
|
||||
/* Ditto for plancache references */
|
||||
while (owner->nplanrefs > 0)
|
||||
{
|
||||
if (isCommit)
|
||||
PrintPlanCacheLeakWarning(owner->planrefs[owner->nplanrefs - 1]);
|
||||
ReleaseCachedPlan(owner->planrefs[owner->nplanrefs - 1], true);
|
||||
}
|
||||
/* Ditto for tupdesc references */
|
||||
while (owner->ntupdescs > 0)
|
||||
{
|
||||
@ -316,6 +329,7 @@ ResourceOwnerDelete(ResourceOwner owner)
|
||||
Assert(owner->ncatrefs == 0);
|
||||
Assert(owner->ncatlistrefs == 0);
|
||||
Assert(owner->nrelrefs == 0);
|
||||
Assert(owner->nplanrefs == 0);
|
||||
Assert(owner->ntupdescs == 0);
|
||||
|
||||
/*
|
||||
@ -341,6 +355,8 @@ ResourceOwnerDelete(ResourceOwner owner)
|
||||
pfree(owner->catlistrefs);
|
||||
if (owner->relrefs)
|
||||
pfree(owner->relrefs);
|
||||
if (owner->planrefs)
|
||||
pfree(owner->planrefs);
|
||||
if (owner->tupdescs)
|
||||
pfree(owner->tupdescs);
|
||||
|
||||
@ -758,6 +774,86 @@ PrintRelCacheLeakWarning(Relation rel)
|
||||
RelationGetRelationName(rel));
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure there is room for at least one more entry in a ResourceOwner's
|
||||
* plancache reference array.
|
||||
*
|
||||
* This is separate from actually inserting an entry because if we run out
|
||||
* of memory, it's critical to do so *before* acquiring the resource.
|
||||
*/
|
||||
void
|
||||
ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
|
||||
{
|
||||
int newmax;
|
||||
|
||||
if (owner->nplanrefs < owner->maxplanrefs)
|
||||
return; /* nothing to do */
|
||||
|
||||
if (owner->planrefs == NULL)
|
||||
{
|
||||
newmax = 16;
|
||||
owner->planrefs = (CachedPlan **)
|
||||
MemoryContextAlloc(TopMemoryContext, newmax * sizeof(CachedPlan *));
|
||||
owner->maxplanrefs = newmax;
|
||||
}
|
||||
else
|
||||
{
|
||||
newmax = owner->maxplanrefs * 2;
|
||||
owner->planrefs = (CachedPlan **)
|
||||
repalloc(owner->planrefs, newmax * sizeof(CachedPlan *));
|
||||
owner->maxplanrefs = newmax;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remember that a plancache reference is owned by a ResourceOwner
|
||||
*
|
||||
* Caller must have previously done ResourceOwnerEnlargePlanCacheRefs()
|
||||
*/
|
||||
void
|
||||
ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
|
||||
{
|
||||
Assert(owner->nplanrefs < owner->maxplanrefs);
|
||||
owner->planrefs[owner->nplanrefs] = plan;
|
||||
owner->nplanrefs++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forget that a plancache reference is owned by a ResourceOwner
|
||||
*/
|
||||
void
|
||||
ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
|
||||
{
|
||||
CachedPlan **planrefs = owner->planrefs;
|
||||
int np1 = owner->nplanrefs - 1;
|
||||
int i;
|
||||
|
||||
for (i = np1; i >= 0; i--)
|
||||
{
|
||||
if (planrefs[i] == plan)
|
||||
{
|
||||
while (i < np1)
|
||||
{
|
||||
planrefs[i] = planrefs[i + 1];
|
||||
i++;
|
||||
}
|
||||
owner->nplanrefs = np1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
elog(ERROR, "plancache reference %p is not owned by resource owner %s",
|
||||
plan, owner->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Debugging subroutine
|
||||
*/
|
||||
static void
|
||||
PrintPlanCacheLeakWarning(CachedPlan *plan)
|
||||
{
|
||||
elog(WARNING, "plancache reference leak: plan %p not closed", plan);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure there is room for at least one more entry in a ResourceOwner's
|
||||
* tupdesc reference array.
|
||||
|
Reference in New Issue
Block a user