aboutsummaryrefslogtreecommitdiff
path: root/src/include/executor
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2011-09-16 00:42:53 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2011-09-16 00:43:52 -0400
commite6faf910d75027bdce7cd0f2033db4e912592bcc (patch)
treeb5fdc2340cc1cdf27dd473e23a09cb2953b5053c /src/include/executor
parent09e98a3e170ecdeb25a0e1afe81bdbeeeaf21f48 (diff)
downloadpostgresql-e6faf910d75027bdce7cd0f2033db4e912592bcc.tar.gz
postgresql-e6faf910d75027bdce7cd0f2033db4e912592bcc.zip
Redesign the plancache mechanism for more flexibility and efficiency.
Rewrite plancache.c so that a "cached plan" (which is rather a misnomer at this point) can support generation of custom, parameter-value-dependent plans, and can make an intelligent choice between using custom plans and the traditional generic-plan approach. The specific choice algorithm implemented here can probably be improved in future, but this commit is all about getting the mechanism in place, not the policy. In addition, restructure the API to greatly reduce the amount of extraneous data copying needed. The main compromise needed to make that possible was to split the initial creation of a CachedPlanSource into two steps. It's worth noting in particular that SPI_saveplan is now deprecated in favor of SPI_keepplan, which accomplishes the same end result with zero data copying, and no need to then spend even more cycles throwing away the original SPIPlan. The risk of long-term memory leaks while manipulating SPIPlans has also been greatly reduced. Most of this improvement is based on use of the recently-added MemoryContextSetParent primitive.
Diffstat (limited to 'src/include/executor')
-rw-r--r--src/include/executor/spi.h1
-rw-r--r--src/include/executor/spi_priv.h41
2 files changed, 24 insertions, 18 deletions
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 7199debb27a..3b1b27ee49e 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -93,6 +93,7 @@ extern SPIPlanPtr SPI_prepare_params(const char *src,
ParserSetupHook parserSetup,
void *parserSetupArg,
int cursorOptions);
+extern int SPI_keepplan(SPIPlanPtr plan);
extern SPIPlanPtr SPI_saveplan(SPIPlanPtr plan);
extern int SPI_freeplan(SPIPlanPtr plan);
diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h
index 5865f532802..3e7bf860948 100644
--- a/src/include/executor/spi_priv.h
+++ b/src/include/executor/spi_priv.h
@@ -32,27 +32,32 @@ typedef struct
} _SPI_connection;
/*
- * SPI plans have two states: saved or unsaved.
+ * SPI plans have three states: saved, unsaved, or temporary.
*
- * For an unsaved plan, the _SPI_plan struct and all its subsidiary data are in
- * a dedicated memory context identified by plancxt. An unsaved plan is good
- * at most for the current transaction, since the locks that protect it from
- * schema changes will be lost at end of transaction. Hence the plancxt is
- * always a transient one.
+ * Ordinarily, the _SPI_plan struct itself as well as the argtypes array
+ * are in a dedicated memory context identified by plancxt (which can be
+ * really small). All the other subsidiary state is in plancache entries
+ * identified by plancache_list (note: the list cells themselves are in
+ * plancxt).
*
- * For a saved plan, the _SPI_plan struct and the argument type array are in
- * the plancxt (which can be really small). All the other subsidiary state
- * is in plancache entries identified by plancache_list (note: the list cells
- * themselves are in plancxt). We rely on plancache.c to keep the cache
- * entries up-to-date as needed. The plancxt is a child of CacheMemoryContext
- * since it should persist until explicitly destroyed.
+ * In an unsaved plan, the plancxt as well as the plancache entries' contexts
+ * are children of the SPI procedure context, so they'll all disappear at
+ * function exit. plancache.c also knows that the plancache entries are
+ * "unsaved", so it doesn't link them into its global list; hence they do
+ * not respond to inval events. This is OK since we are presumably holding
+ * adequate locks to prevent other backends from messing with the tables.
*
- * To avoid redundant coding, the representation of unsaved plans matches
- * that of saved plans, ie, plancache_list is a list of CachedPlanSource
- * structs which in turn point to CachedPlan structs. However, in an unsaved
- * plan all these structs are just created by spi.c and are not known to
- * plancache.c. We don't try very hard to make all their fields valid,
- * only the ones spi.c actually uses.
+ * For a saved plan, the plancxt is made a child of CacheMemoryContext
+ * since it should persist until explicitly destroyed. Likewise, the
+ * plancache entries will be under CacheMemoryContext since we tell
+ * plancache.c to save them. We rely on plancache.c to keep the cache
+ * entries up-to-date as needed in the face of invalidation events.
+ *
+ * There are also "temporary" SPI plans, in which the _SPI_plan struct is
+ * not even palloc'd but just exists in some function's local variable.
+ * The plancache entries are unsaved and exist under the SPI executor context,
+ * while additional data such as argtypes and list cells is loose in the SPI
+ * executor context. Such plans can be identified by having plancxt == NULL.
*
* Note: if the original query string contained only whitespace and comments,
* the plancache_list will be NIL and so there is no place to store the