Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)