]> granicus.if.org Git - postgresql/blob - src/backend/storage/lmgr/lmgr.c
heap_fetch requires buffer pointer, must be released; heap_getnext
[postgresql] / src / backend / storage / lmgr / lmgr.c
1 /*-------------------------------------------------------------------------
2  *
3  * lmgr.c--
4  *        POSTGRES lock manager code
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.17 1998/08/19 02:02:40 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /* #define LOCKDEBUGALL 1 */
15 /* #define LOCKDEBUG    1 */
16
17 #ifdef  LOCKDEBUGALL
18 #define LOCKDEBUG               1
19 #endif                                                  /* LOCKDEBUGALL */
20
21 #include <string.h>
22
23 #include "postgres.h"
24
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"
30
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"
37
38 #include "utils/palloc.h"
39 #include "utils/mcxt.h"
40 #include "utils/rel.h"
41
42 #include "catalog/catname.h"
43 #include "catalog/catalog.h"
44 #ifdef MULTIBYTE
45 #include "catalog/pg_class_mb.h"
46 #else
47 #include "catalog/pg_class.h"
48 #endif
49
50 #include "nodes/memnodes.h"
51 #include "storage/bufmgr.h"
52 #include "access/transam.h"             /* for AmiTransactionId */
53
54 extern Oid      MyDatabaseId;
55
56 /*
57  * RelationInitLockInfo --
58  *              Initializes the lock information in a relation descriptor.
59  */
60 void
61 RelationInitLockInfo(Relation relation)
62 {
63         LockInfo                        info;
64         char                       *relname;
65         MemoryContext           oldcxt;
66         extern Oid                      MyDatabaseId;   /* XXX use include */
67         extern GlobalMemory     CacheCxt;
68
69         Assert(RelationIsValid(relation));
70         Assert(OidIsValid(RelationGetRelid(relation)));
71
72         info = (LockInfo) relation->lockInfo;
73         
74         if (LockInfoIsValid(info))
75                 return;
76         
77         relname = (char *) RelationGetRelationName(relation);
78
79         oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
80         info = (LockInfo) palloc(sizeof(LockInfoData));
81         MemoryContextSwitchTo(oldcxt);
82
83         info->lockRelId.relId = RelationGetRelid(relation);
84         if (IsSharedSystemRelationName(relname))
85                 info->lockRelId.dbId = InvalidOid;
86         else
87                 info->lockRelId.dbId = MyDatabaseId;
88
89 #ifdef LowLevelLocking
90         memset(info->lockHeld, 0, sizeof(info->lockHeld));
91 #endif
92
93         relation->lockInfo = (Pointer) info;
94 }
95
96 /*
97  * RelationSetLockForDescriptorOpen --
98  *              Sets read locks for a relation descriptor.
99  */
100 #ifdef  LOCKDEBUGALL
101 #define LOCKDEBUGALL_30 \
102 elog(DEBUG, "RelationSetLockForDescriptorOpen(%s[%d,%d]) called", \
103          RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
104 #else
105 #define LOCKDEBUGALL_30
106 #endif                                                  /* LOCKDEBUGALL */
107
108 void
109 RelationSetLockForDescriptorOpen(Relation relation)
110 {
111         /* ----------------
112          *      sanity checks
113          * ----------------
114          */
115         Assert(RelationIsValid(relation));
116         if (LockingDisabled())
117                 return;
118
119         LOCKDEBUGALL_30;
120
121         /* ----------------
122          * read lock catalog tuples which compose the relation descriptor
123          * XXX race condition? XXX For now, do nothing.
124          * ----------------
125          */
126 }
127
128 /* ----------------
129  *              RelationSetLockForRead
130  * ----------------
131  */
132 #ifdef  LOCKDEBUG
133 #define LOCKDEBUG_40 \
134 elog(DEBUG, "RelationSetLockForRead(%s[%d,%d]) called", \
135          RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
136 #else
137 #define LOCKDEBUG_40
138 #endif                                                  /* LOCKDEBUG */
139
140 /*
141  * RelationSetLockForRead --
142  *              Sets relation level read lock.
143  */
144 void
145 RelationSetLockForRead(Relation relation)
146 {
147         LockInfo        lockinfo;
148
149         /* ----------------
150          *      sanity checks
151          * ----------------
152          */
153         Assert(RelationIsValid(relation));
154         if (LockingDisabled())
155                 return;
156
157         LOCKDEBUG_40;
158
159         /* ----------------
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.
162          * ----------------
163          */
164         if (!LockInfoIsValid(relation->lockInfo))
165         {
166                 RelationInitLockInfo(relation);
167                 lockinfo = (LockInfo) relation->lockInfo;
168                 MultiLockReln(lockinfo, READ_LOCK);
169                 return;
170         }
171         else
172                 lockinfo = (LockInfo) relation->lockInfo;
173
174         MultiLockReln(lockinfo, READ_LOCK);
175 }
176
177 /* ----------------
178  *              RelationUnsetLockForRead
179  * ----------------
180  */
181 #ifdef  LOCKDEBUG
182 #define LOCKDEBUG_50 \
183 elog(DEBUG, "RelationUnsetLockForRead(%s[%d,%d]) called", \
184          RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
185 #else
186 #define LOCKDEBUG_50
187 #endif                                                  /* LOCKDEBUG */
188
189 /*
190  * RelationUnsetLockForRead --
191  *              Unsets relation level read lock.
192  */
193 void
194 RelationUnsetLockForRead(Relation relation)
195 {
196         LockInfo        lockinfo;
197
198         /* ----------------
199          *      sanity check
200          * ----------------
201          */
202         Assert(RelationIsValid(relation));
203         if (LockingDisabled())
204                 return;
205
206         lockinfo = (LockInfo) relation->lockInfo;
207
208         /* ----------------
209          * If we don't have lock info on the reln just go ahead and
210          * release it.
211          * ----------------
212          */
213         if (!LockInfoIsValid(lockinfo))
214         {
215                 elog(ERROR,
216                          "Releasing a lock on %s with invalid lock information",
217                          RelationGetRelationName(relation));
218         }
219
220         MultiReleaseReln(lockinfo, READ_LOCK);
221 }
222
223 /* ----------------
224  *              RelationSetLockForWrite(relation)
225  * ----------------
226  */
227 #ifdef  LOCKDEBUG
228 #define LOCKDEBUG_60 \
229 elog(DEBUG, "RelationSetLockForWrite(%s[%d,%d]) called", \
230          RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
231 #else
232 #define LOCKDEBUG_60
233 #endif                                                  /* LOCKDEBUG */
234
235 /*
236  * RelationSetLockForWrite --
237  *              Sets relation level write lock.
238  */
239 void
240 RelationSetLockForWrite(Relation relation)
241 {
242         LockInfo        lockinfo;
243
244         /* ----------------
245          *      sanity checks
246          * ----------------
247          */
248         Assert(RelationIsValid(relation));
249         if (LockingDisabled())
250                 return;
251
252         LOCKDEBUG_60;
253
254         /* ----------------
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.
257          * ----------------
258          */
259         if (!LockInfoIsValid(relation->lockInfo))
260         {
261                 RelationInitLockInfo(relation);
262                 lockinfo = (LockInfo) relation->lockInfo;
263                 MultiLockReln(lockinfo, WRITE_LOCK);
264                 return;
265         }
266         else
267                 lockinfo = (LockInfo) relation->lockInfo;
268
269         MultiLockReln(lockinfo, WRITE_LOCK);
270 }
271
272 /* ----------------
273  *              RelationUnsetLockForWrite
274  * ----------------
275  */
276 #ifdef  LOCKDEBUG
277 #define LOCKDEBUG_70 \
278 elog(DEBUG, "RelationUnsetLockForWrite(%s[%d,%d]) called", \
279          RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId)
280 #else
281 #define LOCKDEBUG_70
282 #endif                                                  /* LOCKDEBUG */
283
284 /*
285  * RelationUnsetLockForWrite --
286  *              Unsets relation level write lock.
287  */
288 void
289 RelationUnsetLockForWrite(Relation relation)
290 {
291         LockInfo        lockinfo;
292
293         /* ----------------
294          *      sanity checks
295          * ----------------
296          */
297         Assert(RelationIsValid(relation));
298         if (LockingDisabled())
299                 return;
300
301         lockinfo = (LockInfo) relation->lockInfo;
302
303         if (!LockInfoIsValid(lockinfo))
304         {
305                 elog(ERROR,
306                          "Releasing a lock on %s with invalid lock information",
307                          RelationGetRelationName(relation));
308         }
309
310         MultiReleaseReln(lockinfo, WRITE_LOCK);
311 }
312
313 /* ----------------
314  *              RelationSetLockForReadPage
315  * ----------------
316  */
317 #ifdef  LOCKDEBUG
318 #define LOCKDEBUG_90 \
319 elog(DEBUG, "RelationSetLockForReadPage(%s[%d,%d], @%d) called", \
320          RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
321 #else
322 #define LOCKDEBUG_90
323 #endif                                                  /* LOCKDEBUG */
324
325 /* ----------------
326  *              RelationSetLockForWritePage
327  * ----------------
328  */
329 #ifdef  LOCKDEBUG
330 #define LOCKDEBUG_100 \
331 elog(DEBUG, "RelationSetLockForWritePage(%s[%d,%d], @%d) called", \
332          RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
333 #else
334 #define LOCKDEBUG_100
335 #endif                                                  /* LOCKDEBUG */
336
337 /*
338  * RelationSetLockForWritePage --
339  *              Sets write lock on a page.
340  */
341 void
342 RelationSetLockForWritePage(Relation relation,
343                                                         ItemPointer itemPointer)
344 {
345         /* ----------------
346          *      sanity checks
347          * ----------------
348          */
349         Assert(RelationIsValid(relation));
350         if (LockingDisabled())
351                 return;
352
353         /* ---------------
354          * Make sure lockinfo is initialized
355          * ---------------
356          */
357         if (!LockInfoIsValid(relation->lockInfo))
358                 RelationInitLockInfo(relation);
359
360         /* ----------------
361          *      attempt to set lock
362          * ----------------
363          */
364         MultiLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK);
365 }
366
367 /* ----------------
368  *              RelationUnsetLockForReadPage
369  * ----------------
370  */
371 #ifdef  LOCKDEBUG
372 #define LOCKDEBUG_110 \
373 elog(DEBUG, "RelationUnsetLockForReadPage(%s[%d,%d], @%d) called", \
374          RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
375 #else
376 #define LOCKDEBUG_110
377 #endif                                                  /* LOCKDEBUG */
378
379 /* ----------------
380  *              RelationUnsetLockForWritePage
381  * ----------------
382  */
383 #ifdef  LOCKDEBUG
384 #define LOCKDEBUG_120 \
385 elog(DEBUG, "RelationUnsetLockForWritePage(%s[%d,%d], @%d) called", \
386          RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page)
387 #else
388 #define LOCKDEBUG_120
389 #endif                                                  /* LOCKDEBUG */
390
391 /*
392  * Set a single level write page lock.  Assumes that you already
393  * have a write intent lock on the relation.
394  */
395 void
396 RelationSetSingleWLockPage(Relation relation,
397                                                    ItemPointer itemPointer)
398 {
399
400         /* ----------------
401          *      sanity checks
402          * ----------------
403          */
404         Assert(RelationIsValid(relation));
405         if (LockingDisabled())
406                 return;
407
408         if (!LockInfoIsValid(relation->lockInfo))
409                 RelationInitLockInfo(relation);
410
411         SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, !UNLOCK);
412 }
413
414 /*
415  * Unset a single level write page lock
416  */
417 void
418 RelationUnsetSingleWLockPage(Relation relation,
419                                                          ItemPointer itemPointer)
420 {
421
422         /* ----------------
423          *      sanity checks
424          * ----------------
425          */
426         Assert(RelationIsValid(relation));
427         if (LockingDisabled())
428                 return;
429
430         if (!LockInfoIsValid(relation->lockInfo))
431                 elog(ERROR,
432                          "Releasing a lock on %s with invalid lock information",
433                          RelationGetRelationName(relation));
434
435         SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, UNLOCK);
436 }
437
438 /*
439  * Set a single level read page lock.  Assumes you already have a read
440  * intent lock set on the relation.
441  */
442 void
443 RelationSetSingleRLockPage(Relation relation,
444                                                    ItemPointer itemPointer)
445 {
446
447         /* ----------------
448          *      sanity checks
449          * ----------------
450          */
451         Assert(RelationIsValid(relation));
452         if (LockingDisabled())
453                 return;
454
455         if (!LockInfoIsValid(relation->lockInfo))
456                 RelationInitLockInfo(relation);
457
458         SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, !UNLOCK);
459 }
460
461 /*
462  * Unset a single level read page lock.
463  */
464 void
465 RelationUnsetSingleRLockPage(Relation relation,
466                                                          ItemPointer itemPointer)
467 {
468
469         /* ----------------
470          *      sanity checks
471          * ----------------
472          */
473         Assert(RelationIsValid(relation));
474         if (LockingDisabled())
475                 return;
476
477         if (!LockInfoIsValid(relation->lockInfo))
478                 elog(ERROR,
479                          "Releasing a lock on %s with invalid lock information",
480                          RelationGetRelationName(relation));
481
482         SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, UNLOCK);
483 }
484
485 /*
486  * Set a read intent lock on a relation.
487  *
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.
493  */
494 void
495 RelationSetRIntentLock(Relation relation)
496 {
497         /* -----------------
498          * Sanity check
499          * -----------------
500          */
501         Assert(RelationIsValid(relation));
502         if (LockingDisabled())
503                 return;
504
505         if (!LockInfoIsValid(relation->lockInfo))
506                 RelationInitLockInfo(relation);
507
508         SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, !UNLOCK);
509 }
510
511 /*
512  * Unset a read intent lock on a relation
513  */
514 void
515 RelationUnsetRIntentLock(Relation relation)
516 {
517         /* -----------------
518          * Sanity check
519          * -----------------
520          */
521         Assert(RelationIsValid(relation));
522         if (LockingDisabled())
523                 return;
524
525         if (!LockInfoIsValid(relation->lockInfo))
526                 RelationInitLockInfo(relation);
527
528         SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, UNLOCK);
529 }
530
531 /*
532  * Set a write intent lock on a relation. For a more complete explanation
533  * see RelationSetRIntentLock()
534  */
535 void
536 RelationSetWIntentLock(Relation relation)
537 {
538         /* -----------------
539          * Sanity check
540          * -----------------
541          */
542         Assert(RelationIsValid(relation));
543         if (LockingDisabled())
544                 return;
545
546         if (!LockInfoIsValid(relation->lockInfo))
547                 RelationInitLockInfo(relation);
548
549         SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, !UNLOCK);
550 }
551
552 /*
553  * Unset a write intent lock.
554  */
555 void
556 RelationUnsetWIntentLock(Relation relation)
557 {
558         /* -----------------
559          * Sanity check
560          * -----------------
561          */
562         Assert(RelationIsValid(relation));
563         if (LockingDisabled())
564                 return;
565
566         if (!LockInfoIsValid(relation->lockInfo))
567                 RelationInitLockInfo(relation);
568
569         SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, UNLOCK);
570 }
571
572 /*
573  * Extend locks are used primarily in tertiary storage devices such as
574  * a WORM disk jukebox.  Sometimes need exclusive access to extend a
575  * file by a block.
576  */
577 #ifdef NOT_USED
578 void
579 RelationSetLockForExtend(Relation relation)
580 {
581         /* -----------------
582          * Sanity check
583          * -----------------
584          */
585         Assert(RelationIsValid(relation));
586         if (LockingDisabled())
587                 return;
588
589         if (!LockInfoIsValid(relation->lockInfo))
590                 RelationInitLockInfo(relation);
591
592         MultiLockReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
593 }
594
595 #endif
596
597 #ifdef NOT_USED
598 void
599 RelationUnsetLockForExtend(Relation relation)
600 {
601         /* -----------------
602          * Sanity check
603          * -----------------
604          */
605         Assert(RelationIsValid(relation));
606         if (LockingDisabled())
607                 return;
608
609         if (!LockInfoIsValid(relation->lockInfo))
610                 RelationInitLockInfo(relation);
611
612         MultiReleaseReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
613 }
614
615 #endif
616