Change the way WAL records are constructed.
authorHeikki Linnakangas <[email protected]>
Thu, 14 Aug 2014 10:23:54 +0000 (13:23 +0300)
committerHeikki Linnakangas <[email protected]>
Mon, 10 Nov 2014 19:24:36 +0000 (21:24 +0200)
60 files changed:
contrib/pg_xlogdump/pg_xlogdump.c
src/backend/access/brin/brin.c
src/backend/access/brin/brin_pageops.c
src/backend/access/brin/brin_revmap.c
src/backend/access/brin/brin_xlog.c
src/backend/access/gin/ginbtree.c
src/backend/access/gin/gindatapage.c
src/backend/access/gin/ginentrypage.c
src/backend/access/gin/ginfast.c
src/backend/access/gin/gininsert.c
src/backend/access/gin/ginutil.c
src/backend/access/gin/ginvacuum.c
src/backend/access/gin/ginxlog.c
src/backend/access/gist/gist.c
src/backend/access/gist/gistbuild.c
src/backend/access/gist/gistxlog.c
src/backend/access/heap/heapam.c
src/backend/access/heap/rewriteheap.c
src/backend/access/nbtree/nbtinsert.c
src/backend/access/nbtree/nbtpage.c
src/backend/access/nbtree/nbtxlog.c
src/backend/access/rmgrdesc/brindesc.c
src/backend/access/rmgrdesc/gindesc.c
src/backend/access/rmgrdesc/gistdesc.c
src/backend/access/rmgrdesc/heapdesc.c
src/backend/access/rmgrdesc/nbtdesc.c
src/backend/access/rmgrdesc/spgdesc.c
src/backend/access/rmgrdesc/xlogdesc.c
src/backend/access/spgist/spgdoinsert.c
src/backend/access/spgist/spginsert.c
src/backend/access/spgist/spgvacuum.c
src/backend/access/spgist/spgxlog.c
src/backend/access/transam/README
src/backend/access/transam/clog.c
src/backend/access/transam/multixact.c
src/backend/access/transam/twophase.c
src/backend/access/transam/xact.c
src/backend/access/transam/xlog.c
src/backend/access/transam/xloginsert.c
src/backend/access/transam/xlogreader.c
src/backend/access/transam/xlogutils.c
src/backend/catalog/storage.c
src/backend/commands/dbcommands.c
src/backend/commands/sequence.c
src/backend/commands/tablespace.c
src/backend/replication/logical/decode.c
src/backend/replication/logical/snapbuild.c
src/backend/storage/ipc/standby.c
src/backend/utils/cache/relmapper.c
src/include/access/brin_xlog.h
src/include/access/gin_private.h
src/include/access/gist_private.h
src/include/access/heapam_xlog.h
src/include/access/nbtree.h
src/include/access/spgist_private.h
src/include/access/xlog.h
src/include/access/xlog_internal.h
src/include/access/xloginsert.h
src/include/access/xlogrecord.h
src/include/access/xlogutils.h

index 7f151f961c87b799ac1aa63c7518d5e191ef5ac4..6d867da9f35c1608eb4edda160015bdf332ddf07 100644 (file)
@@ -384,51 +384,87 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
 {
        const char         *id;
        const RmgrDescData *desc = &RmgrDescTable[record->xl_rmid];
+       int                     nblockrefs;
+       uint8      *blockrefids;
+       int                     i;
+       RelFileNode rnode;
+       ForkNumber      forknum;
+       BlockNumber blk;
+       XLogRecordBlockData *bkpb;
 
        id = desc->rm_identify(record->xl_info);
        if (id == NULL)
                id = psprintf("UNKNOWN (%x)", record->xl_info & ~XLR_INFO_MASK);
 
-       printf("rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, bkp: %u%u%u%u, desc: %s ",
+       config->already_displayed_records++;
+
+       printf("rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, ",
                   desc->rm_name,
                   record->xl_len, record->xl_tot_len,
                   record->xl_xid,
                   (uint32) (ReadRecPtr >> 32), (uint32) ReadRecPtr,
-                  (uint32) (record->xl_prev >> 32), (uint32) record->xl_prev,
-                  !!(XLR_BKP_BLOCK(0) & record->xl_info),
-                  !!(XLR_BKP_BLOCK(1) & record->xl_info),
-                  !!(XLR_BKP_BLOCK(2) & record->xl_info),
-                  !!(XLR_BKP_BLOCK(3) & record->xl_info),
-                  id);
+                  (uint32) (record->xl_prev >> 32), (uint32) record->xl_prev);
+
+       /* print block references (short format) */
+       blockrefids = XLogRecGetBlockRefIds(record, &nblockrefs);
+       if (!config->bkp_details)
+       {
+               for (i = 0; i < nblockrefs; i++)
+               {
+                       uint8           id = blockrefids[i];
+
+                       bkpb = XLogRecGetBlockRef(record, id, NULL);
+                       XLogRecGetBlockTag(record, id, &rnode, &forknum, &blk);
+                       if (forknum != MAIN_FORKNUM)
+                               printf("blkref #%u: rel %u/%u/%u fork %s blk %u",
+                                          id,
+                                          rnode.spcNode, rnode.dbNode, rnode.relNode,
+                                          forkNames[forknum],
+                                          blk);
+                       else
+                               printf("blkref #%u: rel %u/%u/%u blk %u",
+                                          id,
+                                          rnode.spcNode, rnode.dbNode, rnode.relNode,
+                                          blk);
+                       if (bkpb->fork_flags & BKPBLOCK_HAS_IMAGE)
+                               printf(" FPW");
+                       printf(", ");
+               }
+       }
+       printf("desc: %s ", id);
 
        /* the desc routine will printf the description directly to stdout */
        desc->rm_desc(NULL, record);
 
        putchar('\n');
 
+       /* print block references (detailed format) */
        if (config->bkp_details)
        {
-               int                     bkpnum;
-               char       *blk = (char *) XLogRecGetData(record) + record->xl_len;
-
-               for (bkpnum = 0; bkpnum < XLR_MAX_BKP_BLOCKS; bkpnum++)
+               for (i = 0; i < nblockrefs; i++)
                {
-                       BkpBlock        bkpb;
-
-                       if (!(XLR_BKP_BLOCK(bkpnum) & record->xl_info))
-                               continue;
-
-                       memcpy(&bkpb, blk, sizeof(BkpBlock));
-                       blk += sizeof(BkpBlock);
-                       blk += BLCKSZ - bkpb.hole_length;
-
-                       printf("\tbackup bkp #%u; rel %u/%u/%u; fork: %s; block: %u; hole: offset: %u, length: %u\n",
-                                  bkpnum,
-                                  bkpb.node.spcNode, bkpb.node.dbNode, bkpb.node.relNode,
-                                  forkNames[bkpb.fork],
-                                  bkpb.block, bkpb.hole_offset, bkpb.hole_length);
+                       uint8           id = blockrefids[i];
+                       char       *blkdata;
+
+                       bkpb = XLogRecGetBlockRef(record, id, &blkdata);
+
+                       XLogRecGetBlockTag(record, id, &rnode, &forknum, &blk);
+                       printf("\tblkref #%u: rel %u/%u/%u fork %s blk %u",
+                                  id,
+                                  rnode.spcNode, rnode.dbNode, rnode.relNode,
+                                  forkNames[forknum],
+                                  blk);
+                       if (bkpb->fork_flags & BKPBLOCK_HAS_IMAGE)
+                       {
+                               XLogRecordBlockImage *blkimg = (XLogRecordBlockImage *) blkdata;
+                               printf(" (FPW); hole: offset: %u, length: %u\n",
+                                          blkimg->hole_offset, blkimg->hole_length);
+                       }
+                       printf("\n");
                }
        }
+
+       pfree(blockrefids);
 }
 
 /*
index bd35cf6696acac2f207e6fb77d3076865d387d80..cb645e3d4596a77038b587233ca7aab2071421de 100644 (file)
@@ -666,19 +666,16 @@ brinbuild(PG_FUNCTION_ARGS)
        {
                xl_brin_createidx xlrec;
                XLogRecPtr      recptr;
-               XLogRecData rdata;
                Page            page;
 
-               xlrec.node = index->rd_node;
                xlrec.version = BRIN_CURRENT_VERSION;
                xlrec.pagesPerRange = BrinGetPagesPerRange(index);
 
-               rdata.buffer = InvalidBuffer;
-               rdata.data = (char *) &xlrec;
-               rdata.len = SizeOfBrinCreateIdx;
-               rdata.next = NULL;
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, SizeOfBrinCreateIdx);
+               XLogRegisterBuffer(0, meta, REGBUF_WILL_INIT);
 
-               recptr = XLogInsert(RM_BRIN_ID, XLOG_BRIN_CREATE_INDEX, &rdata);
+               recptr = XLogInsert(RM_BRIN_ID, XLOG_BRIN_CREATE_INDEX);
 
                page = BufferGetPage(meta);
                PageSetLSN(page, recptr);
index 50f1dec1631a376461fc7f4d4d62a2c5b56f450b..0b6fbeb603cd49117ee58832709dc0ff4c614a72 100644 (file)
@@ -140,27 +140,19 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
                /* XLOG stuff */
                if (RelationNeedsWAL(idxrel))
                {
-                       BlockNumber blk = BufferGetBlockNumber(oldbuf);
                        xl_brin_samepage_update xlrec;
                        XLogRecPtr      recptr;
-                       XLogRecData rdata[2];
                        uint8           info = XLOG_BRIN_SAMEPAGE_UPDATE;
 
-                       xlrec.node = idxrel->rd_node;
-                       ItemPointerSetBlockNumber(&xlrec.tid, blk);
-                       ItemPointerSetOffsetNumber(&xlrec.tid, oldoff);
-                       rdata[0].data = (char *) &xlrec;
-                       rdata[0].len = SizeOfBrinSamepageUpdate;
-                       rdata[0].buffer = InvalidBuffer;
-                       rdata[0].next = &(rdata[1]);
+                       xlrec.offnum = oldoff;
 
-                       rdata[1].data = (char *) newtup;
-                       rdata[1].len = newsz;
-                       rdata[1].buffer = oldbuf;
-                       rdata[1].buffer_std = true;
-                       rdata[1].next = NULL;
+                       XLogBeginInsert();
+                       XLogRegisterData((char *) &xlrec, SizeOfBrinSamepageUpdate);
 
-                       recptr = XLogInsert(RM_BRIN_ID, info, rdata);
+                       XLogRegisterBuffer(0, oldbuf, REGBUF_STANDARD);
+                       XLogRegisterBufData(0, (char *) newtup, newsz);
+
+                       recptr = XLogInsert(RM_BRIN_ID, info);
 
                        PageSetLSN(oldpage, recptr);
                }
@@ -211,43 +203,30 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
                {
                        xl_brin_update xlrec;
                        XLogRecPtr      recptr;
-                       XLogRecData rdata[4];
                        uint8           info;
 
                        info = XLOG_BRIN_UPDATE | (extended ? XLOG_BRIN_INIT_PAGE : 0);
 
-                       xlrec.insert.node = idxrel->rd_node;
-                       ItemPointerSet(&xlrec.insert.tid, BufferGetBlockNumber(newbuf), newoff);
+                       xlrec.insert.offnum = newoff;
                        xlrec.insert.heapBlk = heapBlk;
-                       xlrec.insert.tuplen = newsz;
-                       xlrec.insert.revmapBlk = BufferGetBlockNumber(revmapbuf);
                        xlrec.insert.pagesPerRange = pagesPerRange;
-                       ItemPointerSet(&xlrec.oldtid, BufferGetBlockNumber(oldbuf), oldoff);
+                       xlrec.oldOffnum = oldoff;
+
+                       XLogBeginInsert();
 
-                       rdata[0].data = (char *) &xlrec;
-                       rdata[0].len = SizeOfBrinUpdate;
-                       rdata[0].buffer = InvalidBuffer;
-                       rdata[0].next = &(rdata[1]);
+                       /* new page */
+                       XLogRegisterData((char *) &xlrec, SizeOfBrinUpdate);
 
-                       rdata[1].data = (char *) newtup;
-                       rdata[1].len = newsz;
-                       rdata[1].buffer = extended ? InvalidBuffer : newbuf;
-                       rdata[1].buffer_std = true;
-                       rdata[1].next = &(rdata[2]);
+                       XLogRegisterBuffer(0, newbuf, REGBUF_STANDARD | (extended ? REGBUF_WILL_INIT : 0));
+                       XLogRegisterBufData(0, (char *) newtup, newsz);
 
-                       rdata[2].data = (char *) NULL;
-                       rdata[2].len = 0;
-                       rdata[2].buffer = revmapbuf;
-                       rdata[2].buffer_std = true;
-                       rdata[2].next = &(rdata[3]);
+                       /* revmap page */
+                       XLogRegisterBuffer(1, revmapbuf, REGBUF_STANDARD);
 
-                       rdata[3].data = (char *) NULL;
-                       rdata[3].len = 0;
-                       rdata[3].buffer = oldbuf;
-                       rdata[3].buffer_std = true;
-                       rdata[3].next = NULL;
+                       /* old page */
+                       XLogRegisterBuffer(2, oldbuf, REGBUF_STANDARD);
 
-                       recptr = XLogInsert(RM_BRIN_ID, info, rdata);
+                       recptr = XLogInsert(RM_BRIN_ID, info);
 
                        PageSetLSN(oldpage, recptr);
                        PageSetLSN(newpage, recptr);
@@ -354,36 +333,22 @@ brin_doinsert(Relation idxrel, BlockNumber pagesPerRange,
        {
                xl_brin_insert xlrec;
                XLogRecPtr      recptr;
-               XLogRecData rdata[3];
                uint8           info;
 
                info = XLOG_BRIN_INSERT | (extended ? XLOG_BRIN_INIT_PAGE : 0);
-               xlrec.node = idxrel->rd_node;
                xlrec.heapBlk = heapBlk;
                xlrec.pagesPerRange = pagesPerRange;
-               xlrec.revmapBlk = BufferGetBlockNumber(revmapbuf);
-               xlrec.tuplen = itemsz;
-               ItemPointerSet(&xlrec.tid, blk, off);
-
-               rdata[0].data = (char *) &xlrec;
-               rdata[0].len = SizeOfBrinInsert;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].buffer_std = false;
-               rdata[0].next = &(rdata[1]);
-
-               rdata[1].data = (char *) tup;
-               rdata[1].len = itemsz;
-               rdata[1].buffer = extended ? InvalidBuffer : *buffer;
-               rdata[1].buffer_std = true;
-               rdata[1].next = &(rdata[2]);
-
-               rdata[2].data = (char *) NULL;
-               rdata[2].len = 0;
-               rdata[2].buffer = revmapbuf;
-               rdata[2].buffer_std = false;
-               rdata[2].next = NULL;
-
-               recptr = XLogInsert(RM_BRIN_ID, info, rdata);
+               xlrec.offnum = off;
+
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, SizeOfBrinInsert);
+
+               XLogRegisterBuffer(0, *buffer, REGBUF_STANDARD | (extended ? REGBUF_WILL_INIT : 0));
+               XLogRegisterBufData(0, (char *) tup, itemsz);
+
+               XLogRegisterBuffer(1, revmapbuf, 0);
+
+               recptr = XLogInsert(RM_BRIN_ID, info);
 
                PageSetLSN(page, recptr);
                PageSetLSN(BufferGetPage(revmapbuf), recptr);
index 272c74e6b6e10cc885a2d684c58503411e32bd44..adc7d0b8473bc2b8f129ef152c4e94229ba6508a 100644 (file)
@@ -477,23 +477,16 @@ revmap_physical_extend(BrinRevmap *revmap)
        {
                xl_brin_revmap_extend xlrec;
                XLogRecPtr      recptr;
-               XLogRecData rdata[2];
 
-               xlrec.node = revmap->rm_irel->rd_node;
                xlrec.targetBlk = mapBlk;
-               rdata[0].data = (char *) &xlrec;
-               rdata[0].len = SizeOfBrinRevmapExtend;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].buffer_std = false;
-               rdata[0].next = &(rdata[1]);
-
-               rdata[1].data = (char *) NULL;
-               rdata[1].len = 0;
-               rdata[1].buffer = revmap->rm_metaBuf;
-               rdata[1].buffer_std = false;
-               rdata[1].next = NULL;
-
-               recptr = XLogInsert(RM_BRIN_ID, XLOG_BRIN_REVMAP_EXTEND, rdata);
+
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, SizeOfBrinRevmapExtend);
+               XLogRegisterBuffer(0, revmap->rm_metaBuf, 0);
+
+               XLogRegisterBuffer(1, buf, REGBUF_WILL_INIT);
+
+               recptr = XLogInsert(RM_BRIN_ID, XLOG_BRIN_REVMAP_EXTEND);
                PageSetLSN(metapage, recptr);
                PageSetLSN(page, recptr);
        }
index ebef984e7f161e7870fa3d31d841f631da12abb9..19701a1ad214d433d75699f36f7356a33f7c04e2 100644 (file)
@@ -26,11 +26,8 @@ brin_xlog_createidx(XLogRecPtr lsn, XLogRecord *record)
        Buffer          buf;
        Page            page;
 
-       /* Backup blocks are not used in create_index records */
-       Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
-
        /* create the index' metapage */
-       buf = XLogReadBuffer(xlrec->node, BRIN_METAPAGE_BLKNO, true);
+       XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buf);
        Assert(BufferIsValid(buf));
        page = (Page) BufferGetPage(buf);
        brin_metapage_init(page, xlrec->pagesPerRange, xlrec->version);
@@ -45,48 +42,45 @@ brin_xlog_createidx(XLogRecPtr lsn, XLogRecord *record)
  */
 static void
 brin_xlog_insert_update(XLogRecPtr lsn, XLogRecord *record,
-                                               xl_brin_insert *xlrec, BrinTuple *tuple)
+                                               xl_brin_insert *xlrec)
 {
-       BlockNumber blkno;
        Buffer          buffer;
        Page            page;
        XLogRedoAction action;
 
-       blkno = ItemPointerGetBlockNumber(&xlrec->tid);
-
        /*
         * If we inserted the first and only tuple on the page, re-initialize the
         * page from scratch.
         */
        if (record->xl_info & XLOG_BRIN_INIT_PAGE)
        {
-               XLogReadBufferForRedoExtended(lsn, record, 0,
-                                                                         xlrec->node, MAIN_FORKNUM, blkno,
-                                                                         RBM_ZERO, false, &buffer);
+               XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buffer);
                page = BufferGetPage(buffer);
                brin_page_init(page, BRIN_PAGETYPE_REGULAR);
                action = BLK_NEEDS_REDO;
        }
        else
        {
-               action = XLogReadBufferForRedo(lsn, record, 0,
-                                                                          xlrec->node, blkno, &buffer);
+               action = XLogReadBufferForRedo(lsn, record, 0, &buffer);
        }
 
        /* insert the index item into the page */
        if (action == BLK_NEEDS_REDO)
        {
                OffsetNumber offnum;
+               BrinTuple  *tuple;
+               Size            tuplen;
+
+               tuple = (BrinTuple *) XLogRecGetBlockData(record, 0, &tuplen);
 
                Assert(tuple->bt_blkno == xlrec->heapBlk);
 
                page = (Page) BufferGetPage(buffer);
-               offnum = ItemPointerGetOffsetNumber(&(xlrec->tid));
+               offnum = xlrec->offnum;
                if (PageGetMaxOffsetNumber(page) + 1 < offnum)
                        elog(PANIC, "brin_xlog_insert_update: invalid max offset number");
 
-               offnum = PageAddItem(page, (Item) tuple, xlrec->tuplen, offnum, true,
-                                                        false);
+               offnum = PageAddItem(page, (Item) tuple, tuplen, offnum, true, false);
                if (offnum == InvalidOffsetNumber)
                        elog(PANIC, "brin_xlog_insert_update: failed to add tuple");
 
@@ -97,14 +91,17 @@ brin_xlog_insert_update(XLogRecPtr lsn, XLogRecord *record,
                UnlockReleaseBuffer(buffer);
 
        /* update the revmap */
-       action = XLogReadBufferForRedo(lsn, record, 1, xlrec->node,
-                                                                  xlrec->revmapBlk, &buffer);
+       action = XLogReadBufferForRedo(lsn, record, 1, &buffer);
        if (action == BLK_NEEDS_REDO)
        {
+               ItemPointerData tid;
+               BlockNumber blkno = BufferGetBlockNumber(buffer);
+
+               ItemPointerSet(&tid, blkno, xlrec->offnum);
                page = (Page) BufferGetPage(buffer);
 
                brinSetHeapBlockItemptr(buffer, xlrec->pagesPerRange, xlrec->heapBlk,
-                                                               xlrec->tid);
+                                                               tid);
                PageSetLSN(page, lsn);
                MarkBufferDirty(buffer);
        }
@@ -121,11 +118,8 @@ static void
 brin_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
 {
        xl_brin_insert *xlrec = (xl_brin_insert *) XLogRecGetData(record);
-       BrinTuple  *newtup;
 
-       newtup = (BrinTuple *) ((char *) xlrec + SizeOfBrinInsert);
-
-       brin_xlog_insert_update(lsn, record, xlrec, newtup);
+       brin_xlog_insert_update(lsn, record, xlrec);
 }
 
 /*
@@ -135,17 +129,11 @@ static void
 brin_xlog_update(XLogRecPtr lsn, XLogRecord *record)
 {
        xl_brin_update *xlrec = (xl_brin_update *) XLogRecGetData(record);
-       BlockNumber blkno;
        Buffer          buffer;
-       BrinTuple  *newtup;
        XLogRedoAction action;
 
-       newtup = (BrinTuple *) ((char *) xlrec + SizeOfBrinUpdate);
-
        /* First remove the old tuple */
-       blkno = ItemPointerGetBlockNumber(&(xlrec->oldtid));
-       action = XLogReadBufferForRedo(lsn, record, 2, xlrec->insert.node,
-                                                                  blkno, &buffer);
+       action = XLogReadBufferForRedo(lsn, record, 2, &buffer);
        if (action == BLK_NEEDS_REDO)
        {
                Page            page;
@@ -153,7 +141,7 @@ brin_xlog_update(XLogRecPtr lsn, XLogRecord *record)
 
                page = (Page) BufferGetPage(buffer);
 
-               offnum = ItemPointerGetOffsetNumber(&(xlrec->oldtid));
+               offnum = xlrec->oldOffnum;
                if (PageGetMaxOffsetNumber(page) + 1 < offnum)
                        elog(PANIC, "brin_xlog_update: invalid max offset number");
 
@@ -164,7 +152,7 @@ brin_xlog_update(XLogRecPtr lsn, XLogRecord *record)
        }
 
        /* Then insert the new tuple and update revmap, like in an insertion. */
-       brin_xlog_insert_update(lsn, record, &xlrec->insert, newtup);
+       brin_xlog_insert_update(lsn, record, &xlrec->insert);
 
        if (BufferIsValid(buffer))
                UnlockReleaseBuffer(buffer);
@@ -177,27 +165,23 @@ static void
 brin_xlog_samepage_update(XLogRecPtr lsn, XLogRecord *record)
 {
        xl_brin_samepage_update *xlrec;
-       BlockNumber blkno;
        Buffer          buffer;
        XLogRedoAction action;
 
        xlrec = (xl_brin_samepage_update *) XLogRecGetData(record);
-       blkno = ItemPointerGetBlockNumber(&(xlrec->tid));
-       action = XLogReadBufferForRedo(lsn, record, 0, xlrec->node, blkno,
-                                                                  &buffer);
+       action = XLogReadBufferForRedo(lsn, record, 0, &buffer);
        if (action == BLK_NEEDS_REDO)
        {
-               int                     tuplen;
+               Size            tuplen;
                BrinTuple  *mmtuple;
                Page            page;
                OffsetNumber offnum;
 
-               tuplen = record->xl_len - SizeOfBrinSamepageUpdate;
-               mmtuple = (BrinTuple *) ((char *) xlrec + SizeOfBrinSamepageUpdate);
+               mmtuple = (BrinTuple *) XLogRecGetBlockData(record, 0, &tuplen);
 
                page = (Page) BufferGetPage(buffer);
 
-               offnum = ItemPointerGetOffsetNumber(&(xlrec->tid));
+               offnum = xlrec->offnum;
                if (PageGetMaxOffsetNumber(page) + 1 < offnum)
                        elog(PANIC, "brin_xlog_samepage_update: invalid max offset number");
 
@@ -225,12 +209,16 @@ brin_xlog_revmap_extend(XLogRecPtr lsn, XLogRecord *record)
        Buffer          metabuf;
        Buffer          buf;
        Page            page;
+       BlockNumber targetBlk;
        XLogRedoAction action;
 
        xlrec = (xl_brin_revmap_extend *) XLogRecGetData(record);
+
+       XLogRecGetBlockTag(record, 1, NULL, NULL, &targetBlk);
+       Assert(xlrec->targetBlk == targetBlk);
+
        /* Update the metapage */
-       action = XLogReadBufferForRedo(lsn, record, 0, xlrec->node,
-                                                                  BRIN_METAPAGE_BLKNO, &metabuf);
+       action = XLogReadBufferForRedo(lsn, record, 0, &metabuf);
        if (action == BLK_NEEDS_REDO)
        {
                Page            metapg;
@@ -251,7 +239,7 @@ brin_xlog_revmap_extend(XLogRecPtr lsn, XLogRecord *record)
         * image here.
         */
 
-       buf = XLogReadBuffer(xlrec->node, xlrec->targetBlk, true);
+       XLogReadBufferForRedoExtended(lsn, record, 1, RBM_ZERO, false, &buf);
        page = (Page) BufferGetPage(buf);
        brin_page_init(page, BRIN_PAGETYPE_REVMAP);
 
index 5365477000adc378d865b31f1095957369d0c09f..a241894e726c97b88a0d33b49970e192a0c3757e 100644 (file)
@@ -326,7 +326,6 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
                           Buffer childbuf, GinStatsData *buildStats)
 {
        Page            page = BufferGetPage(stack->buffer);
-       XLogRecData *payloadrdata;
        GinPlaceToPageRC rc;
        uint16          xlflags = 0;
        Page            childpage = NULL;
@@ -351,12 +350,36 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
        /*
         * Try to put the incoming tuple on the page. placeToPage will decide if
         * the page needs to be split.
+        *
+        * WAL-logging this operation is a bit funny:
+        *
+        * We're responsible for calling XLogBeginInsert() and XLogInsert().
+        * XLogBeginInsert() must be called before placeToPage, because placeToPage
+        * register some data to the WAL record.
+        *
+        * If placeToPage returns INSERTED, placeToPage has already called
+        * START_CRIT_SECTION(), and we're responsible for calling
+        * END_CRIT_SECTION. When it returns INSERTED, it is also responsible for
+        * registering any data required to replay the operation with
+        * XLogRegisterData(0, ...). It may only add data to block index 0; the
+        * main data of the WAL record is reserved for this function.
+        *
+        * If placeToPage returns SPLIT, we're wholly responsible for WAL logging.
+        * Splits happen infrequently, so we just make a full-page image of all
+        * the pages involved.
         */
+
+       if (RelationNeedsWAL(btree->index))
+               XLogBeginInsert();
+
        rc = btree->placeToPage(btree, stack->buffer, stack,
                                                        insertdata, updateblkno,
-                                                       &payloadrdata, &newlpage, &newrpage);
+                                                       &newlpage, &newrpage);
        if (rc == UNMODIFIED)
+       {
+               XLogResetInsertion();
                return true;
+       }
        else if (rc == INSERTED)
        {
                /* placeToPage did START_CRIT_SECTION() */
@@ -372,17 +395,18 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
                if (RelationNeedsWAL(btree->index))
                {
                        XLogRecPtr      recptr;
-                       XLogRecData rdata[3];
                        ginxlogInsert xlrec;
                        BlockIdData childblknos[2];
 
-                       xlrec.node = btree->index->rd_node;
-                       xlrec.blkno = BufferGetBlockNumber(stack->buffer);
+                       /*
+                        * placetopage already registered stack->buffer as block 0.
+                        */
                        xlrec.flags = xlflags;
 
-                       rdata[0].buffer = InvalidBuffer;
-                       rdata[0].data = (char *) &xlrec;
-                       rdata[0].len = sizeof(ginxlogInsert);
+                       if (childbuf != InvalidBuffer)
+                               XLogRegisterBuffer(1, childbuf, REGBUF_STANDARD);
+
+                       XLogRegisterData((char *) &xlrec, sizeof(ginxlogInsert));
 
                        /*
                         * Log information about child if this was an insertion of a
@@ -390,26 +414,13 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
                         */
                        if (childbuf != InvalidBuffer)
                        {
-                               rdata[0].next = &rdata[1];
-
                                BlockIdSet(&childblknos[0], BufferGetBlockNumber(childbuf));
                                BlockIdSet(&childblknos[1], GinPageGetOpaque(childpage)->rightlink);
-
-                               rdata[1].buffer = InvalidBuffer;
-                               rdata[1].data = (char *) childblknos;
-                               rdata[1].len = sizeof(BlockIdData) * 2;
-                               rdata[1].next = &rdata[2];
-
-                               rdata[2].buffer = childbuf;
-                               rdata[2].buffer_std = false;
-                               rdata[2].data = NULL;
-                               rdata[2].len = 0;
-                               rdata[2].next = payloadrdata;
+                               XLogRegisterData((char *) childblknos,
+                                                                        sizeof(BlockIdData) * 2);
                        }
-                       else
-                               rdata[0].next = payloadrdata;
 
-                       recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT, rdata);
+                       recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT);
                        PageSetLSN(page, recptr);
                        if (childbuf != InvalidBuffer)
                                PageSetLSN(childpage, recptr);
@@ -421,10 +432,9 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
        }
        else if (rc == SPLIT)
        {
-               /* Didn't fit, have to split */
+               /* Didn't fit, had to split */
                Buffer          rbuffer;
                BlockNumber savedRightLink;
-               XLogRecData rdata[2];
                ginxlogSplit data;
                Buffer          lbuffer = InvalidBuffer;
                Page            newrootpg = NULL;
@@ -448,7 +458,6 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
                 */
 
                data.node = btree->index->rd_node;
-               data.rblkno = BufferGetBlockNumber(rbuffer);
                data.flags = xlflags;
                if (childbuf != InvalidBuffer)
                {
@@ -462,23 +471,6 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
                else
                        data.leftChildBlkno = data.rightChildBlkno = InvalidBlockNumber;
 
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].data = (char *) &data;
-               rdata[0].len = sizeof(ginxlogSplit);
-
-               if (childbuf != InvalidBuffer)
-               {
-                       rdata[0].next = &rdata[1];
-
-                       rdata[1].buffer = childbuf;
-                       rdata[1].buffer_std = false;
-                       rdata[1].data = NULL;
-                       rdata[1].len = 0;
-                       rdata[1].next = payloadrdata;
-               }
-               else
-                       rdata[0].next = payloadrdata;
-
                if (stack->parent == NULL)
                {
                        /*
@@ -496,12 +488,7 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
                                        buildStats->nEntryPages++;
                        }
 
-                       /*
-                        * root never has a right-link, so we borrow the rrlink field to
-                        * store the root block number.
-                        */
-                       data.rrlink = BufferGetBlockNumber(stack->buffer);
-                       data.lblkno = BufferGetBlockNumber(lbuffer);
+                       data.rrlink = InvalidBlockNumber;
                        data.flags |= GIN_SPLIT_ROOT;
 
                        GinPageGetOpaque(newrpage)->rightlink = InvalidBlockNumber;
@@ -524,7 +511,6 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
                {
                        /* split non-root page */
                        data.rrlink = savedRightLink;
-                       data.lblkno = BufferGetBlockNumber(stack->buffer);
 
                        GinPageGetOpaque(newrpage)->rightlink = savedRightLink;
                        GinPageGetOpaque(newlpage)->flags |= GIN_INCOMPLETE_SPLIT;
@@ -572,7 +558,28 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
                {
                        XLogRecPtr      recptr;
 
-                       recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata);
+                       /*
+                        * We just take full page images of all the split pages. Splits
+                        * are uncommon enough that it's not worth complicating the code
+                        * to be more efficient.
+                        */
+                       if (stack->parent == NULL)
+                       {
+                               XLogRegisterBuffer(0, lbuffer, REGBUF_FORCE_IMAGE | REGBUF_STANDARD);
+                               XLogRegisterBuffer(1, rbuffer, REGBUF_FORCE_IMAGE | REGBUF_STANDARD);
+                               XLogRegisterBuffer(2, stack->buffer, REGBUF_FORCE_IMAGE | REGBUF_STANDARD);
+                       }
+                       else
+                       {
+                               XLogRegisterBuffer(0, stack->buffer, REGBUF_FORCE_IMAGE | REGBUF_STANDARD);
+                               XLogRegisterBuffer(1, rbuffer, REGBUF_FORCE_IMAGE | REGBUF_STANDARD);
+                       }
+                       if (BufferIsValid(childbuf))
+                               XLogRegisterBuffer(3, childbuf, 0);
+
+                       XLogRegisterData((char *) &data, sizeof(ginxlogSplit));
+
+                       recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT);
                        PageSetLSN(BufferGetPage(stack->buffer), recptr);
                        PageSetLSN(BufferGetPage(rbuffer), recptr);
                        if (stack->parent == NULL)
index 97cd706c08e58b91c9481c52f30b8af4a1045b6f..685c6fcb3a664204c62c732ad364670c078863e5 100644 (file)
@@ -98,20 +98,19 @@ static ItemPointer dataLeafPageGetUncompressed(Page page, int *nitems);
 static void dataSplitPageInternal(GinBtree btree, Buffer origbuf,
                                          GinBtreeStack *stack,
                                          void *insertdata, BlockNumber updateblkno,
-                                         XLogRecData **prdata, Page *newlpage, Page *newrpage);
+                                         Page *newlpage, Page *newrpage);
 
 static disassembledLeaf *disassembleLeaf(Page page);
 static bool leafRepackItems(disassembledLeaf *leaf, ItemPointer remaining);
 static bool addItemsToLeaf(disassembledLeaf *leaf, ItemPointer newItems,
                           int nNewItems);
 
-static XLogRecData *constructLeafRecompressWALData(Buffer buf,
-                                                          disassembledLeaf *leaf);
+static void registerLeafRecompressWALData(Buffer buf, disassembledLeaf *leaf);
 static void dataPlaceToPageLeafRecompress(Buffer buf, disassembledLeaf *leaf);
 static void dataPlaceToPageLeafSplit(Buffer buf,
                                                 disassembledLeaf *leaf,
                                                 ItemPointerData lbound, ItemPointerData rbound,
-                                                XLogRecData **prdata, Page lpage, Page rpage);
+                                                Page lpage, Page rpage);
 
 /*
  * Read TIDs from leaf data page to single uncompressed array. The TIDs are
@@ -428,8 +427,7 @@ GinPageDeletePostingItem(Page page, OffsetNumber offset)
  */
 static GinPlaceToPageRC
 dataPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack,
-                                       void *insertdata, XLogRecData **prdata,
-                                       Page *newlpage, Page *newrpage)
+                                       void *insertdata, Page *newlpage, Page *newrpage)
 {
        GinBtreeDataLeafInsertData *items = insertdata;
        ItemPointer newItems = &items->items[items->curitem];
@@ -602,9 +600,7 @@ dataPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack,
                 */
                MemoryContextSwitchTo(oldCxt);
                if (RelationNeedsWAL(btree->index))
-                       *prdata = constructLeafRecompressWALData(buf, leaf);
-               else
-                       *prdata = NULL;
+                       registerLeafRecompressWALData(buf, leaf);
                START_CRIT_SECTION();
                dataPlaceToPageLeafRecompress(buf, leaf);
 
@@ -685,7 +681,7 @@ dataPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack,
                *newrpage = MemoryContextAlloc(oldCxt, BLCKSZ);
 
                dataPlaceToPageLeafSplit(buf, leaf, lbound, rbound,
-                                                                prdata, *newlpage, *newrpage);
+                                                                *newlpage, *newrpage);
 
                Assert(GinPageRightMost(page) ||
                           ginCompareItemPointers(GinDataPageGetRightBound(*newlpage),
@@ -791,7 +787,6 @@ ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer, GinVacuumState *gvs)
         */
        if (removedsomething)
        {
-               XLogRecData *payloadrdata = NULL;
                bool            modified;
 
                /*
@@ -818,7 +813,10 @@ ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer, GinVacuumState *gvs)
                }
 
                if (RelationNeedsWAL(indexrel))
-                       payloadrdata = constructLeafRecompressWALData(buffer, leaf);
+               {
+                       XLogBeginInsert();
+                       registerLeafRecompressWALData(buffer, leaf);
+               }
                START_CRIT_SECTION();
                dataPlaceToPageLeafRecompress(buffer, leaf);
 
@@ -827,18 +825,8 @@ ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer, GinVacuumState *gvs)
                if (RelationNeedsWAL(indexrel))
                {
                        XLogRecPtr      recptr;
-                       XLogRecData rdata;
-                       ginxlogVacuumDataLeafPage xlrec;
 
-                       xlrec.node = indexrel->rd_node;
-                       xlrec.blkno = BufferGetBlockNumber(buffer);
-
-                       rdata.buffer = InvalidBuffer;
-                       rdata.data = (char *) &xlrec;
-                       rdata.len = offsetof(ginxlogVacuumDataLeafPage, data);
-                       rdata.next = payloadrdata;
-
-                       recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_VACUUM_DATA_LEAF_PAGE, &rdata);
+                       recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_VACUUM_DATA_LEAF_PAGE);
                        PageSetLSN(page, recptr);
                }
 
@@ -850,13 +838,12 @@ ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer, GinVacuumState *gvs)
  * Construct a ginxlogRecompressDataLeaf record representing the changes
  * in *leaf.
  */
-static XLogRecData *
-constructLeafRecompressWALData(Buffer buf, disassembledLeaf *leaf)
+static void
+registerLeafRecompressWALData(Buffer buf, disassembledLeaf *leaf)
 {
        int                     nmodified = 0;
        char       *walbufbegin;
        char       *walbufend;
-       XLogRecData *rdata;
        dlist_iter      iter;
        int                     segno;
        ginxlogRecompressDataLeaf *recompress_xlog;
@@ -872,11 +859,10 @@ constructLeafRecompressWALData(Buffer buf, disassembledLeaf *leaf)
        }
 
        walbufbegin = palloc(
-                                                sizeof(ginxlogRecompressDataLeaf) +
-                                                BLCKSZ +               /* max size needed to hold the segment
-                                                                                * data */
-                                                nmodified * 2 +                /* (segno + action) per action */
-                                                sizeof(XLogRecData));
+               sizeof(ginxlogRecompressDataLeaf) +
+               BLCKSZ  +               /* max size needed to hold the segment data */
+               nmodified *2            /* (segno + action) per action */
+               );
        walbufend = walbufbegin;
 
        recompress_xlog = (ginxlogRecompressDataLeaf *) walbufend;
@@ -944,14 +930,10 @@ constructLeafRecompressWALData(Buffer buf, disassembledLeaf *leaf)
                        segno++;
        }
 
