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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user