static void ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) { RelFileNode *node = (RelFileNode *) XLogRecGetData(record); Buffer RootBuffer, MetaBuffer; Page page; /* Backup blocks are not used in create_index records */ Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK)); MetaBuffer = XLogReadBuffer(*node, GIN_METAPAGE_BLKNO, true); Assert(BufferIsValid(MetaBuffer)); page = (Page) BufferGetPage(MetaBuffer); GinInitMetabuffer(MetaBuffer); PageSetLSN(page, lsn); MarkBufferDirty(MetaBuffer); RootBuffer = XLogReadBuffer(*node, GIN_ROOT_BLKNO, true); Assert(BufferIsValid(RootBuffer)); page = (Page) BufferGetPage(RootBuffer); GinInitBuffer(RootBuffer, GIN_LEAF); PageSetLSN(page, lsn); MarkBufferDirty(RootBuffer); UnlockReleaseBuffer(RootBuffer); UnlockReleaseBuffer(MetaBuffer); }
static void spgRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) { RelFileNode *node = (RelFileNode *) XLogRecGetData(record); Buffer buffer; Page page; /* Backup blocks are not used in create_index records */ Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK)); buffer = XLogReadBuffer(*node, SPGIST_METAPAGE_BLKNO, true); Assert(BufferIsValid(buffer)); page = (Page) BufferGetPage(buffer); SpGistInitMetapage(page); PageSetLSN(page, lsn); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); buffer = XLogReadBuffer(*node, SPGIST_ROOT_BLKNO, true); Assert(BufferIsValid(buffer)); SpGistInitBuffer(buffer, SPGIST_LEAF); page = (Page) BufferGetPage(buffer); PageSetLSN(page, lsn); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); buffer = XLogReadBuffer(*node, SPGIST_NULL_BLKNO, true); Assert(BufferIsValid(buffer)); SpGistInitBuffer(buffer, SPGIST_LEAF | SPGIST_NULLS); page = (Page) BufferGetPage(buffer); PageSetLSN(page, lsn); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); }
static void spgRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) { RelFileNode *node = (RelFileNode *) XLogRecGetData(record); Buffer buffer; Page page; buffer = XLogReadBuffer(*node, SPGIST_METAPAGE_BLKNO, true); Assert(BufferIsValid(buffer)); page = (Page) BufferGetPage(buffer); SpGistInitMetapage(page); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); buffer = XLogReadBuffer(*node, SPGIST_HEAD_BLKNO, true); Assert(BufferIsValid(buffer)); SpGistInitBuffer(buffer, SPGIST_LEAF); page = (Page) BufferGetPage(buffer); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); }
static void ginRedoDeleteListPages(XLogRecPtr lsn, XLogRecord *record) { ginxlogDeleteListPages *data = (ginxlogDeleteListPages *) XLogRecGetData(record); Buffer metabuffer; Page metapage; int i; /* Backup blocks are not used in delete_listpage records */ Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK)); metabuffer = XLogReadBuffer(data->node, GIN_METAPAGE_BLKNO, false); if (!BufferIsValid(metabuffer)) return; /* assume index was deleted, nothing to do */ metapage = BufferGetPage(metabuffer); memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData)); PageSetLSN(metapage, lsn); MarkBufferDirty(metabuffer); /* * In normal operation, shiftList() takes exclusive lock on all the * pages-to-be-deleted simultaneously. During replay, however, it should * be all right to lock them one at a time. This is dependent on the fact * that we are deleting pages from the head of the list, and that readers * share-lock the next page before releasing the one they are on. So we * cannot get past a reader that is on, or due to visit, any page we are * going to delete. New incoming readers will block behind our metapage * lock and then see a fully updated page list. */ for (i = 0; i < data->ndeleted; i++) { Buffer buffer = XLogReadBuffer(data->node, data->toDelete[i], false); if (BufferIsValid(buffer)) { Page page = BufferGetPage(buffer); if (lsn > PageGetLSN(page)) { GinPageGetOpaque(page)->flags = GIN_DELETED; PageSetLSN(page, lsn); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } UnlockReleaseBuffer(metabuffer); }
/* * Replay the clearing of F_FOLLOW_RIGHT flag. */ static void gistRedoClearFollowRight(RelFileNode node, XLogRecPtr lsn, BlockNumber leftblkno) { Buffer buffer; buffer = XLogReadBuffer(node, leftblkno, false); if (BufferIsValid(buffer)) { Page page = (Page) BufferGetPage(buffer); /* * Note that we still update the page even if page LSN is equal to the * LSN of this record, because the updated NSN is not included in the * full page image. */ if (!XLByteLT(lsn, PageGetLSN(page))) { GistPageGetOpaque(page)->nsn = lsn; GistClearFollowRight(page); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } }
static void spgRedoVacuumRoot(XLogRecPtr lsn, XLogRecord *record) { char *ptr = XLogRecGetData(record); spgxlogVacuumRoot *xldata = (spgxlogVacuumRoot *) ptr; OffsetNumber *toDelete; Buffer buffer; Page page; ptr += sizeof(spgxlogVacuumRoot); toDelete = (OffsetNumber *) ptr; if (!(record->xl_info & XLR_BKP_BLOCK_1)) { buffer = XLogReadBuffer(xldata->node, SPGIST_HEAD_BLKNO, false); if (BufferIsValid(buffer)) { page = BufferGetPage(buffer); if (!XLByteLE(lsn, PageGetLSN(page))) { /* The tuple numbers are in order */ PageIndexMultiDelete(page, toDelete, xldata->nDelete); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } }
static void ginRedoVacuumDataLeafPage(XLogRecPtr lsn, XLogRecord *record) { ginxlogVacuumDataLeafPage *xlrec = (ginxlogVacuumDataLeafPage *) XLogRecGetData(record); Buffer buffer; Page page; /* If we have a full-page image, restore it and we're done */ if (record->xl_info & XLR_BKP_BLOCK(0)) { (void) RestoreBackupBlock(lsn, record, 0, false, false); return; } buffer = XLogReadBuffer(xlrec->node, xlrec->blkno, false); if (!BufferIsValid(buffer)) return; page = (Page) BufferGetPage(buffer); Assert(GinPageIsLeaf(page)); Assert(GinPageIsData(page)); if (lsn > PageGetLSN(page)) { ginRedoRecompress(page, &xlrec->data); PageSetLSN(page, lsn); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); }
static void ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record) { ginxlogCreatePostingTree *data = (ginxlogCreatePostingTree *) XLogRecGetData(record); char *ptr; Buffer buffer; Page page; /* Backup blocks are not used in create_ptree records */ Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK)); buffer = XLogReadBuffer(data->node, data->blkno, true); Assert(BufferIsValid(buffer)); page = (Page) BufferGetPage(buffer); GinInitBuffer(buffer, GIN_DATA | GIN_LEAF | GIN_COMPRESSED); ptr = XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree); /* Place page data */ memcpy(GinDataLeafPageGetPostingList(page), ptr, data->size); GinDataPageSetDataSize(page, data->size); PageSetLSN(page, lsn); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); }
/* * Replay the clearing of F_FOLLOW_RIGHT flag on a child page. * * Even if the WAL record includes a full-page image, we have to update the * follow-right flag, because that change is not included in the full-page * image. To be sure that the intermediate state with the wrong flag value is * not visible to concurrent Hot Standby queries, this function handles * restoring the full-page image as well as updating the flag. (Note that * we never need to do anything else to the child page in the current WAL * action.) */ static void gistRedoClearFollowRight(XLogRecPtr lsn, XLogRecord *record, int block_index, RelFileNode node, BlockNumber childblkno) { Buffer buffer; Page page; if (record->xl_info & XLR_BKP_BLOCK(block_index)) buffer = RestoreBackupBlock(lsn, record, block_index, false, true); else { buffer = XLogReadBuffer(node, childblkno, false); if (!BufferIsValid(buffer)) return; /* page was deleted, nothing to do */ } page = (Page) BufferGetPage(buffer); /* * Note that we still update the page even if page LSN is equal to the LSN * of this record, because the updated NSN is not included in the full * page image. */ if (lsn >= PageGetLSN(page)) { GistPageSetNSN(page, lsn); GistClearFollowRight(page); PageSetLSN(page, lsn); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); }
static void forget_matching_split(Relation reln, RelFileNode node, BlockNumber insertblk, OffsetNumber offnum, bool is_root) { Buffer buffer; Page page; BTItem btitem; BlockNumber rightblk; List *l; /* Get downlink TID from page */ buffer = XLogReadBuffer(false, reln, insertblk); if (!BufferIsValid(buffer)) elog(PANIC, "forget_matching_split: block unfound"); page = (Page) BufferGetPage(buffer); btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum)); rightblk = ItemPointerGetBlockNumber(&(btitem->bti_itup.t_tid)); Assert(ItemPointerGetOffsetNumber(&(btitem->bti_itup.t_tid)) == P_HIKEY); UnlockAndReleaseBuffer(buffer); foreach(l, incomplete_splits) { bt_incomplete_split *split = (bt_incomplete_split *) lfirst(l); if (RelFileNodeEquals(node, split->node) && rightblk == split->rightblk) { if (is_root != split->is_root) elog(LOG, "forget_matching_split: fishy is_root data"); incomplete_splits = lremove(split, incomplete_splits); break; /* need not look further */ } }
static void ginRedoInsertListPage(XLogRecPtr lsn, XLogRecord *record) { ginxlogInsertListPage *data = (ginxlogInsertListPage *) XLogRecGetData(record); Buffer buffer; Page page; OffsetNumber l, off = FirstOffsetNumber; int i, tupsize; IndexTuple tuples = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsertListPage)); /* If we have a full-page image, restore it and we're done */ if (record->xl_info & XLR_BKP_BLOCK(0)) { (void) RestoreBackupBlock(lsn, record, 0, false, false); return; } buffer = XLogReadBuffer(data->node, data->blkno, true); Assert(BufferIsValid(buffer)); page = BufferGetPage(buffer); GinInitBuffer(buffer, GIN_LIST); GinPageGetOpaque(page)->rightlink = data->rightlink; if (data->rightlink == InvalidBlockNumber) { /* tail of sublist */ GinPageSetFullRow(page); GinPageGetOpaque(page)->maxoff = 1; } else { GinPageGetOpaque(page)->maxoff = 0; } for (i = 0; i < data->ntuples; i++) { tupsize = IndexTupleSize(tuples); l = PageAddItem(page, (Item) tuples, tupsize, off, false, false); if (l == InvalidOffsetNumber) elog(ERROR, "failed to add item to index page"); tuples = (IndexTuple) (((char *) tuples) + tupsize); } PageSetLSN(page, lsn); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); }
static void ginRedoInsertListPage(XLogRecPtr lsn, XLogRecord *record) { ginxlogInsertListPage *data = (ginxlogInsertListPage *) XLogRecGetData(record); Buffer buffer; Page page; OffsetNumber l, off = FirstOffsetNumber; int i, tupsize; IndexTuple tuples = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsertListPage)); /* * Backup blocks are not used, we always re-initialize the page. */ Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK)); buffer = XLogReadBuffer(data->node, data->blkno, true); Assert(BufferIsValid(buffer)); page = BufferGetPage(buffer); GinInitBuffer(buffer, GIN_LIST); GinPageGetOpaque(page)->rightlink = data->rightlink; if (data->rightlink == InvalidBlockNumber) { /* tail of sublist */ GinPageSetFullRow(page); GinPageGetOpaque(page)->maxoff = 1; } else { GinPageGetOpaque(page)->maxoff = 0; } for (i = 0; i < data->ntuples; i++) { tupsize = IndexTupleSize(tuples); l = PageAddItem(page, (Item) tuples, tupsize, off, false, false); if (l == InvalidOffsetNumber) elog(ERROR, "failed to add item to index page"); tuples = (IndexTuple) (((char *) tuples) + tupsize); off++; } PageSetLSN(page, lsn); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); }
static void bitmap_xlog_insert_bitmap_lastwords(bool redo, XLogRecPtr lsn, XLogRecord* record) { xl_bm_bitmap_lastwords *xlrec = (xl_bm_bitmap_lastwords*) XLogRecGetData(record); Relation reln; reln = XLogOpenRelation(xlrec->bm_node); if (!RelationIsValid(reln)) return; if (redo) { Buffer lovBuffer; Page lovPage; BMLOVItem lovItem; #ifdef BM_DEBUG ereport(LOG, (errcode(LOG), errmsg("call bitmap_xlog_insert_bitmap_lastwords: redo=%d\n", redo))); #endif lovBuffer = XLogReadBuffer(false, reln, xlrec->bm_lov_blkno); if (!BufferIsValid(lovBuffer)) elog(PANIC, "bm_insert_redo: block unfound: %d", xlrec->bm_lov_blkno); lovPage = BufferGetPage(lovBuffer); if (XLByteLT(PageGetLSN(lovPage), lsn)) { lovItem = (BMLOVItem) PageGetItem(lovPage, PageGetItemId(lovPage, xlrec->bm_lov_offset)); lovItem->bm_last_compword = xlrec->bm_last_compword; lovItem->bm_last_word = xlrec->bm_last_word; lovItem->bm_last_two_headerbits = xlrec->bm_last_two_headerbits; PageSetLSN(lovPage, lsn); PageSetTLI(lovPage, ThisTimeLineID); _bitmap_wrtbuf(lovBuffer); } else _bitmap_relbuf(lovBuffer); } else elog(PANIC, "bm_insert_undo: not implemented."); }
static void gistRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) { RelFileNode *node = (RelFileNode *) XLogRecGetData(record); Buffer buffer; Page page; buffer = XLogReadBuffer(*node, GIST_ROOT_BLKNO, true); Assert(BufferIsValid(buffer)); page = (Page) BufferGetPage(buffer); GISTInitBuffer(buffer, F_LEAF); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); }
static void bitmap_xlog_insert_meta(bool redo, XLogRecPtr lsn, XLogRecord* record) { xl_bm_metapage *xlrec = (xl_bm_metapage*) XLogRecGetData(record); Relation reln; reln = XLogOpenRelation(xlrec->bm_node); if (!RelationIsValid(reln)) return; if (redo) { Buffer metabuf; BMMetaPage metapage; #ifdef BM_DEBUG ereport(LOG, (errcode(LOG), errmsg("call bitmap_xlog_insert_meta: redo=%d\n", redo))); #endif metabuf = XLogReadBuffer(false, reln, BM_METAPAGE); if (!BufferIsValid(metabuf)) elog(PANIC, "bm_insert_redo: block unfound: %d", BM_METAPAGE); /* restore the page */ metapage = (BMMetaPage)BufferGetPage(metabuf); if (XLByteLT(PageGetLSN(metapage), lsn)) { PageSetLSN(metapage, lsn); PageSetTLI(metapage, ThisTimeLineID); _bitmap_wrtbuf(metabuf); } else _bitmap_relbuf(metabuf); } else elog(PANIC, "bm_insert_undo: not implemented."); }
static void ginRedoClearIncompleteSplit(XLogRecPtr lsn, RelFileNode node, BlockNumber blkno) { Buffer buffer; Page page; buffer = XLogReadBuffer(node, blkno, false); if (!BufferIsValid(buffer)) return; /* page was deleted, nothing to do */ page = (Page) BufferGetPage(buffer); if (lsn > PageGetLSN(page)) { GinPageGetOpaque(page)->flags &= ~GIN_INCOMPLETE_SPLIT; PageSetLSN(page, lsn); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); }
static void gistRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) { RelFileNode *node = (RelFileNode *) XLogRecGetData(record); Buffer buffer; Page page; /* Backup blocks are not used in create_index records */ Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK)); buffer = XLogReadBuffer(*node, GIST_ROOT_BLKNO, true); Assert(BufferIsValid(buffer)); page = (Page) BufferGetPage(buffer); GISTInitBuffer(buffer, F_LEAF); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); }
/* * This is functionally the same as heap_xlog_newpage. */ static void ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) { ginxlogVacuumPage *xlrec = (ginxlogVacuumPage *) XLogRecGetData(record); char *blk = ((char *) xlrec) + sizeof(ginxlogVacuumPage); Buffer buffer; Page page; Assert(xlrec->hole_offset < BLCKSZ); Assert(xlrec->hole_length < BLCKSZ); /* Backup blocks are not used, we'll re-initialize the page always. */ Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK)); buffer = XLogReadBuffer(xlrec->node, xlrec->blkno, true); if (!BufferIsValid(buffer)) return; page = (Page) BufferGetPage(buffer); if (xlrec->hole_length == 0) { memcpy((char *) page, blk, BLCKSZ); } else { memcpy((char *) page, blk, xlrec->hole_offset); /* must zero-fill the hole */ MemSet((char *) page + xlrec->hole_offset, 0, xlrec->hole_length); memcpy((char *) page + (xlrec->hole_offset + xlrec->hole_length), blk + xlrec->hole_offset, BLCKSZ - (xlrec->hole_offset + xlrec->hole_length)); } PageSetLSN(page, lsn); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); }
static void gistRedoPageDeleteRecord(XLogRecPtr lsn, XLogRecord *record) { gistxlogPageDelete *xldata = (gistxlogPageDelete *) XLogRecGetData(record); Buffer buffer; Page page; /* nothing else 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(xldata->node, xldata->blkno, false); if (!BufferIsValid(buffer)) return; page = (Page) BufferGetPage(buffer); GistPageSetDeleted(page); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); }
static void spgRedoSplitTuple(XLogRecPtr lsn, XLogRecord *record) { char *ptr = XLogRecGetData(record); spgxlogSplitTuple *xldata = (spgxlogSplitTuple *) ptr; SpGistInnerTuple prefixTuple; SpGistInnerTuple postfixTuple; Buffer buffer; Page page; /* we assume this is adequately aligned */ ptr += sizeof(spgxlogSplitTuple); prefixTuple = (SpGistInnerTuple) ptr; ptr += prefixTuple->size; postfixTuple = (SpGistInnerTuple) ptr; /* insert postfix tuple first to avoid dangling link */ if (xldata->blknoPostfix != xldata->blknoPrefix && !(record->xl_info & XLR_BKP_BLOCK_2)) { buffer = XLogReadBuffer(xldata->node, xldata->blknoPostfix, xldata->newPage); if (BufferIsValid(buffer)) { page = BufferGetPage(buffer); if (xldata->newPage) SpGistInitBuffer(buffer, 0); if (!XLByteLE(lsn, PageGetLSN(page))) { addOrReplaceTuple(page, (Item) postfixTuple, postfixTuple->size, xldata->offnumPostfix); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } /* now handle the original page */ if (!(record->xl_info & XLR_BKP_BLOCK_1)) { buffer = XLogReadBuffer(xldata->node, xldata->blknoPrefix, false); if (BufferIsValid(buffer)) { page = BufferGetPage(buffer); if (!XLByteLE(lsn, PageGetLSN(page))) { PageIndexTupleDelete(page, xldata->offnumPrefix); if (PageAddItem(page, (Item) prefixTuple, prefixTuple->size, xldata->offnumPrefix, false, false) != xldata->offnumPrefix) elog(ERROR, "failed to add item of size %u to SPGiST index page", prefixTuple->size); if (xldata->blknoPostfix == xldata->blknoPrefix) addOrReplaceTuple(page, (Item) postfixTuple, postfixTuple->size, xldata->offnumPostfix); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } }
static void ginRedoUpdateMetapage(XLogRecPtr lsn, XLogRecord *record) { ginxlogUpdateMeta *data = (ginxlogUpdateMeta *) XLogRecGetData(record); Buffer metabuffer; Page metapage; Buffer buffer; /* * Restore the metapage. This is essentially the same as a full-page * image, so restore the metapage unconditionally without looking at the * LSN, to avoid torn page hazards. */ metabuffer = XLogReadBuffer(data->node, GIN_METAPAGE_BLKNO, false); if (!BufferIsValid(metabuffer)) return; /* assume index was deleted, nothing to do */ metapage = BufferGetPage(metabuffer); memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData)); PageSetLSN(metapage, lsn); MarkBufferDirty(metabuffer); if (data->ntuples > 0) { /* * insert into tail page */ if (record->xl_info & XLR_BKP_BLOCK(0)) (void) RestoreBackupBlock(lsn, record, 0, false, false); else { buffer = XLogReadBuffer(data->node, data->metadata.tail, false); if (BufferIsValid(buffer)) { Page page = BufferGetPage(buffer); if (lsn > PageGetLSN(page)) { 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++) { tupsize = IndexTupleSize(tuples); l = PageAddItem(page, (Item) tuples, tupsize, off, false, false); if (l == InvalidOffsetNumber) elog(ERROR, "failed to add item to index page"); tuples = (IndexTuple) (((char *) tuples) + tupsize); off++; } /* * Increase counter of heap tuples */ GinPageGetOpaque(page)->maxoff++; PageSetLSN(page, lsn); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } } else if (data->prevTail != InvalidBlockNumber) { /* * New tail */ if (record->xl_info & XLR_BKP_BLOCK(0)) (void) RestoreBackupBlock(lsn, record, 0, false, false); else { buffer = XLogReadBuffer(data->node, data->prevTail, false); if (BufferIsValid(buffer)) { Page page = BufferGetPage(buffer); if (lsn > PageGetLSN(page)) { GinPageGetOpaque(page)->rightlink = data->newRightlink; PageSetLSN(page, lsn); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } } UnlockReleaseBuffer(metabuffer); }
static void ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) { ginxlogDeletePage *data = (ginxlogDeletePage *) XLogRecGetData(record); Buffer dbuffer; Buffer pbuffer; Buffer lbuffer; Page page; if (record->xl_info & XLR_BKP_BLOCK(0)) dbuffer = RestoreBackupBlock(lsn, record, 0, false, true); else { dbuffer = XLogReadBuffer(data->node, data->blkno, false); if (BufferIsValid(dbuffer)) { page = BufferGetPage(dbuffer); if (lsn > PageGetLSN(page)) { Assert(GinPageIsData(page)); GinPageGetOpaque(page)->flags = GIN_DELETED; PageSetLSN(page, lsn); MarkBufferDirty(dbuffer); } } } if (record->xl_info & XLR_BKP_BLOCK(1)) pbuffer = RestoreBackupBlock(lsn, record, 1, false, true); else { pbuffer = XLogReadBuffer(data->node, data->parentBlkno, false); if (BufferIsValid(pbuffer)) { page = BufferGetPage(pbuffer); if (lsn > PageGetLSN(page)) { Assert(GinPageIsData(page)); Assert(!GinPageIsLeaf(page)); GinPageDeletePostingItem(page, data->parentOffset); PageSetLSN(page, lsn); MarkBufferDirty(pbuffer); } } } if (record->xl_info & XLR_BKP_BLOCK(2)) (void) RestoreBackupBlock(lsn, record, 2, false, false); else if (data->leftBlkno != InvalidBlockNumber) { lbuffer = XLogReadBuffer(data->node, data->leftBlkno, false); if (BufferIsValid(lbuffer)) { page = BufferGetPage(lbuffer); if (lsn > PageGetLSN(page)) { Assert(GinPageIsData(page)); GinPageGetOpaque(page)->rightlink = data->rightLink; PageSetLSN(page, lsn); MarkBufferDirty(lbuffer); } UnlockReleaseBuffer(lbuffer); } } if (BufferIsValid(pbuffer)) UnlockReleaseBuffer(pbuffer); if (BufferIsValid(dbuffer)) UnlockReleaseBuffer(dbuffer); }
static void spgRedoPickSplit(XLogRecPtr lsn, XLogRecord *record) { char *ptr = XLogRecGetData(record); spgxlogPickSplit *xldata = (spgxlogPickSplit *) ptr; SpGistInnerTuple innerTuple; SpGistState state; OffsetNumber *toDelete; OffsetNumber *toInsert; uint8 *leafPageSelect; Buffer srcBuffer; Buffer destBuffer; Page page; int bbi; int i; fillFakeState(&state, xldata->stateSrc); ptr += MAXALIGN(sizeof(spgxlogPickSplit)); innerTuple = (SpGistInnerTuple) ptr; ptr += innerTuple->size; toDelete = (OffsetNumber *) ptr; ptr += MAXALIGN(sizeof(OffsetNumber) * xldata->nDelete); toInsert = (OffsetNumber *) ptr; ptr += MAXALIGN(sizeof(OffsetNumber) * xldata->nInsert); leafPageSelect = (uint8 *) ptr; ptr += MAXALIGN(sizeof(uint8) * xldata->nInsert); /* now ptr points to the list of leaf tuples */ /* * It's a bit tricky to identify which pages have been handled as * full-page images, so we explicitly count each referenced buffer. */ bbi = 0; if (xldata->blknoSrc == SPGIST_HEAD_BLKNO) { /* when splitting root, we touch it only in the guise of new inner */ srcBuffer = InvalidBuffer; } else if (xldata->initSrc) { /* just re-init the source page */ srcBuffer = XLogReadBuffer(xldata->node, xldata->blknoSrc, true); Assert(BufferIsValid(srcBuffer)); page = (Page) BufferGetPage(srcBuffer); SpGistInitBuffer(srcBuffer, SPGIST_LEAF); /* don't update LSN etc till we're done with it */ } else { /* delete the specified tuples from source page */ if (!(record->xl_info & XLR_SET_BKP_BLOCK(bbi))) { srcBuffer = XLogReadBuffer(xldata->node, xldata->blknoSrc, false); if (BufferIsValid(srcBuffer)) { page = BufferGetPage(srcBuffer); if (!XLByteLE(lsn, PageGetLSN(page))) { /* * We have it a bit easier here than in doPickSplit(), * because we know the inner tuple's location already, * so we can inject the correct redirection tuple now. */ if (!state.isBuild) spgPageIndexMultiDelete(&state, page, toDelete, xldata->nDelete, SPGIST_REDIRECT, SPGIST_PLACEHOLDER, xldata->blknoInner, xldata->offnumInner); else spgPageIndexMultiDelete(&state, page, toDelete, xldata->nDelete, SPGIST_PLACEHOLDER, SPGIST_PLACEHOLDER, InvalidBlockNumber, InvalidOffsetNumber); /* don't update LSN etc till we're done with it */ } } } else srcBuffer = InvalidBuffer; bbi++; } /* try to access dest page if any */ if (xldata->blknoDest == InvalidBlockNumber) { destBuffer = InvalidBuffer; } else if (xldata->initDest) { /* just re-init the dest page */ destBuffer = XLogReadBuffer(xldata->node, xldata->blknoDest, true); Assert(BufferIsValid(destBuffer)); page = (Page) BufferGetPage(destBuffer); SpGistInitBuffer(destBuffer, SPGIST_LEAF); /* don't update LSN etc till we're done with it */ } else { if (!(record->xl_info & XLR_SET_BKP_BLOCK(bbi))) destBuffer = XLogReadBuffer(xldata->node, xldata->blknoDest, false); else destBuffer = InvalidBuffer; bbi++; } /* restore leaf tuples to src and/or dest page */ for (i = 0; i < xldata->nInsert; i++) { SpGistLeafTuple lt = (SpGistLeafTuple) ptr; Buffer leafBuffer; ptr += lt->size; leafBuffer = leafPageSelect[i] ? destBuffer : srcBuffer; if (!BufferIsValid(leafBuffer)) continue; /* no need to touch this page */ page = BufferGetPage(leafBuffer); if (!XLByteLE(lsn, PageGetLSN(page))) { addOrReplaceTuple(page, (Item) lt, lt->size, toInsert[i]); } } /* Now update src and dest page LSNs */ if (BufferIsValid(srcBuffer)) { page = BufferGetPage(srcBuffer); if (!XLByteLE(lsn, PageGetLSN(page))) { PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(srcBuffer); } UnlockReleaseBuffer(srcBuffer); } if (BufferIsValid(destBuffer)) { page = BufferGetPage(destBuffer); if (!XLByteLE(lsn, PageGetLSN(page))) { PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(destBuffer); } UnlockReleaseBuffer(destBuffer); } /* restore new inner tuple */ if (!(record->xl_info & XLR_SET_BKP_BLOCK(bbi))) { Buffer buffer = XLogReadBuffer(xldata->node, xldata->blknoInner, xldata->initInner); if (BufferIsValid(buffer)) { page = BufferGetPage(buffer); if (xldata->initInner) SpGistInitBuffer(buffer, 0); if (!XLByteLE(lsn, PageGetLSN(page))) { addOrReplaceTuple(page, (Item) innerTuple, innerTuple->size, xldata->offnumInner); /* if inner is also parent, update link while we're here */ if (xldata->blknoInner == xldata->blknoParent) { SpGistInnerTuple parent; parent = (SpGistInnerTuple) PageGetItem(page, PageGetItemId(page, xldata->offnumParent)); spgUpdateNodeLink(parent, xldata->nodeI, xldata->blknoInner, xldata->offnumInner); } PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } bbi++; /* update parent downlink, unless we did it above */ if (xldata->blknoParent == InvalidBlockNumber) { /* no parent cause we split the root */ Assert(xldata->blknoInner == SPGIST_HEAD_BLKNO); } else if (xldata->blknoInner != xldata->blknoParent) { if (!(record->xl_info & XLR_SET_BKP_BLOCK(bbi))) { Buffer buffer = XLogReadBuffer(xldata->node, xldata->blknoParent, false); if (BufferIsValid(buffer)) { page = BufferGetPage(buffer); if (!XLByteLE(lsn, PageGetLSN(page))) { SpGistInnerTuple parent; parent = (SpGistInnerTuple) PageGetItem(page, PageGetItemId(page, xldata->offnumParent)); spgUpdateNodeLink(parent, xldata->nodeI, xldata->blknoInner, xldata->offnumInner); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } } }
static void ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) { ginxlogSplit *data = (ginxlogSplit *) XLogRecGetData(record); Buffer lbuffer, rbuffer; Page lpage, rpage; uint32 flags; uint32 lflags, rflags; char *payload; bool isLeaf = (data->flags & GIN_INSERT_ISLEAF) != 0; bool isData = (data->flags & GIN_INSERT_ISDATA) != 0; bool isRoot = (data->flags & GIN_SPLIT_ROOT) != 0; payload = XLogRecGetData(record) + sizeof(ginxlogSplit); /* * First clear incomplete-split flag on child page if this finishes a * split */ if (!isLeaf) { if (record->xl_info & XLR_BKP_BLOCK(0)) (void) RestoreBackupBlock(lsn, record, 0, false, false); else ginRedoClearIncompleteSplit(lsn, data->node, data->leftChildBlkno); } flags = 0; if (isLeaf) flags |= GIN_LEAF; if (isData) flags |= GIN_DATA; if (isLeaf && isData) flags |= GIN_COMPRESSED; lflags = rflags = flags; if (!isRoot) lflags |= GIN_INCOMPLETE_SPLIT; lbuffer = XLogReadBuffer(data->node, data->lblkno, true); Assert(BufferIsValid(lbuffer)); lpage = (Page) BufferGetPage(lbuffer); GinInitBuffer(lbuffer, lflags); rbuffer = XLogReadBuffer(data->node, data->rblkno, true); Assert(BufferIsValid(rbuffer)); rpage = (Page) BufferGetPage(rbuffer); GinInitBuffer(rbuffer, rflags); GinPageGetOpaque(lpage)->rightlink = BufferGetBlockNumber(rbuffer); GinPageGetOpaque(rpage)->rightlink = isRoot ? InvalidBlockNumber : data->rrlink; /* Do the tree-type specific portion to restore the page contents */ if (isData) ginRedoSplitData(lpage, rpage, payload); else ginRedoSplitEntry(lpage, rpage, payload); PageSetLSN(rpage, lsn); MarkBufferDirty(rbuffer); PageSetLSN(lpage, lsn); MarkBufferDirty(lbuffer); if (isRoot) { BlockNumber rootBlkno = data->rrlink; Buffer rootBuf = XLogReadBuffer(data->node, rootBlkno, true); Page rootPage = BufferGetPage(rootBuf); GinInitBuffer(rootBuf, flags & ~GIN_LEAF & ~GIN_COMPRESSED); if (isData) { Assert(rootBlkno != GIN_ROOT_BLKNO); ginDataFillRoot(NULL, BufferGetPage(rootBuf), BufferGetBlockNumber(lbuffer), BufferGetPage(lbuffer), BufferGetBlockNumber(rbuffer), BufferGetPage(rbuffer)); } else { Assert(rootBlkno == GIN_ROOT_BLKNO); ginEntryFillRoot(NULL, BufferGetPage(rootBuf), BufferGetBlockNumber(lbuffer), BufferGetPage(lbuffer), BufferGetBlockNumber(rbuffer), BufferGetPage(rbuffer)); } PageSetLSN(rootPage, lsn); MarkBufferDirty(rootBuf); UnlockReleaseBuffer(rootBuf); } UnlockReleaseBuffer(rbuffer); UnlockReleaseBuffer(lbuffer); }
static void spgRedoVacuumLeaf(XLogRecPtr lsn, XLogRecord *record) { char *ptr = XLogRecGetData(record); spgxlogVacuumLeaf *xldata = (spgxlogVacuumLeaf *) ptr; OffsetNumber *toDead; OffsetNumber *toPlaceholder; OffsetNumber *moveSrc; OffsetNumber *moveDest; OffsetNumber *chainSrc; OffsetNumber *chainDest; SpGistState state; Buffer buffer; Page page; int i; fillFakeState(&state, xldata->stateSrc); ptr += sizeof(spgxlogVacuumLeaf); toDead = (OffsetNumber *) ptr; ptr += sizeof(OffsetNumber) * xldata->nDead; toPlaceholder = (OffsetNumber *) ptr; ptr += sizeof(OffsetNumber) * xldata->nPlaceholder; moveSrc = (OffsetNumber *) ptr; ptr += sizeof(OffsetNumber) * xldata->nMove; moveDest = (OffsetNumber *) ptr; ptr += sizeof(OffsetNumber) * xldata->nMove; chainSrc = (OffsetNumber *) ptr; ptr += sizeof(OffsetNumber) * xldata->nChain; chainDest = (OffsetNumber *) ptr; if (!(record->xl_info & XLR_BKP_BLOCK_1)) { buffer = XLogReadBuffer(xldata->node, xldata->blkno, false); if (BufferIsValid(buffer)) { page = BufferGetPage(buffer); if (!XLByteLE(lsn, PageGetLSN(page))) { spgPageIndexMultiDelete(&state, page, toDead, xldata->nDead, SPGIST_DEAD, SPGIST_DEAD, InvalidBlockNumber, InvalidOffsetNumber); spgPageIndexMultiDelete(&state, page, toPlaceholder, xldata->nPlaceholder, SPGIST_PLACEHOLDER, SPGIST_PLACEHOLDER, InvalidBlockNumber, InvalidOffsetNumber); /* see comments in vacuumLeafPage() */ for (i = 0; i < xldata->nMove; i++) { ItemId idSrc = PageGetItemId(page, moveSrc[i]); ItemId idDest = PageGetItemId(page, moveDest[i]); ItemIdData tmp; tmp = *idSrc; *idSrc = *idDest; *idDest = tmp; } spgPageIndexMultiDelete(&state, page, moveSrc, xldata->nMove, SPGIST_PLACEHOLDER, SPGIST_PLACEHOLDER, InvalidBlockNumber, InvalidOffsetNumber); for (i = 0; i < xldata->nChain; i++) { SpGistLeafTuple lt; lt = (SpGistLeafTuple) PageGetItem(page, PageGetItemId(page, chainSrc[i])); Assert(lt->tupstate == SPGIST_LIVE); lt->nextOffset = chainDest[i]; } PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } }
static void ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) { ginxlogInsert *data = (ginxlogInsert *) XLogRecGetData(record); Buffer buffer; Page page; char *payload; BlockNumber leftChildBlkno = InvalidBlockNumber; BlockNumber rightChildBlkno = InvalidBlockNumber; bool isLeaf = (data->flags & GIN_INSERT_ISLEAF) != 0; payload = XLogRecGetData(record) + sizeof(ginxlogInsert); /* * First clear incomplete-split flag on child page if this finishes a * split. */ if (!isLeaf) { leftChildBlkno = BlockIdGetBlockNumber((BlockId) payload); payload += sizeof(BlockIdData); rightChildBlkno = BlockIdGetBlockNumber((BlockId) payload); payload += sizeof(BlockIdData); if (record->xl_info & XLR_BKP_BLOCK(0)) (void) RestoreBackupBlock(lsn, record, 0, false, false); else ginRedoClearIncompleteSplit(lsn, data->node, leftChildBlkno); } /* If we have a full-page image, restore it and we're done */ if (record->xl_info & XLR_BKP_BLOCK(isLeaf ? 0 : 1)) { (void) RestoreBackupBlock(lsn, record, isLeaf ? 0 : 1, false, false); return; } buffer = XLogReadBuffer(data->node, data->blkno, false); if (!BufferIsValid(buffer)) return; /* page was deleted, nothing to do */ page = (Page) BufferGetPage(buffer); if (lsn > PageGetLSN(page)) { /* How to insert the payload is tree-type specific */ if (data->flags & GIN_INSERT_ISDATA) { Assert(GinPageIsData(page)); ginRedoInsertData(buffer, isLeaf, rightChildBlkno, payload); } else { Assert(!GinPageIsData(page)); ginRedoInsertEntry(buffer, isLeaf, rightChildBlkno, payload); } PageSetLSN(page, lsn); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); }
static void spgRedoVacuumRedirect(XLogRecPtr lsn, XLogRecord *record) { char *ptr = XLogRecGetData(record); spgxlogVacuumRedirect *xldata = (spgxlogVacuumRedirect *) ptr; OffsetNumber *itemToPlaceholder; Buffer buffer; Page page; ptr += sizeof(spgxlogVacuumRedirect); itemToPlaceholder = (OffsetNumber *) ptr; if (!(record->xl_info & XLR_BKP_BLOCK_1)) { buffer = XLogReadBuffer(xldata->node, xldata->blkno, false); if (BufferIsValid(buffer)) { page = BufferGetPage(buffer); if (!XLByteLE(lsn, PageGetLSN(page))) { SpGistPageOpaque opaque = SpGistPageGetOpaque(page); int i; /* Convert redirect pointers to plain placeholders */ for (i = 0; i < xldata->nToPlaceholder; i++) { SpGistDeadTuple dt; dt = (SpGistDeadTuple) PageGetItem(page, PageGetItemId(page, itemToPlaceholder[i])); Assert(dt->tupstate == SPGIST_REDIRECT); dt->tupstate = SPGIST_PLACEHOLDER; ItemPointerSetInvalid(&dt->pointer); } Assert(opaque->nRedirection >= xldata->nToPlaceholder); opaque->nRedirection -= xldata->nToPlaceholder; opaque->nPlaceholder += xldata->nToPlaceholder; /* Remove placeholder tuples at end of page */ if (xldata->firstPlaceholder != InvalidOffsetNumber) { int max = PageGetMaxOffsetNumber(page); OffsetNumber *toDelete; toDelete = palloc(sizeof(OffsetNumber) * max); for (i = xldata->firstPlaceholder; i <= max; i++) toDelete[i - xldata->firstPlaceholder] = i; i = max - xldata->firstPlaceholder + 1; Assert(opaque->nPlaceholder >= i); opaque->nPlaceholder -= i; /* The array is sorted, so can use PageIndexMultiDelete */ PageIndexMultiDelete(page, toDelete, i); pfree(toDelete); } PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } }
/* * redo any page update (except page split) */ static void gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record) { char *begin = XLogRecGetData(record); gistxlogPageUpdate *xldata = (gistxlogPageUpdate *) begin; Buffer buffer; Page page; char *data; if (BlockNumberIsValid(xldata->leftchild)) gistRedoClearFollowRight(xldata->node, lsn, xldata->leftchild); /* nothing more 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(xldata->node, xldata->blkno, false); if (!BufferIsValid(buffer)) return; page = (Page) BufferGetPage(buffer); if (XLByteLE(lsn, PageGetLSN(page))) { UnlockReleaseBuffer(buffer); return; } data = begin + sizeof(gistxlogPageUpdate); /* Delete old tuples */ if (xldata->ntodelete > 0) { int i; OffsetNumber *todelete = (OffsetNumber *) data; data += sizeof(OffsetNumber) * xldata->ntodelete; for (i = 0; i < xldata->ntodelete; i++) PageIndexTupleDelete(page, todelete[i]); if (GistPageIsLeaf(page)) GistMarkTuplesDeleted(page); } /* add tuples */ if (data - begin < record->xl_len) { OffsetNumber off = (PageIsEmpty(page)) ? FirstOffsetNumber : OffsetNumberNext(PageGetMaxOffsetNumber(page)); while (data - begin < record->xl_len) { IndexTuple itup = (IndexTuple) data; Size sz = IndexTupleSize(itup); OffsetNumber l; data += sz; l = PageAddItem(page, (Item) itup, sz, off, false, false); if (l == InvalidOffsetNumber) elog(ERROR, "failed to add item to GiST index page, size %d bytes", (int) sz); off++; } } else { /* * special case: leafpage, nothing to insert, nothing to delete, then * vacuum marks page */ if (GistPageIsLeaf(page) && xldata->ntodelete == 0) GistClearTuplesDeleted(page); } if (!GistPageIsLeaf(page) && PageGetMaxOffsetNumber(page) == InvalidOffsetNumber && xldata->blkno == GIST_ROOT_BLKNO) /* * all links on non-leaf root page was deleted by vacuum full, so root * page becomes a leaf */ GistPageSetLeaf(page); GistPageGetOpaque(page)->rightlink = InvalidBlockNumber; PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); }
static void spgRedoAddLeaf(XLogRecPtr lsn, XLogRecord *record) { char *ptr = XLogRecGetData(record); spgxlogAddLeaf *xldata = (spgxlogAddLeaf *) ptr; SpGistLeafTuple leafTuple; Buffer buffer; Page page; /* we assume this is adequately aligned */ ptr += sizeof(spgxlogAddLeaf); leafTuple = (SpGistLeafTuple) ptr; if (!(record->xl_info & XLR_BKP_BLOCK_1)) { buffer = XLogReadBuffer(xldata->node, xldata->blknoLeaf, xldata->newPage); if (BufferIsValid(buffer)) { page = BufferGetPage(buffer); if (xldata->newPage) SpGistInitBuffer(buffer, SPGIST_LEAF); if (!XLByteLE(lsn, PageGetLSN(page))) { /* insert new tuple */ if (xldata->offnumLeaf != xldata->offnumHeadLeaf) { /* normal cases, tuple was added by SpGistPageAddNewItem */ addOrReplaceTuple(page, (Item) leafTuple, leafTuple->size, xldata->offnumLeaf); /* update head tuple's chain link if needed */ if (xldata->offnumHeadLeaf != InvalidOffsetNumber) { SpGistLeafTuple head; head = (SpGistLeafTuple) PageGetItem(page, PageGetItemId(page, xldata->offnumHeadLeaf)); Assert(head->nextOffset == leafTuple->nextOffset); head->nextOffset = xldata->offnumLeaf; } } else { /* replacing a DEAD tuple */ PageIndexTupleDelete(page, xldata->offnumLeaf); if (PageAddItem(page, (Item) leafTuple, leafTuple->size, xldata->offnumLeaf, false, false) != xldata->offnumLeaf) elog(ERROR, "failed to add item of size %u to SPGiST index page", leafTuple->size); } PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } /* update parent downlink if necessary */ if (xldata->blknoParent != InvalidBlockNumber && !(record->xl_info & XLR_BKP_BLOCK_2)) { buffer = XLogReadBuffer(xldata->node, xldata->blknoParent, false); if (BufferIsValid(buffer)) { page = BufferGetPage(buffer); if (!XLByteLE(lsn, PageGetLSN(page))) { SpGistInnerTuple tuple; tuple = (SpGistInnerTuple) PageGetItem(page, PageGetItemId(page, xldata->offnumParent)); spgUpdateNodeLink(tuple, xldata->nodeI, xldata->blknoLeaf, xldata->offnumLeaf); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); } UnlockReleaseBuffer(buffer); } } }
static void gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record) { gistxlogPageSplit *xldata = (gistxlogPageSplit *) XLogRecGetData(record); PageSplitRecord xlrec; Buffer buffer; Page page; int i; bool isrootsplit = false; if (BlockNumberIsValid(xldata->leftchild)) gistRedoClearFollowRight(xldata->node, lsn, xldata->leftchild); decodePageSplitRecord(&xlrec, record); /* loop around all pages */ for (i = 0; i < xlrec.data->npage; i++) { NewPage *newpage = xlrec.page + i; int flags; if (newpage->header->blkno == GIST_ROOT_BLKNO) { Assert(i == 0); isrootsplit = true; } buffer = XLogReadBuffer(xlrec.data->node, newpage->header->blkno, true); Assert(BufferIsValid(buffer)); page = (Page) BufferGetPage(buffer); /* ok, clear buffer */ if (xlrec.data->origleaf && newpage->header->blkno != GIST_ROOT_BLKNO) flags = F_LEAF; else flags = 0; GISTInitBuffer(buffer, flags); /* and fill it */ gistfillbuffer(page, newpage->itup, newpage->header->num, FirstOffsetNumber); if (newpage->header->blkno == GIST_ROOT_BLKNO) { GistPageGetOpaque(page)->rightlink = InvalidBlockNumber; GistPageGetOpaque(page)->nsn = xldata->orignsn; GistClearFollowRight(page); } else { if (i < xlrec.data->npage - 1) GistPageGetOpaque(page)->rightlink = xlrec.page[i + 1].header->blkno; else GistPageGetOpaque(page)->rightlink = xldata->origrlink; GistPageGetOpaque(page)->nsn = xldata->orignsn; if (i < xlrec.data->npage - 1 && !isrootsplit) GistMarkFollowRight(page); else GistClearFollowRight(page); } PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); } }