提交 6d61cdec 编写于 作者: T Tom Lane

Clean up and document the API for XLogOpenRelation and XLogReadBuffer.

This commit doesn't make much functional change, but it does eliminate some
duplicated code --- for instance, PageIsNew tests are now done inside
XLogReadBuffer rather than by each caller.
The GIST xlog code still needs a lot of love, but I'll worry about that
separately.
上级 2154e1c1
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.11 2006/03/24 04:32:12 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.12 2006/03/29 21:17:36 tgl Exp $
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -177,9 +177,7 @@ gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot) ...@@ -177,9 +177,7 @@ gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot)
decodeEntryUpdateRecord(&xlrec, record); decodeEntryUpdateRecord(&xlrec, record);
reln = XLogOpenRelation(xlrec.data->node); reln = XLogOpenRelation(xlrec.data->node);
if (!RelationIsValid(reln)) buffer = XLogReadBuffer(reln, xlrec.data->blkno, false);
return;
buffer = XLogReadBuffer(false, reln, xlrec.data->blkno);
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "block %u unfound", xlrec.data->blkno); elog(PANIC, "block %u unfound", xlrec.data->blkno);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
...@@ -195,8 +193,6 @@ gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot) ...@@ -195,8 +193,6 @@ gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot)
} }
else else
{ {
if (PageIsNew((PageHeader) page))
elog(PANIC, "uninitialized page %u", xlrec.data->blkno);
if (XLByteLE(lsn, PageGetLSN(page))) if (XLByteLE(lsn, PageGetLSN(page)))
{ {
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
...@@ -302,17 +298,12 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record) ...@@ -302,17 +298,12 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
decodePageSplitRecord(&xlrec, record); decodePageSplitRecord(&xlrec, record);
reln = XLogOpenRelation(xlrec.data->node); reln = XLogOpenRelation(xlrec.data->node);
if (!RelationIsValid(reln))
return;
/* first of all wee need get F_LEAF flag from original page */ /* first of all wee need get F_LEAF flag from original page */
buffer = XLogReadBuffer(false, reln, xlrec.data->origblkno); buffer = XLogReadBuffer(reln, xlrec.data->origblkno, false);
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "block %u unfound", xlrec.data->origblkno); elog(PANIC, "block %u unfound", xlrec.data->origblkno);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page))
elog(PANIC, "uninitialized page %u", xlrec.data->origblkno);
flags = (GistPageIsLeaf(page)) ? F_LEAF : 0; flags = (GistPageIsLeaf(page)) ? F_LEAF : 0;
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer); ReleaseBuffer(buffer);
...@@ -323,7 +314,7 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record) ...@@ -323,7 +314,7 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
NewPage *newpage = xlrec.page + i; NewPage *newpage = xlrec.page + i;
bool isorigpage = (xlrec.data->origblkno == newpage->header->blkno) ? true : false; bool isorigpage = (xlrec.data->origblkno == newpage->header->blkno) ? true : false;
buffer = XLogReadBuffer(!isorigpage, reln, newpage->header->blkno); buffer = XLogReadBuffer(reln, newpage->header->blkno, !isorigpage);
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "block %u unfound", newpage->header->blkno); elog(PANIC, "block %u unfound", newpage->header->blkno);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
...@@ -367,24 +358,15 @@ gistRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) ...@@ -367,24 +358,15 @@ gistRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record)
Page page; Page page;
reln = XLogOpenRelation(*node); reln = XLogOpenRelation(*node);
if (!RelationIsValid(reln)) buffer = XLogReadBuffer(reln, GIST_ROOT_BLKNO, true);
return; Assert(BufferIsValid(buffer));
buffer = XLogReadBuffer(true, reln, GIST_ROOT_BLKNO);
if (!BufferIsValid(buffer))
elog(PANIC, "root block unfound");
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if (!PageIsNew((PageHeader) page) && XLByteLE(lsn, PageGetLSN(page)))
{
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
return;
}
GISTInitBuffer(buffer, F_LEAF); GISTInitBuffer(buffer, F_LEAF);
PageSetLSN(page, lsn); PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID); PageSetTLI(page, ThisTimeLineID);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer); WriteBuffer(buffer);
} }
...@@ -527,12 +509,10 @@ gist_form_invalid_tuple(BlockNumber blkno) ...@@ -527,12 +509,10 @@ gist_form_invalid_tuple(BlockNumber blkno)
static Buffer static Buffer
gistXLogReadAndLockBuffer(Relation r, BlockNumber blkno) gistXLogReadAndLockBuffer(Relation r, BlockNumber blkno)
{ {
Buffer buffer = XLogReadBuffer(false, r, blkno); Buffer buffer = XLogReadBuffer(r, blkno, false);
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "block %u unfound", blkno); elog(PANIC, "block %u unfound", blkno);
if (PageIsNew((PageHeader) (BufferGetPage(buffer))))
elog(PANIC, "uninitialized page %u", blkno);
return buffer; return buffer;
} }
...@@ -590,8 +570,6 @@ gistContinueInsert(gistIncompleteInsert *insert) ...@@ -590,8 +570,6 @@ gistContinueInsert(gistIncompleteInsert *insert)
Relation index; Relation index;
index = XLogOpenRelation(insert->node); index = XLogOpenRelation(insert->node);
if (!RelationIsValid(index))
return;
/* /*
* needed vector itup never will be more than initial lenblkno+2, because * needed vector itup never will be more than initial lenblkno+2, because
...@@ -606,29 +584,22 @@ gistContinueInsert(gistIncompleteInsert *insert) ...@@ -606,29 +584,22 @@ gistContinueInsert(gistIncompleteInsert *insert)
if (insert->origblkno == GIST_ROOT_BLKNO) if (insert->origblkno == GIST_ROOT_BLKNO)
{ {
/* /*
* it was split root, so we should only make new root. it can't be * it was split root, so we should only make new root. it can't be
* simple insert into root, look at call pushIncompleteInsert in * simple insert into root, look at call pushIncompleteInsert in
* gistRedoPageSplitRecord * gistRedoPageSplitRecord
*/ */
Buffer buffer = XLogReadBuffer(true, index, GIST_ROOT_BLKNO); Buffer buffer = XLogReadBuffer(index, GIST_ROOT_BLKNO, true);
Page page; Page page;
if (!BufferIsValid(buffer)) Assert(BufferIsValid(buffer));
elog(PANIC, "root block unfound");
page = BufferGetPage(buffer); page = BufferGetPage(buffer);
if (XLByteLE(insert->lsn, PageGetLSN(page)))
{
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
return;
}
GISTInitBuffer(buffer, 0); GISTInitBuffer(buffer, 0);
page = BufferGetPage(buffer);
gistfillbuffer(index, page, itup, lenitup, FirstOffsetNumber); gistfillbuffer(index, page, itup, lenitup, FirstOffsetNumber);
PageSetLSN(page, insert->lsn); PageSetLSN(page, insert->lsn);
PageSetTLI(page, ThisTimeLineID); PageSetTLI(page, ThisTimeLineID);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer); WriteBuffer(buffer);
} }
...@@ -654,12 +625,10 @@ gistContinueInsert(gistIncompleteInsert *insert) ...@@ -654,12 +625,10 @@ gistContinueInsert(gistIncompleteInsert *insert)
childfound = 0; childfound = 0;
numbuffer = 1; numbuffer = 1;
buffers[numbuffer - 1] = XLogReadBuffer(false, index, insert->path[i]); buffers[numbuffer - 1] = XLogReadBuffer(index, insert->path[i], false);
if (!BufferIsValid(buffers[numbuffer - 1])) if (!BufferIsValid(buffers[numbuffer - 1]))
elog(PANIC, "block %u unfound", insert->path[i]); elog(PANIC, "block %u unfound", insert->path[i]);
pages[numbuffer - 1] = BufferGetPage(buffers[numbuffer - 1]); pages[numbuffer - 1] = BufferGetPage(buffers[numbuffer - 1]);
if (PageIsNew((PageHeader) (pages[numbuffer - 1])))
elog(PANIC, "uninitialized page %u", insert->path[i]);
if (XLByteLE(insert->lsn, PageGetLSN(pages[numbuffer - 1]))) if (XLByteLE(insert->lsn, PageGetLSN(pages[numbuffer - 1])))
{ {
...@@ -693,7 +662,7 @@ gistContinueInsert(gistIncompleteInsert *insert) ...@@ -693,7 +662,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
if (gistnospace(pages[numbuffer - 1], itup, lenitup)) if (gistnospace(pages[numbuffer - 1], itup, lenitup))
{ {
/* no space left on page, so we should split */ /* no space left on page, so we should split */
buffers[numbuffer] = XLogReadBuffer(true, index, P_NEW); buffers[numbuffer] = XLogReadBuffer(index, P_NEW, true);
if (!BufferIsValid(buffers[numbuffer])) if (!BufferIsValid(buffers[numbuffer]))
elog(PANIC, "could not obtain new block"); elog(PANIC, "could not obtain new block");
GISTInitBuffer(buffers[numbuffer], 0); GISTInitBuffer(buffers[numbuffer], 0);
...@@ -717,7 +686,7 @@ gistContinueInsert(gistIncompleteInsert *insert) ...@@ -717,7 +686,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
RelationGetRelationName(index)); RelationGetRelationName(index));
/* fill new page */ /* fill new page */
buffers[numbuffer] = XLogReadBuffer(true, index, P_NEW); buffers[numbuffer] = XLogReadBuffer(index, P_NEW, true);
if (!BufferIsValid(buffers[numbuffer])) if (!BufferIsValid(buffers[numbuffer]))
elog(PANIC, "could not obtain new block"); elog(PANIC, "could not obtain new block");
GISTInitBuffer(buffers[numbuffer], 0); GISTInitBuffer(buffers[numbuffer], 0);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.209 2006/03/24 04:32:12 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.210 2006/03/29 21:17:36 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -2888,16 +2888,10 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record) ...@@ -2888,16 +2888,10 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record)
return; return;
reln = XLogOpenRelation(xlrec->node); reln = XLogOpenRelation(xlrec->node);
if (!RelationIsValid(reln)) buffer = XLogReadBuffer(reln, xlrec->block, false);
return;
buffer = XLogReadBuffer(false, reln, xlrec->block);
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "heap_clean_redo: no block"); return;
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page))
elog(PANIC, "heap_clean_redo: uninitialized page");
if (XLByteLE(lsn, PageGetLSN(page))) if (XLByteLE(lsn, PageGetLSN(page)))
{ {
...@@ -2943,16 +2937,9 @@ heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record) ...@@ -2943,16 +2937,9 @@ heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record)
* Note: the NEWPAGE log record is used for both heaps and indexes, so do * Note: the NEWPAGE log record is used for both heaps and indexes, so do
* not do anything that assumes we are touching a heap. * not do anything that assumes we are touching a heap.
*/ */
if (record->xl_info & XLR_BKP_BLOCK_1)
return;
reln = XLogOpenRelation(xlrec->node); reln = XLogOpenRelation(xlrec->node);
if (!RelationIsValid(reln)) buffer = XLogReadBuffer(reln, xlrec->blkno, true);
return; Assert(BufferIsValid(buffer));
buffer = XLogReadBuffer(true, reln, xlrec->blkno);
if (!BufferIsValid(buffer))
elog(PANIC, "heap_newpage_redo: no block");
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
Assert(record->xl_len == SizeOfHeapNewpage + BLCKSZ); Assert(record->xl_len == SizeOfHeapNewpage + BLCKSZ);
...@@ -2979,18 +2966,12 @@ heap_xlog_delete(XLogRecPtr lsn, XLogRecord *record) ...@@ -2979,18 +2966,12 @@ heap_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
return; return;
reln = XLogOpenRelation(xlrec->target.node); reln = XLogOpenRelation(xlrec->target.node);
buffer = XLogReadBuffer(reln,
if (!RelationIsValid(reln)) ItemPointerGetBlockNumber(&(xlrec->target.tid)),
return; false);
buffer = XLogReadBuffer(false, reln,
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "heap_delete_redo: no block"); return;
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page))
elog(PANIC, "heap_delete_redo: uninitialized page");
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
{ {
...@@ -3045,27 +3026,31 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record) ...@@ -3045,27 +3026,31 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
reln = XLogOpenRelation(xlrec->target.node); reln = XLogOpenRelation(xlrec->target.node);
if (!RelationIsValid(reln))
return;
buffer = XLogReadBuffer(true, reln,
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
if (!BufferIsValid(buffer))
return;
page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page) &&
!(record->xl_info & XLOG_HEAP_INIT_PAGE))
elog(PANIC, "heap_insert_redo: uninitialized page");
if (record->xl_info & XLOG_HEAP_INIT_PAGE) if (record->xl_info & XLOG_HEAP_INIT_PAGE)
PageInit(page, BufferGetPageSize(buffer), 0); {
buffer = XLogReadBuffer(reln,
ItemPointerGetBlockNumber(&(xlrec->target.tid)),
true);
Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer);
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ PageInit(page, BufferGetPageSize(buffer), 0);
}
else
{ {
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); buffer = XLogReadBuffer(reln,
ReleaseBuffer(buffer); ItemPointerGetBlockNumber(&(xlrec->target.tid)),
return; false);
if (!BufferIsValid(buffer))
return;
page = (Page) BufferGetPage(buffer);
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
{
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
return;
}
} }
offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid)); offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
...@@ -3110,9 +3095,8 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move) ...@@ -3110,9 +3095,8 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move)
xl_heap_update *xlrec = (xl_heap_update *) XLogRecGetData(record); xl_heap_update *xlrec = (xl_heap_update *) XLogRecGetData(record);
Relation reln = XLogOpenRelation(xlrec->target.node); Relation reln = XLogOpenRelation(xlrec->target.node);
Buffer buffer; Buffer buffer;
bool samepage = bool samepage = (ItemPointerGetBlockNumber(&(xlrec->newtid)) ==
(ItemPointerGetBlockNumber(&(xlrec->newtid)) == ItemPointerGetBlockNumber(&(xlrec->target.tid)));
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
Page page; Page page;
OffsetNumber offnum; OffsetNumber offnum;
ItemId lp = NULL; ItemId lp = NULL;
...@@ -3126,22 +3110,21 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move) ...@@ -3126,22 +3110,21 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move)
int hsize; int hsize;
uint32 newlen; uint32 newlen;
if (!RelationIsValid(reln))
return;
if (record->xl_info & XLR_BKP_BLOCK_1) if (record->xl_info & XLR_BKP_BLOCK_1)
{
if (samepage)
return; /* backup block covered both changes */
goto newt; goto newt;
}
/* Deal with old tuple version */ /* Deal with old tuple version */
buffer = XLogReadBuffer(false, reln, buffer = XLogReadBuffer(reln,
ItemPointerGetBlockNumber(&(xlrec->target.tid))); ItemPointerGetBlockNumber(&(xlrec->target.tid)),
false);
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "heap_update_redo: no block"); goto newt;
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page))
elog(PANIC, "heap_update_redo: uninitialized old page");
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
{ {
...@@ -3183,6 +3166,10 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move) ...@@ -3183,6 +3166,10 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move)
/* Set forward chain link in t_ctid */ /* Set forward chain link in t_ctid */
htup->t_ctid = xlrec->newtid; htup->t_ctid = xlrec->newtid;
} }
/*
* this test is ugly, but necessary to avoid thinking that insert change
* is already applied
*/
if (samepage) if (samepage)
goto newsame; goto newsame;
PageSetLSN(page, lsn); PageSetLSN(page, lsn);
...@@ -3194,32 +3181,38 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move) ...@@ -3194,32 +3181,38 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move)
newt:; newt:;
if ((record->xl_info & XLR_BKP_BLOCK_2) || if (record->xl_info & XLR_BKP_BLOCK_2)
((record->xl_info & XLR_BKP_BLOCK_1) && samepage))
return;
buffer = XLogReadBuffer(true, reln,
ItemPointerGetBlockNumber(&(xlrec->newtid)));
if (!BufferIsValid(buffer))
return; return;
page = (Page) BufferGetPage(buffer);
newsame:;
if (PageIsNew((PageHeader) page) &&
!(record->xl_info & XLOG_HEAP_INIT_PAGE))
elog(PANIC, "heap_update_redo: uninitialized page");
if (record->xl_info & XLOG_HEAP_INIT_PAGE) if (record->xl_info & XLOG_HEAP_INIT_PAGE)
PageInit(page, BufferGetPageSize(buffer), 0); {
buffer = XLogReadBuffer(reln,
ItemPointerGetBlockNumber(&(xlrec->newtid)),
true);
Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer);
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ PageInit(page, BufferGetPageSize(buffer), 0);
}
else
{ {
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); buffer = XLogReadBuffer(reln,
ReleaseBuffer(buffer); ItemPointerGetBlockNumber(&(xlrec->newtid)),
return; false);
if (!BufferIsValid(buffer))
return;
page = (Page) BufferGetPage(buffer);
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
{
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
return;
}
} }
newsame:;
offnum = ItemPointerGetOffsetNumber(&(xlrec->newtid)); offnum = ItemPointerGetOffsetNumber(&(xlrec->newtid));
if (PageGetMaxOffsetNumber(page) + 1 < offnum) if (PageGetMaxOffsetNumber(page) + 1 < offnum)
elog(PANIC, "heap_update_redo: invalid max offset number"); elog(PANIC, "heap_update_redo: invalid max offset number");
...@@ -3288,18 +3281,12 @@ heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record) ...@@ -3288,18 +3281,12 @@ heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record)
return; return;
reln = XLogOpenRelation(xlrec->target.node); reln = XLogOpenRelation(xlrec->target.node);
buffer = XLogReadBuffer(reln,
if (!RelationIsValid(reln)) ItemPointerGetBlockNumber(&(xlrec->target.tid)),
return; false);
buffer = XLogReadBuffer(false, reln,
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "heap_lock_redo: no block"); return;
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page))
elog(PANIC, "heap_lock_redo: uninitialized page");
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
{ {
...@@ -3381,7 +3368,10 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec) ...@@ -3381,7 +3368,10 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
{ {
xl_heap_insert *xlrec = (xl_heap_insert *) rec; xl_heap_insert *xlrec = (xl_heap_insert *) rec;
appendStringInfo(buf, "insert: "); if (xl_info & XLOG_HEAP_INIT_PAGE)
appendStringInfo(buf, "insert(init): ");
else
appendStringInfo(buf, "insert: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
} }
else if (info == XLOG_HEAP_DELETE) else if (info == XLOG_HEAP_DELETE)
...@@ -3391,12 +3381,25 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec) ...@@ -3391,12 +3381,25 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
appendStringInfo(buf, "delete: "); appendStringInfo(buf, "delete: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
} }
else if (info == XLOG_HEAP_UPDATE || info == XLOG_HEAP_MOVE) else if (info == XLOG_HEAP_UPDATE)
{ {
xl_heap_update *xlrec = (xl_heap_update *) rec; xl_heap_update *xlrec = (xl_heap_update *) rec;
if (info == XLOG_HEAP_UPDATE) if (xl_info & XLOG_HEAP_INIT_PAGE)
appendStringInfo(buf, "update(init): ");
else
appendStringInfo(buf, "update: "); appendStringInfo(buf, "update: ");
out_target(buf, &(xlrec->target));
appendStringInfo(buf, "; new %u/%u",
ItemPointerGetBlockNumber(&(xlrec->newtid)),
ItemPointerGetOffsetNumber(&(xlrec->newtid)));
}
else if (info == XLOG_HEAP_MOVE)
{
xl_heap_update *xlrec = (xl_heap_update *) rec;
if (xl_info & XLOG_HEAP_INIT_PAGE)
appendStringInfo(buf, "move(init): ");
else else
appendStringInfo(buf, "move: "); appendStringInfo(buf, "move: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.28 2006/03/28 21:17:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.29 2006/03/29 21:17:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -62,9 +62,9 @@ forget_matching_split(Relation reln, RelFileNode node, ...@@ -62,9 +62,9 @@ forget_matching_split(Relation reln, RelFileNode node,
ListCell *l; ListCell *l;
/* Get downlink TID from page */ /* Get downlink TID from page */
buffer = XLogReadBuffer(false, reln, insertblk); buffer = XLogReadBuffer(reln, insertblk, false);
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "forget_matching_split: block unfound"); return;
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum)); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
rightblk = ItemPointerGetBlockNumber(&(itup->t_tid)); rightblk = ItemPointerGetBlockNumber(&(itup->t_tid));
...@@ -117,11 +117,10 @@ _bt_restore_meta(Relation reln, XLogRecPtr lsn, ...@@ -117,11 +117,10 @@ _bt_restore_meta(Relation reln, XLogRecPtr lsn,
BTMetaPageData *md; BTMetaPageData *md;
BTPageOpaque pageop; BTPageOpaque pageop;
metabuf = XLogReadBuffer(true, reln, BTREE_METAPAGE); metabuf = XLogReadBuffer(reln, BTREE_METAPAGE, true);
if (!BufferIsValid(metabuf)) Assert(BufferIsValid(metabuf));
elog(PANIC, "_bt_restore_meta: no metapage");
metapg = BufferGetPage(metabuf); metapg = BufferGetPage(metabuf);
_bt_pageinit(metapg, BufferGetPageSize(metabuf)); _bt_pageinit(metapg, BufferGetPageSize(metabuf));
md = BTPageGetMeta(metapg); md = BTPageGetMeta(metapg);
...@@ -174,35 +173,33 @@ btree_xlog_insert(bool isleaf, bool ismeta, ...@@ -174,35 +173,33 @@ btree_xlog_insert(bool isleaf, bool ismeta,
return; /* nothing to do */ return; /* nothing to do */
reln = XLogOpenRelation(xlrec->target.node); reln = XLogOpenRelation(xlrec->target.node);
if (!RelationIsValid(reln))
return;
if (!(record->xl_info & XLR_BKP_BLOCK_1)) if (!(record->xl_info & XLR_BKP_BLOCK_1))
{ {
buffer = XLogReadBuffer(false, reln, buffer = XLogReadBuffer(reln,
ItemPointerGetBlockNumber(&(xlrec->target.tid))); ItemPointerGetBlockNumber(&(xlrec->target.tid)),
if (!BufferIsValid(buffer)) false);
elog(PANIC, "btree_insert_redo: block unfound"); if (BufferIsValid(buffer))
page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page))
elog(PANIC, "btree_insert_redo: uninitialized page");
if (XLByteLE(lsn, PageGetLSN(page)))
{
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
}
else
{ {
if (PageAddItem(page, (Item) datapos, datalen, page = (Page) BufferGetPage(buffer);
ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
LP_USED) == InvalidOffsetNumber)
elog(PANIC, "btree_insert_redo: failed to add item");
PageSetLSN(page, lsn); if (XLByteLE(lsn, PageGetLSN(page)))
PageSetTLI(page, ThisTimeLineID); {
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer); ReleaseBuffer(buffer);
}
else
{
if (PageAddItem(page, (Item) datapos, datalen,
ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
LP_USED) == InvalidOffsetNumber)
elog(PANIC, "btree_insert_redo: failed to add item");
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer);
}
} }
} }
...@@ -235,19 +232,15 @@ btree_xlog_split(bool onleft, bool isroot, ...@@ -235,19 +232,15 @@ btree_xlog_split(bool onleft, bool isroot,
BTPageOpaque pageop; BTPageOpaque pageop;
reln = XLogOpenRelation(xlrec->target.node); reln = XLogOpenRelation(xlrec->target.node);
if (!RelationIsValid(reln))
return;
targetblk = ItemPointerGetBlockNumber(&(xlrec->target.tid)); targetblk = ItemPointerGetBlockNumber(&(xlrec->target.tid));
leftsib = (onleft) ? targetblk : xlrec->otherblk; leftsib = (onleft) ? targetblk : xlrec->otherblk;
rightsib = (onleft) ? xlrec->otherblk : targetblk; rightsib = (onleft) ? xlrec->otherblk : targetblk;
/* Left (original) sibling */ /* Left (original) sibling */
buffer = XLogReadBuffer(true, reln, leftsib); buffer = XLogReadBuffer(reln, leftsib, true);
if (!BufferIsValid(buffer)) Assert(BufferIsValid(buffer));
elog(PANIC, "btree_split_redo: lost left sibling");
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
_bt_pageinit(page, BufferGetPageSize(buffer)); _bt_pageinit(page, BufferGetPageSize(buffer));
pageop = (BTPageOpaque) PageGetSpecialPointer(page); pageop = (BTPageOpaque) PageGetSpecialPointer(page);
...@@ -266,11 +259,10 @@ btree_xlog_split(bool onleft, bool isroot, ...@@ -266,11 +259,10 @@ btree_xlog_split(bool onleft, bool isroot,
WriteBuffer(buffer); WriteBuffer(buffer);
/* Right (new) sibling */ /* Right (new) sibling */
buffer = XLogReadBuffer(true, reln, rightsib); buffer = XLogReadBuffer(reln, rightsib, true);
if (!BufferIsValid(buffer)) Assert(BufferIsValid(buffer));
elog(PANIC, "btree_split_redo: lost right sibling");
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
_bt_pageinit(page, BufferGetPageSize(buffer)); _bt_pageinit(page, BufferGetPageSize(buffer));
pageop = (BTPageOpaque) PageGetSpecialPointer(page); pageop = (BTPageOpaque) PageGetSpecialPointer(page);
...@@ -293,28 +285,26 @@ btree_xlog_split(bool onleft, bool isroot, ...@@ -293,28 +285,26 @@ btree_xlog_split(bool onleft, bool isroot,
{ {
if (xlrec->rightblk != P_NONE) if (xlrec->rightblk != P_NONE)
{ {
buffer = XLogReadBuffer(false, reln, xlrec->rightblk); buffer = XLogReadBuffer(reln, xlrec->rightblk, false);
if (!BufferIsValid(buffer)) if (BufferIsValid(buffer))
elog(PANIC, "btree_split_redo: lost next right page");
page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page))
elog(PANIC, "btree_split_redo: uninitialized next right page");
if (XLByteLE(lsn, PageGetLSN(page)))
{ {
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); page = (Page) BufferGetPage(buffer);
ReleaseBuffer(buffer);
} if (XLByteLE(lsn, PageGetLSN(page)))
else {
{ LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
pageop = (BTPageOpaque) PageGetSpecialPointer(page); ReleaseBuffer(buffer);
pageop->btpo_prev = rightsib; }
else
PageSetLSN(page, lsn); {
PageSetTLI(page, ThisTimeLineID); pageop = (BTPageOpaque) PageGetSpecialPointer(page);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); pageop->btpo_prev = rightsib;
WriteBuffer(buffer);
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer);
}
} }
} }
} }
...@@ -346,14 +336,10 @@ btree_xlog_delete(XLogRecPtr lsn, XLogRecord *record) ...@@ -346,14 +336,10 @@ btree_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
xlrec = (xl_btree_delete *) XLogRecGetData(record); xlrec = (xl_btree_delete *) XLogRecGetData(record);
reln = XLogOpenRelation(xlrec->node); reln = XLogOpenRelation(xlrec->node);
if (!RelationIsValid(reln)) buffer = XLogReadBuffer(reln, xlrec->block, false);
return;
buffer = XLogReadBuffer(false, reln, xlrec->block);
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "btree_delete_redo: block unfound"); return;
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page))
elog(PANIC, "btree_delete_redo: uninitialized page");
if (XLByteLE(lsn, PageGetLSN(page))) if (XLByteLE(lsn, PageGetLSN(page)))
{ {
...@@ -394,9 +380,6 @@ btree_xlog_delete_page(bool ismeta, ...@@ -394,9 +380,6 @@ btree_xlog_delete_page(bool ismeta,
BTPageOpaque pageop; BTPageOpaque pageop;
reln = XLogOpenRelation(xlrec->target.node); reln = XLogOpenRelation(xlrec->target.node);
if (!RelationIsValid(reln))
return;
parent = ItemPointerGetBlockNumber(&(xlrec->target.tid)); parent = ItemPointerGetBlockNumber(&(xlrec->target.tid));
target = xlrec->deadblk; target = xlrec->deadblk;
leftsib = xlrec->leftblk; leftsib = xlrec->leftblk;
...@@ -405,86 +388,55 @@ btree_xlog_delete_page(bool ismeta, ...@@ -405,86 +388,55 @@ btree_xlog_delete_page(bool ismeta,
/* parent page */ /* parent page */
if (!(record->xl_info & XLR_BKP_BLOCK_1)) if (!(record->xl_info & XLR_BKP_BLOCK_1))
{ {
buffer = XLogReadBuffer(false, reln, parent); buffer = XLogReadBuffer(reln, parent, false);
if (!BufferIsValid(buffer)) if (BufferIsValid(buffer))
elog(PANIC, "btree_delete_page_redo: parent block unfound");
page = (Page) BufferGetPage(buffer);
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
if (PageIsNew((PageHeader) page))
elog(PANIC, "btree_delete_page_redo: uninitialized parent page");
if (XLByteLE(lsn, PageGetLSN(page)))
{
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
}
else
{ {
OffsetNumber poffset; page = (Page) BufferGetPage(buffer);
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
poffset = ItemPointerGetOffsetNumber(&(xlrec->target.tid)); if (XLByteLE(lsn, PageGetLSN(page)))
if (poffset >= PageGetMaxOffsetNumber(page))
{ {
Assert(poffset == P_FIRSTDATAKEY(pageop)); LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
PageIndexTupleDelete(page, poffset); ReleaseBuffer(buffer);
pageop->btpo_flags |= BTP_HALF_DEAD;
} }
else else
{ {
ItemId itemid; OffsetNumber poffset;
IndexTuple itup;
OffsetNumber nextoffset; poffset = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
if (poffset >= PageGetMaxOffsetNumber(page))
itemid = PageGetItemId(page, poffset); {
itup = (IndexTuple) PageGetItem(page, itemid); Assert(poffset == P_FIRSTDATAKEY(pageop));
ItemPointerSet(&(itup->t_tid), rightsib, P_HIKEY); PageIndexTupleDelete(page, poffset);
nextoffset = OffsetNumberNext(poffset); pageop->btpo_flags |= BTP_HALF_DEAD;
PageIndexTupleDelete(page, nextoffset); }
} else
{
ItemId itemid;
IndexTuple itup;
OffsetNumber nextoffset;
itemid = PageGetItemId(page, poffset);
itup = (IndexTuple) PageGetItem(page, itemid);
ItemPointerSet(&(itup->t_tid), rightsib, P_HIKEY);
nextoffset = OffsetNumberNext(poffset);
PageIndexTupleDelete(page, nextoffset);
}
PageSetLSN(page, lsn); PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID); PageSetTLI(page, ThisTimeLineID);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer); WriteBuffer(buffer);
}
} }
} }
/* Fix left-link of right sibling */ /* Fix left-link of right sibling */
if (!(record->xl_info & XLR_BKP_BLOCK_2)) if (!(record->xl_info & XLR_BKP_BLOCK_2))
{ {
buffer = XLogReadBuffer(false, reln, rightsib); buffer = XLogReadBuffer(reln, rightsib, false);
if (!BufferIsValid(buffer)) if (BufferIsValid(buffer))
elog(PANIC, "btree_delete_page_redo: lost right sibling");
page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page))
elog(PANIC, "btree_delete_page_redo: uninitialized right sibling");
if (XLByteLE(lsn, PageGetLSN(page)))
{
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
}
else
{
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
pageop->btpo_prev = leftsib;
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer);
}
}
/* Fix right-link of left sibling, if any */
if (!(record->xl_info & XLR_BKP_BLOCK_3))
{
if (leftsib != P_NONE)
{ {
buffer = XLogReadBuffer(false, reln, leftsib);
if (!BufferIsValid(buffer))
elog(PANIC, "btree_delete_page_redo: lost left sibling");
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page))
elog(PANIC, "btree_delete_page_redo: uninitialized left sibling");
if (XLByteLE(lsn, PageGetLSN(page))) if (XLByteLE(lsn, PageGetLSN(page)))
{ {
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
...@@ -493,7 +445,7 @@ btree_xlog_delete_page(bool ismeta, ...@@ -493,7 +445,7 @@ btree_xlog_delete_page(bool ismeta,
else else
{ {
pageop = (BTPageOpaque) PageGetSpecialPointer(page); pageop = (BTPageOpaque) PageGetSpecialPointer(page);
pageop->btpo_next = rightsib; pageop->btpo_prev = leftsib;
PageSetLSN(page, lsn); PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID); PageSetTLI(page, ThisTimeLineID);
...@@ -503,11 +455,39 @@ btree_xlog_delete_page(bool ismeta, ...@@ -503,11 +455,39 @@ btree_xlog_delete_page(bool ismeta,
} }
} }
/* Fix right-link of left sibling, if any */
if (!(record->xl_info & XLR_BKP_BLOCK_3))
{
if (leftsib != P_NONE)
{
buffer = XLogReadBuffer(reln, leftsib, false);
if (BufferIsValid(buffer))
{
page = (Page) BufferGetPage(buffer);
if (XLByteLE(lsn, PageGetLSN(page)))
{
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
}
else
{
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
pageop->btpo_next = rightsib;
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer);
}
}
}
}
/* Rewrite target page as empty deleted page */ /* Rewrite target page as empty deleted page */
buffer = XLogReadBuffer(true, reln, target); buffer = XLogReadBuffer(reln, target, true);
if (!BufferIsValid(buffer)) Assert(BufferIsValid(buffer));
elog(PANIC, "btree_delete_page_redo: lost target page");
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
_bt_pageinit(page, BufferGetPageSize(buffer)); _bt_pageinit(page, BufferGetPageSize(buffer));
pageop = (BTPageOpaque) PageGetSpecialPointer(page); pageop = (BTPageOpaque) PageGetSpecialPointer(page);
...@@ -544,13 +524,10 @@ btree_xlog_newroot(XLogRecPtr lsn, XLogRecord *record) ...@@ -544,13 +524,10 @@ btree_xlog_newroot(XLogRecPtr lsn, XLogRecord *record)
BTPageOpaque pageop; BTPageOpaque pageop;
reln = XLogOpenRelation(xlrec->node); reln = XLogOpenRelation(xlrec->node);
if (!RelationIsValid(reln)) buffer = XLogReadBuffer(reln, xlrec->rootblk, true);
return; Assert(BufferIsValid(buffer));
buffer = XLogReadBuffer(true, reln, xlrec->rootblk);
if (!BufferIsValid(buffer))
elog(PANIC, "btree_newroot_redo: no root page");
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
_bt_pageinit(page, BufferGetPageSize(buffer)); _bt_pageinit(page, BufferGetPageSize(buffer));
pageop = (BTPageOpaque) PageGetSpecialPointer(page); pageop = (BTPageOpaque) PageGetSpecialPointer(page);
...@@ -592,9 +569,6 @@ btree_xlog_newmeta(XLogRecPtr lsn, XLogRecord *record) ...@@ -592,9 +569,6 @@ btree_xlog_newmeta(XLogRecPtr lsn, XLogRecord *record)
Relation reln; Relation reln;
reln = XLogOpenRelation(xlrec->node); reln = XLogOpenRelation(xlrec->node);
if (!RelationIsValid(reln))
return;
_bt_restore_meta(reln, lsn, _bt_restore_meta(reln, lsn,
xlrec->meta.root, xlrec->meta.level, xlrec->meta.root, xlrec->meta.level,
xlrec->meta.fastroot, xlrec->meta.fastlevel); xlrec->meta.fastroot, xlrec->meta.fastlevel);
...@@ -800,14 +774,14 @@ btree_xlog_cleanup(void) ...@@ -800,14 +774,14 @@ btree_xlog_cleanup(void)
bool is_only; bool is_only;
reln = XLogOpenRelation(split->node); reln = XLogOpenRelation(split->node);
if (!RelationIsValid(reln)) lbuf = XLogReadBuffer(reln, split->leftblk, false);
continue; /* failure should be impossible because we wrote this page earlier */
lbuf = XLogReadBuffer(false, reln, split->leftblk);
if (!BufferIsValid(lbuf)) if (!BufferIsValid(lbuf))
elog(PANIC, "btree_xlog_cleanup: left block unfound"); elog(PANIC, "btree_xlog_cleanup: left block unfound");
lpage = (Page) BufferGetPage(lbuf); lpage = (Page) BufferGetPage(lbuf);
lpageop = (BTPageOpaque) PageGetSpecialPointer(lpage); lpageop = (BTPageOpaque) PageGetSpecialPointer(lpage);
rbuf = XLogReadBuffer(false, reln, split->rightblk); rbuf = XLogReadBuffer(reln, split->rightblk, false);
/* failure should be impossible because we wrote this page earlier */
if (!BufferIsValid(rbuf)) if (!BufferIsValid(rbuf))
elog(PANIC, "btree_xlog_cleanup: right block unfound"); elog(PANIC, "btree_xlog_cleanup: right block unfound");
rpage = (Page) BufferGetPage(rbuf); rpage = (Page) BufferGetPage(rbuf);
......
$PostgreSQL: pgsql/src/backend/access/transam/README,v 1.3 2005/05/19 21:35:45 tgl Exp $ $PostgreSQL: pgsql/src/backend/access/transam/README,v 1.4 2006/03/29 21:17:37 tgl Exp $
The Transaction System The Transaction System
---------------------- ----------------------
...@@ -252,3 +252,166 @@ slru.c is the supporting mechanism for both pg_clog and pg_subtrans. It ...@@ -252,3 +252,166 @@ slru.c is the supporting mechanism for both pg_clog and pg_subtrans. It
implements the LRU policy for in-memory buffer pages. The high-level routines implements the LRU policy for in-memory buffer pages. The high-level routines
for pg_clog are implemented in transam.c, while the low-level functions are in for pg_clog are implemented in transam.c, while the low-level functions are in
clog.c. pg_subtrans is contained completely in subtrans.c. clog.c. pg_subtrans is contained completely in subtrans.c.
Write-Ahead Log coding
----------------------
The WAL subsystem (also called XLOG in the code) exists to guarantee crash
recovery. It can also be used to provide point-in-time recovery, as well as
hot-standby replication via log shipping. Here are some notes about
non-obvious aspects of its design.
A basic assumption of a write AHEAD log is that log entries must reach stable
storage before the data-page changes they describe. This ensures that
replaying the log to its end will bring us to a consistent state where there
are no partially-performed transactions. To guarantee this, each data page
(either heap or index) is marked with the LSN (log sequence number --- in
practice, a WAL file location) of the latest XLOG record affecting the page.
Before the bufmgr can write out a dirty page, it must ensure that xlog has
been flushed to disk at least up to the page's LSN. This low-level
interaction improves performance by not waiting for XLOG I/O until necessary.
The LSN check exists only in the shared-buffer manager, not in the local
buffer manager used for temp tables; hence operations on temp tables must not
be WAL-logged.
During WAL replay, we can check the LSN of a page to detect whether the change
recorded by the current log entry is already applied (it has been, if the page
LSN is >= the log entry's WAL location).
Usually, log entries contain just enough information to redo a single
incremental update on a page (or small group of pages). This will work only
if the filesystem and hardware implement data page writes as atomic actions,
so that a page is never left in a corrupt partly-written state. Since that's
often an untenable assumption in practice, we log additional information to
allow complete reconstruction of modified pages. The first WAL record
affecting a given page after a checkpoint is made to contain a copy of the
entire page, and we implement replay by restoring that page copy instead of
redoing the update. (This is more reliable than the data storage itself would
be because we can check the validity of the WAL record's CRC.) We can detect
the "first change after checkpoint" by noting whether the page's old LSN
precedes the end of WAL as of the last checkpoint (the RedoRecPtr).
The general schema for executing a WAL-logged action is
1. Pin and exclusive-lock the shared buffer(s) containing the data page(s)
to be modified.
2. START_CRIT_SECTION() (Any error during the next two steps must cause a
PANIC because the shared buffers will contain unlogged changes, which we
have to ensure don't get to disk. Obviously, you should check conditions
such as whether there's enough free space on the page before you start the
critical section.)
3. Apply the required changes to the shared buffer(s).
4. Build a WAL log record and pass it to XLogInsert(); then update the page's
LSN and TLI using the returned XLOG location. For instance,
recptr = XLogInsert(rmgr_id, info, rdata);
PageSetLSN(dp, recptr);
PageSetTLI(dp, ThisTimeLineID);
5. END_CRIT_SECTION()
6. Unlock and write the buffer(s):
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer);
(Note: WriteBuffer doesn't really "write" the buffer anymore, it just marks it
dirty and unpins it. The write will not happen until a checkpoint occurs or
the shared buffer is needed for another page.)
XLogInsert's "rdata" argument is an array of pointer/size items identifying
chunks of data to be written in the XLOG record, plus optional shared-buffer
IDs for chunks that are in shared buffers rather than temporary variables.
The "rdata" array must mention (at least once) each of the shared buffers
being modified, unless the action is such that the WAL replay routine can
reconstruct the entire page contents. XLogInsert includes the logic that
tests to see whether a shared buffer has been modified since the last
checkpoint. If not, the entire page contents are logged rather than just the
portion(s) pointed to by "rdata".
Because XLogInsert drops the rdata components associated with buffers it
chooses to log in full, the WAL replay routines normally need to test to see
which buffers were handled that way --- otherwise they may be misled about
what the XLOG record actually contains. XLOG records that describe multi-page
changes therefore require some care to design: you must be certain that you
know what data is indicated by each "BKP" bit. An example of the trickiness
is that in a HEAP_UPDATE record, BKP(1) normally is associated with the source
page and BKP(2) is associated with the destination page --- but if these are
the same page, only BKP(1) would have been set.
For this reason as well as the risk of deadlocking on buffer locks, it's best
to design WAL records so that they reflect small atomic actions involving just
one or a few pages. The current XLOG infrastructure cannot handle WAL records
involving references to more than three shared buffers, anyway.
In the case where the WAL record contains enough information to re-generate
the entire contents of a page, do *not* show that page's buffer ID in the
rdata array, even if some of the rdata items point into the buffer. This is
because you don't want XLogInsert to log the whole page contents. The
standard replay-routine pattern for this case is
reln = XLogOpenRelation(rnode);
buffer = XLogReadBuffer(reln, blkno, true);
Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer);
... initialize the page ...
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer);
In the case where the WAL record provides only enough information to
incrementally update the page, the rdata array *must* mention the buffer
ID at least once; otherwise there is no defense against torn-page problems.
The standard replay-routine pattern for this case is
if (record->xl_info & XLR_BKP_BLOCK_n)
<< do nothing, page was rewritten from logged copy >>;
reln = XLogOpenRelation(rnode);
buffer = XLogReadBuffer(reln, blkno, false);
if (!BufferIsValid(buffer))
<< do nothing, page has been deleted >>;
page = (Page) BufferGetPage(buffer);
if (XLByteLE(lsn, PageGetLSN(page)))
{
/* changes are already applied */
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
ReleaseBuffer(buffer);
return;
}
... apply the change ...
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer);
As noted above, for a multi-page update you need to be able to determine
which XLR_BKP_BLOCK_n flag applies to each page. If a WAL record reflects
a combination of fully-rewritable and incremental updates, then the rewritable
pages don't count for the XLR_BKP_BLOCK_n numbering. (XLR_BKP_BLOCK_n is
associated with the n'th distinct buffer ID seen in the "rdata" array, and
per the above discussion, fully-rewritable buffers shouldn't be mentioned in
"rdata".)
Due to all these constraints, complex changes (such as a multilevel index
insertion) normally need to be described by a series of atomic-action WAL
records. What do you do if the intermediate states are not self-consistent?
The answer is that the WAL replay logic has to be able to fix things up.
In btree indexes, for example, a page split requires insertion of a new key in
the parent btree level, but for locking reasons this has to be reflected by
two separate WAL records. The replay code has to remember "unfinished" split
operations, and match them up to subsequent insertions in the parent level.
If no matching insert has been found by the time the WAL replay ends, the
replay code has to do the insertion on its own to restore the index to
consistency.
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.218 2006/03/24 04:32:12 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.219 2006/03/29 21:17:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -4097,7 +4097,7 @@ xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid) ...@@ -4097,7 +4097,7 @@ xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid)
/* Make sure files supposed to be dropped are dropped */ /* Make sure files supposed to be dropped are dropped */
for (i = 0; i < xlrec->nrels; i++) for (i = 0; i < xlrec->nrels; i++)
{ {
XLogCloseRelation(xlrec->xnodes[i]); XLogDropRelation(xlrec->xnodes[i]);
smgrdounlink(smgropen(xlrec->xnodes[i]), false, true); smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
} }
} }
...@@ -4132,7 +4132,7 @@ xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid) ...@@ -4132,7 +4132,7 @@ xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid)
/* Make sure files supposed to be dropped are dropped */ /* Make sure files supposed to be dropped are dropped */
for (i = 0; i < xlrec->nrels; i++) for (i = 0; i < xlrec->nrels; i++)
{ {
XLogCloseRelation(xlrec->xnodes[i]); XLogDropRelation(xlrec->xnodes[i]);
smgrdounlink(smgropen(xlrec->xnodes[i]), false, true); smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
} }
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.229 2006/03/28 22:01:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.230 2006/03/29 21:17:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2509,35 +2509,29 @@ RestoreBkpBlocks(XLogRecord *record, XLogRecPtr lsn) ...@@ -2509,35 +2509,29 @@ RestoreBkpBlocks(XLogRecord *record, XLogRecPtr lsn)
blk += sizeof(BkpBlock); blk += sizeof(BkpBlock);
reln = XLogOpenRelation(bkpb.node); reln = XLogOpenRelation(bkpb.node);
buffer = XLogReadBuffer(reln, bkpb.block, true);
Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer);
if (reln) if (bkpb.hole_length == 0)
{ {
buffer = XLogReadBuffer(true, reln, bkpb.block); memcpy((char *) page, blk, BLCKSZ);
if (BufferIsValid(buffer)) }
{ else
page = (Page) BufferGetPage(buffer); {
/* must zero-fill the hole */
if (bkpb.hole_length == 0) MemSet((char *) page, 0, BLCKSZ);
{ memcpy((char *) page, blk, bkpb.hole_offset);
memcpy((char *) page, blk, BLCKSZ); memcpy((char *) page + (bkpb.hole_offset + bkpb.hole_length),
} blk + bkpb.hole_offset,
else BLCKSZ - (bkpb.hole_offset + bkpb.hole_length));
{
/* must zero-fill the hole */
MemSet((char *) page, 0, BLCKSZ);
memcpy((char *) page, blk, bkpb.hole_offset);
memcpy((char *) page + (bkpb.hole_offset + bkpb.hole_length),
blk + bkpb.hole_offset,
BLCKSZ - (bkpb.hole_offset + bkpb.hole_length));
}
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer);
}
} }
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
WriteBuffer(buffer);
blk += BLCKSZ - bkpb.hole_length; blk += BLCKSZ - bkpb.hole_length;
} }
} }
...@@ -5451,25 +5445,19 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec) ...@@ -5451,25 +5445,19 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
static void static void
xlog_outrec(StringInfo buf, XLogRecord *record) xlog_outrec(StringInfo buf, XLogRecord *record)
{ {
int bkpb;
int i; int i;
appendStringInfo(buf, "prev %X/%X; xid %u", appendStringInfo(buf, "prev %X/%X; xid %u",
record->xl_prev.xlogid, record->xl_prev.xrecoff, record->xl_prev.xlogid, record->xl_prev.xrecoff,
record->xl_xid); record->xl_xid);
for (i = 0, bkpb = 0; i < XLR_MAX_BKP_BLOCKS; i++) for (i = 0; i < XLR_MAX_BKP_BLOCKS; i++)
{ {
if (!(record->xl_info & (XLR_SET_BKP_BLOCK(i)))) if (record->xl_info & XLR_SET_BKP_BLOCK(i))
continue; appendStringInfo(buf, "; bkpb%d", i+1);
bkpb++;
} }
if (bkpb) appendStringInfo(buf, ": %s", RmgrTable[record->xl_rmid].rm_name);
appendStringInfo(buf, "; bkpb %d", bkpb);
appendStringInfo(buf, ": %s",
RmgrTable[record->xl_rmid].rm_name);
} }
#endif /* WAL_DEBUG */ #endif /* WAL_DEBUG */
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.41 2006/03/05 15:58:22 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.42 2006/03/29 21:17:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -19,44 +19,81 @@ ...@@ -19,44 +19,81 @@
#include "access/xlogutils.h" #include "access/xlogutils.h"
#include "storage/bufmgr.h" #include "storage/bufmgr.h"
#include "storage/bufpage.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/hsearch.h" #include "utils/hsearch.h"
/* /*
* XLogReadBuffer
* Read a page during XLOG replay
* *
* Storage related support functions * This is functionally comparable to ReadBuffer followed by
* LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE): you get back a pinned
* and locked buffer. (The lock is not really necessary, since we
* expect that this is only done during single-process XLOG replay,
* but in some places it simplifies sharing code with the non-XLOG case.)
* *
* If "init" is true then the caller intends to rewrite the page fully
* using the info in the XLOG record. In this case we will extend the
* relation if needed to make the page exist, and we will not complain about
* the page being "new" (all zeroes).
*
* If "init" is false then the caller needs the page to be valid already.
* If the page doesn't exist or contains zeroes, we report failure.
*
* If the return value is InvalidBuffer (only possible when init = false),
* the caller should silently skip the update on this page. This currently
* never happens, but we retain it as part of the API spec for possible future
* use.
*/ */
Buffer Buffer
XLogReadBuffer(bool extend, Relation reln, BlockNumber blkno) XLogReadBuffer(Relation reln, BlockNumber blkno, bool init)
{ {
BlockNumber lastblock = RelationGetNumberOfBlocks(reln); BlockNumber lastblock = RelationGetNumberOfBlocks(reln);
Buffer buffer; Buffer buffer;
if (blkno >= lastblock) Assert(blkno != P_NEW);
if (blkno < lastblock)
{ {
/* page exists in file */
buffer = ReadBuffer(reln, blkno);
}
else
{
/* hm, page doesn't exist in file */
if (!init)
elog(PANIC, "block %u of relation %u/%u/%u does not exist",
blkno, reln->rd_node.spcNode,
reln->rd_node.dbNode, reln->rd_node.relNode);
/* OK to extend the file */
/* we do this in recovery only - no rel-extension lock needed */
Assert(InRecovery);
buffer = InvalidBuffer; buffer = InvalidBuffer;
if (extend) /* we do this in recovery only - no locks */ while (blkno >= lastblock)
{ {
Assert(InRecovery); if (buffer != InvalidBuffer)
while (lastblock <= blkno) ReleaseBuffer(buffer); /* must be WriteBuffer()? */
{ buffer = ReadBuffer(reln, P_NEW);
if (buffer != InvalidBuffer) lastblock++;
ReleaseBuffer(buffer); /* must be WriteBuffer()? */
buffer = ReadBuffer(reln, P_NEW);
lastblock++;
}
} }
if (buffer != InvalidBuffer) Assert(BufferGetBlockNumber(buffer) == blkno);
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); }
return buffer;
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
if (!init)
{
/* check that page has been initialized */
Page page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page))
elog(PANIC, "block %u of relation %u/%u/%u is uninitialized",
blkno, reln->rd_node.spcNode,
reln->rd_node.dbNode, reln->rd_node.relNode);
} }
buffer = ReadBuffer(reln, blkno);
if (buffer != InvalidBuffer)
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
return buffer; return buffer;
} }
...@@ -184,6 +221,9 @@ XLogCloseRelationCache(void) ...@@ -184,6 +221,9 @@ XLogCloseRelationCache(void)
/* /*
* Open a relation during XLOG replay * Open a relation during XLOG replay
*
* Note: this once had an API that allowed NULL return on failure, but it
* no longer does; any failure results in elog().
*/ */
Relation Relation
XLogOpenRelation(RelFileNode rnode) XLogOpenRelation(RelFileNode rnode)
...@@ -224,7 +264,7 @@ XLogOpenRelation(RelFileNode rnode) ...@@ -224,7 +264,7 @@ XLogOpenRelation(RelFileNode rnode)
hash_search(_xlrelcache, (void *) &rnode, HASH_ENTER, &found); hash_search(_xlrelcache, (void *) &rnode, HASH_ENTER, &found);
if (found) if (found)
elog(PANIC, "XLogOpenRelation: file found on insert into cache"); elog(PANIC, "xlog relation already present on insert into cache");
hentry->rdesc = res; hentry->rdesc = res;
...@@ -253,7 +293,7 @@ XLogOpenRelation(RelFileNode rnode) ...@@ -253,7 +293,7 @@ XLogOpenRelation(RelFileNode rnode)
} }
/* /*
* Close a relation during XLOG replay * Drop a relation during XLOG replay
* *
* This is called when the relation is about to be deleted; we need to ensure * This is called when the relation is about to be deleted; we need to ensure
* that there is no dangling smgr reference in the xlog relation cache. * that there is no dangling smgr reference in the xlog relation cache.
...@@ -262,7 +302,7 @@ XLogOpenRelation(RelFileNode rnode) ...@@ -262,7 +302,7 @@ XLogOpenRelation(RelFileNode rnode)
* cache, we just let it age out normally. * cache, we just let it age out normally.
*/ */
void void
XLogCloseRelation(RelFileNode rnode) XLogDropRelation(RelFileNode rnode)
{ {
XLogRelDesc *rdesc; XLogRelDesc *rdesc;
XLogRelCacheEntry *hentry; XLogRelCacheEntry *hentry;
...@@ -277,3 +317,25 @@ XLogCloseRelation(RelFileNode rnode) ...@@ -277,3 +317,25 @@ XLogCloseRelation(RelFileNode rnode)
RelationCloseSmgr(&(rdesc->reldata)); RelationCloseSmgr(&(rdesc->reldata));
} }
/*
* Drop a whole database during XLOG replay
*
* As above, but for DROP DATABASE instead of dropping a single rel
*/
void
XLogDropDatabase(Oid dbid)
{
HASH_SEQ_STATUS status;
XLogRelCacheEntry *hentry;
hash_seq_init(&status, _xlrelcache);
while ((hentry = (XLogRelCacheEntry *) hash_seq_search(&status)) != NULL)
{
XLogRelDesc *rdesc = hentry->rdesc;
if (hentry->rnode.dbNode == dbid)
RelationCloseSmgr(&(rdesc->reldata));
}
}
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.178 2006/03/24 04:32:13 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.179 2006/03/29 21:17:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -671,7 +671,7 @@ dropdb(const char *dbname, bool missing_ok) ...@@ -671,7 +671,7 @@ dropdb(const char *dbname, bool missing_ok)
* is important to ensure that no remaining backend tries to write out a * is important to ensure that no remaining backend tries to write out a
* dirty buffer to the dead database later... * dirty buffer to the dead database later...
*/ */
DropBuffers(db_id); DropDatabaseBuffers(db_id);
/* /*
* Also, clean out any entries in the shared free space map. * Also, clean out any entries in the shared free space map.
...@@ -1377,11 +1377,16 @@ dbase_redo(XLogRecPtr lsn, XLogRecord *record) ...@@ -1377,11 +1377,16 @@ dbase_redo(XLogRecPtr lsn, XLogRecord *record)
dst_path = GetDatabasePath(xlrec->db_id, xlrec->tablespace_id); dst_path = GetDatabasePath(xlrec->db_id, xlrec->tablespace_id);
/* /* Drop pages for this database that are in the shared buffer cache */
* Drop pages for this database that are in the shared buffer cache DropDatabaseBuffers(xlrec->db_id);
*/
DropBuffers(xlrec->db_id); /* Also, clean out any entries in the shared free space map */
FreeSpaceMapForgetDatabase(xlrec->db_id);
/* Clean out the xlog relcache too */
XLogDropDatabase(xlrec->db_id);
/* And remove the physical files */
if (!rmtree(dst_path, true)) if (!rmtree(dst_path, true))
ereport(WARNING, ereport(WARNING,
(errmsg("could not remove database directory \"%s\"", (errmsg("could not remove database directory \"%s\"",
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.130 2006/03/24 04:32:13 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.131 2006/03/29 21:17:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1140,14 +1140,8 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record) ...@@ -1140,14 +1140,8 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record)
elog(PANIC, "seq_redo: unknown op code %u", info); elog(PANIC, "seq_redo: unknown op code %u", info);
reln = XLogOpenRelation(xlrec->node); reln = XLogOpenRelation(xlrec->node);
if (!RelationIsValid(reln)) buffer = XLogReadBuffer(reln, 0, true);
return; Assert(BufferIsValid(buffer));
buffer = XLogReadBuffer(true, reln, 0);
if (!BufferIsValid(buffer))
elog(PANIC, "seq_redo: can't read block 0 of rel %u/%u/%u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
/* Always reinit the page and reinstall the magic number */ /* Always reinit the page and reinstall the magic number */
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.33 2006/03/29 15:15:43 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.34 2006/03/29 21:17:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -467,6 +467,12 @@ DropTableSpace(DropTableSpaceStmt *stmt) ...@@ -467,6 +467,12 @@ DropTableSpace(DropTableSpaceStmt *stmt)
(void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_DROP, rdata); (void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_DROP, rdata);
} }
/*
* Note: because we checked that the tablespace was empty, there should
* be no need to worry about flushing shared buffers or free space map
* entries for relations in the tablespace.
*/
/* /*
* Allow TablespaceCreateDbspace again. * Allow TablespaceCreateDbspace again.
*/ */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.204 2006/03/05 15:58:36 momjian Exp $ * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.205 2006/03/29 21:17:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1450,7 +1450,7 @@ DropRelFileNodeBuffers(RelFileNode rnode, bool istemp, ...@@ -1450,7 +1450,7 @@ DropRelFileNodeBuffers(RelFileNode rnode, bool istemp,
} }
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* DropBuffers * DropDatabaseBuffers
* *
* This function removes all the buffers in the buffer cache for a * This function removes all the buffers in the buffer cache for a
* particular database. Dirty pages are simply dropped, without * particular database. Dirty pages are simply dropped, without
...@@ -1461,7 +1461,7 @@ DropRelFileNodeBuffers(RelFileNode rnode, bool istemp, ...@@ -1461,7 +1461,7 @@ DropRelFileNodeBuffers(RelFileNode rnode, bool istemp,
* -------------------------------------------------------------------- * --------------------------------------------------------------------
*/ */
void void
DropBuffers(Oid dbid) DropDatabaseBuffers(Oid dbid)
{ {
int i; int i;
volatile BufferDesc *bufHdr; volatile BufferDesc *bufHdr;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.161 2006/03/05 15:58:46 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.162 2006/03/29 21:17:39 tgl Exp $
* *
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
...@@ -166,7 +166,7 @@ ReverifyMyDatabase(const char *name) ...@@ -166,7 +166,7 @@ ReverifyMyDatabase(const char *name)
* other backend will eventually try to write them and die in * other backend will eventually try to write them and die in
* mdblindwrt. Flush any such pages to forestall trouble. * mdblindwrt. Flush any such pages to forestall trouble.
*/ */
DropBuffers(MyDatabaseId); DropDatabaseBuffers(MyDatabaseId);
/* Now I can commit hara-kiri with a clear conscience... */ /* Now I can commit hara-kiri with a clear conscience... */
ereport(FATAL, ereport(FATAL,
(errcode(ERRCODE_UNDEFINED_DATABASE), (errcode(ERRCODE_UNDEFINED_DATABASE),
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/xlogutils.h,v 1.19 2006/03/05 15:58:54 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/xlogutils.h,v 1.20 2006/03/29 21:17:39 tgl Exp $
*/ */
#ifndef XLOG_UTILS_H #ifndef XLOG_UTILS_H
#define XLOG_UTILS_H #define XLOG_UTILS_H
...@@ -19,8 +19,9 @@ extern void XLogInitRelationCache(void); ...@@ -19,8 +19,9 @@ extern void XLogInitRelationCache(void);
extern void XLogCloseRelationCache(void); extern void XLogCloseRelationCache(void);
extern Relation XLogOpenRelation(RelFileNode rnode); extern Relation XLogOpenRelation(RelFileNode rnode);
extern void XLogCloseRelation(RelFileNode rnode); extern void XLogDropRelation(RelFileNode rnode);
extern void XLogDropDatabase(Oid dbid);
extern Buffer XLogReadBuffer(bool extend, Relation reln, BlockNumber blkno); extern Buffer XLogReadBuffer(Relation reln, BlockNumber blkno, bool init);
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.98 2006/03/05 15:58:59 momjian Exp $ * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.99 2006/03/29 21:17:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -135,7 +135,7 @@ extern void RelationTruncate(Relation rel, BlockNumber nblocks); ...@@ -135,7 +135,7 @@ extern void RelationTruncate(Relation rel, BlockNumber nblocks);
extern void FlushRelationBuffers(Relation rel); extern void FlushRelationBuffers(Relation rel);
extern void DropRelFileNodeBuffers(RelFileNode rnode, bool istemp, extern void DropRelFileNodeBuffers(RelFileNode rnode, bool istemp,
BlockNumber firstDelBlock); BlockNumber firstDelBlock);
extern void DropBuffers(Oid dbid); extern void DropDatabaseBuffers(Oid dbid);
#ifdef NOT_USED #ifdef NOT_USED
extern void PrintPinnedBufs(void); extern void PrintPinnedBufs(void);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册