1
0
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:
Tom Lane
2007-03-13 00:33:44 +00:00
parent f84308f195
commit b9527e9840
61 changed files with 2478 additions and 1354 deletions

View File

@ -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

View File

@ -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.