-       rdata = (XLogRecData *) MAXALIGN(walbufend);
-       rdata->buffer = buf;
-       rdata->buffer_std = TRUE;
-       rdata->data = walbufbegin;
-       rdata->len = walbufend - walbufbegin;
-       rdata->next = NULL;
 
-       return rdata;
+       XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
+       XLogRegisterBufData(0, walbufbegin, walbufend - walbufbegin);
+
 }
 
 /*
@@ -1024,7 +1006,7 @@ dataPlaceToPageLeafRecompress(Buffer buf, disassembledLeaf *leaf)
 static void
 dataPlaceToPageLeafSplit(Buffer buf, disassembledLeaf *leaf,
                                                 ItemPointerData lbound, ItemPointerData rbound,
-                                                XLogRecData **prdata, Page lpage, Page rpage)
+                                                Page lpage, Page rpage)
 {
        char       *ptr;
        int                     segsize;
@@ -1034,10 +1016,6 @@ dataPlaceToPageLeafSplit(Buffer buf, disassembledLeaf *leaf,
        dlist_node *firstright;
        leafSegmentInfo *seginfo;
 
-       /* these must be static so they can be returned to caller */
-       static ginxlogSplitDataLeaf split_xlog;
-       static XLogRecData rdata[3];
-
        /* Initialize temporary pages to hold the new left and right pages */
        GinInitPage(lpage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
        GinInitPage(rpage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
@@ -1092,29 +1070,6 @@ dataPlaceToPageLeafSplit(Buffer buf, disassembledLeaf *leaf,
        Assert(rsize == leaf->rsize);
        GinDataPageSetDataSize(rpage, rsize);
        *GinDataPageGetRightBound(rpage) = rbound;
-
-       /* Create WAL record */
-       split_xlog.lsize = lsize;
-       split_xlog.rsize = rsize;
-       split_xlog.lrightbound = lbound;
-       split_xlog.rrightbound = rbound;
-
-       rdata[0].buffer = InvalidBuffer;
-       rdata[0].data = (char *) &split_xlog;
-       rdata[0].len = sizeof(ginxlogSplitDataLeaf);
-       rdata[0].next = &rdata[1];
-
-       rdata[1].buffer = InvalidBuffer;
-       rdata[1].data = (char *) GinDataLeafPageGetPostingList(lpage);
-       rdata[1].len = lsize;
-       rdata[1].next = &rdata[2];
-
-       rdata[2].buffer = InvalidBuffer;
-       rdata[2].data = (char *) GinDataLeafPageGetPostingList(rpage);
-       rdata[2].len = rsize;
-       rdata[2].next = NULL;
-
-       *prdata = rdata;
 }
 
 /*
@@ -1124,29 +1079,30 @@ dataPlaceToPageLeafSplit(Buffer buf, disassembledLeaf *leaf,
  *
  * In addition to inserting the given item, the downlink of the existing item
  * at 'off' is updated to point to 'updateblkno'.
+ *
+ * On INSERTED, registers the buffer as buffer ID 0, with data.
+ * On SPLIT, returns rdata that represents the split pages in *prdata.
  */
 static GinPlaceToPageRC
 dataPlaceToPageInternal(GinBtree btree, Buffer buf, GinBtreeStack *stack,
                                                void *insertdata, BlockNumber updateblkno,
-                                               XLogRecData **prdata, Page *newlpage, Page *newrpage)
+                                               Page *newlpage, Page *newrpage)
 {
        Page            page = BufferGetPage(buf);
        OffsetNumber off = stack->off;
        PostingItem *pitem;
 
-       /* these must be static so they can be returned to caller */
-       static XLogRecData rdata;
+       /* this must be static so it can be returned to caller */
        static ginxlogInsertDataInternal data;
 
        /* split if we have to */
        if (GinNonLeafDataPageGetFreeSpace(page) < sizeof(PostingItem))
        {
                dataSplitPageInternal(btree, buf, stack, insertdata, updateblkno,
-                                                         prdata, newlpage, newrpage);
+                                                         newlpage, newrpage);
                return SPLIT;
        }
 
-       *prdata = &rdata;
        Assert(GinPageIsData(page));
 
        START_CRIT_SECTION();
@@ -1159,14 +1115,15 @@ dataPlaceToPageInternal(GinBtree btree, Buffer buf, GinBtreeStack *stack,
        pitem = (PostingItem *) insertdata;
        GinDataPageAddPostingItem(page, pitem, off);
 
-       data.offset = off;
-       data.newitem = *pitem;
+       if (RelationNeedsWAL(btree->index))
+       {
+               data.offset = off;
+               data.newitem = *pitem;
 
-       rdata.buffer = buf;
-       rdata.buffer_std = TRUE;
-       rdata.data = (char *) &data;
-       rdata.len = sizeof(ginxlogInsertDataInternal);
-       rdata.next = NULL;
+               XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
+               XLogRegisterBufData(0, (char *) &data,
+                                                       sizeof(ginxlogInsertDataInternal));
+       }
 
        return INSERTED;
 }
@@ -1178,7 +1135,6 @@ dataPlaceToPageInternal(GinBtree btree, Buffer buf, GinBtreeStack *stack,
 static GinPlaceToPageRC
 dataPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack,
                                void *insertdata, BlockNumber updateblkno,
-                               XLogRecData **prdata,
                                Page *newlpage, Page *newrpage)
 {
        Page            page = BufferGetPage(buf);
@@ -1187,11 +1143,11 @@ dataPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack,
 
        if (GinPageIsLeaf(page))
                return dataPlaceToPageLeaf(btree, buf, stack, insertdata,
-                                                                  prdata, newlpage, newrpage);
+                                                                  newlpage, newrpage);
        else
                return dataPlaceToPageInternal(btree, buf, stack,
                                                                           insertdata, updateblkno,
-                                                                          prdata, newlpage, newrpage);
+                                                                          newlpage, newrpage);
 }
 
 /*
@@ -1202,7 +1158,7 @@ static void
 dataSplitPageInternal(GinBtree btree, Buffer origbuf,
                                          GinBtreeStack *stack,
                                          void *insertdata, BlockNumber updateblkno,
-                                         XLogRecData **prdata, Page *newlpage, Page *newrpage)
+                                         Page *newlpage, Page *newrpage)
 {
        Page            oldpage = BufferGetPage(origbuf);
        OffsetNumber off = stack->off;
@@ -1215,19 +1171,13 @@ dataSplitPageInternal(GinBtree btree, Buffer origbuf,
        Page            lpage;
        Page            rpage;
        OffsetNumber separator;
-
-       /* these must be static so they can be returned to caller */
-       static ginxlogSplitDataInternal data;
-       static XLogRecData rdata[4];
-       static PostingItem allitems[(BLCKSZ / sizeof(PostingItem)) + 1];
+       PostingItem allitems[(BLCKSZ / sizeof(PostingItem)) + 1];
 
        lpage = PageGetTempPage(oldpage);
        rpage = PageGetTempPage(oldpage);
        GinInitPage(lpage, GinPageGetOpaque(oldpage)->flags, pageSize);
        GinInitPage(rpage, GinPageGetOpaque(oldpage)->flags, pageSize);
 
-       *prdata = rdata;
-
        /*
         * First construct a new list of PostingItems, which includes all the old
         * items, and the new item.
@@ -1277,20 +1227,6 @@ dataSplitPageInternal(GinBtree btree, Buffer origbuf,
        /* set up right bound for right page */
        *GinDataPageGetRightBound(rpage) = oldbound;
 
-       data.separator = separator;
-       data.nitem = nitems;
-       data.rightbound = oldbound;
-
-       rdata[0].buffer = InvalidBuffer;
-       rdata[0].data = (char *) &data;
-       rdata[0].len = sizeof(ginxlogSplitDataInternal);
-       rdata[0].next = &rdata[1];
-
-       rdata[1].buffer = InvalidBuffer;
-       rdata[1].data = (char *) allitems;
-       rdata[1].len = nitems * sizeof(PostingItem);
-       rdata[1].next = NULL;
-
        *newlpage = lpage;
        *newrpage = rpage;
 }
@@ -1797,24 +1733,18 @@ createPostingTree(Relation index, ItemPointerData *items, uint32 nitems,
        if (RelationNeedsWAL(index))
        {
                XLogRecPtr      recptr;
-               XLogRecData rdata[2];
                ginxlogCreatePostingTree data;
 
-               data.node = index->rd_node;
-               data.blkno = blkno;
                data.size = rootsize;
 
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].data = (char *) &data;
-               rdata[0].len = sizeof(ginxlogCreatePostingTree);
-               rdata[0].next = &rdata[1];
+               XLogBeginInsert();
+               XLogRegisterData((char *) &data, sizeof(ginxlogCreatePostingTree));
 
-               rdata[1].buffer = InvalidBuffer;
-               rdata[1].data = (char *) GinDataLeafPageGetPostingList(page);
-               rdata[1].len = rootsize;
-               rdata[1].next = NULL;
+               XLogRegisterData((char *) GinDataLeafPageGetPostingList(page),
+                                                rootsize);
+               XLogRegisterBuffer(0, buffer, REGBUF_WILL_INIT);
 
-               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_PTREE, rdata);
+               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_PTREE);
                PageSetLSN(page, recptr);
        }
 
index 84dc1e228c1436e85b3b6c8589e594c7ce11616c..c73b15fc8c585df442d50a5c78bbc4c6f6513840 100644 (file)
@@ -22,7 +22,7 @@
 static void entrySplitPage(GinBtree btree, Buffer origbuf,
                           GinBtreeStack *stack,
                           void *insertPayload,
-                          BlockNumber updateblkno, XLogRecData **prdata,
+                          BlockNumber updateblkno,
                           Page *newlpage, Page *newrpage);
 
 /*
@@ -515,33 +515,36 @@ entryPreparePage(GinBtree btree, Page page, OffsetNumber off,
  * On insertion to an internal node, in addition to inserting the given item,
  * the downlink of the existing item at 'off' is updated to point to
  * 'updateblkno'.
+ *
+ * On INSERTED, registers the buffer as buffer ID 0, with data.
+ * On SPLIT, returns rdata that represents the split pages in *prdata.
  */
 static GinPlaceToPageRC
 entryPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack,
                                 void *insertPayload, BlockNumber updateblkno,
-                                XLogRecData **prdata, Page *newlpage, Page *newrpage)
+                                Page *newlpage, Page *newrpage)
 {
        GinBtreeEntryInsertData *insertData = insertPayload;
        Page            page = BufferGetPage(buf);
        OffsetNumber off = stack->off;
        OffsetNumber placed;
-       int                     cnt = 0;
 
-       /* these must be static so they can be returned to caller */
-       static XLogRecData rdata[3];
+       /*
+        * this must be static so it can be returned to caller. XXX: If we
+        * can rely on XLogRegisterData to copy the data, this isn't necessary
+        */
        static ginxlogInsertEntry data;
 
        /* quick exit if it doesn't fit */
        if (!entryIsEnoughSpace(btree, buf, off, insertData))
        {
                entrySplitPage(btree, buf, stack, insertPayload, updateblkno,
-                                          prdata, newlpage, newrpage);
+                                          newlpage, newrpage);
                return SPLIT;
        }
 
        START_CRIT_SECTION();
 
-       *prdata = rdata;
        entryPreparePage(btree, page, off, insertData, updateblkno);
 
        placed = PageAddItem(page,
@@ -552,21 +555,17 @@ entryPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack,
                elog(ERROR, "failed to add item to index page in \"%s\"",
                         RelationGetRelationName(btree->index));
 
-       data.isDelete = insertData->isDelete;
-       data.offset = off;
-
-       rdata[cnt].buffer = buf;
-       rdata[cnt].buffer_std = true;
-       rdata[cnt].data = (char *) &data;
-       rdata[cnt].len = offsetof(ginxlogInsertEntry, tuple);
-       rdata[cnt].next = &rdata[cnt + 1];
-       cnt++;
-
-       rdata[cnt].buffer = buf;
-       rdata[cnt].buffer_std = true;
-       rdata[cnt].data = (char *) insertData->entry;
-       rdata[cnt].len = IndexTupleSize(insertData->entry);
-       rdata[cnt].next = NULL;
+       if (RelationNeedsWAL(btree->index))
+       {
+               data.isDelete = insertData->isDelete;
+               data.offset = off;
+
+               XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
+               XLogRegisterBufData(0, (char *) &data,
+                                                       offsetof(ginxlogInsertEntry, tuple));
+               XLogRegisterBufData(0, (char *) insertData->entry,
+                                                       IndexTupleSize(insertData->entry));
+       }
 
        return INSERTED;
 }
@@ -581,7 +580,7 @@ static void
 entrySplitPage(GinBtree btree, Buffer origbuf,
                           GinBtreeStack *stack,
                           void *insertPayload,
-                          BlockNumber updateblkno, XLogRecData **prdata,
+                          BlockNumber updateblkno,
                           Page *newlpage, Page *newrpage)
 {
        GinBtreeEntryInsertData *insertData = insertPayload;
@@ -590,7 +589,6 @@ entrySplitPage(GinBtree btree, Buffer origbuf,
                                maxoff,
                                separator = InvalidOffsetNumber;
        Size            totalsize = 0;
-       Size            tupstoresize;
        Size            lsize = 0,
                                size;
        char       *ptr;
@@ -599,13 +597,8 @@ entrySplitPage(GinBtree btree, Buffer origbuf,
        Page            lpage = PageGetTempPageCopy(BufferGetPage(origbuf));
        Page            rpage = PageGetTempPageCopy(BufferGetPage(origbuf));
        Size            pageSize = PageGetPageSize(lpage);
+       char            tupstore[2 * BLCKSZ];
 
-       /* these must be static so they can be returned to caller */
-       static XLogRecData rdata[2];
-       static ginxlogSplitEntry data;
-       static char tupstore[2 * BLCKSZ];
-
-       *prdata = rdata;
        entryPreparePage(btree, lpage, off, insertData, updateblkno);
 
        /*
@@ -638,7 +631,6 @@ entrySplitPage(GinBtree btree, Buffer origbuf,
                ptr += size;
                totalsize += size + sizeof(ItemIdData);
        }
-       tupstoresize = ptr - tupstore;
 
        /*
         * Initialize the left and right pages, and copy all the tuples back to
@@ -673,19 +665,6 @@ entrySplitPage(GinBtree btree, Buffer origbuf,
                ptr += MAXALIGN(IndexTupleSize(itup));
        }
 
-       data.separator = separator;
-       data.nitem = maxoff;
-
-       rdata[0].buffer = InvalidBuffer;
-       rdata[0].data = (char *) &data;
-       rdata[0].len = sizeof(ginxlogSplitEntry);
-       rdata[0].next = &rdata[1];
-
-       rdata[1].buffer = InvalidBuffer;
-       rdata[1].data = tupstore;
-       rdata[1].len = tupstoresize;
-       rdata[1].next = NULL;
-
        *newlpage = lpage;
        *newrpage = rpage;
 }
index ed581977f54079e19e85ad51a7765ac09f073c6c..32c8cb1ae4288068ecdce97649097c1fc9346343 100644 (file)
@@ -106,26 +106,19 @@ writeListPage(Relation index, Buffer buffer,
 
        if (RelationNeedsWAL(index))
        {
-               XLogRecData rdata[2];
                ginxlogInsertListPage data;
                XLogRecPtr      recptr;
 
-               data.node = index->rd_node;
-               data.blkno = BufferGetBlockNumber(buffer);
                data.rightlink = rightlink;
                data.ntuples = ntuples;
 
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].data = (char *) &data;
-               rdata[0].len = sizeof(ginxlogInsertListPage);
-               rdata[0].next = rdata + 1;
+               XLogBeginInsert();
+               XLogRegisterData((char *) &data, sizeof(ginxlogInsertListPage));
 
-               rdata[1].buffer = InvalidBuffer;
-               rdata[1].data = workspace;
-               rdata[1].len = size;
-               rdata[1].next = NULL;
+               XLogRegisterBuffer(0, buffer, REGBUF_WILL_INIT);
+               XLogRegisterBufData(0, workspace, size);
 
-               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT_LISTPAGE, rdata);
+               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT_LISTPAGE);
                PageSetLSN(page, recptr);
        }
 
@@ -222,25 +215,22 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
        Buffer          metabuffer;
        Page            metapage;
        GinMetaPageData *metadata = NULL;
-       XLogRecData rdata[2];
        Buffer          buffer = InvalidBuffer;
        Page            page = NULL;
        ginxlogUpdateMeta data;
        bool            separateList = false;
        bool            needCleanup = false;
+       bool            needWal;
 
        if (collector->ntuples == 0)
                return;
 
+       needWal = RelationNeedsWAL(index);
+
        data.node = index->rd_node;
        data.ntuples = 0;
        data.newRightlink = data.prevTail = InvalidBlockNumber;
 
-       rdata[0].buffer = InvalidBuffer;
-       rdata[0].data = (char *) &data;
-       rdata[0].len = sizeof(ginxlogUpdateMeta);
-       rdata[0].next = NULL;
-
        metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
        metapage = BufferGetPage(metabuffer);
 
@@ -280,6 +270,9 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
                memset(&sublist, 0, sizeof(GinMetaPageData));
                makeSublist(index, collector->tuples, collector->ntuples, &sublist);
 
+               if (needWal)
+                       XLogBeginInsert();
+
                /*
                 * metapage was unlocked, see above
                 */
@@ -312,14 +305,6 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
                        LockBuffer(buffer, GIN_EXCLUSIVE);
                        page = BufferGetPage(buffer);
 
-                       rdata[0].next = rdata + 1;
-
-                       rdata[1].buffer = buffer;
-                       rdata[1].buffer_std = true;
-                       rdata[1].data = NULL;
-                       rdata[1].len = 0;
-                       rdata[1].next = NULL;
-
                        Assert(GinPageGetOpaque(page)->rightlink == InvalidBlockNumber);
 
                        START_CRIT_SECTION();
@@ -333,6 +318,9 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
 
                        metadata->nPendingPages += sublist.nPendingPages;
                        metadata->nPendingHeapTuples += sublist.nPendingHeapTuples;
+
+                       if (needWal)
+                               XLogRegisterBuffer(1, buffer, REGBUF_STANDARD);
                }
        }
        else
@@ -345,6 +333,7 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
                int                     i,
                                        tupsize;
                char       *ptr;
+               char       *collectordata;
 
                buffer = ReadBuffer(index, metadata->tail);
                LockBuffer(buffer, GIN_EXCLUSIVE);
@@ -353,16 +342,13 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
                off = (PageIsEmpty(page)) ? FirstOffsetNumber :
                        OffsetNumberNext(PageGetMaxOffsetNumber(page));
 
-               rdata[0].next = rdata + 1;
-
-               rdata[1].buffer = buffer;
-               rdata[1].buffer_std = true;
-               ptr = rdata[1].data = (char *) palloc(collector->sumsize);
-               rdata[1].len = collector->sumsize;
-               rdata[1].next = NULL;
+               collectordata = ptr = (char *) palloc(collector->sumsize);
 
                data.ntuples = collector->ntuples;
 
+               if (needWal)
+                       XLogBeginInsert();
+
                START_CRIT_SECTION();
 
                /*
@@ -387,7 +373,12 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
                        off++;
                }
 
-               Assert((ptr - rdata[1].data) <= collector->sumsize);
+               Assert((ptr - collectordata) <= collector->sumsize);
+               if (needWal)
+               {
+                       XLogRegisterBuffer(1, buffer, REGBUF_STANDARD);
+                       XLogRegisterBufData(1, collectordata, collector->sumsize);
+               }
 
                metadata->tailFreeSize = PageGetExactFreeSpace(page);
 
@@ -399,13 +390,16 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
         */
        MarkBufferDirty(metabuffer);
 
-       if (RelationNeedsWAL(index))
+       if (needWal)
        {
                XLogRecPtr      recptr;
 
                memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
 
-               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE, rdata);
+               XLogRegisterBuffer(0, metabuffer, REGBUF_WILL_INIT);
+               XLogRegisterData((char *) &data, sizeof(ginxlogUpdateMeta));
+
+               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE);
                PageSetLSN(metapage, recptr);
 
                if (buffer != InvalidBuffer)
@@ -521,20 +515,11 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
                int                     i;
                int64           nDeletedHeapTuples = 0;
                ginxlogDeleteListPages data;
-               XLogRecData rdata[1];
                Buffer          buffers[GIN_NDELETE_AT_ONCE];
 
-               data.node = index->rd_node;
-
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].data = (char *) &data;
-               rdata[0].len = sizeof(ginxlogDeleteListPages);
-               rdata[0].next = NULL;
-
                data.ndeleted = 0;
                while (data.ndeleted < GIN_NDELETE_AT_ONCE && blknoToDelete != newHead)
                {
-                       data.toDelete[data.ndeleted] = blknoToDelete;
                        buffers[data.ndeleted] = ReadBuffer(index, blknoToDelete);
                        LockBuffer(buffers[data.ndeleted], GIN_EXCLUSIVE);
                        page = BufferGetPage(buffers[data.ndeleted]);
@@ -557,6 +542,13 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
                if (stats)
                        stats->pages_deleted += data.ndeleted;
 
+               /*
+                * This operation touches an unusually large number of pages, so
+                * prepare the XLogInsert machinery for that before entering the
+                * critical section.
+                */
+               XLogEnsureRecordSpace(data.ndeleted + 1, 0);
+
                START_CRIT_SECTION();
 
                metadata->head = blknoToDelete;
@@ -587,9 +579,17 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
                {
                        XLogRecPtr      recptr;
 
+                       XLogBeginInsert();
+                       XLogRegisterBuffer(0, metabuffer, REGBUF_WILL_INIT);
+                       for (i = 0; i < data.ndeleted; i++)
+                               XLogRegisterBuffer(i + 1, buffers[i], REGBUF_WILL_INIT);
+
                        memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
 
-                       recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_LISTPAGE, rdata);
+                       XLogRegisterData((char *) &data,
+                                                        sizeof(ginxlogDeleteListPages));
+
+                       recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_LISTPAGE);
                        PageSetLSN(metapage, recptr);
 
                        for (i = 0; i < data.ndeleted; i++)
index 370884ed17fee19a8bfda824ce27e5b18f405137..c1ad0fd8c4db24b244d71679c9418d22a3c01f83 100644 (file)
@@ -347,15 +347,13 @@ ginbuild(PG_FUNCTION_ARGS)
        if (RelationNeedsWAL(index))
        {
                XLogRecPtr      recptr;
-               XLogRecData rdata;
                Page            page;
 
-               rdata.buffer = InvalidBuffer;
-               rdata.data = (char *) &(index->rd_node);
-               rdata.len = sizeof(RelFileNode);
-               rdata.next = NULL;
+               XLogBeginInsert();
+               XLogRegisterBuffer(0, MetaBuffer, REGBUF_WILL_INIT);
+               XLogRegisterBuffer(1, RootBuffer, REGBUF_WILL_INIT);
 
-               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_INDEX, &rdata);
+               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_INDEX);
 
                page = BufferGetPage(RootBuffer);
                PageSetLSN(page, recptr);
index 1f8db9de6d94bb7cfaf0de4d5faa4da010d5468c..1f4bd64cd4d85f6939146741efb59fb36a729934 100644 (file)
@@ -603,19 +603,17 @@ ginUpdateStats(Relation index, const GinStatsData *stats)
        {
                XLogRecPtr      recptr;
                ginxlogUpdateMeta data;
-               XLogRecData rdata;
 
                data.node = index->rd_node;
                data.ntuples = 0;
                data.newRightlink = data.prevTail = InvalidBlockNumber;
                memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
 
-               rdata.buffer = InvalidBuffer;
-               rdata.data = (char *) &data;
-               rdata.len = sizeof(ginxlogUpdateMeta);
-               rdata.next = NULL;
+               XLogBeginInsert();
+               XLogRegisterData((char *) &data, sizeof(ginxlogUpdateMeta));
+               XLogRegisterBuffer(0, metabuffer, REGBUF_WILL_INIT);
 
-               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE, &rdata);
+               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE);
                PageSetLSN(metapage, recptr);
        }
 
index 3a61321a835d984a7cc9365bfadc63d9a884918a..6a00383622b7ce6978f391f3c4b9ebb487f09b2c 100644 (file)
@@ -89,10 +89,6 @@ xlogVacuumPage(Relation index, Buffer buffer)
 {
        Page            page = BufferGetPage(buffer);
        XLogRecPtr      recptr;
-       XLogRecData rdata[3];
-       ginxlogVacuumPage xlrec;
-       uint16          lower;
-       uint16          upper;
 
        /* This is only used for entry tree leaf pages. */
        Assert(!GinPageIsData(page));
@@ -101,57 +97,14 @@ xlogVacuumPage(Relation index, Buffer buffer)
        if (!RelationNeedsWAL(index))
                return;
 
-       xlrec.node = index->rd_node;
-       xlrec.blkno = BufferGetBlockNumber(buffer);
-
-       /* Assume we can omit data between pd_lower and pd_upper */
-       lower = ((PageHeader) page)->pd_lower;
-       upper = ((PageHeader) page)->pd_upper;
-
-       Assert(lower < BLCKSZ);
-       Assert(upper < BLCKSZ);
-
-       if (lower >= SizeOfPageHeaderData &&
-               upper > lower &&
-               upper <= BLCKSZ)
-       {
-               xlrec.hole_offset = lower;
-               xlrec.hole_length = upper - lower;
-       }
-       else
-       {
-               /* No "hole" to compress out */
-               xlrec.hole_offset = 0;
-               xlrec.hole_length = 0;
-       }
-
-       rdata[0].data = (char *) &xlrec;
-       rdata[0].len = sizeof(ginxlogVacuumPage);
-       rdata[0].buffer = InvalidBuffer;
-       rdata[0].next = &rdata[1];
-
-       if (xlrec.hole_length == 0)
-       {
-               rdata[1].data = (char *) page;
-               rdata[1].len = BLCKSZ;
-               rdata[1].buffer = InvalidBuffer;
-               rdata[1].next = NULL;
-       }
-       else
-       {
-               /* must skip the hole */
-               rdata[1].data = (char *) page;
-               rdata[1].len = xlrec.hole_offset;
-               rdata[1].buffer = InvalidBuffer;
-               rdata[1].next = &rdata[2];
-
-               rdata[2].data = (char *) page + (xlrec.hole_offset + xlrec.hole_length);
-               rdata[2].len = BLCKSZ - (xlrec.hole_offset + xlrec.hole_length);
-               rdata[2].buffer = InvalidBuffer;
-               rdata[2].next = NULL;
-       }
+       /*
+        * Always create a full-page, we don't track the changes on the page
+        * at any more fine-grained level. This could obviously be improved...
+        */
+       XLogBeginInsert();
+       XLogRegisterBuffer(0, buffer, REGBUF_FORCE_IMAGE | REGBUF_STANDARD);
 
-       recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_VACUUM_PAGE, rdata);
+       recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_VACUUM_PAGE);
        PageSetLSN(page, recptr);
 }
 
@@ -292,48 +245,26 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
        if (RelationNeedsWAL(gvs->index))
        {
                XLogRecPtr      recptr;
-               XLogRecData rdata[4];
                ginxlogDeletePage data;
 
-               data.node = gvs->index->rd_node;
-               data.blkno = deleteBlkno;
-               data.parentBlkno = parentBlkno;
+               /*
+                * We can't pass REGBUF_STANDARD for the deleted page, because we
+                * didn't set pd_lower on pre-9.4 versions. The page might've been
+                * binary-upgraded from an older version, and hence not have pd_lower
+                * set correctly. Ditto for the left page, but removing the item from
+                * the parent updated its pd_lower, so we know that's OK at this point.
+                */
+               XLogBeginInsert();
+               XLogRegisterBuffer(0, dBuffer, 0);
+               XLogRegisterBuffer(1, pBuffer, REGBUF_STANDARD);
+               XLogRegisterBuffer(2, lBuffer, 0);
+
                data.parentOffset = myoff;
-               data.leftBlkno = leftBlkno;
                data.rightLink = GinPageGetOpaque(page)->rightlink;
 
-               /*
-                * We can't pass buffer_std = TRUE, because we didn't set pd_lower on
-                * pre-9.4 versions. The page might've been binary-upgraded from an
-                * older version, and hence not have pd_lower set correctly. Ditto for
-                * the left page, but removing the item from the parent updated its
-                * pd_lower, so we know that's OK at this point.
-                */
-               rdata[0].buffer = dBuffer;
-               rdata[0].buffer_std = FALSE;
-               rdata[0].data = NULL;
-               rdata[0].len = 0;
-               rdata[0].next = rdata + 1;
-
-               rdata[1].buffer = pBuffer;
-               rdata[1].buffer_std = TRUE;
-               rdata[1].data = NULL;
-               rdata[1].len = 0;
-               rdata[1].next = rdata + 2;
-
-               rdata[2].buffer = lBuffer;
-               rdata[2].buffer_std = FALSE;
-               rdata[2].data = NULL;
-               rdata[2].len = 0;
-               rdata[2].next = rdata + 3;
-
-               rdata[3].buffer = InvalidBuffer;
-               rdata[3].buffer_std = FALSE;
-               rdata[3].len = sizeof(ginxlogDeletePage);
-               rdata[3].data = (char *) &data;
-               rdata[3].next = NULL;
-
-               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_PAGE, rdata);
+               XLogRegisterData((char *) &data, sizeof(ginxlogDeletePage));
+
+               recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_PAGE);
                PageSetLSN(page, recptr);
                PageSetLSN(parentPage, recptr);
                PageSetLSN(BufferGetPage(lBuffer), recptr);
index d0553bb8f729753bf39099a3841105a107274559..a7a66d885992590b32793b0c71b751e69299f7e7 100644 (file)
 static MemoryContext opCtx;            /* working memory for operations */
 
 static void
-ginRedoClearIncompleteSplit(XLogRecPtr lsn, XLogRecord *record,
-                                                       int block_index,
-                                                       RelFileNode node, BlockNumber blkno)
+ginRedoClearIncompleteSplit(XLogRecPtr lsn, XLogRecord *record, uint8 block_id)
 {
        Buffer          buffer;
        Page            page;
 
-       if (XLogReadBufferForRedo(lsn, record, block_index, node, blkno, &buffer)
-               == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, block_id, &buffer) == BLK_NEEDS_REDO)
        {
                page = (Page) BufferGetPage(buffer);
-
                GinPageGetOpaque(page)->flags &= ~GIN_INCOMPLETE_SPLIT;
 
                PageSetLSN(page, lsn);
@@ -44,16 +40,12 @@ ginRedoClearIncompleteSplit(XLogRecPtr lsn, XLogRecord *record,
 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));
+       XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &MetaBuffer);
+       Assert(BufferGetBlockNumber(MetaBuffer) == GIN_METAPAGE_BLKNO);
        page = (Page) BufferGetPage(MetaBuffer);
 
        GinInitMetabuffer(MetaBuffer);
@@ -61,8 +53,8 @@ ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record)
        PageSetLSN(page, lsn);
        MarkBufferDirty(MetaBuffer);
 
-       RootBuffer = XLogReadBuffer(*node, GIN_ROOT_BLKNO, true);
-       Assert(BufferIsValid(RootBuffer));
+       XLogReadBufferForRedoExtended(lsn, record, 1, RBM_ZERO, false, &RootBuffer);
+       Assert(BufferGetBlockNumber(RootBuffer) == GIN_ROOT_BLKNO);
        page = (Page) BufferGetPage(RootBuffer);
 
        GinInitBuffer(RootBuffer, GIN_LEAF);
@@ -82,11 +74,7 @@ ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record)
        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));
+       XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buffer);
        page = (Page) BufferGetPage(buffer);
 
        GinInitBuffer(buffer, GIN_DATA | GIN_LEAF | GIN_COMPRESSED);
@@ -332,31 +320,35 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record)
 {
        ginxlogInsert *data = (ginxlogInsert *) XLogRecGetData(record);
        Buffer          buffer;
-       char       *payload;
+#ifdef NOT_USED
        BlockNumber leftChildBlkno = InvalidBlockNumber;
+#endif
        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)
        {
+               char       *payload = XLogRecGetData(record) + sizeof(ginxlogInsert);
+
+#ifdef NOT_USED
                leftChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
+#endif
                payload += sizeof(BlockIdData);
                rightChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
                payload += sizeof(BlockIdData);
 
-               ginRedoClearIncompleteSplit(lsn, record, 0, data->node, leftChildBlkno);
+               ginRedoClearIncompleteSplit(lsn, record, 1);
        }
 
-       if (XLogReadBufferForRedo(lsn, record, isLeaf ? 0 : 1, data->node,
-                                                         data->blkno, &buffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
        {
                Page            page = BufferGetPage(buffer);
+               Size            len;
+               char       *payload = XLogRecGetBlockData(record, 0, &len);
 
                /* How to insert the payload is tree-type specific */
                if (data->flags & GIN_INSERT_ISDATA)
@@ -377,162 +369,34 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record)
                UnlockReleaseBuffer(buffer);
 }
 
-static void
-ginRedoSplitEntry(Page lpage, Page rpage, void *rdata)
-{
-       ginxlogSplitEntry *data = (ginxlogSplitEntry *) rdata;
-       IndexTuple      itup = (IndexTuple) ((char *) rdata + sizeof(ginxlogSplitEntry));
-       OffsetNumber i;
-
-       for (i = 0; i < data->separator; i++)
-       {
-               if (PageAddItem(lpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
-                       elog(ERROR, "failed to add item to gin index page");
-               itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
-       }
-
-       for (i = data->separator; i < data->nitem; i++)
-       {
-               if (PageAddItem(rpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
-                       elog(ERROR, "failed to add item to gin index page");
-               itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
-       }
-}
-
-static void
-ginRedoSplitData(Page lpage, Page rpage, void *rdata)
-{
-       bool            isleaf = GinPageIsLeaf(lpage);
-
-       if (isleaf)
-       {
-               ginxlogSplitDataLeaf *data = (ginxlogSplitDataLeaf *) rdata;
-               Pointer         lptr = (Pointer) rdata + sizeof(ginxlogSplitDataLeaf);
-               Pointer         rptr = lptr + data->lsize;
-
-               Assert(data->lsize > 0 && data->lsize <= GinDataPageMaxDataSize);
-               Assert(data->rsize > 0 && data->rsize <= GinDataPageMaxDataSize);
-
-               memcpy(GinDataLeafPageGetPostingList(lpage), lptr, data->lsize);
-               memcpy(GinDataLeafPageGetPostingList(rpage), rptr, data->rsize);
-
-               GinDataPageSetDataSize(lpage, data->lsize);
-               GinDataPageSetDataSize(rpage, data->rsize);
-               *GinDataPageGetRightBound(lpage) = data->lrightbound;
-               *GinDataPageGetRightBound(rpage) = data->rrightbound;
-       }
-       else
-       {
-               ginxlogSplitDataInternal *data = (ginxlogSplitDataInternal *) rdata;
-               PostingItem *items = (PostingItem *) ((char *) rdata + sizeof(ginxlogSplitDataInternal));
-               OffsetNumber i;
-               OffsetNumber maxoff;
-
-               for (i = 0; i < data->separator; i++)
-                       GinDataPageAddPostingItem(lpage, &items[i], InvalidOffsetNumber);
-               for (i = data->separator; i < data->nitem; i++)
-                       GinDataPageAddPostingItem(rpage, &items[i], InvalidOffsetNumber);
-
-               /* set up right key */
-               maxoff = GinPageGetOpaque(lpage)->maxoff;
-               *GinDataPageGetRightBound(lpage) = GinDataPageGetPostingItem(lpage, maxoff)->key;
-               *GinDataPageGetRightBound(rpage) = data->rightbound;
-       }
-}
-
 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;
+                               rbuffer,
+                               rootbuf;
        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)
-               ginRedoClearIncompleteSplit(lsn, record, 0, 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);
+               ginRedoClearIncompleteSplit(lsn, record, 3);
 
-       PageSetLSN(rpage, lsn);
-       MarkBufferDirty(rbuffer);
+       if (XLogReadBufferForRedo(lsn, record, 0, &lbuffer) != BLK_RESTORED)
+               elog(ERROR, "GIN split record did not contain a full-page image of left page");
 
-       PageSetLSN(lpage, lsn);
-       MarkBufferDirty(lbuffer);
+       if (XLogReadBufferForRedo(lsn, record, 1, &rbuffer) != BLK_RESTORED)
+               elog(ERROR, "GIN split record did not contain a full-page image of right page");
 
        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);
+               if (XLogReadBufferForRedo(lsn, record, 2, &rootbuf) != BLK_RESTORED)
+                       elog(ERROR, "GIN split record did not contain a full-page image of root page");
+               UnlockReleaseBuffer(rootbuf);
        }
 
        UnlockReleaseBuffer(rbuffer);
@@ -546,52 +410,27 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record)
 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)
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) != BLK_RESTORED)
        {
-               memcpy((char *) page, blk, BLCKSZ);
+               elog(ERROR, "replay of gin entry tree page vacuum did not restore the page");
        }
