24
24
*/
25
25
typedef struct
26
26
{
27
+ /* Spinlock: protects the values below */
28
+ slock_t buffer_strategy_lock ;
29
+
27
30
/* Clock sweep hand: index of next buffer to consider grabbing */
28
31
int nextVictimBuffer ;
29
32
@@ -101,37 +104,28 @@ static void AddBufferToRing(BufferAccessStrategy strategy,
101
104
* strategy is a BufferAccessStrategy object, or NULL for default strategy.
102
105
*
103
106
* To ensure that no one else can pin the buffer before we do, we must
104
- * return the buffer with the buffer header spinlock still held. If
105
- * *lock_held is set on exit, we have returned with the BufFreelistLock
106
- * still held, as well; the caller must release that lock once the spinlock
107
- * is dropped. We do it that way because releasing the BufFreelistLock
108
- * might awaken other processes, and it would be bad to do the associated
109
- * kernel calls while holding the buffer header spinlock.
107
+ * return the buffer with the buffer header spinlock still held.
110
108
*/
111
109
volatile BufferDesc *
112
- StrategyGetBuffer (BufferAccessStrategy strategy , bool * lock_held )
110
+ StrategyGetBuffer (BufferAccessStrategy strategy )
113
111
{
114
112
volatile BufferDesc * buf ;
115
113
Latch * bgwriterLatch ;
116
114
int trycounter ;
117
115
118
116
/*
119
117
* If given a strategy object, see whether it can select a buffer. We
120
- * assume strategy objects don't need the BufFreelistLock .
118
+ * assume strategy objects don't need buffer_strategy_lock .
121
119
*/
122
120
if (strategy != NULL )
123
121
{
124
122
buf = GetBufferFromRing (strategy );
125
123
if (buf != NULL )
126
- {
127
- * lock_held = false;
128
124
return buf ;
129
- }
130
125
}
131
126
132
127
/* Nope, so lock the freelist */
133
- * lock_held = true;
134
- LWLockAcquire (BufFreelistLock , LW_EXCLUSIVE );
128
+ SpinLockAcquire (& StrategyControl -> buffer_strategy_lock );
135
129
136
130
/*
137
131
* We count buffer allocation requests so that the bgwriter can estimate
@@ -142,22 +136,22 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
142
136
143
137
/*
144
138
* If bgwriterLatch is set, we need to waken the bgwriter, but we should
145
- * not do so while holding BufFreelistLock ; so release and re-grab. This
146
- * is annoyingly tedious, but it happens at most once per bgwriter cycle,
147
- * so the performance hit is minimal.
139
+ * not do so while holding buffer_strategy_lock ; so release and re-grab.
140
+ * This is annoyingly tedious, but it happens at most once per bgwriter
141
+ * cycle, so the performance hit is minimal.
148
142
*/
149
143
bgwriterLatch = StrategyControl -> bgwriterLatch ;
150
144
if (bgwriterLatch )
151
145
{
152
146
StrategyControl -> bgwriterLatch = NULL ;
153
- LWLockRelease ( BufFreelistLock );
147
+ SpinLockRelease ( & StrategyControl -> buffer_strategy_lock );
154
148
SetLatch (bgwriterLatch );
155
- LWLockAcquire ( BufFreelistLock , LW_EXCLUSIVE );
149
+ SpinLockAcquire ( & StrategyControl -> buffer_strategy_lock );
156
150
}
157
151
158
152
/*
159
153
* Try to get a buffer from the freelist. Note that the freeNext fields
160
- * are considered to be protected by the BufFreelistLock not the
154
+ * are considered to be protected by the buffer_strategy_lock not the
161
155
* individual buffer spinlocks, so it's OK to manipulate them without
162
156
* holding the spinlock.
163
157
*/
@@ -170,6 +164,12 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
170
164
StrategyControl -> firstFreeBuffer = buf -> freeNext ;
171
165
buf -> freeNext = FREENEXT_NOT_IN_LIST ;
172
166
167
+ /*
168
+ * Release the lock so someone else can access the freelist (or run
169
+ * the clocksweep) while we check out this buffer.
170
+ */
171
+ SpinLockRelease (& StrategyControl -> buffer_strategy_lock );
172
+
173
173
/*
174
174
* If the buffer is pinned or has a nonzero usage_count, we cannot use
175
175
* it; discard it and retry. (This can only happen if VACUUM put a
@@ -185,6 +185,9 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
185
185
return buf ;
186
186
}
187
187
UnlockBufHdr (buf );
188
+
189
+ /* Reacquire the lock and go around for another pass. */
190
+ SpinLockAcquire (& StrategyControl -> buffer_strategy_lock );
188
191
}
189
192
190
193
/* Nothing on the freelist, so run the "clock sweep" algorithm */
@@ -199,6 +202,9 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
199
202
StrategyControl -> completePasses ++ ;
200
203
}
201
204
205
+ /* Release the lock before manipulating the candidate buffer. */
206
+ SpinLockRelease (& StrategyControl -> buffer_strategy_lock );
207
+
202
208
/*
203
209
* If the buffer is pinned or has a nonzero usage_count, we cannot use
204
210
* it; decrement the usage_count (unless pinned) and keep scanning.
@@ -232,6 +238,9 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
232
238
elog (ERROR , "no unpinned buffers available" );
233
239
}
234
240
UnlockBufHdr (buf );
241
+
242
+ /* Reacquire the lock and get a new candidate buffer. */
243
+ SpinLockAcquire (& StrategyControl -> buffer_strategy_lock );
235
244
}
236
245
}
237
246
@@ -241,7 +250,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
241
250
void
242
251
StrategyFreeBuffer (volatile BufferDesc * buf )
243
252
{
244
- LWLockAcquire ( BufFreelistLock , LW_EXCLUSIVE );
253
+ SpinLockAcquire ( & StrategyControl -> buffer_strategy_lock );
245
254
246
255
/*
247
256
* It is possible that we are told to put something in the freelist that
@@ -255,7 +264,7 @@ StrategyFreeBuffer(volatile BufferDesc *buf)
255
264
StrategyControl -> firstFreeBuffer = buf -> buf_id ;
256
265
}
257
266
258
- LWLockRelease ( BufFreelistLock );
267
+ SpinLockRelease ( & StrategyControl -> buffer_strategy_lock );
259
268
}
260
269
261
270
/*
@@ -274,7 +283,7 @@ StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc)
274
283
{
275
284
int result ;
276
285
277
- LWLockAcquire ( BufFreelistLock , LW_EXCLUSIVE );
286
+ SpinLockAcquire ( & StrategyControl -> buffer_strategy_lock );
278
287
result = StrategyControl -> nextVictimBuffer ;
279
288
if (complete_passes )
280
289
* complete_passes = StrategyControl -> completePasses ;
@@ -283,7 +292,7 @@ StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc)
283
292
* num_buf_alloc = StrategyControl -> numBufferAllocs ;
284
293
StrategyControl -> numBufferAllocs = 0 ;
285
294
}
286
- LWLockRelease ( BufFreelistLock );
295
+ SpinLockRelease ( & StrategyControl -> buffer_strategy_lock );
287
296
return result ;
288
297
}
289
298
@@ -299,13 +308,13 @@ void
299
308
StrategyNotifyBgWriter (Latch * bgwriterLatch )
300
309
{
301
310
/*
302
- * We acquire the BufFreelistLock just to ensure that the store appears
311
+ * We acquire buffer_strategy_lock just to ensure that the store appears
303
312
* atomic to StrategyGetBuffer. The bgwriter should call this rather
304
313
* infrequently, so there's no performance penalty from being safe.
305
314
*/
306
- LWLockAcquire ( BufFreelistLock , LW_EXCLUSIVE );
315
+ SpinLockAcquire ( & StrategyControl -> buffer_strategy_lock );
307
316
StrategyControl -> bgwriterLatch = bgwriterLatch ;
308
- LWLockRelease ( BufFreelistLock );
317
+ SpinLockRelease ( & StrategyControl -> buffer_strategy_lock );
309
318
}
310
319
311
320
@@ -370,6 +379,8 @@ StrategyInitialize(bool init)
370
379
*/
371
380
Assert (init );
372
381
382
+ SpinLockInit (& StrategyControl -> buffer_strategy_lock );
383
+
373
384
/*
374
385
* Grab the whole linked list of free buffers for our strategy. We
375
386
* assume it was previously set up by InitBufferPool().
0 commit comments