aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorItagaki Takahiro <itagaki.takahiro@gmail.com>2011-02-18 14:04:34 +0900
committerItagaki Takahiro <itagaki.takahiro@gmail.com>2011-02-18 14:05:12 +0900
commit62c7bd31c8878dd45c9b9b2429ab7a12103f3590 (patch)
tree014f8484ac6e96ce9fb48ee13272d57a04495f44 /src
parent87bb2ade2ce646083f39d5ab3e3307490211ad04 (diff)
downloadpostgresql-62c7bd31c8878dd45c9b9b2429ab7a12103f3590.tar.gz
postgresql-62c7bd31c8878dd45c9b9b2429ab7a12103f3590.zip
Add transaction-level advisory locks.
They share the same locking namespace with the existing session-level advisory locks, but they are automatically released at the end of the current transaction and cannot be released explicitly via unlock functions. Marko Tiikkaja, reviewed by me.
Diffstat (limited to 'src')
-rw-r--r--src/backend/storage/lmgr/README11
-rw-r--r--src/backend/storage/lmgr/lock.c101
-rw-r--r--src/backend/storage/lmgr/proc.c5
-rw-r--r--src/backend/utils/adt/lockfuncs.c154
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_proc.h16
-rw-r--r--src/include/storage/lock.h1
-rw-r--r--src/include/utils/builtins.h8
-rw-r--r--src/test/regress/expected/advisory_lock.out275
-rw-r--r--src/test/regress/parallel_schedule2
-rw-r--r--src/test/regress/serial_schedule1
-rw-r--r--src/test/regress/sql/advisory_lock.sql146
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';