mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-28 00:41:52 +02: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:
parent
1acf0d85fe
commit
7dbcf31be2
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user