summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1996-09-19 19:47:31 +0000
committerMarc G. Fournier <scrappy@hub.org>1996-09-19 19:47:31 +0000
commit43b28429ef45aca3653ec9f2763e6d12ee5072c9 (patch)
tree1c56723465a748abb4c283d6eef4d87e085f2e07
parent7f34bdd31e93b85a4ff7f954864abb22e80c10be (diff)
downloadpostgresql-43b28429ef45aca3653ec9f2763e6d12ee5072c9.tar.gz
A fix for the pg_log bug
Submitted by: "Vadim B. Mikheev" <vadim@sable.krasnoyarsk.su>
-rw-r--r--src/backend/storage/buffer/bufmgr.c108
1 files changed, 82 insertions, 26 deletions
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 86246135cc..1ab49526bf 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -7,7 +7,7 @@
*
*
* 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.2.2.1 1996/09/19 19:47:31 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -280,7 +280,7 @@ ReadBufferWithBufferLock(Relation reln,
* the buffer can tell that the contents are invalid.
*/
bufHdr->flags |= BM_IO_ERROR;
-
+ bufHdr->flags &= ~BM_IO_IN_PROGRESS;
} else {
/* IO Succeeded. clear the flags, finish buffer update */
@@ -297,6 +297,9 @@ ReadBufferWithBufferLock(Relation reln,
SpinRelease(BufMgrLock);
+ if (status == SM_FAIL)
+ return(InvalidBuffer);
+
return(BufferDescriptorGetBuffer(bufHdr));
}
@@ -387,6 +390,14 @@ BufferAlloc(Relation reln,
/* GetFreeBuffer will abort if it can't find a free buffer */
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
* it is allocated -- ours. If it had a pin it wouldn't
@@ -399,6 +410,7 @@ BufferAlloc(Relation reln,
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 1;
if (buf->flags & BM_DIRTY) {
+ bool smok;
/*
* Set BM_IO_IN_PROGRESS to keep anyone from doing anything
* with the contents of the buffer while we write it out.
@@ -428,11 +440,38 @@ BufferAlloc(Relation reln,
* you on machines that don't have spinlocks. If you don't
* operate with much concurrency, well...
*/
- (void) BufferReplace(buf, true);
- BufferFlushCount++;
+ smok = BufferReplace(buf, true);
#ifndef OPTIMIZE_SINGLE
SpinAcquire(BufMgrLock);
#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
@@ -445,7 +484,7 @@ BufferAlloc(Relation reln,
* no reason to think that we have an immediate disaster on
* our hands.
*/
- if (buf->refcount > 1) {
+ if (buf && buf->refcount > 1) {
inProgress = FALSE;
buf->flags &= ~BM_IO_IN_PROGRESS;
#ifdef HAS_TEST_AND_SET
@@ -473,18 +512,6 @@ BufferAlloc(Relation reln,
* to do. We'll just handle this as if it were found in
* 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 )
{
#ifdef HAS_TEST_AND_SET
@@ -499,9 +526,19 @@ BufferAlloc(Relation reln,
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
AddBufferToFreelist(buf);
buf->flags |= BM_FREE;
- buf->flags &= ~BM_DIRTY;
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);
@@ -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 */
strcpy (buf->sb_relname, reln->rd_rel->relname.data);
strcpy (buf->sb_dbname, GetDatabaseName());
@@ -813,6 +843,30 @@ BufferSync()
if (bufdb == MyDatabaseId || bufdb == (Oid) 0) {
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
* page out using the 'blind write' storage manager routine. If
@@ -836,8 +890,10 @@ BufferSync()
SpinAcquire(BufMgrLock);
#endif /* OPTIMIZE_SINGLE */
+ UnpinBuffer(bufHdr);
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);
}