Repair an error introduced by log_line_prefix patch: it is not acceptable
authorTom Lane <[email protected]>
Sat, 5 Nov 2005 03:05:05 +0000 (03:05 +0000)
committerTom Lane <[email protected]>
Sat, 5 Nov 2005 03:05:05 +0000 (03:05 +0000)
to assume that the string pointer passed to set_ps_display is good forever.
There's no need to anyway since ps_status.c itself saves the string, and
we already had an API (get_ps_display) to return it.
I believe this explains Jim Nasby's report of intermittent crashes in
elog.c when %i format code is in use in log_line_prefix.
While at it, repair a previously unnoticed problem: on some platforms such as
Darwin, the string returned by get_ps_display was blank-padded to the maximum
length, meaning that lock.c's attempt to append " waiting" to it never worked.

src/backend/postmaster/postmaster.c
src/backend/storage/lmgr/lock.c
src/backend/utils/error/elog.c
src/backend/utils/misc/ps_status.c
src/include/libpq/libpq-be.h
src/include/utils/ps_status.h

index 0360cc468e26427dde3b5710d7f58ecca13cc108..5cfacd173d7f88893f20ec47cd2af519abaeba2a 100644 (file)
@@ -2638,7 +2638,6 @@ BackendRun(Port *port)
        /* set these to empty in case they are needed before we set them up */
        port->remote_host = "";
        port->remote_port = "";
-       port->commandTag = "";
 
        /*
         * Initialize libpq and enable reporting of ereport errors to the
index 87aa730f39a0eccad171ce1ce40211ccb8b31d99..37d8312131d1a665c6dfb9dc90212128ad394936 100644 (file)
@@ -166,6 +166,8 @@ static int WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,
                   ResourceOwner owner);
 static void LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc,
                                 int *myHolding);
+static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode,
+                                               PROCLOCK *proclock, LockMethod lockMethodTable);
 
 
 /*
@@ -957,6 +959,62 @@ GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode)
        Assert(lock->nGranted <= lock->nRequested);
 }
 
+/*
+ * UnGrantLock -- opposite of GrantLock. 
+ *
+ * Updates the lock and proclock data structures to show that the lock
+ * is no longer held nor requested by the current holder.
+ *
+ * Returns true if there were any waiters waiting on the lock that
+ * should now be woken up with ProcLockWakeup.
+ */
+static bool
+UnGrantLock(LOCK *lock, LOCKMODE lockmode,
+                       PROCLOCK *proclock, LockMethod lockMethodTable)
+{
+       bool wakeupNeeded = false;
+
+       Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
+       Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
+       Assert(lock->nGranted <= lock->nRequested);
+
+       /*
+        * fix the general lock stats
+        */
+       lock->nRequested--;
+       lock->requested[lockmode]--;
+       lock->nGranted--;
+       lock->granted[lockmode]--;
+
+       if (lock->granted[lockmode] == 0)
+       {
+               /* change the conflict mask.  No more of this lock type. */
+               lock->grantMask &= LOCKBIT_OFF(lockmode);
+       }
+
+       LOCK_PRINT("UnGrantLock: updated", lock, lockmode);
+
+       /*
+        * We need only run ProcLockWakeup if the released lock conflicts with
+        * at least one of the lock types requested by waiter(s).  Otherwise
+        * whatever conflict made them wait must still exist.  NOTE: before
+        * MVCC, we could skip wakeup if lock->granted[lockmode] was still
+        * positive. But that's not true anymore, because the remaining
+        * granted locks might belong to some waiter, who could now be
+        * awakened because he doesn't conflict with his own locks.
+        */
+       if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
+               wakeupNeeded = true;
+
+       /*
+        * Now fix the per-proclock state.
+        */
+       proclock->holdMask &= LOCKBIT_OFF(lockmode);
+       PROCLOCK_PRINT("UnGrantLock: updated", proclock);
+
+       return wakeupNeeded;
+}
+
 /*
  * GrantLockLocal -- update the locallock data structures to show
  *             the lock request has been granted.
@@ -1016,19 +1074,21 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,
                   ResourceOwner owner)
 {
        LockMethod      lockMethodTable = LockMethods[lockmethodid];
-       char       *new_status,
-                          *old_status;
+       const char *old_status;
+       char       *new_status;
+       int                     len;
 
        Assert(lockmethodid < NumLockMethods);
 
        LOCK_PRINT("WaitOnLock: sleeping on lock",
                           locallock->lock, locallock->tag.mode);
 
-       old_status = pstrdup(get_ps_display());
-       new_status = (char *) palloc(strlen(old_status) + 10);
-       strcpy(new_status, old_status);
-       strcat(new_status, " waiting");
+       old_status = get_ps_display(&len);
+       new_status = (char *) palloc(len + 8 + 1);
+       memcpy(new_status, old_status, len);
+       strcpy(new_status + len, " waiting");
        set_ps_display(new_status);
+       new_status[len] = '\0';         /* truncate off " waiting" */
 
        awaitedLock = locallock;
        awaitedOwner = owner;
