]> granicus.if.org Git - postgresql/blob - src/backend/access/transam/xact.c
First phase of memory management rewrite (see backend/utils/mmgr/README
[postgresql] / src / backend / access / transam / xact.c
1 /*-------------------------------------------------------------------------
2  *
3  * xact.c
4  *        top level transaction system support routines
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.68 2000/06/28 03:31:05 tgl Exp $
12  *
13  * NOTES
14  *              Transaction aborts can now occur two ways:
15  *
16  *              1)      system dies from some internal cause  (Assert, etc..)
17  *              2)      user types abort
18  *
19  *              These two cases used to be treated identically, but now
20  *              we need to distinguish them.  Why?      consider the following
21  *              two situations:
22  *
23  *                              case 1                                                  case 2
24  *                              ------                                                  ------
25  *              1) user types BEGIN                             1) user types BEGIN
26  *              2) user does something                  2) user does something
27  *              3) user does not like what              3) system aborts for some reason
28  *                 she sees and types ABORT
29  *
30  *              In case 1, we want to abort the transaction and return to the
31  *              default state.  In case 2, there may be more commands coming
32  *              our way which are part of the same transaction block and we have
33  *              to ignore these commands until we see an END transaction.
34  *              (or an ABORT! --djm)
35  *
36  *              Internal aborts are now handled by AbortTransactionBlock(), just as
37  *              they always have been, and user aborts are now handled by
38  *              UserAbortTransactionBlock().  Both of them rely on AbortTransaction()
39  *              to do all the real work.  The only difference is what state we
40  *              enter after AbortTransaction() does its work:
41  *
42  *              * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
43  *              * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
44  *
45  *              Low-level transaction abort handling is divided into two phases:
46  *              * AbortTransaction() executes as soon as we realize the transaction
47  *                has failed.  It should release all shared resources (locks etc)
48  *                so that we do not delay other backends unnecessarily.
49  *              * CleanupTransaction() executes when we finally see a user COMMIT
50  *                or ROLLBACK command; it cleans things up and gets us out of
51  *                the transaction internally.  In particular, we mustn't destroy
52  *                TransactionCommandContext until this point.
53  *
54  *       NOTES
55  *              This file is an attempt at a redesign of the upper layer
56  *              of the V1 transaction system which was too poorly thought
57  *              out to describe.  This new system hopes to be both simpler
58  *              in design, simpler to extend and needs to contain added
59  *              functionality to solve problems beyond the scope of the V1
60  *              system.  (In particuler, communication of transaction
61  *              information between parallel backends has to be supported)
62  *
63  *              The essential aspects of the transaction system are:
64  *
65  *                              o  transaction id generation
66  *                              o  transaction log updating
67  *                              o  memory cleanup
68  *                              o  cache invalidation
69  *                              o  lock cleanup
70  *
71  *              Hence, the functional division of the transaction code is
72  *              based on what of the above things need to be done during
73  *              a start/commit/abort transaction.  For instance, the
74  *              routine AtCommit_Memory() takes care of all the memory
75  *              cleanup stuff done at commit time.
76  *
77  *              The code is layered as follows:
78  *
79  *                              StartTransaction
80  *                              CommitTransaction
81  *                              AbortTransaction
82  *                              CleanupTransaction
83  *
84  *              are provided to do the lower level work like recording
85  *              the transaction status in the log and doing memory cleanup.
86  *              above these routines are another set of functions:
87  *
88  *                              StartTransactionCommand
89  *                              CommitTransactionCommand
90  *                              AbortCurrentTransaction
91  *
92  *              These are the routines used in the postgres main processing
93  *              loop.  They are sensitive to the current transaction block state
94  *              and make calls to the lower level routines appropriately.
95  *
96  *              Support for transaction blocks is provided via the functions:
97  *
98  *                              StartTransactionBlock
99  *                              CommitTransactionBlock
100  *                              AbortTransactionBlock
101  *
102  *              These are invoked only in responce to a user "BEGIN", "END",
103  *              or "ABORT" command.  The tricky part about these functions
104  *              is that they are called within the postgres main loop, in between
105  *              the StartTransactionCommand() and CommitTransactionCommand().
106  *
107  *              For example, consider the following sequence of user commands:
108  *
109  *              1)              begin
110  *              2)              retrieve (foo.all)
111  *              3)              append foo (bar = baz)
112  *              4)              end
113  *
114  *              in the main processing loop, this results in the following
115  *              transaction sequence:
116  *
117  *                      /       StartTransactionCommand();
118  *              1) /    ProcessUtility();                               << begin
119  *                 \            StartTransactionBlock();
120  *                      \       CommitTransactionCommand();
121  *
122  *                      /       StartTransactionCommand();
123  *              2) <    ProcessQuery();                                 << retrieve (foo.all)
124  *                      \       CommitTransactionCommand();
125  *
126  *                      /       StartTransactionCommand();
127  *              3) <    ProcessQuery();                                 << append foo (bar = baz)
128  *                      \       CommitTransactionCommand();
129  *
130  *                      /       StartTransactionCommand();
131  *              4) /    ProcessUtility();                               << end
132  *                 \            CommitTransactionBlock();
133  *                      \       CommitTransactionCommand();
134  *
135  *              The point of this example is to demonstrate the need for
136  *              StartTransactionCommand() and CommitTransactionCommand() to
137  *              be state smart -- they should do nothing in between the calls
138  *              to StartTransactionBlock() and EndTransactionBlock() and
139  *              outside these calls they need to do normal start/commit
140  *              processing.
141  *
142  *              Furthermore, suppose the "retrieve (foo.all)" caused an abort
143  *              condition.      We would then want to abort the transaction and
144  *              ignore all subsequent commands up to the "end".
145  *              -cim 3/23/90
146  *
147  *-------------------------------------------------------------------------
148  */
149
150 /*
151  * Large object clean up added in CommitTransaction() to prevent buffer leaks.
152  * [PA, 7/17/98]
153  * [PA] is Pascal AndrĂ© <andre@via.ecp.fr>
154  */
155 #include "postgres.h"
156
157 #include "access/nbtree.h"
158 #include "catalog/heap.h"
159 #include "catalog/index.h"
160 #include "commands/async.h"
161 #include "commands/sequence.h"
162 #include "commands/trigger.h"
163 #include "executor/spi.h"
164 #include "libpq/be-fsstubs.h"
165 #include "storage/proc.h"
166 #include "storage/sinval.h"
167 #include "utils/inval.h"
168 #include "utils/memutils.h"
169 #include "utils/portal.h"
170 #include "utils/relcache.h"
171 #include "utils/temprel.h"
172
173 extern bool SharedBufferChanged;
174
175 static void AbortTransaction(void);
176 static void AtAbort_Cache(void);
177 static void AtAbort_Locks(void);
178 static void AtAbort_Memory(void);
179 static void AtCleanup_Memory(void);
180 static void AtCommit_Cache(void);
181 static void AtCommit_LocalCache(void);
182 static void AtCommit_Locks(void);
183 static void AtCommit_Memory(void);
184 static void AtStart_Cache(void);
185 static void AtStart_Locks(void);
186 static void AtStart_Memory(void);
187 static void CleanupTransaction(void);
188 static void CommitTransaction(void);
189 static void RecordTransactionAbort(void);
190 static void RecordTransactionCommit(void);
191 static void StartTransaction(void);
192
193 /* ----------------
194  *              global variables holding the current transaction state.
195  *
196  *              Note: when we are running several slave processes, the
197  *                        current transaction state data is copied into shared memory
198  *                        and the CurrentTransactionState pointer changed to
199  *                        point to the shared copy.  All this occurrs in slaves.c
200  * ----------------
201  */
202 TransactionStateData CurrentTransactionStateData = {
203         0,                                                      /* transaction id */
204         FirstCommandId,                         /* command id */
205         0,                                                      /* scan command id */
206         0x0,                                            /* start time */
207         TRANS_DEFAULT,                          /* transaction state */
208         TBLOCK_DEFAULT                          /* transaction block state */
209 };
210
211 TransactionState CurrentTransactionState = &CurrentTransactionStateData;
212
213 int                     DefaultXactIsoLevel = XACT_READ_COMMITTED;
214 int                     XactIsoLevel;
215
216 /* ----------------
217  *              info returned when the system is disabled
218  *
219  * Apparently a lot of this code is inherited from other prototype systems.
220  * For DisabledStartTime, use a symbolic value to make the relationships clearer.
221  * The old value of 1073741823 corresponds to a date in y2004, which is coming closer
222  *      every day. It appears that if we return a value guaranteed larger than
223  *      any real time associated with a transaction then comparisons in other
224  *      modules will still be correct. Let's use BIG_ABSTIME for this. tgl 2/14/97
225  *
226  *              Note:  I have no idea what the significance of the
227  *                         1073741823 in DisabledStartTime.. I just carried
228  *                         this over when converting things from the old
229  *                         V1 transaction system.  -cim 3/18/90
230  * ----------------
231  */
232 TransactionId DisabledTransactionId = (TransactionId) -1;
233
234 CommandId       DisabledCommandId = (CommandId) -1;
235
236 AbsoluteTime DisabledStartTime = (AbsoluteTime) BIG_ABSTIME;    /* 1073741823; */
237
238 /* ----------------
239  *              overflow flag
240  * ----------------
241  */
242 bool            CommandIdCounterOverflowFlag;
243
244 /* ----------------
245  *              catalog creation transaction bootstrapping flag.
246  *              This should be eliminated and added to the transaction
247  *              state stuff.  -cim 3/19/90
248  * ----------------
249  */
250 bool            AMI_OVERRIDE = false;
251
252 /* ----------------------------------------------------------------
253  *                                       transaction state accessors
254  * ----------------------------------------------------------------
255  */
256
257 /* --------------------------------
258  *              TranactionFlushEnabled()
259  *              SetTransactionFlushEnabled()
260  *
261  *              These are used to test and set the "TransactionFlushState"
262  *              varable.  If this variable is true (the default), then
263  *              the system will flush all dirty buffers to disk at the end
264  *              of each transaction.   If false then we are assuming the
265  *              buffer pool resides in stable main memory, in which case we
266  *              only do writes as necessary.
267  * --------------------------------
268  */
269 static int      TransactionFlushState = 1;
270
271 int
272 TransactionFlushEnabled(void)
273 {
274         return TransactionFlushState;
275 }
276
277 #ifdef NOT_USED
278 void
279 SetTransactionFlushEnabled(bool state)
280 {
281         TransactionFlushState = (state == true);
282 }
283
284
285 /* --------------------------------
286  *              IsTransactionState
287  *
288  *              This returns true if we are currently running a query
289  *              within an executing transaction.
290  * --------------------------------
291  */
292 bool
293 IsTransactionState(void)
294 {
295         TransactionState s = CurrentTransactionState;
296
297         switch (s->state)
298         {
299                 case TRANS_DEFAULT:
300                         return false;
301                 case TRANS_START:
302                         return true;
303                 case TRANS_INPROGRESS:
304                         return true;
305                 case TRANS_COMMIT:
306                         return true;
307                 case TRANS_ABORT:
308                         return true;
309                 case TRANS_DISABLED:
310                         return false;
311         }
312
313         /*
314          * Shouldn't get here, but lint is not happy with this...
315          */
316         return false;
317 }
318
319 #endif
320
321 /* --------------------------------
322  *              IsAbortedTransactionBlockState
323  *
324  *              This returns true if we are currently running a query
325  *              within an aborted transaction block.
326  * --------------------------------
327  */
328 bool
329 IsAbortedTransactionBlockState()
330 {
331         TransactionState s = CurrentTransactionState;
332
333         if (s->blockState == TBLOCK_ABORT)
334                 return true;
335
336         return false;
337 }
338
339 /* --------------------------------
340  *              OverrideTransactionSystem
341  *
342  *              This is used to temporarily disable the transaction
343  *              processing system in order to do initialization of
344  *              the transaction system data structures and relations
345  *              themselves.
346  * --------------------------------
347  */
348 int                     SavedTransactionState;
349
350 void
351 OverrideTransactionSystem(bool flag)
352 {
353         TransactionState s = CurrentTransactionState;
354
355         if (flag == true)
356         {
357                 if (s->state == TRANS_DISABLED)
358                         return;
359
360                 SavedTransactionState = s->state;
361                 s->state = TRANS_DISABLED;
362         }
363         else
364         {
365                 if (s->state != TRANS_DISABLED)
366                         return;
367
368                 s->state = SavedTransactionState;
369         }
370 }
371
372 /* --------------------------------
373  *              GetCurrentTransactionId
374  *
375  *              This returns the id of the current transaction, or
376  *              the id of the "disabled" transaction.
377  * --------------------------------
378  */
379 TransactionId
380 GetCurrentTransactionId()
381 {
382         TransactionState s = CurrentTransactionState;
383
384         /* ----------------
385          *      if the transaction system is disabled, we return
386          *      the special "disabled" transaction id.
387          * ----------------
388          */
389         if (s->state == TRANS_DISABLED)
390                 return (TransactionId) DisabledTransactionId;
391
392         /* ----------------
393          *      otherwise return the current transaction id.
394          * ----------------
395          */
396         return (TransactionId) s->transactionIdData;
397 }
398
399
400 /* --------------------------------
401  *              GetCurrentCommandId
402  * --------------------------------
403  */
404 CommandId
405 GetCurrentCommandId()
406 {
407         TransactionState s = CurrentTransactionState;
408
409         /* ----------------
410          *      if the transaction system is disabled, we return
411          *      the special "disabled" command id.
412          * ----------------
413          */
414         if (s->state == TRANS_DISABLED)
415                 return (CommandId) DisabledCommandId;
416
417         return s->commandId;
418 }
419
420 CommandId
421 GetScanCommandId()
422 {
423         TransactionState s = CurrentTransactionState;
424
425         /* ----------------
426          *      if the transaction system is disabled, we return
427          *      the special "disabled" command id.
428          * ----------------
429          */
430         if (s->state == TRANS_DISABLED)
431                 return (CommandId) DisabledCommandId;
432
433         return s->scanCommandId;
434 }
435
436
437 /* --------------------------------
438  *              GetCurrentTransactionStartTime
439  * --------------------------------
440  */
441 AbsoluteTime
442 GetCurrentTransactionStartTime()
443 {
444         TransactionState s = CurrentTransactionState;
445
446         /* ----------------
447          *      if the transaction system is disabled, we return
448          *      the special "disabled" starting time.
449          * ----------------
450          */
451         if (s->state == TRANS_DISABLED)
452                 return (AbsoluteTime) DisabledStartTime;
453
454         return s->startTime;
455 }
456
457
458 /* --------------------------------
459  *              TransactionIdIsCurrentTransactionId
460  * --------------------------------
461  */
462 bool
463 TransactionIdIsCurrentTransactionId(TransactionId xid)
464 {
465         TransactionState s = CurrentTransactionState;
466
467         if (AMI_OVERRIDE)
468                 return false;
469
470         return (bool)
471                 TransactionIdEquals(xid, s->transactionIdData);
472 }
473
474
475 /* --------------------------------
476  *              CommandIdIsCurrentCommandId
477  * --------------------------------
478  */
479 bool
480 CommandIdIsCurrentCommandId(CommandId cid)
481 {
482         TransactionState s = CurrentTransactionState;
483
484         if (AMI_OVERRIDE)
485                 return false;
486
487         return (cid == s->commandId) ? true : false;
488 }
489
490 bool
491 CommandIdGEScanCommandId(CommandId cid)
492 {
493         TransactionState s = CurrentTransactionState;
494
495         if (AMI_OVERRIDE)
496                 return false;
497
498         return (cid >= s->scanCommandId) ? true : false;
499 }
500
501
502 /* --------------------------------
503  *              ClearCommandIdCounterOverflowFlag
504  * --------------------------------
505  */
506 #ifdef NOT_USED
507 void
508 ClearCommandIdCounterOverflowFlag()
509 {
510         CommandIdCounterOverflowFlag = false;
511 }
512
513 #endif
514
515 /* --------------------------------
516  *              CommandCounterIncrement
517  * --------------------------------
518  */
519 void
520 CommandCounterIncrement()
521 {
522         CurrentTransactionStateData.commandId += 1;
523         if (CurrentTransactionStateData.commandId == FirstCommandId)
524         {
525                 CommandIdCounterOverflowFlag = true;
526                 elog(ERROR, "You may only have 2^32-1 commands per transaction");
527         }
528
529         CurrentTransactionStateData.scanCommandId = CurrentTransactionStateData.commandId;
530
531         /*
532          * make cache changes visible to me.  AtCommit_LocalCache() instead of
533          * AtCommit_Cache() is called here.
534          */
535         AtCommit_LocalCache();
536         AtStart_Cache();
537
538 }
539
540 void
541 SetScanCommandId(CommandId savedId)
542 {
543
544         CurrentTransactionStateData.scanCommandId = savedId;
545
546 }
547
548 /* ----------------------------------------------------------------
549  *                                              initialization stuff
550  * ----------------------------------------------------------------
551  */
552 void
553 InitializeTransactionSystem()
554 {
555         InitializeTransactionLog();
556 }
557
558 /* ----------------------------------------------------------------
559  *                                              StartTransaction stuff
560  * ----------------------------------------------------------------
561  */
562
563 /* --------------------------------
564  *              AtStart_Cache
565  * --------------------------------
566  */
567 static void
568 AtStart_Cache()
569 {
570         DiscardInvalid();
571 }
572
573 /* --------------------------------
574  *              AtStart_Locks
575  * --------------------------------
576  */
577 static void
578 AtStart_Locks()
579 {
580
581         /*
582          * at present, it is unknown to me what belongs here -cim 3/18/90
583          *
584          * There isn't anything to do at the start of a xact for locks. -mer
585          * 5/24/92
586          */
587 }
588
589 /* --------------------------------
590  *              AtStart_Memory
591  * --------------------------------
592  */
593 static void
594 AtStart_Memory()
595 {
596         /* ----------------
597          *      We shouldn't have any transaction contexts already.
598          * ----------------
599          */
600         Assert(TopTransactionContext == NULL);
601         Assert(TransactionCommandContext == NULL);
602
603         /* ----------------
604          *      Create a toplevel context for the transaction.
605          * ----------------
606          */
607         TopTransactionContext =
608                 AllocSetContextCreate(TopMemoryContext,
609                                                           "TopTransactionContext",
610                                                           ALLOCSET_DEFAULT_MINSIZE,
611                                                           ALLOCSET_DEFAULT_INITSIZE,
612                                                           ALLOCSET_DEFAULT_MAXSIZE);
613
614         /* ----------------
615          *      Create a statement-level context and make it active.
616          * ----------------
617          */
618         TransactionCommandContext =
619                 AllocSetContextCreate(TopTransactionContext,
620                                                           "TransactionCommandContext",
621                                                           ALLOCSET_DEFAULT_MINSIZE,
622                                                           ALLOCSET_DEFAULT_INITSIZE,
623                                                           ALLOCSET_DEFAULT_MAXSIZE);
624         MemoryContextSwitchTo(TransactionCommandContext);
625 }
626
627
628 /* ----------------------------------------------------------------
629  *                                              CommitTransaction stuff
630  * ----------------------------------------------------------------
631  */
632
633 /* --------------------------------
634  *              RecordTransactionCommit
635  *
636  *              Note: the two calls to BufferManagerFlush() exist to ensure
637  *                        that data pages are written before log pages.  These
638  *                        explicit calls should be replaced by a more efficient
639  *                        ordered page write scheme in the buffer manager
640  *                        -cim 3/18/90
641  * --------------------------------
642  */
643 static void
644 RecordTransactionCommit()
645 {
646         TransactionId xid;
647         int                     leak;
648
649         /* ----------------
650          *      get the current transaction id
651          * ----------------
652          */
653         xid = GetCurrentTransactionId();
654
655         /*
656          * flush the buffer manager pages.      Note: if we have stable main
657          * memory, dirty shared buffers are not flushed plai 8/7/90
658          */
659         leak = BufferPoolCheckLeak();
660
661         /*
662          * If no one shared buffer was changed by this transaction then we
663          * don't flush shared buffers and don't record commit status.
664          */
665         if (SharedBufferChanged)
666         {
667                 FlushBufferPool();
668                 if (leak)
669                         ResetBufferPool(true);
670
671                 /*
672                  * have the transaction access methods record the status of this
673                  * transaction id in the pg_log relation.
674                  */
675                 TransactionIdCommit(xid);
676
677                 /*
678                  * Now write the log info to the disk too.
679                  */
680                 leak = BufferPoolCheckLeak();
681                 FlushBufferPool();
682         }
683
684         if (leak)
685                 ResetBufferPool(true);
686 }
687
688
689 /* --------------------------------
690  *              AtCommit_Cache
691  * --------------------------------
692  */
693 static void
694 AtCommit_Cache()
695 {
696         /* ----------------
697          * Make catalog changes visible to all backend.
698          * ----------------
699          */
700         RegisterInvalid(true);
701 }
702
703 /* --------------------------------
704  *              AtCommit_LocalCache
705  * --------------------------------
706  */
707 static void
708 AtCommit_LocalCache()
709 {
710         /* ----------------
711          * Make catalog changes visible to me for the next command.
712          * ----------------
713          */
714         ImmediateLocalInvalidation(true);
715 }
716
717 /* --------------------------------
718  *              AtCommit_Locks
719  * --------------------------------
720  */
721 static void
722 AtCommit_Locks()
723 {
724         /* ----------------
725          *      XXX What if ProcReleaseLocks fails?  (race condition?)
726          *
727          *      Then you're up a creek! -mer 5/24/92
728          * ----------------
729          */
730         ProcReleaseLocks();
731 }
732
733 /* --------------------------------
734  *              AtCommit_Memory
735  * --------------------------------
736  */
737 static void
738 AtCommit_Memory()
739 {
740         /* ----------------
741          *      Now that we're "out" of a transaction, have the
742          *      system allocate things in the top memory context instead
743          *      of per-transaction contexts.
744          * ----------------
745          */
746         MemoryContextSwitchTo(TopMemoryContext);
747
748         /* ----------------
749          *      Release all transaction-local memory.
750          * ----------------
751          */
752         MemoryContextDelete(TopTransactionContext);
753         TopTransactionContext = NULL;
754         TransactionCommandContext = NULL;
755 }
756
757 /* ----------------------------------------------------------------
758  *                                              AbortTransaction stuff
759  * ----------------------------------------------------------------
760  */
761
762 /* --------------------------------
763  *              RecordTransactionAbort
764  * --------------------------------
765  */
766 static void
767 RecordTransactionAbort()
768 {
769         TransactionId xid;
770
771         /* ----------------
772          *      get the current transaction id
773          * ----------------
774          */
775         xid = GetCurrentTransactionId();
776
777         /*
778          * Have the transaction access methods record the status of this
779          * transaction id in the pg_log relation. We skip it if no one shared
780          * buffer was changed by this transaction.
781          */
782         if (SharedBufferChanged && !TransactionIdDidCommit(xid))
783                 TransactionIdAbort(xid);
784
785         /*
786          * Tell bufmgr and smgr to release resources.
787          */
788         ResetBufferPool(false);         /* false -> is abort */
789 }
790
791 /* --------------------------------
792  *              AtAbort_Cache
793  * --------------------------------
794  */
795 static void
796 AtAbort_Cache()
797 {
798         RelationCacheAbort();
799         RegisterInvalid(false);
800 }
801
802 /* --------------------------------
803  *              AtAbort_Locks
804  * --------------------------------
805  */
806 static void
807 AtAbort_Locks()
808 {
809         /* ----------------
810          *      XXX What if ProcReleaseLocks() fails?  (race condition?)
811          *
812          *      Then you're up a creek without a paddle! -mer
813          * ----------------
814          */
815         ProcReleaseLocks();
816 }
817
818
819 /* --------------------------------
820  *              AtAbort_Memory
821  * --------------------------------
822  */
823 static void
824 AtAbort_Memory()
825 {
826         /* ----------------
827          *      Make sure we are in a valid context (not a child of
828          *      TransactionCommandContext...)
829          * ----------------
830          */
831         MemoryContextSwitchTo(TransactionCommandContext);
832
833         /* ----------------
834          *      We do not want to destroy transaction contexts yet,
835          *      but it should be OK to delete any command-local memory.
836          * ----------------
837          */
838         MemoryContextResetAndDeleteChildren(TransactionCommandContext);
839 }
840
841
842 /* ----------------------------------------------------------------
843  *                                              CleanupTransaction stuff
844  * ----------------------------------------------------------------
845  */
846
847 /* --------------------------------
848  *              AtCleanup_Memory
849  * --------------------------------
850  */
851 static void
852 AtCleanup_Memory()
853 {
854         /* ----------------
855          *      Now that we're "out" of a transaction, have the
856          *      system allocate things in the top memory context instead
857          *      of per-transaction contexts.
858          * ----------------
859          */
860         MemoryContextSwitchTo(TopMemoryContext);
861
862         /* ----------------
863          *      Release all transaction-local memory.
864          * ----------------
865          */
866         MemoryContextDelete(TopTransactionContext);
867         TopTransactionContext = NULL;
868         TransactionCommandContext = NULL;
869 }
870
871
872 /* ----------------------------------------------------------------
873  *                                              interface routines
874  * ----------------------------------------------------------------
875  */
876
877 /* --------------------------------
878  *              StartTransaction
879  *
880  * --------------------------------
881  */
882 static void
883 StartTransaction()
884 {
885         TransactionState s = CurrentTransactionState;
886
887         FreeXactSnapshot();
888         XactIsoLevel = DefaultXactIsoLevel;
889
890         /* ----------------
891          *      Check the current transaction state.  If the transaction system
892          *      is switched off, or if we're already in a transaction, do nothing.
893          *      We're already in a transaction when the monitor sends a null
894          *      command to the backend to flush the comm channel.  This is a
895          *      hacky fix to a communications problem, and we keep having to
896          *      deal with it here.      We should fix the comm channel code.  mao 080891
897          * ----------------
898          */
899         if (s->state == TRANS_DISABLED || s->state == TRANS_INPROGRESS)
900                 return;
901
902         /* ----------------
903          *      set the current transaction state information
904          *      appropriately during start processing
905          * ----------------
906          */
907         s->state = TRANS_START;
908
909         SetReindexProcessing(false);
910
911         /* ----------------
912          *      generate a new transaction id
913          * ----------------
914          */
915         GetNewTransactionId(&(s->transactionIdData));
916
917         XactLockTableInsert(s->transactionIdData);
918
919         /* ----------------
920          *      initialize current transaction state fields
921          * ----------------
922          */
923         s->commandId = FirstCommandId;
924         s->scanCommandId = FirstCommandId;
925         s->startTime = GetCurrentAbsoluteTime();
926
927         /* ----------------
928          *      initialize the various transaction subsystems
929          * ----------------
930          */
931         AtStart_Memory();
932         AtStart_Cache();
933         AtStart_Locks();
934
935         /* ----------------
936          *      Tell the trigger manager to we're starting a transaction
937          * ----------------
938          */
939         DeferredTriggerBeginXact();
940
941         /* ----------------
942          *      done with start processing, set current transaction
943          *      state to "in progress"
944          * ----------------
945          */
946         s->state = TRANS_INPROGRESS;
947
948 }
949
950 #ifdef NOT_USED
951 /* ---------------
952  * Tell me if we are currently in progress
953  * ---------------
954  */
955 bool
956 CurrentXactInProgress()
957 {
958         return CurrentTransactionState->state == TRANS_INPROGRESS;
959 }
960 #endif
961
962 /* --------------------------------
963  *              CommitTransaction
964  *
965  * --------------------------------
966  */
967 static void
968 CommitTransaction()
969 {
970         TransactionState s = CurrentTransactionState;
971
972         /* ----------------
973          *      check the current transaction state
974          * ----------------
975          */
976         if (s->state == TRANS_DISABLED)
977                 return;
978
979         if (s->state != TRANS_INPROGRESS)
980                 elog(NOTICE, "CommitTransaction and not in in-progress state ");
981
982         /* ----------------
983          *      Tell the trigger manager that this transaction is about to be
984          *      committed. He'll invoke all trigger deferred until XACT before
985          *      we really start on committing the transaction.
986          * ----------------
987          */
988         DeferredTriggerEndXact();
989
990         /* ----------------
991          *      set the current transaction state information
992          *      appropriately during the abort processing
993          * ----------------
994          */
995         s->state = TRANS_COMMIT;
996
997         /* ----------------
998          *      do commit processing
999          * ----------------
1000          */
1001
1002         /* handle commit for large objects [ PA, 7/17/98 ] */
1003         lo_commit(true);
1004
1005         /* NOTIFY commit must also come before lower-level cleanup */
1006         AtCommit_Notify();
1007
1008         CloseSequences();
1009         AtEOXact_portals();
1010         RecordTransactionCommit();
1011
1012         /*
1013          * Let others know about no transaction in progress by me. Note that
1014          * this must be done _before_ releasing locks we hold and
1015          * SpinAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked
1016          * by xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot -
1017          * if xid 2' GetSnapshotData sees xid 1 as running then it must see
1018          * xid 0 as running as well or it will see two tuple versions - one
1019          * deleted by xid 1 and one inserted by xid 0.
1020          */
1021         if (MyProc != (PROC *) NULL)
1022         {
1023                 /* Lock SInvalLock because that's what GetSnapshotData uses. */
1024                 SpinAcquire(SInvalLock);
1025                 MyProc->xid = InvalidTransactionId;
1026                 MyProc->xmin = InvalidTransactionId;
1027                 SpinRelease(SInvalLock);
1028         }
1029
1030         RelationPurgeLocalRelation(true);
1031         AtEOXact_SPI();
1032         AtEOXact_nbtree();
1033         AtCommit_Cache();
1034         AtCommit_Locks();
1035         AtCommit_Memory();
1036         AtEOXact_Files();
1037
1038         SharedBufferChanged = false; /* safest place to do it */
1039
1040         /* ----------------
1041          *      done with commit processing, set current transaction
1042          *      state back to default
1043          * ----------------
1044          */
1045         s->state = TRANS_DEFAULT;
1046 }
1047
1048 /* --------------------------------
1049  *              AbortTransaction
1050  *
1051  * --------------------------------
1052  */
1053 static void
1054 AbortTransaction()
1055 {
1056         TransactionState s = CurrentTransactionState;
1057
1058         /*
1059          * Let others to know about no transaction in progress - vadim
1060          * 11/26/96
1061          */
1062         if (MyProc != (PROC *) NULL)
1063         {
1064                 MyProc->xid = InvalidTransactionId;
1065                 MyProc->xmin = InvalidTransactionId;
1066         }
1067
1068         /* ----------------
1069          *      check the current transaction state
1070          * ----------------
1071          */
1072         if (s->state == TRANS_DISABLED)
1073                 return;
1074
1075         if (s->state != TRANS_INPROGRESS)
1076                 elog(NOTICE, "AbortTransaction and not in in-progress state");
1077
1078         /* ----------------
1079          *      Tell the trigger manager that this transaction is about to be
1080          *      aborted.
1081          * ----------------
1082          */
1083         DeferredTriggerAbortXact();
1084
1085         /* ----------------
1086          *      set the current transaction state information
1087          *      appropriately during the abort processing
1088          * ----------------
1089          */
1090         s->state = TRANS_ABORT;
1091
1092         /* ----------------
1093          *      do abort processing
1094          * ----------------
1095          */
1096         lo_commit(false);                       /* 'false' means it's abort */
1097         UnlockBuffers();
1098         AtAbort_Notify();
1099         CloseSequences();
1100         AtEOXact_portals();
1101         RecordTransactionAbort();
1102         RelationPurgeLocalRelation(false);
1103         invalidate_temp_relations();
1104         AtEOXact_SPI();
1105         AtEOXact_nbtree();
1106         AtAbort_Cache();
1107         AtAbort_Locks();
1108         AtAbort_Memory();
1109         AtEOXact_Files();
1110
1111         SharedBufferChanged = false; /* safest place to do it */
1112
1113         /* ----------------
1114          *      State remains TRANS_ABORT until CleanupTransaction().
1115          * ----------------
1116          */
1117 }
1118
1119 /* --------------------------------
1120  *              CleanupTransaction
1121  *
1122  * --------------------------------
1123  */
1124 static void
1125 CleanupTransaction()
1126 {
1127         TransactionState s = CurrentTransactionState;
1128
1129         if (s->state == TRANS_DISABLED)
1130                 return;
1131
1132         /* ----------------
1133          *      State should still be TRANS_ABORT from AbortTransaction().
1134          * ----------------
1135          */
1136         if (s->state != TRANS_ABORT)
1137                 elog(FATAL, "CleanupTransaction and not in abort state");
1138
1139         /* ----------------
1140          *      do abort cleanup processing
1141          * ----------------
1142          */
1143         AtCleanup_Memory();
1144
1145         /* ----------------
1146          *      done with abort processing, set current transaction
1147          *      state back to default
1148          * ----------------
1149          */
1150         s->state = TRANS_DEFAULT;
1151 }
1152
1153 /* --------------------------------
1154  *              StartTransactionCommand
1155  * --------------------------------
1156  */
1157 void
1158 StartTransactionCommand()
1159 {
1160         TransactionState s = CurrentTransactionState;
1161
1162         switch (s->blockState)
1163         {
1164                         /* ----------------
1165                          *              if we aren't in a transaction block, we
1166                          *              just do our usual start transaction.
1167                          * ----------------
1168                          */
1169                 case TBLOCK_DEFAULT:
1170                         StartTransaction();
1171                         break;
1172
1173                         /* ----------------
1174                          *              We should never experience this -- if we do it
1175                          *              means the BEGIN state was not changed in the previous
1176                          *              CommitTransactionCommand().  If we get it, we print
1177                          *              a warning and change to the in-progress state.
1178                          * ----------------
1179                          */
1180                 case TBLOCK_BEGIN:
1181                         elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
1182                         s->blockState = TBLOCK_INPROGRESS;
1183                         break;
1184
1185                         /* ----------------
1186                          *              This is the case when are somewhere in a transaction
1187                          *              block and about to start a new command.  For now we
1188                          *              do nothing but someday we may do command-local resource
1189                          *              initialization.
1190                          * ----------------
1191                          */
1192                 case TBLOCK_INPROGRESS:
1193                         break;
1194
1195                         /* ----------------
1196                          *              As with BEGIN, we should never experience this
1197                          *              if we do it means the END state was not changed in the
1198                          *              previous CommitTransactionCommand().  If we get it, we
1199                          *              print a warning, commit the transaction, start a new
1200                          *              transaction and change to the default state.
1201                          * ----------------
1202                          */
1203                 case TBLOCK_END:
1204                         elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_END");
1205                         s->blockState = TBLOCK_DEFAULT;
1206                         CommitTransaction();
1207                         StartTransaction();
1208                         break;
1209
1210                         /* ----------------
1211                          *              Here we are in the middle of a transaction block but
1212                          *              one of the commands caused an abort so we do nothing
1213                          *              but remain in the abort state.  Eventually we will get
1214                          *              to the "END TRANSACTION" which will set things straight.
1215                          * ----------------
1216                          */
1217                 case TBLOCK_ABORT:
1218                         break;
1219
1220                         /* ----------------
1221                          *              This means we somehow aborted and the last call to
1222                          *              CommitTransactionCommand() didn't clear the state so
1223                          *              we remain in the ENDABORT state and maybe next time
1224                          *              we get to CommitTransactionCommand() the state will
1225                          *              get reset to default.
1226                          * ----------------
1227                          */
1228                 case TBLOCK_ENDABORT:
1229                         elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
1230                         break;
1231         }
1232
1233         /*
1234          * We must switch to TransactionCommandContext before returning.
1235          * This is already done if we called StartTransaction, otherwise not.
1236          */
1237         Assert(TransactionCommandContext != NULL);
1238         MemoryContextSwitchTo(TransactionCommandContext);
1239 }
1240
1241 /* --------------------------------
1242  *              CommitTransactionCommand
1243  * --------------------------------
1244  */
1245 void
1246 CommitTransactionCommand()
1247 {
1248         TransactionState s = CurrentTransactionState;
1249
1250         switch (s->blockState)
1251         {
1252                         /* ----------------
1253                          *              if we aren't in a transaction block, we
1254                          *              just do our usual transaction commit
1255                          * ----------------
1256                          */
1257                 case TBLOCK_DEFAULT:
1258                         CommitTransaction();
1259                         break;
1260
1261                         /* ----------------
1262                          *              This is the case right after we get a "BEGIN TRANSACTION"
1263                          *              command, but the user hasn't done anything else yet, so
1264                          *              we change to the "transaction block in progress" state
1265                          *              and return.
1266                          * ----------------
1267                          */
1268                 case TBLOCK_BEGIN:
1269                         s->blockState = TBLOCK_INPROGRESS;
1270                         break;
1271
1272                         /* ----------------
1273                          *              This is the case when we have finished executing a command
1274                          *              someplace within a transaction block.  We increment the
1275                          *              command counter and return.  Someday we may free resources
1276                          *              local to the command.
1277                          *
1278                          *              That someday is today, at least for memory allocated in
1279                          *              TransactionCommandContext.
1280                          *                              - vadim 03/25/97
1281                          * ----------------
1282                          */
1283                 case TBLOCK_INPROGRESS:
1284                         CommandCounterIncrement();
1285                         MemoryContextResetAndDeleteChildren(TransactionCommandContext);
1286                         break;
1287
1288                         /* ----------------
1289                          *              This is the case when we just got the "END TRANSACTION"
1290                          *              statement, so we commit the transaction and go back to
1291                          *              the default state.
1292                          * ----------------
1293                          */
1294                 case TBLOCK_END:
1295                         CommitTransaction();
1296                         s->blockState = TBLOCK_DEFAULT;
1297                         break;
1298
1299                         /* ----------------
1300                          *              Here we are in the middle of a transaction block but
1301                          *              one of the commands caused an abort so we do nothing
1302                          *              but remain in the abort state.  Eventually we will get
1303                          *              to the "END TRANSACTION" which will set things straight.
1304                          * ----------------
1305                          */
1306                 case TBLOCK_ABORT:
1307                         break;
1308
1309                         /* ----------------
1310                          *              Here we were in an aborted transaction block which
1311                          *              just processed the "END TRANSACTION" command from the
1312                          *              user, so clean up and return to the default state.
1313                          * ----------------
1314                          */
1315                 case TBLOCK_ENDABORT:
1316                         CleanupTransaction();
1317                         s->blockState = TBLOCK_DEFAULT;
1318                         break;
1319         }
1320 }
1321
1322 /* --------------------------------
1323  *              AbortCurrentTransaction
1324  * --------------------------------
1325  */
1326 void
1327 AbortCurrentTransaction()
1328 {
1329         TransactionState s = CurrentTransactionState;
1330
1331         switch (s->blockState)
1332         {
1333                         /* ----------------
1334                          *              if we aren't in a transaction block, we
1335                          *              just do the basic abort & cleanup transaction.
1336                          * ----------------
1337                          */
1338                 case TBLOCK_DEFAULT:
1339                         AbortTransaction();
1340                         CleanupTransaction();
1341                         break;
1342
1343                         /* ----------------
1344                          *              If we are in the TBLOCK_BEGIN it means something
1345                          *              screwed up right after reading "BEGIN TRANSACTION"
1346                          *              so we enter the abort state.  Eventually an "END
1347                          *              TRANSACTION" will fix things.
1348                          * ----------------
1349                          */
1350                 case TBLOCK_BEGIN:
1351                         s->blockState = TBLOCK_ABORT;
1352                         AbortTransaction();
1353                         /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1354                         break;
1355
1356                         /* ----------------
1357                          *              This is the case when are somewhere in a transaction
1358                          *              block which aborted so we abort the transaction and
1359                          *              set the ABORT state.  Eventually an "END TRANSACTION"
1360                          *              will fix things and restore us to a normal state.
1361                          * ----------------
1362                          */
1363                 case TBLOCK_INPROGRESS:
1364                         s->blockState = TBLOCK_ABORT;
1365                         AbortTransaction();
1366                         /* CleanupTransaction happens when we exit TBLOCK_ABORT */
1367                         break;
1368
1369                         /* ----------------
1370                          *              Here, the system was fouled up just after the
1371                          *              user wanted to end the transaction block so we
1372                          *              abort the transaction and put us back into the
1373                          *              default state.
1374                          * ----------------
1375                          */
1376                 case TBLOCK_END:
1377                         s->blockState = TBLOCK_DEFAULT;
1378                         AbortTransaction();
1379                         CleanupTransaction();
1380                         break;
1381
1382                         /* ----------------
1383                          *              Here, we are already in an aborted transaction
1384                          *              state and are waiting for an "END TRANSACTION" to
1385                          *              come along and lo and behold, we abort again!
1386                          *              So we just remain in the abort state.
1387                          * ----------------
1388                          */
1389                 case TBLOCK_ABORT:
1390                         break;
1391
1392                         /* ----------------
1393                          *              Here we were in an aborted transaction block which
1394                          *              just processed the "END TRANSACTION" command but somehow
1395                          *              aborted again.. since we must have done the abort
1396                          *              processing, we clean up and return to the default state.
1397                          * ----------------
1398                          */
1399                 case TBLOCK_ENDABORT:
1400                         CleanupTransaction();
1401                         s->blockState = TBLOCK_DEFAULT;
1402                         break;
1403         }
1404 }
1405
1406 /* ----------------------------------------------------------------
1407  *                                         transaction block support
1408  * ----------------------------------------------------------------
1409  */
1410 /* --------------------------------
1411  *              BeginTransactionBlock
1412  * --------------------------------
1413  */
1414 void
1415 BeginTransactionBlock(void)
1416 {
1417         TransactionState s = CurrentTransactionState;
1418
1419         /* ----------------
1420          *      check the current transaction state
1421          * ----------------
1422          */
1423         if (s->state == TRANS_DISABLED)
1424                 return;
1425
1426         if (s->blockState != TBLOCK_DEFAULT)
1427                 elog(NOTICE, "BEGIN: already a transaction in progress");
1428
1429         /* ----------------
1430          *      set the current transaction block state information
1431          *      appropriately during begin processing
1432          * ----------------
1433          */
1434         s->blockState = TBLOCK_BEGIN;
1435
1436         /* ----------------
1437          *      do begin processing
1438          * ----------------
1439          */
1440
1441         /* ----------------
1442          *      done with begin processing, set block state to inprogress
1443          * ----------------
1444          */
1445         s->blockState = TBLOCK_INPROGRESS;
1446 }
1447
1448 /* --------------------------------
1449  *              EndTransactionBlock
1450  * --------------------------------
1451  */
1452 void
1453 EndTransactionBlock(void)
1454 {
1455         TransactionState s = CurrentTransactionState;
1456
1457         /* ----------------
1458          *      check the current transaction state
1459          * ----------------
1460          */
1461         if (s->state == TRANS_DISABLED)
1462                 return;
1463
1464         if (s->blockState == TBLOCK_INPROGRESS)
1465         {
1466                 /* ----------------
1467                  *      here we are in a transaction block which should commit
1468                  *      when we get to the upcoming CommitTransactionCommand()
1469                  *      so we set the state to "END".  CommitTransactionCommand()
1470                  *      will recognize this and commit the transaction and return
1471                  *      us to the default state
1472                  * ----------------
1473                  */
1474                 s->blockState = TBLOCK_END;
1475                 return;
1476         }
1477
1478         if (s->blockState == TBLOCK_ABORT)
1479         {
1480                 /* ----------------
1481                  *      here, we are in a transaction block which aborted
1482                  *      and since the AbortTransaction() was already done,
1483                  *      we do whatever is needed and change to the special
1484                  *      "END ABORT" state.      The upcoming CommitTransactionCommand()
1485                  *      will recognise this and then put us back in the default
1486                  *      state.
1487                  * ----------------
1488                  */
1489                 s->blockState = TBLOCK_ENDABORT;
1490                 return;
1491         }
1492
1493         /* ----------------
1494          *      here, the user issued COMMIT when not inside a transaction.
1495          *      Issue a notice and go to abort state.  The upcoming call to
1496          *      CommitTransactionCommand() will then put us back into the
1497          *      default state.
1498          * ----------------
1499          */
1500         elog(NOTICE, "COMMIT: no transaction in progress");
1501         AbortTransaction();
1502         s->blockState = TBLOCK_ENDABORT;
1503 }
1504
1505 /* --------------------------------
1506  *              AbortTransactionBlock
1507  * --------------------------------
1508  */
1509 #ifdef NOT_USED
1510 static void
1511 AbortTransactionBlock(void)
1512 {
1513         TransactionState s = CurrentTransactionState;
1514
1515         /* ----------------
1516          *      check the current transaction state
1517          * ----------------
1518          */
1519         if (s->state == TRANS_DISABLED)
1520                 return;
1521
1522         if (s->blockState == TBLOCK_INPROGRESS)
1523         {
1524                 /* ----------------
1525                  *      here we were inside a transaction block something
1526                  *      screwed up inside the system so we enter the abort state,
1527                  *      do the abort processing and then return.
1528                  *      We remain in the abort state until we see an
1529                  *      END TRANSACTION command.
1530                  * ----------------
1531                  */
1532                 s->blockState = TBLOCK_ABORT;
1533                 AbortTransaction();
1534                 return;
1535         }
1536
1537         /* ----------------
1538          *      here, the user issued ABORT when not inside a transaction.
1539          *      Issue a notice and go to abort state.  The upcoming call to
1540          *      CommitTransactionCommand() will then put us back into the
1541          *      default state.
1542          * ----------------
1543          */
1544         elog(NOTICE, "ROLLBACK: no transaction in progress");
1545         AbortTransaction();
1546         s->blockState = TBLOCK_ENDABORT;
1547 }
1548
1549 #endif
1550
1551 /* --------------------------------
1552  *              UserAbortTransactionBlock
1553  * --------------------------------
1554  */
1555 void
1556 UserAbortTransactionBlock()
1557 {
1558         TransactionState s = CurrentTransactionState;
1559
1560         /* ----------------
1561          *      check the current transaction state
1562          * ----------------
1563          */
1564         if (s->state == TRANS_DISABLED)
1565                 return;
1566
1567         /*
1568          * if the transaction has already been automatically aborted with an
1569          * error, and the user subsequently types 'abort', allow it.  (the
1570          * behavior is the same as if they had typed 'end'.)
1571          */
1572         if (s->blockState == TBLOCK_ABORT)
1573         {
1574                 s->blockState = TBLOCK_ENDABORT;
1575                 return;
1576         }
1577
1578         if (s->blockState == TBLOCK_INPROGRESS)
1579         {
1580                 /* ----------------
1581                  *      here we were inside a transaction block and we
1582                  *      got an abort command from the user, so we move to
1583                  *      the abort state, do the abort processing and
1584                  *      then change to the ENDABORT state so we will end up
1585                  *      in the default state after the upcoming
1586                  *      CommitTransactionCommand().
1587                  * ----------------
1588                  */
1589                 s->blockState = TBLOCK_ABORT;
1590                 AbortTransaction();
1591                 s->blockState = TBLOCK_ENDABORT;
1592                 return;
1593         }
1594
1595         /* ----------------
1596          *      here, the user issued ABORT when not inside a transaction.
1597          *      Issue a notice and go to abort state.  The upcoming call to
1598          *      CommitTransactionCommand() will then put us back into the
1599          *      default state.
1600          * ----------------
1601          */
1602         elog(NOTICE, "ROLLBACK: no transaction in progress");
1603         AbortTransaction();
1604         s->blockState = TBLOCK_ENDABORT;
1605 }
1606
1607 /* --------------------------------
1608  *              AbortOutOfAnyTransaction
1609  *
1610  * This routine is provided for error recovery purposes.  It aborts any
1611  * active transaction or transaction block, leaving the system in a known
1612  * idle state.
1613  * --------------------------------
1614  */
1615 void
1616 AbortOutOfAnyTransaction()
1617 {
1618         TransactionState s = CurrentTransactionState;
1619
1620         /*
1621          * Get out of any low-level transaction
1622          */
1623         if (s->state != TRANS_DEFAULT)
1624         {
1625                 AbortTransaction();
1626                 CleanupTransaction();
1627         }
1628
1629         /*
1630          * Now reset the high-level state
1631          */
1632         s->blockState = TBLOCK_DEFAULT;
1633 }
1634
1635 bool
1636 IsTransactionBlock()
1637 {
1638         TransactionState s = CurrentTransactionState;
1639
1640         if (s->blockState == TBLOCK_INPROGRESS
1641                 || s->blockState == TBLOCK_ABORT
1642                 || s->blockState == TBLOCK_ENDABORT)
1643                 return true;
1644
1645         return false;
1646 }