-       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
 ginRedoVacuumDataLeafPage(XLogRecPtr lsn, XLogRecord *record)
 {
-       ginxlogVacuumDataLeafPage *xlrec = (ginxlogVacuumDataLeafPage *) XLogRecGetData(record);
        Buffer          buffer;
 
-       if (XLogReadBufferForRedo(lsn, record, 0, xlrec->node, xlrec->blkno,
-                                                         &buffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
        {
                Page            page = BufferGetPage(buffer);
+               Size            len;
+               ginxlogVacuumDataLeafPage *xlrec;
+
+               xlrec = (ginxlogVacuumDataLeafPage *) XLogRecGetBlockData(record, 0, &len);
 
                Assert(GinPageIsLeaf(page));
                Assert(GinPageIsData(page));
@@ -613,22 +452,18 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record)
        Buffer          lbuffer;
        Page            page;
 
-       if (XLogReadBufferForRedo(lsn, record, 0, data->node, data->blkno, &dbuffer)
-               == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 0, &dbuffer) == BLK_NEEDS_REDO)
        {
                page = BufferGetPage(dbuffer);
-
                Assert(GinPageIsData(page));
                GinPageGetOpaque(page)->flags = GIN_DELETED;
                PageSetLSN(page, lsn);
                MarkBufferDirty(dbuffer);
        }
 
-       if (XLogReadBufferForRedo(lsn, record, 1, data->node, data->parentBlkno,
-                                                         &pbuffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 1, &pbuffer) == BLK_NEEDS_REDO)
        {
                page = BufferGetPage(pbuffer);
-
                Assert(GinPageIsData(page));
                Assert(!GinPageIsLeaf(page));
                GinPageDeletePostingItem(page, data->parentOffset);
@@ -636,11 +471,9 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record)
                MarkBufferDirty(pbuffer);
        }
 
-       if (XLogReadBufferForRedo(lsn, record, 2, data->node, data->leftBlkno,
-                                                         &lbuffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 2, &lbuffer) == BLK_NEEDS_REDO)
        {
                page = BufferGetPage(lbuffer);
-
                Assert(GinPageIsData(page));
                GinPageGetOpaque(page)->rightlink = data->rightLink;
                PageSetLSN(page, lsn);
@@ -668,9 +501,8 @@ ginRedoUpdateMetapage(XLogRecPtr lsn, XLogRecord *record)
         * 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 */
+       XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &metabuffer);
+       Assert(BufferGetBlockNumber(metabuffer) == GIN_METAPAGE_BLKNO);
        metapage = BufferGetPage(metabuffer);
 
        memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
@@ -682,17 +514,18 @@ ginRedoUpdateMetapage(XLogRecPtr lsn, XLogRecord *record)
                /*
                 * insert into tail page
                 */
-               if (XLogReadBufferForRedo(lsn, record, 0, data->node,
-                                                                 data->metadata.tail, &buffer)
-                       == BLK_NEEDS_REDO)
+               if (XLogReadBufferForRedo(lsn, record, 1, &buffer) == BLK_NEEDS_REDO)
                {
                        Page            page = BufferGetPage(buffer);
                        OffsetNumber off;
                        int                     i;
                        Size            tupsize;
+                       char       *payload;
                        IndexTuple      tuples;
+                       Size            totaltupsize;
 
-                       tuples = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogUpdateMeta));
+                       payload = XLogRecGetBlockData(record, 1, &totaltupsize);
+                       tuples = (IndexTuple) payload;
 
                        if (PageIsEmpty(page))
                                off = FirstOffsetNumber;
@@ -711,6 +544,7 @@ ginRedoUpdateMetapage(XLogRecPtr lsn, XLogRecord *record)
 
                                off++;
                        }
+                       Assert(payload + totaltupsize == (char *) tuples);
 
                        /*
                         * Increase counter of heap tuples
@@ -728,8 +562,7 @@ ginRedoUpdateMetapage(XLogRecPtr lsn, XLogRecord *record)
                /*
                 * New tail
                 */
-               if (XLogReadBufferForRedo(lsn, record, 0, data->node, data->prevTail,
-                                                                 &buffer) == BLK_NEEDS_REDO)
+               if (XLogReadBufferForRedo(lsn, record, 1, &buffer) == BLK_NEEDS_REDO)
                {
                        Page            page = BufferGetPage(buffer);
 
@@ -755,15 +588,12 @@ ginRedoInsertListPage(XLogRecPtr lsn, XLogRecord *record)
                                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));
+       char       *payload;
+       IndexTuple      tuples;
+       Size            totaltupsize;
 
-       buffer = XLogReadBuffer(data->node, data->blkno, true);
-       Assert(BufferIsValid(buffer));
+       /* We always re-initialize the page. */
+       XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buffer);
        page = BufferGetPage(buffer);
 
        GinInitBuffer(buffer, GIN_LIST);
@@ -779,6 +609,9 @@ ginRedoInsertListPage(XLogRecPtr lsn, XLogRecord *record)
                GinPageGetOpaque(page)->maxoff = 0;
        }
 
+       payload = XLogRecGetBlockData(record, 0, &totaltupsize);
+
+       tuples = (IndexTuple) payload;
        for (i = 0; i < data->ntuples; i++)
        {
                tupsize = IndexTupleSize(tuples);
@@ -791,6 +624,7 @@ ginRedoInsertListPage(XLogRecPtr lsn, XLogRecord *record)
                tuples = (IndexTuple) (((char *) tuples) + tupsize);
                off++;
        }
+       Assert((char *) tuples == payload + totaltupsize);
 
        PageSetLSN(page, lsn);
        MarkBufferDirty(buffer);
@@ -806,14 +640,12 @@ ginRedoDeleteListPages(XLogRecPtr lsn, XLogRecord *record)
        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 */
+       XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &metabuffer);
+       Assert(BufferGetBlockNumber(metabuffer) == GIN_METAPAGE_BLKNO);
        metapage = BufferGetPage(metabuffer);
 
+       GinInitPage(metapage, GIN_META, BufferGetPageSize(metabuffer));
+
        memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
        PageSetLSN(metapage, lsn);
        MarkBufferDirty(metabuffer);
@@ -838,7 +670,8 @@ ginRedoDeleteListPages(XLogRecPtr lsn, XLogRecord *record)
                Buffer          buffer;
                Page            page;
 
-               buffer = XLogReadBuffer(data->node, data->toDelete[i], true);
+               XLogReadBufferForRedoExtended(lsn, record, i + 1, RBM_ZERO, false,
+                                                                         &buffer);
                page = BufferGetPage(buffer);
                GinInitBuffer(buffer, GIN_DELETED);
 
index 644b882b7d4ba44abaeeafa5744b79fb4cf0ec5e..2141045f994be5ff8089071aad1c254fa21adfa6 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "access/genam.h"
 #include "access/gist_private.h"
+#include "access/xloginsert.h"
 #include "catalog/index.h"
 #include "catalog/pg_collation.h"
 #include "miscadmin.h"
@@ -394,6 +395,14 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
                        GistPageSetNSN(ptr->page, oldnsn);
                }
 
+               /*
+                * gistXLogSplit() needs to WAL log a lot of pages, prepare WAL
+                * insertion for that. NB: The number of pages and data segments
+                * specified here must match the calculations in gistXLogSplit()!
+                */
+               if (RelationNeedsWAL(rel))
+                       XLogEnsureRecordSpace(npage, 1 + npage * 2);
+
                START_CRIT_SECTION();
 
                /*
index 2143096c66b50d16e604e7aff8c80dc20e06bbb2..5acc986585a8e2d6aeac800f867fdf8899f4c5a9 100644 (file)
@@ -183,14 +183,11 @@ gistbuild(PG_FUNCTION_ARGS)
        if (RelationNeedsWAL(index))
        {
                XLogRecPtr      recptr;
-               XLogRecData rdata;
 
-               rdata.data = (char *) &(index->rd_node);
-               rdata.len = sizeof(RelFileNode);
-               rdata.buffer = InvalidBuffer;
-               rdata.next = NULL;
+               XLogBeginInsert();
+               XLogRegisterBuffer(0, buffer, REGBUF_WILL_INIT);
 
-               recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_CREATE_INDEX, &rdata);
+               recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_CREATE_INDEX);
                PageSetLSN(page, recptr);
        }
        else
index 2999d211916861cbbaeff9f3928e1403ecd1ae1a..ed95ea2b2d437676f5bdf757fcc7deb5c6b5ae5b 100644 (file)
 #include "access/xlogutils.h"
 #include "utils/memutils.h"
 
-typedef struct
-{
-       gistxlogPage *header;
-       IndexTuple *itup;
-} NewPage;
-
-typedef struct
-{
-       gistxlogPageSplit *data;
-       NewPage    *page;
-} PageSplitRecord;
-
 static MemoryContext opCtx;            /* working memory for operations */
 
 /*
@@ -44,8 +32,7 @@ static MemoryContext opCtx;           /* working memory for operations */
  * action.)
  */
 static void
-gistRedoClearFollowRight(XLogRecPtr lsn, XLogRecord *record, int block_index,
-                                                RelFileNode node, BlockNumber childblkno)
+gistRedoClearFollowRight(XLogRecPtr lsn, XLogRecord *record, uint8 block_id)
 {
        Buffer          buffer;
        Page            page;
@@ -55,8 +42,7 @@ gistRedoClearFollowRight(XLogRecPtr lsn, XLogRecord *record, int block_index,
         * Note that we still update the page even if it was restored from a full
         * page image, because the updated NSN is not included in the image.
         */
-       action = XLogReadBufferForRedo(lsn, record, block_index, node, childblkno,
-                                                                  &buffer);
+       action = XLogReadBufferForRedo(lsn, record, block_id, &buffer);
        if (action == BLK_NEEDS_REDO || action == BLK_RESTORED)
        {
                page = BufferGetPage(buffer);
@@ -77,18 +63,20 @@ gistRedoClearFollowRight(XLogRecPtr lsn, XLogRecord *record, int block_index,
 static void
 gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record)
 {
-       char       *begin = XLogRecGetData(record);
-       gistxlogPageUpdate *xldata = (gistxlogPageUpdate *) begin;
+       gistxlogPageUpdate *xldata = (gistxlogPageUpdate *) XLogRecGetData(record);
        Buffer          buffer;
        Page            page;
-       char       *data;
 
-       if (XLogReadBufferForRedo(lsn, record, 0, xldata->node, xldata->blkno,
-                                                         &buffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
        {
-               page = (Page) BufferGetPage(buffer);
+               char       *begin;
+               char       *data;
+               Size            datalen;
+               int                     ninserted = 0;
 
-               data = begin + sizeof(gistxlogPageUpdate);
+               data = begin = XLogRecGetBlockData(record, 0, &datalen);
+
+               page = (Page) BufferGetPage(buffer);
 
                /* Delete old tuples */
                if (xldata->ntodelete > 0)
@@ -105,12 +93,12 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record)
                }
 
                /* add tuples */
-               if (data - begin < record->xl_len)
+               if (data - begin < datalen)
                {
                        OffsetNumber off = (PageIsEmpty(page)) ? FirstOffsetNumber :
                        OffsetNumberNext(PageGetMaxOffsetNumber(page));
 
-                       while (data - begin < record->xl_len)
+                       while (data - begin < datalen)
                        {
                                IndexTuple      itup = (IndexTuple) data;
                                Size            sz = IndexTupleSize(itup);
@@ -123,9 +111,12 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record)
                                        elog(ERROR, "failed to add item to GiST index page, size %d bytes",
                                                 (int) sz);
                                off++;
+                               ninserted++;
                        }
                }
 
+               Assert(ninserted == xldata->ntoinsert);
+
                PageSetLSN(page, lsn);
                MarkBufferDirty(buffer);
        }
@@ -137,58 +128,50 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record)
         * that even if the target page no longer exists, we still attempt to
         * replay the change on the child page.
         */
-       if (BlockNumberIsValid(xldata->leftchild))
-               gistRedoClearFollowRight(lsn, record, 1,
-                                                                xldata->node, xldata->leftchild);
+       if (XLogRecHasBlockRef(record, 1))
+               gistRedoClearFollowRight(lsn, record, 1);
 
        if (BufferIsValid(buffer))
                UnlockReleaseBuffer(buffer);
 }
 
-static void
-decodePageSplitRecord(PageSplitRecord *decoded, XLogRecord *record)
+/*
+ * Returns an array of index pointers.
+ */
+static IndexTuple *
+decodePageSplitRecord(char *begin, int len, int *n)
 {
-       char       *begin = XLogRecGetData(record),
-                          *ptr;
-       int                     j,
-                               i = 0;
+       char       *ptr;
+       int                     i = 0;
+       IndexTuple *tuples;
+
+       /* extract the number of tuples */
+       memcpy(n, begin, sizeof(int));
+       ptr = begin + sizeof(int);
 
-       decoded->data = (gistxlogPageSplit *) begin;
-       decoded->page = (NewPage *) palloc(sizeof(NewPage) * decoded->data->npage);
+       tuples = palloc(*n * sizeof(IndexTuple));
 
-       ptr = begin + sizeof(gistxlogPageSplit);
-       for (i = 0; i < decoded->data->npage; i++)
+       for (i = 0; i < *n; i++)
        {
-               Assert(ptr - begin < record->xl_len);
-               decoded->page[i].header = (gistxlogPage *) ptr;
-               ptr += sizeof(gistxlogPage);
-
-               decoded->page[i].itup = (IndexTuple *)
-                       palloc(sizeof(IndexTuple) * decoded->page[i].header->num);
-               j = 0;
-               while (j < decoded->page[i].header->num)
-               {
-                       Assert(ptr - begin < record->xl_len);
-                       decoded->page[i].itup[j] = (IndexTuple) ptr;
-                       ptr += IndexTupleSize((IndexTuple) ptr);
-                       j++;
-               }
+               Assert(ptr - begin < len);
+               tuples[i] = (IndexTuple) ptr;
+               ptr += IndexTupleSize((IndexTuple) ptr);
        }
+       Assert(ptr - begin == len);
+
+       return tuples;
 }
 
 static void
 gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
 {
        gistxlogPageSplit *xldata = (gistxlogPageSplit *) XLogRecGetData(record);
-       PageSplitRecord xlrec;
        Buffer          firstbuffer = InvalidBuffer;
        Buffer          buffer;
        Page            page;
        int                     i;
        bool            isrootsplit = false;
 
-       decodePageSplitRecord(&xlrec, record);
-
        /*
         * We must hold lock on the first-listed page throughout the action,
         * including while updating the left child page (if any).  We can unlock
@@ -198,32 +181,40 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
         */
 
        /* loop around all pages */
-       for (i = 0; i < xlrec.data->npage; i++)
+       for (i = 0; i < xldata->npage; i++)
        {
-               NewPage    *newpage = xlrec.page + i;
                int                     flags;
-
-               if (newpage->header->blkno == GIST_ROOT_BLKNO)
+               char       *data;
+               Size            datalen;
+               int                     num;
+               BlockNumber     blkno;
+               IndexTuple *tuples;
+
+               XLogRecGetBlockTag(record, i + 1, NULL, NULL, &blkno);
+               if (blkno == GIST_ROOT_BLKNO)
                {
                        Assert(i == 0);
                        isrootsplit = true;
                }
 
-               buffer = XLogReadBuffer(xlrec.data->node, newpage->header->blkno, true);
-               Assert(BufferIsValid(buffer));
+               XLogReadBufferForRedoExtended(lsn, record, i + 1, RBM_ZERO, false,
+                                                                         &buffer);
                page = (Page) BufferGetPage(buffer);
+               data = XLogRecGetBlockData(record, i + 1, &datalen);
+
+               tuples = decodePageSplitRecord(data, datalen, &num);
 
                /* ok, clear buffer */
-               if (xlrec.data->origleaf && newpage->header->blkno != GIST_ROOT_BLKNO)
+               if (xldata->origleaf && blkno != GIST_ROOT_BLKNO)
                        flags = F_LEAF;
                else
                        flags = 0;
                GISTInitBuffer(buffer, flags);
 
                /* and fill it */
-               gistfillbuffer(page, newpage->itup, newpage->header->num, FirstOffsetNumber);
+               gistfillbuffer(page, tuples, num, FirstOffsetNumber);
 
-               if (newpage->header->blkno == GIST_ROOT_BLKNO)
+               if (blkno == GIST_ROOT_BLKNO)
                {
                        GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
                        GistPageSetNSN(page, xldata->orignsn);
@@ -231,12 +222,17 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
                }
                else
                {
-                       if (i < xlrec.data->npage - 1)
-                               GistPageGetOpaque(page)->rightlink = xlrec.page[i + 1].header->blkno;
+                       if (i < xldata->npage - 1)
+                       {
+                               BlockNumber nextblkno;
+
+                               XLogRecGetBlockTag(record, i + 2, NULL, NULL, &nextblkno);
+                               GistPageGetOpaque(page)->rightlink = nextblkno;
+                       }
                        else
                                GistPageGetOpaque(page)->rightlink = xldata->origrlink;
                        GistPageSetNSN(page, xldata->orignsn);
-                       if (i < xlrec.data->npage - 1 && !isrootsplit &&
+                       if (i < xldata->npage - 1 && !isrootsplit &&
                                xldata->markfollowright)
                                GistMarkFollowRight(page);
                        else
@@ -253,9 +249,8 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
        }
 
        /* Fix follow-right data on left child page, if any */
-       if (BlockNumberIsValid(xldata->leftchild))
-               gistRedoClearFollowRight(lsn, record, 0,
-                                                                xldata->node, xldata->leftchild);
+       if (XLogRecHasBlockRef(record, 0))
+               gistRedoClearFollowRight(lsn, record, 0);
 
        /* Finally, release lock on the first page */
        UnlockReleaseBuffer(firstbuffer);
@@ -264,15 +259,11 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
 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));
+       XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buffer);
+       Assert(BufferGetBlockNumber(buffer) == GIST_ROOT_BLKNO);
        page = (Page) BufferGetPage(buffer);
 
        GISTInitBuffer(buffer, F_LEAF);
@@ -336,70 +327,49 @@ gistXLogSplit(RelFileNode node, BlockNumber blkno, bool page_is_leaf,
                          BlockNumber origrlink, GistNSN orignsn,
                          Buffer leftchildbuf, bool markfollowright)
 {
-       XLogRecData rdata[GIST_MAX_SPLIT_PAGES * 2 + 2];
        gistxlogPageSplit xlrec;
        SplitedPageLayout *ptr;
-       int                     npage = 0,
-                               cur;
+       int                     npage = 0;
        XLogRecPtr      recptr;
+       int                     i;
 
        for (ptr = dist; ptr; ptr = ptr->next)
                npage++;
 
-       /*
-        * the caller should've checked this already, but doesn't hurt to check
-        * again.
-        */
-       if (npage > GIST_MAX_SPLIT_PAGES)
-               elog(ERROR, "GiST page split into too many halves");
-
-       xlrec.node = node;
-       xlrec.origblkno = blkno;
        xlrec.origrlink = origrlink;
        xlrec.orignsn = orignsn;
        xlrec.origleaf = page_is_leaf;
        xlrec.npage = (uint16) npage;
-       xlrec.leftchild =
-               BufferIsValid(leftchildbuf) ? BufferGetBlockNumber(leftchildbuf) : InvalidBlockNumber;
        xlrec.markfollowright = markfollowright;
 
-       rdata[0].data = (char *) &xlrec;
-       rdata[0].len = sizeof(gistxlogPageSplit);
-       rdata[0].buffer = InvalidBuffer;
-
-       cur = 1;
+       XLogBeginInsert();
 
        /*
         * Include a full page image of the child buf. (only necessary if a
         * checkpoint happened since the child page was split)
         */
        if (BufferIsValid(leftchildbuf))
-       {
-               rdata[cur - 1].next = &(rdata[cur]);
-               rdata[cur].data = NULL;
-               rdata[cur].len = 0;
-               rdata[cur].buffer = leftchildbuf;
-               rdata[cur].buffer_std = true;
-               cur++;
-       }
+               XLogRegisterBuffer(0, leftchildbuf, REGBUF_STANDARD);
 
+       /*
+        * NOTE: We register a lot of data. The caller must've called
+        * XLogEnsureRecordSpace() to prepare for that. We cannot do it here,
+        * because we're already in a critical section. If you change the number
+        * of buffer or data registrations here, make sure you modify the
+        * XLogEnsureRecordSpace() calls accordingly!
+        */
+       XLogRegisterData((char *) &xlrec, sizeof(gistxlogPageSplit));
+
+       i = 1;
        for (ptr = dist; ptr; ptr = ptr->next)
        {
-               rdata[cur - 1].next = &(rdata[cur]);
-               rdata[cur].buffer = InvalidBuffer;
-               rdata[cur].data = (char *) &(ptr->block);
-               rdata[cur].len = sizeof(gistxlogPage);
-               cur++;
-
-               rdata[cur - 1].next = &(rdata[cur]);
-               rdata[cur].buffer = InvalidBuffer;
-               rdata[cur].data = (char *) (ptr->list);
-               rdata[cur].len = ptr->lenlist;
-               cur++;
+               XLogRegisterBuffer(i, ptr->buffer, REGBUF_WILL_INIT);
+               XLogRegisterBufData(i, (char *) &(ptr->block.num), sizeof(int));
+               XLogRegisterBufData(i, (char *) ptr->list, ptr->lenlist);
+               i++;
        }
-       rdata[cur - 1].next = NULL;
 
-       recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);
+       recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT);
 
        return recptr;
 }
@@ -413,9 +383,7 @@ gistXLogSplit(RelFileNode node, BlockNumber blkno, bool page_is_leaf,
  *
  * Note that both the todelete array and the tuples are marked as belonging
  * to the target buffer; they need not be stored in XLOG if XLogInsert decides
- * to log the whole buffer contents instead.  Also, we take care that there's
- * at least one rdata item referencing the buffer, even when ntodelete and
- * ituplen are both zero; this ensures that XLogInsert knows about the buffer.
+ * to log the whole buffer contents instead.
  */
 XLogRecPtr
 gistXLogUpdate(RelFileNode node, Buffer buffer,
@@ -423,57 +391,31 @@ gistXLogUpdate(RelFileNode node, Buffer buffer,
                           IndexTuple *itup, int ituplen,
                           Buffer leftchildbuf)
 {
-       XLogRecData rdata[MaxIndexTuplesPerPage + 3];
        gistxlogPageUpdate xlrec;
-       int                     cur,
-                               i;
+       int                     i;
        XLogRecPtr      recptr;
 
-       xlrec.node = node;
-       xlrec.blkno = BufferGetBlockNumber(buffer);
        xlrec.ntodelete = ntodelete;
-       xlrec.leftchild =
-               BufferIsValid(leftchildbuf) ? BufferGetBlockNumber(leftchildbuf) : InvalidBlockNumber;
-
-       rdata[0].data = (char *) &xlrec;
-       rdata[0].len = sizeof(gistxlogPageUpdate);
-       rdata[0].buffer = InvalidBuffer;
-       rdata[0].next = &(rdata[1]);
+       xlrec.ntoinsert = ituplen;
 
-       rdata[1].data = (char *) todelete;
-       rdata[1].len = sizeof(OffsetNumber) * ntodelete;
-       rdata[1].buffer = buffer;
-       rdata[1].buffer_std = true;
+       XLogBeginInsert();
+       XLogRegisterData((char *) &xlrec, sizeof(gistxlogPageUpdate));
 
-       cur = 2;
+       XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
+       XLogRegisterBufData(0, (char *) todelete, sizeof(OffsetNumber) * ntodelete);
 
        /* new tuples */
        for (i = 0; i < ituplen; i++)
-       {
-               rdata[cur - 1].next = &(rdata[cur]);
-               rdata[cur].data = (char *) (itup[i]);
-               rdata[cur].len = IndexTupleSize(itup[i]);
-               rdata[cur].buffer = buffer;
-               rdata[cur].buffer_std = true;
-               cur++;
-       }
+               XLogRegisterBufData(0, (char *) (itup[i]), IndexTupleSize(itup[i]));
 
        /*
         * Include a full page image of the child buf. (only necessary if a
         * checkpoint happened since the child page was split)
         */
        if (BufferIsValid(leftchildbuf))
-       {
-               rdata[cur - 1].next = &(rdata[cur]);
-               rdata[cur].data = NULL;
-               rdata[cur].len = 0;
-               rdata[cur].buffer = leftchildbuf;
-               rdata[cur].buffer_std = true;
-               cur++;
-       }
-       rdata[cur - 1].next = NULL;
+               XLogRegisterBuffer(1, leftchildbuf, REGBUF_STANDARD);
 
-       recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE, rdata);
+       recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE);
 
        return recptr;
 }
index 43098f444224a087d72543db9dce8da43fe28ef2..3382d61ebb614db0e3c431909f3a2f2ca627c3ed 100644 (file)
@@ -2132,84 +2132,64 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
                xl_heap_insert xlrec;
                xl_heap_header xlhdr;
                XLogRecPtr      recptr;
-               XLogRecData rdata[4];
                Page            page = BufferGetPage(buffer);
                uint8           info = XLOG_HEAP_INSERT;
-               bool            need_tuple_data;
+               int                     bufflags = 0;
 
                /*
-                * For logical decoding, we need the tuple even if we're doing a full
-                * page write, so make sure to log it separately. (XXX We could
-                * alternatively store a pointer into the FPW).
-                *
-                * Also, if this is a catalog, we need to transmit combocids to
-                * properly decode, so log that as well.
+                * If this is a catalog, we need to transmit combocids to properly
+                * decode, so log that as well.
                 */
-               need_tuple_data = RelationIsLogicallyLogged(relation);
                if (RelationIsAccessibleInLogicalDecoding(relation))
                        log_heap_new_cid(relation, heaptup);
 
-               xlrec.flags = all_visible_cleared ? XLOG_HEAP_ALL_VISIBLE_CLEARED : 0;
-               xlrec.target.node = relation->rd_node;
-               xlrec.target.tid = heaptup->t_self;
-               rdata[0].data = (char *) &xlrec;
-               rdata[0].len = SizeOfHeapInsert;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].next = &(rdata[1]);
-
-               xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
-               xlhdr.t_infomask = heaptup->t_data->t_infomask;
-               xlhdr.t_hoff = heaptup->t_data->t_hoff;
-
                /*
-                * note we mark rdata[1] as belonging to buffer; if XLogInsert decides
-                * to write the whole page to the xlog, we don't need to store
-                * xl_heap_header in the xlog.
+                * If this is the single and first tuple on page, we can reinit the
+                * page instead of restoring the whole thing.  Set flag, and hide
+                * buffer references from XLogInsert.
                 */
-               rdata[1].data = (char *) &xlhdr;
-               rdata[1].len = SizeOfHeapHeader;
-               rdata[1].buffer = need_tuple_data ? InvalidBuffer : buffer;
-               rdata[1].buffer_std = true;
-               rdata[1].next = &(rdata[2]);
-
-               /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
-               rdata[2].data = (char *) heaptup->t_data + offsetof(HeapTupleHeaderData, t_bits);
-               rdata[2].len = heaptup->t_len - offsetof(HeapTupleHeaderData, t_bits);
-               rdata[2].buffer = need_tuple_data ? InvalidBuffer : buffer;
-               rdata[2].buffer_std = true;
-               rdata[2].next = NULL;
+               if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
+                       PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
+               {
+                       info |= XLOG_HEAP_INIT_PAGE;
+                       bufflags |= REGBUF_WILL_INIT;
+               }
 
                /*
-                * Make a separate rdata entry for the tuple's buffer if we're doing
-                * logical decoding, so that an eventual FPW doesn't remove the
-                * tuple's data.
+                * For logical decoding, we need the tuple even if we're doing a full
+                * page write, so make sure it's included even if we take a full-page
+                * image. (XXX We could alternatively store a pointer into the FPW).
                 */
-               if (need_tuple_data)
+               if (RelationIsLogicallyLogged(relation))
                {
-                       rdata[2].next = &(rdata[3]);
-
-                       rdata[3].data = NULL;
-                       rdata[3].len = 0;
-                       rdata[3].buffer = buffer;
-                       rdata[3].buffer_std = true;
-                       rdata[3].next = NULL;
-
                        xlrec.flags |= XLOG_HEAP_CONTAINS_NEW_TUPLE;
+                       bufflags |= REGBUF_KEEP_DATA;
                }
 
+               xlrec.offnum = ItemPointerGetOffsetNumber(&heaptup->t_self);
+               xlrec.flags = all_visible_cleared ? XLOG_HEAP_ALL_VISIBLE_CLEARED : 0;
+               Assert(ItemPointerGetBlockNumber(&heaptup->t_self) == BufferGetBlockNumber(buffer));
+
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, SizeOfHeapInsert);
+
+               xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
+               xlhdr.t_infomask = heaptup->t_data->t_infomask;
+               xlhdr.t_hoff = heaptup->t_data->t_hoff;
+
                /*
-                * If this is the single and first tuple on page, we can reinit the
-                * page instead of restoring the whole thing.  Set flag, and hide
-                * buffer references from XLogInsert.
+                * note we mark xlhdr as belonging to buffer; if XLogInsert decides
+                * to write the whole page to the xlog, we don't need to store
+                * xl_heap_header in the xlog.
                 */
-               if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
-                       PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
-               {
-                       info |= XLOG_HEAP_INIT_PAGE;
-                       rdata[1].buffer = rdata[2].buffer = rdata[3].buffer = InvalidBuffer;
-               }
+               XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
+               XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);
+               /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
+               XLogRegisterBufData(0,
+                        (char *) heaptup->t_data + offsetof(HeapTupleHeaderData, t_bits),
+                        heaptup->t_len - offsetof(HeapTupleHeaderData, t_bits));
 
-               recptr = XLogInsert(RM_HEAP_ID, info, rdata);
+               recptr = XLogInsert(RM_HEAP_ID, info);
 
                PageSetLSN(page, recptr);
        }
@@ -2397,6 +2377,13 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
                                break;
 
                        RelationPutHeapTuple(relation, buffer, heaptup);
+
+                       /*
+                        * We don't use heap_multi_insert for catalog tuples yet, but
+                        * better be prepared...
+                        */
+                       if (needwal && need_cids)
+                               log_heap_new_cid(relation, heaptup);
                }
 
                if (PageIsAllVisible(page))
@@ -2419,12 +2406,12 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
                {
                        XLogRecPtr      recptr;
                        xl_heap_multi_insert *xlrec;
-                       XLogRecData rdata[3];
                        uint8           info = XLOG_HEAP2_MULTI_INSERT;
                        char       *tupledata;
                        int                     totaldatalen;
                        char       *scratchptr = scratch;
                        bool            init;
+                       int                     bufflags = 0;
 
                        /*
                         * If the page was previously empty, we can reinit the page
@@ -2450,8 +2437,6 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
                        tupledata = scratchptr;
 
                        xlrec->flags = all_visible_cleared ? XLOG_HEAP_ALL_VISIBLE_CLEARED : 0;
-                       xlrec->node = relation->rd_node;
-                       xlrec->blkno = BufferGetBlockNumber(buffer);
                        xlrec->ntuples = nthispage;
 
                        /*
@@ -2481,64 +2466,39 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
                                           datalen);
                                tuphdr->datalen = datalen;
                                scratchptr += datalen;
-
-                               /*
-                                * We don't use heap_multi_insert for catalog tuples yet, but
-                                * better be prepared...
-                                */
-                               if (need_cids)
-                                       log_heap_new_cid(relation, heaptup);
                        }
                        totaldatalen = scratchptr - tupledata;
                        Assert((scratchptr - scratch) < BLCKSZ);
 
-                       rdata[0].data = (char *) xlrec;
-                       rdata[0].len = tupledata - scratch;
-                       rdata[0].buffer = InvalidBuffer;
-                       rdata[0].next = &rdata[1];
-
-                       rdata[1].data = tupledata;
-                       rdata[1].len = totaldatalen;
-                       rdata[1].buffer = need_tuple_data ? InvalidBuffer : buffer;
-                       rdata[1].buffer_std = true;
-                       rdata[1].next = NULL;
-
-                       /*
-                        * Make a separate rdata entry for the tuple's buffer if we're
-                        * doing logical decoding, so that an eventual FPW doesn't remove
-                        * the tuple's data.
-                        */
                        if (need_tuple_data)
-                       {
-                               rdata[1].next = &(rdata[2]);
-
-                               rdata[2].data = NULL;
-                               rdata[2].len = 0;
-                               rdata[2].buffer = buffer;
-                               rdata[2].buffer_std = true;
-                               rdata[2].next = NULL;
                                xlrec->flags |= XLOG_HEAP_CONTAINS_NEW_TUPLE;
-                       }
 
                        /*
-                        * If we're going to reinitialize the whole page using the WAL
-                        * record, hide buffer reference from XLogInsert.
+                        * Signal that this is the last xl_heap_multi_insert record
+                        * emitted by this call to heap_multi_insert(). Needed for logical
+                        * decoding so it knows when to cleanup temporary data.
                         */
+                       if (ndone + nthispage == ntuples)
+                               xlrec->flags |= XLOG_HEAP_LAST_MULTI_INSERT;
+
                        if (init)
                        {
-                               rdata[1].buffer = rdata[2].buffer = InvalidBuffer;
                                info |= XLOG_HEAP_INIT_PAGE;
+                               bufflags |= REGBUF_WILL_INIT;
                        }
-
                        /*
-                        * Signal that this is the last xl_heap_multi_insert record
-                        * emitted by this call to heap_multi_insert(). Needed for logical
-                        * decoding so it knows when to cleanup temporary data.
+                        * If we're doing logical decoding, include the new tuple data
+                        * even if we take a full-page image of the page.
                         */
-                       if (ndone + nthispage == ntuples)
-                               xlrec->flags |= XLOG_HEAP_LAST_MULTI_INSERT;
+                       if (need_tuple_data)
+                               bufflags |= REGBUF_KEEP_DATA;
+
+                       XLogBeginInsert();
+                       XLogRegisterData((char *) xlrec, tupledata - scratch);
+                       XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
 
-                       recptr = XLogInsert(RM_HEAP2_ID, info, rdata);
+                       XLogRegisterBufData(0, tupledata, totaldatalen);
+                       recptr = XLogInsert(RM_HEAP2_ID, info);
 
                        PageSetLSN(page, recptr);
                }
@@ -2909,7 +2869,6 @@ l1:
        {
                xl_heap_delete xlrec;
                XLogRecPtr      recptr;
-               XLogRecData rdata[4];
 
                /* For logical decode we need combocids to properly decode the catalog */
                if (RelationIsAccessibleInLogicalDecoding(relation))
@@ -2918,19 +2877,21 @@ l1:
                xlrec.flags = all_visible_cleared ? XLOG_HEAP_ALL_VISIBLE_CLEARED : 0;
                xlrec.infobits_set = compute_infobits(tp.t_data->t_infomask,
                                                                                          tp.t_data->t_infomask2);
-               xlrec.target.node = relation->rd_node;
-               xlrec.target.tid = tp.t_self;
+               xlrec.offnum = ItemPointerGetOffsetNumber(&tp.t_self);
                xlrec.xmax = new_xmax;
-               rdata[0].data = (char *) &xlrec;
-               rdata[0].len = SizeOfHeapDelete;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].next = &(rdata[1]);
 