@@ -1054,8 +1114,7 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,
        {
                /*
                 * We failed as a result of a deadlock, see CheckDeadLock(). Quit
-                * now.  Removal of the proclock and lock objects, if no longer
-                * needed, will happen in xact cleanup (see above for motivation).
+                * now.
                 */
                awaitedLock = NULL;
                LOCK_PRINT("WaitOnLock: aborting on lock",
@@ -1072,8 +1131,7 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,
 
        awaitedLock = NULL;
 
-       set_ps_display(old_status);
-       pfree(old_status);
+       set_ps_display(new_status);
        pfree(new_status);
 
        LOCK_PRINT("WaitOnLock: wakeup on lock",
@@ -1087,22 +1145,21 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,
  *
  * Locktable lock must be held by caller.
  *
- * NB: this does not remove the process' proclock object, nor the lock object,
- * even though their counts might now have gone to zero.  That will happen
- * during a subsequent LockReleaseAll call, which we expect will happen
- * during transaction cleanup. (Removal of a proc from its wait queue by
- * this routine can only happen if we are aborting the transaction.)
+ * NB: this does not clean up any locallock object that may exist for the lock.
  */
 void
 RemoveFromWaitQueue(PGPROC *proc)
 {
        LOCK       *waitLock = proc->waitLock;
+       PROCLOCK   *proclock = proc->waitProcLock;
        LOCKMODE        lockmode = proc->waitLockMode;
+       LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*waitLock);
 
        /* Make sure proc is waiting */
        Assert(proc->links.next != INVALID_OFFSET);
        Assert(waitLock);
        Assert(waitLock->waitProcs.size > 0);
+       Assert(0 < lockmethodid && lockmethodid < NumLockMethods);
 
        /* Remove proc from lock's wait queue */
        SHMQueueDelete(&(proc->links));
@@ -1122,8 +1179,32 @@ RemoveFromWaitQueue(PGPROC *proc)
        proc->waitLock = NULL;
        proc->waitProcLock = NULL;
 
+       /*
+        * Delete the proclock immediately if it represents no already-held locks.
+        * This must happen now because if the owner of the lock decides to release
+        * it, and the requested/granted counts then go to zero, LockRelease
+        * expects there to be no remaining proclocks.
+        */
+       if (proclock->holdMask == 0)
+       {
+               PROCLOCK_PRINT("RemoveFromWaitQueue: deleting proclock", proclock);
+               SHMQueueDelete(&proclock->lockLink);
+               SHMQueueDelete(&proclock->procLink);
+               proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid],
+                                                                                       (void *) &(proclock->tag),
+                                                                                       HASH_REMOVE, NULL);
+               if (!proclock)
+                       elog(WARNING, "proclock table corrupted");
+       }
+
+       /*
+        * There should still be some requests for the lock ... else what were
+        * we waiting for?  Therefore no need to delete the lock object.
+        */
+       Assert(waitLock->nRequested > 0);
+
        /* See if any other waiters for the lock can be woken up now */
-       ProcLockWakeup(GetLocksMethodTable(waitLock), waitLock);
+       ProcLockWakeup(LockMethods[lockmethodid], waitLock);
 }
 
 /*
@@ -1146,7 +1227,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
        PROCLOCK   *proclock;
        LWLockId        masterLock;
        LockMethod      lockMethodTable;
-       bool            wakeupNeeded = false;
+       bool            wakeupNeeded;
 
 #ifdef LOCK_DEBUG
        if (lockmethodid == USER_LOCKMETHOD && Trace_userlocks)
@@ -1265,46 +1346,8 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
                RemoveLocalLock(locallock);
                return FALSE;
        }
-       Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
-       Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
-       Assert(lock->nGranted <= lock->nRequested);
 
-       /*
-        * fix the general lock stats
-        */
-       lock->nRequested--;
-       lock->requested[lockmode]--;
-       lock->nGranted--;
-       lock->granted[lockmode]--;
-
-       if (lock->granted[lockmode] == 0)
-       {
-               /* change the conflict mask.  No more of this lock type. */
-               lock->grantMask &= LOCKBIT_OFF(lockmode);
-       }
-
-       LOCK_PRINT("LockRelease: updated", lock, lockmode);
-       Assert((lock->nRequested >= 0) && (lock->requested[lockmode] >= 0));
-       Assert((lock->nGranted >= 0) && (lock->granted[lockmode] >= 0));
-       Assert(lock->nGranted <= lock->nRequested);
-
-       /*
-        * We need only run ProcLockWakeup if the released lock conflicts with
-        * at least one of the lock types requested by waiter(s).  Otherwise
-        * whatever conflict made them wait must still exist.  NOTE: before
-        * MVCC, we could skip wakeup if lock->granted[lockmode] was still
-        * positive. But that's not true anymore, because the remaining
-        * granted locks might belong to some waiter, who could now be
-        * awakened because he doesn't conflict with his own locks.
-        */
-       if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
-               wakeupNeeded = true;
-
-       /*
-        * Now fix the per-proclock state.
-        */
-       proclock->holdMask &= LOCKBIT_OFF(lockmode);
-       PROCLOCK_PRINT("LockRelease: updated", proclock);
+       wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);
 
        /*
         * If this was my last hold on this lock, delete my entry in the
@@ -1312,7 +1355,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
         */
        if (proclock->holdMask == 0)
        {
-               PROCLOCK_PRINT("LockRelease: deleting", proclock);
+               PROCLOCK_PRINT("LockRelease: deleting proclock", proclock);
                SHMQueueDelete(&proclock->lockLink);
                SHMQueueDelete(&proclock->procLink);
                proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid],
