Skip to content

Commit 588fb50

Browse files
committed
Show PIDs of lock holders and waiters in log_lock_waits log message.
Christian Kruse, reviewed by Kumar Rajeev Rastogi.
1 parent a0b4c35 commit 588fb50

File tree

4 files changed

+122
-5
lines changed

4 files changed

+122
-5
lines changed

doc/src/sgml/sources.sgml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,15 @@ ereport(ERROR,
249249
sent to the client.
250250
</para>
251251
</listitem>
252+
<listitem>
253+
<para>
254+
<function>errdetail_log_plural(const char *fmt_singuar, const char
255+
*fmt_plural, unsigned long n, ...)</function> is like
256+
<function>errdetail_log</>, but with support for various plural forms of
257+
the message.
258+
For more information see <xref linkend="nls-guidelines">.
259+
</para>
260+
</listitem>
252261
<listitem>
253262
<para>
254263
<function>errhint(const char *msg, ...)</function> supplies an optional

src/backend/storage/lmgr/proc.c

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,13 +1208,23 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
12081208
*/
12091209
if (log_lock_waits && deadlock_state != DS_NOT_YET_CHECKED)
12101210
{
1211-
StringInfoData buf;
1211+
StringInfoData buf,
1212+
lock_waiters_sbuf,
1213+
lock_holders_sbuf;
12121214
const char *modename;
12131215
long secs;
12141216
int usecs;
12151217
long msecs;
1218+
SHM_QUEUE *procLocks;
1219+
PROCLOCK *proclock;
1220+
bool first_holder = true,
1221+
first_waiter = true;
1222+
int lockHoldersNum = 0;
12161223

12171224
initStringInfo(&buf);
1225+
initStringInfo(&lock_waiters_sbuf);
1226+
initStringInfo(&lock_holders_sbuf);
1227+
12181228
DescribeLockTag(&buf, &locallock->tag.lock);
12191229
modename = GetLockmodeName(locallock->tag.lock.locktag_lockmethodid,
12201230
lockmode);
@@ -1224,10 +1234,67 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
12241234
msecs = secs * 1000 + usecs / 1000;
12251235
usecs = usecs % 1000;
12261236

1237+
/*
1238+
* we loop over the lock's procLocks to gather a list of all
1239+
* holders and waiters. Thus we will be able to provide more
1240+
* detailed information for lock debugging purposes.
1241+
*
1242+
* lock->procLocks contains all processes which hold or wait for
1243+
* this lock.
1244+
*/
1245+
1246+
LWLockAcquire(partitionLock, LW_SHARED);
1247+
1248+
procLocks = &(lock->procLocks);
1249+
proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
1250+
offsetof(PROCLOCK, lockLink));
1251+
1252+
while (proclock)
1253+
{
1254+
/*
1255+
* we are a waiter if myProc->waitProcLock == proclock; we are
1256+
* a holder if it is NULL or something different
1257+
*/
1258+
if (proclock->tag.myProc->waitProcLock == proclock)
1259+
{
1260+
if (first_waiter)
1261+
{
1262+
appendStringInfo(&lock_waiters_sbuf, "%d",
1263+
proclock->tag.myProc->pid);
1264+
first_waiter = false;
1265+
}
1266+
else
1267+
appendStringInfo(&lock_waiters_sbuf, ", %d",
1268+
proclock->tag.myProc->pid);
1269+
}
1270+
else
1271+
{
1272+
if (first_holder)
1273+
{
1274+
appendStringInfo(&lock_holders_sbuf, "%d",
1275+
proclock->tag.myProc->pid);
1276+
first_holder = false;
1277+
}
1278+
else
1279+
appendStringInfo(&lock_holders_sbuf, ", %d",
1280+
proclock->tag.myProc->pid);
1281+
1282+
lockHoldersNum++;
1283+
}
1284+
1285+
proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
1286+
offsetof(PROCLOCK, lockLink));
1287+
}
1288+
1289+
LWLockRelease(partitionLock);
1290+
12271291
if (deadlock_state == DS_SOFT_DEADLOCK)
12281292
ereport(LOG,
12291293
(errmsg("process %d avoided deadlock for %s on %s by rearranging queue order after %ld.%03d ms",
1230-
MyProcPid, modename, buf.data, msecs, usecs)));
1294+
MyProcPid, modename, buf.data, msecs, usecs),
1295+
(errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.",
1296+
"Processes holding the lock: %s. Wait queue: %s.",
1297+
lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data))));
12311298
else if (deadlock_state == DS_HARD_DEADLOCK)
12321299
{
12331300
/*
@@ -1239,13 +1306,19 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
12391306
*/
12401307
ereport(LOG,
12411308
(errmsg("process %d detected deadlock while waiting for %s on %s after %ld.%03d ms",
1242-
MyProcPid, modename, buf.data, msecs, usecs)));
1309+
MyProcPid, modename, buf.data, msecs, usecs),
1310+
(errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.",
1311+
"Processes holding the lock: %s. Wait queue: %s.",
1312+
lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data))));
12431313
}
12441314

