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.c933
1 files changed, 933 insertions, 0 deletions
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
new file mode 100644
index 00000000000..bfc2f5b2eec
--- /dev/null
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -0,0 +1,933 @@
+/*-------------------------------------------------------------------------
+ *
+ * lmgr.c--
+ * POSTGRES lock manager code
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.1.1.1 1996/07/09 06:21:56 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/* #define LOCKDEBUGALL 1 */
+/* #define LOCKDEBUG 1 */
+
+#ifdef LOCKDEBUGALL
+#define LOCKDEBUG 1
+#endif /* LOCKDEBUGALL */
+
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "access/htup.h"
+#include "access/relscan.h"
+#include "access/skey.h"
+#include "utils/tqual.h"
+#include "access/xact.h"
+
+#include "storage/block.h"
+#include "storage/buf.h"
+#include "storage/itemptr.h"
+#include "storage/bufpage.h"
+#include "storage/multilev.h"
+#include "storage/lmgr.h"
+
+#include "utils/elog.h"
+#include "utils/palloc.h"
+#include "utils/rel.h"
+
+#include "catalog/catname.h"
+#include "catalog/catalog.h"
+#include "catalog/pg_class.h"
+
+#include "nodes/memnodes.h"
+#include "storage/bufmgr.h"
+#include "access/transam.h" /* for AmiTransactionId */
+
+/* ----------------
+ *
+ * ----------------
+ */
+#define MaxRetries 4 /* XXX about 1/4 minute--a hack */
+
+#define IntentReadRelationLock 0x0100
+#define ReadRelationLock 0x0200
+#define IntentWriteRelationLock 0x0400
+#define WriteRelationLock 0x0800
+#define IntentReadPageLock 0x1000
+#define ReadTupleLock 0x2000
+
+#define TupleLevelLockCountMask 0x000f
+
+#define TupleLevelLockLimit 10
+
+extern Oid MyDatabaseId;
+
+static LRelId VariableRelationLRelId = {
+ RelOid_pg_variable,
+ InvalidOid
+};
+
+/* ----------------
+ * RelationGetLRelId
+ * ----------------
+ */
+#ifdef LOCKDEBUG
+#define LOCKDEBUG_10 \
+elog(NOTICE, "RelationGetLRelId(%s) invalid lockInfo", \
+ RelationGetRelationName(relation));
+#else
+#define LOCKDEBUG_10
+#endif /* LOCKDEBUG */
+
+/*
+ * RelationGetLRelId --
+ * Returns "lock" relation identifier for a relation.
+ */
+LRelId
+RelationGetLRelId(Relation relation)
+{
+ LockInfo linfo;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ linfo = (LockInfo) relation->lockInfo;
+
+ /* ----------------
+ * initialize lock info if necessary
+ * ----------------
+ */
+ if (! LockInfoIsValid(linfo)) {
+ LOCKDEBUG_10;
+ RelationInitLockInfo(relation);
+ linfo = (LockInfo) relation->lockInfo;
+ }
+
+ /* ----------------
+ * XXX hack to prevent problems during
+ * VARIABLE relation initialization
+ * ----------------
+ */
+ if (strcmp(RelationGetRelationName(relation)->data,
+ VariableRelationName) == 0) {
+ return (VariableRelationLRelId);
+ }
+
+ return (linfo->lRelId);
+}
+
+/*
+ * LRelIdGetDatabaseId --
+ * Returns database identifier for a "lock" relation identifier.
+ */
+/* ----------------
+ * LRelIdGetDatabaseId
+ *
+ * Note: The argument may not be correct, if it is not used soon
+ * after it is created.
+ * ----------------
+ */
+Oid
+LRelIdGetDatabaseId(LRelId lRelId)
+{
+ return (lRelId.dbId);
+}
+
+
+/*
+ * LRelIdGetRelationId --
+ * Returns relation identifier for a "lock" relation identifier.
+ */
+Oid
+LRelIdGetRelationId(LRelId lRelId)
+{
+ return (lRelId.relId);
+}
+
+/*
+ * DatabaseIdIsMyDatabaseId --
+ * True iff database object identifier is valid in my present database.
+ */
+bool
+DatabaseIdIsMyDatabaseId(Oid databaseId)
+{
+ return (bool)
+ (!OidIsValid(databaseId) || databaseId == MyDatabaseId);
+}
+
+/*
+ * LRelIdContainsMyDatabaseId --
+ * True iff "lock" relation identifier is valid in my present database.
+ */
+bool
+LRelIdContainsMyDatabaseId(LRelId lRelId)
+{
+ return (bool)
+ (!OidIsValid(lRelId.dbId) || lRelId.dbId == MyDatabaseId);
+}
+
+/*
+ * RelationInitLockInfo --
+ * Initializes the lock information in a relation descriptor.
+ */
+/* ----------------
+ * RelationInitLockInfo
+ *
+ * XXX processingVariable is a hack to prevent problems during
+ * VARIABLE relation initialization.
+ * ----------------
+ */
+void
+RelationInitLockInfo(Relation relation)
+{
+ LockInfo info;
+ char *relname;
+ Oid relationid;
+ bool processingVariable;
+ extern Oid MyDatabaseId; /* XXX use include */
+ extern GlobalMemory CacheCxt;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ Assert(OidIsValid(RelationGetRelationId(relation)));
+
+ /* ----------------
+ * get information from relation descriptor
+ * ----------------
+ */
+ info = (LockInfo) relation->lockInfo;
+ relname = (char *) RelationGetRelationName(relation);
+ relationid = RelationGetRelationId(relation);
+ processingVariable = (strcmp(relname, VariableRelationName) == 0);
+
+ /* ----------------
+ * create a new lockinfo if not already done
+ * ----------------
+ */
+ if (! PointerIsValid(info))
+ {
+ MemoryContext oldcxt;
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
+ info = (LockInfo)palloc(sizeof(LockInfoData));
+ MemoryContextSwitchTo(oldcxt);
+ }
+ else if (processingVariable) {
+ if (IsTransactionState()) {
+ TransactionIdStore(GetCurrentTransactionId(),
+ &info->transactionIdData);
+ }
+ info->flags = 0x0;
+ return; /* prevent an infinite loop--still true? */
+ }
+ else if (info->initialized)
+ {
+ /* ------------
+ * If we've already initialized we're done.
+ * ------------
+ */
+ return;
+ }
+
+ /* ----------------
+ * initialize lockinfo.dbId and .relId appropriately
+ * ----------------
+ */
+ if (IsSharedSystemRelationName(relname))
+ LRelIdAssign(&info->lRelId, InvalidOid, relationid);
+ else
+ LRelIdAssign(&info->lRelId, MyDatabaseId, relationid);
+
+ /* ----------------
+ * store the transaction id in the lockInfo field
+ * ----------------
+ */
+ if (processingVariable)
+ TransactionIdStore(AmiTransactionId,
+ &info->transactionIdData);
+ else if (IsTransactionState())
+ TransactionIdStore(GetCurrentTransactionId(),
+ &info->transactionIdData);
+ else
+ StoreInvalidTransactionId(&(info->transactionIdData));
+
+ /* ----------------
+ * initialize rest of lockinfo
+ * ----------------
+ */
+ info->flags = 0x0;
+ info->initialized = (bool)true;
+ relation->lockInfo = (Pointer) info;
+}
+
+/* ----------------
+ * RelationDiscardLockInfo
+ * ----------------
+ */
+#ifdef LOCKDEBUG
+#define LOCKDEBUG_20 \
+elog(DEBUG, "DiscardLockInfo: NULL relation->lockInfo")
+#else
+#define LOCKDEBUG_20
+#endif /* LOCKDEBUG */
+
+/*
+ * RelationDiscardLockInfo --
+ * Discards the lock information in a relation descriptor.
+ */
+void
+RelationDiscardLockInfo(Relation relation)
+{
+ if (! LockInfoIsValid(relation->lockInfo)) {
+ LOCKDEBUG_20;
+ return;
+ }
+
+ pfree(relation->lockInfo);
+ relation->lockInfo = NULL;
+}
+
+/*
+ * RelationSetLockForDescriptorOpen --
+ * Sets read locks for a relation descriptor.
+ */
+#ifdef LOCKDEBUGALL
+#define LOCKDEBUGALL_30 \
+elog(DEBUG, "RelationSetLockForDescriptorOpen(%s[%d,%d]) called", \
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.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), lRelId.dbId, lRelId.relId)
+#else
+#define LOCKDEBUG_40
+#endif /* LOCKDEBUG*/
+
+/*
+ * RelationSetLockForRead --
+ * Sets relation level read lock.
+ */
+void
+RelationSetLockForRead(Relation relation)
+{
+ LockInfo linfo;
+
+ /* ----------------
+ * 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);
+ linfo = (LockInfo) relation->lockInfo;
+ linfo->flags |= ReadRelationLock;
+ MultiLockReln(linfo, READ_LOCK);
+ return;
+ }
+ else
+ linfo = (LockInfo) relation->lockInfo;
+
+ MultiLockReln(linfo, READ_LOCK);
+}
+
+/* ----------------
+ * RelationUnsetLockForRead
+ * ----------------
+ */
+#ifdef LOCKDEBUG
+#define LOCKDEBUG_50 \
+elog(DEBUG, "RelationUnsetLockForRead(%s[%d,%d]) called", \
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId)
+#else
+#define LOCKDEBUG_50
+#endif /* LOCKDEBUG*/
+
+/*
+ * RelationUnsetLockForRead --
+ * Unsets relation level read lock.
+ */
+void
+RelationUnsetLockForRead(Relation relation)
+{
+ LockInfo linfo;
+
+ /* ----------------
+ * sanity check
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ linfo = (LockInfo) relation->lockInfo;
+
+ /* ----------------
+ * If we don't have lock info on the reln just go ahead and
+ * release it.
+ * ----------------
+ */
+ if (!LockInfoIsValid(linfo))
+ {
+ elog(WARN,
+ "Releasing a lock on %s with invalid lock information",
+ RelationGetRelationName(relation));
+ }
+
+ MultiReleaseReln(linfo, READ_LOCK);
+}
+
+/* ----------------
+ * RelationSetLockForWrite(relation)
+ * ----------------
+ */
+#ifdef LOCKDEBUG
+#define LOCKDEBUG_60 \
+elog(DEBUG, "RelationSetLockForWrite(%s[%d,%d]) called", \
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId)
+#else
+#define LOCKDEBUG_60
+#endif /* LOCKDEBUG*/
+
+/*
+ * RelationSetLockForWrite --
+ * Sets relation level write lock.
+ */
+void
+RelationSetLockForWrite(Relation relation)
+{
+ LockInfo linfo;
+
+ /* ----------------
+ * 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);
+ linfo = (LockInfo) relation->lockInfo;
+ linfo->flags |= WriteRelationLock;
+ MultiLockReln(linfo, WRITE_LOCK);
+ return;
+ }
+ else
+ linfo = (LockInfo) relation->lockInfo;
+
+ MultiLockReln(linfo, WRITE_LOCK);
+}
+
+/* ----------------
+ * RelationUnsetLockForWrite
+ * ----------------
+ */
+#ifdef LOCKDEBUG
+#define LOCKDEBUG_70 \
+elog(DEBUG, "RelationUnsetLockForWrite(%s[%d,%d]) called", \
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId);
+#else
+#define LOCKDEBUG_70
+#endif /* LOCKDEBUG */
+
+/*
+ * RelationUnsetLockForWrite --
+ * Unsets relation level write lock.
+ */
+void
+RelationUnsetLockForWrite(Relation relation)
+{
+ LockInfo linfo;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled()) {
+ return;
+ }
+
+ linfo = (LockInfo) relation->lockInfo;
+
+ if (!LockInfoIsValid(linfo))
+ {
+ elog(WARN,
+ "Releasing a lock on %s with invalid lock information",
+ RelationGetRelationName(relation));
+ }
+
+ MultiReleaseReln(linfo, WRITE_LOCK);
+}
+
+/* ----------------
+ * RelationSetLockForTupleRead
+ * ----------------
+ */
+#ifdef LOCKDEBUG
+#define LOCKDEBUG_80 \
+elog(DEBUG, "RelationSetLockForTupleRead(%s[%d,%d], 0x%x) called", \
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, \
+ itemPointer)
+#define LOCKDEBUG_81 \
+ elog(DEBUG, "RelationSetLockForTupleRead() escalating");
+#else
+#define LOCKDEBUG_80
+#define LOCKDEBUG_81
+#endif /* LOCKDEBUG */
+
+/*
+ * RelationSetLockForTupleRead --
+ * Sets tuple level read lock.
+ */
+void
+RelationSetLockForTupleRead(Relation relation, ItemPointer itemPointer)
+{
+ LockInfo linfo;
+ TransactionId curXact;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ LOCKDEBUG_80;
+
+ /* ---------------------
+ * If our lock info is invalid don't bother trying to short circuit
+ * the lock manager.
+ * ---------------------
+ */
+ if (!LockInfoIsValid(relation->lockInfo))
+ {
+ RelationInitLockInfo(relation);
+ linfo = (LockInfo) relation->lockInfo;
+ linfo->flags |=
+ IntentReadRelationLock |
+ IntentReadPageLock |
+ ReadTupleLock;
+ MultiLockTuple(linfo, itemPointer, READ_LOCK);
+ return;
+ }
+ else
+ linfo = (LockInfo) relation->lockInfo;
+
+ /* ----------------
+ * no need to set a lower granularity lock
+ * ----------------
+ */
+ curXact = GetCurrentTransactionId();
+ if ((linfo->flags & ReadRelationLock) &&
+ TransactionIdEquals(curXact, linfo->transactionIdData))
+ {
+ return;
+ }
+
+ /* ----------------
+ * If we don't already have a tuple lock this transaction
+ * ----------------
+ */
+ if (!( (linfo->flags & ReadTupleLock) &&
+ TransactionIdEquals(curXact, linfo->transactionIdData) )) {
+
+ linfo->flags |=
+ IntentReadRelationLock |
+ IntentReadPageLock |
+ ReadTupleLock;
+
+ /* clear count */
+ linfo->flags &= ~TupleLevelLockCountMask;
+
+ } else {
+ if (TupleLevelLockLimit == (TupleLevelLockCountMask &
+ linfo->flags)) {
+ LOCKDEBUG_81;
+
+ /* escalate */
+ MultiLockReln(linfo, READ_LOCK);
+
+ /* clear count */
+ linfo->flags &= ~TupleLevelLockCountMask;
+ return;
+ }
+
+ /* increment count */
+ linfo->flags =
+ (linfo->flags & ~TupleLevelLockCountMask) |
+ (1 + (TupleLevelLockCountMask & linfo->flags));
+ }
+
+ TransactionIdStore(curXact, &linfo->transactionIdData);
+
+ /* ----------------
+ * Lock the tuple.
+ * ----------------
+ */
+ MultiLockTuple(linfo, itemPointer, READ_LOCK);
+}
+
+/* ----------------
+ * RelationSetLockForReadPage
+ * ----------------
+ */
+#ifdef LOCKDEBUG
+#define LOCKDEBUG_90 \
+elog(DEBUG, "RelationSetLockForReadPage(%s[%d,%d], @%d) called", \
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, page);
+#else
+#define LOCKDEBUG_90
+#endif /* LOCKDEBUG*/
+
+/* ----------------
+ * RelationSetLockForWritePage
+ * ----------------
+ */
+#ifdef LOCKDEBUG
+#define LOCKDEBUG_100 \
+elog(DEBUG, "RelationSetLockForWritePage(%s[%d,%d], @%d) called", \
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.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 linfo is initialized
+ * ---------------
+ */
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ /* ----------------
+ * attempt to set lock
+ * ----------------
+ */
+ MultiLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK);
+}
+
+/* ----------------
+ * RelationUnsetLockForReadPage
+ * ----------------
+ */
+#ifdef LOCKDEBUG
+#define LOCKDEBUG_110 \
+elog(DEBUG, "RelationUnsetLockForReadPage(%s[%d,%d], @%d) called", \
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, page)
+#else
+#define LOCKDEBUG_110
+#endif /* LOCKDEBUG */
+
+/* ----------------
+ * RelationUnsetLockForWritePage
+ * ----------------
+ */
+#ifdef LOCKDEBUG
+#define LOCKDEBUG_120 \
+elog(DEBUG, "RelationUnsetLockForWritePage(%s[%d,%d], @%d) called", \
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.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)
+{
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ SingleLockPage((LockInfo)relation->lockInfo, itemPointer, WRITE_LOCK, !UNLOCK);
+}
+
+/*
+ * Unset a single level write page lock
+ */
+void
+RelationUnsetSingleWLockPage(Relation relation,
+ ItemPointer itemPointer)
+{
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ elog(WARN,
+ "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(WARN,
+ "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);
+
+ SingleLockReln((LockInfo)relation->lockInfo, READ_LOCK+INTENT, UNLOCK);
+}
+
+/*
+ * Set a write intent lock on a relation. For a more complete explanation
+ * see RelationSetRIntentLock()
+ */
+void
+RelationSetWIntentLock(Relation relation)
+{
+ /* -----------------
+ * Sanity check
+ * -----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ 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);
+
+ SingleLockReln((LockInfo)relation->lockInfo, WRITE_LOCK+INTENT, UNLOCK);
+}
+
+/*
+ * 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.
+ */
+void
+RelationSetLockForExtend(Relation relation)
+{
+ /* -----------------
+ * Sanity check
+ * -----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ MultiLockReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
+}
+
+void
+RelationUnsetLockForExtend(Relation relation)
+{
+ /* -----------------
+ * Sanity check
+ * -----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ MultiReleaseReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
+}
+
+/*
+ * Create an LRelid --- Why not just pass in a pointer to the storage?
+ */
+void
+LRelIdAssign(LRelId *lRelId, Oid dbId, Oid relId)
+{
+ lRelId->dbId = dbId;
+ lRelId->relId = relId;
+}