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
|
|
|
*
|
2007-01-05 23:20:05 +01:00
|
|
|
* Portions Copyright (c) 1996-2007, 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
|
2007-09-08 22:31:15 +02:00
|
|
|
* $PostgreSQL: pgsql/src/backend/access/transam/transam.c,v 1.71 2007/09/08 20:31:14 tgl 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"
|
2004-07-01 02:52:04 +02:00
|
|
|
#include "access/subtrans.h"
|
2000-11-21 22:16:06 +01:00
|
|
|
#include "access/transam.h"
|
2004-08-22 04:41:58 +02:00
|
|
|
#include "utils/tqual.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-07-12 06:11:13 +02:00
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
static XidStatus TransactionLogFetch(TransactionId transactionId);
|
1998-09-01 06:40:42 +02:00
|
|
|
static void TransactionLogUpdate(TransactionId transactionId,
|
2007-08-02 00:45:09 +02:00
|
|
|
XidStatus status, XLogRecPtr lsn);
|
1997-08-19 23:40:56 +02:00
|
|
|
|
2007-08-02 00:45:09 +02:00
|
|
|
/*
|
|
|
|
* Single-item cache for results of TransactionLogFetch.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2004-07-01 02:52:04 +02:00
|
|
|
static TransactionId cachedFetchXid = InvalidTransactionId;
|
|
|
|
static XidStatus cachedFetchXidStatus;
|
2007-08-02 00:45:09 +02:00
|
|
|
static XLogRecPtr cachedCommitLSN;
|
|
|
|
|
|
|
|
/* Handy constant for an invalid xlog recptr */
|
|
|
|
static const XLogRecPtr InvalidXLogRecPtr = {0, 0};
|
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
|
|
|
*
|
2004-07-01 02:52:04 +02:00
|
|
|
* TransactionLogFetch
|
1997-09-07 07:04:48 +02:00
|
|
|
* TransactionLogUpdate
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/*
|
|
|
|
* TransactionLogFetch --- fetch commit status of specified transaction id
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2004-07-01 02:52:04 +02:00
|
|
|
static XidStatus
|
|
|
|
TransactionLogFetch(TransactionId transactionId)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2004-07-01 02:52:04 +02:00
|
|
|
XidStatus xidstatus;
|
2007-08-02 00:45:09 +02:00
|
|
|
XLogRecPtr xidlsn;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +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
|
|
|
*/
|
2004-07-01 02:52:04 +02:00
|
|
|
if (TransactionIdEquals(transactionId, cachedFetchXid))
|
|
|
|
return cachedFetchXidStatus;
|
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))
|
2004-07-01 02:52:04 +02:00
|
|
|
return TRANSACTION_STATUS_COMMITTED;
|
2001-08-25 20:52:43 +02:00
|
|
|
if (TransactionIdEquals(transactionId, FrozenTransactionId))
|
2004-07-01 02:52:04 +02:00
|
|
|
return TRANSACTION_STATUS_COMMITTED;
|
|
|
|
return TRANSACTION_STATUS_ABORTED;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2007-08-02 00:45:09 +02:00
|
|
|
* Get the transaction status.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2007-08-02 00:45:09 +02:00
|
|
|
xidstatus = TransactionIdGetStatus(transactionId, &xidlsn);
|
2001-10-25 07:50:21 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* DO NOT cache status for unfinished or sub-committed transactions! We
|
|
|
|
* only cache status that is guaranteed not to change.
|
2001-10-25 07:50:21 +02:00
|
|
|
*/
|
2004-07-01 02:52:04 +02:00
|
|
|
if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS &&
|
|
|
|
xidstatus != TRANSACTION_STATUS_SUB_COMMITTED)
|
2001-10-25 07:50:21 +02:00
|
|
|
{
|
2007-08-02 00:45:09 +02:00
|
|
|
cachedFetchXid = transactionId;
|
2004-07-01 02:52:04 +02:00
|
|
|
cachedFetchXidStatus = xidstatus;
|
2007-08-02 00:45:09 +02:00
|
|
|
cachedCommitLSN = xidlsn;
|
2001-10-25 07:50:21 +02:00
|
|
|
}
|
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
return xidstatus;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TransactionLogUpdate
|
2007-08-02 00:45:09 +02:00
|
|
|
*
|
|
|
|
* Store the new status of a transaction. The commit record LSN must be
|
|
|
|
* passed when recording an async commit; else it should be InvalidXLogRecPtr.
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
|
|
|
*/
|
2007-08-02 00:45:09 +02:00
|
|
|
static inline void
|
|
|
|
TransactionLogUpdate(TransactionId transactionId,
|
|
|
|
XidStatus status, XLogRecPtr lsn)
|
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
|
|
|
*/
|
2007-08-02 00:45:09 +02:00
|
|
|
TransactionIdSetStatus(transactionId, status, lsn);
|
2004-07-01 02:52:04 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/*
|
|
|
|
* TransactionLogMultiUpdate
|
|
|
|
*
|
|
|
|
* Update multiple transaction identifiers to a given status.
|
|
|
|
* Don't depend on this being atomic; it's not.
|
|
|
|
*/
|
2007-08-02 00:45:09 +02:00
|
|
|
static inline void
|
|
|
|
TransactionLogMultiUpdate(int nxids, TransactionId *xids,
|
|
|
|
XidStatus status, XLogRecPtr lsn)
|
2004-07-01 02:52:04 +02:00
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
int i;
|
2004-07-01 02:52:04 +02:00
|
|
|
|
|
|
|
Assert(nxids != 0);
|
|
|
|
|
|
|
|
for (i = 0; i < nxids; i++)
|
2007-08-02 00:45:09 +02:00
|
|
|
TransactionIdSetStatus(xids[i], status, lsn);
|
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)
|
|
|
|
{
|
2004-07-01 02:52:04 +02:00
|
|
|
XidStatus xidstatus;
|
|
|
|
|
|
|
|
xidstatus = TransactionLogFetch(transactionId);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If it's marked committed, it's committed.
|
|
|
|
*/
|
|
|
|
if (xidstatus == TRANSACTION_STATUS_COMMITTED)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If it's marked subcommitted, we have to check the parent recursively.
|
|
|
|
* However, if it's older than TransactionXmin, we can't look at
|
|
|
|
* pg_subtrans; instead assume that the parent crashed without cleaning up
|
|
|
|
* its children.
|
2005-06-18 00:32:51 +02:00
|
|
|
*
|
2005-11-22 19:17:34 +01:00
|
|
|
* Originally we Assert'ed that the result of SubTransGetParent was not
|
|
|
|
* zero. However with the introduction of prepared transactions, there can
|
|
|
|
* be a window just after database startup where we do not have complete
|
2005-10-15 04:49:52 +02:00
|
|
|
* knowledge in pg_subtrans of the transactions after TransactionXmin.
|
|
|
|
* StartupSUBTRANS() has ensured that any missing information will be
|
|
|
|
* zeroed. Since this case should not happen under normal conditions, it
|
|
|
|
* seems reasonable to emit a WARNING for it.
|
2004-07-01 02:52:04 +02:00
|
|
|
*/
|
|
|
|
if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
|
|
|
|
{
|
|
|
|
TransactionId parentXid;
|
2004-08-22 04:41:58 +02:00
|
|
|
|
2004-09-16 20:35:23 +02:00
|
|
|
if (TransactionIdPrecedes(transactionId, TransactionXmin))
|
2004-08-22 04:41:58 +02:00
|
|
|
return false;
|
2004-07-01 02:52:04 +02:00
|
|
|
parentXid = SubTransGetParent(transactionId);
|
2005-06-18 00:32:51 +02:00
|
|
|
if (!TransactionIdIsValid(parentXid))
|
|
|
|
{
|
|
|
|
elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
|
|
|
|
transactionId);
|
|
|
|
return false;
|
|
|
|
}
|
2004-07-01 02:52:04 +02:00
|
|
|
return TransactionIdDidCommit(parentXid);
|
|
|
|
}
|
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
/*
|
2004-07-01 02:52:04 +02:00
|
|
|
* It's not committed.
|
|
|
|
*/
|
|
|
|
return false;
|
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)
|
|
|
|
{
|
2004-07-01 02:52:04 +02:00
|
|
|
XidStatus xidstatus;
|
|
|
|
|
|
|
|
xidstatus = TransactionLogFetch(transactionId);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/*
|
|
|
|
* If it's marked aborted, it's aborted.
|
|
|
|
*/
|
|
|
|
if (xidstatus == TRANSACTION_STATUS_ABORTED)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If it's marked subcommitted, we have to check the parent recursively.
|
|
|
|
* However, if it's older than TransactionXmin, we can't look at
|
|
|
|
* pg_subtrans; instead assume that the parent crashed without cleaning up
|
|
|
|
* its children.
|
2004-07-01 02:52:04 +02:00
|
|
|
*/
|
|
|
|
if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
|
2002-05-25 22:00:12 +02:00
|
|
|
{
|
2004-07-01 02:52:04 +02:00
|
|
|
TransactionId parentXid;
|
|
|
|
|
2004-09-16 20:35:23 +02:00
|
|
|
if (TransactionIdPrecedes(transactionId, TransactionXmin))
|
2004-08-22 04:41:58 +02:00
|
|
|
return true;
|
|
|
|
parentXid = SubTransGetParent(transactionId);
|
2005-06-18 00:32:51 +02:00
|
|
|
if (!TransactionIdIsValid(parentXid))
|
|
|
|
{
|
|
|
|
/* see notes in TransactionIdDidCommit */
|
|
|
|
elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
|
|
|
|
transactionId);
|
|
|
|
return true;
|
|
|
|
}
|
2004-08-22 04:41:58 +02:00
|
|
|
return TransactionIdDidAbort(parentXid);
|
2002-05-25 22:00:12 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/*
|
|
|
|
* It's not aborted.
|
|
|
|
*/
|
|
|
|
return false;
|
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)
|
|
|
|
{
|
2007-08-02 00:45:09 +02:00
|
|
|
TransactionLogUpdate(transactionId, TRANSACTION_STATUS_COMMITTED,
|
|
|
|
InvalidXLogRecPtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TransactionIdAsyncCommit
|
|
|
|
* Same as above, but for async commits. The commit record LSN is needed.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
TransactionIdAsyncCommit(TransactionId transactionId, XLogRecPtr lsn)
|
|
|
|
{
|
|
|
|
TransactionLogUpdate(transactionId, TRANSACTION_STATUS_COMMITTED, lsn);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2007-08-02 00:45:09 +02:00
|
|
|
|
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.
|
2007-08-02 00:45:09 +02:00
|
|
|
* No async version of this is needed.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
TransactionIdAbort(TransactionId transactionId)
|
|
|
|
{
|
2007-08-02 00:45:09 +02:00
|
|
|
TransactionLogUpdate(transactionId, TRANSACTION_STATUS_ABORTED,
|
|
|
|
InvalidXLogRecPtr);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2001-08-26 18:56:03 +02:00
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/*
|
|
|
|
* TransactionIdSubCommit
|
|
|
|
* Marks the subtransaction associated with the identifier as
|
|
|
|
* sub-committed.
|
2007-08-02 00:45:09 +02:00
|
|
|
*
|
|
|
|
* Note:
|
|
|
|
* No async version of this is needed.
|
2004-07-01 02:52:04 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
TransactionIdSubCommit(TransactionId transactionId)
|
|
|
|
{
|
2007-08-02 00:45:09 +02:00
|
|
|
TransactionLogUpdate(transactionId, TRANSACTION_STATUS_SUB_COMMITTED,
|
|
|
|
InvalidXLogRecPtr);
|
2004-07-01 02:52:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TransactionIdCommitTree
|
|
|
|
* Marks all the given transaction ids as committed.
|
|
|
|
*
|
|
|
|
* The caller has to be sure that this is used only to mark subcommitted
|
|
|
|
* subtransactions as committed, and only *after* marking the toplevel
|
|
|
|
* parent as committed. Otherwise there is a race condition against
|
|
|
|
* TransactionIdDidCommit.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
TransactionIdCommitTree(int nxids, TransactionId *xids)
|
|
|
|
{
|
|
|
|
if (nxids > 0)
|
2007-08-02 00:45:09 +02:00
|
|
|
TransactionLogMultiUpdate(nxids, xids, TRANSACTION_STATUS_COMMITTED,
|
|
|
|
InvalidXLogRecPtr);
|
2004-07-01 02:52:04 +02:00
|
|
|
}
|
|
|
|
|
2007-08-02 00:45:09 +02:00
|
|
|
/*
|
|
|
|
* TransactionIdAsyncCommitTree
|
|
|
|
* Same as above, but for async commits. The commit record LSN is needed.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
TransactionIdAsyncCommitTree(int nxids, TransactionId *xids, XLogRecPtr lsn)
|
|
|
|
{
|
|
|
|
if (nxids > 0)
|
|
|
|
TransactionLogMultiUpdate(nxids, xids, TRANSACTION_STATUS_COMMITTED,
|
|
|
|
lsn);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/*
|
|
|
|
* TransactionIdAbortTree
|
|
|
|
* Marks all the given transaction ids as aborted.
|
|
|
|
*
|
|
|
|
* We don't need to worry about the non-atomic behavior, since any onlookers
|
|
|
|
* will consider all the xacts as not-yet-committed anyway.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
TransactionIdAbortTree(int nxids, TransactionId *xids)
|
|
|
|
{
|
|
|
|
if (nxids > 0)
|
2007-08-02 00:45:09 +02:00
|
|
|
TransactionLogMultiUpdate(nxids, xids, TRANSACTION_STATUS_ABORTED,
|
|
|
|
InvalidXLogRecPtr);
|
2004-07-01 02:52:04 +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);
|
|
|
|
}
|
2007-08-02 00:45:09 +02:00
|
|
|
|
2007-09-08 22:31:15 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* TransactionIdLatest --- get latest XID among a main xact and its children
|
|
|
|
*/
|
|
|
|
TransactionId
|
|
|
|
TransactionIdLatest(TransactionId mainxid,
|
|
|
|
int nxids, const TransactionId *xids)
|
|
|
|
{
|
|
|
|
TransactionId result;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In practice it is highly likely that the xids[] array is sorted, and
|
|
|
|
* so we could save some cycles by just taking the last child XID, but
|
|
|
|
* this probably isn't so performance-critical that it's worth depending
|
|
|
|
* on that assumption. But just to show we're not totally stupid, scan
|
|
|
|
* the array back-to-front to avoid useless assignments.
|
|
|
|
*/
|
|
|
|
result = mainxid;
|
|
|
|
while (--nxids >= 0)
|
|
|
|
{
|
|
|
|
if (TransactionIdPrecedes(result, xids[nxids]))
|
|
|
|
result = xids[nxids];
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-02 00:45:09 +02:00
|
|
|
/*
|
|
|
|
* TransactionIdGetCommitLSN
|
|
|
|
*
|
|
|
|
* This function returns an LSN that is late enough to be able
|
|
|
|
* to guarantee that if we flush up to the LSN returned then we
|
|
|
|
* will have flushed the transaction's commit record to disk.
|
|
|
|
*
|
|
|
|
* The result is not necessarily the exact LSN of the transaction's
|
|
|
|
* commit record! For example, for long-past transactions (those whose
|
|
|
|
* clog pages already migrated to disk), we'll return InvalidXLogRecPtr.
|
|
|
|
* Also, because we group transactions on the same clog page to conserve
|
|
|
|
* storage, we might return the LSN of a later transaction that falls into
|
|
|
|
* the same group.
|
|
|
|
*/
|
|
|
|
XLogRecPtr
|
|
|
|
TransactionIdGetCommitLSN(TransactionId xid)
|
|
|
|
{
|
|
|
|
XLogRecPtr result;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Currently, all uses of this function are for xids that were just
|
|
|
|
* reported to be committed by TransactionLogFetch, so we expect that
|
|
|
|
* checking TransactionLogFetch's cache will usually succeed and avoid an
|
|
|
|
* extra trip to shared memory.
|
|
|
|
*/
|
|
|
|
if (TransactionIdEquals(xid, cachedFetchXid))
|
|
|
|
return cachedCommitLSN;
|
|
|
|
|
|
|
|
/* Special XIDs are always known committed */
|
|
|
|
if (!TransactionIdIsNormal(xid))
|
|
|
|
return InvalidXLogRecPtr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the transaction status.
|
|
|
|
*/
|
|
|
|
(void) TransactionIdGetStatus(xid, &result);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|