Skip to content

Commit d573e23

Browse files
committed
Take fewer snapshots.
When a PORTAL_ONE_SELECT query is executed, we can opportunistically reuse the parse/plan shot for the execution phase. This cuts down the number of snapshots per simple query from 2 to 1 for the simple protocol, and 3 to 2 for the extended protocol. Since we are only reusing a snapshot taken early in the processing of the same protocol message, the change shouldn't be user-visible, except that the remote possibility of the planning and execution snapshots being different is eliminated. Note that this change does not make it safe to assume that the parse/plan snapshot will certainly be reused; that will currently only happen if PortalStart() decides to use the PORTAL_ONE_SELECT strategy. It might be worth trying to provide some stronger guarantees here in the future, but for now we don't. Patch by me; review by Dimitri Fontaine.
1 parent e1042a3 commit d573e23

File tree

6 files changed

+39
-32
lines changed

6 files changed

+39
-32
lines changed

src/backend/commands/portalcmds.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
121121
/*
122122
* Start execution, inserting parameters if any.
123123
*/
124-
PortalStart(portal, params, GetActiveSnapshot());
124+
PortalStart(portal, params, true);
125125

126126
Assert(portal->strategy == PORTAL_ONE_SELECT);
127127

src/backend/commands/prepare.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
278278
/*
279279
* Run the portal to completion.
280280
*/
281-
PortalStart(portal, paramLI, GetActiveSnapshot());
281+
PortalStart(portal, paramLI, true);
282282

283283
(void) PortalRun(portal, FETCH_ALL, false, dest, dest, completionTag);
284284

src/backend/executor/spi.c

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,7 +1126,6 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
11261126
CachedPlan *cplan;
11271127
List *stmt_list;
11281128
char *query_string;
1129-
Snapshot snapshot;
11301129
MemoryContext oldcontext;
11311130
Portal portal;
11321131

@@ -1269,15 +1268,6 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
12691268
}
12701269
}
12711270

1272-
/* Set up the snapshot to use. */
1273-
if (read_only)
1274-
snapshot = GetActiveSnapshot();
1275-
else
1276-
{
1277-
CommandCounterIncrement();
1278-
snapshot = GetTransactionSnapshot();
1279-
}
1280-
12811271
/*
12821272
* If the plan has parameters, copy them into the portal. Note that this
12831273
* must be done after revalidating the plan, because in dynamic parameter
@@ -1293,7 +1283,13 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
12931283
/*
12941284
* Start portal execution.
12951285
*/
1296-
PortalStart(portal, paramLI, snapshot);
1286+
if (read_only)
1287+
PortalStart(portal, paramLI, true);
1288+
else
1289+
{
1290+
CommandCounterIncrement();
1291+
PortalStart(portal, paramLI, false);
1292+
}
12971293

12981294
Assert(portal->strategy != PORTAL_MULTI_QUERY);
12991295

src/backend/tcop/postgres.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -943,10 +943,6 @@ exec_simple_query(const char *query_string)
943943

944944
plantree_list = pg_plan_queries(querytree_list, 0, NULL);
945945

946-
/* Done with the snapshot used for parsing/planning */
947-
if (snapshot_set)
948-
PopActiveSnapshot();
949-
950946
/* If we got a cancel signal in analysis or planning, quit */
951947
CHECK_FOR_INTERRUPTS();
952948

@@ -971,9 +967,19 @@ exec_simple_query(const char *query_string)
971967
NULL);
972968

973969
/*
974-
* Start the portal. No parameters here.
970+
* Start the portal.
971+
*
972+
* If we took a snapshot for parsing/planning, the portal may be
973+
* able to reuse it for the execution phase. Currently, this will only
974+
* happen in PORTAL_ONE_SELECT mode. But even if PortalStart doesn't
975+
* end up being able to do this, keeping the parse/plan snapshot around
976+
* until after we start the portal doesn't cost much.
975977
*/
976-
PortalStart(portal, NULL, InvalidSnapshot);
978+
PortalStart(portal, NULL, snapshot_set);
979+
980+
/* Done with the snapshot used for parsing/planning */
981+
if (snapshot_set)
982+
PopActiveSnapshot();
977983

978984
/*
979985
* Select the appropriate output format: text unless we are doing a
@@ -1696,14 +1702,18 @@ exec_bind_message(StringInfo input_message)
16961702
cplan->stmt_list,
16971703
cplan);
16981704

1699-
/* Done with the snapshot used for parameter I/O and parsing/planning */
1700-
if (snapshot_set)
1701-
PopActiveSnapshot();
1702-
17031705
/*
17041706
* And we're ready to start portal execution.
1707+
*
1708+
* If we took a snapshot for parsing/planning, we'll try to reuse it
1709+
* for query execution (currently, reuse will only occur if
1710+
* PORTAL_ONE_SELECT mode is chosen).
17051711
*/
1706-
PortalStart(portal, params, InvalidSnapshot);
1712+
PortalStart(portal, params, snapshot_set);
1713+
1714+
/* Done with the snapshot used for parameter I/O and parsing/planning */
1715+
if (snapshot_set)
1716+
PopActiveSnapshot();
17071717

17081718
/*
17091719
* Apply the result format requests to the portal.

src/backend/tcop/pquery.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -446,16 +446,17 @@ FetchStatementTargetList(Node *stmt)
446446
* the query, they must be passed in here (caller is responsible for
447447
* giving them appropriate lifetime).
448448
*
449-
* The caller can optionally pass a snapshot to be used; pass InvalidSnapshot
450-
* for the normal behavior of setting a new snapshot. This parameter is
451-
* presently ignored for non-PORTAL_ONE_SELECT portals (it's only intended
452-
* to be used for cursors).
449+
* The use_active_snapshot parameter is currently used only for
450+
* PORTAL_ONE_SELECT portals. If it is true, the active snapshot will
451+
* be used when starting up the executor; if false, a new snapshot will
452+
* be taken. This is used both for cursors and to avoid taking an entirely
453+
* new snapshot when it isn't necessary.
453454
*
454455
* On return, portal is ready to accept PortalRun() calls, and the result
455456
* tupdesc (if any) is known.
456457
*/
457458
void
458-
PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
459+
PortalStart(Portal portal, ParamListInfo params, bool use_active_snapshot)
459460
{
460461
Portal saveActivePortal;
461462
ResourceOwner saveResourceOwner;
@@ -497,8 +498,8 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
497498
case PORTAL_ONE_SELECT:
498499

499500
/* Must set snapshot before starting executor. */
500-
if (snapshot)
501-
PushActiveSnapshot(snapshot);
501+
if (use_active_snapshot)
502+
PushActiveSnapshot(GetActiveSnapshot());
502503
else
503504
PushActiveSnapshot(GetTransactionSnapshot());
504505

src/include/tcop/pquery.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ extern List *FetchPortalTargetList(Portal portal);
2828
extern List *FetchStatementTargetList(Node *stmt);
2929

3030
extern void PortalStart(Portal portal, ParamListInfo params,
31-
Snapshot snapshot);
31+
bool use_active_snapshot);
3232

3333
extern void PortalSetResultFormat(Portal portal, int nFormats,
3434
int16 *formats);

0 commit comments

Comments
 (0)