1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-11 04:22:52 +03:00
Files
postgres/src/backend/access/transam/transsup.c
Marc G. Fournier 9a8aeb23a1 Another 'mega-commit' of back-patches ...
- integrating the #include file cleanup that Bruce recently did
- got the CPU change to adt/Makefile
- changing DOUBLEALIGN -> MAXALIGN
1999-08-02 05:25:27 +00:00

430 lines
11 KiB
C

/*-------------------------------------------------------------------------
*
* 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.21.2.1 1999/08/02 05:24:46 scrappy Exp $
*
* NOTES
* This file contains support functions for the high
* level access method interface routines found in transam.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/xact.h"
#include "utils/bit.h"
static XidStatus TransBlockGetXidStatus(Block tblock,
TransactionId transactionId);
static void TransBlockSetXidStatus(Block tblock,
TransactionId transactionId, XidStatus xstatus);
/* ----------------------------------------------------------------
* 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 = 0;
/* ----------------
* 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
elog(ERROR, "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.
* --------------------------------
*/
#ifdef NOT_USED
static 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; index > 0; index--)
{
offset = BitIndexOf(index - 1);
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 - 1);
}
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;
}
#endif
/* --------------------------------
* TransBlockGetXidStatus
*
* This returns the status of the desired transaction
* --------------------------------
*/
static XidStatus
TransBlockGetXidStatus(Block tblock,
TransactionId transactionId)
{
Index index;
bits8 bit1;
bits8 bit2;
BitIndex offset;
/* ----------------
* 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
* --------------------------------
*/
static void
TransBlockSetXidStatus(Block tblock,
TransactionId transactionId,
XidStatus xstatus)
{
Index index;
BitIndex offset;
/* ----------------
* 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;
}
}
/* ----------------------------------------------------------------
* 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 */
/* ----------------
* get the page containing the transaction information
* ----------------
*/
buffer = ReadBuffer(relation, blockNumber);
LockBuffer(buffer, BUFFER_LOCK_SHARE);
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
* ----------------
*/
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
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 */
/* ----------------
* get the block containing the transaction status
* ----------------
*/
buffer = ReadBuffer(relation, blockNumber);
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
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);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
if ((*failP) == false)
WriteBuffer(buffer);
else
ReleaseBuffer(buffer);
}
/* --------------------------------
* TransGetLastRecordedTransaction
* --------------------------------
*/
#ifdef NOT_USED
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 */
TransBlockGetLastTransactionIdStatus(block, baseXid, &xid);
ReleaseBuffer(buffer);
/* ----------------
* SOMEDAY release our lock on the log relation
* ----------------
*/
RelationUnsetLockForRead(relation);
}
#endif