diff -cr pgsql/src/backend/access/heap/heapam.c pgsql-crc/src/backend/access/heap/heapam.c *** pgsql/src/backend/access/heap/heapam.c Sun Dec 14 22:00:56 2008 --- pgsql-crc/src/backend/access/heap/heapam.c Sun Dec 14 22:04:25 2008 *************** *** 4108,4113 **** --- 4108,4200 ---- } /* + * Perform XLogInsert for hint bits changes in a page. This handles hint + * bits set in HeapTupleHeaderData (t_infomask and t_infomask2). + * + * This is intended to be called right before writing a page from shared + * buffers to disk. + * + * The approach used here, instead of WAL-logging every change, is to produce + * a complete record of the current state of hint bits in a page just before + * flushing it. There are two downsides to this approach: first, it stores + * all hint bits in the page, not only those that changed; and second, that + * the flusher of the page needs to flush a lot more of the WAL (namely up + * to this new record's LSN) than the original LSN marked on the page. + */ + XLogRecPtr + log_hintbits(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno, + Page page) + { + xl_heap_hintbits xlrec; + OffsetNumber i; + XLogRecPtr recptr; + XLogRecData rdata[2]; + char *bits; + int pos = 0; + StringInfoData buf; + + /* + * 1 byte for line pointer bits, 2 bytes for infomask, + * 2 bytes for infomask2 + */ + bits = palloc(MaxHeapTuplesPerPage * 5); + + initStringInfo(&buf); + appendStringInfo(&buf, "page %u: ", blkno); + + for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); + i = OffsetNumberNext(i)) + { + HeapTupleHeader htup; + ItemId lp = PageGetItemId(page, i); + + if (!ItemIdHasStorage(lp)) + continue; + + appendStringInfo(&buf, "offset %d: ", i); + + htup = (HeapTupleHeader) PageGetItem(page, lp); + + *((uint16 *) (bits + pos)) = htup->t_infomask & HEAP_XACT_MASK; + appendStringInfo(&buf, "infomask %04x/%04x ", htup->t_infomask, + htup->t_infomask & HEAP_XACT_MASK); + pos += 2; + *((uint16 *) (bits + pos)) = htup->t_infomask2 & HEAP2_XACT_MASK; + appendStringInfo(&buf, "infomask2 %04x/%04x\n", htup->t_infomask2, + htup->t_infomask2 & HEAP2_XACT_MASK); + pos += 2; + } + + elog(LOG, "%s", buf.data); + pfree(buf.data); + + /* NO ELOG(ERROR) from here till hint bits are logged */ + START_CRIT_SECTION(); + + xlrec.node = *rnode; + xlrec.block = blkno; + + rdata[0].data = (char *) &xlrec; + rdata[0].len = SizeOfHeapHintbits; + rdata[0].buffer = InvalidBuffer; + rdata[0].next = &(rdata[1]); + + rdata[1].data = (char *) bits; + rdata[1].len = pos; + rdata[1].buffer = InvalidBuffer; + rdata[1].next = NULL; + + recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_HINTBITS, rdata); + + PageSetLSN(page, recptr); + PageSetTLI(page, ThisTimeLineID); + + END_CRIT_SECTION(); + + return recptr; + } + + /* * Handles CLEAN and CLEAN_MOVE record types */ static void *************** *** 4225,4230 **** --- 4312,4396 ---- } static void + heap_xlog_hintbits(XLogRecPtr lsn, XLogRecord *record) + { + xl_heap_hintbits *xlrec = (xl_heap_hintbits *) XLogRecGetData(record); + Buffer buffer; + Page page; + + buffer = XLogReadBuffer(xlrec->node, xlrec->block, false); + if (!BufferIsValid(buffer)) + return; + page = (Page) BufferGetPage(buffer); + + if (XLByteLE(lsn, PageGetLSN(page))) + { + UnlockReleaseBuffer(buffer); + return; + } + + if (record->xl_len > SizeOfHeapHintbits) + { + char *bits; + char *bits_end; + OffsetNumber offset = FirstOffsetNumber; + StringInfoData buf; + + + bits = (char *) xlrec + SizeOfHeapHintbits; + bits_end = (char *) xlrec + record->xl_len; + + initStringInfo(&buf); + appendStringInfo(&buf, "page %u: ", xlrec->block); + + while (bits < bits_end) + { + + for (;;) + { + HeapTupleHeader htup; + ItemId lp = PageGetItemId(page, offset); + + if (!ItemIdHasStorage(lp)) + { + offset++; + continue; + } + + appendStringInfo(&buf, "offset %d: ", offset); + + htup = (HeapTupleHeader) PageGetItem(page, lp); + + /* set the right bits in infomask */ + htup->t_infomask = *(uint16 *) bits | + (htup->t_infomask & ~HEAP_XACT_MASK); + appendStringInfo(&buf, "infomask %04x/%04x ", htup->t_infomask, + *(uint16 *) bits); + bits += 2; + + /* set the right bits in infomask2 */ + htup->t_infomask2 = *(uint16 *) bits | + (htup->t_infomask2 & ~HEAP2_XACT_MASK); + appendStringInfo(&buf, "infomask2 %04x/%04x\n", htup->t_infomask2, + *(uint16 *) bits); + bits += 2; + + offset++; + + break; + } + } + elog(LOG, "%s", buf.data); + pfree(buf.data); + } + + PageSetLSN(page, lsn); + PageSetTLI(page, ThisTimeLineID); + MarkBufferDirty(buffer); + UnlockReleaseBuffer(buffer); + } + + static void heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record) { xl_heap_newpage *xlrec = (xl_heap_newpage *) XLogRecGetData(record); *************** *** 4823,4828 **** --- 4989,4997 ---- case XLOG_HEAP2_CLEAN_MOVE: heap_xlog_clean(lsn, record, true); break; + case XLOG_HEAP2_HINTBITS: + heap_xlog_hintbits(lsn, record); + break; default: elog(PANIC, "heap2_redo: unknown op code %u", info); } *************** *** 4964,4969 **** --- 5133,5146 ---- xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode, xlrec->block); } + else if (info == XLOG_HEAP2_HINTBITS) + { + xl_heap_hintbits *xlrec = (xl_heap_hintbits *) rec; + + appendStringInfo(buf, "hintbits: rel %u/%u/%u; blk %u", + xlrec->node.spcNode, xlrec->node.dbNode, + xlrec->node.relNode, xlrec->block); + } else appendStringInfo(buf, "UNKNOWN"); } diff -cr pgsql/src/backend/storage/buffer/bufmgr.c pgsql-crc/src/backend/storage/buffer/bufmgr.c *** pgsql/src/backend/storage/buffer/bufmgr.c Sun Dec 14 22:00:58 2008 --- pgsql-crc/src/backend/storage/buffer/bufmgr.c Sun Dec 14 22:35:49 2008 *************** *** 33,38 **** --- 33,39 ---- #include #include + #include "access/heapam.h" #include "catalog/catalog.h" #include "miscadmin.h" #include "pg_trace.h" *************** *** 43,48 **** --- 44,50 ---- #include "storage/ipc.h" #include "storage/proc.h" #include "storage/smgr.h" + #include "utils/memutils.h" #include "utils/rel.h" #include "utils/resowner.h" *************** *** 1461,1467 **** * BUF_REUSABLE: buffer is available for replacement, ie, it has * pin count 0 and usage count 0. * ! * (BUF_WRITTEN could be set in error if FlushBuffers finds the buffer clean * after locking it, but we don't care all that much.) * * Note: caller must have done ResourceOwnerEnlargeBuffers. --- 1463,1469 ---- * BUF_REUSABLE: buffer is available for replacement, ie, it has * pin count 0 and usage count 0. * ! * (BUF_WRITTEN could be set in error if FlushBuffer finds the buffer clean * after locking it, but we don't care all that much.) * * Note: caller must have done ResourceOwnerEnlargeBuffers. *************** *** 1770,1775 **** --- 1772,1785 ---- { XLogRecPtr recptr; ErrorContextCallback errcontext; + static char *dblbuf = NULL; + bool done = false; + + if (enable_block_checksums && dblbuf == NULL) + { + dblbuf = MemoryContextAlloc(TopMemoryContext, BLCKSZ + ALIGNOF_BUFFER); + dblbuf = (char *) BUFFERALIGN(dblbuf); + } /* * Acquire the buffer's io_in_progress lock. If StartBufferIO returns *************** *** 1794,1799 **** --- 1804,1833 ---- reln->smgr_rnode.relNode); /* + * We make a copy of the buffer to write. + */ + if (enable_block_checksums) + memcpy(dblbuf, BufHdrGetBlock(buf), BLCKSZ); + + /* + * If the page has been modified by a hint bit setter, ensure we WAL-log + * their changes before actually writing the page; otherwise the CRC we're + * about to store could be invalid if the page is torn. Note: we check + * the flag on the shared-memory copy of the buffer, not the private copy + * we just made, to forestall the possibility that hints bits could have + * been set in the later parts of the page after we copied the flag in + * unset state. + */ + if (enable_block_checksums && PageHasUnloggedChange(BufHdrGetBlock(buf)) && + !InRecovery) + { + /* XXX cast away the "volatile" qualifier */ + log_hintbits(&((BufferDesc *) buf)->tag.rnode, buf->tag.forkNum, + buf->tag.blockNum, BufHdrGetBlock(buf)); + done = true; + } + + /* * Force XLOG flush up to buffer's LSN. This implements the basic WAL * rule that log updates must hit disk before any of the data-file changes * they describe do. *************** *** 1815,1821 **** smgrwrite(reln, buf->tag.forkNum, buf->tag.blockNum, ! (char *) BufHdrGetBlock(buf), false); BufferFlushCount++; --- 1849,1855 ---- smgrwrite(reln, buf->tag.forkNum, buf->tag.blockNum, ! enable_block_checksums ? dblbuf : BufHdrGetBlock(buf), false); BufferFlushCount++; diff -cr pgsql/src/backend/storage/page/bufpage.c pgsql-crc/src/backend/storage/page/bufpage.c *** pgsql/src/backend/storage/page/bufpage.c Sun Dec 14 22:00:58 2008 --- pgsql-crc/src/backend/storage/page/bufpage.c Sun Dec 14 22:04:25 2008 *************** *** 41,46 **** --- 41,47 ---- MemSet(p, 0, pageSize); /* p->pd_flags = 0; done by above MemSet */ + p->pd_checksum = PAGE_INVALID_CHECKSUM; p->pd_lower = SizeOfPageHeaderData; p->pd_upper = pageSize - specialSize; p->pd_special = pageSize - specialSize; *************** *** 84,92 **** page->pd_special == MAXALIGN(page->pd_special)) return true; ! /* Check all-zeroes case */ pagebytes = (char *) page; ! for (i = 0; i < BLCKSZ; i++) { if (pagebytes[i] != 0) return false; --- 85,93 ---- page->pd_special == MAXALIGN(page->pd_special)) return true; ! /* Check all-zeroes case (skipping the checksum) */ pagebytes = (char *) page; ! for (i = sizeof(PAGE_CHECKSUM_TYPE); i < BLCKSZ; i++) { if (pagebytes[i] != 0) return false; diff -cr pgsql/src/backend/storage/smgr/smgr.c pgsql-crc/src/backend/storage/smgr/smgr.c *** pgsql/src/backend/storage/smgr/smgr.c Sun Dec 14 22:00:58 2008 --- pgsql-crc/src/backend/storage/smgr/smgr.c Sun Dec 14 22:04:25 2008 *************** *** 26,31 **** --- 26,34 ---- #include "utils/hsearch.h" + /* Perform block checksumming for corruption detection */ + bool enable_block_checksums = false; + /* * This struct of function pointers defines the API between smgr.c and * any individual storage manager module. Note that smgr subfunctions are *************** *** 371,376 **** --- 374,385 ---- smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool isTemp) { + /* Perform block checksumming for corruption detection */ + if (enable_block_checksums) + WritePageChecksum(buffer); + else + WriteInvalidPageChecksum(buffer); + (*(smgrsw[reln->smgr_which].smgr_extend)) (reln, forknum, blocknum, buffer, isTemp); } *************** *** 388,393 **** --- 397,424 ---- char *buffer) { (*(smgrsw[reln->smgr_which].smgr_read)) (reln, forknum, blocknum, buffer); + + /* Perform block checksumming for corruption detection */ + if (enable_block_checksums && !PageIsNew(buffer) && !InRecovery && + PageGetChecksum(buffer) != PAGE_INVALID_CHECKSUM) + { + PAGE_CHECKSUM_TYPE chksum; + + CalcPageChecksum(buffer, chksum); + + if (chksum != PageGetChecksum(buffer)) + { + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("invalid checksum on read of block %u of relation %u/%u/%u", + blocknum, + reln->smgr_rnode.spcNode, + reln->smgr_rnode.dbNode, + reln->smgr_rnode.relNode), + errdetail("Got %08x, expected %08x.", + chksum, PageGetChecksum(buffer)))); + } + } } /* *************** *** 409,414 **** --- 440,451 ---- smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool isTemp) { + /* Perform block checksumming for corruption detection */ + if (enable_block_checksums) + WritePageChecksum(buffer); + else + WriteInvalidPageChecksum(buffer); + (*(smgrsw[reln->smgr_which].smgr_write)) (reln, forknum, blocknum, buffer, isTemp); } diff -cr pgsql/src/backend/utils/misc/guc.c pgsql-crc/src/backend/utils/misc/guc.c *** pgsql/src/backend/utils/misc/guc.c Sun Dec 14 22:01:00 2008 --- pgsql-crc/src/backend/utils/misc/guc.c Sun Dec 14 22:04:25 2008 *************** *** 57,62 **** --- 57,63 ---- #include "regex/regex.h" #include "storage/bufmgr.h" #include "storage/fd.h" + #include "storage/smgr.h" #include "tcop/tcopprot.h" #include "tsearch/ts_cache.h" #include "utils/builtins.h" *************** *** 773,778 **** --- 774,789 ---- false, NULL, NULL }, { + {"perform_checksum", PGC_SIGHUP, UNGROUPED, + gettext_noop("Forces checksumming of blocks to/from disk."), + gettext_noop("The server will perform a checksum on the block " + "when read from or written to disk in order to detect storage-related " + "corruption.") + }, + &enable_block_checksums, + false, NULL, NULL + }, + { {"log_duration", PGC_SUSET, LOGGING_WHAT, gettext_noop("Logs the duration of each completed SQL statement."), NULL diff -cr pgsql/src/backend/utils/misc/postgresql.conf.sample pgsql-crc/src/backend/utils/misc/postgresql.conf.sample *** pgsql/src/backend/utils/misc/postgresql.conf.sample Sun Dec 14 22:01:00 2008 --- pgsql-crc/src/backend/utils/misc/postgresql.conf.sample Sun Dec 14 22:23:42 2008 *************** *** 481,486 **** --- 481,491 ---- #transform_null_equals = off + #------------------------------------------------------------------------------ + # CORRUPTION DETECTION + #------------------------------------------------------------------------------ + + #perform_checksum = off # Perform block checksumming to/from disk #------------------------------------------------------------------------------ # CUSTOMIZED OPTIONS diff -cr pgsql/src/backend/utils/time/tqual.c pgsql-crc/src/backend/utils/time/tqual.c *** pgsql/src/backend/utils/time/tqual.c Wed Mar 26 12:20:47 2008 --- pgsql-crc/src/backend/utils/time/tqual.c Sun Dec 14 22:04:25 2008 *************** *** 44,49 **** --- 44,50 ---- #include "access/xact.h" #include "storage/bufmgr.h" #include "storage/procarray.h" + #include "storage/smgr.h" #include "utils/tqual.h" *************** *** 96,101 **** --- 97,104 ---- } tuple->t_infomask |= infomask; + if (enable_block_checksums) + PageSetUnloggedChange(BufferGetPage(buffer)); SetBufferCommitInfoNeedsSave(buffer); } diff -cr pgsql/src/include/access/heapam.h pgsql-crc/src/include/access/heapam.h *** pgsql/src/include/access/heapam.h Sun Dec 14 22:01:06 2008 --- pgsql-crc/src/include/access/heapam.h Sun Dec 14 22:04:25 2008 *************** *** 140,145 **** --- 140,147 ---- OffsetNumber *offsets, int offcnt); extern XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blk, Page page); + extern XLogRecPtr log_hintbits(RelFileNode *rnode, ForkNumber forkNum, + BlockNumber blk, Page page); /* in heap/pruneheap.c */ extern void heap_page_prune_opt(Relation relation, Buffer buffer, diff -cr pgsql/src/include/access/htup.h pgsql-crc/src/include/access/htup.h *** pgsql/src/include/access/htup.h Sun Dec 14 22:01:06 2008 --- pgsql-crc/src/include/access/htup.h Sun Dec 14 22:04:25 2008 *************** *** 580,585 **** --- 580,586 ---- #define XLOG_HEAP2_FREEZE 0x00 #define XLOG_HEAP2_CLEAN 0x10 #define XLOG_HEAP2_CLEAN_MOVE 0x20 + #define XLOG_HEAP2_HINTBITS 0x30 /* * All what we need to find changed tuple *************** *** 718,723 **** --- 719,734 ---- #define SizeOfHeapFreeze (offsetof(xl_heap_freeze, cutoff_xid) + sizeof(TransactionId)) + /* This is what we need to know about hint bits */ + typedef struct xl_heap_hintbits + { + RelFileNode node; + BlockNumber block; + /* HINT BIT ARRAY FOLLOWS AT THE END */ + } xl_heap_hintbits; + + #define SizeOfHeapHintbits (offsetof(xl_heap_hintbits, block) + sizeof(BlockNumber)) + /* HeapTupleHeader functions implemented in utils/time/combocid.c */ extern CommandId HeapTupleHeaderGetCmin(HeapTupleHeader tup); extern CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup); diff -cr pgsql/src/include/storage/bufpage.h pgsql-crc/src/include/storage/bufpage.h *** pgsql/src/include/storage/bufpage.h Sun Dec 14 22:01:15 2008 --- pgsql-crc/src/include/storage/bufpage.h Sun Dec 14 22:07:51 2008 *************** *** 17,22 **** --- 17,23 ---- #include "access/xlogdefs.h" #include "storage/item.h" #include "storage/off.h" + #include "utils/pg_crc.h" /* * A postgres disk page is an abstraction layered on top of a postgres *************** *** 87,92 **** --- 88,94 ---- * * space management information generic to any page * + * pd_checksum - the checksum of the page * pd_lsn - identifies xlog record for last change to this page. * pd_tli - ditto. * pd_flags - flag bits. *************** *** 118,136 **** * the constraint on pagesize mod 256 is not an important restriction. * On the high end, we can only support pages up to 32KB because lp_off/lp_len * are 15 bits. */ typedef struct PageHeaderData { ! /* XXX LSN is member of *any* block, not only page-organized ones */ XLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog * record for last change to this page */ - uint16 pd_tli; /* least significant bits of the TimeLineID - * containing the LSN */ - uint16 pd_flags; /* flag bits, see below */ LocationIndex pd_lower; /* offset to start of free space */ LocationIndex pd_upper; /* offset to end of free space */ LocationIndex pd_special; /* offset to start of special space */ uint16 pd_pagesize_version; TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */ ItemIdData pd_linp[1]; /* beginning of line pointer array */ } PageHeaderData; --- 120,143 ---- * the constraint on pagesize mod 256 is not an important restriction. * On the high end, we can only support pages up to 32KB because lp_off/lp_len * are 15 bits. + * + * Note that pd_tli appears in a rather awkward position in the struct; + * this is because we moved it to accomodate pd_checksum without changing + * pg_pagesize_version's offset. */ typedef struct PageHeaderData { ! /* XXX CRC & LSN are members of *any* block, not only page-organized ones */ ! pg_crc32 pd_checksum; /* The block-level checksum */ XLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog * record for last change to this page */ LocationIndex pd_lower; /* offset to start of free space */ LocationIndex pd_upper; /* offset to end of free space */ LocationIndex pd_special; /* offset to start of special space */ uint16 pd_pagesize_version; + uint16 pd_tli; /* least significant bits of the TimeLineID + * containing the LSN */ + uint16 pd_flags; /* flag bits, see below */ TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */ ItemIdData pd_linp[1]; /* beginning of line pointer array */ } PageHeaderData; *************** *** 154,161 **** * tuple? */ #define PD_ALL_VISIBLE 0x0004 /* all tuples on page are visible to * everyone */ ! #define PD_VALID_FLAG_BITS 0x0007 /* OR of all valid pd_flags bits */ /* * Page layout version number 0 is for pre-7.3 Postgres releases. --- 161,170 ---- * tuple? */ #define PD_ALL_VISIBLE 0x0004 /* all tuples on page are visible to * everyone */ + #define PD_UNLOGGED_CHANGE 0x0008 /* does the page have unlogged hint + bits? */ ! #define PD_VALID_FLAG_BITS 0x000F /* OR of all valid pd_flags bits */ /* * Page layout version number 0 is for pre-7.3 Postgres releases. *************** *** 165,172 **** * Release 8.3 uses 4; it changed the HeapTupleHeader layout again, and * added the pd_flags field (by stealing some bits from pd_tli), * as well as adding the pd_prune_xid field (which enlarges the header). */ ! #define PG_PAGE_LAYOUT_VERSION 4 /* ---------------------------------------------------------------- --- 174,184 ---- * Release 8.3 uses 4; it changed the HeapTupleHeader layout again, and * added the pd_flags field (by stealing some bits from pd_tli), * as well as adding the pd_prune_xid field (which enlarges the header). + * Release 8.4 uses 5; it added a checksum to the page header, and moved + * pd_tli and pd_flags so that the page version would keep the same + * offset. */ ! #define PG_PAGE_LAYOUT_VERSION 5 /* ---------------------------------------------------------------- *************** *** 361,366 **** --- 373,437 ---- #define PageClearPrunable(page) \ (((PageHeader) (page))->pd_prune_xid = InvalidTransactionId) + /* ---------------------------------------------------------------- + * CRC support + * ---------------------------------------------------------------- + */ + #define PAGE_CHECKSUM_TYPE pg_crc32 + #define SIZEOF_PAGE_CHECKSUM sizeof(PAGE_CHECKSUM_TYPE) + #define PAGE_INVALID_CHECKSUM 0xb79a6e9c + + /* + * Given a page, calculate its checksum. + * + * We only include: the page header, the line pointers (except lp_flags), and + * the area between pd_upper and pd_special. The unused area is not included, + * and neither is the "special space". + */ + #define CalcPageChecksum(buffer, sum) \ + do { \ + int i; \ + INIT_CRC32(sum); \ + /* The page header, excluding pd_crc, pd_flags and pd_prune_xid */ \ + COMP_CRC32(sum, (char *) (buffer) + sizeof(pg_crc32), \ + offsetof(PageHeaderData, pd_flags)); \ + /* each line pointer, excluding lp_flags */ \ + for (i = 1; i <= PageGetMaxOffsetNumber(buffer); i++) \ + { \ + uint32 lpval; \ + lpval = *(uint32 *) PageGetItemId(buffer, i); \ + lpval &= ~ITEM_LP_FLAGS_MASK; \ + COMP_CRC32(sum, &lpval, sizeof(ItemIdData)); \ + } \ + /* the space occupied by tuples */ \ + COMP_CRC32(sum, (char *) (buffer) + ((PageHeader) (buffer))->pd_upper, \ + ((PageHeader) (buffer))->pd_special - ((PageHeader) (buffer))->pd_upper); \ + FIN_CRC32(sum); \ + } while (0) + + + /* beware multiple evaluation of argument */ + #define WritePageChecksum(buffer) \ + do { \ + PAGE_CHECKSUM_TYPE chksum; \ + CalcPageChecksum(buffer, chksum); \ + PageSetChecksum(buffer, chksum); \ + } while (0) + + #define WriteInvalidPageChecksum(buffer) \ + PageSetChecksum((buffer), PAGE_INVALID_CHECKSUM) + + #define PageGetChecksum(page) \ + (((PageHeader) (page))->pd_checksum) + #define PageSetChecksum(page, checksum) \ + (((PageHeader) (page))->pd_checksum = (checksum)) + + #define PageHasUnloggedChange(page) \ + (((PageHeader) (page))->pd_flags & PD_UNLOGGED_CHANGE) + #define PageSetUnloggedChange(page) \ + (((PageHeader) (page))->pd_flags |= PD_UNLOGGED_CHANGE) + #define PageClearUnloggedChange(page) \ + (((PageHeader) (page))->pd_flags &= ~PD_UNLOGGED_CHANGE) /* ---------------------------------------------------------------- * extern declarations diff -cr pgsql/src/include/storage/itemid.h pgsql-crc/src/include/storage/itemid.h *** pgsql/src/include/storage/itemid.h Tue Jan 1 14:45:59 2008 --- pgsql-crc/src/include/storage/itemid.h Sun Dec 14 22:04:25 2008 *************** *** 39,44 **** --- 39,47 ---- #define LP_REDIRECT 2 /* HOT redirect (should have lp_len=0) */ #define LP_DEAD 3 /* dead, may or may not have storage */ + /* the bits used by lp_flags */ + #define ITEM_LP_FLAGS_MASK 0x00018000L + /* * Item offsets and lengths are represented by these types when * they're not actually stored in an ItemIdData. diff -cr pgsql/src/include/storage/smgr.h pgsql-crc/src/include/storage/smgr.h *** pgsql/src/include/storage/smgr.h Sun Dec 14 22:01:15 2008 --- pgsql-crc/src/include/storage/smgr.h Sun Dec 14 22:04:25 2008 *************** *** 20,25 **** --- 20,28 ---- #include "storage/relfilenode.h" + /* Perform block checksumming for corruption detection */ + bool enable_block_checksums; + /* * smgr.c maintains a table of SMgrRelation objects, which are essentially * cached file handles. An SMgrRelation is created (if not already present)