aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/lmgr/lmgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/lmgr/lmgr.c')
-rw-r--r--src/backend/storage/lmgr/lmgr.c580
1 files changed, 153 insertions, 427 deletions
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 13adb8c48f8..307c54e39e1 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.19 1998/09/01 04:31:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.20 1998/12/15 12:46:30 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@@ -49,6 +49,85 @@
extern Oid MyDatabaseId;
+static MASK LockConflicts[] = {
+ (int) NULL,
+
+/* AccessShareLock */
+ (1 << AccessExclusiveLock),
+
+/* RowShareLock */
+ (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+/* RowExclusiveLock */
+ (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
+ (1 << AccessExclusiveLock),
+
+/* ShareLock */
+ (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
+ (1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
+
+/* ShareRowExclusiveLock */
+ (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
+ (1 << ShareLock) | (1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
+
+/* ExclusiveLock */
+ (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
+ (1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock),
+
+/* AccessExclusiveLock */
+ (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
+ (1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock) |
+ (1 << AccessShareLock),
+
+/* ExtendLock */
+ (1 << ExtendLock)
+
+};
+
+static int LockPrios[] = {
+ (int) NULL,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 1
+};
+
+LOCKMETHOD LockTableId = (LOCKMETHOD) NULL;
+LOCKMETHOD LongTermTableId = (LOCKMETHOD) NULL;
+
+/*
+ * Create the lock table described by LockConflicts and LockPrios.
+ */
+LOCKMETHOD
+InitLockTable()
+{
+ int lockmethod;
+
+ lockmethod = LockMethodTableInit("LockTable",
+ LockConflicts, LockPrios, MAX_LOCKMODES - 1);
+ LockTableId = lockmethod;
+ if (!(LockTableId))
+ elog(ERROR, "InitLockTable: couldnt initialize lock table");
+
+#ifdef USER_LOCKS
+ /*
+ * Allocate another tableId for long-term locks
+ */
+ LongTermTableId = LockMethodTableRename(LockTableId);
+ if (!(LongTermTableId))
+ {
+ elog(ERROR,
+ "InitLockTable: couldn't rename long-term lock table");
+ }
+#endif
+
+ return LockTableId;
+}
+
/*
* RelationInitLockInfo --
* Initializes the lock information in a relation descriptor.
@@ -82,130 +161,49 @@ RelationInitLockInfo(Relation relation)
else
info->lockRelId.dbId = MyDatabaseId;
-#ifdef LowLevelLocking
- memset(info->lockHeld, 0, sizeof(info->lockHeld));
-#endif
-
relation->lockInfo = (Pointer) info;
}
/*
- * RelationSetLockForDescriptorOpen --
- * Sets read locks for a relation descriptor.
- */
-#ifdef LOCKDEBUGALL
-#define LOCKDEBUGALL_30 \
-elog(DEBUG, "RelationSetLockForDescriptorOpen(%s[%d,%d]) called", \
- RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
-#else
-#define LOCKDEBUGALL_30
-#endif /* LOCKDEBUGALL */
-
-void
-RelationSetLockForDescriptorOpen(Relation relation)
-{
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- LOCKDEBUGALL_30;
-
- /* ----------------
- * read lock catalog tuples which compose the relation descriptor
- * XXX race condition? XXX For now, do nothing.
- * ----------------
- */
-}
-
-/* ----------------
- * RelationSetLockForRead
- * ----------------
- */
-#ifdef LOCKDEBUG
-#define LOCKDEBUG_40 \
-elog(DEBUG, "RelationSetLockForRead(%s[%d,%d]) called", \
- RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
-#else
-#define LOCKDEBUG_40
-#endif /* LOCKDEBUG */
-
-/*
- * RelationSetLockForRead --
- * Sets relation level read lock.
+ * LockRelation
*/
void
-RelationSetLockForRead(Relation relation)
+LockRelation(Relation relation, LOCKMODE lockmode)
{
LockInfo lockinfo;
+ LOCKTAG tag;
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
if (LockingDisabled())
return;
- LOCKDEBUG_40;
-
- /* ----------------
- * If we don't have lock info on the reln just go ahead and
- * lock it without trying to short circuit the lock manager.
- * ----------------
- */
if (!LockInfoIsValid(relation->lockInfo))
- {
RelationInitLockInfo(relation);
- lockinfo = (LockInfo) relation->lockInfo;
- MultiLockReln(lockinfo, READ_LOCK);
- return;
- }
- else
- lockinfo = (LockInfo) relation->lockInfo;
- MultiLockReln(lockinfo, READ_LOCK);
-}
+ lockinfo = (LockInfo) relation->lockInfo;
-/* ----------------
- * RelationUnsetLockForRead
- * ----------------
- */
-#ifdef LOCKDEBUG
-#define LOCKDEBUG_50 \
-elog(DEBUG, "RelationUnsetLockForRead(%s[%d,%d]) called", \
- RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
-#else
-#define LOCKDEBUG_50
-#endif /* LOCKDEBUG */
+ MemSet(&tag, 0, sizeof(tag));
+ tag.relId = lockinfo->lockRelId.relId;
+ tag.dbId = lockinfo->lockRelId.dbId;
+ tag.objId.blkno = InvalidBlockNumber;
+
+ LockAcquire(LockTableId, &tag, lockmode);
+ return;
+}
/*
- * RelationUnsetLockForRead --
- * Unsets relation level read lock.
+ * UnlockRelation
*/
void
-RelationUnsetLockForRead(Relation relation)
+UnlockRelation(Relation relation, LOCKMODE lockmode)
{
LockInfo lockinfo;
+ LOCKTAG tag;
- /* ----------------
- * sanity check
- * ----------------
- */
- Assert(RelationIsValid(relation));
if (LockingDisabled())
return;
lockinfo = (LockInfo) relation->lockInfo;
- /* ----------------
- * If we don't have lock info on the reln just go ahead and
- * release it.
- * ----------------
- */
if (!LockInfoIsValid(lockinfo))
{
elog(ERROR,
@@ -213,84 +211,50 @@ RelationUnsetLockForRead(Relation relation)
RelationGetRelationName(relation));
}
- MultiReleaseReln(lockinfo, READ_LOCK);
-}
+ MemSet(&tag, 0, sizeof(tag));
+ tag.relId = lockinfo->lockRelId.relId;
+ tag.dbId = lockinfo->lockRelId.dbId;
+ tag.objId.blkno = InvalidBlockNumber;
-/* ----------------
- * RelationSetLockForWrite(relation)
- * ----------------
- */
-#ifdef LOCKDEBUG
-#define LOCKDEBUG_60 \
-elog(DEBUG, "RelationSetLockForWrite(%s[%d,%d]) called", \
- RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
-#else
-#define LOCKDEBUG_60
-#endif /* LOCKDEBUG */
+ LockRelease(LockTableId, &tag, lockmode);
+ return;
+}
/*
- * RelationSetLockForWrite --
- * Sets relation level write lock.
+ * LockPage
*/
void
-RelationSetLockForWrite(Relation relation)
+LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
{
LockInfo lockinfo;
+ LOCKTAG tag;
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
if (LockingDisabled())
return;
- LOCKDEBUG_60;
-
- /* ----------------
- * If we don't have lock info on the reln just go ahead and
- * lock it without trying to short circuit the lock manager.
- * ----------------
- */
if (!LockInfoIsValid(relation->lockInfo))
- {
RelationInitLockInfo(relation);
- lockinfo = (LockInfo) relation->lockInfo;
- MultiLockReln(lockinfo, WRITE_LOCK);
- return;
- }
- else
- lockinfo = (LockInfo) relation->lockInfo;
- MultiLockReln(lockinfo, WRITE_LOCK);
-}
+ lockinfo = (LockInfo) relation->lockInfo;
-/* ----------------
- * RelationUnsetLockForWrite
- * ----------------
- */
-#ifdef LOCKDEBUG
-#define LOCKDEBUG_70 \
-elog(DEBUG, "RelationUnsetLockForWrite(%s[%d,%d]) called", \
- RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
-#else
-#define LOCKDEBUG_70
-#endif /* LOCKDEBUG */
+ MemSet(&tag, 0, sizeof(tag));
+ tag.relId = lockinfo->lockRelId.relId;
+ tag.dbId = lockinfo->lockRelId.dbId;
+ tag.objId.blkno = blkno;
+
+ LockAcquire(LockTableId, &tag, lockmode);
+ return;
+}
/*
- * RelationUnsetLockForWrite --
- * Unsets relation level write lock.
+ * UnlockPage
*/
void
-RelationUnsetLockForWrite(Relation relation)
+UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
{
LockInfo lockinfo;
+ LOCKTAG tag;
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
if (LockingDisabled())
return;
@@ -303,309 +267,71 @@ RelationUnsetLockForWrite(Relation relation)
RelationGetRelationName(relation));
}
- MultiReleaseReln(lockinfo, WRITE_LOCK);
-}
+ MemSet(&tag, 0, sizeof(tag));
+ tag.relId = lockinfo->lockRelId.relId;
+ tag.dbId = lockinfo->lockRelId.dbId;
+ tag.objId.blkno = blkno;
-/* ----------------
- * RelationSetLockForReadPage
- * ----------------
- */
-#ifdef LOCKDEBUG
-#define LOCKDEBUG_90 \
-elog(DEBUG, "RelationSetLockForReadPage(%s[%d,%d], @%d) called", \
- RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
-#else
-#define LOCKDEBUG_90
-#endif /* LOCKDEBUG */
-
-/* ----------------
- * RelationSetLockForWritePage
- * ----------------
- */
-#ifdef LOCKDEBUG
-#define LOCKDEBUG_100 \
-elog(DEBUG, "RelationSetLockForWritePage(%s[%d,%d], @%d) called", \
- RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
-#else
-#define LOCKDEBUG_100
-#endif /* LOCKDEBUG */
-
-/*
- * RelationSetLockForWritePage --
- * Sets write lock on a page.
- */
-void
-RelationSetLockForWritePage(Relation relation,
- ItemPointer itemPointer)
-{
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- /* ---------------
- * Make sure lockinfo is initialized
- * ---------------
- */
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- /* ----------------
- * attempt to set lock
- * ----------------
- */
- MultiLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK);
+ LockRelease(LockTableId, &tag, lockmode);
+ return;
}
-/* ----------------
- * RelationUnsetLockForReadPage
- * ----------------
- */
-#ifdef LOCKDEBUG
-#define LOCKDEBUG_110 \
-elog(DEBUG, "RelationUnsetLockForReadPage(%s[%d,%d], @%d) called", \
- RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
-#else
-#define LOCKDEBUG_110
-#endif /* LOCKDEBUG */
-
-/* ----------------
- * RelationUnsetLockForWritePage
- * ----------------
- */
-#ifdef LOCKDEBUG
-#define LOCKDEBUG_120 \
-elog(DEBUG, "RelationUnsetLockForWritePage(%s[%d,%d], @%d) called", \
- RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
-#else
-#define LOCKDEBUG_120
-#endif /* LOCKDEBUG */
-
-/*
- * Set a single level write page lock. Assumes that you already
- * have a write intent lock on the relation.
- */
void
-RelationSetSingleWLockPage(Relation relation,
- ItemPointer itemPointer)
+XactLockTableInsert(TransactionId xid)
{
+ LOCKTAG tag;
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
if (LockingDisabled())
return;
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
+ MemSet(&tag, 0, sizeof(tag));
+ tag.relId = XactLockTableId;
+ tag.dbId = InvalidOid;
+ tag.objId.xid = xid;
- SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, !UNLOCK);
+ LockAcquire(LockTableId, &tag, ExclusiveLock);
+ return;
}
-/*
- * Unset a single level write page lock
- */
void
-RelationUnsetSingleWLockPage(Relation relation,
- ItemPointer itemPointer)
+XactLockTableDelete(TransactionId xid)
{
+ LOCKTAG tag;
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
if (LockingDisabled())
return;
- if (!LockInfoIsValid(relation->lockInfo))
- elog(ERROR,
- "Releasing a lock on %s with invalid lock information",
- RelationGetRelationName(relation));
-
- SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, UNLOCK);
-}
-
-/*
- * Set a single level read page lock. Assumes you already have a read
- * intent lock set on the relation.
- */
-void
-RelationSetSingleRLockPage(Relation relation,
- ItemPointer itemPointer)
-{
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, !UNLOCK);
-}
-
-/*
- * Unset a single level read page lock.
- */
-void
-RelationUnsetSingleRLockPage(Relation relation,
- ItemPointer itemPointer)
-{
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- elog(ERROR,
- "Releasing a lock on %s with invalid lock information",
- RelationGetRelationName(relation));
-
- SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, UNLOCK);
-}
-
-/*
- * Set a read intent lock on a relation.
- *
- * Usually these are set in a multi-level table when you acquiring a
- * page level lock. i.e. To acquire a lock on a page you first acquire
- * an intent lock on the entire relation. Acquiring an intent lock along
- * allows one to use the single level locking routines later. Good for
- * index scans that do a lot of page level locking.
- */
-void
-RelationSetRIntentLock(Relation relation)
-{
- /* -----------------
- * Sanity check
- * -----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, !UNLOCK);
-}
-
-/*
- * Unset a read intent lock on a relation
- */
-void
-RelationUnsetRIntentLock(Relation relation)
-{
- /* -----------------
- * Sanity check
- * -----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
+ MemSet(&tag, 0, sizeof(tag));
+ tag.relId = XactLockTableId;
+ tag.dbId = InvalidOid;
+ tag.objId.xid = xid;
- SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, UNLOCK);
+ LockRelease(LockTableId, &tag, ExclusiveLock);
+ return;
}
-/*
- * Set a write intent lock on a relation. For a more complete explanation
- * see RelationSetRIntentLock()
- */
void
-RelationSetWIntentLock(Relation relation)
+XactLockTableWait(TransactionId xid)
{
- /* -----------------
- * Sanity check
- * -----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
+ LOCKTAG tag;
- SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, !UNLOCK);
-}
-
-/*
- * Unset a write intent lock.
- */
-void
-RelationUnsetWIntentLock(Relation relation)
-{
- /* -----------------
- * Sanity check
- * -----------------
- */
- Assert(RelationIsValid(relation));
if (LockingDisabled())
return;
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
+ MemSet(&tag, 0, sizeof(tag));
+ tag.relId = XactLockTableId;
+ tag.dbId = InvalidOid;
+ tag.objId.xid = xid;
- SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, UNLOCK);
-}
+ LockAcquire(LockTableId, &tag, ShareLock);
-/*
- * Extend locks are used primarily in tertiary storage devices such as
- * a WORM disk jukebox. Sometimes need exclusive access to extend a
- * file by a block.
- */
-#ifdef NOT_USED
-void
-RelationSetLockForExtend(Relation relation)
-{
- /* -----------------
- * Sanity check
- * -----------------
+ /*
+ * Transaction was committed/aborted/crashed -
+ * we have to update pg_log if transaction is still
+ * marked as running.
*/
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
+ if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
+ TransactionIdAbort(xid);
- MultiLockReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
+ return;
}
-
-#endif
-
-#ifdef NOT_USED
-void
-RelationUnsetLockForExtend(Relation relation)
-{
- /* -----------------
- * Sanity check
- * -----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- MultiReleaseReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
-}
-
-#endif