1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-14 08:21:07 +03:00

From: Massimo Dal Zotto <dz@cs.unitn.it>

lock.patch

        I have rewritten lock.c cleaning up the code and adding better
        assert checking I have also added some fields to the lock and
        xid tags for better support of user locks. There is also a new
        function which returns an array of pids owning a lock.
        I'm using this code from over six months and it works fine.
This commit is contained in:
Marc G. Fournier
1998-08-25 21:20:32 +00:00
parent 1acf0d85fe
commit 7dbcf31be2
5 changed files with 958 additions and 506 deletions

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.40 1998/07/27 19:38:15 vadim Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.41 1998/08/25 21:20:29 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -46,7 +46,7 @@
* This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95
*
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.40 1998/07/27 19:38:15 vadim Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.41 1998/08/25 21:20:29 scrappy Exp $
*/
#include <sys/time.h>
#include <unistd.h>
@ -75,10 +75,13 @@
#include "storage/shmem.h"
#include "storage/spin.h"
#include "storage/proc.h"
#include "utils/trace.h"
static void HandleDeadLock(int sig);
static PROC *ProcWakeup(PROC *proc, int errType);
#define DeadlockCheckTimer pg_options[OPT_DEADLOCKTIMEOUT]
/* --------------------
* Spin lock for manipulating the shared process data structure:
* ProcGlobal.... Adding an extra spin lock seemed like the smallest
@ -247,10 +250,7 @@ InitProcess(IPCKey key)
*/
SpinRelease(ProcStructLock);
MyProc->pid = 0;
#if 0
MyProc->pid = MyProcPid;
#endif
MyProc->xid = InvalidTransactionId;
#ifdef LowLevelLocking
MyProc->xmin = InvalidTransactionId;
@ -361,10 +361,13 @@ ProcKill(int exitStatus, int pid)
* ---------------
*/
ProcReleaseSpins(proc);
LockReleaseAll(1, &proc->lockQueue);
LockReleaseAll(DEFAULT_LOCKMETHOD, &proc->lockQueue);
#ifdef USER_LOCKS
LockReleaseAll(0, &proc->lockQueue);
/*
* Assume we have a second lock table.
*/
LockReleaseAll(USER_LOCKMETHOD, &proc->lockQueue);
#endif
/* ----------------
@ -437,11 +440,12 @@ ProcQueueInit(PROC_QUEUE *queue)
* NOTES: The process queue is now a priority queue for locking.
*/
int
ProcSleep(PROC_QUEUE *waitQueue,
ProcSleep(PROC_QUEUE *waitQueue, /* lock->waitProcs */
SPINLOCK spinlock,
int token,
int token, /* lockmode */
int prio,
LOCK *lock)
LOCK *lock,
TransactionId xid) /* needed by user locks, see below */
{
int i;
PROC *proc;
@ -470,7 +474,6 @@ ProcSleep(PROC_QUEUE *waitQueue,
proc = (PROC *) MAKE_PTR(waitQueue->links.prev);
/* If we are a reader, and they are writers, skip past them */
for (i = 0; i < waitQueue->size && proc->prio > prio; i++)
proc = (PROC *) MAKE_PTR(proc->links.prev);
@ -482,12 +485,22 @@ ProcSleep(PROC_QUEUE *waitQueue,
MyProc->token = token;
MyProc->waitLock = lock;
#ifdef USER_LOCKS
/* -------------------
* Currently, we only need this for the ProcWakeup routines.
* This must be 0 for user lock, so we can't just use the value
* from GetCurrentTransactionId().
* -------------------
*/
TransactionIdStore(xid, &MyProc->xid);
#else
#ifndef LowLevelLocking
/* -------------------
* currently, we only need this for the ProcWakeup routines
* -------------------
*/
TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid);
#endif
#endif
/* -------------------
@ -510,7 +523,8 @@ ProcSleep(PROC_QUEUE *waitQueue,
* --------------
*/
MemSet(&timeval, 0, sizeof(struct itimerval));
timeval.it_value.tv_sec = DEADLOCK_CHECK_TIMER;
timeval.it_value.tv_sec = \
(DeadlockCheckTimer ? DeadlockCheckTimer : DEADLOCK_CHECK_TIMER);
do
{
@ -525,7 +539,8 @@ ProcSleep(PROC_QUEUE *waitQueue,
* the semaphore implementation.
* --------------
*/
IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum,
IpcExclusiveLock);
} while (MyProc->errType == STATUS_NOT_FOUND); /* sleep after deadlock
* check */
@ -534,8 +549,6 @@ ProcSleep(PROC_QUEUE *waitQueue,
* ---------------
*/
timeval.it_value.tv_sec = 0;
if (setitimer(ITIMER_REAL, &timeval, &dummy))
elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
@ -546,6 +559,11 @@ ProcSleep(PROC_QUEUE *waitQueue,
*/
SpinAcquire(spinlock);
#ifdef LOCK_MGR_DEBUG
/* Just to get meaningful debug messages from DumpLocks() */
MyProc->waitLock = (LOCK *)NULL;
#endif
return (MyProc->errType);
}
@ -589,17 +607,39 @@ ProcLockWakeup(PROC_QUEUE *queue, LOCKMETHOD lockmethod, LOCK *lock)
{
PROC *proc;
int count;
int trace_flag;
int last_locktype = -1;
int queue_size = queue->size;
Assert(queue->size >= 0);
if (!queue->size)
return (STATUS_NOT_FOUND);
proc = (PROC *) MAKE_PTR(queue->links.prev);
count = 0;
while ((LockResolveConflicts(lockmethod,
while ((queue_size--) && (proc))
{
/*
* This proc will conflict as the previous one did, don't even try.
*/
if (proc->token == last_locktype)
{
continue;
}
/*
* This proc conflicts with locks held by others, ignored.
*/
if (LockResolveConflicts(lockmethod,
lock,
proc->token,
proc->xid) == STATUS_OK))
{
proc->xid,
(XIDLookupEnt *) NULL) != STATUS_OK)
{
last_locktype = proc->token;
continue;
}
/*
* there was a waiting process, grant it the lock before waking it
@ -608,24 +648,34 @@ ProcLockWakeup(PROC_QUEUE *queue, LOCKMETHOD lockmethod, LOCK *lock)
* time that the awoken process begins executing again.
*/
GrantLock(lock, proc->token);
queue->size--;
/*
* ProcWakeup removes proc from the lock waiting process queue and
* returns the next proc in chain.
*/
proc = ProcWakeup(proc, NO_ERROR);
count++;
if (!proc || queue->size == 0)
break;
queue->size--;
proc = ProcWakeup(proc, NO_ERROR);
}
Assert(queue->size >= 0);
if (count)
return (STATUS_OK);
else
else {
/* Something is still blocking us. May have deadlocked. */
trace_flag = (lock->tag.lockmethod == USER_LOCKMETHOD) ? \
TRACE_USERLOCKS : TRACE_LOCKS;
TPRINTF(trace_flag,
"ProcLockWakeup: lock(%x) can't wake up any process",
MAKE_OFFSET(lock));
#ifdef DEADLOCK_DEBUG
if (pg_options[trace_flag] >= 2)
DumpAllLocks();
#endif
return (STATUS_NOT_FOUND);
}
}
void
@ -685,7 +735,7 @@ HandleDeadLock(int sig)
}
#ifdef DEADLOCK_DEBUG
DumpLocks();
DumpAllLocks();
#endif
if (!DeadLockCheck(&(MyProc->lockQueue), MyProc->waitLock, true))
@ -711,7 +761,8 @@ HandleDeadLock(int sig)
* I was awoken by a signal, not by someone unlocking my semaphore.
* ------------------
*/
IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum,
IpcExclusiveLock);
/* -------------
* Set MyProc->errType to STATUS_ERROR so that we abort after