Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d8d9ed9

Browse files
committed
Add support to lock manager for conditionally locking a lock (ie,
return without waiting if we can't get the lock immediately). Not used yet, but will be needed for concurrent VACUUM.
1 parent 986915c commit d8d9ed9

File tree

6 files changed

+112
-86
lines changed

6 files changed

+112
-86
lines changed

contrib/userlock/README.user_locks

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ This software is distributed under the GNU General Public License
55
either version 2, or (at your option) any later version.
66

77

8-
This loadable module, together with my user-lock.patch applied to the
9-
backend, provides support for user-level long-term cooperative locks.
10-
For example one can write:
8+
This loadable module provides support for user-level long-term cooperative
9+
locks. For example one can write:
1110

1211
select some_fields, user_write_lock_oid(oid) from table where id='key';
1312

@@ -26,14 +25,14 @@ After you have finished your work on that item you can do:
2625
You can also ignore the failure and go ahead but this could produce conflicts
2726
or inconsistent data in your application. User locks require a cooperative
2827
behavior between users. User locks don't interfere with the normal locks
29-
used by postgres for transaction processing.
28+
used by Postgres for transaction processing.
3029

3130
This could also be done by setting a flag in the record itself but in
3231
this case you have the overhead of the updates to the records and there
3332
could be some locks not released if the backend or the application crashes
3433
before resetting the lock flag.
3534
It could also be done with a begin/end block but in this case the entire
36-
table would be locked by postgres and it is not acceptable to do this for
35+
table would be locked by Postgres and it is not acceptable to do this for
3736
a long period because other transactions would block completely.
3837

3938
The generic user locks use two values, group and id, to identify a lock,
@@ -44,12 +43,12 @@ use a group equal to 0.
4443

4544
The meaning of group and id is defined by the application. The user
4645
lock code just takes two numbers and tells you if the corresponding
47-
entity has been succesfully locked. What this mean is up to you.
46+
entity has been successfully locked. What this means is up to you.
4847

49-
My succestion is that you use the group to identify an area of your
48+
My suggestion is that you use the group to identify an area of your
5049
application and the id to identify an object in this area.
5150
Or you can just lock the oid of the tuples which are by definition unique.
5251

5352
Note also that a process can acquire more than one lock on the same entity
5453
and it must release the lock the corresponding number of times. This can
55-
be done calling the unlock funtion until it returns 0.
54+
be done by calling the unlock function until it returns 0.

contrib/userlock/user_locks.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,23 @@
11
/*
22
* user_locks.c --
33
*
4-
* This loadable module, together with my user-lock.patch applied to the
5-
* backend, provides support for user-level long-term cooperative locks.
4+
* This loadable module provides support for user-level long-term
5+
* cooperative locks.
66
*
77
* Copyright (C) 1999, Massimo Dal Zotto <dz@cs.unitn.it>
88
*
99
* This software is distributed under the GNU General Public License
1010
* either version 2, or (at your option) any later version.
1111
*/
12-
13-
#include <stdio.h>
14-
#include <string.h>
15-
#include <unistd.h>
16-
1712
#include "postgres.h"
13+
1814
#include "miscadmin.h"
1915
#include "storage/lmgr.h"
2016
#include "storage/proc.h"
21-
#include "utils/elog.h"
2217

2318
#include "user_locks.h"
2419

20+
2521
int
2622
user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode)
2723
{
@@ -33,7 +29,8 @@ user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode)
3329
tag.objId.blkno = (BlockNumber) id2;
3430
tag.offnum = (OffsetNumber) (id1 & 0xffff);
3531

36-
return LockAcquire(USER_LOCKMETHOD, &tag, InvalidTransactionId, lockmode);
32+
return LockAcquire(USER_LOCKMETHOD, &tag, InvalidTransactionId,
33+
lockmode, true);
3734
}
3835

3936
int

src/backend/storage/lmgr/lmgr.c

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.47 2001/06/19 19:42:16 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.48 2001/06/22 00:04:59 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -24,45 +24,52 @@
2424

2525

2626
static LOCKMASK LockConflicts[] = {
27-
(int) NULL,
27+
0,
2828

29-
/* AccessShareLock */
29+
/* AccessShareLock */
3030
(1 << AccessExclusiveLock),
3131

32-
/* RowShareLock */
32+
/* RowShareLock */
3333
(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
3434

35-
/* RowExclusiveLock */
35+
/* RowExclusiveLock */
3636
(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
3737
(1 << AccessExclusiveLock),
3838

39-
/* ShareLock */
39+
/* ShareLock */
4040
(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
4141
(1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
4242

43-
/* ShareRowExclusiveLock */
43+
/* ShareRowExclusiveLock */
4444
(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) |
4545
(1 << ShareLock) | (1 << RowExclusiveLock) | (1 << AccessExclusiveLock),
4646

47-
/* ExclusiveLock */
47+
/* ExclusiveLock */
4848
(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
4949
(1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock),
5050

51-
/* AccessExclusiveLock */
51+
/* AccessExclusiveLock */
5252
(1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) |
53-
(1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock) |
54-
(1 << AccessShareLock),
53+
(1 << RowExclusiveLock) | (1 << RowShareLock) |
54+
(1 << AccessExclusiveLock) | (1 << AccessShareLock)
5555

5656
};
5757

5858
static int LockPrios[] = {
59-
(int) NULL,
59+
0,
60+
/* AccessShareLock */
6061
1,
62+
/* RowShareLock */
6163
2,
64+
/* RowExclusiveLock */
6265
3,
66+
/* ShareLock */
6367
4,
68+
/* ShareRowExclusiveLock */
6469
5,
70+
/* ExclusiveLock */
6571
6,
72+
/* AccessExclusiveLock */
6673
7
6774
};
6875

@@ -134,7 +141,8 @@ LockRelation(Relation relation, LOCKMODE lockmode)
134141
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
135142
tag.objId.blkno = InvalidBlockNumber;
136143

137-
if (!LockAcquire(LockTableId, &tag, GetCurrentTransactionId(), lockmode))
144+
if (!LockAcquire(LockTableId, &tag, GetCurrentTransactionId(),
145+
lockmode, false))
138146
elog(ERROR, "LockRelation: LockAcquire failed");
139147

140148
/*
@@ -148,6 +156,45 @@ LockRelation(Relation relation, LOCKMODE lockmode)
148156
RelationDecrementReferenceCount(relation);
149157
}
150158

159+
/*
160+
* ConditionalLockRelation
161+
*
162+
* As above, but only lock if we can get the lock without blocking.
163+
* Returns TRUE iff the lock was acquired.
164+
*
165+
* NOTE: we do not currently need conditional versions of the other
166+
* LockXXX routines in this file, but they could easily be added if needed.
167+
*/
168+
bool
169+
ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
170+
{
171+
LOCKTAG tag;
172+
173+
if (LockingDisabled())
174+
return true;
175+
176+
MemSet(&tag, 0, sizeof(tag));
177+
tag.relId = relation->rd_lockInfo.lockRelId.relId;
178+
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
179+
tag.objId.blkno = InvalidBlockNumber;
180+
181+
if (!LockAcquire(LockTableId, &tag, GetCurrentTransactionId(),
182+
lockmode, true))
183+
return false;
184+
185+
/*
186+
* Check to see if the relcache entry has been invalidated while we
187+
* were waiting to lock it. If so, rebuild it, or elog() trying.
188+
* Increment the refcount to ensure that RelationFlushRelation will
189+
* rebuild it and not just delete it.
190+
*/
191+
RelationIncrementReferenceCount(relation);
192+
AcceptInvalidationMessages();
193+
RelationDecrementReferenceCount(relation);
194+
195+
return true;
196+
}
197+
151198
/*
152199
* UnlockRelation
153200
*/
@@ -192,7 +239,8 @@ LockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
192239
tag.dbId = relid->dbId;
193240
tag.objId.blkno = InvalidBlockNumber;
194241

195-
if (!LockAcquire(LockTableId, &tag, InvalidTransactionId, lockmode))
242+
if (!LockAcquire(LockTableId, &tag, InvalidTransactionId,
243+
lockmode, false))
196244
elog(ERROR, "LockRelationForSession: LockAcquire failed");
197245
}
198246

@@ -231,7 +279,8 @@ LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
231279
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
232280
tag.objId.blkno = blkno;
233281

234-
if (!LockAcquire(LockTableId, &tag, GetCurrentTransactionId(), lockmode))
282+
if (!LockAcquire(LockTableId, &tag, GetCurrentTransactionId(),
283+
lockmode, false))
235284
elog(ERROR, "LockPage: LockAcquire failed");
236285
}
237286

@@ -267,7 +316,8 @@ XactLockTableInsert(TransactionId xid)
267316
tag.dbId = InvalidOid; /* xids are globally unique */
268317
tag.objId.xid = xid;
269318

270-
if (!LockAcquire(LockTableId, &tag, xid, ExclusiveLock))
319+
if (!LockAcquire(LockTableId, &tag, xid,
320+
ExclusiveLock, false))
271321
elog(ERROR, "XactLockTableInsert: LockAcquire failed");
272322
}
273323

@@ -303,7 +353,8 @@ XactLockTableWait(TransactionId xid)
303353
tag.dbId = InvalidOid;
304354
tag.objId.xid = xid;
305355

306-
if (!LockAcquire(LockTableId, &tag, GetCurrentTransactionId(), ShareLock))
356+
if (!LockAcquire(LockTableId, &tag, GetCurrentTransactionId(),
357+
ShareLock, false))
307358
elog(ERROR, "XactLockTableWait: LockAcquire failed");
308359

309360
LockRelease(LockTableId, &tag, GetCurrentTransactionId(), ShareLock);

0 commit comments

Comments
 (0)