Skip to content

Commit 43b2842

Browse files
committed
A fix for the pg_log bug
Submitted by: "Vadim B. Mikheev" <vadim@sable.krasnoyarsk.su>
1 parent 7f34bdd commit 43b2842

File tree

1 file changed

+82
-26
lines changed

1 file changed

+82
-26
lines changed

src/backend/storage/buffer/bufmgr.c

Lines changed: 82 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.2 1996/07/23 05:44:10 scrappy Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.2.2.1 1996/09/19 19:47:31 scrappy Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -280,7 +280,7 @@ ReadBufferWithBufferLock(Relation reln,
280280
* the buffer can tell that the contents are invalid.
281281
*/
282282
bufHdr->flags |= BM_IO_ERROR;
283-
283+
bufHdr->flags &= ~BM_IO_IN_PROGRESS;
284284
} else {
285285
/* IO Succeeded. clear the flags, finish buffer update */
286286

@@ -297,6 +297,9 @@ ReadBufferWithBufferLock(Relation reln,
297297

298298
SpinRelease(BufMgrLock);
299299

300+
if (status == SM_FAIL)
301+
return(InvalidBuffer);
302+
300303
return(BufferDescriptorGetBuffer(bufHdr));
301304
}
302305

@@ -387,6 +390,14 @@ BufferAlloc(Relation reln,
387390
/* GetFreeBuffer will abort if it can't find a free buffer */
388391
buf = GetFreeBuffer();
389392

393+
/*
394+
* But it can return buf == NULL if we are in aborting
395+
* transaction now and so elog(WARN,...) in GetFreeBuffer
396+
* will not abort again.
397+
*/
398+
if ( buf == NULL )
399+
return (NULL);
400+
390401
/*
391402
* There should be exactly one pin on the buffer after
392403
* it is allocated -- ours. If it had a pin it wouldn't
@@ -399,6 +410,7 @@ BufferAlloc(Relation reln,
399410
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 1;
400411

401412
if (buf->flags & BM_DIRTY) {
413+
bool smok;
402414
/*
403415
* Set BM_IO_IN_PROGRESS to keep anyone from doing anything
404416
* with the contents of the buffer while we write it out.
@@ -428,11 +440,38 @@ BufferAlloc(Relation reln,
428440
* you on machines that don't have spinlocks. If you don't
429441
* operate with much concurrency, well...
430442
*/
431-
(void) BufferReplace(buf, true);
432-
BufferFlushCount++;
443+
smok = BufferReplace(buf, true);
433444
#ifndef OPTIMIZE_SINGLE
434445
SpinAcquire(BufMgrLock);
435446
#endif /* OPTIMIZE_SINGLE */
447+
448+
if ( smok == FALSE )
449+
{
450+
elog(NOTICE, "BufferAlloc: cannot write block %u for %s/%s",
451+
buf->tag.blockNum, buf->sb_dbname, buf->sb_relname);
452+
inProgress = FALSE;
453+
buf->flags |= BM_IO_ERROR;
454+
buf->flags &= ~BM_IO_IN_PROGRESS;
455+
#ifdef HAS_TEST_AND_SET
456+
S_UNLOCK(&(buf->io_in_progress_lock));
457+
#else /* !HAS_TEST_AND_SET */
458+
if (buf->refcount > 1)
459+
SignalIO(buf);
460+
#endif /* !HAS_TEST_AND_SET */
461+
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
462+
buf->refcount--;
463+
if ( buf->refcount == 0 )
464+
{
465+
AddBufferToFreelist(buf);
466+
buf->flags |= BM_FREE;
467+
}
468+
buf = (BufferDesc *) NULL;
469+
}
470+
else
471+
{
472+
BufferFlushCount++;
473+
buf->flags &= ~BM_DIRTY;
474+
}
436475

437476
/*
438477
* Somebody could have pinned the buffer while we were
@@ -445,7 +484,7 @@ BufferAlloc(Relation reln,
445484
* no reason to think that we have an immediate disaster on
446485
* our hands.
447486
*/
448-
if (buf->refcount > 1) {
487+
if (buf && buf->refcount > 1) {
449488
inProgress = FALSE;
450489
buf->flags &= ~BM_IO_IN_PROGRESS;
451490
#ifdef HAS_TEST_AND_SET
@@ -473,18 +512,6 @@ BufferAlloc(Relation reln,
473512
* to do. We'll just handle this as if it were found in
474513
* the buffer pool in the first place.
475514
*/
476-
477-
PinBuffer(buf2);
478-
inProgress = (buf2->flags & BM_IO_IN_PROGRESS);
479-
480-
*foundPtr = TRUE;
481-
if (inProgress) {
482-
WaitIO(buf2, BufMgrLock);
483-
if (buf2->flags & BM_IO_ERROR) {
484-
*foundPtr = FALSE;
485-
}
486-
}
487-
488515
if ( buf != NULL )
489516
{
490517
#ifdef HAS_TEST_AND_SET
@@ -499,9 +526,19 @@ BufferAlloc(Relation reln,
499526
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
500527
AddBufferToFreelist(buf);
501528
buf->flags |= BM_FREE;
502-
buf->flags &= ~BM_DIRTY;
503529
buf->flags &= ~BM_IO_IN_PROGRESS;
504530
}
531+
532+
PinBuffer(buf2);
533+
inProgress = (buf2->flags & BM_IO_IN_PROGRESS);
534+
535+
*foundPtr = TRUE;
536+
if (inProgress) {
537+
WaitIO(buf2, BufMgrLock);
538+
if (buf2->flags & BM_IO_ERROR) {
539+
*foundPtr = FALSE;
540+
}
541+
}
505542

506543
SpinRelease(BufMgrLock);
507544

@@ -532,13 +569,6 @@ BufferAlloc(Relation reln,
532569

533570
}
534571

535-
if (buf->flags & BM_DIRTY) {
536-
/* must clear flag first because of wierd race
537-
* condition described below.
538-
*/
539-
buf->flags &= ~BM_DIRTY;
540-
}
541-
542572
/* record the database name and relation name for this buffer */
543573
strcpy (buf->sb_relname, reln->rd_rel->relname.data);
544574
strcpy (buf->sb_dbname, GetDatabaseName());
@@ -813,6 +843,30 @@ BufferSync()
813843
if (bufdb == MyDatabaseId || bufdb == (Oid) 0) {
814844
reln = RelationIdCacheGetRelation(bufrel);
815845

846+
/*
847+
* We have to pin buffer to keep anyone from stealing it
848+
* from the buffer pool while we are flushing it or
849+
* waiting in WaitIO. It's bad for GetFreeBuffer in
850+
* BufferAlloc, but there is no other way to prevent
851+
* writing into disk block data from some other buffer,
852+
* getting smgr status of some other block and
853+
* clearing BM_DIRTY of ... - VAdim 09/16/96
854+
*/
855+
PinBuffer(bufHdr);
856+
if (bufHdr->flags & BM_IO_IN_PROGRESS)
857+
{
858+
WaitIO(bufHdr, BufMgrLock);
859+
UnpinBuffer(bufHdr);
860+
if (bufHdr->flags & BM_IO_ERROR)
861+
{
862+
elog(WARN, "cannot write %u for %s",
863+
bufHdr->tag.blockNum, bufHdr->sb_relname);
864+
}
865+
if (reln != (Relation)NULL)
866+
RelationDecrementReferenceCount(reln);
867+
continue;
868+
}
869+
816870
/*
817871
* If we didn't have the reldesc in our local cache, flush this
818872
* page out using the 'blind write' storage manager routine. If
@@ -836,8 +890,10 @@ BufferSync()
836890
SpinAcquire(BufMgrLock);
837891
#endif /* OPTIMIZE_SINGLE */
838892

893+
UnpinBuffer(bufHdr);
839894
if (status == SM_FAIL) {
840-
elog(WARN, "cannot write %d for %16s",
895+
bufHdr->flags |= BM_IO_ERROR;
896+
elog(WARN, "cannot write %u for %s",
841897
bufHdr->tag.blockNum, bufHdr->sb_relname);
842898
}
843899

0 commit comments

Comments
 (0)