@@ -1333,6 +1376,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
                 * We've just released the last lock, so garbage-collect the lock
                 * object.
                 */
+               LOCK_PRINT("LockRelease: deleting lock", lock, lockmode);
                Assert(SHMQueueEmpty(&(lock->procLocks)));
                lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid],
                                                                        (void *) &(lock->tag),
@@ -1483,22 +1527,8 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allxids)
                        for (i = 1; i <= numLockModes; i++)
                        {
                                if (proclock->holdMask & LOCKBIT_ON(i))
-                               {
-                                       lock->requested[i]--;
-                                       lock->granted[i]--;
-                                       Assert(lock->requested[i] >= 0 && lock->granted[i] >= 0);
-                                       if (lock->granted[i] == 0)
-                                               lock->grantMask &= LOCKBIT_OFF(i);
-                                       lock->nRequested--;
-                                       lock->nGranted--;
-
-                                       /*
-                                        * Read comments in LockRelease
-                                        */
-                                       if (!wakeupNeeded &&
-                                               lockMethodTable->conflictTab[i] & lock->waitMask)
-                                               wakeupNeeded = true;
-                               }
+                                       wakeupNeeded |= UnGrantLock(lock, i, proclock,
+                                                                                               lockMethodTable);
                        }
                }
                Assert((lock->nRequested >= 0) && (lock->nGranted >= 0));
