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