@ -24,6 +24,9 @@
*/
*/
typedef struct
typedef struct
{
{
/* Spinlock: protects the values below */
slock_t buffer_strategy_lock ;
/* Clock sweep hand: index of next buffer to consider grabbing */
/* Clock sweep hand: index of next buffer to consider grabbing */
int nextVictimBuffer ;
int nextVictimBuffer ;
@ -101,15 +104,10 @@ static void AddBufferToRing(BufferAccessStrategy strategy,
* strategy is a BufferAccessStrategy object , or NULL for default strategy .
* strategy is a BufferAccessStrategy object , or NULL for default strategy .
*
*
* To ensure that no one else can pin the buffer before we do , we must
* To ensure that no one else can pin the buffer before we do , we must
* return the buffer with the buffer header spinlock still held . If
* return the buffer with the buffer header spinlock still held .
* * lock_held is set on exit , we have returned with the BufFreelistLock
* still held , as well ; the caller must release that lock once the spinlock
* is dropped . We do it that way because releasing the BufFreelistLock
* might awaken other processes , and it would be bad to do the associated
* kernel calls while holding the buffer header spinlock .
*/
*/
volatile BufferDesc *
volatile BufferDesc *
StrategyGetBuffer ( BufferAccessStrategy strategy , bool * lock_held )
StrategyGetBuffer ( BufferAccessStrategy strategy )
{
{
volatile BufferDesc * buf ;
volatile BufferDesc * buf ;
Latch * bgwriterLatch ;
Latch * bgwriterLatch ;
@ -117,21 +115,17 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
/*
/*
* If given a strategy object , see whether it can select a buffer . We
* If given a strategy object , see whether it can select a buffer . We
* assume strategy objects don ' t need the BufFreelistL ock.
* assume strategy objects don ' t need buffer_strategy_l ock.
*/
*/
if ( strategy ! = NULL )
if ( strategy ! = NULL )
{
{
buf = GetBufferFromRing ( strategy ) ;
buf = GetBufferFromRing ( strategy ) ;
if ( buf ! = NULL )
if ( buf ! = NULL )
{
* lock_held = false ;
return buf ;
return buf ;
}
}
}
/* Nope, so lock the freelist */
/* Nope, so lock the freelist */
* lock_held = true ;
SpinLockAcquire ( & StrategyControl - > buffer_strategy_lock ) ;
LWLockAcquire ( BufFreelistLock , LW_EXCLUSIVE ) ;
/*
/*
* We count buffer allocation requests so that the bgwriter can estimate
* We count buffer allocation requests so that the bgwriter can estimate
@ -142,22 +136,22 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
/*
/*
* If bgwriterLatch is set , we need to waken the bgwriter , but we should
* If bgwriterLatch is set , we need to waken the bgwriter , but we should
* not do so while holding BufFreelistL ock; so release and re - grab . This
* not do so while holding buffer_strategy_l ock; so release and re - grab .
* is annoyingly tedious , but it happens at most once per bgwriter cycle ,
* This is annoyingly tedious , but it happens at most once per bgwriter
* so the performance hit is minimal .
* cycle , so the performance hit is minimal .
*/
*/
bgwriterLatch = StrategyControl - > bgwriterLatch ;
bgwriterLatch = StrategyControl - > bgwriterLatch ;
if ( bgwriterLatch )
if ( bgwriterLatch )
{
{
StrategyControl - > bgwriterLatch = NULL ;
StrategyControl - > bgwriterLatch = NULL ;
LWLockRelease ( BufFreelistL ock) ;
SpinLockRelease ( & StrategyControl - > buffer_strategy_l ock) ;
SetLatch ( bgwriterLatch ) ;
SetLatch ( bgwriterLatch ) ;
LWLockAcquire ( BufFreelistLock , LW_EXCLUSIVE ) ;
SpinLockAcquire ( & StrategyControl - > buffer_strategy_lock ) ;
}
}
/*
/*
* Try to get a buffer from the freelist . Note that the freeNext fields
* Try to get a buffer from the freelist . Note that the freeNext fields
* are considered to be protected by the BufFreelistL ock not the
* are considered to be protected by the buffer_strategy_l ock not the
* individual buffer spinlocks , so it ' s OK to manipulate them without
* individual buffer spinlocks , so it ' s OK to manipulate them without
* holding the spinlock .
* holding the spinlock .
*/
*/
@ -170,6 +164,12 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
StrategyControl - > firstFreeBuffer = buf - > freeNext ;
StrategyControl - > firstFreeBuffer = buf - > freeNext ;
buf - > freeNext = FREENEXT_NOT_IN_LIST ;
buf - > freeNext = FREENEXT_NOT_IN_LIST ;
/*
* Release the lock so someone else can access the freelist ( or run
* the clocksweep ) while we check out this buffer .
*/
SpinLockRelease ( & StrategyControl - > buffer_strategy_lock ) ;
/*
/*
* If the buffer is pinned or has a nonzero usage_count , we cannot use
* If the buffer is pinned or has a nonzero usage_count , we cannot use
* it ; discard it and retry . ( This can only happen if VACUUM put a
* it ; discard it and retry . ( This can only happen if VACUUM put a
@ -185,6 +185,9 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
return buf ;
return buf ;
}
}
UnlockBufHdr ( buf ) ;
UnlockBufHdr ( buf ) ;
/* Reacquire the lock and go around for another pass. */
SpinLockAcquire ( & StrategyControl - > buffer_strategy_lock ) ;
}
}
/* Nothing on the freelist, so run the "clock sweep" algorithm */
/* Nothing on the freelist, so run the "clock sweep" algorithm */
@ -199,6 +202,9 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
StrategyControl - > completePasses + + ;
StrategyControl - > completePasses + + ;
}
}
/* Release the lock before manipulating the candidate buffer. */
SpinLockRelease ( & StrategyControl - > buffer_strategy_lock ) ;
/*
/*
* If the buffer is pinned or has a nonzero usage_count , we cannot use
* If the buffer is pinned or has a nonzero usage_count , we cannot use
* it ; decrement the usage_count ( unless pinned ) and keep scanning .
* it ; decrement the usage_count ( unless pinned ) and keep scanning .
@ -232,6 +238,9 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
elog ( ERROR , " no unpinned buffers available " ) ;
elog ( ERROR , " no unpinned buffers available " ) ;
}
}
UnlockBufHdr ( buf ) ;
UnlockBufHdr ( buf ) ;
/* Reacquire the lock and get a new candidate buffer. */
SpinLockAcquire ( & StrategyControl - > buffer_strategy_lock ) ;
}
}
}
}
@ -241,7 +250,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
void
void
StrategyFreeBuffer ( volatile BufferDesc * buf )
StrategyFreeBuffer ( volatile BufferDesc * buf )
{
{
LWLockAcquire ( BufFreelistLock , LW_EXCLUSIVE ) ;
SpinLockAcquire ( & StrategyControl - > buffer_strategy_lock ) ;
/*
/*
* It is possible that we are told to put something in the freelist that
* It is possible that we are told to put something in the freelist that
@ -255,7 +264,7 @@ StrategyFreeBuffer(volatile BufferDesc *buf)
StrategyControl - > firstFreeBuffer = buf - > buf_id ;
StrategyControl - > firstFreeBuffer = buf - > buf_id ;
}
}
LWLockRelease ( BufFreelistL ock) ;
SpinLockRelease ( & StrategyControl - > buffer_strategy_l ock) ;
}
}
/*
/*
@ -274,7 +283,7 @@ StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc)
{
{
int result ;
int result ;
LWLockAcquire ( BufFreelistLock , LW_EXCLUSIVE ) ;
SpinLockAcquire ( & StrategyControl - > buffer_strategy_lock ) ;
result = StrategyControl - > nextVictimBuffer ;
result = StrategyControl - > nextVictimBuffer ;
if ( complete_passes )
if ( complete_passes )
* complete_passes = StrategyControl - > completePasses ;
* complete_passes = StrategyControl - > completePasses ;
@ -283,7 +292,7 @@ StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc)
* num_buf_alloc = StrategyControl - > numBufferAllocs ;
* num_buf_alloc = StrategyControl - > numBufferAllocs ;
StrategyControl - > numBufferAllocs = 0 ;
StrategyControl - > numBufferAllocs = 0 ;
}
}
LWLockRelease ( BufFreelistL ock) ;
SpinLockRelease ( & StrategyControl - > buffer_strategy_l ock) ;
return result ;
return result ;
}
}
@ -299,13 +308,13 @@ void
StrategyNotifyBgWriter ( Latch * bgwriterLatch )
StrategyNotifyBgWriter ( Latch * bgwriterLatch )
{
{
/*
/*
* We acquire the BufFreelistL ock just to ensure that the store appears
* We acquire buffer_strategy_l ock just to ensure that the store appears
* atomic to StrategyGetBuffer . The bgwriter should call this rather
* atomic to StrategyGetBuffer . The bgwriter should call this rather
* infrequently , so there ' s no performance penalty from being safe .
* infrequently , so there ' s no performance penalty from being safe .
*/
*/
LWLockAcquire ( BufFreelistLock , LW_EXCLUSIVE ) ;
SpinLockAcquire ( & StrategyControl - > buffer_strategy_lock ) ;
StrategyControl - > bgwriterLatch = bgwriterLatch ;
StrategyControl - > bgwriterLatch = bgwriterLatch ;
LWLockRelease ( BufFreelistL ock) ;
SpinLockRelease ( & StrategyControl - > buffer_strategy_l ock) ;
}
}
@ -370,6 +379,8 @@ StrategyInitialize(bool init)
*/
*/
Assert ( init ) ;
Assert ( init ) ;
SpinLockInit ( & StrategyControl - > buffer_strategy_lock ) ;
/*
/*
* Grab the whole linked list of free buffers for our strategy . We
* Grab the whole linked list of free buffers for our strategy . We
* assume it was previously set up by InitBufferPool ( ) .
* assume it was previously set up by InitBufferPool ( ) .