1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* transam.c
|
2001-08-25 20:52:43 +02:00
|
|
|
* postgres transaction log interface routines
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2002-06-20 22:29:54 +02:00
|
|
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2002-09-04 22:31:48 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.54 2002/09/04 20:31:13 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* NOTES
|
1997-09-07 07:04:48 +02:00
|
|
|
* This file contains the high level access-method interface to the
|
|
|
|
* transaction system.
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1996-10-21 09:15:18 +02:00
|
|
|
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "postgres.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-08-25 20:52:43 +02:00
|
|
|
#include "access/clog.h"
|
2000-11-21 22:16:06 +01:00
|
|
|
#include "access/transam.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-07-12 06:11:13 +02:00
|
|
|
|
2002-05-25 22:00:12 +02:00
|
|
|
/* ----------------
|
|
|
|
* Flag indicating that we are bootstrapping.
|
|
|
|
*
|
|
|
|
* Transaction ID generation is disabled during bootstrap; we just use
|
2002-09-04 22:31:48 +02:00
|
|
|
* BootstrapTransactionId. Also, the transaction ID status-check routines
|
2002-05-25 22:00:12 +02:00
|
|
|
* are short-circuited; they claim that BootstrapTransactionId has already
|
|
|
|
* committed, allowing tuples already inserted to be seen immediately.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
bool AMI_OVERRIDE = false;
|
|
|
|
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool TransactionLogTest(TransactionId transactionId, XidStatus status);
|
1998-09-01 06:40:42 +02:00
|
|
|
static void TransactionLogUpdate(TransactionId transactionId,
|
1997-09-07 07:04:48 +02:00
|
|
|
XidStatus status);
|
1997-08-19 23:40:56 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
2001-07-12 06:11:13 +02:00
|
|
|
* Single-item cache for results of TransactionLogTest.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2001-08-24 01:06:38 +02:00
|
|
|
static TransactionId cachedTestXid = InvalidTransactionId;
|
2001-10-25 07:50:21 +02:00
|
|
|
static XidStatus cachedTestXidStatus;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-11-02 16:27:14 +01:00
|
|
|
* postgres log access method interface
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
|
|
|
* TransactionLogTest
|
|
|
|
* TransactionLogUpdate
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TransactionLogTest
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
|
1997-09-08 23:56:23 +02:00
|
|
|
static bool /* true/false: does transaction id have
|
1997-09-07 07:04:48 +02:00
|
|
|
* specified status? */
|
|
|
|
TransactionLogTest(TransactionId transactionId, /* transaction id to test */
|
|
|
|
XidStatus status) /* transaction status */
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
XidStatus xidstatus; /* recorded status of xid */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-10-25 07:50:21 +02:00
|
|
|
* Before going to the commit log manager, check our single item cache
|
|
|
|
* to see if we didn't just check the transaction status a moment ago.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
if (TransactionIdEquals(transactionId, cachedTestXid))
|
2001-08-25 20:52:43 +02:00
|
|
|
return (status == cachedTestXidStatus);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-08-25 20:52:43 +02:00
|
|
|
* Also, check to see if the transaction ID is a permanent one.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-10-25 07:50:21 +02:00
|
|
|
if (!TransactionIdIsNormal(transactionId))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2001-08-25 20:52:43 +02:00
|
|
|
if (TransactionIdEquals(transactionId, BootstrapTransactionId))
|
|
|
|
return (status == TRANSACTION_STATUS_COMMITTED);
|
|
|
|
if (TransactionIdEquals(transactionId, FrozenTransactionId))
|
|
|
|
return (status == TRANSACTION_STATUS_COMMITTED);
|
|
|
|
return (status == TRANSACTION_STATUS_ABORTED);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-08-25 20:52:43 +02:00
|
|
|
* Get the status.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-10-25 07:50:21 +02:00
|
|
|
xidstatus = TransactionIdGetStatus(transactionId);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* DO NOT cache status for unfinished transactions!
|
|
|
|
*/
|
|
|
|
if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS)
|
|
|
|
{
|
|
|
|
TransactionIdStore(transactionId, &cachedTestXid);
|
|
|
|
cachedTestXidStatus = xidstatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (status == xidstatus);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TransactionLogUpdate
|
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
|
|
|
TransactionLogUpdate(TransactionId transactionId, /* trans id to update */
|
|
|
|
XidStatus status) /* new trans status */
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-08-25 20:52:43 +02:00
|
|
|
* update the commit log
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-08-25 20:52:43 +02:00
|
|
|
TransactionIdSetStatus(transactionId, status);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-12-15 13:47:01 +01:00
|
|
|
/*
|
|
|
|
* update (invalidate) our single item TransactionLogTest cache.
|
|
|
|
*/
|
1998-12-16 12:53:55 +01:00
|
|
|
TransactionIdStore(transactionId, &cachedTestXid);
|
|
|
|
cachedTestXidStatus = status;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
2001-08-25 20:52:43 +02:00
|
|
|
* AmiTransactionOverride
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2001-08-25 20:52:43 +02:00
|
|
|
* This function is used to manipulate the bootstrap flag.
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
2001-08-25 20:52:43 +02:00
|
|
|
void
|
|
|
|
AmiTransactionOverride(bool flag)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2001-08-25 20:52:43 +02:00
|
|
|
AMI_OVERRIDE = flag;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* Interface functions
|
|
|
|
*
|
|
|
|
* TransactionId DidCommit
|
|
|
|
* TransactionId DidAbort
|
|
|
|
* TransactionId IsInProgress
|
|
|
|
* ========
|
|
|
|
* these functions test the transaction status of
|
|
|
|
* a specified transaction id.
|
|
|
|
*
|
|
|
|
* TransactionId Commit
|
|
|
|
* TransactionId Abort
|
|
|
|
* ========
|
|
|
|
* these functions set the transaction status
|
2001-08-25 20:52:43 +02:00
|
|
|
* of the specified xid.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TransactionId DidCommit
|
|
|
|
* TransactionId DidAbort
|
|
|
|
* TransactionId IsInProgress
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
1999-05-25 18:15:34 +02:00
|
|
|
* TransactionIdDidCommit
|
1997-09-07 07:04:48 +02:00
|
|
|
* True iff transaction associated with the identifier did commit.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* Note:
|
1997-09-07 07:04:48 +02:00
|
|
|
* Assumes transaction identifier is valid.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
bool /* true if given transaction committed */
|
1996-07-09 08:22:35 +02:00
|
|
|
TransactionIdDidCommit(TransactionId transactionId)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (AMI_OVERRIDE)
|
2002-05-25 22:00:12 +02:00
|
|
|
{
|
|
|
|
Assert(transactionId == BootstrapTransactionId);
|
1997-09-07 07:04:48 +02:00
|
|
|
return true;
|
2002-05-25 22:00:12 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-08-25 20:52:43 +02:00
|
|
|
return TransactionLogTest(transactionId, TRANSACTION_STATUS_COMMITTED);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2001-08-25 20:52:43 +02:00
|
|
|
* TransactionIdDidAbort
|
1997-09-07 07:04:48 +02:00
|
|
|
* True iff transaction associated with the identifier did abort.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* Note:
|
1997-09-07 07:04:48 +02:00
|
|
|
* Assumes transaction identifier is valid.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
bool /* true if given transaction aborted */
|
1996-07-09 08:22:35 +02:00
|
|
|
TransactionIdDidAbort(TransactionId transactionId)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (AMI_OVERRIDE)
|
2002-05-25 22:00:12 +02:00
|
|
|
{
|
|
|
|
Assert(transactionId == BootstrapTransactionId);
|
1997-09-07 07:04:48 +02:00
|
|
|
return false;
|
2002-05-25 22:00:12 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-08-25 20:52:43 +02:00
|
|
|
return TransactionLogTest(transactionId, TRANSACTION_STATUS_ABORTED);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
1996-11-27 08:10:59 +01:00
|
|
|
* Now this func in shmem.c and gives quality answer by scanning
|
2002-06-11 15:40:53 +02:00
|
|
|
* PGPROC structures of all running backend. - vadim 11/26/96
|
1996-11-27 16:15:54 +01:00
|
|
|
*
|
|
|
|
* Old comments:
|
2001-08-25 20:52:43 +02:00
|
|
|
* true if given transaction has neither committed nor aborted
|
|
|
|
*/
|
|
|
|
#ifdef NOT_USED
|
1996-11-27 16:15:54 +01:00
|
|
|
bool
|
1996-07-09 08:22:35 +02:00
|
|
|
TransactionIdIsInProgress(TransactionId transactionId)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (AMI_OVERRIDE)
|
2002-05-25 22:00:12 +02:00
|
|
|
{
|
|
|
|
Assert(transactionId == BootstrapTransactionId);
|
1997-09-07 07:04:48 +02:00
|
|
|
return false;
|
2002-05-25 22:00:12 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-08-25 20:52:43 +02:00
|
|
|
return TransactionLogTest(transactionId, TRANSACTION_STATUS_IN_PROGRESS);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2001-11-05 18:46:40 +01:00
|
|
|
#endif /* NOT_USED */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TransactionId Commit
|
|
|
|
* TransactionId Abort
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
1999-05-25 18:15:34 +02:00
|
|
|
* TransactionIdCommit
|
1997-09-07 07:04:48 +02:00
|
|
|
* Commits the transaction associated with the identifier.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* Note:
|
1997-09-07 07:04:48 +02:00
|
|
|
* Assumes transaction identifier is valid.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
TransactionIdCommit(TransactionId transactionId)
|
|
|
|
{
|
2001-08-25 20:52:43 +02:00
|
|
|
TransactionLogUpdate(transactionId, TRANSACTION_STATUS_COMMITTED);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1999-05-25 18:15:34 +02:00
|
|
|
* TransactionIdAbort
|
1997-09-07 07:04:48 +02:00
|
|
|
* Aborts the transaction associated with the identifier.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* Note:
|
1997-09-07 07:04:48 +02:00
|
|
|
* Assumes transaction identifier is valid.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
TransactionIdAbort(TransactionId transactionId)
|
|
|
|
{
|
2001-08-25 20:52:43 +02:00
|
|
|
TransactionLogUpdate(transactionId, TRANSACTION_STATUS_ABORTED);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2001-08-26 18:56:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TransactionIdPrecedes --- is id1 logically < id2?
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
TransactionIdPrecedes(TransactionId id1, TransactionId id2)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If either ID is a permanent XID then we can just do unsigned
|
2001-10-25 07:50:21 +02:00
|
|
|
* comparison. If both are normal, do a modulo-2^31 comparison.
|
2001-08-26 18:56:03 +02:00
|
|
|
*/
|
|
|
|
int32 diff;
|
|
|
|
|
|
|
|
if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
|
|
|
|
return (id1 < id2);
|
|
|
|
|
|
|
|
diff = (int32) (id1 - id2);
|
|
|
|
return (diff < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TransactionIdPrecedesOrEquals --- is id1 logically <= id2?
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
|
|
|
|
{
|
|
|
|
int32 diff;
|
|
|
|
|
|
|
|
if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
|
|
|
|
return (id1 <= id2);
|
|
|
|
|
|
|
|
diff = (int32) (id1 - id2);
|
|
|
|
return (diff <= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TransactionIdFollows --- is id1 logically > id2?
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
TransactionIdFollows(TransactionId id1, TransactionId id2)
|
|
|
|
{
|
|
|
|
int32 diff;
|
|
|
|
|
|
|
|
if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
|
|
|
|
return (id1 > id2);
|
|
|
|
|
|
|
|
diff = (int32) (id1 - id2);
|
|
|
|
return (diff > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TransactionIdFollowsOrEquals --- is id1 logically >= id2?
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
|
|
|
|
{
|
|
|
|
int32 diff;
|
|
|
|
|
|
|
|
if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
|
|
|
|
return (id1 >= id2);
|
|
|
|
|
|
|
|
diff = (int32) (id1 - id2);
|
|
|
|
return (diff >= 0);
|
|
|
|
}
|