lmgr.c 7.2 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * lmgr.c
4
 *	  POSTGRES lock manager code
5
 *
6
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
7
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.47 2001/06/19 19:42:16 tgl Exp $
12 13 14
 *
 *-------------------------------------------------------------------------
 */
15

16
#include "postgres.h"
17

B
Bruce Momjian 已提交
18
#include "access/transam.h"
19
#include "access/xact.h"
B
Bruce Momjian 已提交
20
#include "catalog/catalog.h"
21
#include "miscadmin.h"
22
#include "storage/lmgr.h"
23
#include "utils/inval.h"
24 25


B
Bruce Momjian 已提交
26
static LOCKMASK LockConflicts[] = {
V
Vadim B. Mikheev 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
	(int) NULL,

/* AccessShareLock */
	(1 << AccessExclusiveLock),

/* RowShareLock */
	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),

/* RowExclusiveLock */
	(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
	(1 << AccessExclusiveLock),

/* ShareLock */
	(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
	(1 << RowExclusiveLock) | (1 << AccessExclusiveLock),

/* ShareRowExclusiveLock */
	(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
	(1 << ShareLock) | (1 << RowExclusiveLock) | (1 << AccessExclusiveLock),

/* ExclusiveLock */
	(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
	(1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock),

/* AccessExclusiveLock */
	(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
B
Bruce Momjian 已提交
53
	(1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock) |
V
Vadim B. Mikheev 已提交
54 55 56 57 58 59 60 61 62 63 64 65
	(1 << AccessShareLock),

};

static int	LockPrios[] = {
	(int) NULL,
	1,
	2,
	3,
	4,
	5,
	6,
V
Vadim B. Mikheev 已提交
66
	7
V
Vadim B. Mikheev 已提交
67 68
};

69
LOCKMETHOD	LockTableId = (LOCKMETHOD) NULL;
V
Vadim B. Mikheev 已提交
70 71 72 73 74 75
LOCKMETHOD	LongTermTableId = (LOCKMETHOD) NULL;

/*
 * Create the lock table described by LockConflicts and LockPrios.
 */
LOCKMETHOD
76
InitLockTable(int maxBackends)
V
Vadim B. Mikheev 已提交
77 78 79 80
{
	int			lockmethod;

	lockmethod = LockMethodTableInit("LockTable",
81 82
									 LockConflicts, LockPrios,
									 MAX_LOCKMODES - 1, maxBackends);
V
Vadim B. Mikheev 已提交
83
	LockTableId = lockmethod;
B
Bruce Momjian 已提交
84

V
Vadim B. Mikheev 已提交
85
	if (!(LockTableId))
86
		elog(ERROR, "InitLockTable: couldn't initialize lock table");
V
Vadim B. Mikheev 已提交
87 88

#ifdef USER_LOCKS
B
Bruce Momjian 已提交
89

V
Vadim B. Mikheev 已提交
90 91 92 93 94
	/*
	 * Allocate another tableId for long-term locks
	 */
	LongTermTableId = LockMethodTableRename(LockTableId);
	if (!(LongTermTableId))
95
		elog(ERROR, "InitLockTable: couldn't rename long-term lock table");
V
Vadim B. Mikheev 已提交
96 97 98 99 100
#endif

	return LockTableId;
}

101
/*
B
Bruce Momjian 已提交
102
 * RelationInitLockInfo
103
 *		Initializes the lock information in a relation descriptor.
104 105
 *
 *		relcache.c must call this during creation of any reldesc.
106 107 108 109
 */
void
RelationInitLockInfo(Relation relation)
{
110
	Assert(RelationIsValid(relation));
111
	Assert(OidIsValid(RelationGetRelid(relation)));
112

113
	relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
114

115
	if (relation->rd_rel->relisshared)
116
		relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
117
	else
118
		relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
119 120 121
}

/*
V
Vadim B. Mikheev 已提交
122
 *		LockRelation
123 124
 */
void
V
Vadim B. Mikheev 已提交
125
LockRelation(Relation relation, LOCKMODE lockmode)
126
{
V
Vadim B. Mikheev 已提交
127
	LOCKTAG		tag;
128 129 130 131

	if (LockingDisabled())
		return;

V
Vadim B. Mikheev 已提交
132
	MemSet(&tag, 0, sizeof(tag));
133 134
	tag.relId = relation->rd_lockInfo.lockRelId.relId;
	tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
V
Vadim B. Mikheev 已提交
135 136
	tag.objId.blkno = InvalidBlockNumber;

137
	if (!LockAcquire(LockTableId, &tag, GetCurrentTransactionId(), lockmode))
138
		elog(ERROR, "LockRelation: LockAcquire failed");
139 140

	/*
141 142 143 144
	 * Check to see if the relcache entry has been invalidated while we
	 * were waiting to lock it.  If so, rebuild it, or elog() trying.
	 * Increment the refcount to ensure that RelationFlushRelation will
	 * rebuild it and not just delete it.
145 146
	 */
	RelationIncrementReferenceCount(relation);
147
	AcceptInvalidationMessages();
148
	RelationDecrementReferenceCount(relation);
V
Vadim B. Mikheev 已提交
149
}
150

151
/*
V
Vadim B. Mikheev 已提交
152
 *		UnlockRelation
153 154
 */
void
V
Vadim B. Mikheev 已提交
155
UnlockRelation(Relation relation, LOCKMODE lockmode)
156
{
V
Vadim B. Mikheev 已提交
157
	LOCKTAG		tag;
158 159 160 161

	if (LockingDisabled())
		return;

V
Vadim B. Mikheev 已提交
162
	MemSet(&tag, 0, sizeof(tag));
163 164
	tag.relId = relation->rd_lockInfo.lockRelId.relId;
	tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
V
Vadim B. Mikheev 已提交
165
	tag.objId.blkno = InvalidBlockNumber;
166

167 168 169 170 171 172
	LockRelease(LockTableId, &tag, GetCurrentTransactionId(), lockmode);
}

/*
 *		LockRelationForSession
 *
B
Bruce Momjian 已提交
173
 * This routine grabs a session-level lock on the target relation.	The
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
 * session lock persists across transaction boundaries.  It will be removed
 * when UnlockRelationForSession() is called, or if an elog(ERROR) occurs,
 * or if the backend exits.
 *
 * Note that one should also grab a transaction-level lock on the rel
 * in any transaction that actually uses the rel, to ensure that the
 * relcache entry is up to date.
 */
void
LockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
{
	LOCKTAG		tag;

	if (LockingDisabled())
		return;

	MemSet(&tag, 0, sizeof(tag));
	tag.relId = relid->relId;
	tag.dbId = relid->dbId;
	tag.objId.blkno = InvalidBlockNumber;

	if (!LockAcquire(LockTableId, &tag, InvalidTransactionId, lockmode))
		elog(ERROR, "LockRelationForSession: LockAcquire failed");
}

/*
 *		UnlockRelationForSession
 */
void
UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
{
	LOCKTAG		tag;

	if (LockingDisabled())
		return;

	MemSet(&tag, 0, sizeof(tag));
	tag.relId = relid->relId;
	tag.dbId = relid->dbId;
	tag.objId.blkno = InvalidBlockNumber;

	LockRelease(LockTableId, &tag, InvalidTransactionId, lockmode);
V
Vadim B. Mikheev 已提交
216
}
217

218
/*
V
Vadim B. Mikheev 已提交
219
 *		LockPage
220 221
 */
void
V
Vadim B. Mikheev 已提交
222
LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
223
{
V
Vadim B. Mikheev 已提交
224
	LOCKTAG		tag;
225 226 227 228

	if (LockingDisabled())
		return;

V
Vadim B. Mikheev 已提交
229
	MemSet(&tag, 0, sizeof(tag));
230 231
	tag.relId = relation->rd_lockInfo.lockRelId.relId;
	tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
V
Vadim B. Mikheev 已提交
232 233
	tag.objId.blkno = blkno;

234
	if (!LockAcquire(LockTableId, &tag, GetCurrentTransactionId(), lockmode))
235
		elog(ERROR, "LockPage: LockAcquire failed");
V
Vadim B. Mikheev 已提交
236
}
237

238
/*
V
Vadim B. Mikheev 已提交
239
 *		UnlockPage
240 241
 */
void
V
Vadim B. Mikheev 已提交
242
UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
243
{
V
Vadim B. Mikheev 已提交
244
	LOCKTAG		tag;
245 246 247 248

	if (LockingDisabled())
		return;

V
Vadim B. Mikheev 已提交
249
	MemSet(&tag, 0, sizeof(tag));
250 251
	tag.relId = relation->rd_lockInfo.lockRelId.relId;
	tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
V
Vadim B. Mikheev 已提交
252
	tag.objId.blkno = blkno;
253

254
	LockRelease(LockTableId, &tag, GetCurrentTransactionId(), lockmode);
255 256 257
}

void
V
Vadim B. Mikheev 已提交
258
XactLockTableInsert(TransactionId xid)
259
{
V
Vadim B. Mikheev 已提交
260
	LOCKTAG		tag;
261 262 263 264

	if (LockingDisabled())
		return;

V
Vadim B. Mikheev 已提交
265 266
	MemSet(&tag, 0, sizeof(tag));
	tag.relId = XactLockTableId;
267
	tag.dbId = InvalidOid;		/* xids are globally unique */
V
Vadim B. Mikheev 已提交
268
	tag.objId.xid = xid;
269

270
	if (!LockAcquire(LockTableId, &tag, xid, ExclusiveLock))
271
		elog(ERROR, "XactLockTableInsert: LockAcquire failed");
272 273
}

274
#ifdef NOT_USED
275
void
V
Vadim B. Mikheev 已提交
276
XactLockTableDelete(TransactionId xid)
277
{
V
Vadim B. Mikheev 已提交
278
	LOCKTAG		tag;
279 280 281 282

	if (LockingDisabled())
		return;

V
Vadim B. Mikheev 已提交
283 284 285 286
	MemSet(&tag, 0, sizeof(tag));
	tag.relId = XactLockTableId;
	tag.dbId = InvalidOid;
	tag.objId.xid = xid;
287

288
	LockRelease(LockTableId, &tag, xid, ExclusiveLock);
289
}
B
Bruce Momjian 已提交
290

291
#endif
292 293

void
V
Vadim B. Mikheev 已提交
294
XactLockTableWait(TransactionId xid)
295
{
V
Vadim B. Mikheev 已提交
296
	LOCKTAG		tag;
297 298 299 300

	if (LockingDisabled())
		return;

V
Vadim B. Mikheev 已提交
301 302 303 304
	MemSet(&tag, 0, sizeof(tag));
	tag.relId = XactLockTableId;
	tag.dbId = InvalidOid;
	tag.objId.xid = xid;
305

306
	if (!LockAcquire(LockTableId, &tag, GetCurrentTransactionId(), ShareLock))
307 308
		elog(ERROR, "XactLockTableWait: LockAcquire failed");

309
	LockRelease(LockTableId, &tag, GetCurrentTransactionId(), ShareLock);
310

V
Vadim B. Mikheev 已提交
311
	/*
B
Bruce Momjian 已提交
312 313
	 * Transaction was committed/aborted/crashed - we have to update
	 * pg_log if transaction is still marked as running.
314
	 */
V
Vadim B. Mikheev 已提交
315 316
	if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
		TransactionIdAbort(xid);
317
}