Make use of new error context stack mechanism to allow random errors

detected during buffer dump to be labeled with the buffer location.
For example, if a page LSN is clobbered, we now produce something like
ERROR:  XLogFlush: request 2C000000/8468EC8 is not satisfied --- flushed only
to 0/8468EF0
CONTEXT:  writing block 0 of relation 428946/566240
whereas before there was no convenient way to find out which page had
been trashed.
This commit is contained in:
Tom Lane 2003-05-10 19:04:30 +00:00
parent ecc8c3652e
commit a4e775a263

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 StartBufferIO(BufferDesc *buf, bool forInput);
static void TerminateBufferIO(BufferDesc *buf); static void TerminateBufferIO(BufferDesc *buf);
static void ContinueBufferIO(BufferDesc *buf, bool forInput); static void ContinueBufferIO(BufferDesc *buf, bool forInput);
static void buffer_write_error_callback(void *arg);
/* /*
* Macro : BUFFER_IS_BROKEN * Macro : BUFFER_IS_BROKEN
@ -699,14 +700,24 @@ BufferSync(void)
{ {
int i; int i;
BufferDesc *bufHdr; BufferDesc *bufHdr;
Buffer buffer; ErrorContextCallback errcontext;
int status;
RelFileNode rnode; /* Setup error traceback support for ereport() */
XLogRecPtr recptr; errcontext.callback = buffer_write_error_callback;
Relation reln = NULL; errcontext.arg = NULL;
errcontext.previous = error_context_stack;
error_context_stack = &errcontext;
for (i = 0, bufHdr = BufferDescriptors; i < NBuffers; i++, bufHdr++) 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); LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
if (!(bufHdr->flags & BM_VALID)) if (!(bufHdr->flags & BM_VALID))
@ -834,6 +845,8 @@ BufferSync(void)
RelationDecrementReferenceCount(reln); RelationDecrementReferenceCount(reln);
} }
/* Pop the error context stack */
error_context_stack = errcontext.previous;
} }
/* /*
@ -1011,12 +1024,19 @@ BufferReplace(BufferDesc *bufHdr)
Relation reln; Relation reln;
XLogRecPtr recptr; XLogRecPtr recptr;
int status; int status;
ErrorContextCallback errcontext;
/* To check if block content changed while flushing. - vadim 01/17/97 */ /* To check if block content changed while flushing. - vadim 01/17/97 */
bufHdr->flags &= ~BM_JUST_DIRTIED; bufHdr->flags &= ~BM_JUST_DIRTIED;
LWLockRelease(BufMgrLock); 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 * No need to lock buffer context - no one should be able to end
* ReadBuffer * ReadBuffer
@ -1043,6 +1063,9 @@ BufferReplace(BufferDesc *bufHdr)
if (reln != (Relation) NULL) if (reln != (Relation) NULL)
RelationDecrementReferenceCount(reln); RelationDecrementReferenceCount(reln);
/* Pop the error context stack */
error_context_stack = errcontext.previous;
LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
if (status == SM_FAIL) if (status == SM_FAIL)
@ -1380,12 +1403,20 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
BufferDesc *bufHdr; BufferDesc *bufHdr;
XLogRecPtr recptr; XLogRecPtr recptr;
int status; 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) if (rel->rd_istemp)
{ {
for (i = 0; i < NLocBuffer; i++) for (i = 0; i < NLocBuffer; i++)
{ {
bufHdr = &LocalBufferDescriptors[i]; bufHdr = &LocalBufferDescriptors[i];
errcontext.arg = bufHdr;
if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node)) if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node))
{ {
if (bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty) if (bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty)
@ -1395,6 +1426,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
(char *) MAKE_PTR(bufHdr->data)); (char *) MAKE_PTR(bufHdr->data));
if (status == SM_FAIL) if (status == SM_FAIL)
{ {
error_context_stack = errcontext.previous;
elog(WARNING, "FlushRelationBuffers(%s (local), %u): block %u is dirty, could not flush it", elog(WARNING, "FlushRelationBuffers(%s (local), %u): block %u is dirty, could not flush it",
RelationGetRelationName(rel), firstDelBlock, RelationGetRelationName(rel), firstDelBlock,
bufHdr->tag.blockNum); bufHdr->tag.blockNum);
@ -1405,6 +1437,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
} }
if (LocalRefCount[i] > 0) if (LocalRefCount[i] > 0)
{ {
error_context_stack = errcontext.previous;
elog(WARNING, "FlushRelationBuffers(%s (local), %u): block %u is referenced (%ld)", elog(WARNING, "FlushRelationBuffers(%s (local), %u): block %u is referenced (%ld)",
RelationGetRelationName(rel), firstDelBlock, RelationGetRelationName(rel), firstDelBlock,
bufHdr->tag.blockNum, LocalRefCount[i]); bufHdr->tag.blockNum, LocalRefCount[i]);
@ -1414,6 +1447,10 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
bufHdr->tag.rnode.relNode = InvalidOid; bufHdr->tag.rnode.relNode = InvalidOid;
} }
} }
/* Pop the error context stack */
error_context_stack = errcontext.previous;
return 0; return 0;
} }
@ -1422,6 +1459,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
for (i = 0; i < NBuffers; i++) for (i = 0; i < NBuffers; i++)
{ {
bufHdr = &BufferDescriptors[i]; bufHdr = &BufferDescriptors[i];
errcontext.arg = bufHdr;
if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node)) if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node))
{ {
if (bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty) if (bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty)
@ -1483,6 +1521,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
if (!(bufHdr->flags & BM_FREE)) if (!(bufHdr->flags & BM_FREE))
{ {
LWLockRelease(BufMgrLock); LWLockRelease(BufMgrLock);
error_context_stack = errcontext.previous;
elog(WARNING, "FlushRelationBuffers(%s, %u): block %u is referenced (private %ld, global %d)", elog(WARNING, "FlushRelationBuffers(%s, %u): block %u is referenced (private %ld, global %d)",
RelationGetRelationName(rel), firstDelBlock, RelationGetRelationName(rel), firstDelBlock,
bufHdr->tag.blockNum, bufHdr->tag.blockNum,
@ -1493,7 +1532,12 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
BufTableDelete(bufHdr); BufTableDelete(bufHdr);
} }
} }
LWLockRelease(BufMgrLock); LWLockRelease(BufMgrLock);
/* Pop the error context stack */
error_context_stack = errcontext.previous;
return 0; return 0;
} }
@ -2083,3 +2127,17 @@ BufferGetFileNode(Buffer buffer)
return (bufHdr->tag.rnode); 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);
}