Tom Lane 22fe3d4b04 I finally understood what sinvaladt.c is doing --- and it
offended my aesthestic sensibility that there was so much unreadable code
doing so little.  Rewritten code is about half the size, faster, and
(I hope) much more intelligible.
1999-09-06 19:37:38 +00:00

267 lines
7.4 KiB
C

/*-------------------------------------------------------------------------
*
* lock.h
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: lock.h,v 1.34 1999/09/06 19:37:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef LOCK_H_
#define LOCK_H_
#include "storage/ipc.h"
#include "storage/itemptr.h"
#include "storage/shmem.h"
#include "utils/array.h"
extern SPINLOCK LockMgrLock;
typedef int LOCKMASK;
#define INIT_TABLE_SIZE 100
#define MAX_TABLE_SIZE 1000
/* ----------------------
* The following defines are used to estimate how much shared
* memory the lock manager is going to require.
* See LockShmemSize() in lock.c.
*
* NLOCKS_PER_XACT - The number of unique locks acquired in a transaction
* (should be configurable!)
* NLOCKENTS - The maximum number of lock entries in the lock table.
* ----------------------
*/
#define NLOCKS_PER_XACT 64
#define NLOCKENTS(maxBackends) (NLOCKS_PER_XACT*(maxBackends))
typedef int LOCKMODE;
typedef int LOCKMETHOD;
/* MAX_LOCKMODES cannot be larger than the bits in LOCKMASK */
#define MAX_LOCKMODES 8
/*
* MAX_LOCK_METHODS corresponds to the number of spin locks allocated in
* 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 3
#define INVALID_TABLEID 0
#define INVALID_LOCKMETHOD INVALID_TABLEID
#define DEFAULT_LOCKMETHOD 1
#define USER_LOCKMETHOD 2
#define MIN_LOCKMETHOD DEFAULT_LOCKMETHOD
typedef struct LTAG
{
Oid relId;
Oid dbId;
union
{
BlockNumber blkno;
TransactionId xid;
} objId;
/*
* offnum should be part of objId.tupleId above, but would increase
* sizeof(LOCKTAG) and so moved here; currently used by userlocks only.
*/
OffsetNumber offnum;
uint16 lockmethod; /* needed by userlocks */
} 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:
*
* lockmethod -- the handle used by the lock table's clients to
* refer to the type of lock table being used.
*
* numLockModes -- number of lock types (READ,WRITE,etc) that
* are defined on this lock table
*
* conflictTab -- this is an array of bitmasks showing lock
* type conflicts. conflictTab[i] is a mask with the j-th bit
* turned on if lock types i and j conflict.
*
* prio -- each lockmode has a priority, so, for example, waiting
* writers can be given priority over readers (to avoid
* starvation).
*
* masterlock -- synchronizes access to the table
*
*/
typedef struct LOCKMETHODCTL
{
LOCKMETHOD lockmethod;
int numLockModes;
int conflictTab[MAX_LOCKMODES];
int prio[MAX_LOCKMODES];
SPINLOCK masterLock;
} LOCKMETHODCTL;
/*
* lockHash -- hash table on lock Ids,
* xidHash -- hash on xid and lockId in case
* multiple processes are holding the lock
* ctl - control structure described above.
*/
typedef struct LOCKMETHODTABLE
{
HTAB *lockHash;
HTAB *xidHash;
LOCKMETHODCTL *ctl;
} LOCKMETHODTABLE;
/* -----------------------
* A transaction never conflicts with its own locks. Hence, if
* multiple transactions hold non-conflicting locks on the same
* data, private per-transaction information must be stored in the
* XID table. The tag is XID + shared memory lock address so that
* all locks can use the same XID table. The private information
* we store is the number of locks of each type (holders) and the
* total number of locks (nHolding) held by the transaction.
*
* NOTE:
* There were some problems with the fact that currently TransactionIdData
* is a 5 byte entity and compilers long word aligning of structure fields.
* If the 3 byte padding is put in front of the actual xid data then the
* hash function (which uses XID_TAGSIZE when deciding how many bytes of a
* struct to look at for the key) might only see the last two bytes of the xid.
*
* Clearly this is not good since its likely that these bytes will be the
* same for many transactions and hence they will share the same entry in
* hash table causing the entry to be corrupted. For this long-winded
* reason I have put the tag in a struct of its own to ensure that the
* XID_TAGSIZE is computed correctly. It used to be sizeof (SHMEM_OFFSET) +
* sizeof(TransactionIdData) which != sizeof(XIDTAG).
*
* Finally since the hash function will now look at all 12 bytes of the tag
* the padding bytes MUST be zero'd before use in hash_search() as they
* will have random values otherwise. Jeff 22 July 1991.
* -----------------------
*/
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 */
XIDTAG tag;
/* data */
int holders[MAX_LOCKMODES];
int nHolding;
SHM_QUEUE queue;
} XIDLookupEnt;
#define SHMEM_XIDTAB_KEYSIZE sizeof(XIDTAG)
#define SHMEM_XIDTAB_DATASIZE (sizeof(XIDLookupEnt) - SHMEM_XIDTAB_KEYSIZE)
#define XID_TAGSIZE (sizeof(XIDTAG))
#define XIDENT_LOCKMETHOD(xident) (XIDTAG_LOCKMETHOD((xident).tag))
/* originally in procq.h */
typedef struct PROC_QUEUE
{
SHM_QUEUE links;
int size;
} PROC_QUEUE;
/*
* lock information:
*
* tag -- uniquely identifies the object being locked
* mask -- union of the conflict masks of all lock types
* currently held on this object.
* waitProcs -- queue of processes waiting for this lock
* holders -- count of each lock type currently held on the
* lock.
* nHolding -- total locks of all types.
*/
typedef struct LOCK
{
/* hash key */
LOCKTAG tag;
/* data */
int mask;
int waitMask;
PROC_QUEUE waitProcs;
int holders[MAX_LOCKMODES];
int nHolding;
int activeHolders[MAX_LOCKMODES];
int nActive;
} LOCK;
#define SHMEM_LOCKTAB_KEYSIZE sizeof(LOCKTAG)
#define SHMEM_LOCKTAB_DATASIZE (sizeof(LOCK) - SHMEM_LOCKTAB_KEYSIZE)
#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);
extern SPINLOCK LockMgrLock;
/*
* function prototypes
*/
extern void InitLocks(void);
extern void LockDisable(int status);
extern LOCKMETHOD LockMethodTableInit(char *tabName, LOCKMASK *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(int maxBackends);
extern bool LockingDisabled(void);
extern bool DeadLockCheck(void *proc, LOCK *findlock);
#ifdef DEADLOCK_DEBUG
extern void DumpLocks(void);
extern void DumpAllLocks(void);
#endif
#endif /* LOCK_H */