index 730bfc35dd3cf7e2aef5626a1642afdf076202d3..a3c7fa75baf0225d53fdf93e05add51f1c1887f9 100644 (file)
@@ -67,6 +67,7 @@
 #include "tcop/tcopprot.h"
 #include "utils/memutils.h"
 #include "utils/guc.h"
+#include "utils/ps_status.h"
 
 
 /* Global variables */
@@ -1461,13 +1462,20 @@ log_line_prefix(StringInfo buf)
                                break;
                        case 'i':
                                if (MyProcPort)
-                                       appendStringInfo(buf, "%s", MyProcPort->commandTag);
+                               {
+                                       const char *psdisp;
+                                       int             displen;
+
+                                       psdisp = get_ps_display(&displen);
+                                       appendStringInfo(buf, "%.*s", displen, psdisp);
+                               }
                                break;
                        case 'r':
-                               if (MyProcPort)
+                               if (MyProcPort && MyProcPort->remote_host)
                                {
                                        appendStringInfo(buf, "%s", MyProcPort->remote_host);
-                                       if (strlen(MyProcPort->remote_port) > 0)
+                                       if (MyProcPort->remote_port &&
+                                               MyProcPort->remote_port[0] != '\0')
                                                appendStringInfo(buf, "(%s)",
                                                                                 MyProcPort->remote_port);
                                }
index 50fe78cc81dd4e3f8efddd9d0f2e9a486e2d9e57..e493ddb33e78adaee59293129c02d57bf0d21b8a 100644 (file)
@@ -308,10 +308,6 @@ init_ps_display(const char *username, const char *dbname,
 void
 set_ps_display(const char *activity)
 {
-       /* save tag for possible use by elog.c */
-       if (MyProcPort)
-               MyProcPort->commandTag = activity;
-
 #ifndef PS_USE_NONE
        /* no ps display for stand-alone backend */
        if (!IsUnderPostmaster)
@@ -367,15 +363,31 @@ set_ps_display(const char *activity)
 
 /*
  * Returns what's currently in the ps display, in case someone needs
- * it. Note that only the activity part is returned.
+ * it. Note that only the activity part is returned.  On some platforms
+ * the string will not be null-terminated, so return the effective
+ * length into *displen.
  */
 const char *
-get_ps_display(void)
+get_ps_display(int *displen)
 {
 #ifdef PS_USE_CLOBBER_ARGV
+       size_t          offset;
+
        /* If ps_buffer is a pointer, it might still be null */
        if (!ps_buffer)
+       {
+               *displen = 0;
                return "";
+       }
+
+       /* Remove any trailing spaces to offset the effect of PS_PADDING */
+       offset = ps_buffer_size;
+       while (offset > ps_buffer_fixed_size && ps_buffer[offset-1] == PS_PADDING)
+               offset--;
+
+       *displen = offset - ps_buffer_fixed_size;
+#else
+       *displen = strlen(ps_buffer + ps_buffer_fixed_size);
 #endif
 
        return ps_buffer + ps_buffer_fixed_size;
index 9772f2baf06afe6c896964842c0d06c33445be13..578b4a28e33d377d5f37c29628745815128b01d8 100644 (file)
@@ -79,7 +79,6 @@ typedef struct Port
         * database_name and other members of this struct, we may as well keep
         * it here.
         */
-       const char *commandTag;         /* current command tag */
        struct timeval session_start;           /* for session duration logging */
 
        /*
index 122cd94915f64f9782d4e17bb987e92696a25753..20eb6446bec58a8b011e664c26b78cf7b210d7fa 100644 (file)
@@ -19,6 +19,6 @@ extern void init_ps_display(const char *username, const char *dbname,
 
 extern void set_ps_display(const char *activity);
 
-extern const char *get_ps_display(void);
+extern const char *get_ps_display(int *displen);
 
 #endif   /* PS_STATUS_H */