📄 transam.c
字号:
/*------------------------------------------------------------------------- * * transam.c * postgres transaction log/time interface routines * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.27.2.2 1999/08/08 20:24:12 tgl Exp $ * * NOTES * This file contains the high level access-method interface to the * transaction system. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/catname.h"static int RecoveryCheckingEnabled(void);static void TransRecover(Relation logRelation);static bool TransactionLogTest(TransactionId transactionId, XidStatus status);static void TransactionLogUpdate(TransactionId transactionId, XidStatus status);/* ---------------- * global variables holding pointers to relations used * by the transaction system. These are initialized by * InitializeTransactionLog(). * ---------------- */Relation LogRelation = (Relation) NULL;Relation VariableRelation = (Relation) NULL;/* ---------------- * global variables holding cached transaction id's and statuses. * ---------------- */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;/* ---------------- * recovery checking accessors * ---------------- */static intRecoveryCheckingEnabled(void){ return RecoveryCheckingEnableState;}#ifdef NOT_USEDstatic voidSetRecoveryCheckingEnabled(bool state){ RecoveryCheckingEnableState = (state == true);}#endif/* ---------------------------------------------------------------- * postgres log 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 * -------------------------------- */static 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) { /* * DO NOT cache status for transactions in unknown state !!! */ if (xidstatus == XID_COMMIT || xidstatus == XID_ABORT) { TransactionIdStore(transactionId, &cachedTestXid); cachedTestXidStatus = xidstatus; } return (bool) (status == xidstatus); } /* ---------------- * here the block didn't contain the information we wanted * ---------------- */ elog(ERROR, "TransactionLogTest: failed to get xidstatus"); /* * so lint is happy... */ return false;}/* -------------------------------- * TransactionLogUpdate * -------------------------------- */static voidTransactionLogUpdate(TransactionId transactionId, /* trans id to update */ XidStatus status) /* new trans status */{ BlockNumber blockNumber; bool fail = false; /* success/failure */ /* ---------------- * during initialization we don't record any updates. * ---------------- */ if (!RelationIsValid(LogRelation)) return; /* ---------------- * update the log relation * ---------------- */ TransComputeBlockNumber(LogRelation, transactionId, &blockNumber); TransBlockNumberSetXidStatus(LogRelation, blockNumber, transactionId, status, &fail); /* * update (invalidate) our single item TransactionLogTest cache. * * if (status != XID_COMMIT) * * What's the hell ?! Why != XID_COMMIT ?! */ TransactionIdStore(transactionId, &cachedTestXid); cachedTestXidStatus = status;}/* ---------------------------------------------------------------- * 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".
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -