Attached patch fixes oversights converting buf_id to Buffer in
PrintBufferDescs() and InvalidateBuffer(). Especially for the latter,
the reason we haven't seen any reports of the issue might be that it
needs certain concurrent conditions to be true.
Along the line, it also changes all direct maths against buf_id to use
BufferDescriptorGetBuffer() instead.
Regards,
Qingqing
diff --git a/src/backend/storage/buffer/bufmgr.c
b/src/backend/storage/buffer/bufmgr.c
new file mode 100644
index e4b2558..2e9a7c7
*** a/src/backend/storage/buffer/bufmgr.c
--- b/src/backend/storage/buffer/bufmgr.c
*** retry:
*** 1273,1279
UnlockBufHdr(buf);
LWLockRelease(oldPartitionLock);
/* safety check: should definitely not be our *own* pin */
! if (GetPrivateRefCount(buf->buf_id) > 0)
elog(ERROR, "buffer is pinned in InvalidateBuffer");
WaitIO(buf);
goto retry;
--- 1273,1279
UnlockBufHdr(buf);
LWLockRelease(oldPartitionLock);
/* safety check: should definitely not be our *own* pin */
! if (GetPrivateRefCount(BufferDescriptorGetBuffer(buf)) > 0)
elog(ERROR, "buffer is pinned in InvalidateBuffer");
WaitIO(buf);
goto retry;
*** ReleaseAndReadBuffer(Buffer buffer,
*** 1426,1441
static bool
PinBuffer(volatile BufferDesc *buf, BufferAccessStrategy strategy)
{
! int b = buf->buf_id;
boolresult;
PrivateRefCountEntry *ref;
! ref = GetPrivateRefCountEntry(b + 1, true);
if (ref == NULL)
{
ReservePrivateRefCountEntry();
! ref = NewPrivateRefCountEntry(b + 1);
LockBufHdr(buf);
buf->refcount++;
--- 1426,1441
static bool
PinBuffer(volatile BufferDesc *buf, BufferAccessStrategy strategy)
{
! Buffer b = BufferDescriptorGetBuffer(buf);
boolresult;
PrivateRefCountEntry *ref;
! ref = GetPrivateRefCountEntry(b, true);
if (ref == NULL)
{
ReservePrivateRefCountEntry();
! ref = NewPrivateRefCountEntry(b);
LockBufHdr(buf);
buf->refcount++;
*** PinBuffer(volatile BufferDesc *buf, Buff
*** 1460,1467
ref->refcount++;
Assert(ref->refcount > 0);
! ResourceOwnerRememberBuffer(CurrentResourceOwner,
!
BufferDescriptorGetBuffer(buf));
return result;
}
--- 1460,1466
ref->refcount++;
Assert(ref->refcount > 0);
! ResourceOwnerRememberBuffer(CurrentResourceOwner, b);
return result;
}
*** PinBuffer(volatile BufferDesc *buf, Buff
*** 1489,1511
static void
PinBuffer_Locked(volatile BufferDesc *buf)
{
! int b = buf->buf_id;
PrivateRefCountEntry *ref;
/*
* As explained, We don't expect any preexisting pins. That allows us to
* manipulate the PrivateRefCount after releasing the spinlock
*/
! Assert(GetPrivateRefCountEntry(b + 1, false) == NULL);
buf->refcount++;
UnlockBufHdr(buf);
! ref = NewPrivateRefCountEntry(b + 1);
ref->refcount++;
! ResourceOwnerRememberBuffer(CurrentResourceOwner,
!
BufferDescriptorGetBuffer(buf));
}
/*
--- 1488,1509
static void
PinBuffer_Locked(volatile BufferDesc *buf)
{
! Buffer b = BufferDescriptorGetBuffer(buf);
PrivateRefCountEntry *ref;
/*
* As explained, We don't expect any preexisting pins. That allows us to
* manipulate the PrivateRefCount after releasing the spinlock
*/
! Assert(GetPrivateRefCountEntry(b, false) == NULL);
buf->refcount++;
UnlockBufHdr(buf);
! ref = NewPrivateRefCountEntry(b);
ref->refcount++;
! ResourceOwnerRememberBuffer(CurrentResourceOwner, b);
}
/*
*** static void
*** 1520,1533
UnpinBuffer(volatile BufferDesc *buf, bool fixOwner)
{
PrivateRefCountEntry *ref;
/* not moving as we're likely deleting it soon anyway */
! ref = GetPrivateRefCountEntry(buf->buf_id + 1, false);
Assert(ref != NULL);
if (fixOwner)
! ResourceOwnerForgetBuffer(CurrentResourceOwner,
!
BufferDescriptorGetBuffer(buf));
Assert(ref->refcount > 0);
ref->refcount--;
--- 1518,1531
UnpinBuffer(volatile BufferDesc *buf, bool fixOwner)
{
PrivateRefCountEntry *ref;
+ Buffer b = BufferDescriptorGetBuffer(b