]> granicus.if.org Git - postgresql/commitdiff
Add transaction-level advisory locks.
authorItagaki Takahiro <itagaki.takahiro@gmail.com>
Fri, 18 Feb 2011 05:04:34 +0000 (14:04 +0900)
committerItagaki Takahiro <itagaki.takahiro@gmail.com>
Fri, 18 Feb 2011 05:05:12 +0000 (14:05 +0900)
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.

14 files changed:
doc/src/sgml/func.sgml
doc/src/sgml/mvcc.sgml
src/backend/storage/lmgr/README
src/backend/storage/lmgr/lock.c
src/backend/storage/lmgr/proc.c
src/backend/utils/adt/lockfuncs.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/storage/lock.h
src/include/utils/builtins.h
src/test/regress/expected/advisory_lock.out [new file with mode: 0644]
src/test/regress/parallel_schedule
src/test/regress/serial_schedule
src/test/regress/sql/advisory_lock.sql [new file with mode: 0644]

index 70a1bd9ee9fb9559cefaf5573bc73d4237525e70..736eb67dfffbbe2110b86b63aa93108a75c5a1b6 100644 (file)
@@ -14623,91 +14623,147 @@ SELECT (pg_stat_file('filename')).modification;
         <literal><function>pg_advisory_lock(<parameter>key</> <type>bigint</>)</function></literal>
        </entry>
        <entry><type>void</type></entry>
