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.17 1998/08/19 02:02:40 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/palloc.h"
39 #include "utils/mcxt.h"
40 #include "utils/rel.h"
42 #include "catalog/catname.h"
43 #include "catalog/catalog.h"
45 #include "catalog/pg_class_mb.h"
47 #include "catalog/pg_class.h"
50 #include "nodes/memnodes.h"
51 #include "storage/bufmgr.h"
52 #include "access/transam.h" /* for AmiTransactionId */
54 extern Oid MyDatabaseId;
57 * RelationInitLockInfo --
58 * Initializes the lock information in a relation descriptor.
61 RelationInitLockInfo(Relation relation)
66 extern Oid MyDatabaseId; /* XXX use include */
67 extern GlobalMemory CacheCxt;
69 Assert(RelationIsValid(relation));
70 Assert(OidIsValid(RelationGetRelid(relation)));
72 info = (LockInfo) relation->lockInfo;
74 if (LockInfoIsValid(info))
77 relname = (char *) RelationGetRelationName(relation);
79 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
80 info = (LockInfo) palloc(sizeof(LockInfoData));
81 MemoryContextSwitchTo(oldcxt);
83 info->lockRelId.relId = RelationGetRelid(relation);
84 if (IsSharedSystemRelationName(relname))
85 info->lockRelId.dbId = InvalidOid;
87 info->lockRelId.dbId = MyDatabaseId;
89 #ifdef LowLevelLocking
90 memset(info->lockHeld, 0, sizeof(info->lockHeld));
93 relation->lockInfo = (Pointer) info;
97 * RelationSetLockForDescriptorOpen --
98 * Sets read locks for a relation descriptor.
101 #define LOCKDEBUGALL_30 \
102 elog(DEBUG, "RelationSetLockForDescriptorOpen(%s[%d,%d]) called", \
103 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
105 #define LOCKDEBUGALL_30
106 #endif /* LOCKDEBUGALL */
109 RelationSetLockForDescriptorOpen(Relation relation)
115 Assert(RelationIsValid(relation));
116 if (LockingDisabled())
122 * read lock catalog tuples which compose the relation descriptor
123 * XXX race condition? XXX For now, do nothing.
129 * RelationSetLockForRead
133 #define LOCKDEBUG_40 \
134 elog(DEBUG, "RelationSetLockForRead(%s[%d,%d]) called", \
135 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
138 #endif /* LOCKDEBUG */
141 * RelationSetLockForRead --
142 * Sets relation level read lock.
145 RelationSetLockForRead(Relation relation)
153 Assert(RelationIsValid(relation));
154 if (LockingDisabled())
160 * If we don't have lock info on the reln just go ahead and
161 * lock it without trying to short circuit the lock manager.
164 if (!LockInfoIsValid(relation->lockInfo))
166 RelationInitLockInfo(relation);
167 lockinfo = (LockInfo) relation->lockInfo;
168 MultiLockReln(lockinfo, READ_LOCK);
172 lockinfo = (LockInfo) relation->lockInfo;
174 MultiLockReln(lockinfo, READ_LOCK);
178 * RelationUnsetLockForRead
182 #define LOCKDEBUG_50 \
183 elog(DEBUG, "RelationUnsetLockForRead(%s[%d,%d]) called", \
184 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
187 #endif /* LOCKDEBUG */
190 * RelationUnsetLockForRead --
191 * Unsets relation level read lock.
194 RelationUnsetLockForRead(Relation relation)
202 Assert(RelationIsValid(relation));
203 if (LockingDisabled())
206 lockinfo = (LockInfo) relation->lockInfo;
209 * If we don't have lock info on the reln just go ahead and
213 if (!LockInfoIsValid(lockinfo))
216 "Releasing a lock on %s with invalid lock information",
217 RelationGetRelationName(relation));
220 MultiReleaseReln(lockinfo, READ_LOCK);
224 * RelationSetLockForWrite(relation)
228 #define LOCKDEBUG_60 \
229 elog(DEBUG, "RelationSetLockForWrite(%s[%d,%d]) called", \
230 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
233 #endif /* LOCKDEBUG */
236 * RelationSetLockForWrite --
237 * Sets relation level write lock.
240 RelationSetLockForWrite(Relation relation)
248 Assert(RelationIsValid(relation));
249 if (LockingDisabled())
255 * If we don't have lock info on the reln just go ahead and
256 * lock it without trying to short circuit the lock manager.
259 if (!LockInfoIsValid(relation->lockInfo))
261 RelationInitLockInfo(relation);
262 lockinfo = (LockInfo) relation->lockInfo;
263 MultiLockReln(lockinfo, WRITE_LOCK);
267 lockinfo = (LockInfo) relation->lockInfo;
269 MultiLockReln(lockinfo, WRITE_LOCK);
273 * RelationUnsetLockForWrite
277 #define LOCKDEBUG_70 \
278 elog(DEBUG, "RelationUnsetLockForWrite(%s[%d,%d]) called", \
279 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
282 #endif /* LOCKDEBUG */
285 * RelationUnsetLockForWrite --
286 * Unsets relation level write lock.
289 RelationUnsetLockForWrite(Relation relation)
297 Assert(RelationIsValid(relation));
298 if (LockingDisabled())
301 lockinfo = (LockInfo) relation->lockInfo;
303 if (!LockInfoIsValid(lockinfo))
306 "Releasing a lock on %s with invalid lock information",
307 RelationGetRelationName(relation));
310 MultiReleaseReln(lockinfo, WRITE_LOCK);
314 * RelationSetLockForReadPage
318 #define LOCKDEBUG_90 \
319 elog(DEBUG, "RelationSetLockForReadPage(%s[%d,%d], @%d) called", \
320 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
323 #endif /* LOCKDEBUG */
326 * RelationSetLockForWritePage
330 #define LOCKDEBUG_100 \
331 elog(DEBUG, "RelationSetLockForWritePage(%s[%d,%d], @%d) called", \
332 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
334 #define LOCKDEBUG_100
335 #endif /* LOCKDEBUG */
338 * RelationSetLockForWritePage --
339 * Sets write lock on a page.
342 RelationSetLockForWritePage(Relation relation,
343 ItemPointer itemPointer)
349 Assert(RelationIsValid(relation));
350 if (LockingDisabled())
354 * Make sure lockinfo is initialized
357 if (!LockInfoIsValid(relation->lockInfo))
358 RelationInitLockInfo(relation);
361 * attempt to set lock
364 MultiLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK);
368 * RelationUnsetLockForReadPage
372 #define LOCKDEBUG_110 \
373 elog(DEBUG, "RelationUnsetLockForReadPage(%s[%d,%d], @%d) called", \
374 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
376 #define LOCKDEBUG_110
377 #endif /* LOCKDEBUG */
380 * RelationUnsetLockForWritePage
384 #define LOCKDEBUG_120 \
385 elog(DEBUG, "RelationUnsetLockForWritePage(%s[%d,%d], @%d) called", \
386 RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
388 #define LOCKDEBUG_120
389 #endif /* LOCKDEBUG */
392 * Set a single level write page lock. Assumes that you already
393 * have a write intent lock on the relation.
396 RelationSetSingleWLockPage(Relation relation,
397 ItemPointer itemPointer)
404 Assert(RelationIsValid(relation));
405 if (LockingDisabled())
408 if (!LockInfoIsValid(relation->lockInfo))
409 RelationInitLockInfo(relation);
411 SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, !UNLOCK);
415 * Unset a single level write page lock
418 RelationUnsetSingleWLockPage(Relation relation,
419 ItemPointer itemPointer)
426 Assert(RelationIsValid(relation));
427 if (LockingDisabled())
430 if (!LockInfoIsValid(relation->lockInfo))
432 "Releasing a lock on %s with invalid lock information",
433 RelationGetRelationName(relation));
435 SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, UNLOCK);
439 * Set a single level read page lock. Assumes you already have a read
440 * intent lock set on the relation.
443 RelationSetSingleRLockPage(Relation relation,
444 ItemPointer itemPointer)
451 Assert(RelationIsValid(relation));
452 if (LockingDisabled())
455 if (!LockInfoIsValid(relation->lockInfo))
456 RelationInitLockInfo(relation);
458 SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, !UNLOCK);
462 * Unset a single level read page lock.
465 RelationUnsetSingleRLockPage(Relation relation,
466 ItemPointer itemPointer)
473 Assert(RelationIsValid(relation));
474 if (LockingDisabled())
477 if (!LockInfoIsValid(relation->lockInfo))
479 "Releasing a lock on %s with invalid lock information",
480 RelationGetRelationName(relation));
482 SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, UNLOCK);
486 * Set a read intent lock on a relation.
488 * Usually these are set in a multi-level table when you acquiring a
489 * page level lock. i.e. To acquire a lock on a page you first acquire
490 * an intent lock on the entire relation. Acquiring an intent lock along
491 * allows one to use the single level locking routines later. Good for
492 * index scans that do a lot of page level locking.
495 RelationSetRIntentLock(Relation relation)
501 Assert(RelationIsValid(relation));
502 if (LockingDisabled())
505 if (!LockInfoIsValid(relation->lockInfo))
506 RelationInitLockInfo(relation);
508 SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, !UNLOCK);
512 * Unset a read intent lock on a relation
515 RelationUnsetRIntentLock(Relation relation)
521 Assert(RelationIsValid(relation));
522 if (LockingDisabled())
525 if (!LockInfoIsValid(relation->lockInfo))
526 RelationInitLockInfo(relation);
528 SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, UNLOCK);
532 * Set a write intent lock on a relation. For a more complete explanation
533 * see RelationSetRIntentLock()
536 RelationSetWIntentLock(Relation relation)
542 Assert(RelationIsValid(relation));
543 if (LockingDisabled())
546 if (!LockInfoIsValid(relation->lockInfo))
547 RelationInitLockInfo(relation);
549 SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, !UNLOCK);
553 * Unset a write intent lock.
556 RelationUnsetWIntentLock(Relation relation)
562 Assert(RelationIsValid(relation));
563 if (LockingDisabled())
566 if (!LockInfoIsValid(relation->lockInfo))
567 RelationInitLockInfo(relation);
569 SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, UNLOCK);
573 * Extend locks are used primarily in tertiary storage devices such as
574 * a WORM disk jukebox. Sometimes need exclusive access to extend a
579 RelationSetLockForExtend(Relation relation)
585 Assert(RelationIsValid(relation));
586 if (LockingDisabled())
589 if (!LockInfoIsValid(relation->lockInfo))
590 RelationInitLockInfo(relation);
592 MultiLockReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
599 RelationUnsetLockForExtend(Relation relation)
605 Assert(RelationIsValid(relation));
606 if (LockingDisabled())
609 if (!LockInfoIsValid(relation->lockInfo))
610 RelationInitLockInfo(relation);
612 MultiReleaseReln((LockInfo) relation->lockInfo, EXTEND_LOCK);