diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/storage/lmgr/README | 11 | ||||
-rw-r--r-- | src/backend/storage/lmgr/lock.c | 101 | ||||
-rw-r--r-- | src/backend/storage/lmgr/proc.c | 5 | ||||
-rw-r--r-- | src/backend/utils/adt/lockfuncs.c | 154 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/catalog/pg_proc.h | 16 | ||||
-rw-r--r-- | src/include/storage/lock.h | 1 | ||||
-rw-r--r-- | src/include/utils/builtins.h | 8 | ||||
-rw-r--r-- | src/test/regress/expected/advisory_lock.out | 275 | ||||
-rw-r--r-- | src/test/regress/parallel_schedule | 2 | ||||
-rw-r--r-- | src/test/regress/serial_schedule | 1 | ||||
-rw-r--r-- | src/test/regress/sql/advisory_lock.sql | 146 |
12 files changed, 681 insertions, 41 deletions
diff --git a/src/backend/storage/lmgr/README b/src/backend/storage/lmgr/README index 40779d2e359..87fd312e314 100644 --- a/src/backend/storage/lmgr/README +++ b/src/backend/storage/lmgr/README @@ -505,7 +505,7 @@ User Locks ---------- User locks are handled totally on the application side as long term -cooperative locks which extend beyond the normal transaction boundaries. +cooperative locks which may extend beyond the normal transaction boundaries. Their purpose is to indicate to an application that someone is `working' on an item. So it is possible to put an user lock on a tuple's oid, retrieve the tuple, work on it for an hour and then update it and remove @@ -516,9 +516,12 @@ level by someone. User locks and normal locks are completely orthogonal and they don't interfere with each other. -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. +There are two types of user locks: session level and transaction level. +Session level user locks are not released at transaction end. They must +be released explicitly by the application --- but they are released +automatically when a backend terminates. On the other hand, transaction +level user locks are released automatically at the end of the transaction +as like as other normal locks. Locking during Hot Standby -------------------------- diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index cea5096c778..ed0ea1205f4 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -130,7 +130,7 @@ static const LockMethodData default_lockmethod = { static const LockMethodData user_lockmethod = { AccessExclusiveLock, /* highest valid lock mode number */ - false, + true, LockConflicts, lock_mode_names, #ifdef LOCK_DEBUG @@ -256,6 +256,7 @@ static uint32 proclock_hash(const void *key, Size keysize); static void RemoveLocalLock(LOCALLOCK *locallock); static void GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner); static void WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner); +static void ReleaseLockForOwner(LOCALLOCK *locallock, ResourceOwner owner); static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode, PROCLOCK *proclock, LockMethod lockMethodTable); static void CleanUpLock(LOCK *lock, PROCLOCK *proclock, @@ -1484,6 +1485,31 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock) } /* + * LockReleaseSession -- Release all session locks of the specified lock method + * that are held by the current process. + */ +void +LockReleaseSession(LOCKMETHODID lockmethodid) +{ + HASH_SEQ_STATUS status; + LOCALLOCK *locallock; + + if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods)) + elog(ERROR, "unrecognized lock method: %d", lockmethodid); + + hash_seq_init(&status, LockMethodLocalHash); + + while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL) + { + /* Ignore items that are not of the specified lock method */ + if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid) + continue; + + ReleaseLockForOwner(locallock, NULL); + } +} + +/* * LockReleaseAll -- Release all locks of the specified lock method that * are held by the current process. * @@ -1679,8 +1705,6 @@ LockReleaseCurrentOwner(void) { HASH_SEQ_STATUS status; LOCALLOCK *locallock; - LOCALLOCKOWNER *lockOwners; - int i; hash_seq_init(&status, LockMethodLocalHash); @@ -1690,38 +1714,51 @@ LockReleaseCurrentOwner(void) if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional) continue; - /* Scan to see if there are any locks belonging to current owner */ - lockOwners = locallock->lockOwners; - for (i = locallock->numLockOwners - 1; i >= 0; i--) + ReleaseLockForOwner(locallock, CurrentResourceOwner); + } +} + +/* + * Subroutine to release a lock belonging to the 'owner' if found. + * 'owner' can be NULL to release a session lock. + */ +static void +ReleaseLockForOwner(LOCALLOCK *locallock, ResourceOwner owner) +{ + int i; + LOCALLOCKOWNER *lockOwners; + + /* Scan to see if there are any locks belonging to the owner */ + lockOwners = locallock->lockOwners; + for (i = locallock->numLockOwners - 1; i >= 0; i--) + { + if (lockOwners[i].owner == owner) { - if (lockOwners[i].owner == CurrentResourceOwner) + Assert(lockOwners[i].nLocks > 0); + if (lockOwners[i].nLocks < locallock->nLocks) { - Assert(lockOwners[i].nLocks > 0); - if (lockOwners[i].nLocks < locallock->nLocks) - { - /* - * We will still hold this lock after forgetting this - * ResourceOwner. - */ - locallock->nLocks -= lockOwners[i].nLocks; - /* compact out unused slot */ - locallock->numLockOwners--; - if (i < locallock->numLockOwners) - lockOwners[i] = lockOwners[locallock->numLockOwners]; - } - else - { - Assert(lockOwners[i].nLocks == locallock->nLocks); - /* We want to call LockRelease just once */ - lockOwners[i].nLocks = 1; - locallock->nLocks = 1; - if (!LockRelease(&locallock->tag.lock, - locallock->tag.mode, - false)) - elog(WARNING, "LockReleaseCurrentOwner: failed??"); - } - break; + /* + * We will still hold this lock after forgetting this + * ResourceOwner. + */ + locallock->nLocks -= lockOwners[i].nLocks; + /* compact out unused slot */ + locallock->numLockOwners--; + if (i < locallock->numLockOwners) + lockOwners[i] = lockOwners[locallock->numLockOwners]; + } + else + { + Assert(lockOwners[i].nLocks == locallock->nLocks); + /* We want to call LockRelease just once */ + lockOwners[i].nLocks = 1; + locallock->nLocks = 1; + if (!LockRelease(&locallock->tag.lock, + locallock->tag.mode, + owner == NULL)) + elog(WARNING, "ReleaseLockForOwner: failed??"); } + break; } } } diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index be577bcd5fd..afaf5995f00 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -629,8 +629,6 @@ LockWaitCancel(void) * At subtransaction abort, we release all locks held by the subtransaction; * this is implemented by retail releasing of the locks under control of * the ResourceOwner mechanism. - * - * Note that user locks are not released in any case. */ void ProcReleaseLocks(bool isCommit) @@ -641,6 +639,9 @@ ProcReleaseLocks(bool isCommit) LockWaitCancel(); /* Release locks */ LockReleaseAll(DEFAULT_LOCKMETHOD, !isCommit); + + /* Release transaction level advisory locks */ + LockReleaseAll(USER_LOCKMETHOD, false); } diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index 8e369826cec..c6c948ce5e7 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -422,6 +422,23 @@ pg_advisory_lock_int8(PG_FUNCTION_ARGS) } /* + * pg_advisory_xact_lock(int8) - acquire xact scoped + * exclusive lock on an int8 key + */ +Datum +pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS) +{ + int64 key = PG_GETARG_INT64(0); + LOCKTAG tag; + + SET_LOCKTAG_INT64(tag, key); + + (void) LockAcquire(&tag, ExclusiveLock, false, false); + + PG_RETURN_VOID(); +} + +/* * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key */ Datum @@ -438,6 +455,23 @@ pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS) } /* + * pg_advisory_xact_lock_shared(int8) - acquire xact scoped + * share lock on an int8 key + */ +Datum +pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS) +{ + int64 key = PG_GETARG_INT64(0); + LOCKTAG tag; + + SET_LOCKTAG_INT64(tag, key); + + (void) LockAcquire(&tag, ShareLock, false, 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 @@ -457,6 +491,26 @@ pg_try_advisory_lock_int8(PG_FUNCTION_ARGS) } /* + * pg_try_advisory_xact_lock(int8) - acquire xact scoped + * exclusive lock on an int8 key, no wait + * + * Returns true if successful, false if lock not available + */ +Datum +pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS) +{ + int64 key = PG_GETARG_INT64(0); + LOCKTAG tag; + LockAcquireResult res; + + SET_LOCKTAG_INT64(tag, key); + + res = LockAcquire(&tag, ExclusiveLock, false, 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 @@ -476,6 +530,26 @@ pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS) } /* + * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped + * share lock on an int8 key, no wait + * + * Returns true if successful, false if lock not available + */ +Datum +pg_try_advisory_xact_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, false, 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 @@ -531,6 +605,24 @@ pg_advisory_lock_int4(PG_FUNCTION_ARGS) } /* + * pg_advisory_xact_lock(int4, int4) - acquire xact scoped + * exclusive lock on 2 int4 keys + */ +Datum +pg_advisory_xact_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, false, false); + + PG_RETURN_VOID(); +} + +/* * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys */ Datum @@ -548,6 +640,24 @@ pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS) } /* + * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped + * share lock on 2 int4 keys + */ +Datum +pg_advisory_xact_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, false, 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 @@ -568,6 +678,27 @@ pg_try_advisory_lock_int4(PG_FUNCTION_ARGS) } /* + * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped + * exclusive lock on 2 int4 keys, no wait + * + * Returns true if successful, false if lock not available + */ +Datum +pg_try_advisory_xact_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, false, 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 @@ -588,6 +719,27 @@ pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS) } /* + * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped + * share lock on 2 int4 keys, no wait + * + * Returns true if successful, false if lock not available + */ +Datum +pg_try_advisory_xact_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, false, 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 @@ -633,7 +785,7 @@ pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS) Datum pg_advisory_unlock_all(PG_FUNCTION_ARGS) { - LockReleaseAll(USER_LOCKMETHOD, true); + LockReleaseSession(USER_LOCKMETHOD); PG_RETURN_VOID(); } diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 7fb33f09e33..1a7be47fab8 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201102171 +#define CATALOG_VERSION_NO 201102181 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 60a2e623f23..b3458ed56eb 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -4420,25 +4420,41 @@ DESCR("is contained by"); /* userlock replacements */ DATA(insert OID = 2880 ( pg_advisory_lock PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ pg_advisory_lock_int8 _null_ _null_ _null_ )); +DESCR("obtain exclusive a4dvisory lock"); +DATA(insert OID = 3089 ( pg_advisory_xact_lock PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ pg_advisory_xact_lock_int8 _null_ _null_ _null_ )); DESCR("obtain exclusive advisory lock"); DATA(insert OID = 2881 ( pg_advisory_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ pg_advisory_lock_shared_int8 _null_ _null_ _null_ )); DESCR("obtain shared advisory lock"); +DATA(insert OID = 3090 ( pg_advisory_xact_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ pg_advisory_xact_lock_shared_int8 _null_ _null_ _null_ )); +DESCR("obtain shared advisory lock"); DATA(insert OID = 2882 ( pg_try_advisory_lock PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_try_advisory_lock_int8 _null_ _null_ _null_ )); DESCR("obtain exclusive advisory lock if available"); +DATA(insert OID = 3091 ( pg_try_advisory_xact_lock PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_int8 _null_ _null_ _null_ )); +DESCR("obtain exclusive advisory lock if available"); DATA(insert OID = 2883 ( pg_try_advisory_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_try_advisory_lock_shared_int8 _null_ _null_ _null_ )); DESCR("obtain shared advisory lock if available"); +DATA(insert OID = 3092 ( pg_try_advisory_xact_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_shared_int8 _null_ _null_ _null_ )); +DESCR("obtain shared advisory lock if available"); DATA(insert OID = 2884 ( pg_advisory_unlock PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_advisory_unlock_int8 _null_ _null_ _null_ )); DESCR("release exclusive advisory lock"); DATA(insert OID = 2885 ( pg_advisory_unlock_shared PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_advisory_unlock_shared_int8 _null_ _null_ _null_ )); DESCR("release shared advisory lock"); DATA(insert OID = 2886 ( pg_advisory_lock PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2278 "23 23" _null_ _null_ _null_ _null_ pg_advisory_lock_int4 _null_ _null_ _null_ )); DESCR("obtain exclusive advisory lock"); +DATA(insert OID = 3093 ( pg_advisory_xact_lock PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2278 "23 23" _null_ _null_ _null_ _null_ pg_advisory_xact_lock_int4 _null_ _null_ _null_ )); +DESCR("obtain exclusive advisory lock"); DATA(insert OID = 2887 ( pg_advisory_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2278 "23 23" _null_ _null_ _null_ _null_ pg_advisory_lock_shared_int4 _null_ _null_ _null_ )); DESCR("obtain shared advisory lock"); +DATA(insert OID = 3094 ( pg_advisory_xact_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2278 "23 23" _null_ _null_ _null_ _null_ pg_advisory_xact_lock_shared_int4 _null_ _null_ _null_ )); +DESCR("obtain shared advisory lock"); DATA(insert OID = 2888 ( pg_try_advisory_lock PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_try_advisory_lock_int4 _null_ _null_ _null_ )); DESCR("obtain exclusive advisory lock if available"); +DATA(insert OID = 3095 ( pg_try_advisory_xact_lock PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_int4 _null_ _null_ _null_ )); +DESCR("obtain exclusive advisory lock if available"); DATA(insert OID = 2889 ( pg_try_advisory_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_try_advisory_lock_shared_int4 _null_ _null_ _null_ )); DESCR("obtain shared advisory lock if available"); +DATA(insert OID = 3096 ( pg_try_advisory_xact_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_shared_int4 _null_ _null_ _null_ )); +DESCR("obtain shared advisory lock if available"); DATA(insert OID = 2890 ( pg_advisory_unlock PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_advisory_unlock_int4 _null_ _null_ _null_ )); DESCR("release exclusive advisory lock"); DATA(insert OID = 2891 ( pg_advisory_unlock_shared PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_advisory_unlock_shared_int4 _null_ _null_ _null_ )); diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index 7b52d2e6d16..7ec961f4430 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -484,6 +484,7 @@ extern LockAcquireResult LockAcquireExtended(const LOCKTAG *locktag, bool report_memory_error); extern bool LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock); +extern void LockReleaseSession(LOCKMETHODID lockmethodid); extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks); extern void LockReleaseCurrentOwner(void); extern void LockReassignCurrentOwner(void); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 4341025d06a..277aec414c3 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -995,15 +995,23 @@ 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_xact_lock_int8(PG_FUNCTION_ARGS); extern Datum pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS); +extern Datum pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS); extern Datum pg_try_advisory_lock_int8(PG_FUNCTION_ARGS); +extern Datum pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS); extern Datum pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS); +extern Datum pg_try_advisory_xact_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_xact_lock_int4(PG_FUNCTION_ARGS); extern Datum pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS); +extern Datum pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS); extern Datum pg_try_advisory_lock_int4(PG_FUNCTION_ARGS); +extern Datum pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS); extern Datum pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS); +extern Datum pg_try_advisory_xact_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); diff --git a/src/test/regress/expected/advisory_lock.out b/src/test/regress/expected/advisory_lock.out new file mode 100644 index 00000000000..2a2df6f7e4b --- /dev/null +++ b/src/test/regress/expected/advisory_lock.out @@ -0,0 +1,275 @@ +-- +-- ADVISORY LOCKS +-- +BEGIN; +SELECT + pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2), + pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2); + pg_advisory_xact_lock | pg_advisory_xact_lock_shared | pg_advisory_xact_lock | pg_advisory_xact_lock_shared +-----------------------+------------------------------+-----------------------+------------------------------ + | | | +(1 row) + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + locktype | classid | objid | objsubid | mode | granted +----------+---------+-------+----------+---------------+--------- + advisory | 0 | 1 | 1 | ExclusiveLock | t + advisory | 0 | 2 | 1 | ShareLock | t + advisory | 1 | 1 | 2 | ExclusiveLock | t + advisory | 2 | 2 | 2 | ShareLock | t +(4 rows) + +-- pg_advisory_unlock_all() shouldn't release xact locks +SELECT pg_advisory_unlock_all(); + pg_advisory_unlock_all +------------------------ + +(1 row) + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + count +------- + 4 +(1 row) + +-- can't unlock xact locks +SELECT + pg_advisory_unlock(1), pg_advisory_unlock_shared(2), + pg_advisory_unlock(1, 1), pg_advisory_unlock_shared(2, 2); +WARNING: you don't own a lock of type ExclusiveLock +WARNING: you don't own a lock of type ShareLock +WARNING: you don't own a lock of type ExclusiveLock +WARNING: you don't own a lock of type ShareLock + pg_advisory_unlock | pg_advisory_unlock_shared | pg_advisory_unlock | pg_advisory_unlock_shared +--------------------+---------------------------+--------------------+--------------------------- + f | f | f | f +(1 row) + +-- automatically release xact locks at commit +COMMIT; +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + count +------- + 0 +(1 row) + +BEGIN; +-- holding both session and xact locks on the same objects, xact first +SELECT + pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2), + pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2); + pg_advisory_xact_lock | pg_advisory_xact_lock_shared | pg_advisory_xact_lock | pg_advisory_xact_lock_shared +-----------------------+------------------------------+-----------------------+------------------------------ + | | | +(1 row) + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + locktype | classid | objid | objsubid | mode | granted +----------+---------+-------+----------+---------------+--------- + advisory | 0 | 1 | 1 | ExclusiveLock | t + advisory | 0 | 2 | 1 | ShareLock | t + advisory | 1 | 1 | 2 | ExclusiveLock | t + advisory | 2 | 2 | 2 | ShareLock | t +(4 rows) + +SELECT + pg_advisory_lock(1), pg_advisory_lock_shared(2), + pg_advisory_lock(1, 1), pg_advisory_lock_shared(2, 2); + pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock | pg_advisory_lock_shared +------------------+-------------------------+------------------+------------------------- + | | | +(1 row) + +ROLLBACK; +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + locktype | classid | objid | objsubid | mode | granted +----------+---------+-------+----------+---------------+--------- + advisory | 0 | 1 | 1 | ExclusiveLock | t + advisory | 0 | 2 | 1 | ShareLock | t + advisory | 1 | 1 | 2 | ExclusiveLock | t + advisory | 2 | 2 | 2 | ShareLock | t +(4 rows) + +-- unlocking session locks +SELECT + pg_advisory_unlock(1), pg_advisory_unlock(1), + pg_advisory_unlock_shared(2), pg_advisory_unlock_shared(2), + pg_advisory_unlock(1, 1), pg_advisory_unlock(1, 1), + pg_advisory_unlock_shared(2, 2), pg_advisory_unlock_shared(2, 2); +WARNING: you don't own a lock of type ExclusiveLock +WARNING: you don't own a lock of type ShareLock +WARNING: you don't own a lock of type ExclusiveLock +WARNING: you don't own a lock of type ShareLock + pg_advisory_unlock | pg_advisory_unlock | pg_advisory_unlock_shared | pg_advisory_unlock_shared | pg_advisory_unlock | pg_advisory_unlock | pg_advisory_unlock_shared | pg_advisory_unlock_shared +--------------------+--------------------+---------------------------+---------------------------+--------------------+--------------------+---------------------------+--------------------------- + t | f | t | f | t | f | t | f +(1 row) + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + count +------- + 0 +(1 row) + +BEGIN; +-- holding both session and xact locks on the same objects, session first +SELECT + pg_advisory_lock(1), pg_advisory_lock_shared(2), + pg_advisory_lock(1, 1), pg_advisory_lock_shared(2, 2); + pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock | pg_advisory_lock_shared +------------------+-------------------------+------------------+------------------------- + | | | +(1 row) + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + locktype | classid | objid | objsubid | mode | granted +----------+---------+-------+----------+---------------+--------- + advisory | 0 | 1 | 1 | ExclusiveLock | t + advisory | 0 | 2 | 1 | ShareLock | t + advisory | 1 | 1 | 2 | ExclusiveLock | t + advisory | 2 | 2 | 2 | ShareLock | t +(4 rows) + +SELECT + pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2), + pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2); + pg_advisory_xact_lock | pg_advisory_xact_lock_shared | pg_advisory_xact_lock | pg_advisory_xact_lock_shared +-----------------------+------------------------------+-----------------------+------------------------------ + | | | +(1 row) + +ROLLBACK; +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + locktype | classid | objid | objsubid | mode | granted +----------+---------+-------+----------+---------------+--------- + advisory | 0 | 1 | 1 | ExclusiveLock | t + advisory | 0 | 2 | 1 | ShareLock | t + advisory | 1 | 1 | 2 | ExclusiveLock | t + advisory | 2 | 2 | 2 | ShareLock | t +(4 rows) + +-- releasing all session locks +SELECT pg_advisory_unlock_all(); + pg_advisory_unlock_all +------------------------ + +(1 row) + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + count +------- + 0 +(1 row) + +BEGIN; +-- grabbing txn locks multiple times +SELECT + pg_advisory_xact_lock(1), pg_advisory_xact_lock(1), + pg_advisory_xact_lock_shared(2), pg_advisory_xact_lock_shared(2), + pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock(1, 1), + pg_advisory_xact_lock_shared(2, 2), pg_advisory_xact_lock_shared(2, 2); + pg_advisory_xact_lock | pg_advisory_xact_lock | pg_advisory_xact_lock_shared | pg_advisory_xact_lock_shared | pg_advisory_xact_lock | pg_advisory_xact_lock | pg_advisory_xact_lock_shared | pg_advisory_xact_lock_shared +-----------------------+-----------------------+------------------------------+------------------------------+-----------------------+-----------------------+------------------------------+------------------------------ + | | | | | | | +(1 row) + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + locktype | classid | objid | objsubid | mode | granted +----------+---------+-------+----------+---------------+--------- + advisory | 0 | 1 | 1 | ExclusiveLock | t + advisory | 0 | 2 | 1 | ShareLock | t + advisory | 1 | 1 | 2 | ExclusiveLock | t + advisory | 2 | 2 | 2 | ShareLock | t +(4 rows) + +COMMIT; +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + count +------- + 0 +(1 row) + +-- grabbing session locks multiple times +SELECT + pg_advisory_lock(1), pg_advisory_lock(1), + pg_advisory_lock_shared(2), pg_advisory_lock_shared(2), + pg_advisory_lock(1, 1), pg_advisory_lock(1, 1), + pg_advisory_lock_shared(2, 2), pg_advisory_lock_shared(2, 2); + pg_advisory_lock | pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock_shared | pg_advisory_lock | pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock_shared +------------------+------------------+-------------------------+-------------------------+------------------+------------------+-------------------------+------------------------- + | | | | | | | +(1 row) + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + locktype | classid | objid | objsubid | mode | granted +----------+---------+-------+----------+---------------+--------- + advisory | 0 | 1 | 1 | ExclusiveLock | t + advisory | 0 | 2 | 1 | ShareLock | t + advisory | 1 | 1 | 2 | ExclusiveLock | t + advisory | 2 | 2 | 2 | ShareLock | t +(4 rows) + +SELECT + pg_advisory_unlock(1), pg_advisory_unlock(1), + pg_advisory_unlock_shared(2), pg_advisory_unlock_shared(2), + pg_advisory_unlock(1, 1), pg_advisory_unlock(1, 1), + pg_advisory_unlock_shared(2, 2), pg_advisory_unlock_shared(2, 2); + pg_advisory_unlock | pg_advisory_unlock | pg_advisory_unlock_shared | pg_advisory_unlock_shared | pg_advisory_unlock | pg_advisory_unlock | pg_advisory_unlock_shared | pg_advisory_unlock_shared +--------------------+--------------------+---------------------------+---------------------------+--------------------+--------------------+---------------------------+--------------------------- + t | t | t | t | t | t | t | t +(1 row) + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + count +------- + 0 +(1 row) + +-- .. and releasing them all at once +SELECT + pg_advisory_lock(1), pg_advisory_lock(1), + pg_advisory_lock_shared(2), pg_advisory_lock_shared(2), + pg_advisory_lock(1, 1), pg_advisory_lock(1, 1), + pg_advisory_lock_shared(2, 2), pg_advisory_lock_shared(2, 2); + pg_advisory_lock | pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock_shared | pg_advisory_lock | pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock_shared +------------------+------------------+-------------------------+-------------------------+------------------+------------------+-------------------------+------------------------- + | | | | | | | +(1 row) + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + locktype | classid | objid | objsubid | mode | granted +----------+---------+-------+----------+---------------+--------- + advisory | 0 | 1 | 1 | ExclusiveLock | t + advisory | 0 | 2 | 1 | ShareLock | t + advisory | 1 | 1 | 2 | ExclusiveLock | t + advisory | 2 | 2 | 2 | ShareLock | t +(4 rows) + +SELECT pg_advisory_unlock_all(); + pg_advisory_unlock_all +------------------------ + +(1 row) + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + count +------- + 0 +(1 row) + diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 3b99e867efe..aa6f6d2ddd8 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -84,7 +84,7 @@ test: rules # ---------- # Another group of parallel tests # ---------- -test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps +test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock # ---------- # Another group of parallel tests diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index b348f0e1a94..b76b1877a7e 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -105,6 +105,7 @@ test: foreign_data test: window test: xmlmap test: functional_deps +test: advisory_lock test: plancache test: limit test: plpgsql diff --git a/src/test/regress/sql/advisory_lock.sql b/src/test/regress/sql/advisory_lock.sql new file mode 100644 index 00000000000..57c47c0faca --- /dev/null +++ b/src/test/regress/sql/advisory_lock.sql @@ -0,0 +1,146 @@ +-- +-- ADVISORY LOCKS +-- + +BEGIN; + +SELECT + pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2), + pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2); + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + + +-- pg_advisory_unlock_all() shouldn't release xact locks +SELECT pg_advisory_unlock_all(); + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + + +-- can't unlock xact locks +SELECT + pg_advisory_unlock(1), pg_advisory_unlock_shared(2), + pg_advisory_unlock(1, 1), pg_advisory_unlock_shared(2, 2); + + +-- automatically release xact locks at commit +COMMIT; + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + + +BEGIN; + +-- holding both session and xact locks on the same objects, xact first +SELECT + pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2), + pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2); + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + +SELECT + pg_advisory_lock(1), pg_advisory_lock_shared(2), + pg_advisory_lock(1, 1), pg_advisory_lock_shared(2, 2); + +ROLLBACK; + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + + +-- unlocking session locks +SELECT + pg_advisory_unlock(1), pg_advisory_unlock(1), + pg_advisory_unlock_shared(2), pg_advisory_unlock_shared(2), + pg_advisory_unlock(1, 1), pg_advisory_unlock(1, 1), + pg_advisory_unlock_shared(2, 2), pg_advisory_unlock_shared(2, 2); + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + + +BEGIN; + +-- holding both session and xact locks on the same objects, session first +SELECT + pg_advisory_lock(1), pg_advisory_lock_shared(2), + pg_advisory_lock(1, 1), pg_advisory_lock_shared(2, 2); + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + +SELECT + pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2), + pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2); + +ROLLBACK; + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + + +-- releasing all session locks +SELECT pg_advisory_unlock_all(); + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + + +BEGIN; + +-- grabbing txn locks multiple times + +SELECT + pg_advisory_xact_lock(1), pg_advisory_xact_lock(1), + pg_advisory_xact_lock_shared(2), pg_advisory_xact_lock_shared(2), + pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock(1, 1), + pg_advisory_xact_lock_shared(2, 2), pg_advisory_xact_lock_shared(2, 2); + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + +COMMIT; + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + +-- grabbing session locks multiple times + +SELECT + pg_advisory_lock(1), pg_advisory_lock(1), + pg_advisory_lock_shared(2), pg_advisory_lock_shared(2), + pg_advisory_lock(1, 1), pg_advisory_lock(1, 1), + pg_advisory_lock_shared(2, 2), pg_advisory_lock_shared(2, 2); + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + +SELECT + pg_advisory_unlock(1), pg_advisory_unlock(1), + pg_advisory_unlock_shared(2), pg_advisory_unlock_shared(2), + pg_advisory_unlock(1, 1), pg_advisory_unlock(1, 1), + pg_advisory_unlock_shared(2, 2), pg_advisory_unlock_shared(2, 2); + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; + +-- .. and releasing them all at once + +SELECT + pg_advisory_lock(1), pg_advisory_lock(1), + pg_advisory_lock_shared(2), pg_advisory_lock_shared(2), + pg_advisory_lock(1, 1), pg_advisory_lock(1, 1), + pg_advisory_lock_shared(2, 2), pg_advisory_lock_shared(2, 2); + +SELECT locktype, classid, objid, objsubid, mode, granted + FROM pg_locks WHERE locktype = 'advisory' + ORDER BY classid, objid, objsubid; + +SELECT pg_advisory_unlock_all(); + +SELECT count(*) FROM pg_locks WHERE locktype = 'advisory'; |