mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
Postgres95 1.01 Distribution - Virgin Sources
This commit is contained in:
933
src/backend/storage/lmgr/lmgr.c
Normal file
933
src/backend/storage/lmgr/lmgr.c
Normal file
@@ -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;
|
||||
}
|
Reference in New Issue
Block a user