Hack on lock transfer stuff. gathertest
authorRobert Haas <[email protected]>
Sat, 30 Jan 2016 13:35:56 +0000 (08:35 -0500)
committerRobert Haas <[email protected]>
Mon, 1 Feb 2016 21:13:15 +0000 (16:13 -0500)
XXX: I don't think this is the right design.  It will require the workers
to wait for the leader to perform the associated lock acquisitions, and
then the leader will need to tell them, afterwards, that they can go exit.
There's no obvious way to make that signalling work.  Instead, I wonder if
we shouldn't including bookkeeping information in the PROCLOCK structures
somehow, so that the worker actually reassigns the locks to the leader
directly.  However, that has a couple of problems.  One is that the leader
might pick a bad time to die, orphaning locks.  Another is that the leader
wouldn't know how to associate the locks with its own resource owners.
Hmm, need to think more about this.

src/backend/access/transam/parallel.c
src/backend/storage/lmgr/lock.c
src/include/storage/lock.h

index 391575041959df24960830ac998099186c6715d9..31b23a785b567d9b1d86c4a7e3a8f7ab18b4921d 100644 (file)
@@ -807,6 +807,33 @@ HandleParallelMessage(ParallelContext *pcxt, int i, StringInfo msg)
                                break;
                        }
 
+               case 'L':                               /* Lock information */
+                       {
+                               int                     i;
+
+                               Assert(msg->len > 1 && (msg->len % sizeof(LOCALLOCKTAG)) == 1);
+
+                               for (i = 1; i < msg->len; i += sizeof(LOCALLOCKTAG))
+                               {
+                                       LOCALLOCKTAG    locallocktag;
+
+                                       memcpy((char *) &locallocktag, &msg->data[i], sizeof(LOCALLOCKTAG));
+                                       /* XXX.  Now what? */
+#if 0
+                                       ereport(NOTICE,
+                                                       (errmsg("worker has lock %u/%u/%u/%u type %u method %u mode %u",
+                                                                       locallocktag.lock.locktag_field1,
+                                                                       locallocktag.lock.locktag_field2,
+                                                                       locallocktag.lock.locktag_field3,
+                                                                       locallocktag.lock.locktag_field4,
+                                                                       locallocktag.lock.locktag_type,
+                                                                       locallocktag.lock.locktag_lockmethodid,
+                                                                       locallocktag.mode)));
+#endif
+                               }
+                               break;
+                       }
+
                case 'X':                               /* Terminate, indicating clean exit */
                        {
                                pfree(pcxt->worker[i].error_mqh);
@@ -1038,6 +1065,11 @@ ParallelWorkerMain(Datum main_arg)
        /* Must pop active snapshot so resowner.c doesn't complain. */
        PopActiveSnapshot();
 
+       /* Send a message to the leader with the heavyweight locks we still retain. */
+       pq_beginmessage(&msgbuf, 'L');
+       if (GetMyLocks(&msgbuf) != 0)
+               pq_endmessage(&msgbuf);
+
        /* Shut down the parallel-worker transaction. */
        EndParallelWorkerTransaction();
 
index 7c7f250878195ff82e21f7863ce1a27d323ae840..c308531ff17c1bfe0663e7c75d3929c95349af56 100644 (file)
@@ -707,7 +707,6 @@ LockAcquireExtended(const LOCKTAG *locktag,
        lockMethodTable = LockMethods[lockmethodid];
        if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
                elog(ERROR, "unrecognized lock mode: %d", lockmode);
-       Assert(!IsInParallelMode() || MyProc->lockGroupLeader != NULL);
 
        if (RecoveryInProgress() && !InRecovery &&
                (locktag->locktag_type == LOCKTAG_OBJECT ||
@@ -3537,6 +3536,50 @@ GetLockStatusData(void)
        return data;
 }
 
+/*
+ * GetMyLocks -- Write all locks we hold into the provided StringInfo.
+ *
+ * For each lock, we write the LOCKTAG and LOCKMODE, a concept conveniently
+ * encapsulated by the LOCALLOCKTAG data type.
+ *
+ * We return the number of locks written.
+ */
+int
+GetMyLocks(StringInfo buf)
+{
+       HASH_SEQ_STATUS status;
+       LOCALLOCK  *locallock;
+       int                     count = 0;
+
+       /*
+        * We choose to implement this by iterating over the local lock table.
+        * This carries the intrinsic risk that if any our lock management code
+        * is buggy, we might enumerate a different set of locks here than the
+        * shared lock table believes we actually hold.  We could eliminate that
+        * risk by doing this based on the shared memory data structures rather
+        * than our local bookkeeping, but that would require acquiring every lock
+        * manager partition lock in turn.  We prefer to minimize contention.
+        */
+       hash_seq_init(&status, LockMethodLocalHash);
+
+       while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
+       {
+               /*
+                * Normally we remove entries from the hash table when nLocks == 0,
+                * but not if we run out of shared memory while setting up the lock.
+                * Skip any such unheld locks.
+                */
+               if (locallock->nLocks == 0)
+                       continue;
+
+               appendBinaryStringInfo(buf, (char *) &locallock->tag,
+                                                          sizeof(LOCALLOCKTAG));
+               ++count;
+       }
+
+       return count;
+}
+
 /*
  * Returns a list of currently held AccessExclusiveLocks, for use by
  * LogStandbySnapshot().  The result is a palloc'd array,
index 6b4e3655f871d687ae89dc31d56a65fb352af590..e54c613929378f6dc15e9fc8af7f6b00b5ec1a50 100644 (file)
@@ -23,6 +23,8 @@
 #include "storage/lwlock.h"
 #include "storage/shmem.h"
 
+/* avoid including lib/stringinfo.h */
+struct StringInfoData;
 
 /* struct PGPROC is declared in proc.h, but must forward-reference it */
 typedef struct PGPROC PGPROC;
@@ -520,6 +522,7 @@ extern void GrantAwaitedLock(void);
 extern void RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode);
 extern Size LockShmemSize(void);
 extern LockData *GetLockStatusData(void);
+extern int GetMyLocks(struct StringInfoData *buf);
 
 extern xl_standby_lock *GetRunningTransactionLocks(int *nlocks);
 extern const char *GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode);