diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 119cfe92b0..89087f0fb8 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.135 2003/03/28 20:17:13 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.136 2003/05/10 19:04:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -68,6 +68,7 @@ static void WaitIO(BufferDesc *buf); static void StartBufferIO(BufferDesc *buf, bool forInput); static void TerminateBufferIO(BufferDesc *buf); static void ContinueBufferIO(BufferDesc *buf, bool forInput); +static void buffer_write_error_callback(void *arg); /* * Macro : BUFFER_IS_BROKEN @@ -699,14 +700,24 @@ BufferSync(void) { int i; BufferDesc *bufHdr; - Buffer buffer; - int status; - RelFileNode rnode; - XLogRecPtr recptr; - Relation reln = NULL; + ErrorContextCallback errcontext; + + /* Setup error traceback support for ereport() */ + errcontext.callback = buffer_write_error_callback; + errcontext.arg = NULL; + errcontext.previous = error_context_stack; + error_context_stack = &errcontext; for (i = 0, bufHdr = BufferDescriptors; i < NBuffers; i++, bufHdr++) { + Buffer buffer; + int status; + RelFileNode rnode; + XLogRecPtr recptr; + Relation reln; + + errcontext.arg = bufHdr; + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); if (!(bufHdr->flags & BM_VALID)) @@ -834,6 +845,8 @@ BufferSync(void) RelationDecrementReferenceCount(reln); } + /* Pop the error context stack */ + error_context_stack = errcontext.previous; } /* @@ -1011,12 +1024,19 @@ BufferReplace(BufferDesc *bufHdr) Relation reln; XLogRecPtr recptr; int status; + ErrorContextCallback errcontext; /* To check if block content changed while flushing. - vadim 01/17/97 */ bufHdr->flags &= ~BM_JUST_DIRTIED; LWLockRelease(BufMgrLock); + /* Setup error traceback support for ereport() */ + errcontext.callback = buffer_write_error_callback; + errcontext.arg = bufHdr; + errcontext.previous = error_context_stack; + error_context_stack = &errcontext; + /* * No need to lock buffer context - no one should be able to end * ReadBuffer @@ -1043,6 +1063,9 @@ BufferReplace(BufferDesc *bufHdr) if (reln != (Relation) NULL) RelationDecrementReferenceCount(reln); + /* Pop the error context stack */ + error_context_stack = errcontext.previous; + LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); if (status == SM_FAIL) @@ -1380,12 +1403,20 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) BufferDesc *bufHdr; XLogRecPtr recptr; int status; + ErrorContextCallback errcontext; + + /* Setup error traceback support for ereport() */ + errcontext.callback = buffer_write_error_callback; + errcontext.arg = NULL; + errcontext.previous = error_context_stack; + error_context_stack = &errcontext; if (rel->rd_istemp) { for (i = 0; i < NLocBuffer; i++) { bufHdr = &LocalBufferDescriptors[i]; + errcontext.arg = bufHdr; if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node)) { if (bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty) @@ -1395,6 +1426,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) (char *) MAKE_PTR(bufHdr->data)); if (status == SM_FAIL) { + error_context_stack = errcontext.previous; elog(WARNING, "FlushRelationBuffers(%s (local), %u): block %u is dirty, could not flush it", RelationGetRelationName(rel), firstDelBlock, bufHdr->tag.blockNum); @@ -1405,6 +1437,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) } if (LocalRefCount[i] > 0) { + error_context_stack = errcontext.previous; elog(WARNING, "FlushRelationBuffers(%s (local), %u): block %u is referenced (%ld)", RelationGetRelationName(rel), firstDelBlock, bufHdr->tag.blockNum, LocalRefCount[i]); @@ -1414,6 +1447,10 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) bufHdr->tag.rnode.relNode = InvalidOid; } } + + /* Pop the error context stack */ + error_context_stack = errcontext.previous; + return 0; } @@ -1422,6 +1459,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) for (i = 0; i < NBuffers; i++) { bufHdr = &BufferDescriptors[i]; + errcontext.arg = bufHdr; if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node)) { if (bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty) @@ -1483,6 +1521,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) if (!(bufHdr->flags & BM_FREE)) { LWLockRelease(BufMgrLock); + error_context_stack = errcontext.previous; elog(WARNING, "FlushRelationBuffers(%s, %u): block %u is referenced (private %ld, global %d)", RelationGetRelationName(rel), firstDelBlock, bufHdr->tag.blockNum, @@ -1493,7 +1532,12 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) BufTableDelete(bufHdr); } } + LWLockRelease(BufMgrLock); + + /* Pop the error context stack */ + error_context_stack = errcontext.previous; + return 0; } @@ -2083,3 +2127,17 @@ BufferGetFileNode(Buffer buffer) return (bufHdr->tag.rnode); } + +/* + * Error context callback for errors occurring during buffer writes. + */ +static void +buffer_write_error_callback(void *arg) +{ + BufferDesc *bufHdr = (BufferDesc *) arg; + + if (bufHdr != NULL) + errcontext("writing block %u of relation %u/%u", + bufHdr->tag.blockNum, + bufHdr->tag.rnode.tblNode, bufHdr->tag.rnode.relNode); +}