-               rdata[1].data = NULL;
-               rdata[1].len = 0;
-               rdata[1].buffer = buffer;
-               rdata[1].buffer_std = true;
-               rdata[1].next = NULL;
+               if (old_key_tuple != NULL)
+               {
+                       if (relation->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
+                               xlrec.flags |= XLOG_HEAP_CONTAINS_OLD_TUPLE;
+                       else
+                               xlrec.flags |= XLOG_HEAP_CONTAINS_OLD_KEY;
+               }
+
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, SizeOfHeapDelete);
+
+               XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
 
                /*
                 * Log replica identity of the deleted tuple if there is one
@@ -2943,27 +2904,14 @@ l1:
                        xlhdr.t_infomask = old_key_tuple->t_data->t_infomask;
                        xlhdr.t_hoff = old_key_tuple->t_data->t_hoff;
 
-                       rdata[1].next = &(rdata[2]);
-                       rdata[2].data = (char *) &xlhdr;
-                       rdata[2].len = SizeOfHeapHeader;
-                       rdata[2].buffer = InvalidBuffer;
-                       rdata[2].next = NULL;
-
-                       rdata[2].next = &(rdata[3]);
-                       rdata[3].data = (char *) old_key_tuple->t_data
-                               + offsetof(HeapTupleHeaderData, t_bits);
-                       rdata[3].len = old_key_tuple->t_len
-                               - offsetof(HeapTupleHeaderData, t_bits);
-                       rdata[3].buffer = InvalidBuffer;
-                       rdata[3].next = NULL;
-
-                       if (relation->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
-                               xlrec.flags |= XLOG_HEAP_CONTAINS_OLD_TUPLE;
-                       else
-                               xlrec.flags |= XLOG_HEAP_CONTAINS_OLD_KEY;
+                       XLogRegisterData((char *) &xlhdr, SizeOfHeapHeader);
+                       XLogRegisterData((char *) old_key_tuple->t_data
+                                                                + offsetof(HeapTupleHeaderData, t_bits),
+                                                                old_key_tuple->t_len
+                                                                - offsetof(HeapTupleHeaderData, t_bits));
                }
 
-               recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE, rdata);
+               recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE);
 
                PageSetLSN(page, recptr);
        }
@@ -4735,25 +4683,17 @@ failed:
        {
                xl_heap_lock xlrec;
                XLogRecPtr      recptr;
-               XLogRecData rdata[2];
 
-               xlrec.target.node = relation->rd_node;
-               xlrec.target.tid = tuple->t_self;
+               XLogBeginInsert();
+               XLogRegisterBuffer(0, *buffer, REGBUF_STANDARD);
+
+               xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
                xlrec.locking_xid = xid;
                xlrec.infobits_set = compute_infobits(new_infomask,
                                                                                          tuple->t_data->t_infomask2);
-               rdata[0].data = (char *) &xlrec;
-               rdata[0].len = SizeOfHeapLock;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].next = &(rdata[1]);
-
-               rdata[1].data = NULL;
-               rdata[1].len = 0;
-               rdata[1].buffer = *buffer;
-               rdata[1].buffer_std = true;
-               rdata[1].next = NULL;
+               XLogRegisterData((char *) &xlrec, SizeOfHeapLock);
 
-               recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_LOCK, rdata);
+               recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_LOCK);
 
                PageSetLSN(page, recptr);
        }
@@ -5342,26 +5282,18 @@ l4:
                {
                        xl_heap_lock_updated xlrec;
                        XLogRecPtr      recptr;
-                       XLogRecData rdata[2];
                        Page            page = BufferGetPage(buf);
 
-                       xlrec.target.node = rel->rd_node;
-                       xlrec.target.tid = mytup.t_self;
+                       XLogBeginInsert();
+                       XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
+
+                       xlrec.offnum = ItemPointerGetOffsetNumber(&mytup.t_self);
                        xlrec.xmax = new_xmax;
                        xlrec.infobits_set = compute_infobits(new_infomask, new_infomask2);
 
-                       rdata[0].data = (char *) &xlrec;
-                       rdata[0].len = SizeOfHeapLockUpdated;
-                       rdata[0].buffer = InvalidBuffer;
-                       rdata[0].next = &(rdata[1]);
-
-                       rdata[1].data = NULL;
-                       rdata[1].len = 0;
-                       rdata[1].buffer = buf;
-                       rdata[1].buffer_std = true;
-                       rdata[1].next = NULL;
+                       XLogRegisterData((char *) &xlrec, SizeOfHeapLockUpdated);
 
-                       recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_LOCK_UPDATED, rdata);
+                       recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_LOCK_UPDATED);
 
                        PageSetLSN(page, recptr);
                }
@@ -5489,23 +5421,16 @@ heap_inplace_update(Relation relation, HeapTuple tuple)
        {
                xl_heap_inplace xlrec;
                XLogRecPtr      recptr;
-               XLogRecData rdata[2];
 
-               xlrec.target.node = relation->rd_node;
-               xlrec.target.tid = tuple->t_self;
+               xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
 
-               rdata[0].data = (char *) &xlrec;
-               rdata[0].len = SizeOfHeapInplace;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].next = &(rdata[1]);
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, SizeOfHeapInplace);
 
-               rdata[1].data = (char *) htup + htup->t_hoff;
-               rdata[1].len = newlen;
-               rdata[1].buffer = buffer;
-               rdata[1].buffer_std = true;
-               rdata[1].next = NULL;
+               XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
+               XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen);
 
-               recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_INPLACE, rdata);
+               recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_INPLACE);
 
                PageSetLSN(page, recptr);
        }
@@ -6507,17 +6432,14 @@ log_heap_cleanup_info(RelFileNode rnode, TransactionId latestRemovedXid)
 {
        xl_heap_cleanup_info xlrec;
        XLogRecPtr      recptr;
-       XLogRecData rdata;
 
        xlrec.node = rnode;
        xlrec.latestRemovedXid = latestRemovedXid;
 
-       rdata.data = (char *) &xlrec;
-       rdata.len = SizeOfHeapCleanupInfo;
-       rdata.buffer = InvalidBuffer;
-       rdata.next = NULL;
+       XLogBeginInsert();
+       XLogRegisterData((char *) &xlrec, SizeOfHeapCleanupInfo);
 
-       recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_CLEANUP_INFO, &rdata);
+       recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_CLEANUP_INFO);
 
        return recptr;
 }
@@ -6542,23 +6464,19 @@ log_heap_clean(Relation reln, Buffer buffer,
                           TransactionId latestRemovedXid)
 {
        xl_heap_clean xlrec;
-       uint8           info;
        XLogRecPtr      recptr;
-       XLogRecData rdata[4];
 
        /* Caller should not call me on a non-WAL-logged relation */
        Assert(RelationNeedsWAL(reln));
 
-       xlrec.node = reln->rd_node;
-       xlrec.block = BufferGetBlockNumber(buffer);
        xlrec.latestRemovedXid = latestRemovedXid;
        xlrec.nredirected = nredirected;
        xlrec.ndead = ndead;
 
-       rdata[0].data = (char *) &xlrec;
-       rdata[0].len = SizeOfHeapClean;
-       rdata[0].buffer = InvalidBuffer;
-       rdata[0].next = &(rdata[1]);
+       XLogBeginInsert();
+       XLogRegisterData((char *) &xlrec, SizeOfHeapClean);
+
+       XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
 
        /*
         * The OffsetNumber arrays are not actually in the buffer, but we pretend
@@ -6569,49 +6487,18 @@ log_heap_clean(Relation reln, Buffer buffer,
         * even if no item pointers changed state.
         */
        if (nredirected > 0)
-       {
-               rdata[1].data = (char *) redirected;
-               rdata[1].len = nredirected * sizeof(OffsetNumber) * 2;
-       }
-       else
-       {
-               rdata[1].data = NULL;
-               rdata[1].len = 0;
-       }
-       rdata[1].buffer = buffer;
-       rdata[1].buffer_std = true;
-       rdata[1].next = &(rdata[2]);
+               XLogRegisterBufData(0, (char *) redirected,
+                                                nredirected * sizeof(OffsetNumber) * 2);
 
        if (ndead > 0)
-       {
-               rdata[2].data = (char *) nowdead;
-               rdata[2].len = ndead * sizeof(OffsetNumber);
-       }
-       else
-       {
-               rdata[2].data = NULL;
-               rdata[2].len = 0;
-       }
-       rdata[2].buffer = buffer;
-       rdata[2].buffer_std = true;
-       rdata[2].next = &(rdata[3]);
+               XLogRegisterBufData(0, (char *) nowdead,
+                                                ndead * sizeof(OffsetNumber));
 
        if (nunused > 0)
-       {
-               rdata[3].data = (char *) nowunused;
-               rdata[3].len = nunused * sizeof(OffsetNumber);
-       }
-       else
-       {
-               rdata[3].data = NULL;
-               rdata[3].len = 0;
-       }
-       rdata[3].buffer = buffer;
-       rdata[3].buffer_std = true;
-       rdata[3].next = NULL;
+               XLogRegisterBufData(0, (char *) nowunused,
+                                                nunused * sizeof(OffsetNumber));
 
-       info = XLOG_HEAP2_CLEAN;
-       recptr = XLogInsert(RM_HEAP2_ID, info, rdata);
+       recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_CLEAN);
 
        return recptr;
 }
@@ -6626,35 +6513,28 @@ log_heap_freeze(Relation reln, Buffer buffer, TransactionId cutoff_xid,
 {
        xl_heap_freeze_page xlrec;
        XLogRecPtr      recptr;
-       XLogRecData rdata[2];
 
        /* Caller should not call me on a non-WAL-logged relation */
        Assert(RelationNeedsWAL(reln));
        /* nor when there are no tuples to freeze */
        Assert(ntuples > 0);
 
-       xlrec.node = reln->rd_node;
-       xlrec.block = BufferGetBlockNumber(buffer);
        xlrec.cutoff_xid = cutoff_xid;
        xlrec.ntuples = ntuples;
 
-       rdata[0].data = (char *) &xlrec;
-       rdata[0].len = SizeOfHeapFreezePage;
-       rdata[0].buffer = InvalidBuffer;
-       rdata[0].next = &(rdata[1]);
+       XLogBeginInsert();
+       XLogRegisterData((char *) &xlrec, SizeOfHeapFreezePage);
 
        /*
         * The freeze plan array is not actually in the buffer, but pretend that
         * it is.  When XLogInsert stores the whole buffer, the freeze plan need
         * not be stored too.
         */
-       rdata[1].data = (char *) tuples;
-       rdata[1].len = ntuples * sizeof(xl_heap_freeze_tuple);
-       rdata[1].buffer = buffer;
-       rdata[1].buffer_std = true;
-       rdata[1].next = NULL;
+       XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
+       XLogRegisterBufData(0, (char *) tuples,
+                                        ntuples * sizeof(xl_heap_freeze_tuple));
 
-       recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_FREEZE_PAGE, rdata);
+       recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_FREEZE_PAGE);
 
        return recptr;
 }
@@ -6674,38 +6554,17 @@ log_heap_visible(RelFileNode rnode, Buffer heap_buffer, Buffer vm_buffer,
 {
        xl_heap_visible xlrec;
        XLogRecPtr      recptr;
-       XLogRecData rdata[3];
 
        Assert(BufferIsValid(heap_buffer));
        Assert(BufferIsValid(vm_buffer));
 
-       xlrec.node = rnode;
-       xlrec.block = BufferGetBlockNumber(heap_buffer);
        xlrec.cutoff_xid = cutoff_xid;
+       XLogBeginInsert();
+       XLogRegisterData((char *) &xlrec, SizeOfHeapVisible);
+       XLogRegisterBuffer(1, heap_buffer, XLogHintBitIsNeeded() ? REGBUF_STANDARD : (REGBUF_STANDARD | REGBUF_NO_IMAGE));
+       XLogRegisterBuffer(0, vm_buffer, 0);
 
-       rdata[0].data = (char *) &xlrec;
-       rdata[0].len = SizeOfHeapVisible;
-       rdata[0].buffer = InvalidBuffer;
-       rdata[0].next = &(rdata[1]);
-
-       rdata[1].data = NULL;
-       rdata[1].len = 0;
-       rdata[1].buffer = vm_buffer;
-       rdata[1].buffer_std = false;
-       rdata[1].next = NULL;
-
-       if (XLogHintBitIsNeeded())
-       {
-               rdata[1].next = &(rdata[2]);
-
-               rdata[2].data = NULL;
-               rdata[2].len = 0;
-               rdata[2].buffer = heap_buffer;
-               rdata[2].buffer_std = true;
-               rdata[2].next = NULL;
-       }
-
-       recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_VISIBLE, rdata);
+       recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_VISIBLE);
 
        return recptr;
 }
@@ -6721,22 +6580,23 @@ log_heap_update(Relation reln, Buffer oldbuf,
                                bool all_visible_cleared, bool new_all_visible_cleared)
 {
        xl_heap_update xlrec;
-       xl_heap_header_len xlhdr;
-       xl_heap_header_len xlhdr_idx;
+       xl_heap_header xlhdr;
+       xl_heap_header xlhdr_idx;
        uint8           info;
        uint16          prefix_suffix[2];
        uint16          prefixlen = 0,
                                suffixlen = 0;
        XLogRecPtr      recptr;
-       XLogRecData rdata[9];
        Page            page = BufferGetPage(newbuf);
        bool            need_tuple_data = RelationIsLogicallyLogged(reln);
-       int                     nr;
-       Buffer          newbufref;
+       bool            init;
+       int                     bufflags;
 
        /* Caller should not call me on a non-WAL-logged relation */
        Assert(RelationNeedsWAL(reln));
 
+       XLogBeginInsert();
+
        if (HeapTupleIsHeapOnly(newtup))
                info = XLOG_HEAP_HOT_UPDATE;
        else
@@ -6794,103 +6654,97 @@ log_heap_update(Relation reln, Buffer oldbuf,
                        suffixlen = 0;
        }
 
-       xlrec.target.node = reln->rd_node;
-       xlrec.target.tid = oldtup->t_self;
-       xlrec.old_xmax = HeapTupleHeaderGetRawXmax(oldtup->t_data);
-       xlrec.old_infobits_set = compute_infobits(oldtup->t_data->t_infomask,
-                                                                                         oldtup->t_data->t_infomask2);
-       xlrec.new_xmax = HeapTupleHeaderGetRawXmax(newtup->t_data);
+       /* Prepare main WAL data chain */
        xlrec.flags = 0;
        if (all_visible_cleared)
                xlrec.flags |= XLOG_HEAP_ALL_VISIBLE_CLEARED;
-       xlrec.newtid = newtup->t_self;
        if (new_all_visible_cleared)
                xlrec.flags |= XLOG_HEAP_NEW_ALL_VISIBLE_CLEARED;
        if (prefixlen > 0)
                xlrec.flags |= XLOG_HEAP_PREFIX_FROM_OLD;
        if (suffixlen > 0)
                xlrec.flags |= XLOG_HEAP_SUFFIX_FROM_OLD;
+       if (need_tuple_data)
+       {
+               xlrec.flags |= XLOG_HEAP_CONTAINS_NEW_TUPLE;
+               if (old_key_tuple)
+               {
+                       if (reln->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
+                               xlrec.flags |= XLOG_HEAP_CONTAINS_OLD_TUPLE;
+                       else
+                               xlrec.flags |= XLOG_HEAP_CONTAINS_OLD_KEY;
+               }
+       }
 
        /* If new tuple is the single and first tuple on page... */
        if (ItemPointerGetOffsetNumber(&(newtup->t_self)) == FirstOffsetNumber &&
                PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
        {
                info |= XLOG_HEAP_INIT_PAGE;
-               newbufref = InvalidBuffer;
+               init = true;
        }
        else
-               newbufref = newbuf;
+               init = false;
 
-       rdata[0].data = NULL;
-       rdata[0].len = 0;
-       rdata[0].buffer = oldbuf;
-       rdata[0].buffer_std = true;
-       rdata[0].next = &(rdata[1]);
+       /* Prepare WAL data for the old page */
+       xlrec.old_offnum = ItemPointerGetOffsetNumber(&oldtup->t_self);
+       xlrec.old_xmax = HeapTupleHeaderGetRawXmax(oldtup->t_data);
+       xlrec.old_infobits_set = compute_infobits(oldtup->t_data->t_infomask,
+                                                                                         oldtup->t_data->t_infomask2);
+
+       /* Prepare WAL data for the new page */
+       xlrec.new_offnum = ItemPointerGetOffsetNumber(&newtup->t_self);
+       xlrec.new_xmax = HeapTupleHeaderGetRawXmax(newtup->t_data);
+
+       bufflags = REGBUF_STANDARD;
+       if (init)
+               bufflags |= REGBUF_WILL_INIT;
+       if (need_tuple_data)
+               bufflags |= REGBUF_KEEP_DATA;
 
-       rdata[1].data = (char *) &xlrec;
-       rdata[1].len = SizeOfHeapUpdate;
-       rdata[1].buffer = InvalidBuffer;
-       rdata[1].next = &(rdata[2]);
+       XLogRegisterBuffer(0, newbuf, bufflags);
+       if (oldbuf != newbuf)
+               XLogRegisterBuffer(1, oldbuf, REGBUF_STANDARD);
 
-       /* prefix and/or suffix length fields */
+       XLogRegisterData((char *) &xlrec, SizeOfHeapUpdate);
+
+       /*
+        * Prepare WAL data for the new tuple.
+        */
        if (prefixlen > 0 || suffixlen > 0)
        {
                if (prefixlen > 0 && suffixlen > 0)
                {
                        prefix_suffix[0] = prefixlen;
                        prefix_suffix[1] = suffixlen;
-                       rdata[2].data = (char *) &prefix_suffix;
-                       rdata[2].len = 2 * sizeof(uint16);
+                       XLogRegisterBufData(0, (char *) &prefix_suffix, sizeof(uint16) * 2);
                }
                else if (prefixlen > 0)
                {
-                       rdata[2].data = (char *) &prefixlen;
-                       rdata[2].len = sizeof(uint16);
+                       XLogRegisterBufData(0, (char *) &prefixlen, sizeof(uint16));
                }
                else
                {
-                       rdata[2].data = (char *) &suffixlen;
-                       rdata[2].len = sizeof(uint16);
+                       XLogRegisterBufData(0, (char *) &suffixlen, sizeof(uint16));
                }
-               rdata[2].buffer = newbufref;
-               rdata[2].buffer_std = true;
-               rdata[2].next = &(rdata[3]);
-               nr = 3;
        }
-       else
-               nr = 2;
 
-       xlhdr.header.t_infomask2 = newtup->t_data->t_infomask2;
-       xlhdr.header.t_infomask = newtup->t_data->t_infomask;
-       xlhdr.header.t_hoff = newtup->t_data->t_hoff;
-       Assert(offsetof(HeapTupleHeaderData, t_bits) +prefixlen + suffixlen <= newtup->t_len);
-       xlhdr.t_len = newtup->t_len - offsetof(HeapTupleHeaderData, t_bits) -prefixlen - suffixlen;
-
-       /*
-        * As with insert records, we need not store this rdata segment if we
-        * decide to store the whole buffer instead, unless we're doing logical
-        * decoding.
-        */
-       rdata[nr].data = (char *) &xlhdr;
-       rdata[nr].len = SizeOfHeapHeaderLen;
-       rdata[nr].buffer = need_tuple_data ? InvalidBuffer : newbufref;
-       rdata[nr].buffer_std = true;
-       rdata[nr].next = &(rdata[nr + 1]);
-       nr++;
+       xlhdr.t_infomask2 = newtup->t_data->t_infomask2;
+       xlhdr.t_infomask = newtup->t_data->t_infomask;
+       xlhdr.t_hoff = newtup->t_data->t_hoff;
+       Assert(offsetof(HeapTupleHeaderData, t_bits) + prefixlen + suffixlen <= newtup->t_len);
 
        /*
         * PG73FORMAT: write bitmap [+ padding] [+ oid] + data
         *
         * The 'data' doesn't include the common prefix or suffix.
         */
+       XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);
        if (prefixlen == 0)
        {
-               rdata[nr].data = ((char *) newtup->t_data) + offsetof(HeapTupleHeaderData, t_bits);
-               rdata[nr].len = newtup->t_len - offsetof(HeapTupleHeaderData, t_bits) -suffixlen;
-               rdata[nr].buffer = need_tuple_data ? InvalidBuffer : newbufref;
-               rdata[nr].buffer_std = true;
-               rdata[nr].next = NULL;
-               nr++;
+               XLogRegisterBufData(0,
+                        ((char *) newtup->t_data) + offsetof(HeapTupleHeaderData, t_bits),
+                       newtup->t_len - offsetof(HeapTupleHeaderData, t_bits) - suffixlen);
        }
        else
        {
@@ -6901,75 +6755,33 @@ log_heap_update(Relation reln, Buffer oldbuf,
                /* bitmap [+ padding] [+ oid] */
                if (newtup->t_data->t_hoff - offsetof(HeapTupleHeaderData, t_bits) >0)
                {
-                       rdata[nr - 1].next = &(rdata[nr]);
-                       rdata[nr].data = ((char *) newtup->t_data) + offsetof(HeapTupleHeaderData, t_bits);
-                       rdata[nr].len = newtup->t_data->t_hoff - offsetof(HeapTupleHeaderData, t_bits);
-                       rdata[nr].buffer = need_tuple_data ? InvalidBuffer : newbufref;
-                       rdata[nr].buffer_std = true;
-                       rdata[nr].next = NULL;
-                       nr++;
+                       XLogRegisterBufData(0,
+                         ((char *) newtup->t_data) + offsetof(HeapTupleHeaderData, t_bits),
+                               newtup->t_data->t_hoff - offsetof(HeapTupleHeaderData, t_bits));
                }
 
                /* data after common prefix */
-               rdata[nr - 1].next = &(rdata[nr]);
-               rdata[nr].data = ((char *) newtup->t_data) + newtup->t_data->t_hoff + prefixlen;
-               rdata[nr].len = newtup->t_len - newtup->t_data->t_hoff - prefixlen - suffixlen;
-               rdata[nr].buffer = need_tuple_data ? InvalidBuffer : newbufref;
-               rdata[nr].buffer_std = true;
-               rdata[nr].next = NULL;
-               nr++;
+               XLogRegisterBufData(0,
+                                ((char *) newtup->t_data) + newtup->t_data->t_hoff + prefixlen,
+                               newtup->t_len - newtup->t_data->t_hoff - prefixlen - suffixlen);
        }
 
-       /*
-        * Separate storage for the FPW buffer reference of the new page in the
-        * wal_level >= logical case.
-        */
-       if (need_tuple_data)
+       /* We need to log a tuple identity */
+       if (need_tuple_data && old_key_tuple)
        {
-               rdata[nr - 1].next = &(rdata[nr]);
-
-               rdata[nr].data = NULL,
-                       rdata[nr].len = 0;
-               rdata[nr].buffer = newbufref;
-               rdata[nr].buffer_std = true;
-               rdata[nr].next = NULL;
-               nr++;
+               /* don't really need this, but its more comfy to decode */
+               xlhdr_idx.t_infomask2 = old_key_tuple->t_data->t_infomask2;
+               xlhdr_idx.t_infomask = old_key_tuple->t_data->t_infomask;
+               xlhdr_idx.t_hoff = old_key_tuple->t_data->t_hoff;
 
-               xlrec.flags |= XLOG_HEAP_CONTAINS_NEW_TUPLE;
-
-               /* We need to log a tuple identity */
-               if (old_key_tuple)
-               {
-                       /* don't really need this, but its more comfy to decode */
-                       xlhdr_idx.header.t_infomask2 = old_key_tuple->t_data->t_infomask2;
-                       xlhdr_idx.header.t_infomask = old_key_tuple->t_data->t_infomask;
-                       xlhdr_idx.header.t_hoff = old_key_tuple->t_data->t_hoff;
-                       xlhdr_idx.t_len = old_key_tuple->t_len;
-
-                       rdata[nr - 1].next = &(rdata[nr]);
-                       rdata[nr].data = (char *) &xlhdr_idx;
-                       rdata[nr].len = SizeOfHeapHeaderLen;
-                       rdata[nr].buffer = InvalidBuffer;
-                       rdata[nr].next = &(rdata[nr + 1]);
-                       nr++;
-
-                       /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
-                       rdata[nr].data = (char *) old_key_tuple->t_data
-                               + offsetof(HeapTupleHeaderData, t_bits);
-                       rdata[nr].len = old_key_tuple->t_len
-                               - offsetof(HeapTupleHeaderData, t_bits);
-                       rdata[nr].buffer = InvalidBuffer;
-                       rdata[nr].next = NULL;
-                       nr++;
+               XLogRegisterData((char *) &xlhdr_idx, SizeOfHeapHeader);
 
-                       if (reln->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
-                               xlrec.flags |= XLOG_HEAP_CONTAINS_OLD_TUPLE;
-                       else
-                               xlrec.flags |= XLOG_HEAP_CONTAINS_OLD_KEY;
-               }
+               /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
+               XLogRegisterData((char *) old_key_tuple->t_data + offsetof(HeapTupleHeaderData, t_bits),
+                                                old_key_tuple->t_len - offsetof(HeapTupleHeaderData, t_bits));
        }
 
-       recptr = XLogInsert(RM_HEAP_ID, info, rdata);
+       recptr = XLogInsert(RM_HEAP_ID, info);
 
        return recptr;
 }
@@ -6986,15 +6798,14 @@ log_heap_new_cid(Relation relation, HeapTuple tup)
        xl_heap_new_cid xlrec;
 
        XLogRecPtr      recptr;
-       XLogRecData rdata[1];
        HeapTupleHeader hdr = tup->t_data;
 
        Assert(ItemPointerIsValid(&tup->t_self));
        Assert(tup->t_tableOid != InvalidOid);
 
        xlrec.top_xid = GetTopTransactionId();
-       xlrec.target.node = relation->rd_node;
-       xlrec.target.tid = tup->t_self;
+       xlrec.target_node = relation->rd_node;
+       xlrec.target_tid = tup->t_self;
 
        /*
         * If the tuple got inserted & deleted in the same TX we definitely have a
@@ -7035,12 +6846,15 @@ log_heap_new_cid(Relation relation, HeapTuple tup)
                xlrec.combocid = InvalidCommandId;
        }
 
-       rdata[0].data = (char *) &xlrec;
-       rdata[0].len = SizeOfHeapNewCid;
-       rdata[0].buffer = InvalidBuffer;
-       rdata[0].next = NULL;
+       /*
+        * Note that we don't need to register the buffer here, because this
+        * operation does not modify the page. The insert/update/delete that
+        * called us certainly did, but that's WAL-logged separately.
+        */
+       XLogBeginInsert();
+       XLogRegisterData((char *) &xlrec, SizeOfHeapNewCid);
 
-       recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_NEW_CID, rdata);
+       recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_NEW_CID);
 
        return recptr;
 }
@@ -7179,7 +6993,7 @@ heap_xlog_cleanup_info(XLogRecPtr lsn, XLogRecord *record)
         */
 
        /* Backup blocks are not used in cleanup_info records */
-       Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
+       Assert(!XLogRecHasAnyBlockRefs(record));
 }
 
 /*
@@ -7195,8 +7009,7 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record)
        BlockNumber blkno;
        XLogRedoAction action;
 
-       rnode = xlrec->node;
-       blkno = xlrec->block;
+       XLogRecGetBlockTag(record, 0, &rnode, NULL, &blkno);
 
        /*
         * We're about to remove tuples. In Hot Standby mode, ensure that there's
@@ -7213,9 +7026,8 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record)
         * If we have a full-page image, restore it (using a cleanup lock) and
         * we're done.
         */
-       action = XLogReadBufferForRedoExtended(lsn, record, 0,
-                                                                                  rnode, MAIN_FORKNUM, blkno,
-                                                                                  RBM_NORMAL, true, &buffer);
+       action = XLogReadBufferForRedoExtended(lsn, record, 0, RBM_NORMAL, true,
+                                                                                  &buffer);
        if (action == BLK_NEEDS_REDO)
        {
                Page            page = (Page) BufferGetPage(buffer);
@@ -7226,11 +7038,13 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record)
                int                     nredirected;
                int                     ndead;
                int                     nunused;
+               Size            datalen;
+
+               redirected = (OffsetNumber *) XLogRecGetBlockData(record, 0, &datalen);
 
                nredirected = xlrec->nredirected;
                ndead = xlrec->ndead;
-               end = (OffsetNumber *) ((char *) xlrec + record->xl_len);
-               redirected = (OffsetNumber *) ((char *) xlrec + SizeOfHeapClean);
+               end = (OffsetNumber *) ((char *) redirected + datalen);
                nowdead = redirected + (nredirected * 2);
                nowunused = nowdead + ndead;
                nunused = (end - nowunused);
@@ -7263,7 +7077,7 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record)
         * totally accurate anyway.
         */
        if (action == BLK_NEEDS_REDO)
-               XLogRecordPageWithFreeSpace(xlrec->node, xlrec->block, freespace);
+               XLogRecordPageWithFreeSpace(rnode, blkno, freespace);
 }
 
 /*
@@ -7278,14 +7092,14 @@ static void
 heap_xlog_visible(XLogRecPtr lsn, XLogRecord *record)
 {
        xl_heap_visible *xlrec = (xl_heap_visible *) XLogRecGetData(record);
+       Buffer          vmbuffer = InvalidBuffer;
        Buffer          buffer;
        Page            page;
        RelFileNode rnode;
        BlockNumber blkno;
        XLogRedoAction action;
 
-       rnode = xlrec->node;
-       blkno = xlrec->block;
+       XLogRecGetBlockTag(record, 1, &rnode, NULL, &blkno);
 
        /*
         * If there are any Hot Standby transactions running that have an xmin
@@ -7304,7 +7118,7 @@ heap_xlog_visible(XLogRecPtr lsn, XLogRecord *record)
         * truncated later in recovery, we don't need to update the page, but we'd
         * better still update the visibility map.
         */
-       action = XLogReadBufferForRedo(lsn, record, 1, rnode, blkno, &buffer);
+       action = XLogReadBufferForRedo(lsn, record, 1, &buffer);
        if (action == BLK_NEEDS_REDO)
        {
                /*
@@ -7320,9 +7134,9 @@ heap_xlog_visible(XLogRecPtr lsn, XLogRecord *record)
                 * XLOG record's LSN, we mustn't mark the page all-visible, because
                 * the subsequent update won't be replayed to clear the flag.
                 */
-               page = BufferGetPage(buffer);
-               PageSetAllVisible(page);
-               MarkBufferDirty(buffer);
+                       page = BufferGetPage(buffer);
+                       PageSetAllVisible(page);
+                       MarkBufferDirty(buffer);
        }
        else if (action == BLK_RESTORED)
        {
@@ -7341,12 +7155,16 @@ heap_xlog_visible(XLogRecPtr lsn, XLogRecord *record)
         * the visibility map bit does so before checking the page LSN, so any
         * bits that need to be cleared will still be cleared.
         */
-       if (record->xl_info & XLR_BKP_BLOCK(0))
-               (void) RestoreBackupBlock(lsn, record, 0, false, false);
-       else
+       if (XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO_ON_ERROR, false,
+                                                                         &vmbuffer) == BLK_NEEDS_REDO)
        {
                Relation        reln;
-               Buffer          vmbuffer = InvalidBuffer;
+
+               /*
+                * XLogReplayBufferExtended locked the buffer. But visibilitymap_set
+                * will handle locking itself.
+                */
+               LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
 
                reln = CreateFakeRelcacheEntry(rnode);
                visibilitymap_pin(reln, blkno, &vmbuffer);
@@ -7369,6 +7187,8 @@ heap_xlog_visible(XLogRecPtr lsn, XLogRecord *record)
                ReleaseBuffer(vmbuffer);
                FreeFakeRelcacheEntry(reln);
        }
+       else if (BufferIsValid(vmbuffer))
+               UnlockReleaseBuffer(vmbuffer);
 }
 
 /*
@@ -7380,7 +7200,6 @@ heap_xlog_freeze_page(XLogRecPtr lsn, XLogRecord *record)
        xl_heap_freeze_page *xlrec = (xl_heap_freeze_page *) XLogRecGetData(record);
        TransactionId cutoff_xid = xlrec->cutoff_xid;
        Buffer          buffer;
-       Page            page;
        int                     ntup;
 
        /*
@@ -7388,12 +7207,19 @@ heap_xlog_freeze_page(XLogRecPtr lsn, XLogRecord *record)
         * consider the frozen xids as running.
         */
        if (InHotStandby)
-               ResolveRecoveryConflictWithSnapshot(cutoff_xid, xlrec->node);
+       {
+               RelFileNode rnode;
 
-       if (XLogReadBufferForRedo(lsn, record, 0, xlrec->node, xlrec->block,
-                                                         &buffer) == BLK_NEEDS_REDO)
+               XLogRecGetBlockTag(record, 0, &rnode, NULL, NULL);
+               ResolveRecoveryConflictWithSnapshot(cutoff_xid, rnode);
+       }
+
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
        {
-               page = BufferGetPage(buffer);
+               Page            page = BufferGetPage(buffer);
+               xl_heap_freeze_tuple *tuples;
+
+               tuples = (xl_heap_freeze_tuple *) XLogRecGetBlockData(record, 0, NULL);
 
                /* now execute freeze plan for each frozen tuple */
                for (ntup = 0; ntup < xlrec->ntuples; ntup++)
@@ -7402,7 +7228,7 @@ heap_xlog_freeze_page(XLogRecPtr lsn, XLogRecord *record)
                        ItemId          lp;
                        HeapTupleHeader tuple;
 
-                       xlrec_tp = &xlrec->tuples[ntup];
+                       xlrec_tp = &tuples[ntup];
                        lp = PageGetItemId(page, xlrec_tp->offset); /* offsets are one-based */
                        tuple = (HeapTupleHeader) PageGetItem(page, lp);
 
@@ -7449,14 +7275,15 @@ heap_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
        xl_heap_delete *xlrec = (xl_heap_delete *) XLogRecGetData(record);
        Buffer          buffer;
        Page            page;
-       OffsetNumber offnum;
        ItemId          lp = NULL;
        HeapTupleHeader htup;
        BlockNumber blkno;
        RelFileNode target_node;
+       ItemPointerData target_tid;
 
-       blkno = ItemPointerGetBlockNumber(&(xlrec->target.tid));
-       target_node = xlrec->target.node;
+       XLogRecGetBlockTag(record, 0, &target_node, NULL, &blkno);
+       ItemPointerSetBlockNumber(&target_tid, blkno);
+       ItemPointerSetOffsetNumber(&target_tid, xlrec->offnum);
 
        /*
         * The visibility map may need to be fixed even if the heap page is
@@ -7473,16 +7300,14 @@ heap_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
                FreeFakeRelcacheEntry(reln);
        }
 
-       if (XLogReadBufferForRedo(lsn, record, 0, target_node, blkno, &buffer)
-               == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
        {
-               page = (Page) BufferGetPage(buffer);
+               page = BufferGetPage(buffer);
 
-               offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
-               if (PageGetMaxOffsetNumber(page) >= offnum)
-                       lp = PageGetItemId(page, offnum);
+               if (PageGetMaxOffsetNumber(page) >= xlrec->offnum)
+                       lp = PageGetItemId(page, xlrec->offnum);
 
-               if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
+               if (PageGetMaxOffsetNumber(page) < xlrec->offnum || !ItemIdIsNormal(lp))
                        elog(PANIC, "heap_delete_redo: invalid lp");
 
                htup = (HeapTupleHeader) PageGetItem(page, lp);
@@ -7502,7 +7327,7 @@ heap_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
                        PageClearAllVisible(page);
 
                /* Make sure there is no forward chain link in t_ctid */
-               htup->t_ctid = xlrec->target.tid;
+               htup->t_ctid = target_tid;
                PageSetLSN(page, lsn);
                MarkBufferDirty(buffer);
        }
@@ -7516,7 +7341,6 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
        xl_heap_insert *xlrec = (xl_heap_insert *) XLogRecGetData(record);
        Buffer          buffer;
        Page            page;
-       OffsetNumber offnum;
        struct
        {
                HeapTupleHeaderData hdr;
@@ -7528,10 +7352,12 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
        Size            freespace = 0;
        RelFileNode target_node;
        BlockNumber blkno;
+       ItemPointerData target_tid;
        XLogRedoAction action;
 
-       target_node = xlrec->target.node;
-       blkno = ItemPointerGetBlockNumber(&(xlrec->target.tid));
+       XLogRecGetBlockTag(record, 0, &target_node, NULL, &blkno);
+       ItemPointerSetBlockNumber(&target_tid, blkno);
+       ItemPointerSetOffsetNumber(&target_tid, xlrec->offnum);
 
        /*
         * The visibility map may need to be fixed even if the heap page is
@@ -7554,35 +7380,46 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
         */
        if (record->xl_info & XLOG_HEAP_INIT_PAGE)
        {
-               XLogReadBufferForRedoExtended(lsn, record, 0,
-                                                                         target_node, MAIN_FORKNUM, blkno,
-                                                                         RBM_ZERO, false, &buffer);
+               XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buffer);
                page = BufferGetPage(buffer);
                PageInit(page, BufferGetPageSize(buffer), 0);
                action = BLK_NEEDS_REDO;
        }
        else
