1996-07-09 08:22:35 +02:00
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
|
* xact.c
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* top level transaction system support routines
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
2000-01-26 06:58:53 +01:00
|
|
|
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* IDENTIFICATION
|
2000-04-12 19:17:23 +02:00
|
|
|
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.64 2000/04/12 17:14:53 momjian Exp $
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* NOTES
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* Transaction aborts can now occur two ways:
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* 1) system dies from some internal cause (Assert, etc..)
|
|
|
|
|
* 2) user types abort
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* These two cases used to be treated identically, but now
|
|
|
|
|
* we need to distinguish them. Why? consider the following
|
|
|
|
|
* two situatuons:
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* case 1 case 2
|
|
|
|
|
* ------ ------
|
|
|
|
|
* 1) user types BEGIN 1) user types BEGIN
|
|
|
|
|
* 2) user does something 2) user does something
|
|
|
|
|
* 3) user does not like what 3) system aborts for some reason
|
|
|
|
|
* she shes and types ABORT
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* In case 1, we want to abort the transaction and return to the
|
|
|
|
|
* default state. In case 2, there may be more commands coming
|
|
|
|
|
* our way which are part of the same transaction block and we have
|
|
|
|
|
* to ignore these commands until we see an END transaction.
|
|
|
|
|
* (or an ABORT! --djm)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* Internal aborts are now handled by AbortTransactionBlock(), just as
|
|
|
|
|
* they always have been, and user aborts are now handled by
|
|
|
|
|
* UserAbortTransactionBlock(). Both of them rely on AbortTransaction()
|
|
|
|
|
* to do all the real work. The only difference is what state we
|
2000-01-05 19:23:54 +01:00
|
|
|
|
* enter after AbortTransaction() does its work:
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
|
|
|
|
|
* * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* NOTES
|
|
|
|
|
* This file is an attempt at a redesign of the upper layer
|
|
|
|
|
* of the V1 transaction system which was too poorly thought
|
|
|
|
|
* out to describe. This new system hopes to be both simpler
|
|
|
|
|
* in design, simpler to extend and needs to contain added
|
|
|
|
|
* functionality to solve problems beyond the scope of the V1
|
|
|
|
|
* system. (In particuler, communication of transaction
|
|
|
|
|
* information between parallel backends has to be supported)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* The essential aspects of the transaction system are:
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* o transaction id generation
|
|
|
|
|
* o transaction log updating
|
|
|
|
|
* o memory cleanup
|
|
|
|
|
* o cache invalidation
|
|
|
|
|
* o lock cleanup
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* Hence, the functional division of the transaction code is
|
|
|
|
|
* based on what of the above things need to be done during
|
|
|
|
|
* a start/commit/abort transaction. For instance, the
|
|
|
|
|
* routine AtCommit_Memory() takes care of all the memory
|
|
|
|
|
* cleanup stuff done at commit time.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* The code is layered as follows:
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* StartTransaction
|
|
|
|
|
* CommitTransaction
|
|
|
|
|
* AbortTransaction
|
|
|
|
|
* UserAbortTransaction
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* are provided to do the lower level work like recording
|
|
|
|
|
* the transaction status in the log and doing memory cleanup.
|
|
|
|
|
* above these routines are another set of functions:
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* StartTransactionCommand
|
|
|
|
|
* CommitTransactionCommand
|
|
|
|
|
* AbortCurrentTransaction
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* These are the routines used in the postgres main processing
|
|
|
|
|
* loop. They are sensitive to the current transaction block state
|
|
|
|
|
* and make calls to the lower level routines appropriately.
|
|
|
|
|
*
|
|
|
|
|
* Support for transaction blocks is provided via the functions:
|
|
|
|
|
*
|
|
|
|
|
* StartTransactionBlock
|
|
|
|
|
* CommitTransactionBlock
|
|
|
|
|
* AbortTransactionBlock
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* These are invoked only in responce to a user "BEGIN", "END",
|
|
|
|
|
* or "ABORT" command. The tricky part about these functions
|
|
|
|
|
* is that they are called within the postgres main loop, in between
|
|
|
|
|
* the StartTransactionCommand() and CommitTransactionCommand().
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* For example, consider the following sequence of user commands:
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* 1) begin
|
|
|
|
|
* 2) retrieve (foo.all)
|
|
|
|
|
* 3) append foo (bar = baz)
|
|
|
|
|
* 4) end
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* in the main processing loop, this results in the following
|
|
|
|
|
* transaction sequence:
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* / StartTransactionCommand();
|
|
|
|
|
* 1) / ProcessUtility(); << begin
|
|
|
|
|
* \ StartTransactionBlock();
|
|
|
|
|
* \ CommitTransactionCommand();
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* / StartTransactionCommand();
|
|
|
|
|
* 2) < ProcessQuery(); << retrieve (foo.all)
|
|
|
|
|
* \ CommitTransactionCommand();
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* / StartTransactionCommand();
|
|
|
|
|
* 3) < ProcessQuery(); << append foo (bar = baz)
|
|
|
|
|
* \ CommitTransactionCommand();
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* / StartTransactionCommand();
|
|
|
|
|
* 4) / ProcessUtility(); << end
|
|
|
|
|
* \ CommitTransactionBlock();
|
|
|
|
|
* \ CommitTransactionCommand();
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* The point of this example is to demonstrate the need for
|
|
|
|
|
* StartTransactionCommand() and CommitTransactionCommand() to
|
|
|
|
|
* be state smart -- they should do nothing in between the calls
|
|
|
|
|
* to StartTransactionBlock() and EndTransactionBlock() and
|
|
|
|
|
* outside these calls they need to do normal start/commit
|
|
|
|
|
* processing.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* Furthermore, suppose the "retrieve (foo.all)" caused an abort
|
|
|
|
|
* condition. We would then want to abort the transaction and
|
|
|
|
|
* ignore all subsequent commands up to the "end".
|
|
|
|
|
* -cim 3/23/90
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
1996-10-21 09:15:18 +02:00
|
|
|
|
|
1998-07-21 06:17:30 +02:00
|
|
|
|
/*
|
|
|
|
|
* Large object clean up added in CommitTransaction() to prevent buffer leaks.
|
|
|
|
|
* [PA, 7/17/98]
|
|
|
|
|
* [PA] is Pascal Andr<EFBFBD> <andre@via.ecp.fr>
|
|
|
|
|
*/
|
1999-07-16 01:04:24 +02:00
|
|
|
|
#include "postgres.h"
|
1996-10-21 09:15:18 +02:00
|
|
|
|
|
1999-08-08 22:12:52 +02:00
|
|
|
|
#include "access/nbtree.h"
|
1999-07-16 01:04:24 +02:00
|
|
|
|
#include "catalog/heap.h"
|
2000-02-18 10:30:20 +01:00
|
|
|
|
#include "catalog/index.h"
|
1999-07-16 01:04:24 +02:00
|
|
|
|
#include "commands/async.h"
|
|
|
|
|
#include "commands/sequence.h"
|
1999-08-08 22:12:52 +02:00
|
|
|
|
#include "commands/vacuum.h"
|
1999-09-29 18:06:40 +02:00
|
|
|
|
#include "commands/trigger.h"
|
1999-07-16 01:04:24 +02:00
|
|
|
|
#include "libpq/be-fsstubs.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
|
#include "storage/proc.h"
|
1999-09-24 02:25:33 +02:00
|
|
|
|
#include "storage/sinval.h"
|
1999-09-04 21:55:50 +02:00
|
|
|
|
#include "utils/temprel.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
|
#include "utils/inval.h"
|
|
|
|
|
#include "utils/portal.h"
|
|
|
|
|
#include "utils/relcache.h"
|
1998-07-21 06:17:30 +02:00
|
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
|
extern bool SharedBufferChanged;
|
1999-06-29 06:54:49 +02:00
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
|
static void AbortTransaction(void);
|
|
|
|
|
static void AtAbort_Cache(void);
|
|
|
|
|
static void AtAbort_Locks(void);
|
|
|
|
|
static void AtAbort_Memory(void);
|
|
|
|
|
static void AtCommit_Cache(void);
|
2000-01-10 07:30:56 +01:00
|
|
|
|
static void AtCommit_LocalCache(void);
|
1997-09-08 04:41:22 +02:00
|
|
|
|
static void AtCommit_Locks(void);
|
|
|
|
|
static void AtCommit_Memory(void);
|
|
|
|
|
static void AtStart_Cache(void);
|
|
|
|
|
static void AtStart_Locks(void);
|
|
|
|
|
static void AtStart_Memory(void);
|
|
|
|
|
static void CommitTransaction(void);
|
|
|
|
|
static void RecordTransactionAbort(void);
|
|
|
|
|
static void RecordTransactionCommit(void);
|
|
|
|
|
static void StartTransaction(void);
|
1997-08-19 23:40:56 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* global variables holding the current transaction state.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* Note: when we are running several slave processes, the
|
|
|
|
|
* current transaction state data is copied into shared memory
|
|
|
|
|
* and the CurrentTransactionState pointer changed to
|
|
|
|
|
* point to the shared copy. All this occurrs in slaves.c
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
TransactionStateData CurrentTransactionStateData = {
|
1997-09-07 07:04:48 +02:00
|
|
|
|
0, /* transaction id */
|
|
|
|
|
FirstCommandId, /* command id */
|
2000-03-17 03:36:41 +01:00
|
|
|
|
0, /* scan command id */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
0x0, /* start time */
|
|
|
|
|
TRANS_DEFAULT, /* transaction state */
|
|
|
|
|
TBLOCK_DEFAULT /* transaction block state */
|
|
|
|
|
};
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
1999-02-03 22:18:02 +01:00
|
|
|
|
TransactionState CurrentTransactionState = &CurrentTransactionStateData;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
|
int DefaultXactIsoLevel = XACT_READ_COMMITTED;
|
|
|
|
|
int XactIsoLevel;
|
1998-12-15 13:47:01 +01:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* info returned when the system is disabled
|
1997-03-15 00:21:12 +01:00
|
|
|
|
*
|
|
|
|
|
* Apparently a lot of this code is inherited from other prototype systems.
|
|
|
|
|
* For DisabledStartTime, use a symbolic value to make the relationships clearer.
|
|
|
|
|
* The old value of 1073741823 corresponds to a date in y2004, which is coming closer
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* every day. It appears that if we return a value guaranteed larger than
|
|
|
|
|
* any real time associated with a transaction then comparisons in other
|
|
|
|
|
* modules will still be correct. Let's use BIG_ABSTIME for this. tgl 2/14/97
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* Note: I have no idea what the significance of the
|
|
|
|
|
* 1073741823 in DisabledStartTime.. I just carried
|
|
|
|
|
* this over when converting things from the old
|
|
|
|
|
* V1 transaction system. -cim 3/18/90
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-08 23:56:23 +02:00
|
|
|
|
TransactionId DisabledTransactionId = (TransactionId) -1;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1997-09-08 23:56:23 +02:00
|
|
|
|
CommandId DisabledCommandId = (CommandId) -1;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
|
AbsoluteTime DisabledStartTime = (AbsoluteTime) BIG_ABSTIME; /* 1073741823; */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* overflow flag
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
|
bool CommandIdCounterOverflowFlag;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* catalog creation transaction bootstrapping flag.
|
|
|
|
|
* This should be eliminated and added to the transaction
|
|
|
|
|
* state stuff. -cim 3/19/90
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
|
bool AMI_OVERRIDE = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* transaction state accessors
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* TranactionFlushEnabled()
|
|
|
|
|
* SetTranactionFlushEnabled()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* These are used to test and set the "TransactionFlushState"
|
|
|
|
|
* varable. If this variable is true (the default), then
|
|
|
|
|
* the system will flush all dirty buffers to disk at the end
|
|
|
|
|
* of each transaction. If false then we are assuming the
|
|
|
|
|
* buffer pool resides in stable main memory, in which case we
|
|
|
|
|
* only do writes as necessary.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
|
static int TransactionFlushState = 1;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
int
|
1996-11-10 04:06:38 +01:00
|
|
|
|
TransactionFlushEnabled(void)
|
1997-09-07 07:04:48 +02:00
|
|
|
|
{
|
|
|
|
|
return TransactionFlushState;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
1997-08-19 23:40:56 +02:00
|
|
|
|
#ifdef NOT_USED
|
1996-07-09 08:22:35 +02:00
|
|
|
|
void
|
|
|
|
|
SetTransactionFlushEnabled(bool state)
|
1997-09-07 07:04:48 +02:00
|
|
|
|
{
|
|
|
|
|
TransactionFlushState = (state == true);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* IsTransactionState
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* This returns true if we are currently running a query
|
|
|
|
|
* within an executing transaction.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
bool
|
1996-11-10 04:06:38 +01:00
|
|
|
|
IsTransactionState(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
switch (s->state)
|
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
|
case TRANS_DEFAULT:
|
|
|
|
|
return false;
|
|
|
|
|
case TRANS_START:
|
|
|
|
|
return true;
|
|
|
|
|
case TRANS_INPROGRESS:
|
|
|
|
|
return true;
|
|
|
|
|
case TRANS_COMMIT:
|
|
|
|
|
return true;
|
|
|
|
|
case TRANS_ABORT:
|
|
|
|
|
return true;
|
|
|
|
|
case TRANS_DISABLED:
|
|
|
|
|
return false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Shouldn't get here, but lint is not happy with this...
|
|
|
|
|
*/
|
1998-09-01 05:29:17 +02:00
|
|
|
|
return false;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
1999-05-25 18:15:34 +02:00
|
|
|
|
|
1998-10-08 20:30:52 +02:00
|
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* IsAbortedTransactionBlockState
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* This returns true if we are currently running a query
|
|
|
|
|
* within an aborted transaction block.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
IsAbortedTransactionBlockState()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
if (s->blockState == TBLOCK_ABORT)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* OverrideTransactionSystem
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* This is used to temporarily disable the transaction
|
|
|
|
|
* processing system in order to do initialization of
|
|
|
|
|
* the transaction system data structures and relations
|
|
|
|
|
* themselves.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
|
int SavedTransactionState;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
OverrideTransactionSystem(bool flag)
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
if (flag == true)
|
|
|
|
|
{
|
|
|
|
|
if (s->state == TRANS_DISABLED)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
SavedTransactionState = s->state;
|
|
|
|
|
s->state = TRANS_DISABLED;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (s->state != TRANS_DISABLED)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
s->state = SavedTransactionState;
|
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* GetCurrentTransactionId
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* This returns the id of the current transaction, or
|
|
|
|
|
* the id of the "disabled" transaction.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
TransactionId
|
|
|
|
|
GetCurrentTransactionId()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* if the transaction system is disabled, we return
|
|
|
|
|
* the special "disabled" transaction id.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
if (s->state == TRANS_DISABLED)
|
|
|
|
|
return (TransactionId) DisabledTransactionId;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* otherwise return the current transaction id.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
return (TransactionId) s->transactionIdData;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* GetCurrentCommandId
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
CommandId
|
|
|
|
|
GetCurrentCommandId()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* if the transaction system is disabled, we return
|
|
|
|
|
* the special "disabled" command id.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
if (s->state == TRANS_DISABLED)
|
|
|
|
|
return (CommandId) DisabledCommandId;
|
|
|
|
|
|
|
|
|
|
return s->commandId;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
1997-08-29 11:05:25 +02:00
|
|
|
|
CommandId
|
|
|
|
|
GetScanCommandId()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* if the transaction system is disabled, we return
|
|
|
|
|
* the special "disabled" command id.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
if (s->state == TRANS_DISABLED)
|
|
|
|
|
return (CommandId) DisabledCommandId;
|
|
|
|
|
|
|
|
|
|
return s->scanCommandId;
|
1997-08-29 11:05:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* GetCurrentTransactionStartTime
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
AbsoluteTime
|
|
|
|
|
GetCurrentTransactionStartTime()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* if the transaction system is disabled, we return
|
|
|
|
|
* the special "disabled" starting time.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
if (s->state == TRANS_DISABLED)
|
|
|
|
|
return (AbsoluteTime) DisabledStartTime;
|
|
|
|
|
|
|
|
|
|
return s->startTime;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* TransactionIdIsCurrentTransactionId
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
TransactionIdIsCurrentTransactionId(TransactionId xid)
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
if (AMI_OVERRIDE)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return (bool)
|
|
|
|
|
TransactionIdEquals(xid, s->transactionIdData);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* CommandIdIsCurrentCommandId
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
CommandIdIsCurrentCommandId(CommandId cid)
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
if (AMI_OVERRIDE)
|
|
|
|
|
return false;
|
|
|
|
|
|
1999-02-03 22:18:02 +01:00
|
|
|
|
return (cid == s->commandId) ? true : false;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
1997-08-29 11:05:25 +02:00
|
|
|
|
bool
|
|
|
|
|
CommandIdGEScanCommandId(CommandId cid)
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
if (AMI_OVERRIDE)
|
|
|
|
|
return false;
|
|
|
|
|
|
1999-02-03 22:18:02 +01:00
|
|
|
|
return (cid >= s->scanCommandId) ? true : false;
|
1997-08-29 11:05:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* ClearCommandIdCounterOverflowFlag
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
#ifdef NOT_USED
|
1996-07-09 08:22:35 +02:00
|
|
|
|
void
|
|
|
|
|
ClearCommandIdCounterOverflowFlag()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
CommandIdCounterOverflowFlag = false;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1997-08-19 23:40:56 +02:00
|
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* CommandCounterIncrement
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
CommandCounterIncrement()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
CurrentTransactionStateData.commandId += 1;
|
|
|
|
|
if (CurrentTransactionStateData.commandId == FirstCommandId)
|
|
|
|
|
{
|
|
|
|
|
CommandIdCounterOverflowFlag = true;
|
1998-01-07 22:07:04 +01:00
|
|
|
|
elog(ERROR, "You may only have 2^32-1 commands per transaction");
|
1997-09-07 07:04:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
1999-02-03 22:18:02 +01:00
|
|
|
|
CurrentTransactionStateData.scanCommandId = CurrentTransactionStateData.commandId;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2000-01-10 07:30:56 +01:00
|
|
|
|
/*
|
2000-04-12 19:17:23 +02:00
|
|
|
|
* make cache changes visible to me. AtCommit_LocalCache() instead of
|
|
|
|
|
* AtCommit_Cache() is called here.
|
2000-01-10 07:30:56 +01:00
|
|
|
|
*/
|
|
|
|
|
AtCommit_LocalCache();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtStart_Cache();
|
1998-12-16 12:53:55 +01:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
void
|
|
|
|
|
SetScanCommandId(CommandId savedId)
|
1997-08-29 11:05:25 +02:00
|
|
|
|
{
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
CurrentTransactionStateData.scanCommandId = savedId;
|
|
|
|
|
|
1997-08-29 11:05:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* initialization stuff
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
InitializeTransactionSystem()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
InitializeTransactionLog();
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* StartTransaction stuff
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AtStart_Cache
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtStart_Cache()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
DiscardInvalid();
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AtStart_Locks
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtStart_Locks()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* at present, it is unknown to me what belongs here -cim 3/18/90
|
|
|
|
|
*
|
|
|
|
|
* There isn't anything to do at the start of a xact for locks. -mer
|
|
|
|
|
* 5/24/92
|
|
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AtStart_Memory
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtStart_Memory()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
|
Portal portal;
|
|
|
|
|
MemoryContext portalContext;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* get the blank portal and its memory context
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
portal = GetPortalByName(NULL);
|
|
|
|
|
portalContext = (MemoryContext) PortalGetHeapMemory(portal);
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* tell system to allocate in the blank portal context
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
MemoryContextSwitchTo(portalContext);
|
|
|
|
|
StartPortalAllocMode(DefaultAllocMode, 0);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* CommitTransaction stuff
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* RecordTransactionCommit
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* Note: the two calls to BufferManagerFlush() exist to ensure
|
|
|
|
|
* that data pages are written before log pages. These
|
|
|
|
|
* explicit calls should be replaced by a more efficient
|
|
|
|
|
* ordered page write scheme in the buffer manager
|
|
|
|
|
* -cim 3/18/90
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1997-09-07 07:04:48 +02:00
|
|
|
|
RecordTransactionCommit()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
|
TransactionId xid;
|
|
|
|
|
int leak;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* get the current transaction id
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
xid = GetCurrentTransactionId();
|
|
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
|
/*
|
|
|
|
|
* flush the buffer manager pages. Note: if we have stable main
|
|
|
|
|
* memory, dirty shared buffers are not flushed plai 8/7/90
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
|
|
|
|
leak = BufferPoolCheckLeak();
|
|
|
|
|
|
1999-06-29 06:54:49 +02:00
|
|
|
|
/*
|
2000-04-12 19:17:23 +02:00
|
|
|
|
* If no one shared buffer was changed by this transaction then we
|
|
|
|
|
* don't flush shared buffers and don't record commit status.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
1999-06-29 06:54:49 +02:00
|
|
|
|
if (SharedBufferChanged)
|
|
|
|
|
{
|
1999-09-28 13:41:09 +02:00
|
|
|
|
FlushBufferPool();
|
1999-06-29 06:54:49 +02:00
|
|
|
|
if (leak)
|
2000-04-09 06:43:20 +02:00
|
|
|
|
ResetBufferPool(true);
|
1999-06-29 06:54:49 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2000-04-12 19:17:23 +02:00
|
|
|
|
* have the transaction access methods record the status of this
|
|
|
|
|
* transaction id in the pg_log relation.
|
1999-06-29 06:54:49 +02:00
|
|
|
|
*/
|
|
|
|
|
TransactionIdCommit(xid);
|
|
|
|
|
|
|
|
|
|
/*
|
2000-04-12 19:17:23 +02:00
|
|
|
|
* Now write the log info to the disk too.
|
1999-06-29 06:54:49 +02:00
|
|
|
|
*/
|
|
|
|
|
leak = BufferPoolCheckLeak();
|
1999-09-28 13:41:09 +02:00
|
|
|
|
FlushBufferPool();
|
1999-06-29 06:54:49 +02:00
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
|
|
if (leak)
|
2000-04-09 06:43:20 +02:00
|
|
|
|
ResetBufferPool(true);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AtCommit_Cache
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1996-07-09 08:22:35 +02:00
|
|
|
|
AtCommit_Cache()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
/* ----------------
|
2000-01-10 07:30:56 +01:00
|
|
|
|
* Make catalog changes visible to all backend.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
RegisterInvalid(true);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2000-01-10 07:30:56 +01:00
|
|
|
|
/* --------------------------------
|
|
|
|
|
* AtCommit_LocalCache
|
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
AtCommit_LocalCache()
|
|
|
|
|
{
|
|
|
|
|
/* ----------------
|
|
|
|
|
* Make catalog changes visible to me for the next command.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
ImmediateLocalInvalidation(true);
|
|
|
|
|
}
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AtCommit_Locks
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtCommit_Locks()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* XXX What if ProcReleaseLocks fails? (race condition?)
|
|
|
|
|
*
|
|
|
|
|
* Then you're up a creek! -mer 5/24/92
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
ProcReleaseLocks();
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AtCommit_Memory
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtCommit_Memory()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1999-05-13 02:34:57 +02:00
|
|
|
|
Portal portal;
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
/* ----------------
|
1999-09-09 18:25:35 +02:00
|
|
|
|
* Release all heap memory in the blank portal.
|
1999-05-13 02:34:57 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
portal = GetPortalByName(NULL);
|
1999-09-09 18:25:35 +02:00
|
|
|
|
PortalResetHeapMemory(portal);
|
1999-05-13 02:34:57 +02:00
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* Now that we're "out" of a transaction, have the
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* system allocate things in the top memory context instead
|
|
|
|
|
* of the blank portal memory context.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
MemoryContextSwitchTo(TopMemoryContext);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AbortTransaction stuff
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* RecordTransactionAbort
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1997-09-07 07:04:48 +02:00
|
|
|
|
RecordTransactionAbort()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
|
TransactionId xid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* get the current transaction id
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
xid = GetCurrentTransactionId();
|
|
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
|
/*
|
|
|
|
|
* Have the transaction access methods record the status of this
|
|
|
|
|
* transaction id in the pg_log relation. We skip it if no one shared
|
|
|
|
|
* buffer was changed by this transaction.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
1999-09-16 11:08:56 +02:00
|
|
|
|
if (SharedBufferChanged && !TransactionIdDidCommit(xid))
|
1999-06-29 06:54:49 +02:00
|
|
|
|
TransactionIdAbort(xid);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2000-04-09 06:43:20 +02:00
|
|
|
|
/*
|
|
|
|
|
* Tell bufmgr and smgr to release resources.
|
|
|
|
|
*/
|
|
|
|
|
ResetBufferPool(false); /* false -> is abort */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AtAbort_Cache
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtAbort_Cache()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1999-09-04 20:42:15 +02:00
|
|
|
|
RelationCacheAbort();
|
1999-09-24 02:25:33 +02:00
|
|
|
|
RegisterInvalid(false);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AtAbort_Locks
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtAbort_Locks()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* XXX What if ProcReleaseLocks() fails? (race condition?)
|
|
|
|
|
*
|
|
|
|
|
* Then you're up a creek without a paddle! -mer
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
ProcReleaseLocks();
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AtAbort_Memory
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtAbort_Memory()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1999-05-13 02:34:57 +02:00
|
|
|
|
Portal portal;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
1999-09-09 18:25:35 +02:00
|
|
|
|
* Release all heap memory in the blank portal.
|
1999-05-13 02:34:57 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
portal = GetPortalByName(NULL);
|
1999-09-09 18:25:35 +02:00
|
|
|
|
PortalResetHeapMemory(portal);
|
1999-05-13 02:34:57 +02:00
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
/* ----------------
|
1999-05-13 02:34:57 +02:00
|
|
|
|
* Now that we're "out" of a transaction, have the
|
|
|
|
|
* system allocate things in the top memory context instead
|
|
|
|
|
* of the blank portal memory context.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
MemoryContextSwitchTo(TopMemoryContext);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* interface routines
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* StartTransaction
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1996-07-09 08:22:35 +02:00
|
|
|
|
StartTransaction()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
1998-12-16 12:53:55 +01:00
|
|
|
|
FreeXactSnapshot();
|
1998-12-18 10:10:39 +01:00
|
|
|
|
XactIsoLevel = DefaultXactIsoLevel;
|
1998-12-16 12:53:55 +01:00
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* Check the current transaction state. If the transaction system
|
|
|
|
|
* is switched off, or if we're already in a transaction, do nothing.
|
|
|
|
|
* We're already in a transaction when the monitor sends a null
|
|
|
|
|
* command to the backend to flush the comm channel. This is a
|
|
|
|
|
* hacky fix to a communications problem, and we keep having to
|
|
|
|
|
* deal with it here. We should fix the comm channel code. mao 080891
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
if (s->state == TRANS_DISABLED || s->state == TRANS_INPROGRESS)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* set the current transaction state information
|
|
|
|
|
* appropriately during start processing
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
s->state = TRANS_START;
|
|
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
|
SetReindexProcessing(false);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* generate a new transaction id
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
GetNewTransactionId(&(s->transactionIdData));
|
|
|
|
|
|
1998-12-15 13:47:01 +01:00
|
|
|
|
XactLockTableInsert(s->transactionIdData);
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* initialize current transaction state fields
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
s->commandId = FirstCommandId;
|
|
|
|
|
s->scanCommandId = FirstCommandId;
|
|
|
|
|
s->startTime = GetCurrentAbsoluteTime();
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* initialize the various transaction subsystems
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
AtStart_Cache();
|
|
|
|
|
AtStart_Locks();
|
|
|
|
|
AtStart_Memory();
|
|
|
|
|
|
|
|
|
|
/* --------------
|
|
|
|
|
initialize temporary relations list
|
|
|
|
|
the tempRelList is a list of temporary relations that
|
|
|
|
|
are created in the course of the transactions
|
|
|
|
|
they need to be destroyed properly at the end of the transactions
|
|
|
|
|
*/
|
1999-02-02 04:45:56 +01:00
|
|
|
|
InitNoNameRelList();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1999-09-29 18:06:40 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* Tell the trigger manager to we're starting a transaction
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
DeferredTriggerBeginXact();
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* done with start processing, set current transaction
|
|
|
|
|
* state to "in progress"
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
s->state = TRANS_INPROGRESS;
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ---------------
|
|
|
|
|
* Tell me if we are currently in progress
|
|
|
|
|
* ---------------
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
CurrentXactInProgress()
|
|
|
|
|
{
|
1998-09-01 05:29:17 +02:00
|
|
|
|
return CurrentTransactionState->state == TRANS_INPROGRESS;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* CommitTransaction
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1996-07-09 08:22:35 +02:00
|
|
|
|
CommitTransaction()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* check the current transaction state
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
if (s->state == TRANS_DISABLED)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (s->state != TRANS_INPROGRESS)
|
|
|
|
|
elog(NOTICE, "CommitTransaction and not in in-progress state ");
|
|
|
|
|
|
1999-09-29 18:06:40 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* Tell the trigger manager that this transaction is about to be
|
|
|
|
|
* committed. He'll invoke all trigger deferred until XACT before
|
2000-04-12 19:17:23 +02:00
|
|
|
|
* we really start on committing the transaction.
|
1999-09-29 18:06:40 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
DeferredTriggerEndXact();
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* set the current transaction state information
|
|
|
|
|
* appropriately during the abort processing
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
s->state = TRANS_COMMIT;
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* do commit processing
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1998-07-21 06:17:30 +02:00
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
|
/* handle commit for large objects [ PA, 7/17/98 ] */
|
1999-06-01 00:53:59 +02:00
|
|
|
|
lo_commit(true);
|
1998-07-21 06:17:30 +02:00
|
|
|
|
|
1998-10-06 04:40:09 +02:00
|
|
|
|
/* NOTIFY commit must also come before lower-level cleanup */
|
|
|
|
|
AtCommit_Notify();
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
CloseSequences();
|
1999-12-10 04:56:14 +01:00
|
|
|
|
DropNoNameRels();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtEOXact_portals();
|
|
|
|
|
RecordTransactionCommit();
|
1999-06-03 15:33:13 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2000-04-12 19:17:23 +02:00
|
|
|
|
* Let others know about no transaction in progress by me. Note that
|
|
|
|
|
* this must be done _before_ releasing locks we hold and
|
|
|
|
|
* SpinAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked
|
|
|
|
|
* by xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot -
|
|
|
|
|
* if xid 2' GetSnapshotData sees xid 1 as running then it must see
|
|
|
|
|
* xid 0 as running as well or it will see two tuple versions - one
|
|
|
|
|
* deleted by xid 1 and one inserted by xid 0.
|
1999-06-03 15:33:13 +02:00
|
|
|
|
*/
|
|
|
|
|
if (MyProc != (PROC *) NULL)
|
|
|
|
|
{
|
1999-09-24 02:25:33 +02:00
|
|
|
|
/* Lock SInvalLock because that's what GetSnapshotData uses. */
|
|
|
|
|
SpinAcquire(SInvalLock);
|
1999-06-03 15:33:13 +02:00
|
|
|
|
MyProc->xid = InvalidTransactionId;
|
|
|
|
|
MyProc->xmin = InvalidTransactionId;
|
1999-09-24 02:25:33 +02:00
|
|
|
|
SpinRelease(SInvalLock);
|
1999-06-03 15:33:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
RelationPurgeLocalRelation(true);
|
1999-08-08 22:12:52 +02:00
|
|
|
|
AtEOXact_nbtree();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtCommit_Cache();
|
|
|
|
|
AtCommit_Locks();
|
|
|
|
|
AtCommit_Memory();
|
1999-05-09 02:52:08 +02:00
|
|
|
|
AtEOXact_Files();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* done with commit processing, set current transaction
|
|
|
|
|
* state back to default
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
s->state = TRANS_DEFAULT;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
SharedBufferChanged = false;/* safest place to do it */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AbortTransaction
|
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
static void
|
|
|
|
|
AbortTransaction()
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Let others to know about no transaction in progress - vadim
|
|
|
|
|
* 11/26/96
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
if (MyProc != (PROC *) NULL)
|
1999-03-28 22:32:42 +02:00
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
MyProc->xid = InvalidTransactionId;
|
1999-03-28 22:32:42 +02:00
|
|
|
|
MyProc->xmin = InvalidTransactionId;
|
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* check the current transaction state
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
if (s->state == TRANS_DISABLED)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (s->state != TRANS_INPROGRESS)
|
|
|
|
|
elog(NOTICE, "AbortTransaction and not in in-progress state ");
|
|
|
|
|
|
1999-09-29 18:06:40 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* Tell the trigger manager that this transaction is about to be
|
2000-04-12 19:17:23 +02:00
|
|
|
|
* aborted.
|
1999-09-29 18:06:40 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
DeferredTriggerAbortXact();
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* set the current transaction state information
|
|
|
|
|
* appropriately during the abort processing
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
s->state = TRANS_ABORT;
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* do abort processing
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1999-06-01 00:53:59 +02:00
|
|
|
|
lo_commit(false); /* 'false' means it's abort */
|
1998-12-15 13:47:01 +01:00
|
|
|
|
UnlockBuffers();
|
1998-10-06 04:40:09 +02:00
|
|
|
|
AtAbort_Notify();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
CloseSequences();
|
|
|
|
|
AtEOXact_portals();
|
2000-02-18 10:30:20 +01:00
|
|
|
|
if (CommonSpecialPortalIsOpen())
|
|
|
|
|
CommonSpecialPortalClose();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
RecordTransactionAbort();
|
|
|
|
|
RelationPurgeLocalRelation(false);
|
1999-12-10 04:56:14 +01:00
|
|
|
|
DropNoNameRels();
|
1999-09-04 21:55:50 +02:00
|
|
|
|
invalidate_temp_relations();
|
1999-08-08 22:12:52 +02:00
|
|
|
|
AtEOXact_nbtree();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AtAbort_Cache();
|
|
|
|
|
AtAbort_Locks();
|
|
|
|
|
AtAbort_Memory();
|
1999-05-09 02:52:08 +02:00
|
|
|
|
AtEOXact_Files();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* done with abort processing, set current transaction
|
|
|
|
|
* state back to default
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
s->state = TRANS_DEFAULT;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
SharedBufferChanged = false;/* safest place to do it */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
|
* StartTransactionCommand
|
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
StartTransactionCommand()
|
|
|
|
|
{
|
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
switch (s->blockState)
|
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* if we aren't in a transaction block, we
|
|
|
|
|
* just do our usual start transaction.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_DEFAULT:
|
|
|
|
|
StartTransaction();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* We should never experience this -- if we do it
|
|
|
|
|
* means the BEGIN state was not changed in the previous
|
|
|
|
|
* CommitTransactionCommand(). If we get it, we print
|
|
|
|
|
* a warning and change to the in-progress state.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_BEGIN:
|
|
|
|
|
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
|
|
|
|
|
s->blockState = TBLOCK_INPROGRESS;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* This is the case when are somewhere in a transaction
|
|
|
|
|
* block and about to start a new command. For now we
|
|
|
|
|
* do nothing but someday we may do command-local resource
|
|
|
|
|
* initialization.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_INPROGRESS:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
1999-05-25 18:15:34 +02:00
|
|
|
|
* As with BEGIN, we should never experience this
|
1997-09-08 04:41:22 +02:00
|
|
|
|
* if we do it means the END state was not changed in the
|
|
|
|
|
* previous CommitTransactionCommand(). If we get it, we
|
|
|
|
|
* print a warning, commit the transaction, start a new
|
|
|
|
|
* transaction and change to the default state.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_END:
|
|
|
|
|
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_END");
|
|
|
|
|
s->blockState = TBLOCK_DEFAULT;
|
|
|
|
|
CommitTransaction();
|
|
|
|
|
StartTransaction();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* Here we are in the middle of a transaction block but
|
|
|
|
|
* one of the commands caused an abort so we do nothing
|
|
|
|
|
* but remain in the abort state. Eventually we will get
|
|
|
|
|
* to the "END TRANSACTION" which will set things straight.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_ABORT:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* This means we somehow aborted and the last call to
|
|
|
|
|
* CommitTransactionCommand() didn't clear the state so
|
|
|
|
|
* we remain in the ENDABORT state and mabey next time
|
|
|
|
|
* we get to CommitTransactionCommand() the state will
|
|
|
|
|
* get reset to default.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_ENDABORT:
|
|
|
|
|
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
|
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
|
* CommitTransactionCommand
|
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
CommitTransactionCommand()
|
|
|
|
|
{
|
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
switch (s->blockState)
|
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* if we aren't in a transaction block, we
|
|
|
|
|
* just do our usual transaction commit
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_DEFAULT:
|
|
|
|
|
CommitTransaction();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* This is the case right after we get a "BEGIN TRANSACTION"
|
|
|
|
|
* command, but the user hasn't done anything else yet, so
|
|
|
|
|
* we change to the "transaction block in progress" state
|
|
|
|
|
* and return.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_BEGIN:
|
|
|
|
|
s->blockState = TBLOCK_INPROGRESS;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* This is the case when we have finished executing a command
|
|
|
|
|
* someplace within a transaction block. We increment the
|
|
|
|
|
* command counter and return. Someday we may free resources
|
|
|
|
|
* local to the command.
|
|
|
|
|
*
|
|
|
|
|
* That someday is today, at least for memory allocated by
|
|
|
|
|
* command in the BlankPortal' HeapMemory context.
|
|
|
|
|
* - vadim 03/25/97
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_INPROGRESS:
|
|
|
|
|
CommandCounterIncrement();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
#ifdef TBL_FREE_CMD_MEMORY
|
1997-09-08 04:41:22 +02:00
|
|
|
|
EndPortalAllocMode();
|
|
|
|
|
StartPortalAllocMode(DefaultAllocMode, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
#endif
|
1997-09-08 04:41:22 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* This is the case when we just got the "END TRANSACTION"
|
|
|
|
|
* statement, so we go back to the default state and
|
|
|
|
|
* commit the transaction.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_END:
|
|
|
|
|
s->blockState = TBLOCK_DEFAULT;
|
|
|
|
|
CommitTransaction();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* Here we are in the middle of a transaction block but
|
|
|
|
|
* one of the commands caused an abort so we do nothing
|
|
|
|
|
* but remain in the abort state. Eventually we will get
|
|
|
|
|
* to the "END TRANSACTION" which will set things straight.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_ABORT:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* Here we were in an aborted transaction block which
|
|
|
|
|
* just processed the "END TRANSACTION" command from the
|
|
|
|
|
* user, so now we return the to default state.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_ENDABORT:
|
|
|
|
|
s->blockState = TBLOCK_DEFAULT;
|
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AbortCurrentTransaction
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
AbortCurrentTransaction()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
switch (s->blockState)
|
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
|
/* ----------------
|
|
|
|
|
* if we aren't in a transaction block, we
|
|
|
|
|
* just do our usual abort transaction.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_DEFAULT:
|
|
|
|
|
AbortTransaction();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* If we are in the TBLOCK_BEGIN it means something
|
|
|
|
|
* screwed up right after reading "BEGIN TRANSACTION"
|
|
|
|
|
* so we enter the abort state. Eventually an "END
|
|
|
|
|
* TRANSACTION" will fix things.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_BEGIN:
|
|
|
|
|
s->blockState = TBLOCK_ABORT;
|
|
|
|
|
AbortTransaction();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* This is the case when are somewhere in a transaction
|
|
|
|
|
* block which aborted so we abort the transaction and
|
|
|
|
|
* set the ABORT state. Eventually an "END TRANSACTION"
|
|
|
|
|
* will fix things and restore us to a normal state.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_INPROGRESS:
|
|
|
|
|
s->blockState = TBLOCK_ABORT;
|
|
|
|
|
AbortTransaction();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* Here, the system was fouled up just after the
|
|
|
|
|
* user wanted to end the transaction block so we
|
|
|
|
|
* abort the transaction and put us back into the
|
|
|
|
|
* default state.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_END:
|
|
|
|
|
s->blockState = TBLOCK_DEFAULT;
|
|
|
|
|
AbortTransaction();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* Here, we are already in an aborted transaction
|
|
|
|
|
* state and are waiting for an "END TRANSACTION" to
|
|
|
|
|
* come along and lo and behold, we abort again!
|
|
|
|
|
* So we just remain in the abort state.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_ABORT:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* Here we were in an aborted transaction block which
|
|
|
|
|
* just processed the "END TRANSACTION" command but somehow
|
|
|
|
|
* aborted again.. since we must have done the abort
|
|
|
|
|
* processing, we return to the default state.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
case TBLOCK_ENDABORT:
|
|
|
|
|
s->blockState = TBLOCK_DEFAULT;
|
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
|
* transaction block support
|
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
/* --------------------------------
|
|
|
|
|
* BeginTransactionBlock
|
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
BeginTransactionBlock(void)
|
|
|
|
|
{
|
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* check the current transaction state
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
if (s->state == TRANS_DISABLED)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (s->blockState != TBLOCK_DEFAULT)
|
2000-01-29 17:58:54 +01:00
|
|
|
|
elog(NOTICE, "BEGIN: already a transaction in progress");
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* set the current transaction block state information
|
|
|
|
|
* appropriately during begin processing
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
s->blockState = TBLOCK_BEGIN;
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* do begin processing
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* done with begin processing, set block state to inprogress
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
s->blockState = TBLOCK_INPROGRESS;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* EndTransactionBlock
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
1996-11-10 04:06:38 +01:00
|
|
|
|
EndTransactionBlock(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* check the current transaction state
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
if (s->state == TRANS_DISABLED)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (s->blockState == TBLOCK_INPROGRESS)
|
|
|
|
|
{
|
|
|
|
|
/* ----------------
|
|
|
|
|
* here we are in a transaction block which should commit
|
|
|
|
|
* when we get to the upcoming CommitTransactionCommand()
|
|
|
|
|
* so we set the state to "END". CommitTransactionCommand()
|
|
|
|
|
* will recognize this and commit the transaction and return
|
|
|
|
|
* us to the default state
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
s->blockState = TBLOCK_END;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (s->blockState == TBLOCK_ABORT)
|
|
|
|
|
{
|
|
|
|
|
/* ----------------
|
|
|
|
|
* here, we are in a transaction block which aborted
|
|
|
|
|
* and since the AbortTransaction() was already done,
|
|
|
|
|
* we do whatever is needed and change to the special
|
|
|
|
|
* "END ABORT" state. The upcoming CommitTransactionCommand()
|
|
|
|
|
* will recognise this and then put us back in the default
|
|
|
|
|
* state.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
s->blockState = TBLOCK_ENDABORT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* We should not get here, but if we do, we go to the ENDABORT
|
|
|
|
|
* state after printing a warning. The upcoming call to
|
|
|
|
|
* CommitTransactionCommand() will then put us back into the
|
|
|
|
|
* default state.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
2000-01-29 17:58:54 +01:00
|
|
|
|
elog(NOTICE, "COMMIT: no transaction in progress");
|
1996-07-09 08:22:35 +02:00
|
|
|
|
s->blockState = TBLOCK_ENDABORT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AbortTransactionBlock
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
#ifdef NOT_USED
|
|
|
|
|
static void
|
1996-11-10 04:06:38 +01:00
|
|
|
|
AbortTransactionBlock(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* check the current transaction state
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
if (s->state == TRANS_DISABLED)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (s->blockState == TBLOCK_INPROGRESS)
|
|
|
|
|
{
|
|
|
|
|
/* ----------------
|
|
|
|
|
* here we were inside a transaction block something
|
|
|
|
|
* screwed up inside the system so we enter the abort state,
|
|
|
|
|
* do the abort processing and then return.
|
|
|
|
|
* We remain in the abort state until we see the upcoming
|
|
|
|
|
* END TRANSACTION command.
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
s->blockState = TBLOCK_ABORT;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* do abort processing and return
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
AbortTransaction();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* this case should not be possible, because it would mean
|
|
|
|
|
* the user entered an "abort" from outside a transaction block.
|
|
|
|
|
* So we print an error message, abort the transaction and
|
|
|
|
|
* enter the "ENDABORT" state so we will end up in the default
|
|
|
|
|
* state after the upcoming CommitTransactionCommand().
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
elog(NOTICE, "AbortTransactionBlock and not in in-progress state");
|
1996-07-09 08:22:35 +02:00
|
|
|
|
AbortTransaction();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
s->blockState = TBLOCK_ENDABORT;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1997-08-19 23:40:56 +02:00
|
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* UserAbortTransactionBlock
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
UserAbortTransactionBlock()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* check the current transaction state
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
if (s->state == TRANS_DISABLED)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* if the transaction has already been automatically aborted with an
|
|
|
|
|
* error, and the user subsequently types 'abort', allow it. (the
|
|
|
|
|
* behavior is the same as if they had typed 'end'.)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
if (s->blockState == TBLOCK_ABORT)
|
|
|
|
|
{
|
|
|
|
|
s->blockState = TBLOCK_ENDABORT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (s->blockState == TBLOCK_INPROGRESS)
|
|
|
|
|
{
|
|
|
|
|
/* ----------------
|
|
|
|
|
* here we were inside a transaction block and we
|
|
|
|
|
* got an abort command from the user, so we move to
|
|
|
|
|
* the abort state, do the abort processing and
|
|
|
|
|
* then change to the ENDABORT state so we will end up
|
|
|
|
|
* in the default state after the upcoming
|
|
|
|
|
* CommitTransactionCommand().
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
s->blockState = TBLOCK_ABORT;
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* do abort processing
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
AbortTransaction();
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* change to the end abort state and return
|
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
|
|
|
|
s->blockState = TBLOCK_ENDABORT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* this case should not be possible, because it would mean
|
2000-01-29 17:58:54 +01:00
|
|
|
|
* the user entered a "rollback" from outside a transaction block.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* So we print an error message, abort the transaction and
|
|
|
|
|
* enter the "ENDABORT" state so we will end up in the default
|
|
|
|
|
* state after the upcoming CommitTransactionCommand().
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------
|
|
|
|
|
*/
|
2000-01-29 17:58:54 +01:00
|
|
|
|
elog(NOTICE, "ROLLBACK: no transaction in progress");
|
1997-09-07 07:04:48 +02:00
|
|
|
|
AbortTransaction();
|
1996-07-09 08:22:35 +02:00
|
|
|
|
s->blockState = TBLOCK_ENDABORT;
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-06 04:40:09 +02:00
|
|
|
|
/* --------------------------------
|
|
|
|
|
* AbortOutOfAnyTransaction
|
|
|
|
|
*
|
|
|
|
|
* This routine is provided for error recovery purposes. It aborts any
|
|
|
|
|
* active transaction or transaction block, leaving the system in a known
|
|
|
|
|
* idle state.
|
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
AbortOutOfAnyTransaction()
|
|
|
|
|
{
|
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get out of any low-level transaction
|
|
|
|
|
*/
|
|
|
|
|
if (s->state != TRANS_DEFAULT)
|
|
|
|
|
AbortTransaction();
|
1999-05-25 18:15:34 +02:00
|
|
|
|
|
1998-10-06 04:40:09 +02:00
|
|
|
|
/*
|
|
|
|
|
* Now reset the high-level state
|
|
|
|
|
*/
|
|
|
|
|
s->blockState = TBLOCK_DEFAULT;
|
|
|
|
|
}
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
bool
|
|
|
|
|
IsTransactionBlock()
|
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
TransactionState s = CurrentTransactionState;
|
|
|
|
|
|
|
|
|
|
if (s->blockState == TBLOCK_INPROGRESS
|
1999-09-05 19:12:34 +02:00
|
|
|
|
|| s->blockState == TBLOCK_ABORT
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|| s->blockState == TBLOCK_ENDABORT)
|
1998-09-01 05:29:17 +02:00
|
|
|
|
return true;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
|
return false;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|