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

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Attic/multi.c,v 1.22 1998/08/19 02:02:44 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Attic/multi.c,v 1.23 1998/08/25 21:20:28 scrappy Exp $
*
* NOTES:
* (1) The lock.c module assumes that the caller here is doing
@ -29,12 +29,10 @@
#include "utils/rel.h"
#include "miscadmin.h" /* MyDatabaseId */
static bool
MultiAcquire(LOCKMETHOD lockmethod, LOCKTAG *tag, LOCKMODE lockmode,
PG_LOCK_LEVEL level);
static bool
MultiRelease(LOCKMETHOD lockmethod, LOCKTAG *tag, LOCKMODE lockmode,
PG_LOCK_LEVEL level);
static bool MultiAcquire(LOCKMETHOD lockmethod, LOCKTAG *tag,
LOCKMODE lockmode, PG_LOCK_LEVEL level);
static bool MultiRelease(LOCKMETHOD lockmethod, LOCKTAG *tag,
LOCKMODE lockmode, PG_LOCK_LEVEL level);
#ifdef LowLevelLocking
@ -130,6 +128,7 @@ static int MultiPrios[] = {
* lock table is ONE lock table, not three.
*/
LOCKMETHOD MultiTableId = (LOCKMETHOD) NULL;
LOCKMETHOD LongTermTableId = (LOCKMETHOD) NULL;
#ifdef NOT_USED
LOCKMETHOD ShortTermTableId = (LOCKMETHOD) NULL;
#endif
@ -150,12 +149,25 @@ InitMultiLevelLocks()
/* -----------------------
* No short term lock table for now. -Jeff 15 July 1991
*
* ShortTermTableId = LockTableRename(lockmethod);
* ShortTermTableId = LockMethodTableRename(lockmethod);
* if (! (ShortTermTableId)) {
* elog(ERROR,"InitMultiLocks: couldnt rename lock table");
* }
* -----------------------
*/
#ifdef USER_LOCKS
/*
* Allocate another tableId for long-term locks
*/
LongTermTableId = LockMethodTableRename(MultiTableId);
if (!(LongTermTableId))
{
elog(ERROR,
"InitMultiLevelLocks: couldn't rename long-term lock table");
}
#endif
return MultiTableId;
}

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

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: lock.h,v 1.16 1998/08/01 15:26:37 vadim Exp $
* $Id: lock.h,v 1.17 1998/08/25 21:20:31 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -15,6 +15,8 @@
#include <storage/shmem.h>
#include <storage/itemptr.h>
#include <storage/sinvaladt.h>
#include <utils/array.h>
extern SPINLOCK LockMgrLock;
typedef int MASK;
@ -32,7 +34,7 @@ typedef int MASK;
* NLOCKENTS - The maximum number of lock entries in the lock table.
* ----------------------
*/
#define NBACKENDS 50
#define NBACKENDS MaxBackendId
#define NLOCKS_PER_XACT 40
#define NLOCKENTS NLOCKS_PER_XACT*NBACKENDS
@ -51,9 +53,14 @@ typedef int LOCKMETHOD;
* CreateSpinLocks() or the number of shared memory locations allocated
* for lock table spin locks in the case of machines with TAS instructions.
*/
#define MAX_LOCK_METHODS 2
#define MAX_LOCK_METHODS 3
#define INVALID_TABLEID 0
#define INVALID_TABLEID 0
#define INVALID_LOCKMETHOD INVALID_TABLEID
#define DEFAULT_LOCKMETHOD 1
#define USER_LOCKMETHOD 2
#define MIN_LOCKMETHOD DEFAULT_LOCKMETHOD
/*typedef struct LOCK LOCK; */
@ -63,9 +70,11 @@ typedef struct LTAG
Oid relId;
Oid dbId;
ItemPointerData tupleId;
uint16 lockmethod; /* needed by user locks */
} LOCKTAG;
#define TAGSIZE (sizeof(LOCKTAG))
#define LOCKTAG_LOCKMETHOD(locktag) ((locktag).lockmethod)
/* This is the control structure for a lock table. It
* lives in shared memory:
@ -143,8 +152,18 @@ typedef struct XIDTAG
SHMEM_OFFSET lock;
int pid;
TransactionId xid;
#ifdef USE_XIDTAG_LOCKMETHOD
uint16 lockmethod; /* for debug or consistency checking */
#endif
} XIDTAG;
#ifdef USE_XIDTAG_LOCKMETHOD
#define XIDTAG_LOCKMETHOD(xidtag) ((xidtag).lockmethod)
#else
#define XIDTAG_LOCKMETHOD(xidtag) \
(((LOCK*) MAKE_PTR((xidtag).lock))->tag.lockmethod)
#endif
typedef struct XIDLookupEnt
{
/* tag */
@ -157,6 +176,7 @@ typedef struct XIDLookupEnt
} XIDLookupEnt;
#define XID_TAGSIZE (sizeof(XIDTAG))
#define XIDENT_LOCKMETHOD(xident) (XIDTAG_LOCKMETHOD((xident).tag))
/* originally in procq.h */
typedef struct PROC_QUEUE
@ -191,14 +211,16 @@ typedef struct LOCK
int nActive;
} LOCK;
#define LockGetLock_nHolders(l) l->nHolders
#define LOCK_LOCKMETHOD(lock) (LOCKTAG_LOCKMETHOD((lock).tag))
#define LockGetLock_nHolders(l) l->nHolders
#ifdef NOT_USED
#define LockDecrWaitHolders(lock, lockmode) \
( \
lock->nHolding--, \
lock->holders[lockmode]-- \
)
#endif
#define LockLockTable() SpinAcquire(LockMgrLock);
#define UnlockLockTable() SpinRelease(LockMgrLock);
@ -209,23 +231,27 @@ extern SPINLOCK LockMgrLock;
*/
extern void InitLocks(void);
extern void LockDisable(int status);
extern LOCKMETHOD
LockMethodTableInit(char *tabName, MASK *conflictsP, int *prioP,
int numModes);
extern bool LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag, LOCKMODE lockmode);
extern int
LockResolveConflicts(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode,
TransactionId xid);
extern bool LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag, LOCKMODE lockmode);
extern LOCKMETHOD LockMethodTableInit(char *tabName, MASK *conflictsP,
int *prioP, int numModes);
extern LOCKMETHOD LockMethodTableRename(LOCKMETHOD lockmethod);
extern bool LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
LOCKMODE lockmode);
extern int LockResolveConflicts(LOCKMETHOD lockmethod, LOCK *lock,
LOCKMODE lockmode, TransactionId xid,
XIDLookupEnt *xidentP);
extern bool LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
LOCKMODE lockmode);
extern void GrantLock(LOCK *lock, LOCKMODE lockmode);
extern bool LockReleaseAll(LOCKMETHOD lockmethod, SHM_QUEUE *lockQueue);
extern int LockShmemSize(void);
extern bool LockingDisabled(void);
extern bool DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check);
extern bool DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock,
bool skip_check);
ArrayType* LockOwners(LOCKMETHOD lockmethod, LOCKTAG *locktag);
#ifdef DEADLOCK_DEBUG
extern void DumpLocks(void);
extern void DumpAllLocks(void);
#endif
#endif /* LOCK_H */

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: proc.h,v 1.13 1998/07/27 19:38:38 vadim Exp $
* $Id: proc.h,v 1.14 1998/08/25 21:20:32 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -105,10 +105,10 @@ extern bool ProcRemove(int pid);
/* make static in storage/lmgr/proc.c -- jolly */
extern void ProcQueueInit(PROC_QUEUE *queue);
extern int
ProcSleep(PROC_QUEUE *queue, SPINLOCK spinlock, int token,
int prio, LOCK *lock);
extern int ProcLockWakeup(PROC_QUEUE *queue, LOCKMETHOD lockmethod, LOCK *lock);
extern int ProcSleep(PROC_QUEUE *queue, SPINLOCK spinlock, int token,
int prio, LOCK *lock, TransactionId xid);
extern int ProcLockWakeup(PROC_QUEUE *queue, LOCKMETHOD lockmethod,
LOCK *lock);
extern void ProcAddLock(SHM_QUEUE *elem);
extern void ProcReleaseSpins(PROC *proc);
extern void ProcFreeAllSemaphores(void);