-               action = XLogReadBufferForRedo(lsn, record, 0, target_node, blkno,
-                                                                          &buffer);
-
+               action = XLogReadBufferForRedo(lsn, record, 0, &buffer);
        if (action == BLK_NEEDS_REDO)
        {
+               Size            datalen;
+               char       *data;
+
+               /*
+                * The new tuple is normally stored as buffer 0's data. But if
+                * XLOG_HEAP_CONTAINS_NEW_TUPLE flag is set, it's part of the main
+                * data, after the xl_heap_insert struct.
+                */
+               if (xlrec->flags & XLOG_HEAP_CONTAINS_NEW_TUPLE)
+               {
+                       data = XLogRecGetData(record) + SizeOfHeapInsert;
+                       datalen = record->xl_len - SizeOfHeapInsert;
+               }
+               else
+                       data = XLogRecGetBlockData(record, 0, &datalen);
+
                page = BufferGetPage(buffer);
 
-               offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
-               if (PageGetMaxOffsetNumber(page) + 1 < offnum)
+               if (PageGetMaxOffsetNumber(page) + 1 < xlrec->offnum)
                        elog(PANIC, "heap_insert_redo: invalid max offset number");
 
-               newlen = record->xl_len - SizeOfHeapInsert - SizeOfHeapHeader;
-               Assert(newlen <= MaxHeapTupleSize);
-               memcpy((char *) &xlhdr,
-                          (char *) xlrec + SizeOfHeapInsert,
-                          SizeOfHeapHeader);
+               newlen = datalen - SizeOfHeapHeader;
+               Assert(datalen > SizeOfHeapHeader && newlen <= MaxHeapTupleSize);
+               memcpy((char *) &xlhdr, data, SizeOfHeapHeader);
+               data += SizeOfHeapHeader;
+
                htup = &tbuf.hdr;
                MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData));
                /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */
                memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits),
-                          (char *) xlrec + SizeOfHeapInsert + SizeOfHeapHeader,
+                          data,
                           newlen);
                newlen += offsetof(HeapTupleHeaderData, t_bits);
                htup->t_infomask2 = xlhdr.t_infomask2;
@@ -7590,10 +7427,10 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
                htup->t_hoff = xlhdr.t_hoff;
                HeapTupleHeaderSetXmin(htup, record->xl_xid);
                HeapTupleHeaderSetCmin(htup, FirstCommandId);
-               htup->t_ctid = xlrec->target.tid;
+               htup->t_ctid = target_tid;
 
-               offnum = PageAddItem(page, (Item) htup, newlen, offnum, true, true);
-               if (offnum == InvalidOffsetNumber)
+               if (PageAddItem(page, (Item) htup, newlen, xlrec->offnum,
+                                               true, true) == InvalidOffsetNumber)
                        elog(PANIC, "heap_insert_redo: failed to add tuple");
 
                freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
@@ -7618,7 +7455,7 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
         * totally accurate anyway.
         */
        if (action == BLK_NEEDS_REDO && freespace < BLCKSZ / 5)
-               XLogRecordPageWithFreeSpace(xlrec->target.node, blkno, freespace);
+               XLogRecordPageWithFreeSpace(target_node, blkno, freespace);
 }
 
 /*
@@ -7627,7 +7464,6 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
 static void
 heap_xlog_multi_insert(XLogRecPtr lsn, XLogRecord *record)
 {
-       char       *recdata = XLogRecGetData(record);
        xl_heap_multi_insert *xlrec;
        RelFileNode rnode;
        BlockNumber blkno;
@@ -7649,20 +7485,9 @@ heap_xlog_multi_insert(XLogRecPtr lsn, XLogRecord *record)
         * Insertion doesn't overwrite MVCC data, so no conflict processing is
         * required.
         */
+       xlrec = (xl_heap_multi_insert *) XLogRecGetData(record);
 
-       xlrec = (xl_heap_multi_insert *) recdata;
-       recdata += SizeOfHeapMultiInsert;
-
-       rnode = xlrec->node;
-       blkno = xlrec->blkno;
-
-       /*
-        * If we're reinitializing the page, the tuples are stored in order from
-        * FirstOffsetNumber. Otherwise there's an array of offsets in the WAL
-        * record.
-        */
-       if (!isinit)
-               recdata += sizeof(OffsetNumber) * xlrec->ntuples;
+       XLogRecGetBlockTag(record, 0, &rnode, NULL, &blkno);
 
        /*
         * The visibility map may need to be fixed even if the heap page is
@@ -7681,24 +7506,35 @@ heap_xlog_multi_insert(XLogRecPtr lsn, XLogRecord *record)
 
        if (isinit)
        {
-               XLogReadBufferForRedoExtended(lsn, record, 0,
-                                                                         rnode, MAIN_FORKNUM, blkno,
-                                                                         RBM_ZERO, false, &buffer);
+               XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buffer);
                page = BufferGetPage(buffer);
                PageInit(page, BufferGetPageSize(buffer), 0);
                action = BLK_NEEDS_REDO;
        }
        else
-               action = XLogReadBufferForRedo(lsn, record, 0, rnode, blkno, &buffer);
-
+               action = XLogReadBufferForRedo(lsn, record, 0, &buffer);
        if (action == BLK_NEEDS_REDO)
        {
-               page = BufferGetPage(buffer);
+               char       *tupdata;
+               char       *endptr;
+               Size            len;
+
+               /* Tuples are stored as block data */
+               tupdata = XLogRecGetBlockData(record, 0, &len);
+               endptr = tupdata + len;
+
+               page = (Page) BufferGetPage(buffer);
+
                for (i = 0; i < xlrec->ntuples; i++)
                {
                        OffsetNumber offnum;
                        xl_multi_insert_tuple *xlhdr;
 
+                       /*
+                        * If we're reinitializing the page, the tuples are stored in order
+                        * from FirstOffsetNumber. Otherwise there's an array of offsets in
+                        * the WAL record, and the tuples come after that.
+                        */
                        if (isinit)
                                offnum = FirstOffsetNumber + i;
                        else
@@ -7706,8 +7542,8 @@ heap_xlog_multi_insert(XLogRecPtr lsn, XLogRecord *record)
                        if (PageGetMaxOffsetNumber(page) + 1 < offnum)
                                elog(PANIC, "heap_multi_insert_redo: invalid max offset number");
 
-                       xlhdr = (xl_multi_insert_tuple *) SHORTALIGN(recdata);
-                       recdata = ((char *) xlhdr) + SizeOfMultiInsertTuple;
+                       xlhdr = (xl_multi_insert_tuple *) SHORTALIGN(tupdata);
+                       tupdata = ((char *) xlhdr) + SizeOfMultiInsertTuple;
 
                        newlen = xlhdr->datalen;
                        Assert(newlen <= MaxHeapTupleSize);
@@ -7715,9 +7551,9 @@ heap_xlog_multi_insert(XLogRecPtr lsn, XLogRecord *record)
                        MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData));
                        /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */
                        memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits),
-                                  (char *) recdata,
+                                  (char *) tupdata,
                                   newlen);
-                       recdata += newlen;
+                       tupdata += newlen;
 
                        newlen += offsetof(HeapTupleHeaderData, t_bits);
                        htup->t_infomask2 = xlhdr->t_infomask2;
@@ -7732,6 +7568,8 @@ heap_xlog_multi_insert(XLogRecPtr lsn, XLogRecord *record)
                        if (offnum == InvalidOffsetNumber)
                                elog(PANIC, "heap_multi_insert_redo: failed to add tuple");
                }
+               if (tupdata != endptr)
+                       elog(PANIC, "heap_multi_insert_redo: total tuple length mismatch");
 
                freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
 
@@ -7755,7 +7593,7 @@ heap_xlog_multi_insert(XLogRecPtr lsn, XLogRecord *record)
         * totally accurate anyway.
         */
        if (action == BLK_NEEDS_REDO && freespace < BLCKSZ / 5)
-               XLogRecordPageWithFreeSpace(xlrec->node, blkno, freespace);
+               XLogRecordPageWithFreeSpace(rnode, blkno, freespace);
 }
 
 /*
@@ -7768,6 +7606,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
        RelFileNode rnode;
        BlockNumber oldblk;
        BlockNumber newblk;
+       ItemPointerData newtid;
        Buffer          obuffer,
                                nbuffer;
        Page            page;
@@ -7775,7 +7614,6 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
        ItemId          lp = NULL;
        HeapTupleData oldtup;
        HeapTupleHeader htup;
-       char       *recdata;
        uint16          prefixlen = 0,
                                suffixlen = 0;
        char       *newp;
@@ -7784,7 +7622,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
                HeapTupleHeaderData hdr;
                char            data[MaxHeapTupleSize];
        }                       tbuf;
-       xl_heap_header_len xlhdr;
+       xl_heap_header xlhdr;
        uint32          newlen;
        Size            freespace = 0;
        XLogRedoAction oldaction;
@@ -7794,9 +7632,17 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
        oldtup.t_data = NULL;
        oldtup.t_len = 0;
 
-       rnode = xlrec->target.node;
-       newblk = ItemPointerGetBlockNumber(&xlrec->newtid);
-       oldblk = ItemPointerGetBlockNumber(&xlrec->target.tid);
+       XLogRecGetBlockTag(record, 0, &rnode, NULL, &newblk);
+       if (XLogRecHasBlockRef(record, 1))
+       {
+               /* HOT updates are never done across pages */
+               Assert(!hot_update);
+               XLogRecGetBlockTag(record, 1, NULL, NULL, &oldblk);
+       }
+       else
+               oldblk = newblk;
+
+       ItemPointerSet(&newtid, newblk, xlrec->new_offnum);
 
        /*
         * The visibility map may need to be fixed even if the heap page is
@@ -7824,12 +7670,12 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
         */
 
        /* Deal with old tuple version */
-       oldaction = XLogReadBufferForRedo(lsn, record, 0, rnode, oldblk, &obuffer);
+       oldaction = XLogReadBufferForRedo(lsn, record, (oldblk == newblk) ? 0 : 1,
+                                                                         &obuffer);
        if (oldaction == BLK_NEEDS_REDO)
        {
-               page = (Page) BufferGetPage(obuffer);
-
-               offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
+               page = BufferGetPage(obuffer);
+               offnum = xlrec->old_offnum;
                if (PageGetMaxOffsetNumber(page) >= offnum)
                        lp = PageGetItemId(page, offnum);
 
@@ -7852,7 +7698,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
                HeapTupleHeaderSetXmax(htup, xlrec->old_xmax);
                HeapTupleHeaderSetCmax(htup, FirstCommandId, false);
                /* Set forward chain link in t_ctid */
-               htup->t_ctid = xlrec->newtid;
+               htup->t_ctid = newtid;
 
                /* Mark the page as a candidate for pruning */
                PageSetPrunable(page, record->xl_xid);
@@ -7874,16 +7720,14 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
        }
        else if (record->xl_info & XLOG_HEAP_INIT_PAGE)
        {
-               XLogReadBufferForRedoExtended(lsn, record, 1,
-                                                                         rnode, MAIN_FORKNUM, newblk,
-                                                                         RBM_ZERO, false, &nbuffer);
+               XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false,
+                                                                         &nbuffer);
                page = (Page) BufferGetPage(nbuffer);
                PageInit(page, BufferGetPageSize(nbuffer), 0);
                newaction = BLK_NEEDS_REDO;
        }
        else
-               newaction = XLogReadBufferForRedo(lsn, record, 1, rnode, newblk,
-                                                                                 &nbuffer);
+               newaction = XLogReadBufferForRedo(lsn, record, 0, &nbuffer);
 
        /*
         * The visibility map may need to be fixed even if the heap page is
@@ -7891,7 +7735,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
         */
        if (xlrec->flags & XLOG_HEAP_NEW_ALL_VISIBLE_CLEARED)
        {
-               Relation        reln = CreateFakeRelcacheEntry(xlrec->target.node);
+               Relation        reln = CreateFakeRelcacheEntry(rnode);
                Buffer          vmbuffer = InvalidBuffer;
 
                visibilitymap_pin(reln, newblk, &vmbuffer);
@@ -7903,14 +7747,20 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
        /* Deal with new tuple */
        if (newaction == BLK_NEEDS_REDO)
        {
-               page = (Page) BufferGetPage(nbuffer);
+               char       *recdata;
+               char       *recdataend;
+               Size            datalen;
+               Size            tuplen;
+
+               recdata = XLogRecGetBlockData(record, 0, &datalen);
+               recdataend = recdata + datalen;
 
-               offnum = ItemPointerGetOffsetNumber(&(xlrec->newtid));
+               page = BufferGetPage(nbuffer);
+
+               offnum = xlrec->new_offnum;
                if (PageGetMaxOffsetNumber(page) + 1 < offnum)
                        elog(PANIC, "heap_update_redo: invalid max offset number");
 
-               recdata = (char *) xlrec + SizeOfHeapUpdate;
-
                if (xlrec->flags & XLOG_HEAP_PREFIX_FROM_OLD)
                {
                        Assert(newblk == oldblk);
@@ -7924,10 +7774,12 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
                        recdata += sizeof(uint16);
                }
 
-               memcpy((char *) &xlhdr, recdata, SizeOfHeapHeaderLen);
-               recdata += SizeOfHeapHeaderLen;
+               memcpy((char *) &xlhdr, recdata, SizeOfHeapHeader);
+               recdata += SizeOfHeapHeader;
+
+               tuplen = recdataend - recdata;
+               Assert(tuplen <= MaxHeapTupleSize);
 
-               Assert(xlhdr.t_len + prefixlen + suffixlen <= MaxHeapTupleSize);
                htup = &tbuf.hdr;
                MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData));
 
@@ -7941,7 +7793,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
                        int                     len;
 
                        /* copy bitmap [+ padding] [+ oid] from WAL record */
-                       len = xlhdr.header.t_hoff - offsetof(HeapTupleHeaderData, t_bits);
+                       len = xlhdr.t_hoff - offsetof(HeapTupleHeaderData, t_bits);
                        memcpy(newp, recdata, len);
                        recdata += len;
                        newp += len;
@@ -7951,7 +7803,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
                        newp += prefixlen;
 
                        /* copy new tuple data from WAL record */
-                       len = xlhdr.t_len - (xlhdr.header.t_hoff - offsetof(HeapTupleHeaderData, t_bits));
+                       len = tuplen - (xlhdr.t_hoff - offsetof(HeapTupleHeaderData, t_bits));
                        memcpy(newp, recdata, len);
                        recdata += len;
                        newp += len;
@@ -7962,24 +7814,26 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
                         * copy bitmap [+ padding] [+ oid] + data from record, all in one
                         * go
                         */
-                       memcpy(newp, recdata, xlhdr.t_len);
-                       recdata += xlhdr.t_len;
-                       newp += xlhdr.t_len;
+                       memcpy(newp, recdata, tuplen);
+                       recdata += tuplen;
+                       newp += tuplen;
                }
+               Assert(recdata == recdataend);
+
                /* copy suffix from old tuple */
                if (suffixlen > 0)
                        memcpy(newp, (char *) oldtup.t_data + oldtup.t_len - suffixlen, suffixlen);
 
-               newlen = offsetof(HeapTupleHeaderData, t_bits) + xlhdr.t_len + prefixlen + suffixlen;
-               htup->t_infomask2 = xlhdr.header.t_infomask2;
-               htup->t_infomask = xlhdr.header.t_infomask;
-               htup->t_hoff = xlhdr.header.t_hoff;
+               newlen = offsetof(HeapTupleHeaderData, t_bits) + tuplen + prefixlen + suffixlen;
+               htup->t_infomask2 = xlhdr.t_infomask2;
+               htup->t_infomask = xlhdr.t_infomask;
+               htup->t_hoff = xlhdr.t_hoff;
 
                HeapTupleHeaderSetXmin(htup, record->xl_xid);
                HeapTupleHeaderSetCmin(htup, FirstCommandId);
                HeapTupleHeaderSetXmax(htup, xlrec->new_xmax);
                /* Make sure there is no forward chain link in t_ctid */
-               htup->t_ctid = xlrec->newtid;
+               htup->t_ctid = newtid;
 
                offnum = PageAddItem(page, (Item) htup, newlen, offnum, true, true);
                if (offnum == InvalidOffsetNumber)
@@ -7993,6 +7847,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
                PageSetLSN(page, lsn);
                MarkBufferDirty(nbuffer);
        }
+
        if (BufferIsValid(nbuffer) && nbuffer != obuffer)
                UnlockReleaseBuffer(nbuffer);
        if (BufferIsValid(obuffer))
@@ -8014,9 +7869,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
         * totally accurate anyway.
         */
        if (newaction == BLK_NEEDS_REDO && !hot_update && freespace < BLCKSZ / 5)
-               XLogRecordPageWithFreeSpace(xlrec->target.node,
-                                                                ItemPointerGetBlockNumber(&(xlrec->newtid)),
-                                                                       freespace);
+               XLogRecordPageWithFreeSpace(rnode, newblk, freespace);
 }
 
 static void
@@ -8029,13 +7882,11 @@ heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record)
        ItemId          lp = NULL;
        HeapTupleHeader htup;
 
-       if (XLogReadBufferForRedo(lsn, record, 0, xlrec->target.node,
-                                                         ItemPointerGetBlockNumber(&xlrec->target.tid),
-                                                         &buffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
        {
                page = (Page) BufferGetPage(buffer);
 
-               offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
+               offnum = xlrec->offnum;
                if (PageGetMaxOffsetNumber(page) >= offnum)
                        lp = PageGetItemId(page, offnum);
 
@@ -8055,7 +7906,9 @@ heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record)
                {
                        HeapTupleHeaderClearHotUpdated(htup);
                        /* Make sure there is no forward chain link in t_ctid */
-                       htup->t_ctid = xlrec->target.tid;
+                       ItemPointerSet(&htup->t_ctid,
+                                                  BufferGetBlockNumber(buffer),
+                                                  offnum);
                }
                HeapTupleHeaderSetXmax(htup, xlrec->locking_xid);
                HeapTupleHeaderSetCmax(htup, FirstCommandId, false);
@@ -8077,12 +7930,11 @@ heap_xlog_lock_updated(XLogRecPtr lsn, XLogRecord *record)
        ItemId          lp = NULL;
        HeapTupleHeader htup;
 
-       if (XLogReadBufferForRedo(lsn, record, 0, xlrec->target.node,
-                                                         ItemPointerGetBlockNumber(&(xlrec->target.tid)),
-                                                         &buffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
        {
                page = BufferGetPage(buffer);
-               offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
+
+               offnum = xlrec->offnum;
                if (PageGetMaxOffsetNumber(page) >= offnum)
                        lp = PageGetItemId(page, offnum);
 
@@ -8112,15 +7964,15 @@ heap_xlog_inplace(XLogRecPtr lsn, XLogRecord *record)
        ItemId          lp = NULL;
        HeapTupleHeader htup;
        uint32          oldlen;
-       uint32          newlen;
+       Size            newlen;
 
-       if (XLogReadBufferForRedo(lsn, record, 0, xlrec->target.node,
-                                                         ItemPointerGetBlockNumber(&(xlrec->target.tid)),
-                                                         &buffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
        {
+               char       *newtup = XLogRecGetBlockData(record, 0, &newlen);
+
                page = BufferGetPage(buffer);
 
-               offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
+               offnum = xlrec->offnum;
                if (PageGetMaxOffsetNumber(page) >= offnum)
                        lp = PageGetItemId(page, offnum);
 
@@ -8130,13 +7982,10 @@ heap_xlog_inplace(XLogRecPtr lsn, XLogRecord *record)
                htup = (HeapTupleHeader) PageGetItem(page, lp);
 
                oldlen = ItemIdGetLength(lp) - htup->t_hoff;
-               newlen = record->xl_len - SizeOfHeapInplace;
                if (oldlen != newlen)
                        elog(PANIC, "heap_inplace_redo: wrong tuple length");
 
-               memcpy((char *) htup + htup->t_hoff,
-                          (char *) xlrec + SizeOfHeapInplace,
-                          newlen);
+               memcpy((char *) htup + htup->t_hoff, newtup, newlen);
 
                PageSetLSN(page, lsn);
                MarkBufferDirty(buffer);
index bea52460a086cde3f3743df42aebedf7d88b5197..344de0ba2ed501a4be73b5e499c16fa811058bfe 100644 (file)
@@ -865,7 +865,6 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
        hash_seq_init(&seq_status, state->rs_logical_mappings);
        while ((src = (RewriteMappingFile *) hash_seq_search(&seq_status)) != NULL)
        {
-               XLogRecData rdata[2];
                char       *waldata;
                char       *waldata_start;
                xl_heap_rewrite_mapping xlrec;
@@ -889,11 +888,6 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
                xlrec.offset = src->off;
                xlrec.start_lsn = state->rs_begin_lsn;
 
-               rdata[0].data = (char *) (&xlrec);
-               rdata[0].len = sizeof(xlrec);
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].next = &(rdata[1]);
-
                /* write all mappings consecutively */
                len = src->num_mappings * sizeof(LogicalRewriteMappingData);
                waldata_start = waldata = palloc(len);
@@ -934,13 +928,12 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
                                                        written, len)));
                src->off += len;
 
-               rdata[1].data = waldata_start;
-               rdata[1].len = len;
-               rdata[1].buffer = InvalidBuffer;
-               rdata[1].next = NULL;
+               XLogBeginInsert();
+               XLogRegisterData((char *) (&xlrec), sizeof(xlrec));
+               XLogRegisterData(waldata_start, len);
 
                /* write xlog record */
-               XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_REWRITE, rdata);
+               XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_REWRITE);
 
                pfree(waldata_start);
        }
index bcaba7e5e8400f1b144131043d5818b2ffa50c33..de3557efabb28760bc347cbe59c7a641fdf4d596 100644 (file)
@@ -837,37 +837,25 @@ _bt_insertonpg(Relation rel,
                if (RelationNeedsWAL(rel))
                {
                        xl_btree_insert xlrec;
-                       BlockNumber xlleftchild;
                        xl_btree_metadata xlmeta;
                        uint8           xlinfo;
                        XLogRecPtr      recptr;
-                       XLogRecData rdata[4];
-                       XLogRecData *nextrdata;
                        IndexTupleData trunctuple;
 
-                       xlrec.target.node = rel->rd_node;
-                       ItemPointerSet(&(xlrec.target.tid), itup_blkno, itup_off);
+                       xlrec.offnum = itup_off;
 
-                       rdata[0].data = (char *) &xlrec;
-                       rdata[0].len = SizeOfBtreeInsert;
-                       rdata[0].buffer = InvalidBuffer;
-                       rdata[0].next = nextrdata = &(rdata[1]);
+                       XLogBeginInsert();
+                       XLogRegisterData((char *) &xlrec, SizeOfBtreeInsert);
 
                        if (P_ISLEAF(lpageop))
                                xlinfo = XLOG_BTREE_INSERT_LEAF;
                        else
                        {
                                /*
-                                * Include the block number of the left child, whose
-                                * INCOMPLETE_SPLIT flag was cleared.
+                                * Register the left child whose INCOMPLETE_SPLIT flag was
+                                * cleared.
                                 */
-                               xlleftchild = BufferGetBlockNumber(cbuf);
-                               nextrdata->data = (char *) &xlleftchild;
-                               nextrdata->len = sizeof(BlockNumber);
-                               nextrdata->buffer = cbuf;
-                               nextrdata->buffer_std = true;
-                               nextrdata->next = nextrdata + 1;
-                               nextrdata++;
+                               XLogRegisterBuffer(1, cbuf, REGBUF_STANDARD);
 
                                xlinfo = XLOG_BTREE_INSERT_UPPER;
                        }
@@ -879,33 +867,25 @@ _bt_insertonpg(Relation rel,
                                xlmeta.fastroot = metad->btm_fastroot;
                                xlmeta.fastlevel = metad->btm_fastlevel;
 
-                               nextrdata->data = (char *) &xlmeta;
-                               nextrdata->len = sizeof(xl_btree_metadata);
-                               nextrdata->buffer = InvalidBuffer;
-                               nextrdata->next = nextrdata + 1;
-                               nextrdata++;
+                               XLogRegisterBuffer(2, metabuf, REGBUF_WILL_INIT);
+                               XLogRegisterBufData(2, (char *) &xlmeta, sizeof(xl_btree_metadata));
 
                                xlinfo = XLOG_BTREE_INSERT_META;
                        }
 
                        /* Read comments in _bt_pgaddtup */
+                       XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
                        if (!P_ISLEAF(lpageop) && newitemoff == P_FIRSTDATAKEY(lpageop))
                        {
                                trunctuple = *itup;
                                trunctuple.t_info = sizeof(IndexTupleData);
-                               nextrdata->data = (char *) &trunctuple;
-                               nextrdata->len = sizeof(IndexTupleData);
+                               XLogRegisterBufData(0, (char *) &trunctuple,
+                                                                sizeof(IndexTupleData));
                        }
                        else
-                       {
-                               nextrdata->data = (char *) itup;
-                               nextrdata->len = IndexTupleDSize(*itup);
-                       }
-                       nextrdata->buffer = buf;
-                       nextrdata->buffer_std = true;
-                       nextrdata->next = NULL;
+                               XLogRegisterBufData(0, (char *) itup, IndexTupleDSize(*itup));
 
-                       recptr = XLogInsert(RM_BTREE_ID, xlinfo, rdata);
+                       recptr = XLogInsert(RM_BTREE_ID, xlinfo);
 
                        if (BufferIsValid(metabuf))
                        {
@@ -1260,25 +1240,24 @@ _bt_split(Relation rel, Buffer buf, Buffer cbuf, OffsetNumber firstright,
                xl_btree_split xlrec;
                uint8           xlinfo;
                XLogRecPtr      recptr;
-               XLogRecData rdata[7];
-               XLogRecData *lastrdata;
-               BlockNumber cblkno;
-
-               xlrec.node = rel->rd_node;
-               xlrec.leftsib = origpagenumber;
-               xlrec.rightsib = rightpagenumber;
-               xlrec.rnext = ropaque->btpo_next;
+
                xlrec.level = ropaque->btpo.level;
                xlrec.firstright = firstright;
+               xlrec.newitemoff = newitemoff;
 
-               rdata[0].data = (char *) &xlrec;
-               rdata[0].len = SizeOfBtreeSplit;
-               rdata[0].buffer = InvalidBuffer;
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, SizeOfBtreeSplit);
 
-               lastrdata = &rdata[0];
+               XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
+               XLogRegisterBuffer(1, rbuf, REGBUF_WILL_INIT);
+               /* Log the right sibling, because we've changed its prev-pointer. */
+               if (!P_RIGHTMOST(ropaque))
+                       XLogRegisterBuffer(2, sbuf, REGBUF_STANDARD);
+               if (BufferIsValid(cbuf))
+                       XLogRegisterBuffer(3, cbuf, REGBUF_STANDARD);
 
                /*
-                * Log the new item and its offset, if it was inserted on the left
+                * Log the new item, if it was inserted on the left
                 * page. (If it was put on the right page, we don't need to explicitly
                 * WAL log it because it's included with all the other items on the
                 * right page.) Show the new item as belonging to the left page
@@ -1287,29 +1266,11 @@ _bt_split(Relation rel, Buffer buf, Buffer cbuf, OffsetNumber firstright,
                 * though, to support archive compression of these records.
                 */
                if (newitemonleft)
-               {
-                       lastrdata->next = lastrdata + 1;
-                       lastrdata++;
-
-                       lastrdata->data = (char *) &newitemoff;
-                       lastrdata->len = sizeof(OffsetNumber);
-                       lastrdata->buffer = InvalidBuffer;
-
-                       lastrdata->next = lastrdata + 1;
-                       lastrdata++;
-
-                       lastrdata->data = (char *) newitem;
-                       lastrdata->len = MAXALIGN(newitemsz);
-                       lastrdata->buffer = buf;        /* backup block 0 */
-                       lastrdata->buffer_std = true;
-               }
+                       XLogRegisterBufData(0, (char *) newitem, MAXALIGN(newitemsz));
 
                /* Log left page */
                if (!isleaf)
                {
-                       lastrdata->next = lastrdata + 1;
-                       lastrdata++;
-
                        /*
                         * We must also log the left page's high key, because the right
                         * page's leftmost key is suppressed on non-leaf levels.  Show it
@@ -1319,43 +1280,7 @@ _bt_split(Relation rel, Buffer buf, Buffer cbuf, OffsetNumber firstright,
                         */
                        itemid = PageGetItemId(origpage, P_HIKEY);
                        item = (IndexTuple) PageGetItem(origpage, itemid);
-                       lastrdata->data = (char *) item;
-                       lastrdata->len = MAXALIGN(IndexTupleSize(item));
-                       lastrdata->buffer = buf;        /* backup block 0 */
-                       lastrdata->buffer_std = true;
-               }
-
-               if (isleaf && !newitemonleft)
-               {
-                       lastrdata->next = lastrdata + 1;
-                       lastrdata++;
-
-                       /*
-                        * Although we don't need to WAL-log anything on the left page, we
-                        * still need XLogInsert to consider storing a full-page image of
-                        * the left page, so make an empty entry referencing that buffer.
-                        * This also ensures that the left page is always backup block 0.
-                        */
-                       lastrdata->data = NULL;
-                       lastrdata->len = 0;
-                       lastrdata->buffer = buf;        /* backup block 0 */
-                       lastrdata->buffer_std = true;
-               }
-
-               /*
-                * Log block number of left child, whose INCOMPLETE_SPLIT flag this
-                * insertion clears.
-                */
-               if (!isleaf)
-               {
-                       lastrdata->next = lastrdata + 1;
-                       lastrdata++;
-
-                       cblkno = BufferGetBlockNumber(cbuf);
-                       lastrdata->data = (char *) &cblkno;
-                       lastrdata->len = sizeof(BlockNumber);
-                       lastrdata->buffer = cbuf;       /* backup block 1 */
-                       lastrdata->buffer_std = true;
+                       XLogRegisterBufData(0, (char *) item, MAXALIGN(IndexTupleSize(item)));
                }
 
                /*
@@ -1370,35 +1295,16 @@ _bt_split(Relation rel, Buffer buf, Buffer cbuf, OffsetNumber firstright,
                 * and so the item pointers can be reconstructed.  See comments for
                 * _bt_restore_page().
                 */
-               lastrdata->next = lastrdata + 1;
-               lastrdata++;
-
-               lastrdata->data = (char *) rightpage +
-                       ((PageHeader) rightpage)->pd_upper;
-               lastrdata->len = ((PageHeader) rightpage)->pd_special -
-                       ((PageHeader) rightpage)->pd_upper;
-               lastrdata->buffer = InvalidBuffer;
-
-               /* Log the right sibling, because we've changed its' prev-pointer. */
-               if (!P_RIGHTMOST(ropaque))
-               {
-                       lastrdata->next = lastrdata + 1;
-                       lastrdata++;
-
-                       lastrdata->data = NULL;
-                       lastrdata->len = 0;
-                       lastrdata->buffer = sbuf;       /* bkp block 1 (leaf) or 2 (non-leaf) */
-                       lastrdata->buffer_std = true;
-               }
-
-               lastrdata->next = NULL;
+               XLogRegisterBufData(1,
+                                                (char *) rightpage + ((PageHeader) rightpage)->pd_upper,
+                                                ((PageHeader) rightpage)->pd_special - ((PageHeader) rightpage)->pd_upper);
 
                if (isroot)
                        xlinfo = newitemonleft ? XLOG_BTREE_SPLIT_L_ROOT : XLOG_BTREE_SPLIT_R_ROOT;
                else
                        xlinfo = newitemonleft ? XLOG_BTREE_SPLIT_L : XLOG_BTREE_SPLIT_R;
 
-               recptr = XLogInsert(RM_BTREE_ID, xlinfo, rdata);
+               recptr = XLogInsert(RM_BTREE_ID, xlinfo);
 
                PageSetLSN(origpage, recptr);
                PageSetLSN(rightpage, recptr);
@@ -2090,34 +1996,35 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
        {
                xl_btree_newroot xlrec;
                XLogRecPtr      recptr;
-               XLogRecData rdata[3];
+               xl_btree_metadata md;
 
-               xlrec.node = rel->rd_node;
                xlrec.rootblk = rootblknum;
                xlrec.level = metad->btm_level;
 
-               rdata[0].data = (char *) &xlrec;
-               rdata[0].len = SizeOfBtreeNewroot;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].next = &(rdata[1]);
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, SizeOfBtreeNewroot);
+
+               XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT);
+               XLogRegisterBuffer(1, lbuf, REGBUF_STANDARD);
+               XLogRegisterBuffer(2, metabuf, REGBUF_WILL_INIT);
+
+               md.root = rootblknum;
+               md.level = metad->btm_level;
+               md.fastroot = rootblknum;
+               md.fastlevel = metad->btm_level;
+
+               XLogRegisterBufData(2, (char *) &md, sizeof(xl_btree_metadata));
 
                /*
                 * Direct access to page is not good but faster - we should implement
                 * some new func in page API.
                 */
-               rdata[1].data = (char *) rootpage + ((PageHeader) rootpage)->pd_upper;
-               rdata[1].len = ((PageHeader) rootpage)->pd_special -
-                       ((PageHeader) rootpage)->pd_upper;
-               rdata[1].buffer = InvalidBuffer;
-               rdata[1].next = &(rdata[2]);
-
-               /* Make a full-page image of the left child if needed */
-               rdata[2].data = NULL;
-               rdata[2].len = 0;
-               rdata[2].buffer = lbuf;
-               rdata[2].next = NULL;
-
-               recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT, rdata);
+               XLogRegisterBufData(0,
+                                                (char *) rootpage + ((PageHeader) rootpage)->pd_upper,
+                                                ((PageHeader) rootpage)->pd_special -
+                                                        ((PageHeader) rootpage)->pd_upper);
+
+               recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT);
 
                PageSetLSN(lpage, recptr);
                PageSetLSN(rootpage, recptr);
index 6093215c43df363718155ba3b8fbe0a587ebbaaa..cbcf8f7956006255d44a9e31189f1ada0be18cba 100644 (file)
@@ -38,8 +38,7 @@ static bool _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf,
 static bool _bt_lock_branch_parent(Relation rel, BlockNumber child,
                                           BTStack stack, Buffer *topparent, OffsetNumber *topoff,
                                           BlockNumber *target, BlockNumber *rightsib);
-static void _bt_log_reuse_page(Relation rel, BlockNumber blkno,
-                                  TransactionId latestRemovedXid);
+static void _bt_log_reuse_page(Relation rel, BlockNumber blkno, TransactionId latestRemovedXid);
 
 /*
  *     _bt_initmetapage() -- Fill a page buffer with a correct metapage image
@@ -236,18 +235,25 @@ _bt_getroot(Relation rel, int access)
                {
                        xl_btree_newroot xlrec;
                        XLogRecPtr      recptr;
-                       XLogRecData rdata;
+                       xl_btree_metadata md;
+
+                       XLogBeginInsert();
+                       XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT);
+                       XLogRegisterBuffer(2, metabuf, REGBUF_WILL_INIT);
+
+                       md.root = rootblkno;
+                       md.level = 0;
+                       md.fastroot = rootblkno;
+                       md.fastlevel = 0;
+
+                       XLogRegisterBufData(2, (char *) &md, sizeof(xl_btree_metadata));
 
-                       xlrec.node = rel->rd_node;
                        xlrec.rootblk = rootblkno;
                        xlrec.level = 0;
 
-                       rdata.data = (char *) &xlrec;
-                       rdata.len = SizeOfBtreeNewroot;
-                       rdata.buffer = InvalidBuffer;
-                       rdata.next = NULL;
+                       XLogRegisterData((char *) &xlrec, SizeOfBtreeNewroot);
 
-                       recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT, &rdata);
+                       recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT);
 
                        PageSetLSN(rootpage, recptr);
                        PageSetLSN(metapg, recptr);
@@ -528,39 +534,23 @@ _bt_checkpage(Relation rel, Buffer buf)
 static void
 _bt_log_reuse_page(Relation rel, BlockNumber blkno, TransactionId latestRemovedXid)
 {
-       if (!RelationNeedsWAL(rel))
-               return;
-
-       /* No ereport(ERROR) until changes are logged */
-       START_CRIT_SECTION();
+       xl_btree_reuse_page xlrec_reuse;
 
        /*
-        * We don't do MarkBufferDirty here because we're about to initialise the
-        * page, and nobody else can see it yet.
+        * Note that we don't register the buffer with the record, because this
+        * operation doesn't modify the page. This record only exists to provide
+        * a conflict point for Hot Standby.
         */
 
        /* XLOG stuff */
-       {
-               XLogRecData rdata[1];
-               xl_btree_reuse_page xlrec_reuse;
-
-               xlrec_reuse.node = rel->rd_node;
-               xlrec_reuse.block = blkno;
-               xlrec_reuse.latestRemovedXid = latestRemovedXid;
-               rdata[0].data = (char *) &xlrec_reuse;
-               rdata[0].len = SizeOfBtreeReusePage;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].next = NULL;
-
-               XLogInsert(RM_BTREE_ID, XLOG_BTREE_REUSE_PAGE, rdata);
+       xlrec_reuse.node = rel->rd_node;
+       xlrec_reuse.block = blkno;
+       xlrec_reuse.latestRemovedXid = latestRemovedXid;
 
-               /*
-                * We don't do PageSetLSN here because we're about to initialise the
-                * page, so no need.
-                */
-       }
+       XLogBeginInsert();
+       XLogRegisterData((char *) &xlrec_reuse, SizeOfBtreeReusePage);
 
