]> granicus.if.org Git - postgresql/commitdiff
A fix for the pg_log bug
authorMarc G. Fournier <scrappy@hub.org>
Thu, 19 Sep 1996 19:47:31 +0000 (19:47 +0000)
committerMarc G. Fournier <scrappy@hub.org>
Thu, 19 Sep 1996 19:47:31 +0000 (19:47 +0000)
Submitted by: "Vadim B. Mikheev" <vadim@sable.krasnoyarsk.su>

src/backend/storage/buffer/bufmgr.c

index 86246135cc5b8b96614c4ea2bc2e30d76a3b5ef8..1ab49526bf9b7cf33359f93a2a23ebd189ba7335 100644 (file)
@@ -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);
                }