1 /*-------------------------------------------------------------------------
4 * POSTGRES lock manager code
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.28 1999/07/15 15:19:51 momjian Exp $
12 *-------------------------------------------------------------------------
14 /* #define LOCKDEBUGALL 1 */
15 /* #define LOCKDEBUG 1 */
19 #endif /* LOCKDEBUGALL */
25 #include "access/heapam.h"
26 #include "access/htup.h"
27 #include "access/relscan.h"
28 #include "access/skey.h"
29 #include "access/xact.h"
31 #include "storage/block.h"
32 #include "storage/buf.h"
33 #include "storage/itemptr.h"
34 #include "storage/bufpage.h"
35 #include "storage/multilev.h"
36 #include "storage/lmgr.h"
38 #include "utils/rel.h"
40 #include "catalog/catname.h"
41 #include "catalog/catalog.h"
42 #include "catalog/pg_class.h"
44 #include "nodes/memnodes.h"
45 #include "storage/bufmgr.h"
46 #include "access/transam.h" /* for AmiTransactionId */
48 extern Oid MyDatabaseId;
50 static MASK LockConflicts[] = {
54 (1 << AccessExclusiveLock),
57 (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
59 /* RowExclusiveLock */
60 (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
61 (1 << AccessExclusiveLock),
64 (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
65 (1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
67 /* ShareRowExclusiveLock */
68 (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
69 (1 << ShareLock) | (1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
72 (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
73 (1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock),
75 /* AccessExclusiveLock */
76 (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
77 (1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock) |
78 (1 << AccessShareLock),
82 static int LockPrios[] = {
93 LOCKMETHOD LockTableId = (LOCKMETHOD) NULL;
94 LOCKMETHOD LongTermTableId = (LOCKMETHOD) NULL;
97 * Create the lock table described by LockConflicts and LockPrios.
104 lockmethod = LockMethodTableInit("LockTable",
105 LockConflicts, LockPrios, MAX_LOCKMODES - 1);
106 LockTableId = lockmethod;
109 elog(ERROR, "InitLockTable: couldnt initialize lock table");
114 * Allocate another tableId for long-term locks
116 LongTermTableId = LockMethodTableRename(LockTableId);
117 if (!(LongTermTableId))
120 "InitLockTable: couldn't rename long-term lock table");
128 * RelationInitLockInfo
129 * Initializes the lock information in a relation descriptor.
132 RelationInitLockInfo(Relation relation)
136 MemoryContext oldcxt;
137 extern Oid MyDatabaseId; /* XXX use include */
138 extern GlobalMemory CacheCxt;
140 Assert(RelationIsValid(relation));
141 Assert(OidIsValid(RelationGetRelid(relation)));
143 info = (LockInfo) relation->lockInfo;
145 if (LockInfoIsValid(info))
148 relname = (char *) RelationGetRelationName(relation);
150 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
151 info = (LockInfo) palloc(sizeof(LockInfoData));
152 MemoryContextSwitchTo(oldcxt);
154 info->lockRelId.relId = RelationGetRelid(relation);
155 if (IsSharedSystemRelationName(relname))
156 info->lockRelId.dbId = InvalidOid;
158 info->lockRelId.dbId = MyDatabaseId;
160 relation->lockInfo = (Pointer) info;
167 LockRelation(Relation relation, LOCKMODE lockmode)
172 if (LockingDisabled())
175 if (!LockInfoIsValid(relation->lockInfo))
176 RelationInitLockInfo(relation);
178 lockinfo = (LockInfo) relation->lockInfo;
180 MemSet(&tag, 0, sizeof(tag));
181 tag.relId = lockinfo->lockRelId.relId;
182 tag.dbId = lockinfo->lockRelId.dbId;
183 tag.objId.blkno = InvalidBlockNumber;
185 LockAcquire(LockTableId, &tag, lockmode);
193 UnlockRelation(Relation relation, LOCKMODE lockmode)
198 if (LockingDisabled())
201 lockinfo = (LockInfo) relation->lockInfo;
203 if (!LockInfoIsValid(lockinfo))
206 "Releasing a lock on %s with invalid lock information",
207 RelationGetRelationName(relation));
210 MemSet(&tag, 0, sizeof(tag));
211 tag.relId = lockinfo->lockRelId.relId;
212 tag.dbId = lockinfo->lockRelId.dbId;
213 tag.objId.blkno = InvalidBlockNumber;
215 LockRelease(LockTableId, &tag, lockmode);
223 LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
228 if (LockingDisabled())
231 if (!LockInfoIsValid(relation->lockInfo))
232 RelationInitLockInfo(relation);
234 lockinfo = (LockInfo) relation->lockInfo;
236 MemSet(&tag, 0, sizeof(tag));
237 tag.relId = lockinfo->lockRelId.relId;
238 tag.dbId = lockinfo->lockRelId.dbId;
239 tag.objId.blkno = blkno;
241 LockAcquire(LockTableId, &tag, lockmode);
249 UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
254 if (LockingDisabled())
257 lockinfo = (LockInfo) relation->lockInfo;
259 if (!LockInfoIsValid(lockinfo))
262 "Releasing a lock on %s with invalid lock information",
263 RelationGetRelationName(relation));
266 MemSet(&tag, 0, sizeof(tag));
267 tag.relId = lockinfo->lockRelId.relId;
268 tag.dbId = lockinfo->lockRelId.dbId;
269 tag.objId.blkno = blkno;
271 LockRelease(LockTableId, &tag, lockmode);
276 XactLockTableInsert(TransactionId xid)
280 if (LockingDisabled())
283 MemSet(&tag, 0, sizeof(tag));
284 tag.relId = XactLockTableId;
285 tag.dbId = InvalidOid;
288 LockAcquire(LockTableId, &tag, ExclusiveLock);
293 XactLockTableDelete(TransactionId xid)
297 if (LockingDisabled())
300 MemSet(&tag, 0, sizeof(tag));
301 tag.relId = XactLockTableId;
302 tag.dbId = InvalidOid;
305 LockRelease(LockTableId, &tag, ExclusiveLock);
310 XactLockTableWait(TransactionId xid)
314 if (LockingDisabled())
317 MemSet(&tag, 0, sizeof(tag));
318 tag.relId = XactLockTableId;
319 tag.dbId = InvalidOid;
322 LockAcquire(LockTableId, &tag, ShareLock);
323 LockRelease(LockTableId, &tag, ShareLock);
326 * Transaction was committed/aborted/crashed - we have to update
327 * pg_log if transaction is still marked as running.
329 if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
330 TransactionIdAbort(xid);