-       END_CRIT_SECTION();
+       XLogInsert(RM_BTREE_ID, XLOG_BTREE_REUSE_PAGE);
 }
 
 /*
@@ -633,7 +623,7 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
                                         * WAL record that will allow us to conflict with queries
                                         * running on standby.
                                         */
-                                       if (XLogStandbyInfoActive())
+                                       if (XLogStandbyInfoActive() && RelationNeedsWAL(rel))
                                        {
                                                BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
 
@@ -830,17 +820,13 @@ _bt_delitems_vacuum(Relation rel, Buffer buf,
        if (RelationNeedsWAL(rel))
        {
                XLogRecPtr      recptr;
-               XLogRecData rdata[2];
                xl_btree_vacuum xlrec_vacuum;
 
-               xlrec_vacuum.node = rel->rd_node;
-               xlrec_vacuum.block = BufferGetBlockNumber(buf);
-
                xlrec_vacuum.lastBlockVacuumed = lastBlockVacuumed;
-               rdata[0].data = (char *) &xlrec_vacuum;
-               rdata[0].len = SizeOfBtreeVacuum;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].next = &(rdata[1]);
+
+               XLogBeginInsert();
+               XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
+               XLogRegisterData((char *) &xlrec_vacuum, SizeOfBtreeVacuum);
 
                /*
                 * The target-offsets array is not in the buffer, but pretend that it
@@ -848,20 +834,9 @@ _bt_delitems_vacuum(Relation rel, Buffer buf,
                 * need not be stored too.
                 */
                if (nitems > 0)
-               {
-                       rdata[1].data = (char *) itemnos;
-                       rdata[1].len = nitems * sizeof(OffsetNumber);
-               }
-               else
-               {
-                       rdata[1].data = NULL;
-                       rdata[1].len = 0;
-               }
-               rdata[1].buffer = buf;
-               rdata[1].buffer_std = true;
-               rdata[1].next = NULL;
+                       XLogRegisterBufData(0, (char *) itemnos, nitems * sizeof(OffsetNumber));
 
-               recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_VACUUM, rdata);
+               recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_VACUUM);
 
                PageSetLSN(page, recptr);
        }
@@ -919,36 +894,23 @@ _bt_delitems_delete(Relation rel, Buffer buf,
        if (RelationNeedsWAL(rel))
        {
                XLogRecPtr      recptr;
-               XLogRecData rdata[3];
                xl_btree_delete xlrec_delete;
 
-               xlrec_delete.node = rel->rd_node;
                xlrec_delete.hnode = heapRel->rd_node;
-               xlrec_delete.block = BufferGetBlockNumber(buf);
                xlrec_delete.nitems = nitems;
 
-               rdata[0].data = (char *) &xlrec_delete;
-               rdata[0].len = SizeOfBtreeDelete;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].next = &(rdata[1]);
+               XLogBeginInsert();
+               XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
+               XLogRegisterData((char *) &xlrec_delete, SizeOfBtreeDelete);
 
                /*
                 * We need the target-offsets array whether or not we store the whole
                 * buffer, to allow us to find the latestRemovedXid on a standby
                 * server.
                 */
-               rdata[1].data = (char *) itemnos;
-               rdata[1].len = nitems * sizeof(OffsetNumber);
-               rdata[1].buffer = InvalidBuffer;
-               rdata[1].next = &(rdata[2]);
-
-               rdata[2].data = NULL;
-               rdata[2].len = 0;
-               rdata[2].buffer = buf;
-               rdata[2].buffer_std = true;
-               rdata[2].next = NULL;
+               XLogRegisterData((char *) itemnos, nitems * sizeof(OffsetNumber));
 
-               recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_DELETE, rdata);
+               recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_DELETE);
 
                PageSetLSN(page, recptr);
        }
@@ -1493,33 +1455,26 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
        {
                xl_btree_mark_page_halfdead xlrec;
                XLogRecPtr      recptr;
-               XLogRecData rdata[2];
 
-               xlrec.target.node = rel->rd_node;
-               ItemPointerSet(&(xlrec.target.tid), BufferGetBlockNumber(topparent), topoff);
+               xlrec.poffset = topoff;
                xlrec.leafblk = leafblkno;
                if (target != leafblkno)
                        xlrec.topparent = target;
                else
                        xlrec.topparent = InvalidBlockNumber;
 
+               XLogBeginInsert();
+               XLogRegisterBuffer(0, leafbuf, REGBUF_WILL_INIT);
+               XLogRegisterBuffer(1, topparent, REGBUF_STANDARD);
+
                page = BufferGetPage(leafbuf);
                opaque = (BTPageOpaque) PageGetSpecialPointer(page);
                xlrec.leftblk = opaque->btpo_prev;
                xlrec.rightblk = opaque->btpo_next;
 
-               rdata[0].data = (char *) &xlrec;
-               rdata[0].len = SizeOfBtreeMarkPageHalfDead;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].next = &(rdata[1]);
-
-               rdata[1].data = NULL;
-               rdata[1].len = 0;
-               rdata[1].buffer = topparent;
-               rdata[1].buffer_std = true;
-               rdata[1].next = NULL;
+               XLogRegisterData((char *) &xlrec, SizeOfBtreeMarkPageHalfDead);
 
-               recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_MARK_PAGE_HALFDEAD, rdata);
+               recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_MARK_PAGE_HALFDEAD);
 
                page = BufferGetPage(topparent);
                PageSetLSN(page, recptr);
@@ -1755,6 +1710,12 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty)
         * Here we begin doing the deletion.
         */
 
+       /*
+        * The WAL record needs at most 5 buffer references, which is more than
+        * the default allowance.
+        */
+       XLogEnsureRecordSpace(5, 0);
+
        /* No ereport(ERROR) until changes are logged */
        START_CRIT_SECTION();
 
@@ -1827,63 +1788,44 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty)
                xl_btree_metadata xlmeta;
                uint8           xlinfo;
                XLogRecPtr      recptr;
-               XLogRecData rdata[4];
-               XLogRecData *nextrdata;
 
-               xlrec.node = rel->rd_node;
+               XLogBeginInsert();
+
+               XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
+               if (BufferIsValid(lbuf))
+                       XLogRegisterBuffer(1, lbuf, REGBUF_STANDARD);
+               XLogRegisterBuffer(2, rbuf, REGBUF_STANDARD);
+               if (target != leafblkno)
+                       XLogRegisterBuffer(3, leafbuf, REGBUF_WILL_INIT);
 
                /* information on the unlinked block */
-               xlrec.deadblk = target;
                xlrec.leftsib = leftsib;
                xlrec.rightsib = rightsib;
                xlrec.btpo_xact = opaque->btpo.xact;
 
                /* information needed to recreate the leaf block (if not the target) */
-               xlrec.leafblk = leafblkno;
                xlrec.leafleftsib = leafleftsib;
                xlrec.leafrightsib = leafrightsib;
                xlrec.topparent = nextchild;
 
-               rdata[0].data = (char *) &xlrec;
-               rdata[0].len = SizeOfBtreeUnlinkPage;
-               rdata[0].buffer = InvalidBuffer;
-               rdata[0].next = nextrdata = &(rdata[1]);
+               XLogRegisterData((char *) &xlrec, SizeOfBtreeUnlinkPage);
 
                if (BufferIsValid(metabuf))
                {
+                       XLogRegisterBuffer(4, metabuf, REGBUF_WILL_INIT);
+
                        xlmeta.root = metad->btm_root;
                        xlmeta.level = metad->btm_level;
                        xlmeta.fastroot = metad->btm_fastroot;
                        xlmeta.fastlevel = metad->btm_fastlevel;
 
-                       nextrdata->data = (char *) &xlmeta;
-                       nextrdata->len = sizeof(xl_btree_metadata);
-                       nextrdata->buffer = InvalidBuffer;
-                       nextrdata->next = nextrdata + 1;
-                       nextrdata++;
+                       XLogRegisterBufData(4, (char *) &xlmeta, sizeof(xl_btree_metadata));
                        xlinfo = XLOG_BTREE_UNLINK_PAGE_META;
                }
                else
                        xlinfo = XLOG_BTREE_UNLINK_PAGE;
 
-               nextrdata->data = NULL;
-               nextrdata->len = 0;
-               nextrdata->buffer = rbuf;
-               nextrdata->buffer_std = true;
-               nextrdata->next = NULL;
-
-               if (BufferIsValid(lbuf))
-               {
-                       nextrdata->next = nextrdata + 1;
-                       nextrdata++;
-                       nextrdata->data = NULL;
-                       nextrdata->len = 0;
-                       nextrdata->buffer = lbuf;
-                       nextrdata->buffer_std = true;
-                       nextrdata->next = NULL;
-               }
-
-               recptr = XLogInsert(RM_BTREE_ID, xlinfo, rdata);
+               recptr = XLogInsert(RM_BTREE_ID, xlinfo);
 
                if (BufferIsValid(metabuf))
                {
index 13951be62af2e376ee1f669ba81782ec1e93055b..1dd909b2fa21a97827f086ce1ccc44ca2ed17ff9 100644 (file)
@@ -72,17 +72,23 @@ _bt_restore_page(Page page, char *from, int len)
 }
 
 static void
