1 /*-------------------------------------------------------------------------
4 * POSTGRES lock manager code
6 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.85 2006/07/14 16:59:19 tgl Exp $
13 *-------------------------------------------------------------------------
18 #include "access/subtrans.h"
19 #include "access/transam.h"
20 #include "access/xact.h"
21 #include "miscadmin.h"
22 #include "storage/lmgr.h"
23 #include "storage/procarray.h"
24 #include "utils/inval.h"
28 * RelationInitLockInfo
29 * Initializes the lock information in a relation descriptor.
31 * relcache.c must call this during creation of any reldesc.
34 RelationInitLockInfo(Relation relation)
36 Assert(RelationIsValid(relation));
37 Assert(OidIsValid(RelationGetRelid(relation)));
39 relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
41 if (relation->rd_rel->relisshared)
42 relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
44 relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
51 LockRelation(Relation relation, LOCKMODE lockmode)
54 LockAcquireResult res;
56 SET_LOCKTAG_RELATION(tag,
57 relation->rd_lockInfo.lockRelId.dbId,
58 relation->rd_lockInfo.lockRelId.relId);
60 res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
63 * Check to see if the relcache entry has been invalidated while we were
64 * waiting to lock it. If so, rebuild it, or ereport() trying. Increment
65 * the refcount to ensure that RelationFlushRelation will rebuild it and
66 * not just delete it. We can skip this if the lock was already held,
69 if (res != LOCKACQUIRE_ALREADY_HELD)
71 RelationIncrementReferenceCount(relation);
72 AcceptInvalidationMessages();
73 RelationDecrementReferenceCount(relation);
78 * ConditionalLockRelation
80 * As above, but only lock if we can get the lock without blocking.
81 * Returns TRUE iff the lock was acquired.
83 * NOTE: we do not currently need conditional versions of all the
84 * LockXXX routines in this file, but they could easily be added if needed.
87 ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
90 LockAcquireResult res;
92 SET_LOCKTAG_RELATION(tag,
93 relation->rd_lockInfo.lockRelId.dbId,
94 relation->rd_lockInfo.lockRelId.relId);
96 res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, true);
98 if (res == LOCKACQUIRE_NOT_AVAIL)
102 * Check to see if the relcache entry has been invalidated while we were
103 * waiting to lock it. If so, rebuild it, or ereport() trying. Increment
104 * the refcount to ensure that RelationFlushRelation will rebuild it and
105 * not just delete it. We can skip this if the lock was already held,
108 if (res != LOCKACQUIRE_ALREADY_HELD)
110 RelationIncrementReferenceCount(relation);
111 AcceptInvalidationMessages();
112 RelationDecrementReferenceCount(relation);
122 UnlockRelation(Relation relation, LOCKMODE lockmode)
126 SET_LOCKTAG_RELATION(tag,
127 relation->rd_lockInfo.lockRelId.dbId,
128 relation->rd_lockInfo.lockRelId.relId);
130 LockRelease(&tag, lockmode, false);
134 * LockRelationForSession
136 * This routine grabs a session-level lock on the target relation. The
137 * session lock persists across transaction boundaries. It will be removed
138 * when UnlockRelationForSession() is called, or if an ereport(ERROR) occurs,
139 * or if the backend exits.
141 * Note that one should also grab a transaction-level lock on the rel
142 * in any transaction that actually uses the rel, to ensure that the
143 * relcache entry is up to date.
146 LockRelationForSession(LockRelId *relid, bool istemprel, LOCKMODE lockmode)
150 SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
152 (void) LockAcquire(&tag, istemprel, lockmode, true, false);
156 * UnlockRelationForSession
159 UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
163 SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
165 LockRelease(&tag, lockmode, true);
169 * LockRelationForExtension
171 * This lock tag is used to interlock addition of pages to relations.
172 * We need such locking because bufmgr/smgr definition of P_NEW is not
173 * race-condition-proof.
175 * We assume the caller is already holding some type of regular lock on
176 * the relation, so no AcceptInvalidationMessages call is needed here.
179 LockRelationForExtension(Relation relation, LOCKMODE lockmode)
183 SET_LOCKTAG_RELATION_EXTEND(tag,
184 relation->rd_lockInfo.lockRelId.dbId,
185 relation->rd_lockInfo.lockRelId.relId);
187 (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
191 * UnlockRelationForExtension
194 UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
198 SET_LOCKTAG_RELATION_EXTEND(tag,
199 relation->rd_lockInfo.lockRelId.dbId,
200 relation->rd_lockInfo.lockRelId.relId);
202 LockRelease(&tag, lockmode, false);
208 * Obtain a page-level lock. This is currently used by some index access
209 * methods to lock individual index pages.
212 LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
216 SET_LOCKTAG_PAGE(tag,
217 relation->rd_lockInfo.lockRelId.dbId,
218 relation->rd_lockInfo.lockRelId.relId,
221 (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
225 * ConditionalLockPage
227 * As above, but only lock if we can get the lock without blocking.
228 * Returns TRUE iff the lock was acquired.
231 ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
235 SET_LOCKTAG_PAGE(tag,
236 relation->rd_lockInfo.lockRelId.dbId,
237 relation->rd_lockInfo.lockRelId.relId,
240 return (LockAcquire(&tag, relation->rd_istemp,
241 lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
248 UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
252 SET_LOCKTAG_PAGE(tag,
253 relation->rd_lockInfo.lockRelId.dbId,
254 relation->rd_lockInfo.lockRelId.relId,
257 LockRelease(&tag, lockmode, false);
263 * Obtain a tuple-level lock. This is used in a less-than-intuitive fashion
264 * because we can't afford to keep a separate lock in shared memory for every
265 * tuple. See heap_lock_tuple before using this!
268 LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
272 SET_LOCKTAG_TUPLE(tag,
273 relation->rd_lockInfo.lockRelId.dbId,
274 relation->rd_lockInfo.lockRelId.relId,
275 ItemPointerGetBlockNumber(tid),
276 ItemPointerGetOffsetNumber(tid));
278 (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
282 * ConditionalLockTuple
284 * As above, but only lock if we can get the lock without blocking.
285 * Returns TRUE iff the lock was acquired.
288 ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
292 SET_LOCKTAG_TUPLE(tag,
293 relation->rd_lockInfo.lockRelId.dbId,
294 relation->rd_lockInfo.lockRelId.relId,
295 ItemPointerGetBlockNumber(tid),
296 ItemPointerGetOffsetNumber(tid));
298 return (LockAcquire(&tag, relation->rd_istemp,
299 lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
306 UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
310 SET_LOCKTAG_TUPLE(tag,
311 relation->rd_lockInfo.lockRelId.dbId,
312 relation->rd_lockInfo.lockRelId.relId,
313 ItemPointerGetBlockNumber(tid),
314 ItemPointerGetOffsetNumber(tid));
316 LockRelease(&tag, lockmode, false);
320 * XactLockTableInsert
322 * Insert a lock showing that the given transaction ID is running ---
323 * this is done during xact startup. The lock can then be used to wait
324 * for the transaction to finish.
327 XactLockTableInsert(TransactionId xid)
331 SET_LOCKTAG_TRANSACTION(tag, xid);
333 (void) LockAcquire(&tag, false, ExclusiveLock, false, false);
337 * XactLockTableDelete
339 * Delete the lock showing that the given transaction ID is running.
340 * (This is never used for main transaction IDs; those locks are only
341 * released implicitly at transaction end. But we do use it for subtrans
345 XactLockTableDelete(TransactionId xid)
349 SET_LOCKTAG_TRANSACTION(tag, xid);
351 LockRelease(&tag, ExclusiveLock, false);
357 * Wait for the specified transaction to commit or abort.
359 * Note that this does the right thing for subtransactions: if we wait on a
360 * subtransaction, we will exit as soon as it aborts or its top parent commits.
361 * It takes some extra work to ensure this, because to save on shared memory
362 * the XID lock of a subtransaction is released when it ends, whether
363 * successfully or unsuccessfully. So we have to check if it's "still running"
364 * and if so wait for its parent.
367 XactLockTableWait(TransactionId xid)
373 Assert(TransactionIdIsValid(xid));
374 Assert(!TransactionIdEquals(xid, GetTopTransactionId()));
376 SET_LOCKTAG_TRANSACTION(tag, xid);
378 (void) LockAcquire(&tag, false, ShareLock, false, false);
380 LockRelease(&tag, ShareLock, false);
382 if (!TransactionIdIsInProgress(xid))
384 xid = SubTransGetParent(xid);
389 * ConditionalXactLockTableWait
391 * As above, but only lock if we can get the lock without blocking.
392 * Returns TRUE if the lock was acquired.
395 ConditionalXactLockTableWait(TransactionId xid)
401 Assert(TransactionIdIsValid(xid));
402 Assert(!TransactionIdEquals(xid, GetTopTransactionId()));
404 SET_LOCKTAG_TRANSACTION(tag, xid);
406 if (LockAcquire(&tag, false,
407 ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
410 LockRelease(&tag, ShareLock, false);
412 if (!TransactionIdIsInProgress(xid))
414 xid = SubTransGetParent(xid);
423 * Obtain a lock on a general object of the current database. Don't use
424 * this for shared objects (such as tablespaces). It's unwise to apply it
425 * to relations, also, since a lock taken this way will NOT conflict with
426 * LockRelation, and also may be wrongly marked if the relation is temp.
427 * (If we ever invent temp objects that aren't tables, we'll want to extend
428 * the API of this routine to include an isTempObject flag.)
431 LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
436 SET_LOCKTAG_OBJECT(tag,
442 (void) LockAcquire(&tag, false, lockmode, false, false);
446 * UnlockDatabaseObject
449 UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
454 SET_LOCKTAG_OBJECT(tag,
460 LockRelease(&tag, lockmode, false);
466 * Obtain a lock on a shared-across-databases object.
469 LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
474 SET_LOCKTAG_OBJECT(tag,
480 (void) LockAcquire(&tag, false, lockmode, false, false);
482 /* Make sure syscaches are up-to-date with any changes we waited for */
483 AcceptInvalidationMessages();
490 UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
495 SET_LOCKTAG_OBJECT(tag,
501 LockRelease(&tag, lockmode, false);