Commit aceac3a9 authored by Marc G. Fournier's avatar Marc G. Fournier

Fix for pg_log bug

Submitted by: "Vadim B. Mikheev" <vadim@sable.krasnoyarsk.su>
parent 0318f227
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.2 1996/07/23 05:44:10 scrappy Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.3 1996/09/19 19:50:48 scrappy Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -280,7 +280,7 @@ ReadBufferWithBufferLock(Relation reln, ...@@ -280,7 +280,7 @@ ReadBufferWithBufferLock(Relation reln,
* the buffer can tell that the contents are invalid. * the buffer can tell that the contents are invalid.
*/ */
bufHdr->flags |= BM_IO_ERROR; bufHdr->flags |= BM_IO_ERROR;
bufHdr->flags &= ~BM_IO_IN_PROGRESS;
} else { } else {
/* IO Succeeded. clear the flags, finish buffer update */ /* IO Succeeded. clear the flags, finish buffer update */
...@@ -297,6 +297,9 @@ ReadBufferWithBufferLock(Relation reln, ...@@ -297,6 +297,9 @@ ReadBufferWithBufferLock(Relation reln,
SpinRelease(BufMgrLock); SpinRelease(BufMgrLock);
if (status == SM_FAIL)
return(InvalidBuffer);
return(BufferDescriptorGetBuffer(bufHdr)); return(BufferDescriptorGetBuffer(bufHdr));
} }
...@@ -387,6 +390,14 @@ BufferAlloc(Relation reln, ...@@ -387,6 +390,14 @@ BufferAlloc(Relation reln,
/* GetFreeBuffer will abort if it can't find a free buffer */ /* GetFreeBuffer will abort if it can't find a free buffer */
buf = GetFreeBuffer(); buf = GetFreeBuffer();
/*
* But it can return buf == NULL if we are in aborting
* transaction now and so elog(WARN,...) in GetFreeBuffer
* will not abort again.
*/
if ( buf == NULL )
return (NULL);
/* /*
* There should be exactly one pin on the buffer after * There should be exactly one pin on the buffer after
* it is allocated -- ours. If it had a pin it wouldn't * it is allocated -- ours. If it had a pin it wouldn't
...@@ -399,6 +410,7 @@ BufferAlloc(Relation reln, ...@@ -399,6 +410,7 @@ BufferAlloc(Relation reln,
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 1; PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 1;
if (buf->flags & BM_DIRTY) { if (buf->flags & BM_DIRTY) {
bool smok;
/* /*
* Set BM_IO_IN_PROGRESS to keep anyone from doing anything * Set BM_IO_IN_PROGRESS to keep anyone from doing anything
* with the contents of the buffer while we write it out. * with the contents of the buffer while we write it out.
...@@ -428,12 +440,39 @@ BufferAlloc(Relation reln, ...@@ -428,12 +440,39 @@ BufferAlloc(Relation reln,
* you on machines that don't have spinlocks. If you don't * you on machines that don't have spinlocks. If you don't
* operate with much concurrency, well... * operate with much concurrency, well...
*/ */
(void) BufferReplace(buf, true); smok = BufferReplace(buf, true);
BufferFlushCount++;
#ifndef OPTIMIZE_SINGLE #ifndef OPTIMIZE_SINGLE
SpinAcquire(BufMgrLock); SpinAcquire(BufMgrLock);
#endif /* OPTIMIZE_SINGLE */ #endif /* OPTIMIZE_SINGLE */
if ( smok == FALSE )
{
elog(NOTICE, "BufferAlloc: cannot write block %u for %s/%s",
buf->tag.blockNum, buf->sb_dbname, buf->sb_relname);
inProgress = FALSE;
buf->flags |= BM_IO_ERROR;
buf->flags &= ~BM_IO_IN_PROGRESS;
#ifdef HAS_TEST_AND_SET
S_UNLOCK(&(buf->io_in_progress_lock));
#else /* !HAS_TEST_AND_SET */
if (buf->refcount > 1)
SignalIO(buf);
#endif /* !HAS_TEST_AND_SET */
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
buf->refcount--;
if ( buf->refcount == 0 )
{
AddBufferToFreelist(buf);
buf->flags |= BM_FREE;
}
buf = (BufferDesc *) NULL;
}
else
{
BufferFlushCount++;
buf->flags &= ~BM_DIRTY;
}
/* /*
* Somebody could have pinned the buffer while we were * Somebody could have pinned the buffer while we were
* doing the I/O and had given up the BufMgrLock (though * doing the I/O and had given up the BufMgrLock (though
...@@ -445,7 +484,7 @@ BufferAlloc(Relation reln, ...@@ -445,7 +484,7 @@ BufferAlloc(Relation reln,
* no reason to think that we have an immediate disaster on * no reason to think that we have an immediate disaster on
* our hands. * our hands.
*/ */
if (buf->refcount > 1) { if (buf && buf->refcount > 1) {
inProgress = FALSE; inProgress = FALSE;
buf->flags &= ~BM_IO_IN_PROGRESS; buf->flags &= ~BM_IO_IN_PROGRESS;
#ifdef HAS_TEST_AND_SET #ifdef HAS_TEST_AND_SET
...@@ -473,18 +512,6 @@ BufferAlloc(Relation reln, ...@@ -473,18 +512,6 @@ BufferAlloc(Relation reln,
* to do. We'll just handle this as if it were found in * to do. We'll just handle this as if it were found in
* the buffer pool in the first place. * the buffer pool in the first place.
*/ */
PinBuffer(buf2);
inProgress = (buf2->flags & BM_IO_IN_PROGRESS);
*foundPtr = TRUE;
if (inProgress) {
WaitIO(buf2, BufMgrLock);
if (buf2->flags & BM_IO_ERROR) {
*foundPtr = FALSE;
}
}
if ( buf != NULL ) if ( buf != NULL )
{ {
#ifdef HAS_TEST_AND_SET #ifdef HAS_TEST_AND_SET
...@@ -499,10 +526,20 @@ BufferAlloc(Relation reln, ...@@ -499,10 +526,20 @@ BufferAlloc(Relation reln,
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0; PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
AddBufferToFreelist(buf); AddBufferToFreelist(buf);
buf->flags |= BM_FREE; buf->flags |= BM_FREE;
buf->flags &= ~BM_DIRTY;
buf->flags &= ~BM_IO_IN_PROGRESS; buf->flags &= ~BM_IO_IN_PROGRESS;
} }
PinBuffer(buf2);
inProgress = (buf2->flags & BM_IO_IN_PROGRESS);
*foundPtr = TRUE;
if (inProgress) {
WaitIO(buf2, BufMgrLock);
if (buf2->flags & BM_IO_ERROR) {
*foundPtr = FALSE;
}
}
SpinRelease(BufMgrLock); SpinRelease(BufMgrLock);
return(buf2); return(buf2);
...@@ -532,13 +569,6 @@ BufferAlloc(Relation reln, ...@@ -532,13 +569,6 @@ BufferAlloc(Relation reln,
} }
if (buf->flags & BM_DIRTY) {
/* must clear flag first because of wierd race
* condition described below.
*/
buf->flags &= ~BM_DIRTY;
}
/* record the database name and relation name for this buffer */ /* record the database name and relation name for this buffer */
strcpy (buf->sb_relname, reln->rd_rel->relname.data); strcpy (buf->sb_relname, reln->rd_rel->relname.data);
strcpy (buf->sb_dbname, GetDatabaseName()); strcpy (buf->sb_dbname, GetDatabaseName());
...@@ -813,6 +843,30 @@ BufferSync() ...@@ -813,6 +843,30 @@ BufferSync()
if (bufdb == MyDatabaseId || bufdb == (Oid) 0) { if (bufdb == MyDatabaseId || bufdb == (Oid) 0) {
reln = RelationIdCacheGetRelation(bufrel); reln = RelationIdCacheGetRelation(bufrel);
/*
* We have to pin buffer to keep anyone from stealing it
* from the buffer pool while we are flushing it or
* waiting in WaitIO. It's bad for GetFreeBuffer in
* BufferAlloc, but there is no other way to prevent
* writing into disk block data from some other buffer,
* getting smgr status of some other block and
* clearing BM_DIRTY of ... - VAdim 09/16/96
*/
PinBuffer(bufHdr);
if (bufHdr->flags & BM_IO_IN_PROGRESS)
{
WaitIO(bufHdr, BufMgrLock);
UnpinBuffer(bufHdr);
if (bufHdr->flags & BM_IO_ERROR)
{
elog(WARN, "cannot write %u for %s",
bufHdr->tag.blockNum, bufHdr->sb_relname);
}
if (reln != (Relation)NULL)
RelationDecrementReferenceCount(reln);
continue;
}
/* /*
* If we didn't have the reldesc in our local cache, flush this * If we didn't have the reldesc in our local cache, flush this
* page out using the 'blind write' storage manager routine. If * page out using the 'blind write' storage manager routine. If
...@@ -836,8 +890,10 @@ BufferSync() ...@@ -836,8 +890,10 @@ BufferSync()
SpinAcquire(BufMgrLock); SpinAcquire(BufMgrLock);
#endif /* OPTIMIZE_SINGLE */ #endif /* OPTIMIZE_SINGLE */
UnpinBuffer(bufHdr);
if (status == SM_FAIL) { if (status == SM_FAIL) {
elog(WARN, "cannot write %d for %16s", bufHdr->flags |= BM_IO_ERROR;
elog(WARN, "cannot write %u for %s",
bufHdr->tag.blockNum, bufHdr->sb_relname); bufHdr->tag.blockNum, bufHdr->sb_relname);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment