Add built-in userlock manipulation functions to replace the former

contrib functionality.  Along the way, remove the USER_LOCKS configuration
symbol, since it no longer makes any sense to try to compile that out.
No user documentation yet ... mmoncure has promised to write some.
Thanks to Abhijit Menon-Sen for creating a first draft to work from.
This commit is contained in:
Tom Lane 2006-09-18 22:40:40 +00:00
parent f7f308d6a6
commit 9b4cda0df6
11 changed files with 336 additions and 50 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.132 2006/09/16 20:14:32 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.133 2006/09/18 22:40:36 tgl Exp $ -->
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
-->
@ -5029,9 +5029,14 @@
</para>
<para>
If user-defined locks are in use, they are displayed using the columns
for general database objects. However, the actual meaning of the lock
fields in such cases is up to the user.
User-defined locks can be acquired on keys consisting of either a single
bigint value or two integer values. A bigint key is displayed with its
high-order half in the <structfield>classid</> column, its low-order half
in the <structfield>objid</> column, and <structfield>objsubid</> equal
to 1. Integer keys are displayed with the first key in the
<structfield>classid</> column, the second key in the <structfield>objid</>
column, and <structfield>objsubid</> equal to 2. The actual meaning of
the keys is up to the user.
</para>
<para>

View File

@ -1,4 +1,4 @@
$PostgreSQL: pgsql/src/backend/storage/lmgr/README,v 1.20 2006/07/23 23:08:46 tgl Exp $
$PostgreSQL: pgsql/src/backend/storage/lmgr/README,v 1.21 2006/09/18 22:40:36 tgl Exp $
LOCKING OVERVIEW
@ -48,7 +48,7 @@ The rest of this README file discusses the regular lock manager in detail.
LOCK DATA STRUCTURES
Lock methods describe the overall locking behavior. Currently there are
two lock methods: DEFAULT and USER. (USER locks are non-blocking.)
two lock methods: DEFAULT and USER.
Lock modes describe the type of the lock (read/write or shared/exclusive).
In principle, each lock method can have its own set of lock modes with
@ -502,11 +502,6 @@ level by someone.
User locks and normal locks are completely orthogonal and they don't
interfere with each other.
User locks are always non blocking, therefore they are never acquired if
already held by another process. They must be released explicitly by the
application but they are released automatically when a backend terminates.
The lockmode parameter can have the same values as for normal locks although
probably only ExclusiveLock can have some practical use.
DZ - 22 Nov 1997
User locks are always held as session locks, so that they are not released at
transaction end. They must be released explicitly by the application --- but
they are released automatically when a backend terminates.

View File

@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.41 2006/07/23 23:08:46 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.42 2006/09/18 22:40:36 tgl Exp $
*
* Interface:
*
@ -873,9 +873,11 @@ DescribeLockTag(StringInfo buf, const LOCKTAG *lock)
break;
case LOCKTAG_USERLOCK:
appendStringInfo(buf,
_("user lock [%u,%u]"),
_("user lock [%u,%u,%u,%u]"),
lock->locktag_field1,
lock->locktag_field2);
lock->locktag_field2,
lock->locktag_field3,
lock->locktag_field4);
break;
default:
appendStringInfo(buf,

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.172 2006/08/27 19:14:34 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.173 2006/09/18 22:40:36 tgl Exp $
*
* NOTES
* A lock table is a shared memory hash table. When
@ -127,8 +127,6 @@ static const LockMethodData default_lockmethod = {
#endif
};
#ifdef USER_LOCKS
static const LockMethodData user_lockmethod = {
AccessExclusiveLock, /* highest valid lock mode number */
false,
@ -141,17 +139,13 @@ static const LockMethodData user_lockmethod = {
#endif
};
#endif /* USER_LOCKS */
/*
* map from lock method id to the lock table data structures
*/
static const LockMethod LockMethods[] = {
NULL,
&default_lockmethod,
#ifdef USER_LOCKS
&user_lockmethod
#endif
};

View File

@ -1,20 +1,21 @@
/*-------------------------------------------------------------------------
*
* lockfuncs.c
* Set-returning functions to view the state of locks within the DB.
* Functions for SQL access to various lock-manager capabilities.
*
* Copyright (c) 2002-2006, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.24 2006/07/23 23:08:46 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.25 2006/09/18 22:40:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "funcapi.h"
#include "access/heapam.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "storage/proc.h"
#include "utils/builtins.h"
@ -266,3 +267,256 @@ pg_lock_status(PG_FUNCTION_ARGS)
SRF_RETURN_DONE(funcctx);
}
/*
* Functions for manipulating USERLOCK locks
*
* We make use of the locktag fields as follows:
*
* field1: MyDatabaseId ... ensures locks are local to each database
* field2: first of 2 int4 keys, or high-order half of an int8 key
* field3: second of 2 int4 keys, or low-order half of an int8 key
* field4: 1 if using an int8 key, 2 if using 2 int4 keys
*/
#define SET_LOCKTAG_INT64(tag, key64) \
SET_LOCKTAG_USERLOCK(tag, \
MyDatabaseId, \
(uint32) ((key64) >> 32), \
(uint32) (key64), \
1)
#define SET_LOCKTAG_INT32(tag, key1, key2) \
SET_LOCKTAG_USERLOCK(tag, MyDatabaseId, key1, key2, 2)
/*
* pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
*/
Datum
pg_advisory_lock_int8(PG_FUNCTION_ARGS)
{
int64 key = PG_GETARG_INT64(0);
LOCKTAG tag;
SET_LOCKTAG_INT64(tag, key);
(void) LockAcquire(&tag, ExclusiveLock, true, false);
PG_RETURN_VOID();
}
/*
* pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
*/
Datum
pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
{
int64 key = PG_GETARG_INT64(0);
LOCKTAG tag;
SET_LOCKTAG_INT64(tag, key);
(void) LockAcquire(&tag, ShareLock, true, false);
PG_RETURN_VOID();
}
/*
* pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
*
* Returns true if successful, false if lock not available
*/
Datum
pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
{
int64 key = PG_GETARG_INT64(0);
LOCKTAG tag;
LockAcquireResult res;
SET_LOCKTAG_INT64(tag, key);
res = LockAcquire(&tag, ExclusiveLock, true, true);
PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
}
/*
* pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
*
* Returns true if successful, false if lock not available
*/
Datum
pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
{
int64 key = PG_GETARG_INT64(0);
LOCKTAG tag;
LockAcquireResult res;
SET_LOCKTAG_INT64(tag, key);
res = LockAcquire(&tag, ShareLock, true, true);
PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
}
/*
* pg_advisory_unlock(int8) - release exclusive lock on an int8 key
*
* Returns true if successful, false if lock was not held
*/
Datum
pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
{
int64 key = PG_GETARG_INT64(0);
LOCKTAG tag;
bool res;
SET_LOCKTAG_INT64(tag, key);
res = LockRelease(&tag, ExclusiveLock, true);
PG_RETURN_BOOL(res);
}
/*
* pg_advisory_unlock_shared(int8) - release share lock on an int8 key
*
* Returns true if successful, false if lock was not held
*/
Datum
pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
{
int64 key = PG_GETARG_INT64(0);
LOCKTAG tag;
bool res;
SET_LOCKTAG_INT64(tag, key);
res = LockRelease(&tag, ShareLock, true);
PG_RETURN_BOOL(res);
}
/*
* pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
*/
Datum
pg_advisory_lock_int4(PG_FUNCTION_ARGS)
{
int32 key1 = PG_GETARG_INT32(0);
int32 key2 = PG_GETARG_INT32(1);
LOCKTAG tag;
SET_LOCKTAG_INT32(tag, key1, key2);
(void) LockAcquire(&tag, ExclusiveLock, true, false);
PG_RETURN_VOID();
}
/*
* pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
*/
Datum
pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
{
int32 key1 = PG_GETARG_INT32(0);
int32 key2 = PG_GETARG_INT32(1);
LOCKTAG tag;
SET_LOCKTAG_INT32(tag, key1, key2);
(void) LockAcquire(&tag, ShareLock, true, false);
PG_RETURN_VOID();
}
/*
* pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
*
* Returns true if successful, false if lock not available
*/
Datum
pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
{
int32 key1 = PG_GETARG_INT32(0);
int32 key2 = PG_GETARG_INT32(1);
LOCKTAG tag;
LockAcquireResult res;
SET_LOCKTAG_INT32(tag, key1, key2);
res = LockAcquire(&tag, ExclusiveLock, true, true);
PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
}
/*
* pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
*
* Returns true if successful, false if lock not available
*/
Datum
pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
{
int32 key1 = PG_GETARG_INT32(0);
int32 key2 = PG_GETARG_INT32(1);
LOCKTAG tag;
LockAcquireResult res;
SET_LOCKTAG_INT32(tag, key1, key2);
res = LockAcquire(&tag, ShareLock, true, true);
PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
}
/*
* pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
*
* Returns true if successful, false if lock was not held
*/
Datum
pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
{
int32 key1 = PG_GETARG_INT32(0);
int32 key2 = PG_GETARG_INT32(1);
LOCKTAG tag;
bool res;
SET_LOCKTAG_INT32(tag, key1, key2);
res = LockRelease(&tag, ExclusiveLock, true);
PG_RETURN_BOOL(res);
}
/*
* pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
*
* Returns true if successful, false if lock was not held
*/
Datum
pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
{
int32 key1 = PG_GETARG_INT32(0);
int32 key2 = PG_GETARG_INT32(1);
LOCKTAG tag;
bool res;
SET_LOCKTAG_INT32(tag, key1, key2);
res = LockRelease(&tag, ShareLock, true);
PG_RETURN_BOOL(res);
}
/*
* pg_advisory_unlock_all() - release all userlocks
*/
Datum
pg_advisory_unlock_all(PG_FUNCTION_ARGS)
{
LockReleaseAll(USER_LOCKMETHOD, true);
PG_RETURN_VOID();
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.169 2006/07/13 16:49:18 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.170 2006/09/18 22:40:38 tgl Exp $
*
*
*-------------------------------------------------------------------------
@ -554,9 +554,7 @@ ShutdownPostgres(int code, Datum arg)
* User locks are not released by transaction end, so be sure to release
* them explicitly.
*/
#ifdef USER_LOCKS
LockReleaseAll(USER_LOCKMETHOD, true);
#endif
}

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.357 2006/09/16 20:14:33 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.358 2006/09/18 22:40:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200609161
#define CATALOG_VERSION_NO 200609181
#endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.425 2006/09/16 20:14:33 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.426 2006/09/18 22:40:38 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@ -3946,6 +3946,34 @@ DESCR("contains");
DATA(insert OID = 2749 ( arraycontained PGNSP PGUID 12 f f t f i 2 16 "2277 2277" _null_ _null_ _null_ arraycontained - _null_ ));
DESCR("is contained by");
/* userlock replacements */
DATA(insert OID = 2880 ( pg_advisory_lock PGNSP PGUID 12 f f t f v 1 2278 "20" _null_ _null_ _null_ pg_advisory_lock_int8 - _null_ ));
DESCR("obtain exclusive advisory lock");
DATA(insert OID = 2881 ( pg_advisory_lock_shared PGNSP PGUID 12 f f t f v 1 2278 "20" _null_ _null_ _null_ pg_advisory_lock_shared_int8 - _null_ ));
DESCR("obtain shared advisory lock");
DATA(insert OID = 2882 ( pg_try_advisory_lock PGNSP PGUID 12 f f t f v 1 16 "20" _null_ _null_ _null_ pg_try_advisory_lock_int8 - _null_ ));
DESCR("obtain exclusive advisory lock if available");
DATA(insert OID = 2883 ( pg_try_advisory_lock_shared PGNSP PGUID 12 f f t f v 1 16 "20" _null_ _null_ _null_ pg_try_advisory_lock_shared_int8 - _null_ ));
DESCR("obtain shared advisory lock if available");
DATA(insert OID = 2884 ( pg_advisory_unlock PGNSP PGUID 12 f f t f v 1 16 "20" _null_ _null_ _null_ pg_advisory_unlock_int8 - _null_ ));
DESCR("release exclusive advisory lock");
DATA(insert OID = 2885 ( pg_advisory_unlock_shared PGNSP PGUID 12 f f t f v 1 16 "20" _null_ _null_ _null_ pg_advisory_unlock_shared_int8 - _null_ ));
DESCR("release shared advisory lock");
DATA(insert OID = 2886 ( pg_advisory_lock PGNSP PGUID 12 f f t f v 2 2278 "23 23" _null_ _null_ _null_ pg_advisory_lock_int4 - _null_ ));
DESCR("obtain exclusive advisory lock");
DATA(insert OID = 2887 ( pg_advisory_lock_shared PGNSP PGUID 12 f f t f v 2 2278 "23 23" _null_ _null_ _null_ pg_advisory_lock_shared_int4 - _null_ ));
DESCR("obtain shared advisory lock");
DATA(insert OID = 2888 ( pg_try_advisory_lock PGNSP PGUID 12 f f t f v 2 16 "23 23" _null_ _null_ _null_ pg_try_advisory_lock_int4 - _null_ ));
DESCR("obtain exclusive advisory lock if available");
DATA(insert OID = 2889 ( pg_try_advisory_lock_shared PGNSP PGUID 12 f f t f v 2 16 "23 23" _null_ _null_ _null_ pg_try_advisory_lock_shared_int4 - _null_ ));
DESCR("obtain shared advisory lock if available");
DATA(insert OID = 2890 ( pg_advisory_unlock PGNSP PGUID 12 f f t f v 2 16 "23 23" _null_ _null_ _null_ pg_advisory_unlock_int4 - _null_ ));
DESCR("release exclusive advisory lock");
DATA(insert OID = 2891 ( pg_advisory_unlock_shared PGNSP PGUID 12 f f t f v 2 16 "23 23" _null_ _null_ _null_ pg_advisory_unlock_shared_int4 - _null_ ));
DESCR("release shared advisory lock");
DATA(insert OID = 2892 ( pg_advisory_unlock_all PGNSP PGUID 12 f f t f v 0 2278 "" _null_ _null_ _null_ pg_advisory_unlock_all - _null_ ));
DESCR("release all advisory locks");
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,

View File

@ -6,7 +6,7 @@
* for developers. If you edit any of these, be sure to do a *full*
* rebuild (and an initdb if noted).
*
* $PostgreSQL: pgsql/src/include/pg_config_manual.h,v 1.22 2006/06/06 17:59:58 tgl Exp $
* $PostgreSQL: pgsql/src/include/pg_config_manual.h,v 1.23 2006/09/18 22:40:40 tgl Exp $
*------------------------------------------------------------------------
*/
@ -100,16 +100,6 @@
*/
/* #define TCL_ARRAYS */
/*
* User locks are handled totally on the application side as long term
* cooperative locks which extend beyond the normal transaction
* boundaries. Their purpose is to indicate to an application that
* someone is `working' on an item. Define this flag to enable user
* locks. You will need the loadable module user-locks.c to use this
* feature.
*/
#define USER_LOCKS
/*
* Define this if you want psql to _always_ ask for a username and a
* password for password authentication.

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.98 2006/08/27 19:14:34 tgl Exp $
* $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.99 2006/09/18 22:40:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -146,8 +146,7 @@ typedef enum LockTagType
* pg_description, but notice that we are constraining SUBID to 16 bits.
* Also, we use DB OID = 0 for shared objects such as tablespaces.
*/
LOCKTAG_USERLOCK /* reserved for contrib/userlock */
/* ID info for a userlock is defined by user_locks.c */
LOCKTAG_USERLOCK /* advisory "user" locks */
} LockTagType;
/*
@ -221,6 +220,14 @@ typedef struct LOCKTAG
(locktag).locktag_type = LOCKTAG_OBJECT, \
(locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
#define SET_LOCKTAG_USERLOCK(locktag,id1,id2,id3,id4) \
((locktag).locktag_field1 = (id1), \
(locktag).locktag_field2 = (id2), \
(locktag).locktag_field3 = (id3), \
(locktag).locktag_field4 = (id4), \
(locktag).locktag_type = LOCKTAG_USERLOCK, \
(locktag).locktag_lockmethodid = USER_LOCKMETHOD)
/*
* Per-locked-object lock information:
@ -362,8 +369,8 @@ typedef struct LOCALLOCK
/*
* This struct holds information passed from lmgr internals to the lock
* listing user-level functions (lockfuncs.c). For each PROCLOCK in the
* system, copies of the PROCLOCK object and associated PGPROC and
* listing user-level functions (in lockfuncs.c). For each PROCLOCK in
* the system, copies of the PROCLOCK object and associated PGPROC and
* LOCK objects are stored. Note there will often be multiple copies
* of the same PGPROC or LOCK --- to detect whether two are the same,
* compare the PROCLOCK tag fields.

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.281 2006/07/28 18:33:04 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.282 2006/09/18 22:40:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -892,6 +892,19 @@ extern Datum show_all_settings(PG_FUNCTION_ARGS);
/* lockfuncs.c */
extern Datum pg_lock_status(PG_FUNCTION_ARGS);
extern Datum pg_advisory_lock_int8(PG_FUNCTION_ARGS);
extern Datum pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS);
extern Datum pg_try_advisory_lock_int8(PG_FUNCTION_ARGS);
extern Datum pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS);
extern Datum pg_advisory_unlock_int8(PG_FUNCTION_ARGS);
extern Datum pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS);
extern Datum pg_advisory_lock_int4(PG_FUNCTION_ARGS);
extern Datum pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS);
extern Datum pg_try_advisory_lock_int4(PG_FUNCTION_ARGS);
extern Datum pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS);
extern Datum pg_advisory_unlock_int4(PG_FUNCTION_ARGS);
extern Datum pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS);
extern Datum pg_advisory_unlock_all(PG_FUNCTION_ARGS);
/* access/transam/twophase.c */
extern Datum pg_prepared_xact(PG_FUNCTION_ARGS);