Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb40bc9e

Browse files
committed
Avoid O(N^2) behavior with lots of deferred triggers by making
deferredTriggerInvokeEvents only scan events added since it last ran.Stephan Szabo, some corrections by Tom Lane.
1 parent7773434 commitb40bc9e

File tree

1 file changed

+38
-11
lines changed

1 file changed

+38
-11
lines changed

‎src/backend/commands/trigger.c

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.147 2003/03/31 20:47:51 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.148 2003/04/20 17:03:25 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -1626,12 +1626,18 @@ static List *deftrig_trigstates;
16261626
* Because this can grow pretty large, we don't use separate List nodes,
16271627
* but instead thread the list through the dte_next fields of the member
16281628
* nodes. Saves just a few bytes per entry, but that adds up.
1629+
*
1630+
* deftrig_events_imm holds the tail pointer as of the last
1631+
* deferredTriggerInvokeEvents call; we can use this to avoid rescanning
1632+
* entries unnecessarily. It is NULL if deferredTriggerInvokeEvents
1633+
* hasn't run since the last state change.
16291634
*
16301635
* XXX Need to be able to shove this data out to a file if it grows too
16311636
* large...
16321637
* ----------
16331638
*/
16341639
staticDeferredTriggerEventdeftrig_events;
1640+
staticDeferredTriggerEventdeftrig_events_imm;
16351641
staticDeferredTriggerEventdeftrig_event_tail;
16361642

16371643

@@ -1845,7 +1851,7 @@ static void
18451851
deferredTriggerInvokeEvents(boolimmediate_only)
18461852
{
18471853
DeferredTriggerEventevent,
1848-
prev_event=NULL;
1854+
prev_event;
18491855
MemoryContextper_tuple_context;
18501856
Relationrel=NULL;
18511857
TriggerDesc*trigdesc=NULL;
@@ -1857,13 +1863,12 @@ deferredTriggerInvokeEvents(bool immediate_only)
18571863
* are going to discard the whole event queue on return anyway, so no
18581864
* need to bother with "retail" pfree's.
18591865
*
1860-
* In a scenario with many commands in a transaction and many
1861-
* deferred-to-end-of-transaction triggers, it could get annoying to
1862-
* rescan all the deferred triggers at each command end. To speed this
1863-
* up, we could remember the actual end of the queue at EndQuery and
1864-
* examine only events that are newer. On state changes we simply
1865-
* reset the saved position to the beginning of the queue and process
1866-
* all events once with the new states.
1866+
* If immediate_only is true, we need only scan from where the end of
1867+
* the queue was at the previous deferredTriggerInvokeEvents call;
1868+
* any non-deferred events before that point are already fired.
1869+
* (But if the deferral state changes, we must reset the saved position
1870+
* to the beginning of the queue, so as to process all events once with
1871+
* the new states. See DeferredTriggerSetState.)
18671872
*/
18681873

18691874
/* Make a per-tuple memory context for trigger function calls */
@@ -1874,7 +1879,22 @@ deferredTriggerInvokeEvents(bool immediate_only)
18741879
ALLOCSET_DEFAULT_INITSIZE,
18751880
ALLOCSET_DEFAULT_MAXSIZE);
18761881

1877-
event=deftrig_events;
1882+
/*
1883+
* If immediate_only is true, then the only events that could need firing
1884+
* are those since deftrig_events_imm. (But if deftrig_events_imm is
1885+
* NULL, we must scan the entire list.)
1886+
*/
1887+
if (immediate_only&&deftrig_events_imm!=NULL)
1888+
{
1889+
prev_event=deftrig_events_imm;
1890+
event=prev_event->dte_next;
1891+
}
1892+
else
1893+
{
1894+
prev_event=NULL;
1895+
event=deftrig_events;
1896+
}
1897+
18781898
while (event!=NULL)
18791899
{
18801900
boolstill_deferred_ones= false;
@@ -1993,6 +2013,9 @@ deferredTriggerInvokeEvents(bool immediate_only)
19932013
/* Update list tail pointer in case we just deleted tail event */
19942014
deftrig_event_tail=prev_event;
19952015

2016+
/* Set the immediate event pointer for next time */
2017+
deftrig_events_imm=prev_event;
2018+
19962019
/* Release working resources */
19972020
if (rel)
19982021
heap_close(rel,NoLock);
@@ -2051,6 +2074,7 @@ DeferredTriggerBeginXact(void)
20512074
deftrig_trigstates=NIL;
20522075

20532076
deftrig_events=NULL;
2077+
deftrig_events_imm=NULL;
20542078
deftrig_event_tail=NULL;
20552079
}
20562080

@@ -2280,8 +2304,11 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
22802304
* CONSTRAINTS command applies retroactively. This happens "for free"
22812305
* since we have already made the necessary modifications to the
22822306
* constraints, and deferredTriggerEndQuery() is called by
2283-
* finish_xact_command().
2307+
* finish_xact_command(). But we must reset deferredTriggerInvokeEvents'
2308+
* tail pointer to make it rescan the entire list, in case some deferred
2309+
* events are now immediately invokable.
22842310
*/
2311+
deftrig_events_imm=NULL;
22852312
}
22862313

22872314

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp