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.26 1999/05/31 01:48:13 vadim 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/palloc.h"
39 #include "utils/mcxt.h"
40 #include "utils/rel.h"
42 #include "catalog/catname.h"
43 #include "catalog/catalog.h"
44 #include "catalog/pg_class.h"
46 #include "nodes/memnodes.h"
47 #include "storage/bufmgr.h"
48 #include "access/transam.h" /* for AmiTransactionId */
50 extern Oid MyDatabaseId;
52 static MASK LockConflicts[] = {
56 (1 << AccessExclusiveLock),
59 (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
61 /* RowExclusiveLock */
62 (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
63 (1 << AccessExclusiveLock),
66 (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
67 (1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
69 /* ShareRowExclusiveLock */
70 (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
71 (1 << ShareLock) | (1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
74 (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
75 (1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock),
77 /* AccessExclusiveLock */
78 (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
79 (1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock) |
80 (1 << AccessShareLock),
84 static int LockPrios[] = {
95 LOCKMETHOD LockTableId = (LOCKMETHOD) NULL;
96 LOCKMETHOD LongTermTableId = (LOCKMETHOD) NULL;
99 * Create the lock table described by LockConflicts and LockPrios.
106 lockmethod = LockMethodTableInit("LockTable",
107 LockConflicts, LockPrios, MAX_LOCKMODES - 1);
108 LockTableId = lockmethod;
111 elog(ERROR, "InitLockTable: couldnt initialize lock table");
116 * Allocate another tableId for long-term locks
118 LongTermTableId = LockMethodTableRename(LockTableId);
119 if (!(LongTermTableId))
122 "InitLockTable: couldn't rename long-term lock table");
130 * RelationInitLockInfo
131 * Initializes the lock information in a relation descriptor.
134 RelationInitLockInfo(Relation relation)
138 MemoryContext oldcxt;
139 extern Oid MyDatabaseId; /* XXX use include */
140 extern GlobalMemory CacheCxt;
142 Assert(RelationIsValid(relation));
143 Assert(OidIsValid(RelationGetRelid(relation)));
145 info = (LockInfo) relation->lockInfo;
147 if (LockInfoIsValid(info))
150 relname = (char *) RelationGetRelationName(relation);
152 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
153 info = (LockInfo) palloc(sizeof(LockInfoData));
154 MemoryContextSwitchTo(oldcxt);
156 info->lockRelId.relId = RelationGetRelid(relation);
157 if (IsSharedSystemRelationName(relname))
158 info->lockRelId.dbId = InvalidOid;
160 info->lockRelId.dbId = MyDatabaseId;
162 relation->lockInfo = (Pointer) info;
169 LockRelation(Relation relation, LOCKMODE lockmode)
174 if (LockingDisabled())
177 if (!LockInfoIsValid(relation->lockInfo))
178 RelationInitLockInfo(relation);
180 lockinfo = (LockInfo) relation->lockInfo;
182 MemSet(&tag, 0, sizeof(tag));
183 tag.relId = lockinfo->lockRelId.relId;
184 tag.dbId = lockinfo->lockRelId.dbId;
185 tag.objId.blkno = InvalidBlockNumber;
187 LockAcquire(LockTableId, &tag, lockmode);
195 UnlockRelation(Relation relation, LOCKMODE lockmode)
200 if (LockingDisabled())
203 lockinfo = (LockInfo) relation->lockInfo;
205 if (!LockInfoIsValid(lockinfo))
208 "Releasing a lock on %s with invalid lock information",
209 RelationGetRelationName(relation));
212 MemSet(&tag, 0, sizeof(tag));
213 tag.relId = lockinfo->lockRelId.relId;
214 tag.dbId = lockinfo->lockRelId.dbId;
215 tag.objId.blkno = InvalidBlockNumber;
217 LockRelease(LockTableId, &tag, lockmode);
225 LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
230 if (LockingDisabled())
233 if (!LockInfoIsValid(relation->lockInfo))
234 RelationInitLockInfo(relation);
236 lockinfo = (LockInfo) relation->lockInfo;
238 MemSet(&tag, 0, sizeof(tag));
239 tag.relId = lockinfo->lockRelId.relId;
240 tag.dbId = lockinfo->lockRelId.dbId;
241 tag.objId.blkno = blkno;
243 LockAcquire(LockTableId, &tag, lockmode);
251 UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
256 if (LockingDisabled())
259 lockinfo = (LockInfo) relation->lockInfo;
261 if (!LockInfoIsValid(lockinfo))
264 "Releasing a lock on %s with invalid lock information",
265 RelationGetRelationName(relation));
268 MemSet(&tag, 0, sizeof(tag));
269 tag.relId = lockinfo->lockRelId.relId;
270 tag.dbId = lockinfo->lockRelId.dbId;
271 tag.objId.blkno = blkno;
273 LockRelease(LockTableId, &tag, lockmode);
278 XactLockTableInsert(TransactionId xid)
282 if (LockingDisabled())
285 MemSet(&tag, 0, sizeof(tag));
286 tag.relId = XactLockTableId;
287 tag.dbId = InvalidOid;
290 LockAcquire(LockTableId, &tag, ExclusiveLock);
295 XactLockTableDelete(TransactionId xid)
299 if (LockingDisabled())
302 MemSet(&tag, 0, sizeof(tag));
303 tag.relId = XactLockTableId;
304 tag.dbId = InvalidOid;
307 LockRelease(LockTableId, &tag, ExclusiveLock);
312 XactLockTableWait(TransactionId xid)
316 if (LockingDisabled())
319 MemSet(&tag, 0, sizeof(tag));
320 tag.relId = XactLockTableId;
321 tag.dbId = InvalidOid;
324 LockAcquire(LockTableId, &tag, ShareLock);
325 LockRelease(LockTableId, &tag, ShareLock);
327 TransactionIdFlushCache();
330 * Transaction was committed/aborted/crashed - we have to update
331 * pg_log if transaction is still marked as running.
333 if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
334 TransactionIdAbort(xid);