-       <entry>Obtain exclusive advisory lock</entry>
+       <entry>Obtain exclusive session level advisory lock</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_advisory_lock(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</function></literal>
        </entry>
        <entry><type>void</type></entry>
-       <entry>Obtain exclusive advisory lock</entry>
+       <entry>Obtain exclusive session level advisory lock</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_advisory_lock_shared(<parameter>key</> <type>bigint</>)</function></literal>
        </entry>
        <entry><type>void</type></entry>
-       <entry>Obtain shared advisory lock</entry>
+       <entry>Obtain shared session level advisory lock</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_advisory_lock_shared(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</function></literal>
        </entry>
        <entry><type>void</type></entry>
-       <entry>Obtain shared advisory lock</entry>
+       <entry>Obtain shared session level advisory lock</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_advisory_unlock(<parameter>key</> <type>bigint</>)</function></literal>
        </entry>
        <entry><type>boolean</type></entry>
-       <entry>Release an exclusive advisory lock</entry>
+       <entry>Release an exclusive session level advisory lock</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_advisory_unlock(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</function></literal>
        </entry>
        <entry><type>boolean</type></entry>
-       <entry>Release an exclusive advisory lock</entry>
+       <entry>Release an exclusive session level advisory lock</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_advisory_unlock_all()</function></literal>
        </entry>
        <entry><type>void</type></entry>
-       <entry>Release all advisory locks held by the current session</entry>
+       <entry>Release all session level advisory locks held by the current session</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_advisory_unlock_shared(<parameter>key</> <type>bigint</>)</function></literal>
        </entry>
        <entry><type>boolean</type></entry>
-       <entry>Release a shared advisory lock</entry>
+       <entry>Release a shared session level advisory lock</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_advisory_unlock_shared(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</function></literal>
        </entry>
        <entry><type>boolean</type></entry>
-       <entry>Release a shared advisory lock</entry>
+       <entry>Release a shared session level advisory lock</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_advisory_xact_lock(<parameter>key</> <type>bigint</>)</function></literal>
+       </entry>
+       <entry><type>void</type></entry>
+       <entry>Obtain exclusive transaction level advisory lock</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_advisory_xact_lock(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</function></literal>
+       </entry>
+       <entry><type>void</type></entry>
+       <entry>Obtain exclusive transaction level advisory lock</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_advisory_xact_lock_shared(<parameter>key</> <type>bigint</>)</function></literal>
+       </entry>
+       <entry><type>void</type></entry>
+       <entry>Obtain shared transaction level advisory lock</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_advisory_xact_lock_shared(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</function></literal>
+       </entry>
+       <entry><type>void</type></entry>
+       <entry>Obtain shared advisory lock for the current transaction</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_try_advisory_lock(<parameter>key</> <type>bigint</>)</function></literal>
        </entry>
        <entry><type>boolean</type></entry>
-       <entry>Obtain exclusive advisory lock if available</entry>
+       <entry>Obtain exclusive session level advisory lock if available</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_try_advisory_lock(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</function></literal>
        </entry>
        <entry><type>boolean</type></entry>
-       <entry>Obtain exclusive advisory lock if available</entry>
+       <entry>Obtain exclusive session level advisory lock if available</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_try_advisory_lock_shared(<parameter>key</> <type>bigint</>)</function></literal>
        </entry>
        <entry><type>boolean</type></entry>
-       <entry>Obtain shared advisory lock if available</entry>
+       <entry>Obtain shared session level advisory lock if available</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_try_advisory_lock_shared(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</function></literal>
        </entry>
        <entry><type>boolean</type></entry>
-       <entry>Obtain shared advisory lock if available</entry>
+       <entry>Obtain shared session level advisory lock if available</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_try_advisory_xact_lock(<parameter>key</> <type>bigint</>)</function></literal>
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>Obtain exclusive transaction level advisory lock if available</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_try_advisory_xact_lock(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</function></literal>
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>Obtain exclusive transaction level advisory lock if available</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_try_advisory_xact_lock_shared(<parameter>key</> <type>bigint</>)</function></literal>
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>Obtain shared transaction level advisory lock if available</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_try_advisory_xact_lock_shared(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</function></literal>
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>Obtain shared transaction level advisory lock if available</entry>
       </row>
      </tbody>
     </tgroup>
@@ -14758,12 +14814,50 @@ SELECT (pg_stat_file('filename')).modification;
     a shared rather than an exclusive lock.
    </para>
 
+   <indexterm>
+    <primary>pg_advisory_xact_lock</primary>
+   </indexterm>
+   <para>
+    <function>pg_advisory_xact_lock</> works the same as
+    <function>pg_advisory_lock</>, expect the lock is automatically released
+    at the end of the current transaction and can not be released explicitly.
+   </para>
+
+   <indexterm>
+    <primary>pg_advisory_xact_lock_shared</primary>
+   </indexterm>
+   <para>
+    <function>pg_advisory_xact_lock_shared</> works the same as
+    <function>pg_advisory_lock_shared</>, expect the lock is automatically released
+    at the end of the current transaction and can not be released explicitly.
+   </para>
+
+   <indexterm>
+    <primary>pg_try_advisory_xact_lock</primary>
+   </indexterm>
+   <para>
+    <function>pg_try_advisory_xact_lock</> works the same as
+    <function>pg_try_advisory_lock</>, expect the lock, if acquired,
+    is automatically released at the end of the current transaction and
+    can not be released explicitly.
+   </para>
+
+   <indexterm>
+    <primary>pg_try_advisory_xact_lock_shared</primary>
+   </indexterm>
+   <para>
+    <function>pg_try_advisory_xact_lock_shared</> works the same as
+    <function>pg_try_advisory_lock_shared</>, expect the lock, if acquired,
+    is automatically released at the end of the current transaction and
+    can not be released explicitly.
+   </para>
+
    <indexterm>
     <primary>pg_advisory_unlock</primary>
    </indexterm>
    <para>
     <function>pg_advisory_unlock</> will release a previously-acquired
-    exclusive advisory lock.  It
+    exclusive session level advisory lock.  It
     returns <literal>true</> if the lock is successfully released.
     If the lock was not held, it will return <literal>false</>,
     and in addition, an SQL warning will be raised by the server.
@@ -14775,15 +14869,15 @@ SELECT (pg_stat_file('filename')).modification;
    <para>
     <function>pg_advisory_unlock_shared</> works the same as
     <function>pg_advisory_unlock</>,
-    except it releases a shared advisory lock.
+    except it releases a shared session level advisory lock.
    </para>
 
    <indexterm>
     <primary>pg_advisory_unlock_all</primary>
    </indexterm>
    <para>
-    <function>pg_advisory_unlock_all</> will release all advisory locks
-    held by the current session.  (This function is implicitly invoked
+    <function>pg_advisory_unlock_all</> will release all session level advisory
+    locks held by the current session.  (This function is implicitly invoked
     at session end, even if the client disconnects ungracefully.)
    </para>
 
index f42bb091c13a5902cadbf25aaf48fa404aadb39a..785c9d752181b9e93f165ca73ea187c1663bf7d1 100644 (file)
@@ -1199,19 +1199,28 @@ UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 22222;
      called <firstterm>advisory locks</>, because the system does not
      enforce their use &mdash; it is up to the application to use them
      correctly.  Advisory locks can be useful for locking strategies
-     that are an awkward fit for the MVCC model.  Once acquired, an
-     advisory lock is held until explicitly released or the session ends.
-     Unlike standard locks, advisory locks do not
-     honor transaction semantics: a lock acquired during a
-     transaction that is later rolled back will still be held following the
+     that are an awkward fit for the MVCC model.</para>
+
+    <para>
+     There are two different types of advisory locks in
+     <productname>PostgreSQL</productname>: session level and transaction level.
+     Once acquired, a session level advisory lock is held until explicitly
+     released or the session ends.  Unlike standard locks, session level
+     advisory locks do not honor transaction semantics: a lock acquired during
+     a transaction that is later rolled back will still be held following the
      rollback, and likewise an unlock is effective even if the calling
-     transaction fails later.  The same lock can be acquired multiple times by
-     its owning process: for each lock request there must be a corresponding
-     unlock request before the lock is actually released.  (If a session
-     already holds a given lock, additional requests will always succeed, even
-     if other sessions are awaiting the lock.)  Like all locks in
-     <productname>PostgreSQL</productname>, a complete list of advisory
-     locks currently held by any session can be found in the
+     transaction fails later.  The same session level lock can be acquired
+     multiple times by its owning process: for each lock request there must be
+     a corresponding unlock request before the lock is actually released.  (If a
+     session already holds a given lock, additional requests will always succeed,
+     even if other sessions are awaiting the lock.)  Transaction level locks on
+     the other hand behave more like regular locks; they are automatically
+     released at the end of the transaction, and can not be explicitly unlocked.
+     Session and transaction level locks share the same lock space, which means
+     that a transaction level lock will prevent another session from obtaining
+     a session level lock on that same resource and vice versa.
+     Like all locks in <productname>PostgreSQL</productname>, a complete list of
+     advisory locks currently held by any session can be found in the
      <link linkend="view-pg-locks"><structname>pg_locks</structname></link>
      system view.
     </para>
@@ -1233,7 +1242,7 @@ UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 22222;
      strategies typical of so called <quote>flat file</> data management
      systems.
      While a flag stored in a table could be used for the same purpose,
-     advisory locks are faster, avoid MVCC bloat, and are automatically
+     advisory locks are faster, avoid MVCC bloat, and can be automatically
      cleaned up by the server at the end of the session.
      In certain cases using this advisory locking method, especially in queries
      involving explicit ordering and <literal>LIMIT</> clauses, care must be
index 40779d2e3596a3f8f508c4182f575cbb55706f13..87fd312e31479f26a396a626d36ee4b3c3a2ed4d 100644 (file)
@@ -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
 --------------------------
index cea5096c778f1213d9516337834668ac8b5cbd3d..ed0ea1205f479a75a1684c4766ee03bdf7f7281c 100644 (file)
@@ -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,
@@ -1483,6 +1484,31 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
        return TRUE;
 }
 
+/*
+ * 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;
                }
        }
 }
index be577bcd5fd623840a3564f5d1120f336f0d0777..afaf5995f0065ab989bbd42f1be19fe3fbe26d34 100644 (file)
@@ -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);
 }
 
 
index 8e369826cecf581b4850f547a690ce98544b0c79..c6c948ce5e77fefa676caf8bd51c9258a338a990 100644 (file)
@@ -421,6 +421,23 @@ pg_advisory_lock_int8(PG_FUNCTION_ARGS)
        PG_RETURN_VOID();
 }
 
+/*
+ * 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
  */
@@ -437,6 +454,23 @@ pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
        PG_RETURN_VOID();
 }
 
+/*
+ * 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
  *
@@ -456,6 +490,26 @@ pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
        PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
 }
 
+/*
+ * 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
  *
@@ -475,6 +529,26 @@ pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
        PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
 }
 
+/*
+ * 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
  *
@@ -530,6 +604,24 @@ pg_advisory_lock_int4(PG_FUNCTION_ARGS)
        PG_RETURN_VOID();
 }
 
+/*
+ * 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
  */
@@ -547,6 +639,24 @@ pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
        PG_RETURN_VOID();
 }
 
+/*
+ * 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
  *
@@ -567,6 +677,27 @@ pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
        PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
 }
 
+/*
+ * 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
  *
@@ -587,6 +718,27 @@ pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
        PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
 }
 
+/*
+ * 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
  *
@@ -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();
 }
index 7fb33f09e33bad6cb1186308d0c12919ff09f838..1a7be47fab8609def269011a120b1a2a3e431540 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201102171
+#define CATALOG_VERSION_NO     201102181
 
 #endif
index 60a2e623f23bc63bc0b88a9a53722ddad78af7e8..b3458ed56eb5ae7e51a0cb5a56293bb4b25e240a 100644 (file)
@@ -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_ ));
index 7b52d2e6d16eecdfd35f38ae85d36a592fbec366..7ec961f443004afb33857cc5c5569643997ab3ad 100644 (file)
@@ -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);
index 4341025d06a9ae50b36e8f38bb0ddc8a28237509..277aec414c38100546ca1a488213fef66568f76f 100644 (file)
@@ -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 (file)
index 0000000..2a2df6f
--- /dev/null
@@ -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)
+
index 3b99e867efefcad9052685a7ba1c4ad4fd1967dc..aa6f6d2ddd878c466eb6b659f9a491cc7d73a094 100644 (file)
@@ -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
index b348f0e1a9415955909a5aa5f2ef6d8abd65b27a..b76b1877a7e58ffae275bf2cd1df262464c9f259 100644 (file)
@@ -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 (file)
index 0000000..57c47c0
--- /dev/null
@@ -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';