-_bt_restore_meta(RelFileNode rnode, XLogRecPtr lsn,
-                                BlockNumber root, uint32 level,
-                                BlockNumber fastroot, uint32 fastlevel)
+_bt_restore_meta(XLogRecPtr lsn, XLogRecord *record, uint8 block_id)
 {
        Buffer          metabuf;
        Page            metapg;
        BTMetaPageData *md;
        BTPageOpaque pageop;
+       xl_btree_metadata *xlrec;
+       char       *ptr;
+       Size            len;
 
-       metabuf = XLogReadBuffer(rnode, BTREE_METAPAGE, true);
-       Assert(BufferIsValid(metabuf));
+       XLogReadBufferForRedoExtended(lsn, record, block_id, RBM_ZERO, false,
+                                                                 &metabuf);
+       ptr = XLogRecGetBlockData(record, block_id, &len);
+
+       Assert(len == sizeof(xl_btree_metadata));
+       Assert(BufferGetBlockNumber(metabuf) == BTREE_METAPAGE);
+       xlrec = (xl_btree_metadata *) ptr;
        metapg = BufferGetPage(metabuf);
 
        _bt_pageinit(metapg, BufferGetPageSize(metabuf));
@@ -90,10 +96,10 @@ _bt_restore_meta(RelFileNode rnode, XLogRecPtr lsn,
        md = BTPageGetMeta(metapg);
        md->btm_magic = BTREE_MAGIC;
        md->btm_version = BTREE_VERSION;
-       md->btm_root = root;
-       md->btm_level = level;
-       md->btm_fastroot = fastroot;
-       md->btm_fastlevel = fastlevel;
+       md->btm_root = xlrec->root;
+       md->btm_level = xlrec->level;
+       md->btm_fastroot = xlrec->fastroot;
+       md->btm_fastlevel = xlrec->fastlevel;
 
        pageop = (BTPageOpaque) PageGetSpecialPointer(metapg);
        pageop->btpo_flags = BTP_META;
@@ -117,18 +123,14 @@ _bt_restore_meta(RelFileNode rnode, XLogRecPtr lsn,
  * types that can insert a downlink: insert, split, and newroot.
  */
 static void
-_bt_clear_incomplete_split(XLogRecPtr lsn, XLogRecord *record,
-                                                  int block_index,
-                                                  RelFileNode rnode, BlockNumber cblock)
+_bt_clear_incomplete_split(XLogRecPtr lsn, XLogRecord *record, uint8 block_id)
 {
        Buffer          buf;
 
-       if (XLogReadBufferForRedo(lsn, record, block_index, rnode, cblock, &buf)
-               == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, block_id, &buf) == BLK_NEEDS_REDO)
        {
                Page            page = (Page) BufferGetPage(buf);
                BTPageOpaque pageop = (BTPageOpaque) PageGetSpecialPointer(page);
-
                Assert((pageop->btpo_flags & BTP_INCOMPLETE_SPLIT) != 0);
                pageop->btpo_flags &= ~BTP_INCOMPLETE_SPLIT;
 
@@ -146,32 +148,6 @@ btree_xlog_insert(bool isleaf, bool ismeta,
        xl_btree_insert *xlrec = (xl_btree_insert *) XLogRecGetData(record);
        Buffer          buffer;
        Page            page;
-       char       *datapos;
-       int                     datalen;
-       xl_btree_metadata md;
-       BlockNumber cblkno = 0;
-       int                     main_blk_index;
-
-       datapos = (char *) xlrec + SizeOfBtreeInsert;
-       datalen = record->xl_len - SizeOfBtreeInsert;
-
-       /*
-        * if this insert finishes a split at lower level, extract the block
-        * number of the (left) child.
-        */
-       if (!isleaf && (record->xl_info & XLR_BKP_BLOCK(0)) == 0)
-       {
-               memcpy(&cblkno, datapos, sizeof(BlockNumber));
-               Assert(cblkno != 0);
-               datapos += sizeof(BlockNumber);
-               datalen -= sizeof(BlockNumber);
-       }
-       if (ismeta)
-       {
-               memcpy(&md, datapos, sizeof(xl_btree_metadata));
-               datapos += sizeof(xl_btree_metadata);
-               datalen -= sizeof(xl_btree_metadata);
-       }
 
        /*
         * Insertion to an internal page finishes an incomplete split at the child
@@ -183,21 +159,15 @@ btree_xlog_insert(bool isleaf, bool ismeta,
         * cannot be updates happening.
         */
        if (!isleaf)
+               _bt_clear_incomplete_split(lsn, record, 1);
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
        {
-               _bt_clear_incomplete_split(lsn, record, 0, xlrec->target.node, cblkno);
-               main_blk_index = 1;
-       }
-       else
-               main_blk_index = 0;
+               Size            datalen;
+               char       *datapos = XLogRecGetBlockData(record, 0, &datalen);
 
-       if (XLogReadBufferForRedo(lsn, record, main_blk_index, xlrec->target.node,
-                                                         ItemPointerGetBlockNumber(&(xlrec->target.tid)),
-                                                         &buffer) == BLK_NEEDS_REDO)
-       {
                page = BufferGetPage(buffer);
 
-               if (PageAddItem(page, (Item) datapos, datalen,
-                                               ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
+               if (PageAddItem(page, (Item) datapos, datalen, xlrec->offnum,
                                                false, false) == InvalidOffsetNumber)
                        elog(PANIC, "btree_insert_redo: failed to add item");
 
@@ -215,9 +185,7 @@ btree_xlog_insert(bool isleaf, bool ismeta,
         * obsolete link from the metapage.
         */
        if (ismeta)
-               _bt_restore_meta(xlrec->target.node, lsn,
-                                                md.root, md.level,
-                                                md.fastroot, md.fastlevel);
+               _bt_restore_meta(lsn, record, 2);
 }
 
 static void
@@ -231,56 +199,19 @@ btree_xlog_split(bool onleft, bool isroot,
        Page            rpage;
        BTPageOpaque ropaque;
        char       *datapos;
-       int                     datalen;
-       OffsetNumber newitemoff = 0;
-       Item            newitem = NULL;
-       Size            newitemsz = 0;
+       Size            datalen;
        Item            left_hikey = NULL;
        Size            left_hikeysz = 0;
-       BlockNumber cblkno = InvalidBlockNumber;
-
-       datapos = (char *) xlrec + SizeOfBtreeSplit;
-       datalen = record->xl_len - SizeOfBtreeSplit;
-
-       /* Extract newitemoff and newitem, if present */
-       if (onleft)
-       {
-               memcpy(&newitemoff, datapos, sizeof(OffsetNumber));
-               datapos += sizeof(OffsetNumber);
-               datalen -= sizeof(OffsetNumber);
-       }
-       if (onleft && !(record->xl_info & XLR_BKP_BLOCK(0)))
-       {
-               /*
-                * We assume that 16-bit alignment is enough to apply IndexTupleSize
-                * (since it's fetching from a uint16 field) and also enough for
-                * PageAddItem to insert the tuple.
-                */
-               newitem = (Item) datapos;
-               newitemsz = MAXALIGN(IndexTupleSize(newitem));
-               datapos += newitemsz;
-               datalen -= newitemsz;
-       }
-
-       /* Extract left hikey and its size (still assuming 16-bit alignment) */
-       if (!isleaf && !(record->xl_info & XLR_BKP_BLOCK(0)))
-       {
-               left_hikey = (Item) datapos;
-               left_hikeysz = MAXALIGN(IndexTupleSize(left_hikey));
-               datapos += left_hikeysz;
-               datalen -= left_hikeysz;
-       }
-
-       /*
-        * If this insertion finishes an incomplete split, get the block number of
-        * the child.
-        */
-       if (!isleaf && !(record->xl_info & XLR_BKP_BLOCK(1)))
-       {
-               memcpy(&cblkno, datapos, sizeof(BlockNumber));
-               datapos += sizeof(BlockNumber);
-               datalen -= sizeof(BlockNumber);
-       }
+       BlockNumber     leftsib;
+       BlockNumber     rightsib;
+       BlockNumber     rnext;
+
+       XLogRecGetBlockTag(record, 0, NULL, NULL, &leftsib);
+       XLogRecGetBlockTag(record, 1, NULL, NULL, &rightsib);
+       if (XLogRecHasBlockRef(record, 2))
+               XLogRecGetBlockTag(record, 2, NULL, NULL, &rnext);
+       else
+               rnext = P_NONE;
 
        /*
         * Clear the incomplete split flag on the left sibling of the child page
@@ -288,18 +219,18 @@ btree_xlog_split(bool onleft, bool isroot,
         * before locking the other pages)
         */
        if (!isleaf)
-               _bt_clear_incomplete_split(lsn, record, 1, xlrec->node, cblkno);
+               _bt_clear_incomplete_split(lsn, record, 3);
 
        /* Reconstruct right (new) sibling page from scratch */
-       rbuf = XLogReadBuffer(xlrec->node, xlrec->rightsib, true);
-       Assert(BufferIsValid(rbuf));
+       XLogReadBufferForRedoExtended(lsn, record, 1, RBM_ZERO, false, &rbuf);
+       datapos = XLogRecGetBlockData(record, 1, &datalen);
        rpage = (Page) BufferGetPage(rbuf);
 
        _bt_pageinit(rpage, BufferGetPageSize(rbuf));
        ropaque = (BTPageOpaque) PageGetSpecialPointer(rpage);
 
-       ropaque->btpo_prev = xlrec->leftsib;
-       ropaque->btpo_next = xlrec->rnext;
+       ropaque->btpo_prev = leftsib;
+       ropaque->btpo_next = rnext;
        ropaque->btpo.level = xlrec->level;
        ropaque->btpo_flags = isleaf ? BTP_LEAF : 0;
        ropaque->btpo_cycleid = 0;
@@ -324,8 +255,7 @@ btree_xlog_split(bool onleft, bool isroot,
        /* don't release the buffer yet; we touch right page's first item below */
 
        /* Now reconstruct left (original) sibling page */
-       if (XLogReadBufferForRedo(lsn, record, 0, xlrec->node, xlrec->leftsib,
-                                                         &lbuf) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 0, &lbuf) == BLK_NEEDS_REDO)
        {
                /*
                 * To retain the same physical order of the tuples that they had, we
@@ -339,9 +269,31 @@ btree_xlog_split(bool onleft, bool isroot,
                Page            lpage = (Page) BufferGetPage(lbuf);
                BTPageOpaque lopaque = (BTPageOpaque) PageGetSpecialPointer(lpage);
                OffsetNumber off;
+               Item            newitem;
+               Size            newitemsz = 0;
                Page            newlpage;
                OffsetNumber leftoff;
 
+               datapos = XLogRecGetBlockData(record, 0, &datalen);
+
+               if (onleft)
+               {
+                       newitem = (Item) datapos;
+                       newitemsz = MAXALIGN(IndexTupleSize(newitem));
+                       datapos += newitemsz;
+                       datalen -= newitemsz;
+               }
+
+               /* Extract left hikey and its size (assuming 16-bit alignment) */
+               if (!isleaf)
+               {
+                       left_hikey = (Item) datapos;
+                       left_hikeysz = MAXALIGN(IndexTupleSize(left_hikey));
+                       datapos += left_hikeysz;
+                       datalen -= left_hikeysz;
+               }
+               Assert(datalen == 0);
+
                newlpage = PageGetTempPageCopySpecial(lpage);
 
                /* Set high key */
@@ -358,7 +310,7 @@ btree_xlog_split(bool onleft, bool isroot,
                        Item            item;
 
                        /* add the new item if it was inserted on left page */
-                       if (onleft && off == newitemoff)
+                       if (onleft && off == xlrec->newitemoff)
                        {
                                if (PageAddItem(newlpage, newitem, newitemsz, leftoff,
                                                                false, false) == InvalidOffsetNumber)
@@ -376,7 +328,7 @@ btree_xlog_split(bool onleft, bool isroot,
                }
 
                /* cope with possibility that newitem goes at the end */
-               if (onleft && off == newitemoff)
+               if (onleft && off == xlrec->newitemoff)
                {
                        if (PageAddItem(newlpage, newitem, newitemsz, leftoff,
                                                        false, false) == InvalidOffsetNumber)
@@ -390,7 +342,7 @@ btree_xlog_split(bool onleft, bool isroot,
                lopaque->btpo_flags = BTP_INCOMPLETE_SPLIT;
                if (isleaf)
                        lopaque->btpo_flags |= BTP_LEAF;
-               lopaque->btpo_next = xlrec->rightsib;
+               lopaque->btpo_next = rightsib;
                lopaque->btpo_cycleid = 0;
 
                PageSetLSN(lpage, lsn);
@@ -410,22 +362,16 @@ btree_xlog_split(bool onleft, bool isroot,
         * replay, because no other index update can be in progress, and readers
         * will cope properly when following an obsolete left-link.
         */
-       if (xlrec->rnext != P_NONE)
+       if (rnext != P_NONE)
        {
-               /*
-                * the backup block containing right sibling is 1 or 2, depending
-                * whether this was a leaf or internal page.
-                */
-               int                     rnext_index = isleaf ? 1 : 2;
                Buffer          buffer;
 
-               if (XLogReadBufferForRedo(lsn, record, rnext_index, xlrec->node,
-                                                                 xlrec->rnext, &buffer) == BLK_NEEDS_REDO)
+               if (XLogReadBufferForRedo(lsn, record, 2, &buffer) == BLK_NEEDS_REDO)
                {
                        Page            page = (Page) BufferGetPage(buffer);
                        BTPageOpaque pageop = (BTPageOpaque) PageGetSpecialPointer(page);
 
-                       pageop->btpo_prev = xlrec->rightsib;
+                       pageop->btpo_prev = rightsib;
 
                        PageSetLSN(page, lsn);
                        MarkBufferDirty(buffer);
@@ -466,9 +412,13 @@ btree_xlog_vacuum(XLogRecPtr lsn, XLogRecord *record)
         */
        if (HotStandbyActiveInReplay())
        {
+               RelFileNode thisrnode;
+               BlockNumber thisblkno;
                BlockNumber blkno;
 
-               for (blkno = xlrec->lastBlockVacuumed + 1; blkno < xlrec->block; blkno++)
+               XLogRecGetBlockTag(record, 0, &thisrnode, NULL, &thisblkno);
+
+               for (blkno = xlrec->lastBlockVacuumed + 1; blkno < thisblkno; blkno++)
                {
                        /*
                         * We use RBM_NORMAL_NO_LOG mode because it's not an error
@@ -483,7 +433,7 @@ btree_xlog_vacuum(XLogRecPtr lsn, XLogRecord *record)
                         * buffer manager we could optimise this so that if the block is
                         * not in shared_buffers we confirm it as unpinned.
                         */
-                       buffer = XLogReadBufferExtended(xlrec->node, MAIN_FORKNUM, blkno,
+                       buffer = XLogReadBufferExtended(thisrnode, MAIN_FORKNUM, blkno,
                                                                                        RBM_NORMAL_NO_LOG);
                        if (BufferIsValid(buffer))
                        {
@@ -497,20 +447,23 @@ btree_xlog_vacuum(XLogRecPtr lsn, XLogRecord *record)
         * Like in btvacuumpage(), we need to take a cleanup lock on every leaf
         * page. See nbtree/README for details.
         */
-       if (XLogReadBufferForRedoExtended(lsn, record, 0,
-                                                                         xlrec->node, MAIN_FORKNUM, xlrec->block,
-                                                                         RBM_NORMAL, true, &buffer)
+       if (XLogReadBufferForRedoExtended(lsn, record, 0, RBM_NORMAL, true, &buffer)
                == BLK_NEEDS_REDO)
        {
+               char       *ptr;
+               Size            len;
+
+               ptr = XLogRecGetBlockData(record, 0, &len);
+
                page = (Page) BufferGetPage(buffer);
 
-               if (record->xl_len > SizeOfBtreeVacuum)
+               if (len > 0)
                {
                        OffsetNumber *unused;
                        OffsetNumber *unend;
 
-                       unused = (OffsetNumber *) ((char *) xlrec + SizeOfBtreeVacuum);
-                       unend = (OffsetNumber *) ((char *) xlrec + record->xl_len);
+                       unused = (OffsetNumber *) ptr;
+                       unend = (OffsetNumber *) ((char *) ptr + len);
 
                        if ((unend - unused) > 0)
                                PageIndexMultiDelete(page, unused, unend - unused);
@@ -542,13 +495,16 @@ btree_xlog_vacuum(XLogRecPtr lsn, XLogRecord *record)
  * XXX optimise later with something like XLogPrefetchBuffer()
  */
 static TransactionId
-btree_xlog_delete_get_latestRemovedXid(xl_btree_delete *xlrec)
+btree_xlog_delete_get_latestRemovedXid(XLogRecord *record)
 {
+       xl_btree_delete *xlrec = (xl_btree_delete *) XLogRecGetData(record);
        OffsetNumber *unused;
        Buffer          ibuffer,
                                hbuffer;
        Page            ipage,
                                hpage;
+       RelFileNode rnode;
+       BlockNumber blkno;
        ItemId          iitemid,
                                hitemid;
        IndexTuple      itup;
@@ -588,9 +544,11 @@ btree_xlog_delete_get_latestRemovedXid(xl_btree_delete *xlrec)
         * InvalidTransactionId to cancel all HS transactions.  That's probably
         * overkill, but it's safe, and certainly better than panicking here.
         */
-       ibuffer = XLogReadBuffer(xlrec->node, xlrec->block, false);
+       XLogRecGetBlockTag(record, 0, &rnode, NULL, &blkno);
+       ibuffer = XLogReadBufferExtended(rnode, MAIN_FORKNUM, blkno, RBM_NORMAL);
        if (!BufferIsValid(ibuffer))
                return InvalidTransactionId;
+       LockBuffer(ibuffer, BT_READ);
        ipage = (Page) BufferGetPage(ibuffer);
 
        /*
@@ -611,12 +569,13 @@ btree_xlog_delete_get_latestRemovedXid(xl_btree_delete *xlrec)
                 * Locate the heap page that the index tuple points at
                 */
                hblkno = ItemPointerGetBlockNumber(&(itup->t_tid));
-               hbuffer = XLogReadBuffer(xlrec->hnode, hblkno, false);
+               hbuffer = XLogReadBufferExtended(xlrec->hnode, MAIN_FORKNUM, hblkno, RBM_NORMAL);
                if (!BufferIsValid(hbuffer))
                {
                        UnlockReleaseBuffer(ibuffer);
                        return InvalidTransactionId;
                }
+               LockBuffer(hbuffer, BUFFER_LOCK_SHARE);
                hpage = (Page) BufferGetPage(hbuffer);
 
                /*
@@ -698,17 +657,19 @@ btree_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
         */
        if (InHotStandby)
        {
-               TransactionId latestRemovedXid = btree_xlog_delete_get_latestRemovedXid(xlrec);
+               TransactionId latestRemovedXid = btree_xlog_delete_get_latestRemovedXid(record);
+               RelFileNode rnode;
 
-               ResolveRecoveryConflictWithSnapshot(latestRemovedXid, xlrec->node);
+               XLogRecGetBlockTag(record, 0, &rnode, NULL, NULL);
+
+               ResolveRecoveryConflictWithSnapshot(latestRemovedXid, rnode);
        }
 
        /*
         * We don't need to take a cleanup lock to apply these changes. See
         * nbtree/README for details.
         */
-       if (XLogReadBufferForRedo(lsn, record, 0, xlrec->node, xlrec->block,
-                                                         &buffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
        {
                page = (Page) BufferGetPage(buffer);
 
@@ -739,14 +700,11 @@ static void
 btree_xlog_mark_page_halfdead(uint8 info, XLogRecPtr lsn, XLogRecord *record)
 {
        xl_btree_mark_page_halfdead *xlrec = (xl_btree_mark_page_halfdead *) XLogRecGetData(record);
-       BlockNumber parent;
        Buffer          buffer;
        Page            page;
        BTPageOpaque pageop;
        IndexTupleData trunctuple;
 
-       parent = ItemPointerGetBlockNumber(&(xlrec->target.tid));
-
        /*
         * In normal operation, we would lock all the pages this WAL record
         * touches before changing any of them.  In WAL replay, it should be okay
@@ -756,8 +714,7 @@ btree_xlog_mark_page_halfdead(uint8 info, XLogRecPtr lsn, XLogRecord *record)
         */
 
        /* parent page */
-       if (XLogReadBufferForRedo(lsn, record, 0, xlrec->target.node, parent,
-                                                         &buffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 1, &buffer) == BLK_NEEDS_REDO)
        {
                OffsetNumber poffset;
                ItemId          itemid;
@@ -768,7 +725,7 @@ btree_xlog_mark_page_halfdead(uint8 info, XLogRecPtr lsn, XLogRecord *record)
                page = (Page) BufferGetPage(buffer);
                pageop = (BTPageOpaque) PageGetSpecialPointer(page);
 
-               poffset = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
+               poffset = xlrec->poffset;
 
                nextoffset = OffsetNumberNext(poffset);
                itemid = PageGetItemId(page, nextoffset);
@@ -788,8 +745,7 @@ btree_xlog_mark_page_halfdead(uint8 info, XLogRecPtr lsn, XLogRecord *record)
                UnlockReleaseBuffer(buffer);
 
        /* Rewrite the leaf page as a halfdead page */
-       buffer = XLogReadBuffer(xlrec->target.node, xlrec->leafblk, true);
-       Assert(BufferIsValid(buffer));
+       XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buffer);
        page = (Page) BufferGetPage(buffer);
 
        _bt_pageinit(page, BufferGetPageSize(buffer));
@@ -825,14 +781,12 @@ static void
 btree_xlog_unlink_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
 {
        xl_btree_unlink_page *xlrec = (xl_btree_unlink_page *) XLogRecGetData(record);
-       BlockNumber target;
        BlockNumber leftsib;
        BlockNumber rightsib;
        Buffer          buffer;
        Page            page;
        BTPageOpaque pageop;
 
-       target = xlrec->deadblk;
        leftsib = xlrec->leftsib;
        rightsib = xlrec->rightsib;
 
@@ -845,8 +799,7 @@ btree_xlog_unlink_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
         */
 
        /* Fix left-link of right sibling */
-       if (XLogReadBufferForRedo(lsn, record, 0, xlrec->node, rightsib, &buffer)
-               == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 2, &buffer) == BLK_NEEDS_REDO)
        {
                page = (Page) BufferGetPage(buffer);
                pageop = (BTPageOpaque) PageGetSpecialPointer(page);
@@ -861,8 +814,7 @@ btree_xlog_unlink_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
        /* Fix right-link of left sibling, if any */
        if (leftsib != P_NONE)
        {
-               if (XLogReadBufferForRedo(lsn, record, 1, xlrec->node, leftsib, &buffer)
-                       == BLK_NEEDS_REDO)
+               if (XLogReadBufferForRedo(lsn, record, 1, &buffer) == BLK_NEEDS_REDO)
                {
                        page = (Page) BufferGetPage(buffer);
                        pageop = (BTPageOpaque) PageGetSpecialPointer(page);
@@ -876,8 +828,7 @@ btree_xlog_unlink_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
        }
 
        /* Rewrite target page as empty deleted page */
-       buffer = XLogReadBuffer(xlrec->node, target, true);
-       Assert(BufferIsValid(buffer));
+       XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buffer);
        page = (Page) BufferGetPage(buffer);
 
        _bt_pageinit(page, BufferGetPageSize(buffer));
@@ -898,7 +849,7 @@ btree_xlog_unlink_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
         * itself, update the leaf to point to the next remaining child in the
         * branch.
         */
-       if (target != xlrec->leafblk)
+       if (XLogRecHasBlockRef(record, 3))
        {
                /*
                 * There is no real data on the page, so we just re-create it from
@@ -906,8 +857,7 @@ btree_xlog_unlink_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
                 */
                IndexTupleData trunctuple;
 
-               buffer = XLogReadBuffer(xlrec->node, xlrec->leafblk, true);
-               Assert(BufferIsValid(buffer));
+               XLogReadBufferForRedoExtended(lsn, record, 3, RBM_ZERO, false, &buffer);
                page = (Page) BufferGetPage(buffer);
                pageop = (BTPageOpaque) PageGetSpecialPointer(page);
 
@@ -936,15 +886,7 @@ btree_xlog_unlink_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
 
        /* Update metapage if needed */
        if (info == XLOG_BTREE_UNLINK_PAGE_META)
-       {
-               xl_btree_metadata md;
-
-               memcpy(&md, (char *) xlrec + SizeOfBtreeUnlinkPage,
-                          sizeof(xl_btree_metadata));
-               _bt_restore_meta(xlrec->node, lsn,
-                                                md.root, md.level,
-                                                md.fastroot, md.fastlevel);
-       }
+               _bt_restore_meta(lsn, record, 4);
 }
 
 static void
@@ -954,9 +896,10 @@ btree_xlog_newroot(XLogRecPtr lsn, XLogRecord *record)
        Buffer          buffer;
        Page            page;
        BTPageOpaque pageop;
+       char       *ptr;
+       Size            len;
 
-       buffer = XLogReadBuffer(xlrec->node, xlrec->rootblk, true);
-       Assert(BufferIsValid(buffer));
+       XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buffer);
        page = (Page) BufferGetPage(buffer);
 
        _bt_pageinit(page, BufferGetPageSize(buffer));
@@ -969,30 +912,20 @@ btree_xlog_newroot(XLogRecPtr lsn, XLogRecord *record)
                pageop->btpo_flags |= BTP_LEAF;
        pageop->btpo_cycleid = 0;
 
-       if (record->xl_len > SizeOfBtreeNewroot)
+       if (xlrec->level > 0)
        {
-               IndexTuple      itup;
-               BlockNumber cblkno;
-
-               _bt_restore_page(page,
-                                                (char *) xlrec + SizeOfBtreeNewroot,
-                                                record->xl_len - SizeOfBtreeNewroot);
-               /* extract block number of the left-hand split page */
-               itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, P_HIKEY));
-               cblkno = ItemPointerGetBlockNumber(&(itup->t_tid));
-               Assert(ItemPointerGetOffsetNumber(&(itup->t_tid)) == P_HIKEY);
+               ptr = XLogRecGetBlockData(record, 0, &len);
+               _bt_restore_page(page, ptr, len);
 
                /* Clear the incomplete-split flag in left child */
-               _bt_clear_incomplete_split(lsn, record, 0, xlrec->node, cblkno);
+               _bt_clear_incomplete_split(lsn, record, 1);
        }
 
        PageSetLSN(page, lsn);
        MarkBufferDirty(buffer);
        UnlockReleaseBuffer(buffer);
 
-       _bt_restore_meta(xlrec->node, lsn,
-                                        xlrec->rootblk, xlrec->level,
-                                        xlrec->rootblk, xlrec->level);
+       _bt_restore_meta(lsn, record, 2);
 }
 
 static void
@@ -1015,9 +948,6 @@ btree_xlog_reuse_page(XLogRecPtr lsn, XLogRecord *record)
                ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid,
                                                                                        xlrec->node);
        }
-
-       /* Backup blocks are not used in reuse_page records */
-       Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
 }
 
 
index 97dc3c0fa9115290db63ae412fd047d2601c6596..ffc70aea3dd8471ca68f2449338a42e410e81cf0 100644 (file)
@@ -27,54 +27,39 @@ brin_desc(StringInfo buf, XLogRecord *record)
        {
                xl_brin_createidx *xlrec = (xl_brin_createidx *) rec;
 
-               appendStringInfo(buf, "v%d pagesPerRange %u rel %u/%u/%u",
-                                                xlrec->version, xlrec->pagesPerRange,
-                                                xlrec->node.spcNode, xlrec->node.dbNode,
-                                                xlrec->node.relNode);
+               appendStringInfo(buf, "v%d pagesPerRange %u",
+                                                xlrec->version, xlrec->pagesPerRange);
        }
        else if (info == XLOG_BRIN_INSERT)
        {
                xl_brin_insert *xlrec = (xl_brin_insert *) rec;
 
-               appendStringInfo(buf, "rel %u/%u/%u heapBlk %u revmapBlk %u pagesPerRange %u TID (%u,%u)",
-                                                xlrec->node.spcNode, xlrec->node.dbNode,
-                                                xlrec->node.relNode,
-                                                xlrec->heapBlk, xlrec->revmapBlk,
+               appendStringInfo(buf, "heapBlk %u pagesPerRange %u offnum %u",
+                                                xlrec->heapBlk,
                                                 xlrec->pagesPerRange,
-                                                ItemPointerGetBlockNumber(&xlrec->tid),
-                                                ItemPointerGetOffsetNumber(&xlrec->tid));
+                                                xlrec->offnum);
        }
        else if (info == XLOG_BRIN_UPDATE)
        {
                xl_brin_update *xlrec = (xl_brin_update *) rec;
 
-               appendStringInfo(buf, "rel %u/%u/%u heapBlk %u revmapBlk %u pagesPerRange %u old TID (%u,%u) TID (%u,%u)",
-                                                xlrec->insert.node.spcNode, xlrec->insert.node.dbNode,
-                                                xlrec->insert.node.relNode,
-                                                xlrec->insert.heapBlk, xlrec->insert.revmapBlk,
+               appendStringInfo(buf, "heapBlk %u pagesPerRange %u old offnum %u, new offnum %u",
+                                                xlrec->insert.heapBlk,
                                                 xlrec->insert.pagesPerRange,
-                                                ItemPointerGetBlockNumber(&xlrec->oldtid),
-                                                ItemPointerGetOffsetNumber(&xlrec->oldtid),
-                                                ItemPointerGetBlockNumber(&xlrec->insert.tid),
-                                                ItemPointerGetOffsetNumber(&xlrec->insert.tid));
+                                                xlrec->oldOffnum,
+                                                xlrec->insert.offnum);
        }
        else if (info == XLOG_BRIN_SAMEPAGE_UPDATE)
        {
                xl_brin_samepage_update *xlrec = (xl_brin_samepage_update *) rec;
 
-               appendStringInfo(buf, "rel %u/%u/%u TID (%u,%u)",
-                                                xlrec->node.spcNode, xlrec->node.dbNode,
-                                                xlrec->node.relNode,
-                                                ItemPointerGetBlockNumber(&xlrec->tid),
-                                                ItemPointerGetOffsetNumber(&xlrec->tid));
+               appendStringInfo(buf, "offnum %u", xlrec->offnum);
        }
        else if (info == XLOG_BRIN_REVMAP_EXTEND)
        {
                xl_brin_revmap_extend *xlrec = (xl_brin_revmap_extend *) rec;
 
-               appendStringInfo(buf, "rel %u/%u/%u targetBlk %u",
-                                                xlrec->node.spcNode, xlrec->node.dbNode,
-                                                xlrec->node.relNode, xlrec->targetBlk);
+               appendStringInfo(buf, "targetBlk %u", xlrec->targetBlk);
        }
 }
 
index 2f783cee2bbd77477f274d91103d9d1a0dd418af..a4dc755bca4b0956fe8f08fa864f594426af7912 100644 (file)
 #include "postgres.h"
 
 #include "access/gin_private.h"
+#include "access/xlogutils.h"
 #include "lib/stringinfo.h"
 #include "storage/relfilenode.h"
 
-static void
-desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
-{
-       appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
-                                        node.spcNode, node.dbNode, node.relNode, blkno);
-}
-
 static void
 desc_recompress_leaf(StringInfo buf, ginxlogRecompressDataLeaf *insertData)
 {
@@ -85,18 +79,17 @@ gin_desc(StringInfo buf, XLogRecord *record)
        switch (info)
        {
                case XLOG_GIN_CREATE_INDEX:
-                       desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
+                       /* no further information */
                        break;
                case XLOG_GIN_CREATE_PTREE:
-                       desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
+                       /* no further information */
                        break;
                case XLOG_GIN_INSERT:
                        {
                                ginxlogInsert *xlrec = (ginxlogInsert *) rec;
                                char       *payload = rec + sizeof(ginxlogInsert);
 
-                               desc_node(buf, xlrec->node, xlrec->blkno);
-                               appendStringInfo(buf, " isdata: %c isleaf: %c",
+                               appendStringInfo(buf, "isdata: %c isleaf: %c",
                                                          (xlrec->flags & GIN_INSERT_ISDATA) ? 'T' : 'F',
                                                         (xlrec->flags & GIN_INSERT_ISLEAF) ? 'T' : 'F');
                                if (!(xlrec->flags & GIN_INSERT_ISLEAF))
@@ -119,7 +112,7 @@ gin_desc(StringInfo buf, XLogRecord *record)
                                        ginxlogRecompressDataLeaf *insertData =
                                        (ginxlogRecompressDataLeaf *) payload;
 
-                                       if (record->xl_info & XLR_BKP_BLOCK(0))
+                                       if (XLogRecHasBlockImage(record, 0))
                                                appendStringInfo(buf, " (full page image)");
                                        else
                                                desc_recompress_leaf(buf, insertData);
@@ -139,39 +132,38 @@ gin_desc(StringInfo buf, XLogRecord *record)
                        {
                                ginxlogSplit *xlrec = (ginxlogSplit *) rec;
 
-                               desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
-                               appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->flags & GIN_SPLIT_ROOT) ? 'T' : 'F');
+                               appendStringInfo(buf, "isrootsplit: %c",
+                                                                (((ginxlogSplit *) rec)->flags & GIN_SPLIT_ROOT) ? 'T' : 'F');
                                appendStringInfo(buf, " isdata: %c isleaf: %c",
                                                          (xlrec->flags & GIN_INSERT_ISDATA) ? 'T' : 'F',
                                                         (xlrec->flags & GIN_INSERT_ISLEAF) ? 'T' : 'F');
                        }
                        break;
                case XLOG_GIN_VACUUM_PAGE:
-                       desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
+                       /* no further information */
                        break;
                case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
                        {
                                ginxlogVacuumDataLeafPage *xlrec = (ginxlogVacuumDataLeafPage *) rec;
 
-                               desc_node(buf, xlrec->node, xlrec->blkno);
-                               if (record->xl_info & XLR_BKP_BLOCK(0))
+                               if (XLogRecHasBlockImage(record, 0))
                                        appendStringInfo(buf, " (full page image)");
                                else
                                        desc_recompress_leaf(buf, &xlrec->data);
                        }
                        break;
                case XLOG_GIN_DELETE_PAGE:
-                       desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
+                       /* no further information */
                        break;
                case XLOG_GIN_UPDATE_META_PAGE:
-                       desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO);
+                       /* no further information */
                        break;
                case XLOG_GIN_INSERT_LISTPAGE:
-                       desc_node(buf, ((ginxlogInsertListPage *) rec)->node, ((ginxlogInsertListPage *) rec)->blkno);
+                       /* no further information */
                        break;
                case XLOG_GIN_DELETE_LISTPAGE:
-                       appendStringInfo(buf, "%d pages, ", ((ginxlogDeleteListPages *) rec)->ndeleted);
-                       desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO);
+                       appendStringInfo(buf, "ndeleted: %d",
+                                                        ((ginxlogDeleteListPages *) rec)->ndeleted);
                        break;
        }
 }
index db3ba13ccdd0bcf0f37ee29a83e597ae126d4720..931f15a3e026d46534e40dbf5a4629441d21f6ae 100644 (file)
 #include "lib/stringinfo.h"
 #include "storage/relfilenode.h"
 
-static void
-out_target(StringInfo buf, RelFileNode node)
-{
-       appendStringInfo(buf, "rel %u/%u/%u",
-                                        node.spcNode, node.dbNode, node.relNode);
-}
-
 static void
 out_gistxlogPageUpdate(StringInfo buf, gistxlogPageUpdate *xlrec)
 {
-       out_target(buf, xlrec->node);
-       appendStringInfo(buf, "; block number %u", xlrec->blkno);
 }
 
 static void
 out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
 {
-       appendStringInfoString(buf, "page_split: ");
-       out_target(buf, xlrec->node);
-       appendStringInfo(buf, "; block number %u splits to %d pages",
-                                        xlrec->origblkno, xlrec->npage);
+       appendStringInfo(buf, "page_split: splits to %d pages",
+                                        xlrec->npage);
 }
 
 void
index ee2c073f71f73564f113f7da8166063cba2db48d..76ff2a14a439c27cc478804375479ab134e6efba 100644 (file)
 
 #include "access/heapam_xlog.h"
 
-static void
-out_target(StringInfo buf, xl_heaptid *target)
-{
-       appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
-                        target->node.spcNode, target->node.dbNode, target->node.relNode,
-                                        ItemPointerGetBlockNumber(&(target->tid)),
-                                        ItemPointerGetOffsetNumber(&(target->tid)));
-}
-
 static void
 out_infobits(StringInfo buf, uint8 infobits)
 {
@@ -51,13 +42,13 @@ heap_desc(StringInfo buf, XLogRecord *record)
        {
                xl_heap_insert *xlrec = (xl_heap_insert *) rec;
 
-               out_target(buf, &(xlrec->target));
+               appendStringInfo(buf, "off %u", xlrec->offnum);
        }
        else if (info == XLOG_HEAP_DELETE)
        {
                xl_heap_delete *xlrec = (xl_heap_delete *) rec;
 
-               out_target(buf, &(xlrec->target));
+               appendStringInfo(buf, "off %u", xlrec->offnum);
                appendStringInfoChar(buf, ' ');
                out_infobits(buf, xlrec->infobits_set);
        }
@@ -65,24 +56,24 @@ heap_desc(StringInfo buf, XLogRecord *record)
        {
                xl_heap_update *xlrec = (xl_heap_update *) rec;
 
-               out_target(buf, &(xlrec->target));
-               appendStringInfo(buf, " xmax %u ", xlrec->old_xmax);
+               appendStringInfo(buf, "off %u xmax %u",
+                                                xlrec->old_offnum,
+                                                xlrec->old_xmax);
                out_infobits(buf, xlrec->old_infobits_set);
-               appendStringInfo(buf, "; new tid %u/%u xmax %u",
-                                                ItemPointerGetBlockNumber(&(xlrec->newtid)),
-                                                ItemPointerGetOffsetNumber(&(xlrec->newtid)),
+               appendStringInfo(buf, "; new off %u xmax %u",
+                                                xlrec->new_offnum,
                                                 xlrec->new_xmax);
        }
        else if (info == XLOG_HEAP_HOT_UPDATE)
        {
                xl_heap_update *xlrec = (xl_heap_update *) rec;
 
-               out_target(buf, &(xlrec->target));
-               appendStringInfo(buf, " xmax %u ", xlrec->old_xmax);
+               appendStringInfo(buf, "off %u xmax %u",
+                                                xlrec->old_offnum,
+                                                xlrec->old_xmax);
                out_infobits(buf, xlrec->old_infobits_set);
-               appendStringInfo(buf, "; new tid %u/%u xmax %u",
-                                                ItemPointerGetBlockNumber(&(xlrec->newtid)),
-                                                ItemPointerGetOffsetNumber(&(xlrec->newtid)),
+               appendStringInfo(buf, "; new off %u xmax %u",
+                                                xlrec->new_offnum,
                                                 xlrec->new_xmax);
        }
        else if (info == XLOG_HEAP_LOCK)
@@ -90,15 +81,14 @@ heap_desc(StringInfo buf, XLogRecord *record)
                xl_heap_lock *xlrec = (xl_heap_lock *) rec;
 
                appendStringInfo(buf, "xid %u: ", xlrec->locking_xid);
-               out_target(buf, &(xlrec->target));
-               appendStringInfoChar(buf, ' ');
+               appendStringInfo(buf, "off %u ", xlrec->offnum);
                out_infobits(buf, xlrec->infobits_set);
        }
        else if (info == XLOG_HEAP_INPLACE)
        {
                xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
 
-               out_target(buf, &(xlrec->target));
+               appendStringInfo(buf, "off %u", xlrec->offnum);
        }
 }
 void
@@ -112,18 +102,13 @@ heap2_desc(StringInfo buf, XLogRecord *record)
        {
                xl_heap_clean *xlrec = (xl_heap_clean *) rec;
 
-               appendStringInfo(buf, "rel %u/%u/%u; blk %u remxid %u",
-                                                xlrec->node.spcNode, xlrec->node.dbNode,
-                                                xlrec->node.relNode, xlrec->block,
-                                                xlrec->latestRemovedXid);
+               appendStringInfo(buf, "remxid %u", xlrec->latestRemovedXid);
        }
        else if (info == XLOG_HEAP2_FREEZE_PAGE)
        {
                xl_heap_freeze_page *xlrec = (xl_heap_freeze_page *) rec;
 
-               appendStringInfo(buf, "rel %u/%u/%u; blk %u; cutoff xid %u ntuples %u",
-                                                xlrec->node.spcNode, xlrec->node.dbNode,
-                                                xlrec->node.relNode, xlrec->block,
+               appendStringInfo(buf, "cutoff xid %u ntuples %u",
                                                 xlrec->cutoff_xid, xlrec->ntuples);
        }
        else if (info == XLOG_HEAP2_CLEANUP_INFO)
@@ -136,17 +121,13 @@ heap2_desc(StringInfo buf, XLogRecord *record)
        {
                xl_heap_visible *xlrec = (xl_heap_visible *) rec;
 
-               appendStringInfo(buf, "rel %u/%u/%u; blk %u",
-                                                xlrec->node.spcNode, xlrec->node.dbNode,
-                                                xlrec->node.relNode, xlrec->block);
+               appendStringInfo(buf, "cutoff xid %u", xlrec->cutoff_xid);
        }
        else if (info == XLOG_HEAP2_MULTI_INSERT)
        {
                xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
 
-               appendStringInfo(buf, "rel %u/%u/%u; blk %u; %d tuples",
-                               xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
-                                                xlrec->blkno, xlrec->ntuples);
+               appendStringInfo(buf, "%d tuples", xlrec->ntuples);
        }
        else if (info == XLOG_HEAP2_LOCK_UPDATED)
        {
@@ -154,13 +135,18 @@ heap2_desc(StringInfo buf, XLogRecord *record)
 
                appendStringInfo(buf, "xmax %u msk %04x; ", xlrec->xmax,
                                                 xlrec->infobits_set);
-               out_target(buf, &(xlrec->target));
+               appendStringInfo(buf, "off %u", xlrec->offnum);
        }
        else if (info == XLOG_HEAP2_NEW_CID)
        {
                xl_heap_new_cid *xlrec = (xl_heap_new_cid *) rec;
 
-               out_target(buf, &(xlrec->target));
+               appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
+                                                xlrec->target_node.spcNode,
+                                                xlrec->target_node.dbNode,
+                                                xlrec->target_node.relNode,
+                                                ItemPointerGetBlockNumber(&(xlrec->target_tid)),
+                                                ItemPointerGetOffsetNumber(&(xlrec->target_tid)));
                appendStringInfo(buf, "; cmin: %u, cmax: %u, combo: %u",
                                                 xlrec->cmin, xlrec->cmax, xlrec->combocid);
        }
index 8b63f2b6ba9fbc2570456dfc860648fb1acb8d79..9b89cc2a4ccfccf8c6c6f3146b66201260d95e0c 100644 (file)
 
 #include "access/nbtree.h"
 
-static void
-out_target(StringInfo buf, xl_btreetid *target)
-{
-       appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
-                        target->node.spcNode, target->node.dbNode, target->node.relNode,
-                                        ItemPointerGetBlockNumber(&(target->tid)),
-                                        ItemPointerGetOffsetNumber(&(target->tid)));
-}
-
 void
 btree_desc(StringInfo buf, XLogRecord *record)
 {
@@ -39,7 +30,7 @@ btree_desc(StringInfo buf, XLogRecord *record)
                        {
                                xl_btree_insert *xlrec = (xl_btree_insert *) rec;
 
-                               out_target(buf, &(xlrec->target));
+                               appendStringInfo(buf, "off %u", xlrec->offnum);
                                break;
                        }
                case XLOG_BTREE_SPLIT_L:
@@ -49,11 +40,7 @@ btree_desc(StringInfo buf, XLogRecord *record)
                        {
                                xl_btree_split *xlrec = (xl_btree_split *) rec;
 
-                               appendStringInfo(buf, "rel %u/%u/%u ",
-                                                                xlrec->node.spcNode, xlrec->node.dbNode,
-                                                                xlrec->node.relNode);
-                               appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
-                                                                xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+                               appendStringInfo(buf, "level %u, firstright %d",
                                                                 xlrec->level, xlrec->firstright);
                                break;
                        }
@@ -61,9 +48,7 @@ btree_desc(StringInfo buf, XLogRecord *record)
                        {
                                xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
 
-                               appendStringInfo(buf, "rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
-                                                                xlrec->node.spcNode, xlrec->node.dbNode,
-                                                                xlrec->node.relNode, xlrec->block,
+                               appendStringInfo(buf, "lastBlockVacuumed %u",
                                                                 xlrec->lastBlockVacuumed);
                                break;
                        }
@@ -71,18 +56,14 @@ btree_desc(StringInfo buf, XLogRecord *record)
                        {
                                xl_btree_delete *xlrec = (xl_btree_delete *) rec;
 
-                               appendStringInfo(buf, "index %u/%u/%u; iblk %u, heap %u/%u/%u;",
-                                                                xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
-                                                                xlrec->block,
-                                                                xlrec->hnode.spcNode, xlrec->hnode.dbNode, xlrec->hnode.relNode);
+                               appendStringInfo(buf, "%d items", xlrec->nitems);
                                break;
                        }
                case XLOG_BTREE_MARK_PAGE_HALFDEAD:
                        {
                                xl_btree_mark_page_halfdead *xlrec = (xl_btree_mark_page_halfdead *) rec;
 
-                               out_target(buf, &(xlrec->target));
-                               appendStringInfo(buf, "; topparent %u; leaf %u; left %u; right %u",
+                               appendStringInfo(buf, "topparent %u; leaf %u; left %u; right %u",
                                                                 xlrec->topparent, xlrec->leafblk, xlrec->leftblk, xlrec->rightblk);
                                break;
                        }
@@ -91,22 +72,17 @@ btree_desc(StringInfo buf, XLogRecord *record)
                        {
                                xl_btree_unlink_page *xlrec = (xl_btree_unlink_page *) rec;
 
-                               appendStringInfo(buf, "rel %u/%u/%u; ",
-                                                                xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
-                               appendStringInfo(buf, "dead %u; left %u; right %u; btpo_xact %u; ",
-                                                                xlrec->deadblk, xlrec->leftsib, xlrec->rightsib, xlrec->btpo_xact);
-                               appendStringInfo(buf, "leaf %u; leafleft %u; leafright %u; topparent %u",
-                                                                xlrec->leafblk, xlrec->leafleftsib, xlrec->leafrightsib, xlrec->topparent);
+                               appendStringInfo(buf, "left %u; right %u; btpo_xact %u; ",
+                                                                xlrec->leftsib, xlrec->rightsib, xlrec->btpo_xact);
+                               appendStringInfo(buf, "leafleft %u; leafright %u; topparent %u",
+                                                                xlrec->leafleftsib, xlrec->leafrightsib, xlrec->topparent);
                                break;
                        }
                case XLOG_BTREE_NEWROOT:
                        {
                                xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
 
-                               appendStringInfo(buf, "rel %u/%u/%u; root %u lev %u",
-                                                                xlrec->node.spcNode, xlrec->node.dbNode,
-                                                                xlrec->node.relNode,
-                                                                xlrec->rootblk, xlrec->level);
+                               appendStringInfo(buf, "lev %u", xlrec->level);
                                break;
                        }
                case XLOG_BTREE_REUSE_PAGE:
index 3ee0427dcb6a798a237ae411ac1230a59fa0ce69..6c16776d3ebe39661189f43600225275df1db975 100644 (file)
 
 #include "access/spgist_private.h"
 
-static void
-out_target(StringInfo buf, RelFileNode node)
-{
-       appendStringInfo(buf, "rel %u/%u/%u ",
-                                        node.spcNode, node.dbNode, node.relNode);
-}
-
 void
 spg_desc(StringInfo buf, XLogRecord *record)
 {
@@ -38,48 +31,55 @@ spg_desc(StringInfo buf, XLogRecord *record)
                                                         ((RelFileNode *) rec)->relNode);
                        break;
                case XLOG_SPGIST_ADD_LEAF:
-                       out_target(buf, ((spgxlogAddLeaf *) rec)->node);
-                       appendStringInfo(buf, "%u",
-                                                        ((spgxlogAddLeaf *) rec)->blknoLeaf);
+                       {
+                               spgxlogAddLeaf *xlrec = (spgxlogAddLeaf *) rec;
+
+                               appendStringInfo(buf, "add leaf to page");
+                               appendStringInfo(buf, "; off %u; headoff %u; parentoff %u",
+                                                                xlrec->offnumLeaf, xlrec->offnumHeadLeaf,
+                                                                xlrec->offnumParent);
+                               if (xlrec->newPage)
+                                       appendStringInfo(buf, " (newpage)");
+                               if (xlrec->storesNulls)
+                                       appendStringInfo(buf, " (nulls)");
+                       }
                        break;
                case XLOG_SPGIST_MOVE_LEAFS:
-                       out_target(buf, ((spgxlogMoveLeafs *) rec)->node);
-                       appendStringInfo(buf, "%u leafs from page %u to page %u",
-                                                        ((spgxlogMoveLeafs *) rec)->nMoves,
-                                                        ((spgxlogMoveLeafs *) rec)->blknoSrc,
-                                                        ((spgxlogMoveLeafs *) rec)->blknoDst);
+                       appendStringInfo(buf, "%u leafs",
+                                                        ((spgxlogMoveLeafs *) rec)->nMoves);
                        break;
                case XLOG_SPGIST_ADD_NODE:
-                       out_target(buf, ((spgxlogAddNode *) rec)->node);
-                       appendStringInfo(buf, "%u:%u",
-                                                        ((spgxlogAddNode *) rec)->blkno,
+                       appendStringInfo(buf, "off %u",
                                                         ((spgxlogAddNode *) rec)->offnum);
                        break;
                case XLOG_SPGIST_SPLIT_TUPLE:
-                       out_target(buf, ((spgxlogSplitTuple *) rec)->node);
-                       appendStringInfo(buf, "%u:%u to %u:%u",
-                                                        ((spgxlogSplitTuple *) rec)->blknoPrefix,
+                       appendStringInfo(buf, "prefix off: %u, postfix off: %u (same %d, new %d)",
                                                         ((spgxlogSplitTuple *) rec)->offnumPrefix,
-                                                        ((spgxlogSplitTuple *) rec)->blknoPostfix,
-                                                        ((spgxlogSplitTuple *) rec)->offnumPostfix);
+                                                        ((spgxlogSplitTuple *) rec)->offnumPostfix,
+                                                        ((spgxlogSplitTuple *) rec)->postfixBlkSame,
+                                                        ((spgxlogSplitTuple *) rec)->newPage
+                               );
                        break;
                case XLOG_SPGIST_PICKSPLIT:
-                       out_target(buf, ((spgxlogPickSplit *) rec)->node);
+                       {
+                               spgxlogPickSplit *xlrec = (spgxlogPickSplit *) rec;
+
+                               appendStringInfo(buf, "ndel %u; nins %u",
+                                                                xlrec->nDelete, xlrec->nInsert);
+                               if (xlrec->innerIsParent)
+                                       appendStringInfo(buf, " (innerIsParent)");
+                               if (xlrec->isRootSplit)
+                                       appendStringInfo(buf, " (isRootSplit)");
+                       }
                        break;
                case XLOG_SPGIST_VACUUM_LEAF:
-                       out_target(buf, ((spgxlogVacuumLeaf *) rec)->node);
-                       appendStringInfo(buf, "page %u",
-                                                        ((spgxlogVacuumLeaf *) rec)->blkno);
+                       /* no further information */
                        break;
                case XLOG_SPGIST_VACUUM_ROOT:
-                       out_target(buf, ((spgxlogVacuumRoot *) rec)->node);
-                       appendStringInfo(buf, "page %u",
-                                                        ((spgxlogVacuumRoot *) rec)->blkno);
+                       /* no further information */
                        break;
                case XLOG_SPGIST_VACUUM_REDIRECT:
-                       out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
-                       appendStringInfo(buf, "page %u, newest XID %u",
-                                                        ((spgxlogVacuumRedirect *) rec)->blkno,
+                       appendStringInfo(buf, "newest XID %u",
                                                 ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
                        break;
        }
index e0957ff3a8ce433c091772e313dffffe51191c94..06edb0f45cf19fca5ba00ebd0eec04c441c4007c 100644 (file)
@@ -76,11 +76,7 @@ xlog_desc(StringInfo buf, XLogRecord *record)
        }
        else if (info == XLOG_FPI)
        {
-               BkpBlock   *bkp = (BkpBlock *) rec;
-
-               appendStringInfo(buf, "%s block %u",
-                                                relpathperm(bkp->node, bkp->fork),
-                                                bkp->block);
+               /* no further information to print */
        }
        else if (info == XLOG_BACKUP_END)
        {
index 21a071ab19932179758fb6b0e19009aa625043d6..59944b223d044076d2cbcbd938ad4a5bc3d4098b 100644 (file)
@@ -16,8 +16,8 @@
 #include "postgres.h"
 
 #include "access/genam.h"
-#include "access/xloginsert.h"
 #include "access/spgist_private.h"
+#include "access/xloginsert.h"
 #include "miscadmin.h"
 #include "storage/bufmgr.h"
 #include "utils/rel.h"
@@ -202,25 +202,17 @@ static void
 addLeafTuple(Relation index, SpGistState *state, SpGistLeafTuple leafTuple,
                   SPPageDesc *current, SPPageDesc *parent, bool isNulls, bool isNew)
 {
-       XLogRecData rdata[4];
        spgxlogAddLeaf xlrec;
 
-       xlrec.node = index->rd_node;
-       xlrec.blknoLeaf = current->blkno;
        xlrec.newPage = isNew;
        xlrec.storesNulls = isNulls;
 
        /* these will be filled below as needed */
        xlrec.offnumLeaf = InvalidOffsetNumber;
        xlrec.offnumHeadLeaf = InvalidOffsetNumber;
-       xlrec.blknoParent = InvalidBlockNumber;
        xlrec.offnumParent = InvalidOffsetNumber;
        xlrec.nodeI = 0;
 
-       ACCEPT_RDATA_DATA(&xlrec, sizeof(xlrec), 0);
-       ACCEPT_RDATA_DATA(leafTuple, leafTuple->size, 1);
-       ACCEPT_RDATA_BUFFER(current->buffer, 2);
-
        START_CRIT_SECTION();
 
        if (current->offnum == InvalidOffsetNumber ||
@@ -237,13 +229,10 @@ addLeafTuple(Relation index, SpGistState *state, SpGistLeafTuple leafTuple,
                /* Must update parent's downlink if any */
                if (parent->buffer != InvalidBuffer)
                {
-                       xlrec.blknoParent = parent->blkno;
                        xlrec.offnumParent = parent->offnum;
                        xlrec.nodeI = parent->node;
 
                        saveNodeLink(index, parent, current->blkno, current->offnum);
-
-                       ACCEPT_RDATA_BUFFER(parent->buffer, 3);
                }
        }
        else
@@ -303,12 +292,20 @@ addLeafTuple(Relation index, SpGistState *state, SpGistLeafTuple leafTuple,
        {
                XLogRecPtr      recptr;
 
-               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_ADD_LEAF, rdata);
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, sizeof(xlrec));
+               XLogRegisterData((char *) leafTuple, leafTuple->size);
+
+               XLogRegisterBuffer(0, current->buffer, REGBUF_STANDARD);
+               if (xlrec.offnumParent != InvalidOffsetNumber)
+                       XLogRegisterBuffer(1, parent->buffer, REGBUF_STANDARD);
+
+               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_ADD_LEAF);
 
                PageSetLSN(current->page, recptr);
 
                /* update parent only if we actually changed it */
-               if (xlrec.blknoParent != InvalidBlockNumber)
+               if (xlrec.offnumParent != InvalidOffsetNumber)
                {
                        PageSetLSN(parent->page, recptr);
                }
@@ -399,7 +396,6 @@ moveLeafs(Relation index, SpGistState *state,
        OffsetNumber *toDelete;
        OffsetNumber *toInsert;
        BlockNumber nblkno;
-       XLogRecData rdata[7];
        spgxlogMoveLeafs xlrec;
        char       *leafdata,
                           *leafptr;
@@ -455,20 +451,6 @@ moveLeafs(Relation index, SpGistState *state,
        nblkno = BufferGetBlockNumber(nbuf);
        Assert(nblkno != current->blkno);
 
-       /* prepare WAL info */
-       xlrec.node = index->rd_node;
-       STORE_STATE(state, xlrec.stateSrc);
-
-       xlrec.blknoSrc = current->blkno;
-       xlrec.blknoDst = nblkno;
-       xlrec.nMoves = nDelete;
-       xlrec.replaceDead = replaceDead;
-       xlrec.storesNulls = isNulls;
-
-       xlrec.blknoParent = parent->blkno;
-       xlrec.offnumParent = parent->offnum;
-       xlrec.nodeI = parent->node;
-
        leafdata = leafptr = palloc(size);
 
        START_CRIT_SECTION();
@@ -533,15 +515,29 @@ moveLeafs(Relation index, SpGistState *state,
        {
                XLogRecPtr      recptr;
 
-               ACCEPT_RDATA_DATA(&xlrec, SizeOfSpgxlogMoveLeafs, 0);
-               ACCEPT_RDATA_DATA(toDelete, sizeof(OffsetNumber) * nDelete, 1);
-               ACCEPT_RDATA_DATA(toInsert, sizeof(OffsetNumber) * nInsert, 2);
-               ACCEPT_RDATA_DATA(leafdata, leafptr - leafdata, 3);
-               ACCEPT_RDATA_BUFFER(current->buffer, 4);
-               ACCEPT_RDATA_BUFFER(nbuf, 5);
-               ACCEPT_RDATA_BUFFER(parent->buffer, 6);
+               /* prepare WAL info */
+               STORE_STATE(state, xlrec.stateSrc);
 
-               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_MOVE_LEAFS, rdata);
+               xlrec.nMoves = nDelete;
+               xlrec.replaceDead = replaceDead;
+               xlrec.storesNulls = isNulls;
+
+               xlrec.offnumParent = parent->offnum;
+               xlrec.nodeI = parent->node;
+
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, SizeOfSpgxlogMoveLeafs);
+               XLogRegisterData((char *) toDelete,
+                                                sizeof(OffsetNumber) * nDelete);
+               XLogRegisterData((char *) toInsert,
+                                                sizeof(OffsetNumber) * nInsert);
+               XLogRegisterData((char *) leafdata, leafptr - leafdata);
+
+               XLogRegisterBuffer(0, current->buffer, REGBUF_STANDARD);
+               XLogRegisterBuffer(1, nbuf, REGBUF_STANDARD | (xlrec.newPage ? REGBUF_WILL_INIT : 0));
+               XLogRegisterBuffer(2, parent->buffer, REGBUF_STANDARD);
+
+               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_MOVE_LEAFS);
 
                PageSetLSN(current->page, recptr);
                PageSetLSN(npage, recptr);
@@ -701,8 +697,6 @@ doPickSplit(Relation index, SpGistState *state,
        int                     currentFreeSpace;
        int                     totalLeafSizes;
        bool            allTheSame;
-       XLogRecData rdata[10];
-       int                     nRdata;
        spgxlogPickSplit xlrec;
        char       *leafdata,
                           *leafptr;
@@ -725,7 +719,6 @@ doPickSplit(Relation index, SpGistState *state,
        newLeafs = (SpGistLeafTuple *) palloc(sizeof(SpGistLeafTuple) * n);
        leafPageSelect = (uint8 *) palloc(sizeof(uint8) * n);
 
-       xlrec.node = index->rd_node;
        STORE_STATE(state, xlrec.stateSrc);
 
        /*
@@ -971,10 +964,6 @@ doPickSplit(Relation index, SpGistState *state,
        }
 
        /*
-        * Because a WAL record can't involve more than four buffers, we can only
-        * afford to deal with two leaf pages in each picksplit action, ie the
-        * current page and at most one other.
-        *
         * The new leaf tuples converted from the existing ones should require the
         * same or less space, and therefore should all fit onto one page
         * (although that's not necessarily the current page, since we can't
@@ -1108,17 +1097,13 @@ doPickSplit(Relation index, SpGistState *state,
        }
 
        /* Start preparing WAL record */
-       xlrec.blknoSrc = current->blkno;
-       xlrec.blknoDest = InvalidBlockNumber;
        xlrec.nDelete = 0;
        xlrec.initSrc = isNew;
        xlrec.storesNulls = isNulls;
+       xlrec.isRootSplit = SpGistBlockIsRoot(current->blkno);
 
        leafdata = leafptr = (char *) palloc(totalLeafSizes);
 
-       ACCEPT_RDATA_DATA(&xlrec, SizeOfSpgxlogPickSplit, 0);
-       nRdata = 1;
-
        /* Here we begin making the changes to the target pages */
        START_CRIT_SECTION();
 
@@ -1150,12 +1135,6 @@ doPickSplit(Relation index, SpGistState *state,
                else
                {
                        xlrec.nDelete = nToDelete;
-                       ACCEPT_RDATA_DATA(toDelete,
-                                                         sizeof(OffsetNumber) * nToDelete,
-                                                         nRdata);
-                       nRdata++;
-                       ACCEPT_RDATA_BUFFER(current->buffer, nRdata);
-                       nRdata++;
 
                        if (!state->isBuild)
                        {
@@ -1240,25 +1219,8 @@ doPickSplit(Relation index, SpGistState *state,
        if (newLeafBuffer != InvalidBuffer)
        {
                MarkBufferDirty(newLeafBuffer);
-               /* also save block number for WAL */
-               xlrec.blknoDest = BufferGetBlockNumber(newLeafBuffer);
-               if (!xlrec.initDest)
-               {
-                       ACCEPT_RDATA_BUFFER(newLeafBuffer, nRdata);
-                       nRdata++;
-               }
        }
 
-       xlrec.nInsert = nToInsert;
-       ACCEPT_RDATA_DATA(toInsert, sizeof(OffsetNumber) * nToInsert, nRdata);
-       nRdata++;
-       ACCEPT_RDATA_DATA(leafPageSelect, sizeof(uint8) * nToInsert, nRdata);
-       nRdata++;
-       ACCEPT_RDATA_DATA(innerTuple, innerTuple->size, nRdata);
-       nRdata++;
-       ACCEPT_RDATA_DATA(leafdata, leafptr - leafdata, nRdata);
-       nRdata++;
-
        /* Remember current buffer, since we're about to change "current" */
        saveCurrent = *current;
 
@@ -1276,7 +1238,6 @@ doPickSplit(Relation index, SpGistState *state,
                current->blkno = parent->blkno;
                current->buffer = parent->buffer;
                current->page = parent->page;
-               xlrec.blknoInner = current->blkno;
                xlrec.offnumInner = current->offnum =
                        SpGistPageAddNewItem(state, current->page,
                                                                 (Item) innerTuple, innerTuple->size,
@@ -1285,14 +1246,11 @@ doPickSplit(Relation index, SpGistState *state,
                /*
                 * Update parent node link and mark parent page dirty
                 */
-               xlrec.blknoParent = parent->blkno;
+               xlrec.innerIsParent = true;
                xlrec.offnumParent = parent->offnum;
                xlrec.nodeI = parent->node;
                saveNodeLink(index, parent, current->blkno, current->offnum);
 
-               ACCEPT_RDATA_BUFFER(parent->buffer, nRdata);
-               nRdata++;
-
                /*
                 * Update redirection link (in old current buffer)
                 */
@@ -1314,7 +1272,6 @@ doPickSplit(Relation index, SpGistState *state,
                current->buffer = newInnerBuffer;
                current->blkno = BufferGetBlockNumber(current->buffer);
                current->page = BufferGetPage(current->buffer);
-               xlrec.blknoInner = current->blkno;
                xlrec.offnumInner = current->offnum =
                        SpGistPageAddNewItem(state, current->page,
                                                                 (Item) innerTuple, innerTuple->size,
@@ -1326,16 +1283,11 @@ doPickSplit(Relation index, SpGistState *state,
                /*
                 * Update parent node link and mark parent page dirty
                 */
-               xlrec.blknoParent = parent->blkno;
+               xlrec.innerIsParent = (parent->buffer == current->buffer);
                xlrec.offnumParent = parent->offnum;
                xlrec.nodeI = parent->node;
                saveNodeLink(index, parent, current->blkno, current->offnum);
 
-               ACCEPT_RDATA_BUFFER(current->buffer, nRdata);
-               nRdata++;
-               ACCEPT_RDATA_BUFFER(parent->buffer, nRdata);
-               nRdata++;
-
                /*
                 * Update redirection link (in old current buffer)
                 */
@@ -1357,8 +1309,8 @@ doPickSplit(Relation index, SpGistState *state,
 
                SpGistInitBuffer(current->buffer, (isNulls ? SPGIST_NULLS : 0));
                xlrec.initInner = true;
+               xlrec.innerIsParent = false;
 
-               xlrec.blknoInner = current->blkno;
                xlrec.offnumInner = current->offnum =
                        PageAddItem(current->page, (Item) innerTuple, innerTuple->size,
                                                InvalidOffsetNumber, false, false);
@@ -1367,7 +1319,6 @@ doPickSplit(Relation index, SpGistState *state,
                                 innerTuple->size);
 
                /* No parent link to update, nor redirection to do */
-               xlrec.blknoParent = InvalidBlockNumber;
                xlrec.offnumParent = InvalidOffsetNumber;
                xlrec.nodeI = 0;
 
@@ -1381,9 +1332,46 @@ doPickSplit(Relation index, SpGistState *state,
        if (RelationNeedsWAL(index))
        {
                XLogRecPtr      recptr;
+               int                     flags;
+
+               XLogBeginInsert();
+
+               xlrec.nInsert = nToInsert;
+               XLogRegisterData((char *) &xlrec, SizeOfSpgxlogPickSplit);
+
+               XLogRegisterData((char *) toDelete,
+                                                sizeof(OffsetNumber) * xlrec.nDelete);
+               XLogRegisterData((char *) toInsert,
+                                                sizeof(OffsetNumber) * xlrec.nInsert);
+               XLogRegisterData((char *) leafPageSelect,
+                                                sizeof(uint8) * xlrec.nInsert);
+               XLogRegisterData((char *) innerTuple, innerTuple->size);
+               XLogRegisterData(leafdata, leafptr - leafdata);
+
+               flags = REGBUF_STANDARD;
+               if (xlrec.initSrc)
+                       flags |= REGBUF_WILL_INIT;
+               if (BufferIsValid(saveCurrent.buffer))
+                       XLogRegisterBuffer(0, saveCurrent.buffer, flags);
+
+               if (BufferIsValid(newLeafBuffer))
+               {
+                       flags = REGBUF_STANDARD;
+                       if (xlrec.initDest)
+                               flags |= REGBUF_WILL_INIT;
+                       XLogRegisterBuffer(1, newLeafBuffer, flags);
+               }
+               XLogRegisterBuffer(2, current->buffer, REGBUF_STANDARD);
+               if (parent->buffer != InvalidBuffer)
+               {
+                       if (parent->buffer != current->buffer)
+                               XLogRegisterBuffer(3, parent->buffer, REGBUF_STANDARD);
+                       else
+                               Assert(xlrec.innerIsParent);
+               }
 
                /* Issue the WAL record */
-               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_PICKSPLIT, rdata);
+               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_PICKSPLIT);
 
                /* Update page LSNs on all affected pages */
                if (newLeafBuffer != InvalidBuffer)
@@ -1489,7 +1477,6 @@ spgAddNodeAction(Relation index, SpGistState *state,
                                 int nodeN, Datum nodeLabel)
 {
        SpGistInnerTuple newInnerTuple;
-       XLogRecData rdata[5];
        spgxlogAddNode xlrec;
 
        /* Should not be applied to nulls */
@@ -1499,25 +1486,18 @@ spgAddNodeAction(Relation index, SpGistState *state,
        newInnerTuple = addNode(state, innerTuple, nodeLabel, nodeN);
 
        /* Prepare WAL record */
-       xlrec.node = index->rd_node;
        STORE_STATE(state, xlrec.stateSrc);
-       xlrec.blkno = current->blkno;
        xlrec.offnum = current->offnum;
 
        /* we don't fill these unless we need to change the parent downlink */
-       xlrec.blknoParent = InvalidBlockNumber;
+       xlrec.parentBlk = -1;
        xlrec.offnumParent = InvalidOffsetNumber;
        xlrec.nodeI = 0;
 
        /* we don't fill these unless tuple has to be moved */
-       xlrec.blknoNew = InvalidBlockNumber;
        xlrec.offnumNew = InvalidOffsetNumber;
        xlrec.newPage = false;
 
-       ACCEPT_RDATA_DATA(&xlrec, sizeof(xlrec), 0);
-       ACCEPT_RDATA_DATA(newInnerTuple, newInnerTuple->size, 1);
-       ACCEPT_RDATA_BUFFER(current->buffer, 2);
-
        if (PageGetExactFreeSpace(current->page) >=
                newInnerTuple->size - innerTuple->size)
        {
@@ -1539,7 +1519,13 @@ spgAddNodeAction(Relation index, SpGistState *state,
                {
                        XLogRecPtr      recptr;
 
-                       recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_ADD_NODE, rdata);
+                       XLogBeginInsert();
+                       XLogRegisterData((char *) &xlrec, sizeof(xlrec));
+                       XLogRegisterData((char *) newInnerTuple, newInnerTuple->size);
+
+                       XLogRegisterBuffer(0, current->buffer, REGBUF_STANDARD);
+
+                       recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_ADD_NODE);
 
                        PageSetLSN(current->page, recptr);
                }
@@ -1565,7 +1551,6 @@ spgAddNodeAction(Relation index, SpGistState *state,
 
                saveCurrent = *current;
 
-               xlrec.blknoParent = parent->blkno;
                xlrec.offnumParent = parent->offnum;
                xlrec.nodeI = parent->node;
 
@@ -1580,8 +1565,6 @@ spgAddNodeAction(Relation index, SpGistState *state,
                current->blkno = BufferGetBlockNumber(current->buffer);
                current->page = BufferGetPage(current->buffer);
 
-               xlrec.blknoNew = current->blkno;
-
                /*
                 * Let's just make real sure new current isn't same as old.  Right now
                 * that's impossible, but if SpGistGetBuffer ever got smart enough to
@@ -1590,17 +1573,19 @@ spgAddNodeAction(Relation index, SpGistState *state,
                 * replay would be subtly wrong, so I think a mere assert isn't enough
                 * here.
                 */
-               if (xlrec.blknoNew == xlrec.blkno)
+               if (current->blkno == saveCurrent.blkno)
                        elog(ERROR, "SPGiST new buffer shouldn't be same as old buffer");
 
                /*
                 * New current and parent buffer will both be modified; but note that
                 * parent buffer could be same as either new or old current.
                 */
-               ACCEPT_RDATA_BUFFER(current->buffer, 3);
-               if (parent->buffer != current->buffer &&
-                       parent->buffer != saveCurrent.buffer)
-                       ACCEPT_RDATA_BUFFER(parent->buffer, 4);
+               if (parent->buffer == saveCurrent.buffer)
+                       xlrec.parentBlk = 0;
+               else if (parent->buffer == current->buffer)
+                       xlrec.parentBlk = 1;
+               else
+                       xlrec.parentBlk = 2;
 
                START_CRIT_SECTION();
 
@@ -1647,7 +1632,20 @@ spgAddNodeAction(Relation index, SpGistState *state,
                {
                        XLogRecPtr      recptr;
 
-                       recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_ADD_NODE, rdata);
+                       XLogBeginInsert();
+
+                       /* orig page */
+                       XLogRegisterBuffer(0, saveCurrent.buffer, REGBUF_STANDARD);
+                       /* new page */
+                       XLogRegisterBuffer(1, current->buffer, REGBUF_STANDARD);
+                       /* parent page (if different from orig and new) */
+                       if (xlrec.parentBlk == 2)
+                               XLogRegisterBuffer(2, parent->buffer, REGBUF_STANDARD);
+
+                       XLogRegisterData((char *) &xlrec, sizeof(xlrec));
+                       XLogRegisterData((char *) newInnerTuple, newInnerTuple->size);
+
+                       recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_ADD_NODE);
 
                        /* we don't bother to check if any of these are redundant */
                        PageSetLSN(current->page, recptr);
@@ -1682,7 +1680,6 @@ spgSplitNodeAction(Relation index, SpGistState *state,
        BlockNumber postfixBlkno;
        OffsetNumber postfixOffset;
        int                     i;
-       XLogRecData rdata[5];
        spgxlogSplitTuple xlrec;
        Buffer          newBuffer = InvalidBuffer;
 
@@ -1725,14 +1722,8 @@ spgSplitNodeAction(Relation index, SpGistState *state,
        postfixTuple->allTheSame = innerTuple->allTheSame;
 
        /* prep data for WAL record */
-       xlrec.node = index->rd_node;
        xlrec.newPage = false;
 
-       ACCEPT_RDATA_DATA(&xlrec, sizeof(xlrec), 0);
-       ACCEPT_RDATA_DATA(prefixTuple, prefixTuple->size, 1);
-       ACCEPT_RDATA_DATA(postfixTuple, postfixTuple->size, 2);
-       ACCEPT_RDATA_BUFFER(current->buffer, 3);
-
        /*
         * If we can't fit both tuples on the current page, get a new page for the
         * postfix tuple.  In particular, can't split to the root page.
@@ -1752,7 +1743,6 @@ spgSplitNodeAction(Relation index, SpGistState *state,
                                                                        GBUF_INNER_PARITY(current->blkno + 1),
                                                                        postfixTuple->size + sizeof(ItemIdData),
                                                                        &xlrec.newPage);
-               ACCEPT_RDATA_BUFFER(newBuffer, 4);
        }
 
        START_CRIT_SECTION();
@@ -1767,27 +1757,28 @@ spgSplitNodeAction(Relation index, SpGistState *state,
        if (xlrec.offnumPrefix != current->offnum)
                elog(ERROR, "failed to add item of size %u to SPGiST index page",
                         prefixTuple->size);
-       xlrec.blknoPrefix = current->blkno;
 
        /*
         * put postfix tuple into appropriate page
         */
        if (newBuffer == InvalidBuffer)
        {
-               xlrec.blknoPostfix = postfixBlkno = current->blkno;
+               postfixBlkno = current->blkno;
                xlrec.offnumPostfix = postfixOffset =
                        SpGistPageAddNewItem(state, current->page,
                                                                 (Item) postfixTuple, postfixTuple->size,
                                                                 NULL, false);
+               xlrec.postfixBlkSame = true;
        }
        else
        {
-               xlrec.blknoPostfix = postfixBlkno = BufferGetBlockNumber(newBuffer);
+               postfixBlkno = BufferGetBlockNumber(newBuffer);
                xlrec.offnumPostfix = postfixOffset =
                        SpGistPageAddNewItem(state, BufferGetPage(newBuffer),
                                                                 (Item) postfixTuple, postfixTuple->size,
                                                                 NULL, false);
                MarkBufferDirty(newBuffer);
+               xlrec.postfixBlkSame = false;
        }
 
        /*
@@ -1808,7 +1799,23 @@ spgSplitNodeAction(Relation index, SpGistState *state,
        {
                XLogRecPtr      recptr;
 
-               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_SPLIT_TUPLE, rdata);
+               XLogBeginInsert();
+               XLogRegisterData((char *) &xlrec, sizeof(xlrec));
+               XLogRegisterData((char *) prefixTuple, prefixTuple->size);
+               XLogRegisterData((char *) postfixTuple, postfixTuple->size);
+
+               XLogRegisterBuffer(0, current->buffer, REGBUF_STANDARD);
+               if (newBuffer != InvalidBuffer)
+               {
+                       int             flags;
+
+                       flags = REGBUF_STANDARD;
+                       if (xlrec.newPage)
+                               flags |= REGBUF_WILL_INIT;
+                       XLogRegisterBuffer(1, newBuffer, flags);
+               }
+
+               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_SPLIT_TUPLE);
 
                PageSetLSN(current->page, recptr);
 
index e1dfc8e358076086109c4f79c8fa3ff78bc41f7f..f168ac5c5cf7e3cd7d05ffae88897c2608c97a7a 100644 (file)
@@ -105,15 +105,18 @@ spgbuild(PG_FUNCTION_ARGS)
        if (RelationNeedsWAL(index))
        {
                XLogRecPtr      recptr;
-               XLogRecData rdata;
 
-               /* WAL data is just the relfilenode */
-               rdata.data = (char *) &(index->rd_node);
-               rdata.len = sizeof(RelFileNode);
-               rdata.buffer = InvalidBuffer;
-               rdata.next = NULL;
+               XLogBeginInsert();
 
-               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_CREATE_INDEX, &rdata);
+               /*
+                * Replay will re-initialize the pages, so don't take full pages
+                * images.  No other data to log.
+                */
+               XLogRegisterBuffer(0, metabuffer, REGBUF_WILL_INIT);
+               XLogRegisterBuffer(1, rootbuffer, REGBUF_WILL_INIT | REGBUF_STANDARD);
+               XLogRegisterBuffer(2, nullbuffer, REGBUF_WILL_INIT | REGBUF_STANDARD);
+
+               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_CREATE_INDEX);
 
                PageSetLSN(BufferGetPage(metabuffer), recptr);
                PageSetLSN(BufferGetPage(rootbuffer), recptr);
index 2e05d22b74967ffa4b48c3c84c8d1780a48f076f..c0cab7ee1f186329ea5721e3310a01c098ada860 100644 (file)
@@ -127,7 +127,6 @@ vacuumLeafPage(spgBulkDeleteState *bds, Relation index, Buffer buffer,
 {
        Page            page = BufferGetPage(buffer);
        spgxlogVacuumLeaf xlrec;
-       XLogRecData rdata[8];
        OffsetNumber toDead[MaxIndexTuplesPerPage];
        OffsetNumber toPlaceholder[MaxIndexTuplesPerPage];
        OffsetNumber moveSrc[MaxIndexTuplesPerPage];
@@ -323,23 +322,26 @@ vacuumLeafPage(spgBulkDeleteState *bds, Relation index, Buffer buffer,
        if (nDeletable != xlrec.nDead + xlrec.nPlaceholder + xlrec.nMove)
                elog(ERROR, "inconsistent counts of deletable tuples");
 
-       /* Prepare WAL record */
-       xlrec.node = index->rd_node;
-       xlrec.blkno = BufferGetBlockNumber(buffer);
-       STORE_STATE(&bds->spgstate, xlrec.stateSrc);
-
-       ACCEPT_RDATA_DATA(&xlrec, SizeOfSpgxlogVacuumLeaf, 0);
-       ACCEPT_RDATA_DATA(toDead, sizeof(OffsetNumber) * xlrec.nDead, 1);
-       ACCEPT_RDATA_DATA(toPlaceholder, sizeof(OffsetNumber) * xlrec.nPlaceholder, 2);
-       ACCEPT_RDATA_DATA(moveSrc, sizeof(OffsetNumber) * xlrec.nMove, 3);
-       ACCEPT_RDATA_DATA(moveDest, sizeof(OffsetNumber) * xlrec.nMove, 4);
-       ACCEPT_RDATA_DATA(chainSrc, sizeof(OffsetNumber) * xlrec.nChain, 5);
-       ACCEPT_RDATA_DATA(chainDest, sizeof(OffsetNumber) * xlrec.nChain, 6);
-       ACCEPT_RDATA_BUFFER(buffer, 7);
-
        /* Do the updates */
        START_CRIT_SECTION();
 
+       /* Prepare WAL record */
+       if (RelationNeedsWAL(index))
+       {
+               XLogBeginInsert();
+
+               STORE_STATE(&bds->spgstate, xlrec.stateSrc);
+
+               XLogRegisterData((char *) &xlrec, SizeOfSpgxlogVacuumLeaf);
+               /* sizeof(xlrec) should be a multiple of sizeof(OffsetNumber) */
+               XLogRegisterData((char *) toDead, sizeof(OffsetNumber) * xlrec.nDead);
+               XLogRegisterData((char *) toPlaceholder, sizeof(OffsetNumber) * xlrec.nPlaceholder);
+               XLogRegisterData((char *) moveSrc, sizeof(OffsetNumber) * xlrec.nMove);
+               XLogRegisterData((char *) moveDest, sizeof(OffsetNumber) * xlrec.nMove);
+               XLogRegisterData((char *) chainSrc, sizeof(OffsetNumber) * xlrec.nChain);
+               XLogRegisterData((char *) chainDest, sizeof(OffsetNumber) * xlrec.nChain);
+       }
+
        spgPageIndexMultiDelete(&bds->spgstate, page,
                                                        toDead, xlrec.nDead,
                                                        SPGIST_DEAD, SPGIST_DEAD,
@@ -389,7 +391,9 @@ vacuumLeafPage(spgBulkDeleteState *bds, Relation index, Buffer buffer,
        {
                XLogRecPtr      recptr;
 
-               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_VACUUM_LEAF, rdata);
+               XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | REGBUF_FORCE_IMAGE);
+
+               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_VACUUM_LEAF);
 
                PageSetLSN(page, recptr);
        }
@@ -407,12 +411,10 @@ vacuumLeafRoot(spgBulkDeleteState *bds, Relation index, Buffer buffer)
 {
        Page            page = BufferGetPage(buffer);
        spgxlogVacuumRoot xlrec;
-       XLogRecData rdata[3];
        OffsetNumber toDelete[MaxIndexTuplesPerPage];
        OffsetNumber i,
                                max = PageGetMaxOffsetNumber(page);
 
-       xlrec.blkno = BufferGetBlockNumber(buffer);
        xlrec.nDelete = 0;
 
        /* Scan page, identify tuples to delete, accumulate stats */
@@ -448,15 +450,6 @@ vacuumLeafRoot(spgBulkDeleteState *bds, Relation index, Buffer buffer)
        if (xlrec.nDelete == 0)
                return;                                 /* nothing more to do */
 
-       /* Prepare WAL record */
-       xlrec.node = index->rd_node;
-       STORE_STATE(&bds->spgstate, xlrec.stateSrc);
-
-       ACCEPT_RDATA_DATA(&xlrec, SizeOfSpgxlogVacuumRoot, 0);
-       /* sizeof(xlrec) should be a multiple of sizeof(OffsetNumber) */
-       ACCEPT_RDATA_DATA(toDelete, sizeof(OffsetNumber) * xlrec.nDelete, 1);
-       ACCEPT_RDATA_BUFFER(buffer, 2);
-
        /* Do the update */
        START_CRIT_SECTION();
 
@@ -469,7 +462,19 @@ vacuumLeafRoot(spgBulkDeleteState *bds, Relation index, Buffer buffer)
        {
                XLogRecPtr      recptr;
 
-               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_VACUUM_ROOT, rdata);
+               XLogBeginInsert();
+
+               /* Prepare WAL record */
+               STORE_STATE(&bds->spgstate, xlrec.stateSrc);
+
+               XLogRegisterData((char *) &xlrec, SizeOfSpgxlogVacuumRoot);
+               /* sizeof(xlrec) should be a multiple of sizeof(OffsetNumber) */
+               XLogRegisterData((char *) toDelete,
+                                                sizeof(OffsetNumber) * xlrec.nDelete);
+
+               XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
+
+               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_VACUUM_ROOT);
 
                PageSetLSN(page, recptr);
        }
@@ -499,10 +504,7 @@ vacuumRedirectAndPlaceholder(Relation index, Buffer buffer)
        OffsetNumber itemToPlaceholder[MaxIndexTuplesPerPage];
        OffsetNumber itemnos[MaxIndexTuplesPerPage];
        spgxlogVacuumRedirect xlrec;
-       XLogRecData rdata[3];
 
-       xlrec.node = index->rd_node;
-       xlrec.blkno = BufferGetBlockNumber(buffer);
        xlrec.nToPlaceholder = 0;
        xlrec.newestRedirectXid = InvalidTransactionId;
 
@@ -585,11 +587,15 @@ vacuumRedirectAndPlaceholder(Relation index, Buffer buffer)
        {
                XLogRecPtr      recptr;
 
-               ACCEPT_RDATA_DATA(&xlrec, SizeOfSpgxlogVacuumRedirect, 0);
-               ACCEPT_RDATA_DATA(itemToPlaceholder, sizeof(OffsetNumber) * xlrec.nToPlaceholder, 1);
-               ACCEPT_RDATA_BUFFER(buffer, 2);
+               XLogBeginInsert();
+
+               XLogRegisterData((char *) &xlrec, SizeOfSpgxlogVacuumRedirect);
+               XLogRegisterData((char *) itemToPlaceholder,
+                                                sizeof(OffsetNumber) * xlrec.nToPlaceholder);
+
+               XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
 
-               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_VACUUM_REDIRECT, rdata);
+               recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_VACUUM_REDIRECT);
 
                PageSetLSN(page, recptr);
        }
index 920739436ac37c2a75b06150b00e816119ea7cd1..24990aa24ab14923e8ce6c9f93a731c94ec5d1f2 100644 (file)
@@ -73,31 +73,27 @@ addOrReplaceTuple(Page page, Item tuple, int size, OffsetNumber offset)
 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));
+       XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buffer);
+       Assert(BufferGetBlockNumber(buffer) == SPGIST_METAPAGE_BLKNO);
        page = (Page) BufferGetPage(buffer);
        SpGistInitMetapage(page);
        PageSetLSN(page, lsn);
        MarkBufferDirty(buffer);
        UnlockReleaseBuffer(buffer);
 
-       buffer = XLogReadBuffer(*node, SPGIST_ROOT_BLKNO, true);
-       Assert(BufferIsValid(buffer));
+       XLogReadBufferForRedoExtended(lsn, record, 1, RBM_ZERO, false, &buffer);
+       Assert(BufferGetBlockNumber(buffer) == SPGIST_ROOT_BLKNO);
        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));
+       XLogReadBufferForRedoExtended(lsn, record, 2, RBM_ZERO, false, &buffer);
+       Assert(BufferGetBlockNumber(buffer) == SPGIST_NULL_BLKNO);
        SpGistInitBuffer(buffer, SPGIST_LEAF | SPGIST_NULLS);
        page = (Page) BufferGetPage(buffer);
        PageSetLSN(page, lsn);
@@ -128,15 +124,13 @@ spgRedoAddLeaf(XLogRecPtr lsn, XLogRecord *record)
         */
        if (xldata->newPage)
        {
-               buffer = XLogReadBuffer(xldata->node, xldata->blknoLeaf, true);
+               XLogReadBufferForRedoExtended(lsn, record, 0, RBM_ZERO, false, &buffer);
                SpGistInitBuffer(buffer,
                                         SPGIST_LEAF | (xldata->storesNulls ? SPGIST_NULLS : 0));
                action = BLK_NEEDS_REDO;
        }
        else
-               action = XLogReadBufferForRedo(lsn, record, 0,
-                                                                          xldata->node, xldata->blknoLeaf,
-                                                                          &buffer);
+               action = XLogReadBufferForRedo(lsn, record, 0, &buffer);
 
        if (action == BLK_NEEDS_REDO)
        {
@@ -164,7 +158,8 @@ spgRedoAddLeaf(XLogRecPtr lsn, XLogRecord *record)
                {
                        /* replacing a DEAD tuple */
                        PageIndexTupleDelete(page, xldata->offnumLeaf);
-                       if (PageAddItem(page, (Item) leafTuple, leafTupleHdr.size,
+                       if (PageAddItem(page,
+                                                       (Item) leafTuple, leafTupleHdr.size,
                                         xldata->offnumLeaf, false, false) != xldata->offnumLeaf)
                                elog(ERROR, "failed to add item of size %u to SPGiST index page",
                                         leafTupleHdr.size);
@@ -177,13 +172,14 @@ spgRedoAddLeaf(XLogRecPtr lsn, XLogRecord *record)
                UnlockReleaseBuffer(buffer);
 
        /* update parent downlink if necessary */
-       if (xldata->blknoParent != InvalidBlockNumber)
+       if (xldata->offnumParent != InvalidOffsetNumber)
        {
-               if (XLogReadBufferForRedo(lsn, record, 1,
-                                                                 xldata->node, xldata->blknoParent,
-                                                                 &buffer) == BLK_NEEDS_REDO)
+               if (XLogReadBufferForRedo(lsn, record, 1, &buffer) == BLK_NEEDS_REDO)
                {
                        SpGistInnerTuple tuple;
+                       BlockNumber             blknoLeaf;
+
+                       XLogRecGetBlockTag(record, 0, NULL, NULL, &blknoLeaf);
 
                        page = BufferGetPage(buffer);
 
@@ -191,7 +187,7 @@ spgRedoAddLeaf(XLogRecPtr lsn, XLogRecord *record)
                                                                  PageGetItemId(page, xldata->offnumParent));
 
                        spgUpdateNodeLink(tuple, xldata->nodeI,
-                                                         xldata->blknoLeaf, xldata->offnumLeaf);
+                                                         blknoLeaf, xldata->offnumLeaf);
 
                        PageSetLSN(page, lsn);
                        MarkBufferDirty(buffer);
@@ -213,6 +209,9 @@ spgRedoMoveLeafs(XLogRecPtr lsn, XLogRecord *record)
        Buffer          buffer;
        Page            page;
        XLogRedoAction action;
+       BlockNumber blknoDst;
+
+       XLogRecGetBlockTag(record, 1, NULL, NULL, &blknoDst);
 
        fillFakeState(&state, xldata->stateSrc);
 
@@ -235,15 +234,14 @@ spgRedoMoveLeafs(XLogRecPtr lsn, XLogRecord *record)
        /* Insert tuples on the dest page (do first, so redirect is valid) */
        if (xldata->newPage)
        {
-               buffer = XLogReadBuffer(xldata->node, xldata->blknoDst, true);
+               XLogReadBufferForRedoExtended(lsn, record, 1, RBM_ZERO, false, &buffer);
                SpGistInitBuffer(buffer,
                                         SPGIST_LEAF | (xldata->storesNulls ? SPGIST_NULLS : 0));
                action = BLK_NEEDS_REDO;
        }
        else
-               action = XLogReadBufferForRedo(lsn, record, 1,
-                                                                          xldata->node, xldata->blknoDst,
-                                                                          &buffer);
+               action = XLogReadBufferForRedo(lsn, record, 1, &buffer);
+
        if (action == BLK_NEEDS_REDO)
        {
                int                     i;
@@ -260,7 +258,8 @@ spgRedoMoveLeafs(XLogRecPtr lsn, XLogRecord *record)
                         * field.
                         */
                        leafTuple = ptr;
-                       memcpy(&leafTupleHdr, leafTuple, sizeof(SpGistLeafTupleData));
+                       memcpy(&leafTupleHdr, leafTuple,
+                                  sizeof(SpGistLeafTupleData));
 
                        addOrReplaceTuple(page, (Item) leafTuple,
                                                          leafTupleHdr.size, toInsert[i]);
@@ -274,14 +273,14 @@ spgRedoMoveLeafs(XLogRecPtr lsn, XLogRecord *record)
                UnlockReleaseBuffer(buffer);
 
        /* Delete tuples from the source page, inserting a redirection pointer */
-       if (XLogReadBufferForRedo(lsn, record, 0, xldata->node, xldata->blknoSrc,
-                                                         &buffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
        {
                page = BufferGetPage(buffer);
+
                spgPageIndexMultiDelete(&state, page, toDelete, xldata->nMoves,
                                                state.isBuild ? SPGIST_PLACEHOLDER : SPGIST_REDIRECT,
                                                                SPGIST_PLACEHOLDER,
-                                                               xldata->blknoDst,
+                                                               blknoDst,
                                                                toInsert[nInsert - 1]);
 
                PageSetLSN(page, lsn);
@@ -291,8 +290,7 @@ spgRedoMoveLeafs(XLogRecPtr lsn, XLogRecord *record)
                UnlockReleaseBuffer(buffer);
 
        /* And update the parent downlink */
-       if (XLogReadBufferForRedo(lsn, record, 2, xldata->node, xldata->blknoParent,
-                                                         &buffer) == BLK_NEEDS_REDO)
+       if (XLogReadBufferForRedo(lsn, record, 2, &buffer) == BLK_NEEDS_REDO)
        {
                SpGistInnerTuple tuple;
 
@@ -302,7 +300,7 @@ spgRedoMoveLeafs(XLogRecPtr lsn, XLogRecord *record)
                                                                  PageGetItemId(page, xldata->offnumParent));
 
                spgUpdateNodeLink(tuple, xldata->nodeI,
-                                                 xldata->blknoDst, toInsert[nInsert - 1]);
+                                                 blknoDst, toInsert[nInsert - 1]);
 
                PageSetLSN(page, lsn);
                MarkBufferDirty(buffer);
@@ -321,7 +319,6 @@ spgRedoAddNode(XLogRecPtr lsn, XLogRecord *record)
        SpGistState state;
        Buffer          buffer;
        Page            page;
-       int                     bbi;
        XLogRedoAction action;
 
        ptr += sizeof(spgxlogAddNode);
@@ -331,17 +328,18 @@ spgRedoAddNode(XLogRecPtr lsn, XLogRecord *record)
 
        fillFakeState(&state, xldata->stateSrc);
 
-       if (xldata->blknoNew == InvalidBlockNumber)
+       if (!XLogRecHasBlockRef(record, 1))
        {
                /* update in place */
-               Assert(xldata->blknoParent == InvalidBlockNumber);
-               if (XLogReadBufferForRedo(lsn, record, 0, xldata->node, xldata->blkno,
-                                                                 &buffer) == BLK_NEEDS_REDO)
+               Assert(xldata->parentBlk == -1);
+               if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
                {
                        page = BufferGetPage(buffer);
+
                        PageIndexTupleDelete(page, xldata->offnum);
                        if (PageAddItem(page, (Item) innerTuple, innerTupleHdr.size,
-                                                       xldata->offnum, false, false) != xldata->offnum)
+                                                       xldata->offnum,
+                                                       false, false) != xldata->offnum)
                                elog(ERROR, "failed to add item of size %u to SPGiST index page",
                                         innerTupleHdr.size);
 
@@ -353,30 +351,36 @@ spgRedoAddNode(XLogRecPtr lsn, XLogRecord *record)
        }
        else
        {
+               BlockNumber blkno;
+               BlockNumber blknoNew;
+
+               XLogRecGetBlockTag(record, 0, NULL, NULL, &blkno);
+               XLogRecGetBlockTag(record, 1, NULL, NULL, &blknoNew);
+
                /*
                 * In normal operation we would have all three pages (source, dest,
                 * and parent) locked simultaneously; but in WAL replay it should be
                 * safe to update them one at a time, as long as we do it in the right
-                * order.
+                * order. We must insert the new tuple before replacing the old tuple
+                * with the redirect tuple.
                 *
                 * The logic here depends on the assumption that blkno != blknoNew,
                 * else we can't tell which BKP bit goes with which page, and the LSN
-                * checks could go wrong too.
+                * checks could go wrong too. XXX does this comment still make sense?
                 */
-               Assert(xldata->blkno != xldata->blknoNew);
+               Assert(blkno != blknoNew);
 
                /* Install new tuple first so redirect is valid */
                if (xldata->newPage)
                {
-                       buffer = XLogReadBuffer(xldata->node, xldata->blknoNew, true);
                        /* AddNode is not used for nulls pages */
+                       XLogReadBufferForRedoExtended(lsn, record, 1, RBM_ZERO, false,
+                                                                                 &buffer);
                        SpGistInitBuffer(buffer, 0);
                        action = BLK_NEEDS_REDO;
                }
                else
-                       action = XLogReadBufferForRedo(lsn, record, 1,
-                                                                                  xldata->node, xldata->blknoNew,
-                                                                                  &buffer);
+                       action = XLogReadBufferForRedo(lsn, record, 1, &buffer);
                if (action == BLK_NEEDS_REDO)
                {
                        page = BufferGetPage(buffer);
@@ -385,25 +389,28 @@ spgRedoAddNode(XLogRecPtr lsn, XLogRecord *record)
                                                          innerTupleHdr.size, xldata->offnumNew);
 
                        /*
-                        * If parent is in this same page, don't advance LSN; doing so
-                        * would fool us into not applying the parent downlink update
-                        * below.  We'll update the LSN when we fix the parent downlink.
+                        * If parent is in this same page, update it now.
                         */
-                       if (xldata->blknoParent != xldata->blknoNew)
+                       if (xldata->parentBlk == 1)
                        {
-                               PageSetLSN(page, lsn);
+                               SpGistInnerTuple parentTuple;
+
+                               parentTuple = (SpGistInnerTuple) PageGetItem(page,
+                                                                 PageGetItemId(page, xldata->offnumParent));
+
+                               spgUpdateNodeLink(parentTuple, xldata->nodeI,
+                                                                 blknoNew, xldata->offnumNew);
                        }
+                       PageSetLSN(page, lsn);
                        MarkBufferDirty(buffer);
                }
                if (BufferIsValid(buffer))
                        UnlockReleaseBuffer(buffer);
 
                /* Delete old tuple, replacing it with redirect or placeholder tuple */
-               if (XLogReadBufferForRedo(lsn, record, 0, xldata->node, xldata->blkno,
-                                                                 &buffer) == BLK_NEEDS_REDO)
+               if (XLogReadBufferForRedo(lsn, record, 0, &buffer) == BLK_NEEDS_REDO)
                {
                        SpGistDeadTuple dt;
-
                        page = BufferGetPage(buffer);
 
                        if (state.isBuild)
@@ -412,11 +419,12 @@ spgRedoAddNode(XLogRecPtr lsn, XLogRecord *record)
                                                                          InvalidOffsetNumber);
                        else
                                dt = spgFormDeadTuple(&state, SPGIST_REDIRECT,
-                                                                         xldata->blknoNew,
+                                                                         blknoNew,
                                                                          xldata->offnumNew);
 
                        PageIndexTupleDelete(page, xldata->offnum);
-                       if (PageAddItem(page, (Item) dt, dt->size, xldata->offnum,
+                       if (PageAddItem(page, (Item) dt, dt->size,
+                                                       xldata->offnum,
                                                        false, false) != xldata->offnum)
                                elog(ERROR, "failed to add item of size %u to SPGiST index page",
                                         dt->size);
@@ -427,61 +435,49 @@ spgRedoAddNode(XLogRecPtr lsn, XLogRecord *record)
                                SpGistPageGetOpaque(page)->nRedirection++;
 
                        /*
-                        * If parent is in this same page, don't advance LSN; doing so
-                        * would fool us into not applying the parent downlink update
-                        * below.  We'll update the LSN when we fix the parent downlink.
+                        * If parent is in this same page, don't advance LSN.  We'll
+                        * update it when we fix the parent downlink.
                         */
-                       if (xldata->blknoParent != xldata->blkno)
+                       if (xldata->parentBlk == 0)
                        {
-                               PageSetLSN(page, lsn);
+                               SpGistInnerTuple parentTuple;
+
+                               parentTuple = (SpGistInnerTuple) PageGetItem(page,
+                                                                 PageGetItemId(page, xldata->offnumParent));
+
+                               spgUpdateNodeLink(parentTuple, xldata->nodeI,
+                                                                 blknoNew, xldata->offnumNew);
                        }
+                       PageSetLSN(page, lsn);
                        MarkBufferDirty(buffer);
                }
                if (BufferIsValid(buffer))
                        UnlockReleaseBuffer(buffer);
 
                /*
-                * Update parent downlink.  Since parent could be in either of the
-                * previous two buffers, it's a bit tricky to determine which BKP bit
-                * applies.
+                * Update parent downlink (if we didn't do it as part of the source
+                * or destination page update already).
                 */
-               if (xldata->blknoParent == xldata->blkno)
-                       bbi = 0;
-               else if (xldata->blknoParent == xldata->blknoNew)
-                       bbi = 1;
-               else
-                       bbi = 2;
-
-               if (record->xl_info & XLR_BKP_BLOCK(bbi))
+               if (xldata->parentBlk == 2)
                {
-                       if (bbi == 2)           /* else we already did it */
-                               (void) RestoreBackupBlock(lsn, record, bbi, false, false);
-                       action = BLK_RESTORED;
-                       buffer = InvalidBuffer;
-               }
-               else
-               {
-                       action = XLogReadBufferForRedo(lsn, record, bbi, xldata->node,
-                                                                                  xldata->blknoParent, &buffer);
-                       Assert(action != BLK_RESTORED);
-               }
-               if (action == BLK_NEEDS_REDO)
-               {
-                       SpGistInnerTuple innerTuple;
+                       if (XLogReadBufferForRedo(lsn, record, 2, &buffer) == BLK_NEEDS_REDO)
+                       {
+                               SpGistInnerTuple parentTuple;
 
-                       page = BufferGetPage(buffer);
+                               page = BufferGetPage(buffer);
 
-                       innerTuple = (SpGistInnerTuple) PageGetItem(page,
+                               parentTuple = (SpGistInnerTuple) PageGetItem(page,
                                                                  PageGetItemId(page, xldata->offnumParent));
 
-                       spgUpdateNodeLink(innerTuple, xldata->nod