From 9ff69034b22d20e656c21e6265c07394f4c46045 Mon Sep 17 00:00:00 2001 From: "Vadim B. Mikheev" Date: Mon, 20 Jan 1997 04:36:48 +0000 Subject: [PATCH] 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. --- src/backend/storage/buffer/bufmgr.c | 77 +++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 419e886547..edb8859692 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.8 1997/01/16 08:11:41 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.9 1997/01/20 04:36:48 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -474,7 +474,19 @@ BufferAlloc(Relation reln, else { BufferFlushCount++; - buf->flags &= ~BM_DIRTY; + /* + * BM_JUST_DIRTIED cleared by BufferReplace and shouldn't + * be setted by anyone. - vadim 01/17/97 + */ + if ( buf->flags & BM_JUST_DIRTIED ) + { + elog (FATAL, "BufferAlloc: content of block %u (%s) changed while flushing", + buf->tag.blockNum, buf->sb_relname); + } + else + { + buf->flags &= ~BM_DIRTY; + } } /* @@ -488,7 +500,8 @@ BufferAlloc(Relation reln, * no reason to think that we have an immediate disaster on * our hands. */ - if (buf && buf->refcount > 1) { + if ( buf && buf->refcount > 1 ) + { inProgress = FALSE; buf->flags &= ~BM_IO_IN_PROGRESS; #ifdef HAS_TEST_AND_SET @@ -643,7 +656,7 @@ WriteBuffer(Buffer buffer) SpinAcquire(BufMgrLock); Assert(bufHdr->refcount > 0); - bufHdr->flags |= BM_DIRTY; + bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED); UnpinBuffer(bufHdr); SpinRelease(BufMgrLock); } @@ -733,19 +746,36 @@ FlushBuffer(Buffer buffer, bool release) bufrel = RelationIdCacheGetRelation (bufHdr->tag.relId.relId); Assert (bufrel != (Relation) NULL); + /* To check if block content changed while flushing. - vadim 01/17/97 */ + SpinAcquire(BufMgrLock); + bufHdr->flags &= ~BM_JUST_DIRTIED; + SpinRelease(BufMgrLock); + status = smgrflush(bufHdr->bufsmgr, bufrel, bufHdr->tag.blockNum, (char *) MAKE_PTR(bufHdr->data)); if (status == SM_FAIL) { - elog(WARN, "FlushBuffer: cannot flush block %u of the relation %.*s", - bufHdr->tag.blockNum, - NAMEDATALEN, bufrel->rd_rel->relname.data); + elog(WARN, "FlushBuffer: cannot flush block %u of the relation %s", + bufHdr->tag.blockNum, bufHdr->sb_relname); return (STATUS_ERROR); } SpinAcquire(BufMgrLock); - bufHdr->flags &= ~BM_DIRTY; + /* + * If this buffer was marked by someone as DIRTY while + * we were flushing it out we must not clear DIRTY flag + * - vadim 01/17/97 + */ + if ( bufHdr->flags & BM_JUST_DIRTIED ) + { + elog (NOTICE, "FlusfBuffer: content of block %u (%s) changed while flushing", + bufHdr->tag.blockNum, bufHdr->sb_relname); + } + else + { + bufHdr->flags &= ~BM_DIRTY; + } if ( release ) UnpinBuffer(bufHdr); SpinRelease(BufMgrLock); @@ -779,7 +809,7 @@ WriteNoReleaseBuffer(Buffer buffer) bufHdr = &BufferDescriptors[buffer-1]; SpinAcquire(BufMgrLock); - bufHdr->flags |= BM_DIRTY; + bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED); SpinRelease(BufMgrLock); } return(STATUS_OK); @@ -878,13 +908,19 @@ BufferSync() UnpinBuffer(bufHdr); if (bufHdr->flags & BM_IO_ERROR) { - elog(WARN, "cannot write %u for %s", + elog(WARN, "BufferSync: write error %u for %s", bufHdr->tag.blockNum, bufHdr->sb_relname); } if (reln != (Relation)NULL) RelationDecrementReferenceCount(reln); continue; } + + /* + * To check if block content changed while flushing + * (see below). - vadim 01/17/97 + */ + bufHdr->flags &= ~BM_JUST_DIRTIED; /* * If we didn't have the reldesc in our local cache, flush this @@ -912,15 +948,23 @@ BufferSync() UnpinBuffer(bufHdr); if (status == SM_FAIL) { bufHdr->flags |= BM_IO_ERROR; - elog(WARN, "cannot write %u for %s", + elog(WARN, "BufferSync: cannot write %u for %s", bufHdr->tag.blockNum, bufHdr->sb_relname); } /* - * What if someone has marked this buffer as DIRTY after - * smgr[blind]write but before SpinAcquire(BufMgrLock) - * ??? - vadim 01/16/97 + * If this buffer was marked by someone as DIRTY while + * we were flushing it out we must not clear DIRTY flag + * - vadim 01/17/97 */ - bufHdr->flags &= ~BM_DIRTY; + if ( bufHdr->flags & BM_JUST_DIRTIED ) + { + elog (NOTICE, "BufferSync: content of block %u (%s) changed while flushing", + bufHdr->tag.blockNum, bufHdr->sb_relname); + } + else + { + bufHdr->flags &= ~BM_DIRTY; + } if (reln != (Relation)NULL) RelationDecrementReferenceCount(reln); } @@ -1189,6 +1233,9 @@ BufferReplace(BufferDesc *bufHdr, bool bufferLockHeld) reln = RelationIdCacheGetRelation(bufrel); else reln = (Relation) NULL; + + /* To check if block content changed while flushing. - vadim 01/17/97 */ + bufHdr->flags &= ~BM_JUST_DIRTIED; SpinRelease(BufMgrLock);