]> granicus.if.org Git - postgresql/blob - src/backend/storage/lmgr/lmgr.c
Fix another passel of include-file breakage. Kris Jurka, Tom Lane
[postgresql] / src / backend / storage / lmgr / lmgr.c
1 /*-------------------------------------------------------------------------
2  *
3  * lmgr.c
4  *        POSTGRES lock manager code
5  *
6  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.85 2006/07/14 16:59:19 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "postgres.h"
17
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"
25
26
27 /*
28  * RelationInitLockInfo
29  *              Initializes the lock information in a relation descriptor.
30  *
31  *              relcache.c must call this during creation of any reldesc.
32  */
33 void
34 RelationInitLockInfo(Relation relation)
35 {
36         Assert(RelationIsValid(relation));
37         Assert(OidIsValid(RelationGetRelid(relation)));
38
39         relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
40
41         if (relation->rd_rel->relisshared)
42                 relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
43         else
44                 relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
45 }
46
47 /*
48  *              LockRelation
49  */
50 void
51 LockRelation(Relation relation, LOCKMODE lockmode)
52 {
53         LOCKTAG         tag;
54         LockAcquireResult res;
55
56         SET_LOCKTAG_RELATION(tag,
57                                                  relation->rd_lockInfo.lockRelId.dbId,
58                                                  relation->rd_lockInfo.lockRelId.relId);
59
60         res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
61
62         /*
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,
67          * however.
68          */
69         if (res != LOCKACQUIRE_ALREADY_HELD)
70         {
71                 RelationIncrementReferenceCount(relation);
72                 AcceptInvalidationMessages();
73                 RelationDecrementReferenceCount(relation);
74         }
75 }
76
77 /*
78  *              ConditionalLockRelation
79  *
80  * As above, but only lock if we can get the lock without blocking.
81  * Returns TRUE iff the lock was acquired.
82  *
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.
85  */
86 bool
87 ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
88 {
89         LOCKTAG         tag;
90         LockAcquireResult res;
91
92         SET_LOCKTAG_RELATION(tag,
93                                                  relation->rd_lockInfo.lockRelId.dbId,
94                                                  relation->rd_lockInfo.lockRelId.relId);
95
96         res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, true);
97
98         if (res == LOCKACQUIRE_NOT_AVAIL)
99                 return false;
100
101         /*
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,
106          * however.
107          */
108         if (res != LOCKACQUIRE_ALREADY_HELD)
109         {
110                 RelationIncrementReferenceCount(relation);
111                 AcceptInvalidationMessages();
112                 RelationDecrementReferenceCount(relation);
113         }
114
115         return true;
116 }
117
118 /*
119  *              UnlockRelation
120  */
121 void
122 UnlockRelation(Relation relation, LOCKMODE lockmode)
123 {
124         LOCKTAG         tag;
125
126         SET_LOCKTAG_RELATION(tag,
127                                                  relation->rd_lockInfo.lockRelId.dbId,
128                                                  relation->rd_lockInfo.lockRelId.relId);
129
130         LockRelease(&tag, lockmode, false);
131 }
132
133 /*
134  *              LockRelationForSession
135  *
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.
140  *
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.
144  */
145 void
146 LockRelationForSession(LockRelId *relid, bool istemprel, LOCKMODE lockmode)
147 {
148         LOCKTAG         tag;
149
150         SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
151
152         (void) LockAcquire(&tag, istemprel, lockmode, true, false);
153 }
154
155 /*
156  *              UnlockRelationForSession
157  */
158 void
159 UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
160 {
161         LOCKTAG         tag;
162
163         SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
164
165         LockRelease(&tag, lockmode, true);
166 }
167
168 /*
169  *              LockRelationForExtension
170  *
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.
174  *
175  * We assume the caller is already holding some type of regular lock on
176  * the relation, so no AcceptInvalidationMessages call is needed here.
177  */
178 void
179 LockRelationForExtension(Relation relation, LOCKMODE lockmode)
180 {
181         LOCKTAG         tag;
182
183         SET_LOCKTAG_RELATION_EXTEND(tag,
184                                                                 relation->rd_lockInfo.lockRelId.dbId,
185                                                                 relation->rd_lockInfo.lockRelId.relId);
186
187         (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
188 }
189
190 /*
191  *              UnlockRelationForExtension
192  */
193 void
194 UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
195 {
196         LOCKTAG         tag;
197
198         SET_LOCKTAG_RELATION_EXTEND(tag,
199                                                                 relation->rd_lockInfo.lockRelId.dbId,
200                                                                 relation->rd_lockInfo.lockRelId.relId);
201
202         LockRelease(&tag, lockmode, false);
203 }
204
205 /*
206  *              LockPage
207  *
208  * Obtain a page-level lock.  This is currently used by some index access
209  * methods to lock individual index pages.
210  */
211 void
212 LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
213 {
214         LOCKTAG         tag;
215
216         SET_LOCKTAG_PAGE(tag,
217                                          relation->rd_lockInfo.lockRelId.dbId,
218                                          relation->rd_lockInfo.lockRelId.relId,
219                                          blkno);
220
221         (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
222 }
223
224 /*
225  *              ConditionalLockPage
226  *
227  * As above, but only lock if we can get the lock without blocking.
228  * Returns TRUE iff the lock was acquired.
229  */
230 bool
231 ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
232 {
233         LOCKTAG         tag;
234
235         SET_LOCKTAG_PAGE(tag,
236                                          relation->rd_lockInfo.lockRelId.dbId,
237                                          relation->rd_lockInfo.lockRelId.relId,
238                                          blkno);
239
240         return (LockAcquire(&tag, relation->rd_istemp,
241                                                 lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
242 }
243
244 /*
245  *              UnlockPage
246  */
247 void
248 UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
249 {
250         LOCKTAG         tag;
251
252         SET_LOCKTAG_PAGE(tag,
253                                          relation->rd_lockInfo.lockRelId.dbId,
254                                          relation->rd_lockInfo.lockRelId.relId,
255                                          blkno);
256
257         LockRelease(&tag, lockmode, false);
258 }
259
260 /*
261  *              LockTuple
262  *
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!
266  */
267 void
268 LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
269 {
270         LOCKTAG         tag;
271
272         SET_LOCKTAG_TUPLE(tag,
273                                           relation->rd_lockInfo.lockRelId.dbId,
274                                           relation->rd_lockInfo.lockRelId.relId,
275                                           ItemPointerGetBlockNumber(tid),
276                                           ItemPointerGetOffsetNumber(tid));
277
278         (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
279 }
280
281 /*
282  *              ConditionalLockTuple
283  *
284  * As above, but only lock if we can get the lock without blocking.
285  * Returns TRUE iff the lock was acquired.
286  */
287 bool
288 ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
289 {
290         LOCKTAG         tag;
291
292         SET_LOCKTAG_TUPLE(tag,
293                                           relation->rd_lockInfo.lockRelId.dbId,
294                                           relation->rd_lockInfo.lockRelId.relId,
295                                           ItemPointerGetBlockNumber(tid),
296                                           ItemPointerGetOffsetNumber(tid));
297
298         return (LockAcquire(&tag, relation->rd_istemp,
299                                                 lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
300 }
301
302 /*
303  *              UnlockTuple
304  */
305 void
306 UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
307 {
308         LOCKTAG         tag;
309
310         SET_LOCKTAG_TUPLE(tag,
311                                           relation->rd_lockInfo.lockRelId.dbId,
312                                           relation->rd_lockInfo.lockRelId.relId,
313                                           ItemPointerGetBlockNumber(tid),
314                                           ItemPointerGetOffsetNumber(tid));
315
316         LockRelease(&tag, lockmode, false);
317 }
318
319 /*
320  *              XactLockTableInsert
321  *
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.
325  */
326 void
327 XactLockTableInsert(TransactionId xid)
328 {
329         LOCKTAG         tag;
330
331         SET_LOCKTAG_TRANSACTION(tag, xid);
332
333         (void) LockAcquire(&tag, false, ExclusiveLock, false, false);
334 }
335
336 /*
337  *              XactLockTableDelete
338  *
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
342  * IDs.)
343  */
344 void
345 XactLockTableDelete(TransactionId xid)
346 {
347         LOCKTAG         tag;
348
349         SET_LOCKTAG_TRANSACTION(tag, xid);
350
351         LockRelease(&tag, ExclusiveLock, false);
352 }
353
354 /*
355  *              XactLockTableWait
356  *
357  * Wait for the specified transaction to commit or abort.
358  *
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.
365  */
366 void
367 XactLockTableWait(TransactionId xid)
368 {
369         LOCKTAG         tag;
370
371         for (;;)
372         {
373                 Assert(TransactionIdIsValid(xid));
374                 Assert(!TransactionIdEquals(xid, GetTopTransactionId()));
375
376                 SET_LOCKTAG_TRANSACTION(tag, xid);
377
378                 (void) LockAcquire(&tag, false, ShareLock, false, false);
379
380                 LockRelease(&tag, ShareLock, false);
381
382                 if (!TransactionIdIsInProgress(xid))
383                         break;
384                 xid = SubTransGetParent(xid);
385         }
386 }
387
388 /*
389  *              ConditionalXactLockTableWait
390  *
391  * As above, but only lock if we can get the lock without blocking.
392  * Returns TRUE if the lock was acquired.
393  */
394 bool
395 ConditionalXactLockTableWait(TransactionId xid)
396 {
397         LOCKTAG         tag;
398
399         for (;;)
400         {
401                 Assert(TransactionIdIsValid(xid));
402                 Assert(!TransactionIdEquals(xid, GetTopTransactionId()));
403
404                 SET_LOCKTAG_TRANSACTION(tag, xid);
405
406                 if (LockAcquire(&tag, false,
407                                                 ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
408                         return false;
409
410                 LockRelease(&tag, ShareLock, false);
411
412                 if (!TransactionIdIsInProgress(xid))
413                         break;
414                 xid = SubTransGetParent(xid);
415         }
416
417         return true;
418 }
419
420 /*
421  *              LockDatabaseObject
422  *
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.)
429  */
430 void
431 LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
432                                    LOCKMODE lockmode)
433 {
434         LOCKTAG         tag;
435
436         SET_LOCKTAG_OBJECT(tag,
437                                            MyDatabaseId,
438                                            classid,
439                                            objid,
440                                            objsubid);
441
442         (void) LockAcquire(&tag, false, lockmode, false, false);
443 }
444
445 /*
446  *              UnlockDatabaseObject
447  */
448 void
449 UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
450                                          LOCKMODE lockmode)
451 {
452         LOCKTAG         tag;
453
454         SET_LOCKTAG_OBJECT(tag,
455                                            MyDatabaseId,
456                                            classid,
457                                            objid,
458                                            objsubid);
459
460         LockRelease(&tag, lockmode, false);
461 }
462
463 /*
464  *              LockSharedObject
465  *
466  * Obtain a lock on a shared-across-databases object.
467  */
468 void
469 LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
470                                  LOCKMODE lockmode)
471 {
472         LOCKTAG         tag;
473
474         SET_LOCKTAG_OBJECT(tag,
475                                            InvalidOid,
476                                            classid,
477                                            objid,
478                                            objsubid);
479
480         (void) LockAcquire(&tag, false, lockmode, false, false);
481
482         /* Make sure syscaches are up-to-date with any changes we waited for */
483         AcceptInvalidationMessages();
484 }
485
486 /*
487  *              UnlockSharedObject
488  */
489 void
490 UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
491                                    LOCKMODE lockmode)
492 {
493         LOCKTAG         tag;
494
495         SET_LOCKTAG_OBJECT(tag,
496                                            InvalidOid,
497                                            classid,
498                                            objid,
499                                            objsubid);
500
501         LockRelease(&tag, lockmode, false);
502 }