From 54685338e37889eebd473804c3feb006dd83a882 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Thu, 31 Jul 2014 16:48:43 +0300 Subject: [PATCH] Move log_newpage and log_newpage_buffer to xlog.c. log_newpage is used by many indexams, in addition to heap, but for historical reasons it's always been part of the heapam rmgr. Starting with 9.3, we have another WAL record type for logging an image of a page, XLOG_FPI. Simplify things by moving log_newpage and log_newpage_buffer to xlog.c, and switch to using the XLOG_FPI record type. Bump the WAL version number because the code to replay the old HEAP_NEWPAGE records is removed. --- src/backend/access/gin/gindatapage.c | 1 - src/backend/access/gin/gininsert.c | 1 - src/backend/access/gin/ginxlog.c | 3 +- src/backend/access/gist/gist.c | 1 - src/backend/access/heap/heapam.c | 180 ----------------------- src/backend/access/nbtree/nbtree.c | 1 - src/backend/access/nbtree/nbtsort.c | 1 - src/backend/access/rmgrdesc/heapdesc.c | 9 -- src/backend/access/spgist/spginsert.c | 1 - src/backend/access/transam/xlog.c | 131 ++++++++++++++++- src/backend/commands/tablecmds.c | 1 - src/backend/replication/logical/decode.c | 8 - src/include/access/heapam_xlog.h | 19 +-- src/include/access/xlog.h | 5 + src/include/access/xlog_internal.h | 2 +- 15 files changed, 139 insertions(+), 225 deletions(-) diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c index 272a9ca7c0..5b7c49654c 100644 --- a/src/backend/access/gin/gindatapage.c +++ b/src/backend/access/gin/gindatapage.c @@ -15,7 +15,6 @@ #include "postgres.h" #include "access/gin_private.h" -#include "access/heapam_xlog.h" #include "lib/ilist.h" #include "miscadmin.h" #include "utils/memutils.h" diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index b27cae3aab..2fbd1bf5e4 100644 --- a/src/backend/access/gin/gininsert.c +++ b/src/backend/access/gin/gininsert.c @@ -15,7 +15,6 @@ #include "postgres.h" #include "access/gin_private.h" -#include "access/heapam_xlog.h" #include "catalog/index.h" #include "miscadmin.h" #include "storage/bufmgr.h" diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c index 7f93ce6526..ffabf4e259 100644 --- a/src/backend/access/gin/ginxlog.c +++ b/src/backend/access/gin/ginxlog.c @@ -558,7 +558,8 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) } /* - * This is functionally the same as heap_xlog_newpage. + * VACUUM_PAGE record contains simply a full image of the page, similar to + * a XLOG_FPI record. */ static void ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index e6f06c29e5..f4eb246c91 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -16,7 +16,6 @@ #include "access/genam.h" #include "access/gist_private.h" -#include "access/heapam_xlog.h" #include "catalog/index.h" #include "catalog/pg_collation.h" #include "miscadmin.h" diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 21e76d6a2a..d731f988b8 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -6921,133 +6921,6 @@ log_heap_update(Relation reln, Buffer oldbuf, return recptr; } -/* - * Perform XLogInsert of a HEAP_NEWPAGE record to WAL. Caller is responsible - * for writing the page to disk after calling this routine. - * - * Note: If you're using this function, you should be building pages in private - * memory and writing them directly to smgr. If you're using buffers, call - * log_newpage_buffer instead. - * - * If the page follows the standard page layout, with a PageHeader and unused - * space between pd_lower and pd_upper, set 'page_std' to TRUE. That allows - * the unused space to be left out from the WAL record, making it smaller. - */ -XLogRecPtr -log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno, - Page page, bool page_std) -{ - xl_heap_newpage xlrec; - XLogRecPtr recptr; - XLogRecData rdata[3]; - - /* - * Note: the NEWPAGE log record is used for both heaps and indexes, so do - * not do anything that assumes we are touching a heap. - */ - - /* NO ELOG(ERROR) from here till newpage op is logged */ - START_CRIT_SECTION(); - - xlrec.node = *rnode; - xlrec.forknum = forkNum; - xlrec.blkno = blkno; - - if (page_std) - { - /* Assume we can omit data between pd_lower and pd_upper */ - uint16 lower = ((PageHeader) page)->pd_lower; - uint16 upper = ((PageHeader) page)->pd_upper; - - 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; - } - } - else - { - /* Not a standard page header, don't try to eliminate "hole" */ - xlrec.hole_offset = 0; - xlrec.hole_length = 0; - } - - rdata[0].data = (char *) &xlrec; - rdata[0].len = SizeOfHeapNewpage; - 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; - } - - recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_NEWPAGE, rdata); - - /* - * The page may be uninitialized. If so, we can't set the LSN because that - * would corrupt the page. - */ - if (!PageIsNew(page)) - { - PageSetLSN(page, recptr); - } - - END_CRIT_SECTION(); - - return recptr; -} - -/* - * Perform XLogInsert of a HEAP_NEWPAGE record to WAL. - * - * Caller should initialize the buffer and mark it dirty before calling this - * function. This function will set the page LSN and TLI. - * - * If the page follows the standard page layout, with a PageHeader and unused - * space between pd_lower and pd_upper, set 'page_std' to TRUE. That allows - * the unused space to be left out from the WAL record, making it smaller. - */ -XLogRecPtr -log_newpage_buffer(Buffer buffer, bool page_std) -{ - Page page = BufferGetPage(buffer); - RelFileNode rnode; - ForkNumber forkNum; - BlockNumber blkno; - - /* Shared buffers should be modified in a critical section. */ - Assert(CritSectionCount > 0); - - BufferGetTag(buffer, &rnode, &forkNum, &blkno); - - return log_newpage(&rnode, forkNum, blkno, page, page_std); -} - /* * Perform XLogInsert of a XLOG_HEAP2_NEW_CID record * @@ -7515,56 +7388,6 @@ heap_xlog_freeze_page(XLogRecPtr lsn, XLogRecord *record) UnlockReleaseBuffer(buffer); } -static void -heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record) -{ - xl_heap_newpage *xlrec = (xl_heap_newpage *) XLogRecGetData(record); - char *blk = ((char *) xlrec) + sizeof(xl_heap_newpage); - Buffer buffer; - Page page; - - /* Backup blocks are not used in newpage records */ - Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK)); - - Assert(record->xl_len == SizeOfHeapNewpage + BLCKSZ - xlrec->hole_length); - - /* - * Note: the NEWPAGE log record is used for both heaps and indexes, so do - * not do anything that assumes we are touching a heap. - */ - buffer = XLogReadBufferExtended(xlrec->node, xlrec->forknum, xlrec->blkno, - RBM_ZERO); - Assert(BufferIsValid(buffer)); - LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); - page = (Page) BufferGetPage(buffer); - - if (xlrec->hole_length == 0) - { - memcpy((char *) page, blk, BLCKSZ); - } - else - { - memcpy((char *) page, blk, xlrec->hole_offset); - /* must zero-fill the hole */ - MemSet((char *) page + xlrec->hole_offset, 0, xlrec->hole_length); - memcpy((char *) page + (xlrec->hole_offset + xlrec->hole_length), - blk + xlrec->hole_offset, - BLCKSZ - (xlrec->hole_offset + xlrec->hole_length)); - } - - /* - * The page may be uninitialized. If so, we can't set the LSN because that - * would corrupt the page. - */ - if (!PageIsNew(page)) - { - PageSetLSN(page, lsn); - } - - MarkBufferDirty(buffer); - UnlockReleaseBuffer(buffer); -} - /* * Given an "infobits" field from an XLog record, set the correct bits in the * given infomask and infomask2 for the tuple touched by the record. @@ -8421,9 +8244,6 @@ heap_redo(XLogRecPtr lsn, XLogRecord *record) case XLOG_HEAP_HOT_UPDATE: heap_xlog_update(lsn, record, true); break; - case XLOG_HEAP_NEWPAGE: - heap_xlog_newpage(lsn, record); - break; case XLOG_HEAP_LOCK: heap_xlog_lock(lsn, record); break; diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 89a9827079..117b18e590 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -18,7 +18,6 @@ */ #include "postgres.h" -#include "access/heapam_xlog.h" #include "access/nbtree.h" #include "access/relscan.h" #include "catalog/index.h" diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index 048b215118..e8a89d24ae 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -66,7 +66,6 @@ #include "postgres.h" -#include "access/heapam_xlog.h" #include "access/nbtree.h" #include "miscadmin.h" #include "storage/smgr.h" diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c index 7df18fa2d2..24b6f92bd5 100644 --- a/src/backend/access/rmgrdesc/heapdesc.c +++ b/src/backend/access/rmgrdesc/heapdesc.c @@ -98,15 +98,6 @@ heap_desc(StringInfo buf, XLogRecord *record) ItemPointerGetOffsetNumber(&(xlrec->newtid)), xlrec->new_xmax); } - else if (info == XLOG_HEAP_NEWPAGE) - { - xl_heap_newpage *xlrec = (xl_heap_newpage *) rec; - - appendStringInfo(buf, "newpage: rel %u/%u/%u; fork %u, blk %u", - xlrec->node.spcNode, xlrec->node.dbNode, - xlrec->node.relNode, xlrec->forknum, - xlrec->blkno); - } else if (info == XLOG_HEAP_LOCK) { xl_heap_lock *xlrec = (xl_heap_lock *) rec; diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c index a4408f03bd..7c104f49cc 100644 --- a/src/backend/access/spgist/spginsert.c +++ b/src/backend/access/spgist/spginsert.c @@ -17,7 +17,6 @@ #include "postgres.h" #include "access/genam.h" -#include "access/heapam_xlog.h" #include "access/spgist_private.h" #include "catalog/index.h" #include "miscadmin.h" diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index fe184bde3b..34f2fc0e21 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -4084,7 +4084,14 @@ RestoreBackupBlockContents(XLogRecPtr lsn, BkpBlock bkpb, char *blk, * reset it here since it will be set before being written. */ - PageSetLSN(page, lsn); + /* + * The page may be uninitialized. If so, we can't set the LSN because that + * would corrupt the page. + */ + if (!PageIsNew(page)) + { + PageSetLSN(page, lsn); + } MarkBufferDirty(buffer); if (!keep_buffer) @@ -8988,6 +8995,128 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std) return recptr; } +/* + * Write a WAL record containing a full image of a page. Caller is responsible + * for writing the page to disk after calling this routine. + * + * Note: If you're using this function, you should be building pages in private + * memory and writing them directly to smgr. If you're using buffers, call + * log_newpage_buffer instead. + * + * If the page follows the standard page layout, with a PageHeader and unused + * space between pd_lower and pd_upper, set 'page_std' to TRUE. That allows + * the unused space to be left out from the WAL record, making it smaller. + */ +XLogRecPtr +log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno, + Page page, bool page_std) +{ + BkpBlock bkpb; + XLogRecPtr recptr; + XLogRecData rdata[3]; + + /* NO ELOG(ERROR) from here till newpage op is logged */ + START_CRIT_SECTION(); + + bkpb.node = *rnode; + bkpb.fork = forkNum; + bkpb.block = blkno; + + if (page_std) + { + /* Assume we can omit data between pd_lower and pd_upper */ + uint16 lower = ((PageHeader) page)->pd_lower; + uint16 upper = ((PageHeader) page)->pd_upper; + + if (lower >= SizeOfPageHeaderData && + upper > lower && + upper <= BLCKSZ) + { + bkpb.hole_offset = lower; + bkpb.hole_length = upper - lower; + } + else + { + /* No "hole" to compress out */ + bkpb.hole_offset = 0; + bkpb.hole_length = 0; + } + } + else + { + /* Not a standard page header, don't try to eliminate "hole" */ + bkpb.hole_offset = 0; + bkpb.hole_length = 0; + } + + rdata[0].data = (char *) &bkpb; + rdata[0].len = sizeof(BkpBlock); + rdata[0].buffer = InvalidBuffer; + rdata[0].next = &(rdata[1]); + + if (bkpb.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 = bkpb.hole_offset; + rdata[1].buffer = InvalidBuffer; + rdata[1].next = &rdata[2]; + + rdata[2].data = (char *) page + (bkpb.hole_offset + bkpb.hole_length); + rdata[2].len = BLCKSZ - (bkpb.hole_offset + bkpb.hole_length); + rdata[2].buffer = InvalidBuffer; + rdata[2].next = NULL; + } + + recptr = XLogInsert(RM_XLOG_ID, XLOG_FPI, rdata); + + /* + * The page may be uninitialized. If so, we can't set the LSN because that + * would corrupt the page. + */ + if (!PageIsNew(page)) + { + PageSetLSN(page, recptr); + } + + END_CRIT_SECTION(); + + return recptr; +} + +/* + * Write a WAL record containing a full image of a page. + * + * Caller should initialize the buffer and mark it dirty before calling this + * function. This function will set the page LSN. + * + * If the page follows the standard page layout, with a PageHeader and unused + * space between pd_lower and pd_upper, set 'page_std' to TRUE. That allows + * the unused space to be left out from the WAL record, making it smaller. + */ +XLogRecPtr +log_newpage_buffer(Buffer buffer, bool page_std) +{ + Page page = BufferGetPage(buffer); + RelFileNode rnode; + ForkNumber forkNum; + BlockNumber blkno; + + /* Shared buffers should be modified in a critical section. */ + Assert(CritSectionCount > 0); + + BufferGetTag(buffer, &rnode, &forkNum, &blkno); + + return log_newpage(&rnode, forkNum, blkno, page, page_std); +} + /* * Check if any of the GUC parameters that are critical for hot standby * have changed, and update the value in pg_control file if necessary. diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 5dc4d18b6a..158c594a84 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -16,7 +16,6 @@ #include "access/genam.h" #include "access/heapam.h" -#include "access/heapam_xlog.h" #include "access/multixact.h" #include "access/reloptions.h" #include "access/relscan.h" diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index 8f8732afdc..9f1b20e04a 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -435,14 +435,6 @@ DecodeHeapOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) DecodeDelete(ctx, buf); break; - case XLOG_HEAP_NEWPAGE: - - /* - * This is only used in places like indexams and CLUSTER which - * don't contain changes relevant for logical replication. - */ - break; - case XLOG_HEAP_INPLACE: /* diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h index e964ecce46..254434773e 100644 --- a/src/include/access/heapam_xlog.h +++ b/src/include/access/heapam_xlog.h @@ -32,7 +32,7 @@ #define XLOG_HEAP_UPDATE 0x20 /* 0x030 is free, was XLOG_HEAP_MOVE */ #define XLOG_HEAP_HOT_UPDATE 0x40 -#define XLOG_HEAP_NEWPAGE 0x50 +/* 0x050 is free, was XLOG_HEAP_NEWPAGE */ #define XLOG_HEAP_LOCK 0x60 #define XLOG_HEAP_INPLACE 0x70 @@ -239,20 +239,6 @@ typedef struct xl_heap_cleanup_info #define SizeOfHeapCleanupInfo (sizeof(xl_heap_cleanup_info)) -/* This is for replacing a page's contents in toto */ -/* NB: this is used for indexes as well as heaps */ -typedef struct xl_heap_newpage -{ - RelFileNode node; - ForkNumber forknum; - BlockNumber blkno; /* location of new page */ - uint16 hole_offset; /* number of bytes before "hole" */ - uint16 hole_length; /* number of bytes in "hole" */ - /* entire page contents (minus the hole) follow at end of record */ -} xl_heap_newpage; - -#define SizeOfHeapNewpage (offsetof(xl_heap_newpage, hole_length) + sizeof(uint16)) - /* flags for infobits_set */ #define XLHL_XMAX_IS_MULTI 0x01 #define XLHL_XMAX_LOCK_ONLY 0x02 @@ -393,8 +379,5 @@ extern void heap_execute_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *xlrec_tp); extern XLogRecPtr log_heap_visible(RelFileNode rnode, Buffer heap_buffer, Buffer vm_buffer, TransactionId cutoff_xid); -extern XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, - BlockNumber blk, Page page, bool page_std); -extern XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std); #endif /* HEAPAM_XLOG_H */ diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 85f9cb7cab..7d6db49893 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -15,7 +15,9 @@ #include "access/xlogdefs.h" #include "datatype/timestamp.h" #include "lib/stringinfo.h" +#include "storage/block.h" #include "storage/buf.h" +#include "storage/relfilenode.h" #include "utils/pg_crc.h" /* @@ -286,6 +288,9 @@ extern bool XLogNeedsFlush(XLogRecPtr RecPtr); extern int XLogFileInit(XLogSegNo segno, bool *use_existent, bool use_lock); extern int XLogFileOpen(XLogSegNo segno); +extern XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, + BlockNumber blk, char *page, bool page_std); +extern XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std); extern XLogRecPtr XLogSaveBufferForHint(Buffer buffer, bool buffer_std); extern void CheckXLogRemoved(XLogSegNo segno, TimeLineID tli); diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 8c8de387e0..954114f0d5 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -55,7 +55,7 @@ typedef struct BkpBlock /* * Each page of XLOG file has a header like this: */ -#define XLOG_PAGE_MAGIC 0xD07E /* can be used as WAL version indicator */ +#define XLOG_PAGE_MAGIC 0xD07F /* can be used as WAL version indicator */ typedef struct XLogPageHeaderData {