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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * multi.c
  4.  *   multi level lock table manager
  5.  *
  6.  *   Standard multi-level lock manager as per the Gray paper
  7.  *   (at least, that is what it is supposed to be).  We implement
  8.  *   three levels -- RELN, PAGE, TUPLE.  Tuple is actually TID
  9.  *   a physical record pointer.  It isn't an object id.
  10.  *
  11.  * Copyright (c) 1994, Regents of the University of California
  12.  *
  13.  *
  14.  * IDENTIFICATION
  15.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/storage/lmgr/multi.c,v 1.29 1999/05/25 16:11:22 momjian Exp $
  16.  *
  17.  * NOTES:
  18.  *  (1) The lock.c module assumes that the caller here is doing
  19.  *  two phase locking.
  20.  *
  21.  *-------------------------------------------------------------------------
  22.  */
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include "postgres.h"
  26. #include "storage/lmgr.h"
  27. #include "storage/multilev.h"
  28. #include "utils/rel.h"
  29. #include "miscadmin.h" /* MyDatabaseId */
  30. static bool MultiAcquire(LOCKMETHOD lockmethod, LOCKTAG *tag,
  31.  LOCKMODE lockmode, PG_LOCK_LEVEL level);
  32. static bool MultiRelease(LOCKMETHOD lockmethod, LOCKTAG *tag,
  33.  LOCKMODE lockmode, PG_LOCK_LEVEL level);
  34. /*
  35.  * INTENT indicates to higher level that a lower level lock has been
  36.  * set.  For example, a write lock on a tuple conflicts with a write
  37.  * lock on a relation. This conflict is detected as a WRITE_INTENT/
  38.  * WRITE conflict between the tuple's intent lock and the relation's
  39.  * write lock.
  40.  */
  41. static MASK MultiConflicts[] = {
  42. (int) NULL,
  43. /* All reads and writes at any level conflict with a write lock */
  44. (1 << WRITE_LOCK) | (1 << WRITE_INTENT) | (1 << READ_LOCK) | (1 << READ_INTENT),
  45. /* read locks conflict with write locks at curr and lower levels */
  46. (1 << WRITE_LOCK) | (1 << WRITE_INTENT),
  47. /* write intent locks */
  48. (1 << READ_LOCK) | (1 << WRITE_LOCK),
  49. /* read intent locks */
  50. (1 << WRITE_LOCK),
  51. /*
  52.  * extend locks for archive storage manager conflict only w/extend
  53.  * locks
  54.  */
  55. (1 << EXTEND_LOCK)
  56. };
  57. /*
  58.  * write locks have higher priority than read locks and extend locks.  May
  59.  * want to treat INTENT locks differently.
  60.  */
  61. static int MultiPrios[] = {
  62. (int) NULL,
  63. 2,
  64. 1,
  65. 2,
  66. 1,
  67. 1
  68. };
  69. /*
  70.  * Lock table identifier for this lock table.  The multi-level
  71.  * lock table is ONE lock table, not three.
  72.  */
  73. LOCKMETHOD MultiTableId = (LOCKMETHOD) NULL;
  74. LOCKMETHOD LongTermTableId = (LOCKMETHOD) NULL;
  75. #ifdef NOT_USED
  76. LOCKMETHOD ShortTermTableId = (LOCKMETHOD) NULL;
  77. #endif
  78. /*
  79.  * Create the lock table described by MultiConflicts and Multiprio.
  80.  */
  81. LOCKMETHOD
  82. InitMultiLevelLocks()
  83. {
  84. int lockmethod;
  85. lockmethod = LockMethodTableInit("MultiLevelLockTable",
  86.   MultiConflicts, MultiPrios, MAX_LOCKMODES - 1);
  87. MultiTableId = lockmethod;
  88. if (!(MultiTableId))
  89. elog(ERROR, "InitMultiLocks: couldnt initialize lock table");
  90. /* -----------------------
  91.  * No short term lock table for now.  -Jeff 15 July 1991
  92.  *
  93.  * ShortTermTableId = LockMethodTableRename(lockmethod);
  94.  * if (! (ShortTermTableId)) {
  95.  *  elog(ERROR,"InitMultiLocks: couldnt rename lock table");
  96.  * }
  97.  * -----------------------
  98.  */
  99. #ifdef USER_LOCKS
  100. /*
  101.  * Allocate another tableId for long-term locks
  102.  */
  103. LongTermTableId = LockMethodTableRename(MultiTableId);
  104. if (!(LongTermTableId))
  105. {
  106. elog(ERROR,
  107.  "InitMultiLevelLocks: couldn't rename long-term lock table");
  108. }
  109. #endif
  110. return MultiTableId;
  111. }
  112. /*
  113.  * MultiLockReln -- lock a relation
  114.  *
  115.  * Returns: TRUE if the lock can be set, FALSE otherwise.
  116.  */
  117. bool
  118. MultiLockReln(LockInfo lockinfo, LOCKMODE lockmode)
  119. {
  120. LOCKTAG tag;
  121. /*
  122.  * LOCKTAG has two bytes of padding, unfortunately.  The hash function
  123.  * will return miss if the padding bytes aren't zero'd.
  124.  */
  125. MemSet(&tag, 0, sizeof(tag));
  126. tag.relId = lockinfo->lockRelId.relId;
  127. tag.dbId = lockinfo->lockRelId.dbId;
  128. return MultiAcquire(MultiTableId, &tag, lockmode, RELN_LEVEL);
  129. }
  130. #ifdef NOT_USED
  131. /*
  132.  * MultiLockTuple -- Lock the TID associated with a tuple
  133.  *
  134.  * Returns: TRUE if lock is set, FALSE otherwise.
  135.  *
  136.  * Side Effects: causes intention level locks to be set
  137.  * at the page and relation level.
  138.  */
  139. bool
  140. MultiLockTuple(LockInfo lockinfo, ItemPointer tidPtr, LOCKMODE lockmode)
  141. {
  142. LOCKTAG tag;
  143. /*
  144.  * LOCKTAG has two bytes of padding, unfortunately.  The hash function
  145.  * will return miss if the padding bytes aren't zero'd.
  146.  */
  147. MemSet(&tag, 0, sizeof(tag));
  148. tag.relId = lockinfo->lockRelId.relId;
  149. tag.dbId = lockinfo->lockRelId.dbId;
  150. /* not locking any valid Tuple, just the page */
  151. tag.tupleId = *tidPtr;
  152. return MultiAcquire(MultiTableId, &tag, lockmode, TUPLE_LEVEL);
  153. }
  154. #endif
  155. /*
  156.  * same as above at page level
  157.  */
  158. bool
  159. MultiLockPage(LockInfo lockinfo, ItemPointer tidPtr, LOCKMODE lockmode)
  160. {
  161. LOCKTAG tag;
  162. /*
  163.  * LOCKTAG has two bytes of padding, unfortunately.  The hash function
  164.  * will return miss if the padding bytes aren't zero'd.
  165.  */
  166. MemSet(&tag, 0, sizeof(tag));
  167. /* ----------------------------
  168.  * Now we want to set the page offset to be invalid
  169.  * and lock the block. There is some confusion here as to what
  170.  * a page is.  In Postgres a page is an 8k block, however this
  171.  * block may be partitioned into many subpages which are sometimes
  172.  * also called pages.  The term is overloaded, so don't be fooled
  173.  * when we say lock the page we mean the 8k block. -Jeff 16 July 1991
  174.  * ----------------------------
  175.  */
  176. tag.relId = lockinfo->lockRelId.relId;
  177. tag.dbId = lockinfo->lockRelId.dbId;
  178. BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid));
  179. return MultiAcquire(MultiTableId, &tag, lockmode, PAGE_LEVEL);
  180. }
  181. /*
  182.  * MultiAcquire -- acquire multi level lock at requested level
  183.  *
  184.  * Returns: TRUE if lock is set, FALSE if not
  185.  * Side Effects:
  186.  */
  187. static bool
  188. MultiAcquire(LOCKMETHOD lockmethod,
  189.  LOCKTAG *tag,
  190.  LOCKMODE lockmode,
  191.  PG_LOCK_LEVEL level)
  192. {
  193. LOCKMODE locks[N_LEVELS];
  194. int i,
  195. status;
  196. LOCKTAG xxTag,
  197.    *tmpTag = &xxTag;
  198. int retStatus = TRUE;
  199. /*
  200.  * Three levels implemented.  If we set a low level (e.g. Tuple) lock,
  201.  * we must set INTENT locks on the higher levels.  The intent lock
  202.  * detects conflicts between the low level lock and an existing high
  203.  * level lock. For example, setting a write lock on a tuple in a
  204.  * relation is disallowed if there is an existing read lock on the
  205.  * entire relation.  The write lock would set a WRITE + INTENT lock on
  206.  * the relation and that lock would conflict with the read.
  207.  */
  208. switch (level)
  209. {
  210. case RELN_LEVEL:
  211. locks[0] = lockmode;
  212. locks[1] = NO_LOCK;
  213. locks[2] = NO_LOCK;
  214. break;
  215. case PAGE_LEVEL:
  216. locks[0] = lockmode + INTENT;
  217. locks[1] = lockmode;
  218. locks[2] = NO_LOCK;
  219. break;
  220. case TUPLE_LEVEL:
  221. locks[0] = lockmode + INTENT;
  222. locks[1] = lockmode + INTENT;
  223. locks[2] = lockmode;
  224. break;
  225. default:
  226. elog(ERROR, "MultiAcquire: bad lock level");
  227. return FALSE;
  228. }
  229. /*
  230.  * construct a new tag as we go. Always loop through all levels, but
  231.  * if we arent' seting a low level lock, locks[i] is set to NO_LOCK
  232.  * for the lower levels.  Always start from the highest level and go
  233.  * to the lowest level.
  234.  */
  235. MemSet(tmpTag, 0, sizeof(*tmpTag));
  236. tmpTag->relId = tag->relId;
  237. tmpTag->dbId = tag->dbId;
  238. for (i = 0; i < N_LEVELS; i++)
  239. {
  240. if (locks[i] != NO_LOCK)
  241. {
  242. switch (i)
  243. {
  244. case RELN_LEVEL:
  245. /* -------------
  246.  * Set the block # and offset to invalid
  247.  * -------------
  248.  */
  249. BlockIdSet(&(tmpTag->tupleId.ip_blkid), InvalidBlockNumber);
  250. tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
  251. break;
  252. case PAGE_LEVEL:
  253. /* -------------
  254.  * Copy the block #, set the offset to invalid
  255.  * -------------
  256.  */
  257. BlockIdCopy(&(tmpTag->tupleId.ip_blkid),
  258. &(tag->tupleId.ip_blkid));
  259. tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
  260. break;
  261. case TUPLE_LEVEL:
  262. /* --------------
  263.  * Copy the entire tuple id.
  264.  * --------------
  265.  */
  266. ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId);
  267. break;
  268. }
  269. status = LockAcquire(lockmethod, tmpTag, locks[i]);
  270. if (!status)
  271. {
  272. /*
  273.  * failed for some reason. Before returning we have to
  274.  * release all of the locks we just acquired.
  275.  * MultiRelease(xx,xx,xx, i) means release starting from
  276.  * the last level lock we successfully acquired
  277.  */
  278. retStatus = FALSE;
  279. MultiRelease(lockmethod, tag, lockmode, i);
  280. /* now leave the loop. Don't try for any more locks */
  281. break;
  282. }
  283. }
  284. }
  285. return retStatus;
  286. }
  287. /* ------------------
  288.  * Release a page in the multi-level lock table
  289.  * ------------------
  290.  */
  291. #ifdef NOT_USED
  292. bool
  293. MultiReleasePage(LockInfo lockinfo, ItemPointer tidPtr, LOCKMODE lockmode)
  294. {
  295. LOCKTAG tag;
  296. /* ------------------
  297.  * LOCKTAG has two bytes of padding, unfortunately.  The
  298.  * hash function will return miss if the padding bytes aren't
  299.  * zero'd.
  300.  * ------------------
  301.  */
  302. MemSet(&tag, 0, sizeof(LOCKTAG));
  303. tag.relId = lockinfo->lockRelId.relId;
  304. tag.dbId = lockinfo->lockRelId.dbId;
  305. BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid));
  306. return MultiRelease(MultiTableId, &tag, lockmode, PAGE_LEVEL);
  307. }
  308. #endif
  309. /* ------------------
  310.  * Release a relation in the multi-level lock table
  311.  * ------------------
  312.  */
  313. bool
  314. MultiReleaseReln(LockInfo lockinfo, LOCKMODE lockmode)
  315. {
  316. LOCKTAG tag;
  317. /* ------------------
  318.  * LOCKTAG has two bytes of padding, unfortunately.  The
  319.  * hash function will return miss if the padding bytes aren't
  320.  * zero'd.
  321.  * ------------------
  322.  */
  323. MemSet(&tag, 0, sizeof(LOCKTAG));
  324. tag.relId = lockinfo->lockRelId.relId;
  325. tag.dbId = lockinfo->lockRelId.dbId;
  326. return MultiRelease(MultiTableId, &tag, lockmode, RELN_LEVEL);
  327. }
  328. /*
  329.  * MultiRelease -- release a multi-level lock
  330.  *
  331.  * Returns: TRUE if successful, FALSE otherwise.
  332.  */
  333. static bool
  334. MultiRelease(LOCKMETHOD lockmethod,
  335.  LOCKTAG *tag,
  336.  LOCKMODE lockmode,
  337.  PG_LOCK_LEVEL level)
  338. {
  339. LOCKMODE locks[N_LEVELS];
  340. int i,
  341. status;
  342. LOCKTAG xxTag,
  343.    *tmpTag = &xxTag;
  344. /*
  345.  * same level scheme as MultiAcquire().
  346.  */
  347. switch (level)
  348. {
  349. case RELN_LEVEL:
  350. locks[0] = lockmode;
  351. locks[1] = NO_LOCK;
  352. locks[2] = NO_LOCK;
  353. break;
  354. case PAGE_LEVEL:
  355. locks[0] = lockmode + INTENT;
  356. locks[1] = lockmode;
  357. locks[2] = NO_LOCK;
  358. break;
  359. case TUPLE_LEVEL:
  360. locks[0] = lockmode + INTENT;
  361. locks[1] = lockmode + INTENT;
  362. locks[2] = lockmode;
  363. break;
  364. default:
  365. elog(ERROR, "MultiRelease: bad lockmode");
  366. }
  367. /*
  368.  * again, construct the tag on the fly.  This time, however, we
  369.  * release the locks in the REVERSE order -- from lowest level to
  370.  * highest level.
  371.  *
  372.  * Must zero out the tag to set padding byes to zero and ensure hashing
  373.  * consistency.
  374.  */
  375. MemSet(tmpTag, 0, sizeof(*tmpTag));
  376. tmpTag->relId = tag->relId;
  377. tmpTag->dbId = tag->dbId;
  378. for (i = (N_LEVELS - 1); i >= 0; i--)
  379. {
  380. if (locks[i] != NO_LOCK)
  381. {
  382. switch (i)
  383. {
  384. case RELN_LEVEL:
  385. /* -------------
  386.  * Set the block # and offset to invalid
  387.  * -------------
  388.  */
  389. BlockIdSet(&(tmpTag->tupleId.ip_blkid), InvalidBlockNumber);
  390. tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
  391. break;
  392. case PAGE_LEVEL:
  393. /* -------------
  394.  * Copy the block #, set the offset to invalid
  395.  * -------------
  396.  */
  397. BlockIdCopy(&(tmpTag->tupleId.ip_blkid),
  398. &(tag->tupleId.ip_blkid));
  399. tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
  400. break;
  401. case TUPLE_LEVEL:
  402. ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId);
  403. break;
  404. }
  405. status = LockRelease(lockmethod, tmpTag, locks[i]);
  406. if (!status)
  407. elog(ERROR, "MultiRelease: couldn't release after error");
  408. }
  409. }
  410. /* shouldn't reach here */
  411. return false;
  412. }