mirror of
https://github.com/postgres/postgres.git
synced 2025-08-30 06:01:21 +03:00
Postgres95 1.01 Distribution - Virgin Sources
This commit is contained in:
14
src/backend/access/transam/Makefile.inc
Normal file
14
src/backend/access/transam/Makefile.inc
Normal file
@@ -0,0 +1,14 @@
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile.inc--
|
||||
# Makefile for access/transam
|
||||
#
|
||||
# Copyright (c) 1994, Regents of the University of California
|
||||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/Makefile.inc,v 1.1.1.1 1996/07/09 06:21:13 scrappy Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
SUBSRCS+= transam.c transsup.c varsup.c xact.c xid.c
|
675
src/backend/access/transam/transam.c
Normal file
675
src/backend/access/transam/transam.c
Normal file
@@ -0,0 +1,675 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* transam.c--
|
||||
* postgres transaction log/time interface routines
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.1.1.1 1996/07/09 06:21:13 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains the high level access-method interface to the
|
||||
* transaction system.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "machine.h" /* in port/ directory (needed for BLCKSZ) */
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "storage/buf.h"
|
||||
#include "storage/bufmgr.h"
|
||||
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/mcxt.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/elog.h"
|
||||
|
||||
#include "utils/nabstime.h"
|
||||
#include "catalog/catname.h"
|
||||
|
||||
#include "access/transam.h"
|
||||
#include "access/xact.h"
|
||||
#include "commands/vacuum.h" /* for VacuumRunning */
|
||||
|
||||
/* ----------------
|
||||
* global variables holding pointers to relations used
|
||||
* by the transaction system. These are initialized by
|
||||
* InitializeTransactionLog().
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
Relation LogRelation = (Relation) NULL;
|
||||
Relation TimeRelation = (Relation) NULL;
|
||||
Relation VariableRelation = (Relation) NULL;
|
||||
|
||||
/* ----------------
|
||||
* global variables holding cached transaction id's and statuses.
|
||||
* ----------------
|
||||
*/
|
||||
TransactionId cachedGetCommitTimeXid;
|
||||
AbsoluteTime cachedGetCommitTime;
|
||||
TransactionId cachedTestXid;
|
||||
XidStatus cachedTestXidStatus;
|
||||
|
||||
/* ----------------
|
||||
* transaction system constants
|
||||
* ----------------
|
||||
*/
|
||||
/* ----------------------------------------------------------------
|
||||
* transaction system constants
|
||||
*
|
||||
* read the comments for GetNewTransactionId in order to
|
||||
* understand the initial values for AmiTransactionId and
|
||||
* FirstTransactionId. -cim 3/23/90
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TransactionId NullTransactionId = (TransactionId) 0;
|
||||
|
||||
TransactionId AmiTransactionId = (TransactionId) 512;
|
||||
|
||||
TransactionId FirstTransactionId = (TransactionId) 514;
|
||||
|
||||
/* ----------------
|
||||
* transaction recovery state variables
|
||||
*
|
||||
* When the transaction system is initialized, we may
|
||||
* need to do recovery checking. This decision is decided
|
||||
* by the postmaster or the user by supplying the backend
|
||||
* with a special flag. In general, we want to do recovery
|
||||
* checking whenever we are running without a postmaster
|
||||
* or when the number of backends running under the postmaster
|
||||
* goes from zero to one. -cim 3/21/90
|
||||
* ----------------
|
||||
*/
|
||||
int RecoveryCheckingEnableState = 0;
|
||||
|
||||
/* ------------------
|
||||
* spinlock for oid generation
|
||||
* -----------------
|
||||
*/
|
||||
extern int OidGenLockId;
|
||||
|
||||
/* ----------------
|
||||
* globals that must be reset at abort
|
||||
* ----------------
|
||||
*/
|
||||
extern bool BuildingBtree;
|
||||
|
||||
|
||||
/* ----------------
|
||||
* recovery checking accessors
|
||||
* ----------------
|
||||
*/
|
||||
int
|
||||
RecoveryCheckingEnabled()
|
||||
{
|
||||
return RecoveryCheckingEnableState;
|
||||
}
|
||||
|
||||
void
|
||||
SetRecoveryCheckingEnabled(bool state)
|
||||
{
|
||||
RecoveryCheckingEnableState = (state == true);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* postgres log/time access method interface
|
||||
*
|
||||
* TransactionLogTest
|
||||
* TransactionLogUpdate
|
||||
* ========
|
||||
* these functions do work for the interface
|
||||
* functions - they search/retrieve and append/update
|
||||
* information in the log and time relations.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* --------------------------------
|
||||
* TransactionLogTest
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
bool /* true/false: does transaction id have specified status? */
|
||||
TransactionLogTest(TransactionId transactionId, /* transaction id to test */
|
||||
XidStatus status) /* transaction status */
|
||||
{
|
||||
BlockNumber blockNumber;
|
||||
XidStatus xidstatus; /* recorded status of xid */
|
||||
bool fail = false; /* success/failure */
|
||||
|
||||
/* ----------------
|
||||
* during initialization consider all transactions
|
||||
* as having been committed
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(LogRelation))
|
||||
return (bool) (status == XID_COMMIT);
|
||||
|
||||
/* ----------------
|
||||
* before going to the buffer manager, check our single
|
||||
* item cache to see if we didn't just check the transaction
|
||||
* status a moment ago.
|
||||
* ----------------
|
||||
*/
|
||||
if (TransactionIdEquals(transactionId, cachedTestXid))
|
||||
return (bool)
|
||||
(status == cachedTestXidStatus);
|
||||
|
||||
/* ----------------
|
||||
* compute the item pointer corresponding to the
|
||||
* page containing our transaction id. We save the item in
|
||||
* our cache to speed up things if we happen to ask for the
|
||||
* same xid's status more than once.
|
||||
* ----------------
|
||||
*/
|
||||
TransComputeBlockNumber(LogRelation, transactionId, &blockNumber);
|
||||
xidstatus = TransBlockNumberGetXidStatus(LogRelation,
|
||||
blockNumber,
|
||||
transactionId,
|
||||
&fail);
|
||||
|
||||
if (! fail) {
|
||||
TransactionIdStore(transactionId, &cachedTestXid);
|
||||
cachedTestXidStatus = xidstatus;
|
||||
return (bool)
|
||||
(status == xidstatus);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* here the block didn't contain the information we wanted
|
||||
* ----------------
|
||||
*/
|
||||
elog(WARN, "TransactionLogTest: failed to get xidstatus");
|
||||
|
||||
/*
|
||||
* so lint is happy...
|
||||
*/
|
||||
return(false);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransactionLogUpdate
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
TransactionLogUpdate(TransactionId transactionId, /* trans id to update */
|
||||
XidStatus status) /* new trans status */
|
||||
{
|
||||
BlockNumber blockNumber;
|
||||
bool fail = false; /* success/failure */
|
||||
AbsoluteTime currentTime; /* time of this transaction */
|
||||
|
||||
/* ----------------
|
||||
* during initialization we don't record any updates.
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(LogRelation))
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* get the transaction commit time
|
||||
* ----------------
|
||||
*/
|
||||
currentTime = getSystemTime();
|
||||
|
||||
/* ----------------
|
||||
* update the log relation
|
||||
* ----------------
|
||||
*/
|
||||
TransComputeBlockNumber(LogRelation, transactionId, &blockNumber);
|
||||
TransBlockNumberSetXidStatus(LogRelation,
|
||||
blockNumber,
|
||||
transactionId,
|
||||
status,
|
||||
&fail);
|
||||
|
||||
/* ----------------
|
||||
* update (invalidate) our single item TransactionLogTest cache.
|
||||
* ----------------
|
||||
*/
|
||||
TransactionIdStore(transactionId, &cachedTestXid);
|
||||
cachedTestXidStatus = status;
|
||||
|
||||
/* ----------------
|
||||
* now we update the time relation, if necessary
|
||||
* (we only record commit times)
|
||||
* ----------------
|
||||
*/
|
||||
if (RelationIsValid(TimeRelation) && status == XID_COMMIT) {
|
||||
TransComputeBlockNumber(TimeRelation, transactionId, &blockNumber);
|
||||
TransBlockNumberSetCommitTime(TimeRelation,
|
||||
blockNumber,
|
||||
transactionId,
|
||||
currentTime,
|
||||
&fail);
|
||||
/* ----------------
|
||||
* update (invalidate) our single item GetCommitTime cache.
|
||||
* ----------------
|
||||
*/
|
||||
TransactionIdStore(transactionId, &cachedGetCommitTimeXid);
|
||||
cachedGetCommitTime = currentTime;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* now we update the "last committed transaction" field
|
||||
* in the variable relation if we are recording a commit.
|
||||
* ----------------
|
||||
*/
|
||||
if (RelationIsValid(VariableRelation) && status == XID_COMMIT)
|
||||
UpdateLastCommittedXid(transactionId);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransactionIdGetCommitTime
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
AbsoluteTime /* commit time of transaction id */
|
||||
TransactionIdGetCommitTime(TransactionId transactionId) /* transaction id to test */
|
||||
{
|
||||
BlockNumber blockNumber;
|
||||
AbsoluteTime commitTime; /* commit time */
|
||||
bool fail = false; /* success/failure */
|
||||
|
||||
/* ----------------
|
||||
* return invalid if we aren't running yet...
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(TimeRelation))
|
||||
return INVALID_ABSTIME;
|
||||
|
||||
/* ----------------
|
||||
* before going to the buffer manager, check our single
|
||||
* item cache to see if we didn't just get the commit time
|
||||
* a moment ago.
|
||||
* ----------------
|
||||
*/
|
||||
if (TransactionIdEquals(transactionId, cachedGetCommitTimeXid))
|
||||
return cachedGetCommitTime;
|
||||
|
||||
/* ----------------
|
||||
* compute the item pointer corresponding to the
|
||||
* page containing our transaction commit time
|
||||
* ----------------
|
||||
*/
|
||||
TransComputeBlockNumber(TimeRelation, transactionId, &blockNumber);
|
||||
commitTime = TransBlockNumberGetCommitTime(TimeRelation,
|
||||
blockNumber,
|
||||
transactionId,
|
||||
&fail);
|
||||
|
||||
/* ----------------
|
||||
* update our cache and return the transaction commit time
|
||||
* ----------------
|
||||
*/
|
||||
if (! fail) {
|
||||
TransactionIdStore(transactionId, &cachedGetCommitTimeXid);
|
||||
cachedGetCommitTime = commitTime;
|
||||
return commitTime;
|
||||
} else
|
||||
return INVALID_ABSTIME;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* transaction recovery code
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* --------------------------------
|
||||
* TransRecover
|
||||
*
|
||||
* preform transaction recovery checking.
|
||||
*
|
||||
* Note: this should only be preformed if no other backends
|
||||
* are running. This is known by the postmaster and
|
||||
* conveyed by the postmaster passing a "do recovery checking"
|
||||
* flag to the backend.
|
||||
*
|
||||
* here we get the last recorded transaction from the log,
|
||||
* get the "last" and "next" transactions from the variable relation
|
||||
* and then preform some integrity tests:
|
||||
*
|
||||
* 1) No transaction may exist higher then the "next" available
|
||||
* transaction recorded in the variable relation. If this is the
|
||||
* case then it means either the log or the variable relation
|
||||
* has become corrupted.
|
||||
*
|
||||
* 2) The last committed transaction may not be higher then the
|
||||
* next available transaction for the same reason.
|
||||
*
|
||||
* 3) The last recorded transaction may not be lower then the
|
||||
* last committed transaction. (the reverse is ok - it means
|
||||
* that some transactions have aborted since the last commit)
|
||||
*
|
||||
* Here is what the proper situation looks like. The line
|
||||
* represents the data stored in the log. 'c' indicates the
|
||||
* transaction was recorded as committed, 'a' indicates an
|
||||
* abortted transaction and '.' represents information not
|
||||
* recorded. These may correspond to in progress transactions.
|
||||
*
|
||||
* c c a c . . a . . . . . . . . . .
|
||||
* | |
|
||||
* last next
|
||||
*
|
||||
* Since "next" is only incremented by GetNewTransactionId() which
|
||||
* is called when transactions are started. Hence if there
|
||||
* are commits or aborts after "next", then it means we committed
|
||||
* or aborted BEFORE we started the transaction. This is the
|
||||
* rational behind constraint (1).
|
||||
*
|
||||
* Likewise, "last" should never greater then "next" for essentially
|
||||
* the same reason - it would imply we committed before we started.
|
||||
* This is the reasoning for (2).
|
||||
*
|
||||
* (3) implies we may never have a situation such as:
|
||||
*
|
||||
* c c a c . . a c . . . . . . . . .
|
||||
* | |
|
||||
* last next
|
||||
*
|
||||
* where there is a 'c' greater then "last".
|
||||
*
|
||||
* Recovery checking is more difficult in the case where
|
||||
* several backends are executing concurrently because the
|
||||
* transactions may be executing in the other backends.
|
||||
* So, we only do recovery stuff when the backend is explicitly
|
||||
* passed a flag on the command line.
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
TransRecover(Relation logRelation)
|
||||
{
|
||||
#if 0
|
||||
/* ----------------
|
||||
* first get the last recorded transaction in the log.
|
||||
* ----------------
|
||||
*/
|
||||
TransGetLastRecordedTransaction(logRelation, logLastXid, &fail);
|
||||
if (fail == true)
|
||||
elog(WARN, "TransRecover: failed TransGetLastRecordedTransaction");
|
||||
|
||||
/* ----------------
|
||||
* next get the "last" and "next" variables
|
||||
* ----------------
|
||||
*/
|
||||
VariableRelationGetLastXid(&varLastXid);
|
||||
VariableRelationGetNextXid(&varNextXid);
|
||||
|
||||
/* ----------------
|
||||
* intregity test (1)
|
||||
* ----------------
|
||||
*/
|
||||
if (TransactionIdIsLessThan(varNextXid, logLastXid))
|
||||
elog(WARN, "TransRecover: varNextXid < logLastXid");
|
||||
|
||||
/* ----------------
|
||||
* intregity test (2)
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* intregity test (3)
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* here we have a valid "
|
||||
*
|
||||
* **** RESUME HERE ****
|
||||
* ----------------
|
||||
*/
|
||||
varNextXid = TransactionIdDup(varLastXid);
|
||||
TransactionIdIncrement(&varNextXid);
|
||||
|
||||
VarPut(var, VAR_PUT_LASTXID, varLastXid);
|
||||
VarPut(var, VAR_PUT_NEXTXID, varNextXid);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* Interface functions
|
||||
*
|
||||
* InitializeTransactionLog
|
||||
* ========
|
||||
* this function (called near cinit) initializes
|
||||
* the transaction log, time and variable relations.
|
||||
*
|
||||
* TransactionId DidCommit
|
||||
* TransactionId DidAbort
|
||||
* TransactionId IsInProgress
|
||||
* ========
|
||||
* these functions test the transaction status of
|
||||
* a specified transaction id.
|
||||
*
|
||||
* TransactionId Commit
|
||||
* TransactionId Abort
|
||||
* TransactionId SetInProgress
|
||||
* ========
|
||||
* these functions set the transaction status
|
||||
* of the specified xid. TransactionIdCommit() also
|
||||
* records the current time in the time relation
|
||||
* and updates the variable relation counter.
|
||||
*
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* InitializeTransactionLog --
|
||||
* Initializes transaction logging.
|
||||
*/
|
||||
void
|
||||
InitializeTransactionLog()
|
||||
{
|
||||
Relation logRelation;
|
||||
Relation timeRelation;
|
||||
MemoryContext oldContext;
|
||||
|
||||
/* ----------------
|
||||
* don't do anything during bootstrapping
|
||||
* ----------------
|
||||
*/
|
||||
if (AMI_OVERRIDE)
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* disable the transaction system so the access methods
|
||||
* don't interfere during initialization.
|
||||
* ----------------
|
||||
*/
|
||||
OverrideTransactionSystem(true);
|
||||
|
||||
/* ----------------
|
||||
* make sure allocations occur within the top memory context
|
||||
* so that our log management structures are protected from
|
||||
* garbage collection at the end of every transaction.
|
||||
* ----------------
|
||||
*/
|
||||
oldContext = MemoryContextSwitchTo(TopMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* first open the log and time relations
|
||||
* (these are created by amiint so they are guaranteed to exist)
|
||||
* ----------------
|
||||
*/
|
||||
logRelation = heap_openr(LogRelationName);
|
||||
timeRelation = heap_openr(TimeRelationName);
|
||||
VariableRelation = heap_openr(VariableRelationName);
|
||||
/* ----------------
|
||||
* XXX TransactionLogUpdate requires that LogRelation
|
||||
* and TimeRelation are valid so we temporarily set
|
||||
* them so we can initialize things properly.
|
||||
* This could be done cleaner.
|
||||
* ----------------
|
||||
*/
|
||||
LogRelation = logRelation;
|
||||
TimeRelation = timeRelation;
|
||||
|
||||
/* ----------------
|
||||
* if we have a virgin database, we initialize the log and time
|
||||
* relation by committing the AmiTransactionId (id 512) and we
|
||||
* initialize the variable relation by setting the next available
|
||||
* transaction id to FirstTransactionId (id 514). OID initialization
|
||||
* happens as a side effect of bootstrapping in varsup.c.
|
||||
* ----------------
|
||||
*/
|
||||
SpinAcquire(OidGenLockId);
|
||||
if (!TransactionIdDidCommit(AmiTransactionId)) {
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY initialize the information stored in
|
||||
* the headers of the log/time/variable relations.
|
||||
* ----------------
|
||||
*/
|
||||
TransactionLogUpdate(AmiTransactionId, XID_COMMIT);
|
||||
VariableRelationPutNextXid(FirstTransactionId);
|
||||
|
||||
} else if (RecoveryCheckingEnabled()) {
|
||||
/* ----------------
|
||||
* if we have a pre-initialized database and if the
|
||||
* perform recovery checking flag was passed then we
|
||||
* do our database integrity checking.
|
||||
* ----------------
|
||||
*/
|
||||
TransRecover(logRelation);
|
||||
}
|
||||
LogRelation = (Relation) NULL;
|
||||
TimeRelation = (Relation) NULL;
|
||||
SpinRelease(OidGenLockId);
|
||||
|
||||
/* ----------------
|
||||
* now re-enable the transaction system
|
||||
* ----------------
|
||||
*/
|
||||
OverrideTransactionSystem(false);
|
||||
|
||||
/* ----------------
|
||||
* instantiate the global variables
|
||||
* ----------------
|
||||
*/
|
||||
LogRelation = logRelation;
|
||||
TimeRelation = timeRelation;
|
||||
|
||||
/* ----------------
|
||||
* restore the memory context to the previous context
|
||||
* before we return from initialization.
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextSwitchTo(oldContext);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransactionId DidCommit
|
||||
* TransactionId DidAbort
|
||||
* TransactionId IsInProgress
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* TransactionIdDidCommit --
|
||||
* True iff transaction associated with the identifier did commit.
|
||||
*
|
||||
* Note:
|
||||
* Assumes transaction identifier is valid.
|
||||
*/
|
||||
bool /* true if given transaction committed */
|
||||
TransactionIdDidCommit(TransactionId transactionId)
|
||||
{
|
||||
if (AMI_OVERRIDE)
|
||||
return true;
|
||||
|
||||
return
|
||||
TransactionLogTest(transactionId, XID_COMMIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* TransactionIdDidAborted --
|
||||
* True iff transaction associated with the identifier did abort.
|
||||
*
|
||||
* Note:
|
||||
* Assumes transaction identifier is valid.
|
||||
* XXX Is this unneeded?
|
||||
*/
|
||||
bool /* true if given transaction aborted */
|
||||
TransactionIdDidAbort(TransactionId transactionId)
|
||||
{
|
||||
if (AMI_OVERRIDE)
|
||||
return false;
|
||||
|
||||
return
|
||||
TransactionLogTest(transactionId, XID_ABORT);
|
||||
}
|
||||
|
||||
bool /* true if given transaction neither committed nor aborted */
|
||||
TransactionIdIsInProgress(TransactionId transactionId)
|
||||
{
|
||||
if (AMI_OVERRIDE)
|
||||
return false;
|
||||
|
||||
return
|
||||
TransactionLogTest(transactionId, XID_INPROGRESS);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransactionId Commit
|
||||
* TransactionId Abort
|
||||
* TransactionId SetInProgress
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* TransactionIdCommit --
|
||||
* Commits the transaction associated with the identifier.
|
||||
*
|
||||
* Note:
|
||||
* Assumes transaction identifier is valid.
|
||||
*/
|
||||
void
|
||||
TransactionIdCommit(TransactionId transactionId)
|
||||
{
|
||||
if (AMI_OVERRIDE)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Within TransactionLogUpdate we call UpdateLastCommited()
|
||||
* which assumes we have exclusive access to pg_variable.
|
||||
* Therefore we need to get exclusive access before calling
|
||||
* TransactionLogUpdate. -mer 18 Aug 1992
|
||||
*/
|
||||
SpinAcquire(OidGenLockId);
|
||||
TransactionLogUpdate(transactionId, XID_COMMIT);
|
||||
SpinRelease(OidGenLockId);
|
||||
}
|
||||
|
||||
/*
|
||||
* TransactionIdAbort --
|
||||
* Aborts the transaction associated with the identifier.
|
||||
*
|
||||
* Note:
|
||||
* Assumes transaction identifier is valid.
|
||||
*/
|
||||
void
|
||||
TransactionIdAbort(TransactionId transactionId)
|
||||
{
|
||||
BuildingBtree = false;
|
||||
|
||||
if (VacuumRunning)
|
||||
vc_abort();
|
||||
|
||||
if (AMI_OVERRIDE)
|
||||
return;
|
||||
|
||||
TransactionLogUpdate(transactionId, XID_ABORT);
|
||||
}
|
||||
|
||||
void
|
||||
TransactionIdSetInProgress(TransactionId transactionId)
|
||||
{
|
||||
if (AMI_OVERRIDE)
|
||||
return;
|
||||
|
||||
TransactionLogUpdate(transactionId, XID_INPROGRESS);
|
||||
}
|
663
src/backend/access/transam/transsup.c
Normal file
663
src/backend/access/transam/transsup.c
Normal file
@@ -0,0 +1,663 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* transsup.c--
|
||||
* postgres transaction access method support code
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/transsup.c,v 1.1.1.1 1996/07/09 06:21:13 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains support functions for the high
|
||||
* level access method interface routines found in transam.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "machine.h" /* in port/ directory (needed for BLCKSZ) */
|
||||
|
||||
#include "storage/buf.h"
|
||||
#include "storage/bufmgr.h"
|
||||
|
||||
#include "utils/rel.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/nabstime.h"
|
||||
|
||||
#include "catalog/heap.h"
|
||||
#include "access/transam.h" /* where the declarations go */
|
||||
#include "access/xact.h" /* where the declarations go */
|
||||
|
||||
#include "storage/smgr.h"
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* general support routines
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* --------------------------------
|
||||
* AmiTransactionOverride
|
||||
*
|
||||
* This function is used to manipulate the bootstrap flag.
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
AmiTransactionOverride(bool flag)
|
||||
{
|
||||
AMI_OVERRIDE = flag;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransComputeBlockNumber
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
TransComputeBlockNumber(Relation relation, /* relation to test */
|
||||
TransactionId transactionId, /* transaction id to test */
|
||||
BlockNumber *blockNumberOutP)
|
||||
{
|
||||
long itemsPerBlock;
|
||||
|
||||
/* ----------------
|
||||
* we calculate the block number of our transaction
|
||||
* by dividing the transaction id by the number of
|
||||
* transaction things per block.
|
||||
* ----------------
|
||||
*/
|
||||
if (relation == LogRelation)
|
||||
itemsPerBlock = TP_NumXidStatusPerBlock;
|
||||
else if (relation == TimeRelation)
|
||||
itemsPerBlock = TP_NumTimePerBlock;
|
||||
else
|
||||
elog(WARN, "TransComputeBlockNumber: unknown relation");
|
||||
|
||||
/* ----------------
|
||||
* warning! if the transaction id's get too large
|
||||
* then a BlockNumber may not be large enough to hold the results
|
||||
* of our division.
|
||||
*
|
||||
* XXX this will all vanish soon when we implement an improved
|
||||
* transaction id schema -cim 3/23/90
|
||||
*
|
||||
* This has vanished now that xid's are 4 bytes (no longer 5).
|
||||
* -mer 5/24/92
|
||||
* ----------------
|
||||
*/
|
||||
(*blockNumberOutP) = transactionId / itemsPerBlock;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* trans block support routines
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* --------------------------------
|
||||
* TransBlockGetLastTransactionIdStatus
|
||||
*
|
||||
* This returns the status and transaction id of the last
|
||||
* transaction information recorded on the given TransBlock.
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
XidStatus
|
||||
TransBlockGetLastTransactionIdStatus(Block tblock,
|
||||
TransactionId baseXid,
|
||||
TransactionId *returnXidP)
|
||||
{
|
||||
Index index;
|
||||
Index maxIndex;
|
||||
bits8 bit1;
|
||||
bits8 bit2;
|
||||
BitIndex offset;
|
||||
XidStatus xstatus;
|
||||
|
||||
/* ----------------
|
||||
* sanity check
|
||||
* ----------------
|
||||
*/
|
||||
Assert((tblock != NULL));
|
||||
|
||||
/* ----------------
|
||||
* search downward from the top of the block data, looking
|
||||
* for the first Non-in progress transaction status. Since we
|
||||
* are scanning backward, this will be last recorded transaction
|
||||
* status on the block.
|
||||
* ----------------
|
||||
*/
|
||||
maxIndex = TP_NumXidStatusPerBlock;
|
||||
for (index = maxIndex-1; index>=0; index--) {
|
||||
offset = BitIndexOf(index);
|
||||
bit1 = ((bits8) BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
|
||||
bit2 = (bits8) BitArrayBitIsSet((BitArray) tblock, offset);
|
||||
|
||||
xstatus = (bit1 | bit2) ;
|
||||
|
||||
/* ----------------
|
||||
* here we have the status of some transaction, so test
|
||||
* if the status is recorded as "in progress". If so, then
|
||||
* we save the transaction id in the place specified by the caller.
|
||||
* ----------------
|
||||
*/
|
||||
if (xstatus != XID_INPROGRESS) {
|
||||
if (returnXidP != NULL) {
|
||||
TransactionIdStore(baseXid, returnXidP);
|
||||
TransactionIdAdd(returnXidP, index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* if we get here and index is 0 it means we couldn't find
|
||||
* a non-inprogress transaction on the block. For now we just
|
||||
* return this info to the user. They can check if the return
|
||||
* status is "in progress" to know this condition has arisen.
|
||||
* ----------------
|
||||
*/
|
||||
if (index == 0) {
|
||||
if (returnXidP != NULL)
|
||||
TransactionIdStore(baseXid, returnXidP);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* return the status to the user
|
||||
* ----------------
|
||||
*/
|
||||
return xstatus;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransBlockGetXidStatus
|
||||
*
|
||||
* This returns the status of the desired transaction
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
XidStatus
|
||||
TransBlockGetXidStatus(Block tblock,
|
||||
TransactionId transactionId)
|
||||
{
|
||||
Index index;
|
||||
bits8 bit1;
|
||||
bits8 bit2;
|
||||
BitIndex offset;
|
||||
|
||||
/* ----------------
|
||||
* sanity check
|
||||
* ----------------
|
||||
*/
|
||||
if (tblock == NULL) {
|
||||
return XID_INVALID;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* calculate the index into the transaction data where
|
||||
* our transaction status is located
|
||||
*
|
||||
* XXX this will be replaced soon when we move to the
|
||||
* new transaction id scheme -cim 3/23/90
|
||||
*
|
||||
* The old system has now been replaced. -mer 5/24/92
|
||||
* ----------------
|
||||
*/
|
||||
index = transactionId % TP_NumXidStatusPerBlock;
|
||||
|
||||
/* ----------------
|
||||
* get the data at the specified index
|
||||
* ----------------
|
||||
*/
|
||||
offset = BitIndexOf(index);
|
||||
bit1 = ((bits8) BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
|
||||
bit2 = (bits8) BitArrayBitIsSet((BitArray) tblock, offset);
|
||||
|
||||
/* ----------------
|
||||
* return the transaction status to the caller
|
||||
* ----------------
|
||||
*/
|
||||
return (XidStatus)
|
||||
(bit1 | bit2);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransBlockSetXidStatus
|
||||
*
|
||||
* This sets the status of the desired transaction
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
TransBlockSetXidStatus(Block tblock,
|
||||
TransactionId transactionId,
|
||||
XidStatus xstatus)
|
||||
{
|
||||
Index index;
|
||||
BitIndex offset;
|
||||
|
||||
/* ----------------
|
||||
* sanity check
|
||||
* ----------------
|
||||
*/
|
||||
if (tblock == NULL)
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* calculate the index into the transaction data where
|
||||
* we sould store our transaction status.
|
||||
*
|
||||
* XXX this will be replaced soon when we move to the
|
||||
* new transaction id scheme -cim 3/23/90
|
||||
*
|
||||
* The new scheme is here -mer 5/24/92
|
||||
* ----------------
|
||||
*/
|
||||
index = transactionId % TP_NumXidStatusPerBlock;
|
||||
|
||||
offset = BitIndexOf(index);
|
||||
|
||||
/* ----------------
|
||||
* store the transaction value at the specified offset
|
||||
* ----------------
|
||||
*/
|
||||
switch(xstatus) {
|
||||
case XID_COMMIT: /* set 10 */
|
||||
BitArraySetBit((BitArray) tblock, offset);
|
||||
BitArrayClearBit((BitArray) tblock, offset + 1);
|
||||
break;
|
||||
case XID_ABORT: /* set 01 */
|
||||
BitArrayClearBit((BitArray) tblock, offset);
|
||||
BitArraySetBit((BitArray) tblock, offset + 1);
|
||||
break;
|
||||
case XID_INPROGRESS: /* set 00 */
|
||||
BitArrayClearBit((BitArray) tblock, offset);
|
||||
BitArrayClearBit((BitArray) tblock, offset + 1);
|
||||
break;
|
||||
default:
|
||||
elog(NOTICE,
|
||||
"TransBlockSetXidStatus: invalid status: %d (ignored)",
|
||||
xstatus);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransBlockGetCommitTime
|
||||
*
|
||||
* This returns the transaction commit time for the
|
||||
* specified transaction id in the trans block.
|
||||
* --------------------------------
|
||||
*/
|
||||
AbsoluteTime
|
||||
TransBlockGetCommitTime(Block tblock,
|
||||
TransactionId transactionId)
|
||||
{
|
||||
Index index;
|
||||
AbsoluteTime *timeArray;
|
||||
|
||||
/* ----------------
|
||||
* sanity check
|
||||
* ----------------
|
||||
*/
|
||||
if (tblock == NULL)
|
||||
return INVALID_ABSTIME;
|
||||
|
||||
/* ----------------
|
||||
* calculate the index into the transaction data where
|
||||
* our transaction commit time is located
|
||||
*
|
||||
* XXX this will be replaced soon when we move to the
|
||||
* new transaction id scheme -cim 3/23/90
|
||||
*
|
||||
* The new scheme is here. -mer 5/24/92
|
||||
* ----------------
|
||||
*/
|
||||
index = transactionId % TP_NumTimePerBlock;
|
||||
|
||||
/* ----------------
|
||||
* return the commit time to the caller
|
||||
* ----------------
|
||||
*/
|
||||
timeArray = (AbsoluteTime *) tblock;
|
||||
return (AbsoluteTime)
|
||||
timeArray[ index ];
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransBlockSetCommitTime
|
||||
*
|
||||
* This sets the commit time of the specified transaction
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
TransBlockSetCommitTime(Block tblock,
|
||||
TransactionId transactionId,
|
||||
AbsoluteTime commitTime)
|
||||
{
|
||||
Index index;
|
||||
AbsoluteTime *timeArray;
|
||||
|
||||
/* ----------------
|
||||
* sanity check
|
||||
* ----------------
|
||||
*/
|
||||
if (tblock == NULL)
|
||||
return;
|
||||
|
||||
|
||||
/* ----------------
|
||||
* calculate the index into the transaction data where
|
||||
* we sould store our transaction status.
|
||||
*
|
||||
* XXX this will be replaced soon when we move to the
|
||||
* new transaction id scheme -cim 3/23/90
|
||||
*
|
||||
* The new scheme is here. -mer 5/24/92
|
||||
* ----------------
|
||||
*/
|
||||
index = transactionId % TP_NumTimePerBlock;
|
||||
|
||||
/* ----------------
|
||||
* store the transaction commit time at the specified index
|
||||
* ----------------
|
||||
*/
|
||||
timeArray = (AbsoluteTime *) tblock;
|
||||
timeArray[ index ] = commitTime;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* transam i/o support routines
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* --------------------------------
|
||||
* TransBlockNumberGetXidStatus
|
||||
* --------------------------------
|
||||
*/
|
||||
XidStatus
|
||||
TransBlockNumberGetXidStatus(Relation relation,
|
||||
BlockNumber blockNumber,
|
||||
TransactionId xid,
|
||||
bool *failP)
|
||||
{
|
||||
Buffer buffer; /* buffer associated with block */
|
||||
Block block; /* block containing xstatus */
|
||||
XidStatus xstatus; /* recorded status of xid */
|
||||
bool localfail; /* bool used if failP = NULL */
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY place a read lock on the log relation
|
||||
* That someday is today 5 Aug 1991 -mer
|
||||
* ----------------
|
||||
*/
|
||||
RelationSetLockForRead(relation);
|
||||
|
||||
/* ----------------
|
||||
* get the page containing the transaction information
|
||||
* ----------------
|
||||
*/
|
||||
buffer = ReadBuffer(relation, blockNumber);
|
||||
block = BufferGetBlock(buffer);
|
||||
|
||||
/* ----------------
|
||||
* get the status from the block. note, for now we always
|
||||
* return false in failP.
|
||||
* ----------------
|
||||
*/
|
||||
if (failP == NULL)
|
||||
failP = &localfail;
|
||||
(*failP) = false;
|
||||
|
||||
xstatus = TransBlockGetXidStatus(block, xid);
|
||||
|
||||
/* ----------------
|
||||
* release the buffer and return the status
|
||||
* ----------------
|
||||
*/
|
||||
ReleaseBuffer(buffer);
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY release our lock on the log relation
|
||||
* ----------------
|
||||
*/
|
||||
RelationUnsetLockForRead(relation);
|
||||
|
||||
return
|
||||
xstatus;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransBlockNumberSetXidStatus
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
TransBlockNumberSetXidStatus(Relation relation,
|
||||
BlockNumber blockNumber,
|
||||
TransactionId xid,
|
||||
XidStatus xstatus,
|
||||
bool *failP)
|
||||
{
|
||||
Buffer buffer; /* buffer associated with block */
|
||||
Block block; /* block containing xstatus */
|
||||
bool localfail; /* bool used if failP = NULL */
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY gain exclusive access to the log relation
|
||||
*
|
||||
* That someday is today 5 Aug 1991 -mer
|
||||
* ----------------
|
||||
*/
|
||||
RelationSetLockForWrite(relation);
|
||||
|
||||
/* ----------------
|
||||
* get the block containing the transaction status
|
||||
* ----------------
|
||||
*/
|
||||
buffer = ReadBuffer(relation, blockNumber);
|
||||
block = BufferGetBlock(buffer);
|
||||
|
||||
/* ----------------
|
||||
* attempt to update the status of the transaction on the block.
|
||||
* if we are successful, write the block. otherwise release the buffer.
|
||||
* note, for now we always return false in failP.
|
||||
* ----------------
|
||||
*/
|
||||
if (failP == NULL)
|
||||
failP = &localfail;
|
||||
(*failP) = false;
|
||||
|
||||
TransBlockSetXidStatus(block, xid, xstatus);
|
||||
|
||||
if ((*failP) == false)
|
||||
WriteBuffer(buffer);
|
||||
else
|
||||
ReleaseBuffer(buffer);
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY release our lock on the log relation
|
||||
* ----------------
|
||||
*/
|
||||
RelationUnsetLockForWrite(relation);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransBlockNumberGetCommitTime
|
||||
* --------------------------------
|
||||
*/
|
||||
AbsoluteTime
|
||||
TransBlockNumberGetCommitTime(Relation relation,
|
||||
BlockNumber blockNumber,
|
||||
TransactionId xid,
|
||||
bool *failP)
|
||||
{
|
||||
Buffer buffer; /* buffer associated with block */
|
||||
Block block; /* block containing commit time */
|
||||
bool localfail; /* bool used if failP = NULL */
|
||||
AbsoluteTime xtime; /* commit time */
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY place a read lock on the time relation
|
||||
*
|
||||
* That someday is today 5 Aug. 1991 -mer
|
||||
* ----------------
|
||||
*/
|
||||
RelationSetLockForRead(relation);
|
||||
|
||||
/* ----------------
|
||||
* get the block containing the transaction information
|
||||
* ----------------
|
||||
*/
|
||||
buffer = ReadBuffer(relation, blockNumber);
|
||||
block = BufferGetBlock(buffer);
|
||||
|
||||
/* ----------------
|
||||
* get the commit time from the block
|
||||
* note, for now we always return false in failP.
|
||||
* ----------------
|
||||
*/
|
||||
if (failP == NULL)
|
||||
failP = &localfail;
|
||||
(*failP) = false;
|
||||
|
||||
xtime = TransBlockGetCommitTime(block, xid);
|
||||
|
||||
/* ----------------
|
||||
* release the buffer and return the commit time
|
||||
* ----------------
|
||||
*/
|
||||
ReleaseBuffer(buffer);
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY release our lock on the time relation
|
||||
* ----------------
|
||||
*/
|
||||
RelationUnsetLockForRead(relation);
|
||||
|
||||
if ((*failP) == false)
|
||||
return xtime;
|
||||
else
|
||||
return INVALID_ABSTIME;
|
||||
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransBlockNumberSetCommitTime
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
TransBlockNumberSetCommitTime(Relation relation,
|
||||
BlockNumber blockNumber,
|
||||
TransactionId xid,
|
||||
AbsoluteTime xtime,
|
||||
bool *failP)
|
||||
{
|
||||
Buffer buffer; /* buffer associated with block */
|
||||
Block block; /* block containing commit time */
|
||||
bool localfail; /* bool used if failP = NULL */
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY gain exclusive access to the time relation
|
||||
*
|
||||
* That someday is today 5 Aug. 1991 -mer
|
||||
* ----------------
|
||||
*/
|
||||
RelationSetLockForWrite(relation);
|
||||
|
||||
/* ----------------
|
||||
* get the block containing our commit time
|
||||
* ----------------
|
||||
*/
|
||||
buffer = ReadBuffer(relation, blockNumber);
|
||||
block = BufferGetBlock(buffer);
|
||||
|
||||
/* ----------------
|
||||
* attempt to update the commit time of the transaction on the block.
|
||||
* if we are successful, write the block. otherwise release the buffer.
|
||||
* note, for now we always return false in failP.
|
||||
* ----------------
|
||||
*/
|
||||
if (failP == NULL)
|
||||
failP = &localfail;
|
||||
(*failP) = false;
|
||||
|
||||
TransBlockSetCommitTime(block, xid, xtime);
|
||||
|
||||
if ((*failP) == false)
|
||||
WriteBuffer(buffer);
|
||||
else
|
||||
ReleaseBuffer(buffer);
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY release our lock on the time relation
|
||||
* ----------------
|
||||
*/
|
||||
RelationUnsetLockForWrite(relation);
|
||||
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* TransGetLastRecordedTransaction
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
TransGetLastRecordedTransaction(Relation relation,
|
||||
TransactionId xid, /* return: transaction id */
|
||||
bool *failP)
|
||||
{
|
||||
BlockNumber blockNumber; /* block number */
|
||||
Buffer buffer; /* buffer associated with block */
|
||||
Block block; /* block containing xid status */
|
||||
BlockNumber n; /* number of blocks in the relation */
|
||||
TransactionId baseXid;
|
||||
|
||||
(*failP) = false;
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY gain exclusive access to the log relation
|
||||
*
|
||||
* That someday is today 5 Aug. 1991 -mer
|
||||
* It looks to me like we only need to set a read lock here, despite
|
||||
* the above comment about exclusive access. The block is never
|
||||
* actually written into, we only check status bits.
|
||||
* ----------------
|
||||
*/
|
||||
RelationSetLockForRead(relation);
|
||||
|
||||
/* ----------------
|
||||
* we assume the last block of the log contains the last
|
||||
* recorded transaction. If the relation is empty we return
|
||||
* failure to the user.
|
||||
* ----------------
|
||||
*/
|
||||
n = RelationGetNumberOfBlocks(relation);
|
||||
if (n == 0) {
|
||||
(*failP) = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* get the block containing the transaction information
|
||||
* ----------------
|
||||
*/
|
||||
blockNumber = n-1;
|
||||
buffer = ReadBuffer(relation, blockNumber);
|
||||
block = BufferGetBlock(buffer);
|
||||
|
||||
/* ----------------
|
||||
* get the last xid on the block
|
||||
* ----------------
|
||||
*/
|
||||
baseXid = blockNumber * TP_NumXidStatusPerBlock;
|
||||
|
||||
/* XXX ???? xid won't get returned! - AY '94 */
|
||||
(void) TransBlockGetLastTransactionIdStatus(block, baseXid, &xid);
|
||||
|
||||
ReleaseBuffer(buffer);
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY release our lock on the log relation
|
||||
* ----------------
|
||||
*/
|
||||
RelationUnsetLockForRead(relation);
|
||||
}
|
606
src/backend/access/transam/varsup.c
Normal file
606
src/backend/access/transam/varsup.c
Normal file
@@ -0,0 +1,606 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* varsup.c--
|
||||
* postgres variable relation support routines
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.1.1.1 1996/07/09 06:21:13 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include <math.h>
|
||||
#include "postgres.h"
|
||||
|
||||
#include "machine.h" /* in port/ directory (needed for BLCKSZ) */
|
||||
#include "storage/buf.h"
|
||||
#include "storage/bufmgr.h"
|
||||
#include "storage/ipc.h" /* for OIDGENLOCKID */
|
||||
|
||||
#include "utils/rel.h"
|
||||
#include "utils/elog.h"
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "access/transam.h" /* where the declarations go */
|
||||
#include "access/xact.h" /* where the declarations go */
|
||||
|
||||
#include "catalog/catname.h"
|
||||
|
||||
/* ----------
|
||||
* note: we reserve the first 16384 object ids for internal use.
|
||||
* oid's less than this appear in the .bki files. the choice of
|
||||
* 16384 is completely arbitrary.
|
||||
* ----------
|
||||
*/
|
||||
#define BootstrapObjectIdData 16384
|
||||
|
||||
/* ---------------------
|
||||
* spin lock for oid generation
|
||||
* ---------------------
|
||||
*/
|
||||
int OidGenLockId;
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* variable relation query/update routines
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationGetNextXid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationGetNextXid(TransactionId *xidP)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire to guarantee
|
||||
* exclusive access to the variable relation.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* do nothing before things are initialized
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(VariableRelation))
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* read the variable page, get the the nextXid field and
|
||||
* release the buffer
|
||||
* ----------------
|
||||
*/
|
||||
buf = ReadBuffer(VariableRelation, 0);
|
||||
|
||||
if (! BufferIsValid(buf))
|
||||
{
|
||||
SpinRelease(OidGenLockId);
|
||||
elog(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
var = (VariableRelationContents) BufferGetBlock(buf);
|
||||
|
||||
TransactionIdStore(var->nextXidData, xidP);
|
||||
ReleaseBuffer(buf);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationGetLastXid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationGetLastXid(TransactionId *xidP)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire to guarantee
|
||||
* exclusive access to the variable relation.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* do nothing before things are initialized
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(VariableRelation))
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* read the variable page, get the the lastXid field and
|
||||
* release the buffer
|
||||
* ----------------
|
||||
*/
|
||||
buf = ReadBuffer(VariableRelation, 0);
|
||||
|
||||
if (! BufferIsValid(buf))
|
||||
{
|
||||
SpinRelease(OidGenLockId);
|
||||
elog(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
var = (VariableRelationContents) BufferGetBlock(buf);
|
||||
|
||||
TransactionIdStore(var->lastXidData, xidP);
|
||||
|
||||
ReleaseBuffer(buf);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationPutNextXid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationPutNextXid(TransactionId xid)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire to guarantee
|
||||
* exclusive access to the variable relation.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* do nothing before things are initialized
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(VariableRelation))
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* read the variable page, update the nextXid field and
|
||||
* write the page back out to disk.
|
||||
* ----------------
|
||||
*/
|
||||
buf = ReadBuffer(VariableRelation, 0);
|
||||
|
||||
if (! BufferIsValid(buf))
|
||||
{
|
||||
SpinRelease(OidGenLockId);
|
||||
elog(WARN, "VariableRelationPutNextXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
var = (VariableRelationContents) BufferGetBlock(buf);
|
||||
|
||||
TransactionIdStore(xid, &(var->nextXidData));
|
||||
|
||||
WriteBuffer(buf);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationPutLastXid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationPutLastXid(TransactionId xid)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire to guarantee
|
||||
* exclusive access to the variable relation.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* do nothing before things are initialized
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(VariableRelation))
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* read the variable page, update the lastXid field and
|
||||
* force the page back out to disk.
|
||||
* ----------------
|
||||
*/
|
||||
buf = ReadBuffer(VariableRelation, 0);
|
||||
|
||||
if (! BufferIsValid(buf))
|
||||
{
|
||||
SpinRelease(OidGenLockId);
|
||||
elog(WARN, "VariableRelationPutLastXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
var = (VariableRelationContents) BufferGetBlock(buf);
|
||||
|
||||
TransactionIdStore(xid, &(var->lastXidData));
|
||||
|
||||
WriteBuffer(buf);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationGetNextOid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationGetNextOid(Oid *oid_return)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire to guarantee
|
||||
* exclusive access to the variable relation.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* if the variable relation is not initialized, then we
|
||||
* assume we are running at bootstrap time and so we return
|
||||
* an invalid object id -- during this time GetNextBootstrapObjectId
|
||||
* should be called instead..
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(VariableRelation)) {
|
||||
if (PointerIsValid(oid_return))
|
||||
(*oid_return) = InvalidOid;
|
||||
return;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* read the variable page, get the the nextOid field and
|
||||
* release the buffer
|
||||
* ----------------
|
||||
*/
|
||||
buf = ReadBuffer(VariableRelation, 0);
|
||||
|
||||
if (! BufferIsValid(buf))
|
||||
{
|
||||
SpinRelease(OidGenLockId);
|
||||
elog(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
var = (VariableRelationContents) BufferGetBlock(buf);
|
||||
|
||||
if (PointerIsValid(oid_return)) {
|
||||
|
||||
/* ----------------
|
||||
* nothing up my sleeve... what's going on here is that this code
|
||||
* is guaranteed never to be called until all files in data/base/
|
||||
* are created, and the template database exists. at that point,
|
||||
* we want to append a pg_database tuple. the first time we do
|
||||
* this, the oid stored in pg_variable will be bogus, so we use
|
||||
* a bootstrap value defined at the top of this file.
|
||||
*
|
||||
* this comment no longer holds true. This code is called before
|
||||
* all of the files in data/base are created and you can't rely
|
||||
* on system oid's to be less than BootstrapObjectIdData. mer 9/18/91
|
||||
* ----------------
|
||||
*/
|
||||
if (OidIsValid(var->nextOid))
|
||||
(*oid_return) = var->nextOid;
|
||||
else
|
||||
(*oid_return) = BootstrapObjectIdData;
|
||||
}
|
||||
|
||||
ReleaseBuffer(buf);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationPutNextOid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationPutNextOid(Oid *oidP)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire to guarantee
|
||||
* exclusive access to the variable relation.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* do nothing before things are initialized
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(VariableRelation))
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* sanity check
|
||||
* ----------------
|
||||
*/
|
||||
if (! PointerIsValid(oidP))
|
||||
{
|
||||
SpinRelease(OidGenLockId);
|
||||
elog(WARN, "VariableRelationPutNextOid: invalid oid pointer");
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* read the variable page, update the nextXid field and
|
||||
* write the page back out to disk.
|
||||
* ----------------
|
||||
*/
|
||||
buf = ReadBuffer(VariableRelation, 0);
|
||||
|
||||
if (! BufferIsValid(buf))
|
||||
{
|
||||
SpinRelease(OidGenLockId);
|
||||
elog(WARN, "VariableRelationPutNextXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
var = (VariableRelationContents) BufferGetBlock(buf);
|
||||
|
||||
var->nextOid = (*oidP);
|
||||
|
||||
WriteBuffer(buf);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* transaction id generation support
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* GetNewTransactionId
|
||||
*
|
||||
* In the version 2 transaction system, transaction id's are
|
||||
* restricted in several ways.
|
||||
*
|
||||
* First, all transaction id's are even numbers (4, 88, 121342, etc).
|
||||
* This means the binary representation of the number will never
|
||||
* have the least significent bit set. This bit is reserved to
|
||||
* indicate that the transaction id does not in fact hold an XID,
|
||||
* but rather a commit time. This makes it possible for the
|
||||
* vaccuum daemon to disgard information from the log and time
|
||||
* relations for committed tuples. This is important when archiving
|
||||
* tuples to an optical disk because tuples with commit times
|
||||
* stored in their xid fields will not need to consult the log
|
||||
* and time relations.
|
||||
*
|
||||
* Second, since we may someday preform compression of the data
|
||||
* in the log and time relations, we cause the numbering of the
|
||||
* transaction ids to begin at 512. This means that some space
|
||||
* on the page of the log and time relations corresponding to
|
||||
* transaction id's 0 - 510 will never be used. This space is
|
||||
* in fact used to store the version number of the postgres
|
||||
* transaction log and will someday store compression information
|
||||
* about the log.
|
||||
*
|
||||
* Lastly, rather then access the variable relation each time
|
||||
* a backend requests a new transction id, we "prefetch" 32
|
||||
* transaction id's by incrementing the nextXid stored in the
|
||||
* var relation by 64 (remember only even xid's are legal) and then
|
||||
* returning these id's one at a time until they are exhausted.
|
||||
* This means we reduce the number of accesses to the variable
|
||||
* relation by 32 for each backend.
|
||||
*
|
||||
* Note: 32 has no special significance. We don't want the
|
||||
* number to be too large because if when the backend
|
||||
* terminates, we lose the xid's we cached.
|
||||
*
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
#define VAR_XID_PREFETCH 32
|
||||
|
||||
static int prefetched_xid_count = 0;
|
||||
static TransactionId next_prefetched_xid;
|
||||
|
||||
void
|
||||
GetNewTransactionId(TransactionId *xid)
|
||||
{
|
||||
TransactionId nextid;
|
||||
|
||||
/* ----------------
|
||||
* during bootstrap initialization, we return the special
|
||||
* bootstrap transaction id.
|
||||
* ----------------
|
||||
*/
|
||||
if (AMI_OVERRIDE) {
|
||||
TransactionIdStore(AmiTransactionId, xid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* if we run out of prefetched xids, then we get some
|
||||
* more before handing them out to the caller.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
if (prefetched_xid_count == 0) {
|
||||
/* ----------------
|
||||
* obtain exclusive access to the variable relation page
|
||||
*
|
||||
* get the "next" xid from the variable relation
|
||||
* and save it in the prefetched id.
|
||||
* ----------------
|
||||
*/
|
||||
SpinAcquire(OidGenLockId);
|
||||
VariableRelationGetNextXid(&nextid);
|
||||
TransactionIdStore(nextid, &next_prefetched_xid);
|
||||
|
||||
/* ----------------
|
||||
* now increment the variable relation's next xid
|
||||
* and reset the prefetched_xid_count. We multiply
|
||||
* the id by two because our xid's are always even.
|
||||
* ----------------
|
||||
*/
|
||||
prefetched_xid_count = VAR_XID_PREFETCH;
|
||||
TransactionIdAdd(&nextid, prefetched_xid_count);
|
||||
VariableRelationPutNextXid(nextid);
|
||||
SpinRelease(OidGenLockId);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* return the next prefetched xid in the pointer passed by
|
||||
* the user and decrement the prefetch count. We add two
|
||||
* to id we return the next time this is called because our
|
||||
* transaction ids are always even.
|
||||
*
|
||||
* XXX Transaction Ids used to be even as the low order bit was
|
||||
* used to determine commit status. This is no long true so
|
||||
* we now use even and odd transaction ids. -mer 5/26/92
|
||||
* ----------------
|
||||
*/
|
||||
TransactionIdStore(next_prefetched_xid, xid);
|
||||
TransactionIdAdd(&next_prefetched_xid, 1);
|
||||
prefetched_xid_count--;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* UpdateLastCommittedXid
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
void
|
||||
UpdateLastCommittedXid(TransactionId xid)
|
||||
{
|
||||
TransactionId lastid;
|
||||
|
||||
|
||||
/* we assume that spinlock OidGenLockId has been acquired
|
||||
* prior to entering this function
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* get the "last committed" transaction id from
|
||||
* the variable relation page.
|
||||
* ----------------
|
||||
*/
|
||||
VariableRelationGetLastXid(&lastid);
|
||||
|
||||
/* ----------------
|
||||
* if the transaction id is greater than the last committed
|
||||
* transaction then we update the last committed transaction
|
||||
* in the variable relation.
|
||||
* ----------------
|
||||
*/
|
||||
if (TransactionIdIsLessThan(lastid, xid))
|
||||
VariableRelationPutLastXid(xid);
|
||||
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* object id generation support
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* GetNewObjectIdBlock
|
||||
*
|
||||
* This support function is used to allocate a block of object ids
|
||||
* of the given size. applications wishing to do their own object
|
||||
* id assignments should use this
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
GetNewObjectIdBlock(Oid *oid_return, /* place to return the new object id */
|
||||
int oid_block_size) /* number of oids desired */
|
||||
{
|
||||
Oid nextoid;
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY obtain exclusive access to the variable relation page
|
||||
* That someday is today -mer 6 Aug 1992
|
||||
* ----------------
|
||||
*/
|
||||
SpinAcquire(OidGenLockId);
|
||||
|
||||
/* ----------------
|
||||
* get the "next" oid from the variable relation
|
||||
* and give it to the caller.
|
||||
* ----------------
|
||||
*/
|
||||
VariableRelationGetNextOid(&nextoid);
|
||||
if (PointerIsValid(oid_return))
|
||||
(*oid_return) = nextoid;
|
||||
|
||||
/* ----------------
|
||||
* now increment the variable relation's next oid
|
||||
* field by the size of the oid block requested.
|
||||
* ----------------
|
||||
*/
|
||||
nextoid += oid_block_size;
|
||||
VariableRelationPutNextOid(&nextoid);
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY relinquish our lock on the variable relation page
|
||||
* That someday is today -mer 6 Apr 1992
|
||||
* ----------------
|
||||
*/
|
||||
SpinRelease(OidGenLockId);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* GetNewObjectId
|
||||
*
|
||||
* This function allocates and parses out object ids. Like
|
||||
* GetNewTransactionId(), it "prefetches" 32 object ids by
|
||||
* incrementing the nextOid stored in the var relation by 32 and then
|
||||
* returning these id's one at a time until they are exhausted.
|
||||
* This means we reduce the number of accesses to the variable
|
||||
* relation by 32 for each backend.
|
||||
*
|
||||
* Note: 32 has no special significance. We don't want the
|
||||
* number to be too large because if when the backend
|
||||
* terminates, we lose the oids we cached.
|
||||
*
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
#define VAR_OID_PREFETCH 32
|
||||
|
||||
static int prefetched_oid_count = 0;
|
||||
static Oid next_prefetched_oid;
|
||||
|
||||
void
|
||||
GetNewObjectId(Oid *oid_return) /* place to return the new object id */
|
||||
{
|
||||
/* ----------------
|
||||
* if we run out of prefetched oids, then we get some
|
||||
* more before handing them out to the caller.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
if (prefetched_oid_count == 0) {
|
||||
int oid_block_size = VAR_OID_PREFETCH;
|
||||
|
||||
/* ----------------
|
||||
* during bootstrap time, we want to allocate oids
|
||||
* one at a time. Otherwise there might be some
|
||||
* bootstrap oid's left in the block we prefetch which
|
||||
* would be passed out after the variable relation was
|
||||
* initialized. This would be bad.
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(VariableRelation))
|
||||
VariableRelation = heap_openr(VariableRelationName);
|
||||
|
||||
/* ----------------
|
||||
* get a new block of prefetched object ids.
|
||||
* ----------------
|
||||
*/
|
||||
GetNewObjectIdBlock(&next_prefetched_oid, oid_block_size);
|
||||
|
||||
/* ----------------
|
||||
* now reset the prefetched_oid_count.
|
||||
* ----------------
|
||||
*/
|
||||
prefetched_oid_count = oid_block_size;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* return the next prefetched oid in the pointer passed by
|
||||
* the user and decrement the prefetch count.
|
||||
* ----------------
|
||||
*/
|
||||
if (PointerIsValid(oid_return))
|
||||
(*oid_return) = next_prefetched_oid;
|
||||
|
||||
next_prefetched_oid++;
|
||||
prefetched_oid_count--;
|
||||
}
|
1314
src/backend/access/transam/xact.c
Normal file
1314
src/backend/access/transam/xact.c
Normal file
File diff suppressed because it is too large
Load Diff
156
src/backend/access/transam/xid.c
Normal file
156
src/backend/access/transam/xid.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* xid.c--
|
||||
* POSTGRES transaction identifier code.
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/xid.c,v 1.1.1.1 1996/07/09 06:21:14 scrappy Exp $
|
||||
*
|
||||
* OLD COMMENTS
|
||||
* XXX WARNING
|
||||
* Much of this file will change when we change our representation
|
||||
* of transaction ids -cim 3/23/90
|
||||
*
|
||||
* It is time to make the switch from 5 byte to 4 byte transaction ids
|
||||
* This file was totally reworked. -mer 5/22/92
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "postgres.h"
|
||||
#include "utils/palloc.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/nabstime.h"
|
||||
|
||||
extern TransactionId NullTransactionId;
|
||||
extern TransactionId DisabledTransactionId;
|
||||
extern TransactionId AmiTransactionId;
|
||||
extern TransactionId FirstTransactionId;
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* TransactionIdIsValid
|
||||
*
|
||||
* Macro-ize me.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
TransactionIdIsValid(TransactionId transactionId)
|
||||
{
|
||||
return ((bool) (transactionId != NullTransactionId) );
|
||||
}
|
||||
|
||||
/* XXX char16 name for catalogs */
|
||||
TransactionId
|
||||
xidin(char *representation)
|
||||
{
|
||||
return (atol(representation));
|
||||
}
|
||||
|
||||
/* XXX char16 name for catalogs */
|
||||
char*
|
||||
xidout(TransactionId transactionId)
|
||||
{
|
||||
/* return(TransactionIdFormString(transactionId)); */
|
||||
char *representation;
|
||||
|
||||
/* maximum 32 bit unsigned integer representation takes 10 chars */
|
||||
representation = palloc(11);
|
||||
|
||||
(void)sprintf(representation, "%u", transactionId);
|
||||
|
||||
return (representation);
|
||||
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* StoreInvalidTransactionId
|
||||
*
|
||||
* Maybe do away with Pointer types in these routines.
|
||||
* Macro-ize this one.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
StoreInvalidTransactionId(TransactionId *destination)
|
||||
{
|
||||
*destination = NullTransactionId;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* TransactionIdStore
|
||||
*
|
||||
* Macro-ize this one.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
TransactionIdStore(TransactionId transactionId,
|
||||
TransactionId *destination)
|
||||
{
|
||||
*destination = transactionId;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* TransactionIdEquals
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
TransactionIdEquals(TransactionId id1, TransactionId id2)
|
||||
{
|
||||
return ((bool) (id1 == id2));
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* TransactionIdIsLessThan
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
TransactionIdIsLessThan(TransactionId id1, TransactionId id2)
|
||||
{
|
||||
return ((bool)(id1 < id2));
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* xideq
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* xideq - returns 1, iff xid1 == xid2
|
||||
* 0 else;
|
||||
*/
|
||||
bool
|
||||
xideq(TransactionId xid1, TransactionId xid2)
|
||||
{
|
||||
return( (bool) (xid1 == xid2) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* TransactionIdIncrement
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
TransactionIdIncrement(TransactionId *transactionId)
|
||||
{
|
||||
|
||||
(*transactionId)++;
|
||||
if (*transactionId == DisabledTransactionId)
|
||||
elog(FATAL, "TransactionIdIncrement: exhausted XID's");
|
||||
return;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* TransactionIdAdd
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
TransactionIdAdd(TransactionId *xid, int value)
|
||||
{
|
||||
*xid += value;
|
||||
return;
|
||||
}
|
||||
|
Reference in New Issue
Block a user