In an attempt to simplify my life I'm submitting this patch that

restructures the deferred trigger queue.  The fundamental change is to
put all the static variables to hold the deferred triggers in a single
structure.

Alvaro Herrera
This commit is contained in:
Bruce Momjian 2003-06-24 23:25:44 +00:00
parent aa62f7f74a
commit 7f7919256a
1 changed files with 70 additions and 69 deletions

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.148 2003/04/20 17:03:25 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.149 2003/06/24 23:25:44 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1601,25 +1601,22 @@ ltrmark:;
* ---------- * ----------
*/ */
typedef struct DeferredTriggersData {
/* /* Internal data is held in a per-transaction memory context */
* Internal data to the deferred trigger mechanism is held over MemoryContext deftrig_cxt;
* statements/commands in a context which is created at transaction /* ALL DEFERRED or ALL IMMEDIATE */
* start and destroyed at transaction end. bool deftrig_all_isset;
*/ bool deftrig_all_isdeferred;
/* Per trigger state */
static MemoryContext deftrig_cxt = NULL; List *deftrig_trigstates;
/* List of pending deferred triggers. Previous comment below */
/* ---------- DeferredTriggerEvent deftrig_events;
* Global data that tells which triggers are actually in DeferredTriggerEvent deftrig_events_imm;
* state IMMEDIATE or DEFERRED. DeferredTriggerEvent deftrig_event_tail;
* ---------- } DeferredTriggersData;
*/
static bool deftrig_all_isset = false;
static bool deftrig_all_isdeferred = false;
static List *deftrig_trigstates;
/* ---------- /* ----------
* deftrig_events, deftrig_event_tail:
* The list of pending deferred trigger events during the current transaction. * The list of pending deferred trigger events during the current transaction.
* *
* deftrig_events is the head, deftrig_event_tail is the last entry. * deftrig_events is the head, deftrig_event_tail is the last entry.
@ -1636,10 +1633,10 @@ static List *deftrig_trigstates;
* large... * large...
* ---------- * ----------
*/ */
static DeferredTriggerEvent deftrig_events;
static DeferredTriggerEvent deftrig_events_imm;
static DeferredTriggerEvent deftrig_event_tail;
typedef DeferredTriggersData *DeferredTriggers;
static DeferredTriggers deferredTriggers;
/* ---------- /* ----------
* deferredTriggerCheckState() * deferredTriggerCheckState()
@ -1665,7 +1662,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
/* /*
* Lookup if we know an individual state for this trigger * Lookup if we know an individual state for this trigger
*/ */
foreach(sl, deftrig_trigstates) foreach(sl, deferredTriggers->deftrig_trigstates)
{ {
trigstate = (DeferredTriggerStatus) lfirst(sl); trigstate = (DeferredTriggerStatus) lfirst(sl);
if (trigstate->dts_tgoid == tgoid) if (trigstate->dts_tgoid == tgoid)
@ -1676,21 +1673,22 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
* No individual state known - so if the user issued a SET CONSTRAINT * No individual state known - so if the user issued a SET CONSTRAINT
* ALL ..., we return that instead of the triggers default state. * ALL ..., we return that instead of the triggers default state.
*/ */
if (deftrig_all_isset) if (deferredTriggers->deftrig_all_isset)
return deftrig_all_isdeferred; return deferredTriggers->deftrig_all_isdeferred;
/* /*
* No ALL state known either, remember the default state as the * No ALL state known either, remember the default state as the
* current and return that. * current and return that.
*/ */
oldcxt = MemoryContextSwitchTo(deftrig_cxt); oldcxt = MemoryContextSwitchTo(deferredTriggers->deftrig_cxt);
trigstate = (DeferredTriggerStatus) trigstate = (DeferredTriggerStatus)
palloc(sizeof(DeferredTriggerStatusData)); palloc(sizeof(DeferredTriggerStatusData));
trigstate->dts_tgoid = tgoid; trigstate->dts_tgoid = tgoid;
trigstate->dts_tgisdeferred = trigstate->dts_tgisdeferred =
((itemstate & TRIGGER_DEFERRED_INITDEFERRED) != 0); ((itemstate & TRIGGER_DEFERRED_INITDEFERRED) != 0);
deftrig_trigstates = lappend(deftrig_trigstates, trigstate); deferredTriggers->deftrig_trigstates =
lappend(deferredTriggers->deftrig_trigstates, trigstate);
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
@ -1713,16 +1711,16 @@ deferredTriggerAddEvent(DeferredTriggerEvent event)
* "lappend". This avoids O(N^2) behavior for large numbers of events. * "lappend". This avoids O(N^2) behavior for large numbers of events.
*/ */
event->dte_next = NULL; event->dte_next = NULL;
if (deftrig_event_tail == NULL) if (deferredTriggers->deftrig_event_tail == NULL)
{ {
/* first list entry */ /* first list entry */
deftrig_events = event; deferredTriggers->deftrig_events = event;
deftrig_event_tail = event; deferredTriggers->deftrig_event_tail = event;
} }
else else
{ {
deftrig_event_tail->dte_next = event; deferredTriggers->deftrig_event_tail->dte_next = event;
deftrig_event_tail = event; deferredTriggers->deftrig_event_tail = event;
} }
} }
@ -1884,15 +1882,15 @@ deferredTriggerInvokeEvents(bool immediate_only)
* are those since deftrig_events_imm. (But if deftrig_events_imm is * are those since deftrig_events_imm. (But if deftrig_events_imm is
* NULL, we must scan the entire list.) * NULL, we must scan the entire list.)
*/ */
if (immediate_only && deftrig_events_imm != NULL) if (immediate_only && deferredTriggers->deftrig_events_imm != NULL)
{ {
prev_event = deftrig_events_imm; prev_event = deferredTriggers->deftrig_events_imm;
event = prev_event->dte_next; event = prev_event->dte_next;
} }
else else
{ {
prev_event = NULL; prev_event = NULL;
event = deftrig_events; event = deferredTriggers->deftrig_events;
} }
while (event != NULL) while (event != NULL)
@ -1994,7 +1992,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
if (prev_event) if (prev_event)
prev_event->dte_next = next_event; prev_event->dte_next = next_event;
else else
deftrig_events = next_event; deferredTriggers->deftrig_events = next_event;
pfree(event); pfree(event);
} }
else else
@ -2011,10 +2009,10 @@ deferredTriggerInvokeEvents(bool immediate_only)
} }
/* Update list tail pointer in case we just deleted tail event */ /* Update list tail pointer in case we just deleted tail event */
deftrig_event_tail = prev_event; deferredTriggers->deftrig_event_tail = prev_event;
/* Set the immediate event pointer for next time */ /* Set the immediate event pointer for next time */
deftrig_events_imm = prev_event; deferredTriggers->deftrig_events_imm = prev_event;
/* Release working resources */ /* Release working resources */
if (rel) if (rel)
@ -2052,30 +2050,32 @@ DeferredTriggerInit(void)
void void
DeferredTriggerBeginXact(void) DeferredTriggerBeginXact(void)
{ {
if (deftrig_cxt != NULL) /*
elog(ERROR, * This will be changed to a special context when
"DeferredTriggerBeginXact() called while inside transaction"); * the nested transactions project moves forward.
*/
MemoryContext cxt = TopTransactionContext;
deferredTriggers = (DeferredTriggers) MemoryContextAlloc(TopTransactionContext,
sizeof(DeferredTriggersData));
/* /*
* Create the per transaction memory context * Create the per transaction memory context
*/ */
deftrig_cxt = AllocSetContextCreate(TopTransactionContext, deferredTriggers->deftrig_cxt = AllocSetContextCreate(cxt,
"DeferredTriggerXact", "DeferredTriggerXact",
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
deftrig_all_isset = false;
/* /*
* If unspecified, constraints default to IMMEDIATE, per SQL * If unspecified, constraints default to IMMEDIATE, per SQL
*/ */
deftrig_all_isdeferred = false; deferredTriggers->deftrig_all_isdeferred = false;
deferredTriggers->deftrig_all_isset = false;
deftrig_trigstates = NIL; deferredTriggers->deftrig_trigstates = NIL;
deferredTriggers->deftrig_events = NULL;
deftrig_events = NULL; deferredTriggers->deftrig_events_imm = NULL;
deftrig_events_imm = NULL; deferredTriggers->deftrig_event_tail = NULL;
deftrig_event_tail = NULL;
} }
@ -2092,7 +2092,7 @@ DeferredTriggerEndQuery(void)
/* /*
* Ignore call if we aren't in a transaction. * Ignore call if we aren't in a transaction.
*/ */
if (deftrig_cxt == NULL) if (deferredTriggers == NULL)
return; return;
deferredTriggerInvokeEvents(true); deferredTriggerInvokeEvents(true);
@ -2112,13 +2112,12 @@ DeferredTriggerEndXact(void)
/* /*
* Ignore call if we aren't in a transaction. * Ignore call if we aren't in a transaction.
*/ */
if (deftrig_cxt == NULL) if (deferredTriggers == NULL)
return; return;
deferredTriggerInvokeEvents(false); deferredTriggerInvokeEvents(false);
MemoryContextDelete(deftrig_cxt); deferredTriggers = NULL;
deftrig_cxt = NULL;
} }
@ -2136,11 +2135,13 @@ DeferredTriggerAbortXact(void)
/* /*
* Ignore call if we aren't in a transaction. * Ignore call if we aren't in a transaction.
*/ */
if (deftrig_cxt == NULL) if (deferredTriggers == NULL)
return; return;
MemoryContextDelete(deftrig_cxt); /*
deftrig_cxt = NULL; * Forget everything we know about deferred triggers.
*/
deferredTriggers = NULL;
} }
@ -2158,7 +2159,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
/* /*
* Ignore call if we aren't in a transaction. * Ignore call if we aren't in a transaction.
*/ */
if (deftrig_cxt == NULL) if (deferredTriggers == NULL)
return; return;
/* /*
@ -2170,7 +2171,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* Drop all per-transaction information about individual trigger * Drop all per-transaction information about individual trigger
* states. * states.
*/ */
l = deftrig_trigstates; l = deferredTriggers->deftrig_trigstates;
while (l != NIL) while (l != NIL)
{ {
List *next = lnext(l); List *next = lnext(l);
@ -2179,13 +2180,13 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
pfree(l); pfree(l);
l = next; l = next;
} }
deftrig_trigstates = NIL; deferredTriggers->deftrig_trigstates = NIL;
/* /*
* Set the per-transaction ALL state to known. * Set the per-transaction ALL state to known.
*/ */
deftrig_all_isset = true; deferredTriggers->deftrig_all_isset = true;
deftrig_all_isdeferred = stmt->deferred; deferredTriggers->deftrig_all_isdeferred = stmt->deferred;
} }
else else
{ {
@ -2267,12 +2268,12 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* Inside of a transaction block set the trigger states of * Inside of a transaction block set the trigger states of
* individual triggers on transaction level. * individual triggers on transaction level.
*/ */
oldcxt = MemoryContextSwitchTo(deftrig_cxt); oldcxt = MemoryContextSwitchTo(deferredTriggers->deftrig_cxt);
foreach(l, loid) foreach(l, loid)
{ {
found = false; found = false;
foreach(ls, deftrig_trigstates) foreach(ls, deferredTriggers->deftrig_trigstates)
{ {
state = (DeferredTriggerStatus) lfirst(ls); state = (DeferredTriggerStatus) lfirst(ls);
if (state->dts_tgoid == lfirsto(l)) if (state->dts_tgoid == lfirsto(l))
@ -2289,8 +2290,8 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
state->dts_tgoid = lfirsto(l); state->dts_tgoid = lfirsto(l);
state->dts_tgisdeferred = stmt->deferred; state->dts_tgisdeferred = stmt->deferred;
deftrig_trigstates = deferredTriggers->deftrig_trigstates =
lappend(deftrig_trigstates, state); lappend(deferredTriggers->deftrig_trigstates, state);
} }
} }
@ -2308,7 +2309,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* tail pointer to make it rescan the entire list, in case some deferred * tail pointer to make it rescan the entire list, in case some deferred
* events are now immediately invokable. * events are now immediately invokable.
*/ */
deftrig_events_imm = NULL; deferredTriggers->deftrig_events_imm = NULL;
} }
@ -2337,7 +2338,7 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
ItemPointerData oldctid; ItemPointerData oldctid;
ItemPointerData newctid; ItemPointerData newctid;
if (deftrig_cxt == NULL) if (deferredTriggers == NULL)
elog(ERROR, elog(ERROR,
"DeferredTriggerSaveEvent() called outside of transaction"); "DeferredTriggerSaveEvent() called outside of transaction");
@ -2387,7 +2388,7 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
/* /*
* Create a new event * Create a new event
*/ */
oldcxt = MemoryContextSwitchTo(deftrig_cxt); oldcxt = MemoryContextSwitchTo(deferredTriggers->deftrig_cxt);
new_size = offsetof(DeferredTriggerEventData, dte_item[0]) + new_size = offsetof(DeferredTriggerEventData, dte_item[0]) +
n_enabled_triggers * sizeof(DeferredTriggerEventItem); n_enabled_triggers * sizeof(DeferredTriggerEventItem);