]> granicus.if.org Git - postgresql/blob - src/backend/storage/lmgr/lmgr.c
2dce65a108a5e5894c849c43914de60d551c8491
[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.28 1999/07/15 15:19:51 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/rel.h"
39
40 #include "catalog/catname.h"
41 #include "catalog/catalog.h"
42 #include "catalog/pg_class.h"
43
44 #include "nodes/memnodes.h"
45 #include "storage/bufmgr.h"
46 #include "access/transam.h"             /* for AmiTransactionId */
47
48 extern Oid      MyDatabaseId;
49
50 static MASK LockConflicts[] = {
51         (int) NULL,
52
53 /* AccessShareLock */
54         (1 << AccessExclusiveLock),
55
56 /* RowShareLock */
57         (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
58
59 /* RowExclusiveLock */
60         (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
61         (1 << AccessExclusiveLock),
62
63 /* ShareLock */
64         (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
65         (1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
66
67 /* ShareRowExclusiveLock */
68         (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
69         (1 << ShareLock) | (1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
70
71 /* ExclusiveLock */
72         (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
73         (1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock),
74
75 /* AccessExclusiveLock */
76         (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
77         (1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock) |
78         (1 << AccessShareLock),
79
80 };
81
82 static int      LockPrios[] = {
83         (int) NULL,
84         1,
85         2,
86         3,
87         4,
88         5,
89         6,
90         7
91 };
92
93 LOCKMETHOD      LockTableId = (LOCKMETHOD) NULL;
94 LOCKMETHOD      LongTermTableId = (LOCKMETHOD) NULL;
95
96 /*
97  * Create the lock table described by LockConflicts and LockPrios.
98  */
99 LOCKMETHOD
100 InitLockTable()
101 {
102         int                     lockmethod;
103
104         lockmethod = LockMethodTableInit("LockTable",
105                                                         LockConflicts, LockPrios, MAX_LOCKMODES - 1);
106         LockTableId = lockmethod;
107
108         if (!(LockTableId))
109                 elog(ERROR, "InitLockTable: couldnt initialize lock table");
110
111 #ifdef USER_LOCKS
112
113         /*
114          * Allocate another tableId for long-term locks
115          */
116         LongTermTableId = LockMethodTableRename(LockTableId);
117         if (!(LongTermTableId))
118         {
119                 elog(ERROR,
120                          "InitLockTable: couldn't rename long-term lock table");
121         }
122 #endif
123
124         return LockTableId;
125 }
126
127 /*
128  * RelationInitLockInfo
129  *              Initializes the lock information in a relation descriptor.
130  */
131 void
132 RelationInitLockInfo(Relation relation)
133 {
134         LockInfo        info;
135         char       *relname;
136         MemoryContext oldcxt;
137         extern Oid      MyDatabaseId;   /* XXX use include */
138         extern GlobalMemory CacheCxt;
139
140         Assert(RelationIsValid(relation));
141         Assert(OidIsValid(RelationGetRelid(relation)));
142
143         info = (LockInfo) relation->lockInfo;
144
145         if (LockInfoIsValid(info))
146                 return;
147
148         relname = (char *) RelationGetRelationName(relation);
149
150         oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
151         info = (LockInfo) palloc(sizeof(LockInfoData));
152         MemoryContextSwitchTo(oldcxt);
153
154         info->lockRelId.relId = RelationGetRelid(relation);
155         if (IsSharedSystemRelationName(relname))
156                 info->lockRelId.dbId = InvalidOid;
157         else
158                 info->lockRelId.dbId = MyDatabaseId;
159
160         relation->lockInfo = (Pointer) info;
161 }
162
163 /*
164  *              LockRelation
165  */
166 void
167 LockRelation(Relation relation, LOCKMODE lockmode)
168 {
169         LockInfo        lockinfo;
170         LOCKTAG         tag;
171
172         if (LockingDisabled())
173                 return;
174
175         if (!LockInfoIsValid(relation->lockInfo))
176                 RelationInitLockInfo(relation);
177
178         lockinfo = (LockInfo) relation->lockInfo;
179
180         MemSet(&tag, 0, sizeof(tag));
181         tag.relId = lockinfo->lockRelId.relId;
182         tag.dbId = lockinfo->lockRelId.dbId;
183         tag.objId.blkno = InvalidBlockNumber;
184
185         LockAcquire(LockTableId, &tag, lockmode);
186         return;
187 }
188
189 /*
190  *              UnlockRelation
191  */
192 void
193 UnlockRelation(Relation relation, LOCKMODE lockmode)
194 {
195         LockInfo        lockinfo;
196         LOCKTAG         tag;
197
198         if (LockingDisabled())
199                 return;
200
201         lockinfo = (LockInfo) relation->lockInfo;
202
203         if (!LockInfoIsValid(lockinfo))
204         {
205                 elog(ERROR,
206                          "Releasing a lock on %s with invalid lock information",
207                          RelationGetRelationName(relation));
208         }
209
210         MemSet(&tag, 0, sizeof(tag));
211         tag.relId = lockinfo->lockRelId.relId;
212         tag.dbId = lockinfo->lockRelId.dbId;
213         tag.objId.blkno = InvalidBlockNumber;
214
215         LockRelease(LockTableId, &tag, lockmode);
216         return;
217 }
218
219 /*
220  *              LockPage
221  */
222 void
223 LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
224 {
225         LockInfo        lockinfo;
226         LOCKTAG         tag;
227
228         if (LockingDisabled())
229                 return;
230
231         if (!LockInfoIsValid(relation->lockInfo))
232                 RelationInitLockInfo(relation);
233
234         lockinfo = (LockInfo) relation->lockInfo;
235
236         MemSet(&tag, 0, sizeof(tag));
237         tag.relId = lockinfo->lockRelId.relId;
238         tag.dbId = lockinfo->lockRelId.dbId;
239         tag.objId.blkno = blkno;
240
241         LockAcquire(LockTableId, &tag, lockmode);
242         return;
243 }
244
245 /*
246  *              UnlockPage
247  */
248 void
249 UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
250 {
251         LockInfo        lockinfo;
252         LOCKTAG         tag;
253
254         if (LockingDisabled())
255                 return;
256
257         lockinfo = (LockInfo) relation->lockInfo;
258
259         if (!LockInfoIsValid(lockinfo))
260         {
261                 elog(ERROR,
262                          "Releasing a lock on %s with invalid lock information",
263                          RelationGetRelationName(relation));
264         }
265
266         MemSet(&tag, 0, sizeof(tag));
267         tag.relId = lockinfo->lockRelId.relId;
268         tag.dbId = lockinfo->lockRelId.dbId;
269         tag.objId.blkno = blkno;
270
271         LockRelease(LockTableId, &tag, lockmode);
272         return;
273 }
274
275 void
276 XactLockTableInsert(TransactionId xid)
277 {
278         LOCKTAG         tag;
279
280         if (LockingDisabled())
281                 return;
282
283         MemSet(&tag, 0, sizeof(tag));
284         tag.relId = XactLockTableId;
285         tag.dbId = InvalidOid;
286         tag.objId.xid = xid;
287
288         LockAcquire(LockTableId, &tag, ExclusiveLock);
289         return;
290 }
291
292 void
293 XactLockTableDelete(TransactionId xid)
294 {
295         LOCKTAG         tag;
296
297         if (LockingDisabled())
298                 return;
299
300         MemSet(&tag, 0, sizeof(tag));
301         tag.relId = XactLockTableId;
302         tag.dbId = InvalidOid;
303         tag.objId.xid = xid;
304
305         LockRelease(LockTableId, &tag, ExclusiveLock);
306         return;
307 }
308
309 void
310 XactLockTableWait(TransactionId xid)
311 {
312         LOCKTAG         tag;
313
314         if (LockingDisabled())
315                 return;
316
317         MemSet(&tag, 0, sizeof(tag));
318         tag.relId = XactLockTableId;
319         tag.dbId = InvalidOid;
320         tag.objId.xid = xid;
321
322         LockAcquire(LockTableId, &tag, ShareLock);
323         LockRelease(LockTableId, &tag, ShareLock);
324
325         /*
326          * Transaction was committed/aborted/crashed - we have to update
327          * pg_log if transaction is still marked as running.
328          */
329         if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
330                 TransactionIdAbort(xid);
331
332         return;
333 }