aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execMain.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-11-30 21:22:54 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-11-30 21:22:54 +0000
commit895a94de6dffa71741586a2228275f66db03f8ca (patch)
tree55ec3c2629305d83b35f98956c3c3bee449d86bb /src/backend/executor/execMain.c
parentf0f18c7087e04a60e2612151401b07df87e51d96 (diff)
downloadpostgresql-895a94de6dffa71741586a2228275f66db03f8ca.tar.gz
postgresql-895a94de6dffa71741586a2228275f66db03f8ca.zip
Avoid incrementing the CommandCounter when CommandCounterIncrement is called
but no database changes have been made since the last CommandCounterIncrement. This should result in a significant improvement in the number of "commands" that can typically be performed within a transaction before hitting the 2^32 CommandId size limit. In particular this buys back (and more) the possible adverse consequences of my previous patch to fix plan caching behavior. The implementation requires tracking whether the current CommandCounter value has been "used" to mark any tuples. CommandCounter values stored into snapshots are presumed not to be used for this purpose. This requires some small executor changes, since the executor used to conflate the curcid of the snapshot it was using with the command ID to mark output tuples with. Separating these concepts allows some small simplifications in executor APIs. Something for the TODO list: look into having CommandCounterIncrement not do AcceptInvalidationMessages. It seems fairly bogus to be doing it there, but exactly where to do it instead isn't clear, and I'm disinclined to mess with asynchronous behavior during late beta.
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r--src/backend/executor/execMain.c65
1 files changed, 42 insertions, 23 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 4b6ad47adb0..5886234a1e8 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.300 2007/11/15 22:25:15 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.301 2007/11/30 21:22:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -161,6 +161,30 @@ ExecutorStart(QueryDesc *queryDesc, int eflags)
palloc0(queryDesc->plannedstmt->nParamExec * sizeof(ParamExecData));
/*
+ * If non-read-only query, set the command ID to mark output tuples with
+ */
+ switch (queryDesc->operation)
+ {
+ case CMD_SELECT:
+ /* SELECT INTO and SELECT FOR UPDATE/SHARE need to mark tuples */
+ if (queryDesc->plannedstmt->intoClause != NULL ||
+ queryDesc->plannedstmt->rowMarks != NIL)
+ estate->es_output_cid = GetCurrentCommandId(true);
+ break;
+
+ case CMD_INSERT:
+ case CMD_DELETE:
+ case CMD_UPDATE:
+ estate->es_output_cid = GetCurrentCommandId(true);
+ break;
+
+ default:
+ elog(ERROR, "unrecognized operation code: %d",
+ (int) queryDesc->operation);
+ break;
+ }
+
+ /*
* Copy other important information into the EState
*/
estate->es_snapshot = queryDesc->snapshot;
@@ -1285,7 +1309,7 @@ lnext: ;
test = heap_lock_tuple(erm->relation, &tuple, &buffer,
&update_ctid, &update_xmax,
- estate->es_snapshot->curcid,
+ estate->es_output_cid,
lockmode, erm->noWait);
ReleaseBuffer(buffer);
switch (test)
@@ -1309,8 +1333,7 @@ lnext: ;
newSlot = EvalPlanQual(estate,
erm->rti,
&update_ctid,
- update_xmax,
- estate->es_snapshot->curcid);
+ update_xmax);
if (!TupIsNull(newSlot))
{
slot = planSlot = newSlot;
@@ -1503,7 +1526,7 @@ ExecInsert(TupleTableSlot *slot,
* t_self field.
*/
newId = heap_insert(resultRelationDesc, tuple,
- estate->es_snapshot->curcid,
+ estate->es_output_cid,
true, true);
IncrAppended();
@@ -1557,8 +1580,7 @@ ExecDelete(ItemPointer tupleid,
{
bool dodelete;
- dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid,
- estate->es_snapshot->curcid);
+ dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid);
if (!dodelete) /* "do nothing" */
return;
@@ -1575,7 +1597,7 @@ ExecDelete(ItemPointer tupleid,
ldelete:;
result = heap_delete(resultRelationDesc, tupleid,
&update_ctid, &update_xmax,
- estate->es_snapshot->curcid,
+ estate->es_output_cid,
estate->es_crosscheck_snapshot,
true /* wait for commit */ );
switch (result)
@@ -1599,8 +1621,7 @@ ldelete:;
epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex,
&update_ctid,
- update_xmax,
- estate->es_snapshot->curcid);
+ update_xmax);
if (!TupIsNull(epqslot))
{
*tupleid = update_ctid;
@@ -1708,8 +1729,7 @@ ExecUpdate(TupleTableSlot *slot,
HeapTuple newtuple;
newtuple = ExecBRUpdateTriggers(estate, resultRelInfo,
- tupleid, tuple,
- estate->es_snapshot->curcid);
+ tupleid, tuple);
if (newtuple == NULL) /* "do nothing" */
return;
@@ -1755,7 +1775,7 @@ lreplace:;
*/
result = heap_update(resultRelationDesc, tupleid, tuple,
&update_ctid, &update_xmax,
- estate->es_snapshot->curcid,
+ estate->es_output_cid,
estate->es_crosscheck_snapshot,
true /* wait for commit */ );
switch (result)
@@ -1779,8 +1799,7 @@ lreplace:;
epqslot = EvalPlanQual(estate,
resultRelInfo->ri_RangeTableIndex,
&update_ctid,
- update_xmax,
- estate->es_snapshot->curcid);
+ update_xmax);
if (!TupIsNull(epqslot))
{
*tupleid = update_ctid;
@@ -1973,7 +1992,6 @@ ExecProcessReturning(ProjectionInfo *projectReturning,
* rti - rangetable index of table containing tuple
* *tid - t_ctid from the outdated tuple (ie, next updated version)
* priorXmax - t_xmax from the outdated tuple
- * curCid - command ID of current command of my transaction
*
* *tid is also an output parameter: it's modified to hold the TID of the
* latest version of the tuple (note this may be changed even on failure)
@@ -1983,7 +2001,7 @@ ExecProcessReturning(ProjectionInfo *projectReturning,
*/
TupleTableSlot *
EvalPlanQual(EState *estate, Index rti,
- ItemPointer tid, TransactionId priorXmax, CommandId curCid)
+ ItemPointer tid, TransactionId priorXmax)
{
evalPlanQual *epq;
EState *epqstate;
@@ -2063,17 +2081,17 @@ EvalPlanQual(EState *estate, Index rti,
/*
* If tuple was inserted by our own transaction, we have to check
- * cmin against curCid: cmin >= curCid means our command cannot
- * see the tuple, so we should ignore it. Without this we are
- * open to the "Halloween problem" of indefinitely re-updating the
- * same tuple. (We need not check cmax because
+ * cmin against es_output_cid: cmin >= current CID means our
+ * command cannot see the tuple, so we should ignore it. Without
+ * this we are open to the "Halloween problem" of indefinitely
+ * re-updating the same tuple. (We need not check cmax because
* HeapTupleSatisfiesDirty will consider a tuple deleted by our
* transaction dead, regardless of cmax.) We just checked that
* priorXmax == xmin, so we can test that variable instead of
* doing HeapTupleHeaderGetXmin again.
*/
if (TransactionIdIsCurrentTransactionId(priorXmax) &&
- HeapTupleHeaderGetCmin(tuple.t_data) >= curCid)
+ HeapTupleHeaderGetCmin(tuple.t_data) >= estate->es_output_cid)
{
ReleaseBuffer(buffer);
return NULL;
@@ -2360,6 +2378,7 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
epqstate->es_snapshot = estate->es_snapshot;
epqstate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot;
epqstate->es_range_table = estate->es_range_table;
+ epqstate->es_output_cid = estate->es_output_cid;
epqstate->es_result_relations = estate->es_result_relations;
epqstate->es_num_result_relations = estate->es_num_result_relations;
epqstate->es_result_relation_info = estate->es_result_relation_info;
@@ -2718,7 +2737,7 @@ intorel_receive(TupleTableSlot *slot, DestReceiver *self)
heap_insert(estate->es_into_relation_descriptor,
tuple,
- estate->es_snapshot->curcid,
+ estate->es_output_cid,
estate->es_into_relation_use_wal,
false); /* never any point in using FSM */