diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-09-16 00:42:53 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-09-16 00:43:52 -0400 |
commit | e6faf910d75027bdce7cd0f2033db4e912592bcc (patch) | |
tree | b5fdc2340cc1cdf27dd473e23a09cb2953b5053c /src/include/executor | |
parent | 09e98a3e170ecdeb25a0e1afe81bdbeeeaf21f48 (diff) | |
download | postgresql-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.h | 1 | ||||
-rw-r--r-- | src/include/executor/spi_priv.h | 41 |
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 |