diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c index 7a581334f1466a767950ff7e3a2c18047cdb5d9d..75997d9534b4e03558a21e9f1a9fd6534fa5cf81 100644 --- a/src/backend/access/gin/ginxlog.c +++ b/src/backend/access/gin/ginxlog.c @@ -77,11 +77,13 @@ ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) MetaBuffer = XLogReadBuffer(*node, GIN_METAPAGE_BLKNO, true); Assert(BufferIsValid(MetaBuffer)); + page = (Page) BufferGetPage(MetaBuffer); + GinInitMetabuffer(MetaBuffer); - page = (Page) BufferGetPage(MetaBuffer); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); + MarkBufferDirty(MetaBuffer); RootBuffer = XLogReadBuffer(*node, GIN_ROOT_BLKNO, true); Assert(BufferIsValid(RootBuffer)); @@ -91,11 +93,10 @@ ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); - - MarkBufferDirty(MetaBuffer); - UnlockReleaseBuffer(MetaBuffer); MarkBufferDirty(RootBuffer); + UnlockReleaseBuffer(RootBuffer); + UnlockReleaseBuffer(MetaBuffer); } static void @@ -128,21 +129,49 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) Buffer buffer; Page page; + /* first, forget any incomplete split this insertion completes */ + if (data->isData) + { + Assert(data->isDelete == FALSE); + if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber) + { + PostingItem *pitem; + + pitem = (PostingItem *) (XLogRecGetData(record) + sizeof(ginxlogInsert)); + forgetIncompleteSplit(data->node, + PostingItemGetBlockNumber(pitem), + data->updateBlkno); + } + + } + else + { + if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber) + { + IndexTuple itup; + + itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsert)); + forgetIncompleteSplit(data->node, + GinItemPointerGetBlockNumber(&itup->t_tid), + data->updateBlkno); + } + } + /* nothing else to do if page was backed up */ if (record->xl_info & XLR_BKP_BLOCK_1) return; buffer = XLogReadBuffer(data->node, data->blkno, false); - Assert(BufferIsValid(buffer)); + if (!BufferIsValid(buffer)) + return; /* page was deleted, nothing to do */ page = (Page) BufferGetPage(buffer); - if (data->isData) + if (!XLByteLE(lsn, PageGetLSN(page))) { - Assert(data->isDelete == FALSE); - Assert(GinPageIsData(page)); - - if (!XLByteLE(lsn, PageGetLSN(page))) + if (data->isData) { + Assert(GinPageIsData(page)); + if (data->isLeaf) { OffsetNumber i; @@ -172,23 +201,12 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) GinDataPageAddItem(page, pitem, data->offset); } } - - if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber) + else { - PostingItem *pitem = (PostingItem *) (XLogRecGetData(record) + sizeof(ginxlogInsert)); + IndexTuple itup; - forgetIncompleteSplit(data->node, PostingItemGetBlockNumber(pitem), data->updateBlkno); - } + Assert(!GinPageIsData(page)); - } - else - { - IndexTuple itup; - - Assert(!GinPageIsData(page)); - - if (!XLByteLE(lsn, PageGetLSN(page))) - { if (data->updateBlkno != InvalidBlockNumber) { /* update link to right page after split */ @@ -212,20 +230,12 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) data->node.spcNode, data->node.dbNode, data->node.relNode); } - if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber) - { - itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsert)); - forgetIncompleteSplit(data->node, GinItemPointerGetBlockNumber(&itup->t_tid), data->updateBlkno); - } - } - - if (!XLByteLE(lsn, PageGetLSN(page))) - { PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); } + UnlockReleaseBuffer(buffer); } @@ -244,7 +254,7 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) if (data->isData) flags |= GIN_DATA; - lbuffer = XLogReadBuffer(data->node, data->lblkno, data->isRootSplit); + lbuffer = XLogReadBuffer(data->node, data->lblkno, true); Assert(BufferIsValid(lbuffer)); lpage = (Page) BufferGetPage(lbuffer); GinInitBuffer(lbuffer, flags); @@ -321,7 +331,7 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) if (data->isRootSplit) { - Buffer rootBuf = XLogReadBuffer(data->node, data->rootBlkno, false); + Buffer rootBuf = XLogReadBuffer(data->node, data->rootBlkno, true); Page rootPage = BufferGetPage(rootBuf); GinInitBuffer(rootBuf, flags & ~GIN_LEAF); @@ -357,45 +367,49 @@ ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) Buffer buffer; Page page; - /* nothing else to do if page was backed up (and no info to do it with) */ + /* nothing to do if page was backed up (and no info to do it with) */ if (record->xl_info & XLR_BKP_BLOCK_1) return; buffer = XLogReadBuffer(data->node, data->blkno, false); - Assert(BufferIsValid(buffer)); + if (!BufferIsValid(buffer)) + return; page = (Page) BufferGetPage(buffer); - if (GinPageIsData(page)) - { - memcpy(GinDataPageGetData(page), XLogRecGetData(record) + sizeof(ginxlogVacuumPage), - GinSizeOfItem(page) *data->nitem); - GinPageGetOpaque(page)->maxoff = data->nitem; - } - else + if (!XLByteLE(lsn, PageGetLSN(page))) { - OffsetNumber i, - *tod; - IndexTuple itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogVacuumPage)); + if (GinPageIsData(page)) + { + memcpy(GinDataPageGetData(page), XLogRecGetData(record) + sizeof(ginxlogVacuumPage), + GinSizeOfItem(page) *data->nitem); + GinPageGetOpaque(page)->maxoff = data->nitem; + } + else + { + OffsetNumber i, + *tod; + IndexTuple itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogVacuumPage)); - tod = (OffsetNumber *) palloc(sizeof(OffsetNumber) * PageGetMaxOffsetNumber(page)); - for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i++) - tod[i - 1] = i; + tod = (OffsetNumber *) palloc(sizeof(OffsetNumber) * PageGetMaxOffsetNumber(page)); + for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i++) + tod[i - 1] = i; - PageIndexMultiDelete(page, tod, PageGetMaxOffsetNumber(page)); + PageIndexMultiDelete(page, tod, PageGetMaxOffsetNumber(page)); - for (i = 0; i < data->nitem; i++) - { - if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber) - elog(ERROR, "failed to add item to index page in %u/%u/%u", - data->node.spcNode, data->node.dbNode, data->node.relNode); - itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup))); + for (i = 0; i < data->nitem; i++) + { + if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber) + elog(ERROR, "failed to add item to index page in %u/%u/%u", + data->node.spcNode, data->node.dbNode, data->node.relNode); + itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup))); + } } - } - PageSetLSN(page, lsn); - PageSetTLI(page, ThisTimeLineID); + PageSetLSN(page, lsn); + PageSetTLI(page, ThisTimeLineID); + MarkBufferDirty(buffer); + } - MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); } @@ -409,38 +423,56 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) if (!(record->xl_info & XLR_BKP_BLOCK_1)) { buffer = XLogReadBuffer(data->node, data->blkno, false); - page = BufferGetPage(buffer); - Assert(GinPageIsData(page)); - GinPageGetOpaque(page)->flags = GIN_DELETED; - PageSetLSN(page, lsn); - PageSetTLI(page, ThisTimeLineID); - MarkBufferDirty(buffer); - UnlockReleaseBuffer(buffer); + if (BufferIsValid(buffer)) + { + page = BufferGetPage(buffer); + if (!XLByteLE(lsn, PageGetLSN(page))) + { + Assert(GinPageIsData(page)); + GinPageGetOpaque(page)->flags = GIN_DELETED; + PageSetLSN(page, lsn); + PageSetTLI(page, ThisTimeLineID); + MarkBufferDirty(buffer); + } + UnlockReleaseBuffer(buffer); + } } if (!(record->xl_info & XLR_BKP_BLOCK_2)) { buffer = XLogReadBuffer(data->node, data->parentBlkno, false); - page = BufferGetPage(buffer); - Assert(GinPageIsData(page)); - Assert(!GinPageIsLeaf(page)); - PageDeletePostingItem(page, data->parentOffset); - PageSetLSN(page, lsn); - PageSetTLI(page, ThisTimeLineID); - MarkBufferDirty(buffer); - UnlockReleaseBuffer(buffer); + if (BufferIsValid(buffer)) + { + page = BufferGetPage(buffer); + if (!XLByteLE(lsn, PageGetLSN(page))) + { + Assert(GinPageIsData(page)); + Assert(!GinPageIsLeaf(page)); + PageDeletePostingItem(page, data->parentOffset); + PageSetLSN(page, lsn); + PageSetTLI(page, ThisTimeLineID); + MarkBufferDirty(buffer); + } + UnlockReleaseBuffer(buffer); + } } if (!(record->xl_info & XLR_BKP_BLOCK_3) && data->leftBlkno != InvalidBlockNumber) { buffer = XLogReadBuffer(data->node, data->leftBlkno, false); - page = BufferGetPage(buffer); - Assert(GinPageIsData(page)); - GinPageGetOpaque(page)->rightlink = data->rightLink; - PageSetLSN(page, lsn); - PageSetTLI(page, ThisTimeLineID); - MarkBufferDirty(buffer); - UnlockReleaseBuffer(buffer); + if (BufferIsValid(buffer)) + { + page = BufferGetPage(buffer); + if (!XLByteLE(lsn, PageGetLSN(page))) + { + Assert(GinPageIsData(page)); + GinPageGetOpaque(page)->rightlink = data->rightLink; + PageSetLSN(page, lsn); + PageSetTLI(page, ThisTimeLineID); + MarkBufferDirty(buffer); + } + UnlockReleaseBuffer(buffer); + } } } @@ -450,8 +482,11 @@ ginRedoUpdateMetapage(XLogRecPtr lsn, XLogRecord *record) ginxlogUpdateMeta *data = (ginxlogUpdateMeta *) XLogRecGetData(record); Buffer metabuffer; Page metapage; + Buffer buffer; metabuffer = XLogReadBuffer(data->node, GIN_METAPAGE_BLKNO, false); + if (!BufferIsValid(metabuffer)) + elog(PANIC, "GIN metapage disappeared"); metapage = BufferGetPage(metabuffer); if (!XLByteLE(lsn, PageGetLSN(metapage))) @@ -469,40 +504,43 @@ ginRedoUpdateMetapage(XLogRecPtr lsn, XLogRecord *record) */ if (!(record->xl_info & XLR_BKP_BLOCK_1)) { - Buffer buffer = XLogReadBuffer(data->node, data->metadata.tail, false); - Page page = BufferGetPage(buffer); - - if (!XLByteLE(lsn, PageGetLSN(page))) + buffer = XLogReadBuffer(data->node, data->metadata.tail, false); + if (BufferIsValid(buffer)) { - OffsetNumber l, - off = (PageIsEmpty(page)) ? FirstOffsetNumber : - OffsetNumberNext(PageGetMaxOffsetNumber(page)); - int i, - tupsize; - IndexTuple tuples = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogUpdateMeta)); - - for (i = 0; i < data->ntuples; i++) + Page page = BufferGetPage(buffer); + + if (!XLByteLE(lsn, PageGetLSN(page))) { - tupsize = IndexTupleSize(tuples); + OffsetNumber l, + off = (PageIsEmpty(page)) ? FirstOffsetNumber : + OffsetNumberNext(PageGetMaxOffsetNumber(page)); + int i, + tupsize; + IndexTuple tuples = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogUpdateMeta)); - l = PageAddItem(page, (Item) tuples, tupsize, off, false, false); + for (i = 0; i < data->ntuples; i++) + { + tupsize = IndexTupleSize(tuples); - if (l == InvalidOffsetNumber) - elog(ERROR, "failed to add item to index page"); + l = PageAddItem(page, (Item) tuples, tupsize, off, false, false); - tuples = (IndexTuple) (((char *) tuples) + tupsize); - } + if (l == InvalidOffsetNumber) + elog(ERROR, "failed to add item to index page"); - /* - * Increase counter of heap tuples - */ - GinPageGetOpaque(page)->maxoff++; + tuples = (IndexTuple) (((char *) tuples) + tupsize); + } - PageSetLSN(page, lsn); - PageSetTLI(page, ThisTimeLineID); - MarkBufferDirty(buffer); + /* + * Increase counter of heap tuples + */ + GinPageGetOpaque(page)->maxoff++; + + PageSetLSN(page, lsn); + PageSetTLI(page, ThisTimeLineID); + MarkBufferDirty(buffer); + } + UnlockReleaseBuffer(buffer); } - UnlockReleaseBuffer(buffer); } } else if (data->prevTail != InvalidBlockNumber) @@ -510,19 +548,21 @@ ginRedoUpdateMetapage(XLogRecPtr lsn, XLogRecord *record) /* * New tail */ - - Buffer buffer = XLogReadBuffer(data->node, data->prevTail, false); - Page page = BufferGetPage(buffer); - - if (!XLByteLE(lsn, PageGetLSN(page))) + buffer = XLogReadBuffer(data->node, data->prevTail, false); + if (BufferIsValid(buffer)) { - GinPageGetOpaque(page)->rightlink = data->newRightlink; + Page page = BufferGetPage(buffer); - PageSetLSN(page, lsn); - PageSetTLI(page, ThisTimeLineID); - MarkBufferDirty(buffer); + if (!XLByteLE(lsn, PageGetLSN(page))) + { + GinPageGetOpaque(page)->rightlink = data->newRightlink; + + PageSetLSN(page, lsn); + PageSetTLI(page, ThisTimeLineID); + MarkBufferDirty(buffer); + } + UnlockReleaseBuffer(buffer); } - UnlockReleaseBuffer(buffer); } UnlockReleaseBuffer(metabuffer); @@ -544,6 +584,7 @@ ginRedoInsertListPage(XLogRecPtr lsn, XLogRecord *record) return; buffer = XLogReadBuffer(data->node, data->blkno, true); + Assert(BufferIsValid(buffer)); page = BufferGetPage(buffer); GinInitBuffer(buffer, GIN_LIST); @@ -587,6 +628,8 @@ ginRedoDeleteListPages(XLogRecPtr lsn, XLogRecord *record) int i; metabuffer = XLogReadBuffer(data->node, GIN_METAPAGE_BLKNO, false); + if (!BufferIsValid(metabuffer)) + elog(PANIC, "GIN metapage disappeared"); metapage = BufferGetPage(metabuffer); if (!XLByteLE(lsn, PageGetLSN(metapage))) @@ -600,18 +643,22 @@ ginRedoDeleteListPages(XLogRecPtr lsn, XLogRecord *record) for (i = 0; i < data->ndeleted; i++) { Buffer buffer = XLogReadBuffer(data->node, data->toDelete[i], false); - Page page = BufferGetPage(buffer); - if (!XLByteLE(lsn, PageGetLSN(page))) + if (BufferIsValid(buffer)) { - GinPageGetOpaque(page)->flags = GIN_DELETED; + Page page = BufferGetPage(buffer); - PageSetLSN(page, lsn); - PageSetTLI(page, ThisTimeLineID); - MarkBufferDirty(buffer); - } + if (!XLByteLE(lsn, PageGetLSN(page))) + { + GinPageGetOpaque(page)->flags = GIN_DELETED; - UnlockReleaseBuffer(buffer); + PageSetLSN(page, lsn); + PageSetTLI(page, ThisTimeLineID); + MarkBufferDirty(buffer); + } + + UnlockReleaseBuffer(buffer); + } } UnlockReleaseBuffer(metabuffer); } @@ -755,6 +802,13 @@ ginContinueSplit(ginIncompleteSplit *split) */ buffer = XLogReadBuffer(split->node, split->leftBlkno, false); + /* + * Failure should be impossible here, because we wrote the page earlier. + */ + if (!BufferIsValid(buffer)) + elog(PANIC, "ginContinueSplit: left block %u not found", + split->leftBlkno); + reln = CreateFakeRelcacheEntry(split->node); if (split->rootBlkno == GIN_ROOT_BLKNO)