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 272a9ca7c09..5b7c49654c6 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 b27cae3aab2..2fbd1bf5e47 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 7f93ce6526f..ffabf4e2594 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 e6f06c29e51..f4eb246c91a 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 21e76d6a2a9..d731f988b80 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 89a98270798..117b18e5905 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 048b2151186..e8a89d24ae5 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 7df18fa2d2c..24b6f92bd55 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 a4408f03bd3..7c104f49cc8 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 fe184bde3b9..34f2fc0e21b 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 5dc4d18b6a5..158c594a848 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 8f8732afdce..9f1b20e04ab 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 e964ecce461..254434773ed 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 85f9cb7cab2..7d6db498936 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 8c8de387e02..954114f0d54 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 {