1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-29 23:43:17 +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/mmgr/README,v 1.9 2006/09/07 22:52:01 tgl Exp $
$PostgreSQL: pgsql/src/backend/utils/mmgr/README,v 1.10 2007/03/13 00:33:42 tgl Exp $
Notes about memory allocation redesign
--------------------------------------
@@ -201,15 +201,6 @@ have dangling pointers leading to a crash at top-level commit. An example of
data kept here is pending NOTIFY messages, which are sent at top-level commit,
but only if the generating subtransaction did not abort.
QueryContext --- this is not actually a separate context, but a global
variable pointing to the context that holds the current command's parse tree.
(In simple-Query mode this points to MessageContext; when executing a
prepared statement it will point to the prepared statement's private context.
Note that the plan tree may or may not be in this same context.)
Generally it is not appropriate for any code to use QueryContext as an
allocation target --- from the point of view of any code that would be
referencing the QueryContext variable, it's a read-only context.
PortalContext --- this is not actually a separate context either, but a
global variable pointing to the per-portal context of the currently active
execution portal. This can be used if it's necessary to allocate storage
@@ -229,9 +220,7 @@ Contexts for prepared statements and portals
A prepared-statement object has an associated private context, in which
the parse and plan trees for its query are stored. Because these trees
are read-only to the executor, the prepared statement can be re-used many
times without further copying of these trees. QueryContext points at this
private context while executing any portal built from the prepared
statement.
times without further copying of these trees.
An execution-portal object has a private context that is referenced by
PortalContext when the portal is active. In the case of a portal created

View File

@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/mmgr/mcxt.c,v 1.59 2007/01/05 22:19:47 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/mmgr/mcxt.c,v 1.60 2007/03/13 00:33:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -46,8 +46,7 @@ MemoryContext MessageContext = NULL;
MemoryContext TopTransactionContext = NULL;
MemoryContext CurTransactionContext = NULL;
/* These two are transient links to contexts owned by other objects: */
MemoryContext QueryContext = NULL;
/* This is a transient link to the active portal's memory context: */
MemoryContext PortalContext = NULL;

View File

@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.99 2007/02/20 17:32:17 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.100 2007/03/13 00:33:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -149,9 +149,9 @@ GetPortalByName(const char *name)
* cases should occur in present usages of this function.
*
* Copes if given a list of Querys --- can't happen in a portal, but this
* code also supports prepared statements, which need both cases.
* code also supports plancache.c, which needs both cases.
*
* Note: the reason this is just handed a List is so that prepared statements
* Note: the reason this is just handed a List is so that plancache.c
* can share the code. For use with a portal, use PortalGetPrimaryStmt
* rather than calling this directly.
*/
@@ -275,9 +275,17 @@ CreateNewPortal(void)
*
* Notes: commandTag shall be NULL if and only if the original query string
* (before rewriting) was an empty string. Also, the passed commandTag must
* be a pointer to a constant string, since it is not copied. The caller is
* responsible for ensuring that the passed prepStmtName (if any), sourceText
* (if any), and plan trees have adequate lifetime.
* be a pointer to a constant string, since it is not copied. However,
* prepStmtName and sourceText, if provided, are copied into the portal's
* heap context for safekeeping.
*
* If cplan is provided, then it is a cached plan containing the stmts,
* and the caller must have done RevalidateCachedPlan(), causing a refcount
* increment. The refcount will be released when the portal is destroyed.
*
* If cplan is NULL, then it is the caller's responsibility to ensure that
* the passed plan trees have adequate lifetime. Typically this is done by
* copying them into the portal's heap context.
*/
void
PortalDefineQuery(Portal portal,
@@ -285,18 +293,35 @@ PortalDefineQuery(Portal portal,
const char *sourceText,
const char *commandTag,
List *stmts,
MemoryContext queryContext)
CachedPlan *cplan)
{
AssertArg(PortalIsValid(portal));
AssertState(portal->queryContext == NULL); /* else defined already */
AssertState(portal->status == PORTAL_NEW);
Assert(commandTag != NULL || stmts == NIL);
portal->prepStmtName = prepStmtName;
portal->sourceText = sourceText;
portal->prepStmtName = prepStmtName ?
MemoryContextStrdup(PortalGetHeapMemory(portal), prepStmtName) : NULL;
portal->sourceText = sourceText ?
MemoryContextStrdup(PortalGetHeapMemory(portal), sourceText) : NULL;
portal->commandTag = commandTag;
portal->stmts = stmts;
portal->queryContext = queryContext;
portal->cplan = cplan;
portal->status = PORTAL_DEFINED;
}
/*
* PortalReleaseCachedPlan
* Release a portal's reference to its cached plan, if any.
*/
static void
PortalReleaseCachedPlan(Portal portal)
{
if (portal->cplan)
{
ReleaseCachedPlan(portal->cplan, false);
portal->cplan = NULL;
}
}
/*
@@ -356,6 +381,10 @@ PortalDrop(Portal portal, bool isTopCommit)
if (PointerIsValid(portal->cleanup))
(*portal->cleanup) (portal);
/* drop cached plan reference, if any */
if (portal->cplan)
PortalReleaseCachedPlan(portal);
/*
* Release any resources still attached to the portal. There are several
* cases being covered here:
@@ -423,29 +452,6 @@ PortalDrop(Portal portal, bool isTopCommit)
pfree(portal);
}
/*
* DropDependentPortals
* Drop any portals using the specified context as queryContext.
*
* This is normally used to make sure we can safely drop a prepared statement.
*/
void
DropDependentPortals(MemoryContext queryContext)
{
HASH_SEQ_STATUS status;
PortalHashEnt *hentry;
hash_seq_init(&status, PortalHashTable);
while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
{
Portal portal = hentry->portal;
if (portal->queryContext == queryContext)
PortalDrop(portal, false);
}
}
/*
* Pre-commit processing for portals.
@@ -485,6 +491,10 @@ CommitHoldablePortals(void)
PortalCreateHoldStore(portal);
PersistHoldablePortal(portal);
/* drop cached plan reference, if any */
if (portal->cplan)
PortalReleaseCachedPlan(portal);
/*
* Any resources belonging to the portal will be released in the
* upcoming transaction-wide cleanup; the portal will no longer
@@ -630,6 +640,10 @@ AtAbort_Portals(void)
portal->cleanup = NULL;
}
/* drop cached plan reference, if any */
if (portal->cplan)
PortalReleaseCachedPlan(portal);
/*
* Any resources belonging to the portal will be released in the
* upcoming transaction-wide cleanup; they will be gone before we run
@@ -769,6 +783,10 @@ AtSubAbort_Portals(SubTransactionId mySubid,
portal->cleanup = NULL;
}
/* drop cached plan reference, if any */
if (portal->cplan)
PortalReleaseCachedPlan(portal);
/*
* Any resources belonging to the portal will be released in the
* upcoming transaction-wide cleanup; they will be gone before we