12451315
if (myWaitStatus == STATUS_WAITING)
12461316
ereport(LOG,
12471317
(errmsg("process %d still waiting for %s on %s after %ld.%03d ms",
1248-
MyProcPid, modename, buf.data, msecs, usecs)));
1318+
MyProcPid, modename, buf.data, msecs, usecs),
1319+
(errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.",
1320+
"Processes holding the lock: %s. Wait queue: %s.",
1321+
lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data))));
12491322
else if (myWaitStatus == STATUS_OK)
12501323
ereport(LOG,
12511324
(errmsg("process %d acquired %s on %s after %ld.%03d ms",
@@ -1265,7 +1338,10 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
12651338
if (deadlock_state != DS_HARD_DEADLOCK)
12661339
ereport(LOG,
12671340
(errmsg("process %d failed to acquire %s on %s after %ld.%03d ms",
1268-
MyProcPid, modename, buf.data, msecs, usecs)));
1341+
MyProcPid, modename, buf.data, msecs, usecs),
1342+
(errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.",
1343+
"Processes holding the lock: %s. Wait queue: %s.",
1344+
lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data))));
12691345
}
12701346

12711347
/*
@@ -1275,6 +1351,8 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
12751351
deadlock_state = DS_NO_DEADLOCK;
12761352

12771353
pfree(buf.data);
1354+
pfree(lock_holders_sbuf.data);
1355+
pfree(lock_waiters_sbuf.data);
12781356
}
12791357
} while (myWaitStatus == STATUS_WAITING);
12801358

src/backend/utils/error/elog.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,28 @@ errdetail_log(const char *fmt,...)
937937
return 0; /* return value does not matter */
938938
}
939939

940+
/*
941+
* errdetail_log_plural --- add a detail_log error message text to the current error
942+
* with support for pluralization of the message text
943+
*/
944+
int
945+
errdetail_log_plural(const char *fmt_singular, const char *fmt_plural,
946+
unsigned long n,...)
947+
{
948+
ErrorData *edata = &errordata[errordata_stack_depth];
949+
MemoryContext oldcontext;
950+
951+
recursion_depth++;
952+
CHECK_STACK_DEPTH();
953+
oldcontext = MemoryContextSwitchTo(edata->assoc_context);
954+
955+
EVALUATE_MESSAGE_PLURAL(edata->domain, detail_log, false);
956+
957+
MemoryContextSwitchTo(oldcontext);
958+
recursion_depth--;
959+
return 0; /* return value does not matter */
960+
}
961+
940962

941963
/*
942964
* errdetail_plural --- add a detail error message text to the current error,

src/include/utils/elog.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,14 @@ errdetail_log(const char *fmt,...)
181181
the supplied arguments. */
182182
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
183183

184+
extern int
185+
errdetail_log_plural(const char *fmt_singular, const char *fmt_plural,
186+
unsigned long n,...)
187+
/* This extension allows gcc to check the format string for consistency with
188+
the supplied arguments. */
189+
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 4)))
190+
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 4)));
191+
184192
extern int
185193
errdetail_plural(const char *fmt_singular, const char *fmt_plural,
186194
unsigned long n,...)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy