mirror of
https://github.com/postgres/postgres.git
synced 2025-11-06 07:49:08 +03:00
Patch from Massimo Dal Zotto <dz@cs.unitn.it>
The following patches add to the backend a new debugging flag -K which prints a debug trace of all locking operations on user relations (those with oid greater than 20000). The code is compiled only if LOCK_MGR_DEBUG is defined, so the patch should be harmless if not explicitly enabled. I'm using the code to trace deadlock conditions caused by application queries using the command "$POSTMASTER -D $PGDATA -o '-d 1 -K 1'. The patches are for version 6.0 dated 970126.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.6 1996/12/26 17:50:26 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.7 1997/02/12 05:23:49 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Outside modules can create a lock table and acquire/release
|
||||
@@ -57,41 +57,65 @@
|
||||
|
||||
#else /* LOCK_MGR_DEBUG */
|
||||
|
||||
int lockDebug = 0;
|
||||
|
||||
#ifndef LOCK_DEBUG_OID_MIN
|
||||
/*
|
||||
* This is totally arbitrary. It is the minimum relation oid
|
||||
* which will trigger the locking debug when the -K option
|
||||
* is given to the backend. This is done to avoid tracing
|
||||
* locks on system relations.
|
||||
*/
|
||||
#define LOCK_DEBUG_OID_MIN 20000
|
||||
#endif
|
||||
|
||||
#define LOCK_PRINT(where,tag,type)\
|
||||
elog(NOTICE, "%s: rel (%d) dbid (%d) tid (%d,%d) type (%d)\n",where, \
|
||||
tag->relId, tag->dbId, \
|
||||
( (tag->tupleId.ip_blkid.data[0] >= 0) ? \
|
||||
BlockIdGetBlockNumber(&tag->tupleId.ip_blkid) : -1 ), \
|
||||
tag->tupleId.ip_posid, \
|
||||
type);
|
||||
if ((lockDebug >= 1) && (tag->relId >= LOCK_DEBUG_OID_MIN)) \
|
||||
elog(DEBUG, \
|
||||
"%s: pid (%d) rel (%d) dbid (%d) tid (%d,%d) type (%d)",where, \
|
||||
getpid(),\
|
||||
tag->relId, tag->dbId, \
|
||||
((tag->tupleId.ip_blkid.bi_hi<<16)+\
|
||||
tag->tupleId.ip_blkid.bi_lo),\
|
||||
tag->tupleId.ip_posid, \
|
||||
type);
|
||||
|
||||
#define LOCK_DUMP(where,lock,type)\
|
||||
elog(NOTICE, "%s: rel (%d) dbid (%d) tid (%d,%d) nHolding (%d) holders (%d,%d,%d,%d,%d) type (%d)\n",where, \
|
||||
lock->tag.relId, lock->tag.dbId, \
|
||||
((lock->tag.tupleId.ip_blkid.data[0] >= 0) ? \
|
||||
BlockIdGetBlockNumber(&lock->tag.tupleId.ip_blkid) : -1 ), \
|
||||
lock->tag.tupleId.ip_posid, \
|
||||
lock->nHolding,\
|
||||
lock->holders[1],\
|
||||
lock->holders[2],\
|
||||
lock->holders[3],\
|
||||
lock->holders[4],\
|
||||
lock->holders[5],\
|
||||
type);
|
||||
if ((lockDebug >= 1) && (lock->tag.relId >= LOCK_DEBUG_OID_MIN)) \
|
||||
elog(DEBUG, \
|
||||
"%s: pid (%d) rel (%d) dbid (%d) tid (%d,%d) nHolding (%d) "\
|
||||
"holders (%d,%d,%d,%d,%d) type (%d)",where, \
|
||||
getpid(),\
|
||||
lock->tag.relId, lock->tag.dbId, \
|
||||
((lock->tag.tupleId.ip_blkid.bi_hi<<16)+\
|
||||
lock->tag.tupleId.ip_blkid.bi_lo),\
|
||||
lock->tag.tupleId.ip_posid, \
|
||||
lock->nHolding,\
|
||||
lock->holders[1],\
|
||||
lock->holders[2],\
|
||||
lock->holders[3],\
|
||||
lock->holders[4],\
|
||||
lock->holders[5],\
|
||||
type);
|
||||
|
||||
#define XID_PRINT(where,xidentP)\
|
||||
elog(NOTICE,\
|
||||
"%s:xid (%d) pid (%d) lock (%x) nHolding (%d) holders (%d,%d,%d,%d,%d)",\
|
||||
where,\
|
||||
xidentP->tag.xid,\
|
||||
xidentP->tag.pid,\
|
||||
xidentP->tag.lock,\
|
||||
xidentP->nHolding,\
|
||||
xidentP->holders[1],\
|
||||
xidentP->holders[2],\
|
||||
xidentP->holders[3],\
|
||||
xidentP->holders[4],\
|
||||
xidentP->holders[5]);
|
||||
if ((lockDebug >= 2) && \
|
||||
(((LOCK *)MAKE_PTR(xidentP->tag.lock))->tag.relId \
|
||||
>= LOCK_DEBUG_OID_MIN)) \
|
||||
elog(DEBUG,\
|
||||
"%s: pid (%d) xid (%d) pid (%d) lock (%x) nHolding (%d) "\
|
||||
"holders (%d,%d,%d,%d,%d)",\
|
||||
where,\
|
||||
getpid(),\
|
||||
xidentP->tag.xid,\
|
||||
xidentP->tag.pid,\
|
||||
xidentP->tag.lock,\
|
||||
xidentP->nHolding,\
|
||||
xidentP->holders[1],\
|
||||
xidentP->holders[2],\
|
||||
xidentP->holders[3],\
|
||||
xidentP->holders[4],\
|
||||
xidentP->holders[5]);
|
||||
|
||||
#endif /* LOCK_MGR_DEBUG */
|
||||
|
||||
@@ -528,7 +552,7 @@ LockAcquire(LockTableId tableId, LOCKTAG *lockName, LOCKT lockt)
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
XID_PRINT("queueing XidEnt LockAcquire:", result);
|
||||
XID_PRINT("LockAcquire: queueing XidEnt", result);
|
||||
ProcAddLock(&result->queue);
|
||||
result->nHolding = 0;
|
||||
memset((char *)result->holders, 0, sizeof(int)*MAX_LOCKTYPES);
|
||||
@@ -1102,7 +1126,7 @@ LockReleaseAll(LockTableId tableId, SHM_QUEUE *lockQueue)
|
||||
#endif
|
||||
SHMQueueFirst(lockQueue,(Pointer*)&xidLook,&xidLook->queue);
|
||||
|
||||
XID_PRINT("LockReleaseAll:", xidLook);
|
||||
XID_PRINT("LockReleaseAll", xidLook);
|
||||
|
||||
#ifndef USER_LOCKS
|
||||
SpinAcquire(masterLock);
|
||||
@@ -1322,3 +1346,75 @@ LockingDisabled()
|
||||
{
|
||||
return LockingIsDisabled;
|
||||
}
|
||||
|
||||
#ifdef DEADLOCK_DEBUG
|
||||
/*
|
||||
* Dump all locks. Must have already acquired the masterLock.
|
||||
*/
|
||||
void
|
||||
DumpLocks()
|
||||
{
|
||||
SHMEM_OFFSET location;
|
||||
PROC *proc;
|
||||
SHM_QUEUE *lockQueue;
|
||||
int done;
|
||||
XIDLookupEnt *xidLook = NULL;
|
||||
XIDLookupEnt *tmp = NULL;
|
||||
SHMEM_OFFSET end;
|
||||
SPINLOCK masterLock;
|
||||
int nLockTypes;
|
||||
LOCK *lock;
|
||||
int pid, count;
|
||||
int tableId = 1;
|
||||
LOCKTAB *ltable;
|
||||
|
||||
pid = getpid();
|
||||
ShmemPIDLookup(pid,&location);
|
||||
if (location == INVALID_OFFSET)
|
||||
return;
|
||||
proc = (PROC *) MAKE_PTR(location);
|
||||
if (proc != MyProc)
|
||||
return;
|
||||
lockQueue = &proc->lockQueue;
|
||||
|
||||
Assert (tableId < NumTables);
|
||||
ltable = AllTables[tableId];
|
||||
if (!ltable)
|
||||
return;
|
||||
|
||||
nLockTypes = ltable->ctl->nLockTypes;
|
||||
masterLock = ltable->ctl->masterLock;
|
||||
|
||||
if (SHMQueueEmpty(lockQueue))
|
||||
return;
|
||||
|
||||
SHMQueueFirst(lockQueue,(Pointer*)&xidLook,&xidLook->queue);
|
||||
end = MAKE_OFFSET(lockQueue);
|
||||
|
||||
LOCK_DUMP("DumpLocks", MyProc->waitLock, 0);
|
||||
XID_PRINT("DumpLocks", xidLook);
|
||||
|
||||
for (count=0;;) {
|
||||
/* ---------------------------
|
||||
* XXX Here we assume the shared memory queue is circular and
|
||||
* that we know its internal structure. Should have some sort of
|
||||
* macros to allow one to walk it. mer 20 July 1991
|
||||
* ---------------------------
|
||||
*/
|
||||
done = (xidLook->queue.next == end);
|
||||
lock = (LOCK *) MAKE_PTR(xidLook->tag.lock);
|
||||
|
||||
LOCK_DUMP("DumpLocks",lock,0);
|
||||
|
||||
if (count++ > 2000) {
|
||||
elog(NOTICE,"DumpLocks: xid loop detected, giving up");
|
||||
break;
|
||||
}
|
||||
|
||||
if (done)
|
||||
break;
|
||||
SHMQueueFirst(&xidLook->queue,(Pointer*)&tmp,&tmp->queue);
|
||||
xidLook = tmp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user