Skip to content

Commit 9ff6903

Browse files
committed
Fixing possible losing data changes:
1. New flag - BM_JUST_DIRTIED - added for BufferDesc; 2. All data "dirtiers" (WriteBuffer and WriteNoReleaseBuffer) set this flag (and BM_DIRTY too); 3. All data "flushers" (FlushBuffer, BufferSync and BufferReplace) turn this flag off just before calling smgr[blind]write/smgrflush and check this flag after flushing buffer: if it turned ON then BM_DIRTY will stay ON.
1 parent deef313 commit 9ff6903

File tree

1 file changed

+62
-15
lines changed

1 file changed

+62
-15
lines changed

src/backend/storage/buffer/bufmgr.c

Lines changed: 62 additions & 15 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.8 1997/01/16 08:11:41 vadim Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.9 1997/01/20 04:36:48 vadim Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -474,7 +474,19 @@ BufferAlloc(Relation reln,
474474
else
475475
{
476476
BufferFlushCount++;
477-
buf->flags &= ~BM_DIRTY;
477+
/*
478+
* BM_JUST_DIRTIED cleared by BufferReplace and shouldn't
479+
* be setted by anyone. - vadim 01/17/97
480+
*/
481+
if ( buf->flags & BM_JUST_DIRTIED )
482+
{
483+
elog (FATAL, "BufferAlloc: content of block %u (%s) changed while flushing",
484+
buf->tag.blockNum, buf->sb_relname);
485+
}
486+
else
487+
{
488+
buf->flags &= ~BM_DIRTY;
489+
}
478490
}
479491

480492
/*
@@ -488,7 +500,8 @@ BufferAlloc(Relation reln,
488500
* no reason to think that we have an immediate disaster on
489501
* our hands.
490502
*/
491-
if (buf && buf->refcount > 1) {
503+
if ( buf && buf->refcount > 1 )
504+
{
492505
inProgress = FALSE;
493506
buf->flags &= ~BM_IO_IN_PROGRESS;
494507
#ifdef HAS_TEST_AND_SET
@@ -643,7 +656,7 @@ WriteBuffer(Buffer buffer)
643656

644657
SpinAcquire(BufMgrLock);
645658
Assert(bufHdr->refcount > 0);
646-
bufHdr->flags |= BM_DIRTY;
659+
bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
647660
UnpinBuffer(bufHdr);
648661
SpinRelease(BufMgrLock);
649662
}
@@ -733,19 +746,36 @@ FlushBuffer(Buffer buffer, bool release)
733746
bufrel = RelationIdCacheGetRelation (bufHdr->tag.relId.relId);
734747
Assert (bufrel != (Relation) NULL);
735748

749+
/* To check if block content changed while flushing. - vadim 01/17/97 */
750+
SpinAcquire(BufMgrLock);
751+
bufHdr->flags &= ~BM_JUST_DIRTIED;
752+
SpinRelease(BufMgrLock);
753+
736754
status = smgrflush(bufHdr->bufsmgr, bufrel, bufHdr->tag.blockNum,
737755
(char *) MAKE_PTR(bufHdr->data));
738756

739757
if (status == SM_FAIL)
740758
{
741-
elog(WARN, "FlushBuffer: cannot flush block %u of the relation %.*s",
742-
bufHdr->tag.blockNum,
743-
NAMEDATALEN, bufrel->rd_rel->relname.data);
759+
elog(WARN, "FlushBuffer: cannot flush block %u of the relation %s",
760+
bufHdr->tag.blockNum, bufHdr->sb_relname);
744761
return (STATUS_ERROR);
745762
}
746763

747764
SpinAcquire(BufMgrLock);
748-
bufHdr->flags &= ~BM_DIRTY;
765+
/*
766+
* If this buffer was marked by someone as DIRTY while
767+
* we were flushing it out we must not clear DIRTY flag
768+
* - vadim 01/17/97
769+
*/
770+
if ( bufHdr->flags & BM_JUST_DIRTIED )
771+
{
772+
elog (NOTICE, "FlusfBuffer: content of block %u (%s) changed while flushing",
773+
bufHdr->tag.blockNum, bufHdr->sb_relname);
774+
}
775+
else
776+
{
777+
bufHdr->flags &= ~BM_DIRTY;
778+
}
749779
if ( release )
750780
UnpinBuffer(bufHdr);
751781
SpinRelease(BufMgrLock);
@@ -779,7 +809,7 @@ WriteNoReleaseBuffer(Buffer buffer)
779809
bufHdr = &BufferDescriptors[buffer-1];
780810

781811
SpinAcquire(BufMgrLock);
782-
bufHdr->flags |= BM_DIRTY;
812+
bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
783813
SpinRelease(BufMgrLock);
784814
}
785815
return(STATUS_OK);
@@ -878,13 +908,19 @@ BufferSync()
878908
UnpinBuffer(bufHdr);
879909
if (bufHdr->flags & BM_IO_ERROR)
880910
{
881-
elog(WARN, "cannot write %u for %s",
911+
elog(WARN, "BufferSync: write error %u for %s",
882912
bufHdr->tag.blockNum, bufHdr->sb_relname);
883913
}
884914
if (reln != (Relation)NULL)
885915
RelationDecrementReferenceCount(reln);
886916
continue;
887917
}
918+
919+
/*
920+
* To check if block content changed while flushing
921+
* (see below). - vadim 01/17/97
922+
*/
923+
bufHdr->flags &= ~BM_JUST_DIRTIED;
888924

889925
/*
890926
* If we didn't have the reldesc in our local cache, flush this
@@ -912,15 +948,23 @@ BufferSync()
912948
UnpinBuffer(bufHdr);
913949
if (status == SM_FAIL) {
914950
bufHdr->flags |= BM_IO_ERROR;
915-
elog(WARN, "cannot write %u for %s",
951+
elog(WARN, "BufferSync: cannot write %u for %s",
916952
bufHdr->tag.blockNum, bufHdr->sb_relname);
917953
}
918954
/*
919-
* What if someone has marked this buffer as DIRTY after
920-
* smgr[blind]write but before SpinAcquire(BufMgrLock)
921-
* ??? - vadim 01/16/97
955+
* If this buffer was marked by someone as DIRTY while
956+
* we were flushing it out we must not clear DIRTY flag
957+
* - vadim 01/17/97
922958
*/
923-
bufHdr->flags &= ~BM_DIRTY;
959+
if ( bufHdr->flags & BM_JUST_DIRTIED )
960+
{
961+
elog (NOTICE, "BufferSync: content of block %u (%s) changed while flushing",
962+
bufHdr->tag.blockNum, bufHdr->sb_relname);
963+
}
964+
else
965+
{
966+
bufHdr->flags &= ~BM_DIRTY;
967+
}
924968
if (reln != (Relation)NULL)
925969
RelationDecrementReferenceCount(reln);
926970
}
@@ -1189,6 +1233,9 @@ BufferReplace(BufferDesc *bufHdr, bool bufferLockHeld)
11891233
reln = RelationIdCacheGetRelation(bufrel);
11901234
else
11911235
reln = (Relation) NULL;
1236+
1237+
/* To check if block content changed while flushing. - vadim 01/17/97 */
1238+
bufHdr->flags &= ~BM_JUST_DIRTIED;
11921239

11931240
SpinRelease(BufMgrLock);
11941241

0 commit comments

Comments
 (0)