transsup.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:11k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * transsup.c
  4.  *   postgres transaction access method support code
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/access/transam/transsup.c,v 1.21.2.2 1999/08/02 05:56:46 scrappy Exp $
  11.  *
  12.  * NOTES
  13.  *   This file contains support functions for the high
  14.  *   level access method interface routines found in transam.c
  15.  *
  16.  *-------------------------------------------------------------------------
  17.  */
  18. #include "postgres.h"
  19. #include "access/xact.h"
  20. #include "utils/bit.h"
  21. static XidStatus TransBlockGetXidStatus(Block tblock,
  22.    TransactionId transactionId);
  23. static void TransBlockSetXidStatus(Block tblock,
  24.    TransactionId transactionId, XidStatus xstatus);
  25. /* ----------------------------------------------------------------
  26.  *   general support routines
  27.  * ----------------------------------------------------------------
  28.  */
  29. /* --------------------------------
  30.  * AmiTransactionOverride
  31.  *
  32.  * This function is used to manipulate the bootstrap flag.
  33.  * --------------------------------
  34.  */
  35. void
  36. AmiTransactionOverride(bool flag)
  37. {
  38. AMI_OVERRIDE = flag;
  39. }
  40. /* --------------------------------
  41.  * TransComputeBlockNumber
  42.  * --------------------------------
  43.  */
  44. void
  45. TransComputeBlockNumber(Relation relation, /* relation to test */
  46. TransactionId transactionId, /* transaction id to
  47.  * test */
  48. BlockNumber *blockNumberOutP)
  49. {
  50. long itemsPerBlock = 0;
  51. /* ----------------
  52.  * we calculate the block number of our transaction
  53.  * by dividing the transaction id by the number of
  54.  * transaction things per block.
  55.  * ----------------
  56.  */
  57. if (relation == LogRelation)
  58. itemsPerBlock = TP_NumXidStatusPerBlock;
  59. else
  60. elog(ERROR, "TransComputeBlockNumber: unknown relation");
  61. /* ----------------
  62.  * warning! if the transaction id's get too large
  63.  * then a BlockNumber may not be large enough to hold the results
  64.  * of our division.
  65.  *
  66.  * XXX  this will all vanish soon when we implement an improved
  67.  *  transaction id schema -cim 3/23/90
  68.  *
  69.  * This has vanished now that xid's are 4 bytes (no longer 5).
  70.  * -mer 5/24/92
  71.  * ----------------
  72.  */
  73. (*blockNumberOutP) = transactionId / itemsPerBlock;
  74. }
  75. /* ----------------------------------------------------------------
  76.  *  trans block support routines
  77.  * ----------------------------------------------------------------
  78.  */
  79. /* --------------------------------
  80.  * TransBlockGetLastTransactionIdStatus
  81.  *
  82.  * This returns the status and transaction id of the last
  83.  * transaction information recorded on the given TransBlock.
  84.  * --------------------------------
  85.  */
  86. #ifdef NOT_USED
  87. static XidStatus
  88. TransBlockGetLastTransactionIdStatus(Block tblock,
  89.  TransactionId baseXid,
  90.  TransactionId *returnXidP)
  91. {
  92. Index index;
  93. Index maxIndex;
  94. bits8 bit1;
  95. bits8 bit2;
  96. BitIndex offset;
  97. XidStatus xstatus;
  98. /* ----------------
  99.  * sanity check
  100.  * ----------------
  101.  */
  102. Assert((tblock != NULL));
  103. /* ----------------
  104.  * search downward from the top of the block data, looking
  105.  * for the first Non-in progress transaction status.  Since we
  106.  * are scanning backward, this will be last recorded transaction
  107.  * status on the block.
  108.  * ----------------
  109.  */
  110. maxIndex = TP_NumXidStatusPerBlock;
  111. for (index = maxIndex; index > 0; index--)
  112. {
  113. offset = BitIndexOf(index - 1);
  114. bit1 = ((bits8) BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
  115. bit2 = (bits8) BitArrayBitIsSet((BitArray) tblock, offset);
  116. xstatus = (bit1 | bit2);
  117. /* ----------------
  118.  * here we have the status of some transaction, so test
  119.  * if the status is recorded as "in progress".  If so, then
  120.  * we save the transaction id in the place specified by the caller.
  121.  * ----------------
  122.  */
  123. if (xstatus != XID_INPROGRESS)
  124. {
  125. if (returnXidP != NULL)
  126. {
  127. TransactionIdStore(baseXid, returnXidP);
  128. TransactionIdAdd(returnXidP, index - 1);
  129. }
  130. break;
  131. }
  132. }
  133. /* ----------------
  134.  * if we get here and index is 0 it means we couldn't find
  135.  * a non-inprogress transaction on the block. For now we just
  136.  * return this info to the user.  They can check if the return
  137.  * status is "in progress" to know this condition has arisen.
  138.  * ----------------
  139.  */
  140. if (index == 0)
  141. {
  142. if (returnXidP != NULL)
  143. TransactionIdStore(baseXid, returnXidP);
  144. }
  145. /* ----------------
  146.  * return the status to the user
  147.  * ----------------
  148.  */
  149. return xstatus;
  150. }
  151. #endif
  152. /* --------------------------------
  153.  * TransBlockGetXidStatus
  154.  *
  155.  * This returns the status of the desired transaction
  156.  * --------------------------------
  157.  */
  158. static XidStatus
  159. TransBlockGetXidStatus(Block tblock,
  160.    TransactionId transactionId)
  161. {
  162. Index index;
  163. bits8 bit1;
  164. bits8 bit2;
  165. BitIndex offset;
  166. /* ----------------
  167.  * calculate the index into the transaction data where
  168.  * our transaction status is located
  169.  *
  170.  * XXX this will be replaced soon when we move to the
  171.  * new transaction id scheme -cim 3/23/90
  172.  *
  173.  * The old system has now been replaced. -mer 5/24/92
  174.  * ----------------
  175.  */
  176. index = transactionId % TP_NumXidStatusPerBlock;
  177. /* ----------------
  178.  * get the data at the specified index
  179.  * ----------------
  180.  */
  181. offset = BitIndexOf(index);
  182. bit1 = ((bits8) BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
  183. bit2 = (bits8) BitArrayBitIsSet((BitArray) tblock, offset);
  184. /* ----------------
  185.  * return the transaction status to the caller
  186.  * ----------------
  187.  */
  188. return (XidStatus) (bit1 | bit2);
  189. }
  190. /* --------------------------------
  191.  * TransBlockSetXidStatus
  192.  *
  193.  * This sets the status of the desired transaction
  194.  * --------------------------------
  195.  */
  196. static void
  197. TransBlockSetXidStatus(Block tblock,
  198.    TransactionId transactionId,
  199.    XidStatus xstatus)
  200. {
  201. Index index;
  202. BitIndex offset;
  203. /* ----------------
  204.  * calculate the index into the transaction data where
  205.  * we sould store our transaction status.
  206.  *
  207.  * XXX this will be replaced soon when we move to the
  208.  * new transaction id scheme -cim 3/23/90
  209.  *
  210.  * The new scheme is here -mer 5/24/92
  211.  * ----------------
  212.  */
  213. index = transactionId % TP_NumXidStatusPerBlock;
  214. offset = BitIndexOf(index);
  215. /* ----------------
  216.  * store the transaction value at the specified offset
  217.  * ----------------
  218.  */
  219. switch (xstatus)
  220. {
  221. case XID_COMMIT: /* set 10 */
  222. BitArraySetBit((BitArray) tblock, offset);
  223. BitArrayClearBit((BitArray) tblock, offset + 1);
  224. break;
  225. case XID_ABORT: /* set 01 */
  226. BitArrayClearBit((BitArray) tblock, offset);
  227. BitArraySetBit((BitArray) tblock, offset + 1);
  228. break;
  229. case XID_INPROGRESS: /* set 00 */
  230. BitArrayClearBit((BitArray) tblock, offset);
  231. BitArrayClearBit((BitArray) tblock, offset + 1);
  232. break;
  233. default:
  234. elog(NOTICE,
  235.  "TransBlockSetXidStatus: invalid status: %d (ignored)",
  236.  xstatus);
  237. break;
  238. }
  239. }
  240. /* ----------------------------------------------------------------
  241.  *    transam i/o support routines
  242.  * ----------------------------------------------------------------
  243.  */
  244. /* --------------------------------
  245.  * TransBlockNumberGetXidStatus
  246.  * --------------------------------
  247.  */
  248. XidStatus
  249. TransBlockNumberGetXidStatus(Relation relation,
  250.  BlockNumber blockNumber,
  251.  TransactionId xid,
  252.  bool *failP)
  253. {
  254. Buffer buffer; /* buffer associated with block */
  255. Block block; /* block containing xstatus */
  256. XidStatus xstatus; /* recorded status of xid */
  257. bool localfail; /* bool used if failP = NULL */
  258. /* ----------------
  259.  * get the page containing the transaction information
  260.  * ----------------
  261.  */
  262. buffer = ReadBuffer(relation, blockNumber);
  263. LockBuffer(buffer, BUFFER_LOCK_SHARE);
  264. block = BufferGetBlock(buffer);
  265. /* ----------------
  266.  * get the status from the block. note, for now we always
  267.  * return false in failP.
  268.  * ----------------
  269.  */
  270. if (failP == NULL)
  271. failP = &localfail;
  272. (*failP) = false;
  273. xstatus = TransBlockGetXidStatus(block, xid);
  274. /* ----------------
  275.  * release the buffer and return the status
  276.  * ----------------
  277.  */
  278. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  279. ReleaseBuffer(buffer);
  280. return xstatus;
  281. }
  282. /* --------------------------------
  283.  * TransBlockNumberSetXidStatus
  284.  * --------------------------------
  285.  */
  286. void
  287. TransBlockNumberSetXidStatus(Relation relation,
  288.  BlockNumber blockNumber,
  289.  TransactionId xid,
  290.  XidStatus xstatus,
  291.  bool *failP)
  292. {
  293. Buffer buffer; /* buffer associated with block */
  294. Block block; /* block containing xstatus */
  295. bool localfail; /* bool used if failP = NULL */
  296. /* ----------------
  297.  * get the block containing the transaction status
  298.  * ----------------
  299.  */
  300. buffer = ReadBuffer(relation, blockNumber);
  301. LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  302. block = BufferGetBlock(buffer);
  303. /* ----------------
  304.  * attempt to update the status of the transaction on the block.
  305.  * if we are successful, write the block. otherwise release the buffer.
  306.  * note, for now we always return false in failP.
  307.  * ----------------
  308.  */
  309. if (failP == NULL)
  310. failP = &localfail;
  311. (*failP) = false;
  312. TransBlockSetXidStatus(block, xid, xstatus);
  313. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  314. if ((*failP) == false)
  315. WriteBuffer(buffer);
  316. else
  317. ReleaseBuffer(buffer);
  318. }
  319. /* --------------------------------
  320.  * TransGetLastRecordedTransaction
  321.  * --------------------------------
  322.  */
  323. #ifdef NOT_USED
  324. void
  325. TransGetLastRecordedTransaction(Relation relation,
  326. TransactionId xid, /* return: transaction
  327.  * id */
  328. bool *failP)
  329. {
  330. BlockNumber blockNumber; /* block number */
  331. Buffer buffer; /* buffer associated with block */
  332. Block block; /* block containing xid status */
  333. BlockNumber n; /* number of blocks in the relation */
  334. TransactionId baseXid;
  335. (*failP) = false;
  336. /* ----------------
  337.  * SOMEDAY gain exclusive access to the log relation
  338.  *
  339.  * That someday is today 5 Aug. 1991 -mer
  340.  * It looks to me like we only need to set a read lock here, despite
  341.  * the above comment about exclusive access.  The block is never
  342.  * actually written into, we only check status bits.
  343.  * ----------------
  344.  */
  345. RelationSetLockForRead(relation);
  346. /* ----------------
  347.  * we assume the last block of the log contains the last
  348.  * recorded transaction.  If the relation is empty we return
  349.  * failure to the user.
  350.  * ----------------
  351.  */
  352. n = RelationGetNumberOfBlocks(relation);
  353. if (n == 0)
  354. {
  355. (*failP) = true;
  356. return;
  357. }
  358. /* ----------------
  359.  * get the block containing the transaction information
  360.  * ----------------
  361.  */
  362. blockNumber = n - 1;
  363. buffer = ReadBuffer(relation, blockNumber);
  364. block = BufferGetBlock(buffer);
  365. /* ----------------
  366.  * get the last xid on the block
  367.  * ----------------
  368.  */
  369. baseXid = blockNumber * TP_NumXidStatusPerBlock;
  370. /* XXX ???? xid won't get returned! - AY '94 */
  371. TransBlockGetLastTransactionIdStatus(block, baseXid, &xid);
  372. ReleaseBuffer(buffer);
  373. /* ----------------
  374.  * SOMEDAY release our lock on the log relation
  375.  * ----------------
  376.  */
  377. RelationUnsetLockForRead(relation);
  378. }
  379. #endif