diff options
Diffstat (limited to 'src/backend/storage/lmgr/multi.c')
-rw-r--r-- | src/backend/storage/lmgr/multi.c | 615 |
1 files changed, 319 insertions, 296 deletions
diff --git a/src/backend/storage/lmgr/multi.c b/src/backend/storage/lmgr/multi.c index 9cd3a36b48c..d5466fce04c 100644 --- a/src/backend/storage/lmgr/multi.c +++ b/src/backend/storage/lmgr/multi.c @@ -1,22 +1,22 @@ /*------------------------------------------------------------------------- * * multi.c-- - * multi level lock table manager + * multi level lock table manager * - * Standard multi-level lock manager as per the Gray paper - * (at least, that is what it is supposed to be). We implement - * three levels -- RELN, PAGE, TUPLE. Tuple is actually TID - * a physical record pointer. It isn't an object id. + * Standard multi-level lock manager as per the Gray paper + * (at least, that is what it is supposed to be). We implement + * three levels -- RELN, PAGE, TUPLE. Tuple is actually TID + * a physical record pointer. It isn't an object id. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Attic/multi.c,v 1.4 1997/08/19 21:33:25 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Attic/multi.c,v 1.5 1997/09/07 04:49:02 momjian Exp $ * * NOTES: - * (1) The lock.c module assumes that the caller here is doing - * two phase locking. + * (1) The lock.c module assumes that the caller here is doing + * two phase locking. * *------------------------------------------------------------------------- */ @@ -27,53 +27,59 @@ #include "storage/multilev.h" #include "utils/rel.h" -#include "miscadmin.h" /* MyDatabaseId */ +#include "miscadmin.h" /* MyDatabaseId */ -static bool MultiAcquire(LockTableId tableId, LOCKTAG *tag, LOCKT lockt, +static bool +MultiAcquire(LockTableId tableId, LOCKTAG * tag, LOCKT lockt, LOCK_LEVEL level); -static bool MultiRelease(LockTableId tableId, LOCKTAG *tag, LOCKT lockt, +static bool +MultiRelease(LockTableId tableId, LOCKTAG * tag, LOCKT lockt, LOCK_LEVEL level); /* * INTENT indicates to higher level that a lower level lock has been - * set. For example, a write lock on a tuple conflicts with a write - * lock on a relation. This conflict is detected as a WRITE_INTENT/ + * set. For example, a write lock on a tuple conflicts with a write + * lock on a relation. This conflict is detected as a WRITE_INTENT/ * WRITE conflict between the tuple's intent lock and the relation's * write lock. */ -static int MultiConflicts[] = { - (int)NULL, - /* All reads and writes at any level conflict with a write lock */ - (1 << WRITE_LOCK)|(1 << WRITE_INTENT)|(1 << READ_LOCK)|(1 << READ_INTENT), - /* read locks conflict with write locks at curr and lower levels */ - (1 << WRITE_LOCK)| (1 << WRITE_INTENT), - /* write intent locks */ - (1 << READ_LOCK) | (1 << WRITE_LOCK), - /* read intent locks*/ - (1 << WRITE_LOCK), - /* extend locks for archive storage manager conflict only w/extend locks */ - (1 << EXTEND_LOCK) +static int MultiConflicts[] = { + (int) NULL, + /* All reads and writes at any level conflict with a write lock */ + (1 << WRITE_LOCK) | (1 << WRITE_INTENT) | (1 << READ_LOCK) | (1 << READ_INTENT), + /* read locks conflict with write locks at curr and lower levels */ + (1 << WRITE_LOCK) | (1 << WRITE_INTENT), + /* write intent locks */ + (1 << READ_LOCK) | (1 << WRITE_LOCK), + /* read intent locks */ + (1 << WRITE_LOCK), + + /* + * extend locks for archive storage manager conflict only w/extend + * locks + */ + (1 << EXTEND_LOCK) }; /* * write locks have higher priority than read locks and extend locks. May * want to treat INTENT locks differently. */ -static int MultiPrios[] = { - (int)NULL, - 2, - 1, - 2, - 1, - 1 +static int MultiPrios[] = { + (int) NULL, + 2, + 1, + 2, + 1, + 1 }; -/* +/* * Lock table identifier for this lock table. The multi-level * lock table is ONE lock table, not three. */ -LockTableId MultiTableId = (LockTableId)NULL; -LockTableId ShortTermTableId = (LockTableId)NULL; +LockTableId MultiTableId = (LockTableId) NULL; +LockTableId ShortTermTableId = (LockTableId) NULL; /* * Create the lock table described by MultiConflicts and Multiprio. @@ -81,30 +87,31 @@ LockTableId ShortTermTableId = (LockTableId)NULL; LockTableId InitMultiLevelLockm() { - int tableId; - - /* ----------------------- - * If we're already initialized just return the table id. - * ----------------------- - */ - if (MultiTableId) + int tableId; + + /* ----------------------- + * If we're already initialized just return the table id. + * ----------------------- + */ + if (MultiTableId) + return MultiTableId; + + tableId = LockTabInit("LockTable", MultiConflicts, MultiPrios, 5); + MultiTableId = tableId; + if (!(MultiTableId)) + { + elog(WARN, "InitMultiLockm: couldnt initialize lock table"); + } + /* ----------------------- + * No short term lock table for now. -Jeff 15 July 1991 + * + * ShortTermTableId = LockTabRename(tableId); + * if (! (ShortTermTableId)) { + * elog(WARN,"InitMultiLockm: couldnt rename lock table"); + * } + * ----------------------- + */ return MultiTableId; - - tableId = LockTabInit("LockTable", MultiConflicts, MultiPrios, 5); - MultiTableId = tableId; - if (! (MultiTableId)) { - elog(WARN,"InitMultiLockm: couldnt initialize lock table"); - } - /* ----------------------- - * No short term lock table for now. -Jeff 15 July 1991 - * - * ShortTermTableId = LockTabRename(tableId); - * if (! (ShortTermTableId)) { - * elog(WARN,"InitMultiLockm: couldnt rename lock table"); - * } - * ----------------------- - */ - return MultiTableId; } /* @@ -115,16 +122,16 @@ InitMultiLevelLockm() bool MultiLockReln(LockInfo linfo, LOCKT lockt) { - LOCKTAG tag; - - /* LOCKTAG has two bytes of padding, unfortunately. The - * hash function will return miss if the padding bytes aren't - * zero'd. - */ - memset(&tag,0,sizeof(tag)); - tag.relId = linfo->lRelId.relId; - tag.dbId = linfo->lRelId.dbId; - return(MultiAcquire(MultiTableId, &tag, lockt, RELN_LEVEL)); + LOCKTAG tag; + + /* + * LOCKTAG has two bytes of padding, unfortunately. The hash function + * will return miss if the padding bytes aren't zero'd. + */ + memset(&tag, 0, sizeof(tag)); + tag.relId = linfo->lRelId.relId; + tag.dbId = linfo->lRelId.dbId; + return (MultiAcquire(MultiTableId, &tag, lockt, RELN_LEVEL)); } /* @@ -133,25 +140,25 @@ MultiLockReln(LockInfo linfo, LOCKT lockt) * Returns: TRUE if lock is set, FALSE otherwise. * * Side Effects: causes intention level locks to be set - * at the page and relation level. + * at the page and relation level. */ bool MultiLockTuple(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt) { - LOCKTAG tag; - - /* LOCKTAG has two bytes of padding, unfortunately. The - * hash function will return miss if the padding bytes aren't - * zero'd. - */ - memset(&tag,0,sizeof(tag)); - - tag.relId = linfo->lRelId.relId; - tag.dbId = linfo->lRelId.dbId; - - /* not locking any valid Tuple, just the page */ - tag.tupleId = *tidPtr; - return(MultiAcquire(MultiTableId, &tag, lockt, TUPLE_LEVEL)); + LOCKTAG tag; + + /* + * LOCKTAG has two bytes of padding, unfortunately. The hash function + * will return miss if the padding bytes aren't zero'd. + */ + memset(&tag, 0, sizeof(tag)); + + tag.relId = linfo->lRelId.relId; + tag.dbId = linfo->lRelId.dbId; + + /* not locking any valid Tuple, just the page */ + tag.tupleId = *tidPtr; + return (MultiAcquire(MultiTableId, &tag, lockt, TUPLE_LEVEL)); } /* @@ -160,28 +167,28 @@ MultiLockTuple(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt) bool MultiLockPage(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt) { - LOCKTAG tag; - - /* LOCKTAG has two bytes of padding, unfortunately. The - * hash function will return miss if the padding bytes aren't - * zero'd. - */ - memset(&tag,0,sizeof(tag)); - - - /* ---------------------------- - * Now we want to set the page offset to be invalid - * and lock the block. There is some confusion here as to what - * a page is. In Postgres a page is an 8k block, however this - * block may be partitioned into many subpages which are sometimes - * also called pages. The term is overloaded, so don't be fooled - * when we say lock the page we mean the 8k block. -Jeff 16 July 1991 - * ---------------------------- - */ - tag.relId = linfo->lRelId.relId; - tag.dbId = linfo->lRelId.dbId; - BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid)); - return(MultiAcquire(MultiTableId, &tag, lockt, PAGE_LEVEL)); + LOCKTAG tag; + + /* + * LOCKTAG has two bytes of padding, unfortunately. The hash function + * will return miss if the padding bytes aren't zero'd. + */ + memset(&tag, 0, sizeof(tag)); + + + /* ---------------------------- + * Now we want to set the page offset to be invalid + * and lock the block. There is some confusion here as to what + * a page is. In Postgres a page is an 8k block, however this + * block may be partitioned into many subpages which are sometimes + * also called pages. The term is overloaded, so don't be fooled + * when we say lock the page we mean the 8k block. -Jeff 16 July 1991 + * ---------------------------- + */ + tag.relId = linfo->lRelId.relId; + tag.dbId = linfo->lRelId.dbId; + BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid)); + return (MultiAcquire(MultiTableId, &tag, lockt, PAGE_LEVEL)); } /* @@ -190,102 +197,110 @@ MultiLockPage(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt) * Returns: TRUE if lock is set, FALSE if not * Side Effects: */ -static bool +static bool MultiAcquire(LockTableId tableId, - LOCKTAG *tag, - LOCKT lockt, - LOCK_LEVEL level) + LOCKTAG * tag, + LOCKT lockt, + LOCK_LEVEL level) { - LOCKT locks[N_LEVELS]; - int i,status; - LOCKTAG xxTag, *tmpTag = &xxTag; - int retStatus = TRUE; - - /* - * Three levels implemented. If we set a low level (e.g. Tuple) - * lock, we must set INTENT locks on the higher levels. The - * intent lock detects conflicts between the low level lock - * and an existing high level lock. For example, setting a - * write lock on a tuple in a relation is disallowed if there - * is an existing read lock on the entire relation. The - * write lock would set a WRITE + INTENT lock on the relation - * and that lock would conflict with the read. - */ - switch (level) { - case RELN_LEVEL: - locks[0] = lockt; - locks[1] = NO_LOCK; - locks[2] = NO_LOCK; - break; - case PAGE_LEVEL: - locks[0] = lockt + INTENT; - locks[1] = lockt; - locks[2] = NO_LOCK; - break; - case TUPLE_LEVEL: - locks[0] = lockt + INTENT; - locks[1] = lockt + INTENT; - locks[2] = lockt; - break; - default: - elog(WARN,"MultiAcquire: bad lock level"); - return(FALSE); - } - - /* - * construct a new tag as we go. Always loop through all levels, - * but if we arent' seting a low level lock, locks[i] is set to - * NO_LOCK for the lower levels. Always start from the highest - * level and go to the lowest level. - */ - memset(tmpTag,0,sizeof(*tmpTag)); - tmpTag->relId = tag->relId; - tmpTag->dbId = tag->dbId; - - for (i=0;i<N_LEVELS;i++) { - if (locks[i] != NO_LOCK) { - switch (i) { - case RELN_LEVEL: - /* ------------- - * Set the block # and offset to invalid - * ------------- - */ - BlockIdSet(&(tmpTag->tupleId.ip_blkid), InvalidBlockNumber); - tmpTag->tupleId.ip_posid = InvalidOffsetNumber; - break; - case PAGE_LEVEL: - /* ------------- - * Copy the block #, set the offset to invalid - * ------------- - */ - BlockIdCopy(&(tmpTag->tupleId.ip_blkid), - &(tag->tupleId.ip_blkid)); - tmpTag->tupleId.ip_posid = InvalidOffsetNumber; + LOCKT locks[N_LEVELS]; + int i, + status; + LOCKTAG xxTag, + *tmpTag = &xxTag; + int retStatus = TRUE; + + /* + * Three levels implemented. If we set a low level (e.g. Tuple) lock, + * we must set INTENT locks on the higher levels. The intent lock + * detects conflicts between the low level lock and an existing high + * level lock. For example, setting a write lock on a tuple in a + * relation is disallowed if there is an existing read lock on the + * entire relation. The write lock would set a WRITE + INTENT lock on + * the relation and that lock would conflict with the read. + */ + switch (level) + { + case RELN_LEVEL: + locks[0] = lockt; + locks[1] = NO_LOCK; + locks[2] = NO_LOCK; break; - case TUPLE_LEVEL: - /* -------------- - * Copy the entire tuple id. - * -------------- - */ - ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId); + case PAGE_LEVEL: + locks[0] = lockt + INTENT; + locks[1] = lockt; + locks[2] = NO_LOCK; break; - } - - status = LockAcquire(tableId, tmpTag, locks[i]); - if (! status) { - /* failed for some reason. Before returning we have - * to release all of the locks we just acquired. - * MultiRelease(xx,xx,xx, i) means release starting from - * the last level lock we successfully acquired - */ - retStatus = FALSE; - MultiRelease(tableId, tag, lockt, i); - /* now leave the loop. Don't try for any more locks */ + case TUPLE_LEVEL: + locks[0] = lockt + INTENT; + locks[1] = lockt + INTENT; + locks[2] = lockt; break; - } + default: + elog(WARN, "MultiAcquire: bad lock level"); + return (FALSE); } - } - return(retStatus); + + /* + * construct a new tag as we go. Always loop through all levels, but + * if we arent' seting a low level lock, locks[i] is set to NO_LOCK + * for the lower levels. Always start from the highest level and go + * to the lowest level. + */ + memset(tmpTag, 0, sizeof(*tmpTag)); + tmpTag->relId = tag->relId; + tmpTag->dbId = tag->dbId; + + for (i = 0; i < N_LEVELS; i++) + { + if (locks[i] != NO_LOCK) + { + switch (i) + { + case RELN_LEVEL: + /* ------------- + * Set the block # and offset to invalid + * ------------- + */ + BlockIdSet(&(tmpTag->tupleId.ip_blkid), InvalidBlockNumber); + tmpTag->tupleId.ip_posid = InvalidOffsetNumber; + break; + case PAGE_LEVEL: + /* ------------- + * Copy the block #, set the offset to invalid + * ------------- + */ + BlockIdCopy(&(tmpTag->tupleId.ip_blkid), + &(tag->tupleId.ip_blkid)); + tmpTag->tupleId.ip_posid = InvalidOffsetNumber; + break; + case TUPLE_LEVEL: + /* -------------- + * Copy the entire tuple id. + * -------------- + */ + ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId); + break; + } + + status = LockAcquire(tableId, tmpTag, locks[i]); + if (!status) + { + + /* + * failed for some reason. Before returning we have to + * release all of the locks we just acquired. + * MultiRelease(xx,xx,xx, i) means release starting from + * the last level lock we successfully acquired + */ + retStatus = FALSE; + MultiRelease(tableId, tag, lockt, i); + /* now leave the loop. Don't try for any more locks */ + break; + } + } + } + return (retStatus); } /* ------------------ @@ -294,24 +309,25 @@ MultiAcquire(LockTableId tableId, */ #ifdef NOT_USED bool -MultiReleasePage(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt) +MultiReleasePage(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt) { - LOCKTAG tag; - - /* ------------------ - * LOCKTAG has two bytes of padding, unfortunately. The - * hash function will return miss if the padding bytes aren't - * zero'd. - * ------------------ - */ - memset(&tag, 0,sizeof(LOCKTAG)); - - tag.relId = linfo->lRelId.relId; - tag.dbId = linfo->lRelId.dbId; - BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid)); - - return (MultiRelease(MultiTableId, &tag, lockt, PAGE_LEVEL)); + LOCKTAG tag; + + /* ------------------ + * LOCKTAG has two bytes of padding, unfortunately. The + * hash function will return miss if the padding bytes aren't + * zero'd. + * ------------------ + */ + memset(&tag, 0, sizeof(LOCKTAG)); + + tag.relId = linfo->lRelId.relId; + tag.dbId = linfo->lRelId.dbId; + BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid)); + + return (MultiRelease(MultiTableId, &tag, lockt, PAGE_LEVEL)); } + #endif /* ------------------ @@ -319,21 +335,21 @@ MultiReleasePage(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt) * ------------------ */ bool -MultiReleaseReln(LockInfo linfo, LOCKT lockt) +MultiReleaseReln(LockInfo linfo, LOCKT lockt) { - LOCKTAG tag; - - /* ------------------ - * LOCKTAG has two bytes of padding, unfortunately. The - * hash function will return miss if the padding bytes aren't - * zero'd. - * ------------------ - */ - memset(&tag, 0, sizeof(LOCKTAG)); - tag.relId = linfo->lRelId.relId; - tag.dbId = linfo->lRelId.dbId; - - return (MultiRelease(MultiTableId, &tag, lockt, RELN_LEVEL)); + LOCKTAG tag; + + /* ------------------ + * LOCKTAG has two bytes of padding, unfortunately. The + * hash function will return miss if the padding bytes aren't + * zero'd. + * ------------------ + */ + memset(&tag, 0, sizeof(LOCKTAG)); + tag.relId = linfo->lRelId.relId; + tag.dbId = linfo->lRelId.dbId; + + return (MultiRelease(MultiTableId, &tag, lockt, RELN_LEVEL)); } /* @@ -341,81 +357,88 @@ MultiReleaseReln(LockInfo linfo, LOCKT lockt) * * Returns: TRUE if successful, FALSE otherwise. */ -static bool +static bool MultiRelease(LockTableId tableId, - LOCKTAG *tag, - LOCKT lockt, - LOCK_LEVEL level) + LOCKTAG * tag, + LOCKT lockt, + LOCK_LEVEL level) { - LOCKT locks[N_LEVELS]; - int i,status; - LOCKTAG xxTag, *tmpTag = &xxTag; - - /* - * same level scheme as MultiAcquire(). - */ - switch (level) { - case RELN_LEVEL: - locks[0] = lockt; - locks[1] = NO_LOCK; - locks[2] = NO_LOCK; - break; - case PAGE_LEVEL: - locks[0] = lockt + INTENT; - locks[1] = lockt; - locks[2] = NO_LOCK; - break; - case TUPLE_LEVEL: - locks[0] = lockt + INTENT; - locks[1] = lockt + INTENT; - locks[2] = lockt; - break; - default: - elog(WARN,"MultiRelease: bad lockt"); - } - - /* - * again, construct the tag on the fly. This time, however, - * we release the locks in the REVERSE order -- from lowest - * level to highest level. - * - * Must zero out the tag to set padding byes to zero and ensure - * hashing consistency. - */ - memset(tmpTag, 0, sizeof(*tmpTag)); - tmpTag->relId = tag->relId; - tmpTag->dbId = tag->dbId; - - for (i=(N_LEVELS-1); i>=0; i--) { - if (locks[i] != NO_LOCK) { - switch (i) { - case RELN_LEVEL: - /* ------------- - * Set the block # and offset to invalid - * ------------- - */ - BlockIdSet(&(tmpTag->tupleId.ip_blkid), InvalidBlockNumber); - tmpTag->tupleId.ip_posid = InvalidOffsetNumber; + LOCKT locks[N_LEVELS]; + int i, + status; + LOCKTAG xxTag, + *tmpTag = &xxTag; + + /* + * same level scheme as MultiAcquire(). + */ + switch (level) + { + case RELN_LEVEL: + locks[0] = lockt; + locks[1] = NO_LOCK; + locks[2] = NO_LOCK; break; - case PAGE_LEVEL: - /* ------------- - * Copy the block #, set the offset to invalid - * ------------- - */ - BlockIdCopy(&(tmpTag->tupleId.ip_blkid), - &(tag->tupleId.ip_blkid)); - tmpTag->tupleId.ip_posid = InvalidOffsetNumber; + case PAGE_LEVEL: + locks[0] = lockt + INTENT; + locks[1] = lockt; + locks[2] = NO_LOCK; break; - case TUPLE_LEVEL: - ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId); + case TUPLE_LEVEL: + locks[0] = lockt + INTENT; + locks[1] = lockt + INTENT; + locks[2] = lockt; break; - } - status = LockRelease(tableId, tmpTag, locks[i]); - if (! status) { - elog(WARN,"MultiRelease: couldn't release after error"); - } + default: + elog(WARN, "MultiRelease: bad lockt"); + } + + /* + * again, construct the tag on the fly. This time, however, we + * release the locks in the REVERSE order -- from lowest level to + * highest level. + * + * Must zero out the tag to set padding byes to zero and ensure hashing + * consistency. + */ + memset(tmpTag, 0, sizeof(*tmpTag)); + tmpTag->relId = tag->relId; + tmpTag->dbId = tag->dbId; + + for (i = (N_LEVELS - 1); i >= 0; i--) + { + if (locks[i] != NO_LOCK) + { + switch (i) + { + case RELN_LEVEL: + /* ------------- + * Set the block # and offset to invalid + * ------------- + */ + BlockIdSet(&(tmpTag->tupleId.ip_blkid), InvalidBlockNumber); + tmpTag->tupleId.ip_posid = InvalidOffsetNumber; + break; + case PAGE_LEVEL: + /* ------------- + * Copy the block #, set the offset to invalid + * ------------- + */ + BlockIdCopy(&(tmpTag->tupleId.ip_blkid), + &(tag->tupleId.ip_blkid)); + tmpTag->tupleId.ip_posid = InvalidOffsetNumber; + break; + case TUPLE_LEVEL: + ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId); + break; + } + status = LockRelease(tableId, tmpTag, locks[i]); + if (!status) + { + elog(WARN, "MultiRelease: couldn't release after error"); + } + } } - } - /* shouldn't reach here */ - return false; + /* shouldn't reach here */ + return false; } |