1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
|
/*-------------------------------------------------------------------------
*
* lock.h--
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: lock.h,v 1.11 1998/02/26 04:43:28 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef LOCK_H_
#define LOCK_H_
#include <storage/shmem.h>
#include <storage/itemptr.h>
extern SPINLOCK LockMgrLock;
typedef int MASK;
#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.
*
* NBACKENDS - The number of concurrently running backends
* NLOCKS_PER_XACT - The number of unique locks acquired in a transaction
* NLOCKENTS - The maximum number of lock entries in the lock table.
* ----------------------
*/
#define NBACKENDS 50
#define NLOCKS_PER_XACT 40
#define NLOCKENTS NLOCKS_PER_XACT*NBACKENDS
typedef int LOCK_TYPE;
typedef int LOCKT;
typedef int LockTableId;
/* MAX_LOCKTYPES cannot be larger than the bits in MASK */
#define MAX_LOCKTYPES 6
/*
* MAX_TABLES 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_TABLES 2
#define INVALID_TABLEID 0
/*typedef struct LOCK LOCK; */
typedef struct ltag
{
Oid relId;
Oid dbId;
ItemPointerData tupleId;
} LOCKTAG;
#define TAGSIZE (sizeof(LOCKTAG))
/* This is the control structure for a lock table. It
* lives in shared memory:
*
* tableID -- the handle used by the lock table's clients to
* refer to the table.
*
* nLockTypes -- 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 locktype 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 lockctl
{
LockTableId tableId;
int nLockTypes;
int conflictTab[MAX_LOCKTYPES];
int prio[MAX_LOCKTYPES];
SPINLOCK masterLock;
} LOCKCTL;
/*
* 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 ltable
{
HTAB *lockHash;
HTAB *xidHash;
LOCKCTL *ctl;
} LOCKTAB;
/* -----------------------
* 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;
} XIDTAG;
typedef struct XIDLookupEnt
{
/* tag */
XIDTAG tag;
/* data */
int holders[MAX_LOCKTYPES];
int nHolding;
SHM_QUEUE queue;
} XIDLookupEnt;
#define XID_TAGSIZE (sizeof(XIDTAG))
/* originally in procq.h */
typedef struct procQueue
{
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;
PROC_QUEUE waitProcs;
int holders[MAX_LOCKTYPES];
int nHolding;
int activeHolders[MAX_LOCKTYPES];
int nActive;
} LOCK;
#define LockGetLock_nHolders(l) l->nHolders
#define LockDecrWaitHolders(lock, lockt) \
lock->nHolding--; \
lock->holders[lockt]--
#define LockLockTable() SpinAcquire(LockMgrLock);
#define UnlockLockTable() SpinRelease(LockMgrLock);
extern SPINLOCK LockMgrLock;
/*
* function prototypes
*/
extern void InitLocks(void);
extern void LockDisable(int status);
extern LockTableId
LockTabInit(char *tabName, MASK *conflictsP, int *prioP,
int ntypes);
extern bool LockAcquire(LockTableId tableId, LOCKTAG *lockName, LOCKT lockt);
extern int
LockResolveConflicts(LOCKTAB *ltable, LOCK *lock, LOCKT lockt,
TransactionId xid);
extern bool LockRelease(LockTableId tableId, LOCKTAG *lockName, LOCKT lockt);
extern void GrantLock(LOCK *lock, LOCKT lockt);
extern bool LockReleaseAll(LockTableId tableId, SHM_QUEUE *lockQueue);
extern int LockShmemSize(void);
extern bool LockingDisabled(void);
extern bool DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check);
#ifdef DEADLOCK_DEBUG
extern void DumpLocks(void);
#endif
#endif /* LOCK_H */
|