diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2013-06-13 22:35:56 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2013-06-13 22:35:56 -0400 |
commit | f04216341dd1cc235e975f93ac806d9d3729a344 (patch) | |
tree | 803d65ef30cc32456bc2798d76ec04e5513fbd12 /src/backend/storage/page/bufpage.c | |
parent | fa2fc066f34f1b631b5f92f11e7cda9f60a25330 (diff) | |
download | postgresql-f04216341dd1cc235e975f93ac806d9d3729a344.tar.gz postgresql-f04216341dd1cc235e975f93ac806d9d3729a344.zip |
Refactor checksumming code to make it easier to use externally.
pg_filedump and other external utility programs are likely to want to be
able to check Postgres page checksums. To avoid messy duplication of code,
move the checksumming functionality into an exported header file, much as
we did awhile back for the CRC code.
In passing, get rid of an unportable assumption that a static char[] array
will be word-aligned, and do some other minor code beautification.
Diffstat (limited to 'src/backend/storage/page/bufpage.c')
-rw-r--r-- | src/backend/storage/page/bufpage.c | 99 |
1 files changed, 30 insertions, 69 deletions
diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c index a5594bde64e..36b88c5729b 100644 --- a/src/backend/storage/page/bufpage.c +++ b/src/backend/storage/page/bufpage.c @@ -17,13 +17,12 @@ #include "access/htup_details.h" #include "access/xlog.h" #include "storage/checksum.h" +#include "utils/memutils.h" -bool ignore_checksum_failure = false; -static char pageCopyData[BLCKSZ]; /* for checksum calculation */ -static Page pageCopy = pageCopyData; +/* GUC variable */ +bool ignore_checksum_failure = false; -static uint16 PageCalcChecksum16(Page page, BlockNumber blkno); /* ---------------------------------------------------------------- * Page support functions @@ -94,7 +93,7 @@ PageIsVerified(Page page, BlockNumber blkno) { if (DataChecksumsEnabled()) { - checksum = PageCalcChecksum16(page, blkno); + checksum = pg_checksum_page((char *) page, blkno); if (checksum != p->pd_checksum) checksum_failure = true; @@ -885,13 +884,16 @@ PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems) pfree(itemidbase); } + /* - * Set checksum for page in shared buffers. + * Set checksum for a page in shared buffers. * * If checksums are disabled, or if the page is not initialized, just return - * the input. Otherwise, we must make a copy of the page before calculating the - * checksum, to prevent concurrent modifications (e.g. setting hint bits) from - * making the final checksum invalid. + * the input. Otherwise, we must make a copy of the page before calculating + * the checksum, to prevent concurrent modifications (e.g. setting hint bits) + * from making the final checksum invalid. It doesn't matter if we include or + * exclude hints during the copy, as long as we write a valid page and + * associated checksum. * * Returns a pointer to the block-sized data that needs to be written. Uses * statically-allocated memory, so the caller must immediately write the @@ -900,79 +902,38 @@ PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems) char * PageSetChecksumCopy(Page page, BlockNumber blkno) { + static char *pageCopy = NULL; + + /* If we don't need a checksum, just return the passed-in data */ if (PageIsNew(page) || !DataChecksumsEnabled()) return (char *) page; /* - * We make a copy iff we need to calculate a checksum because other - * backends may set hint bits on this page while we write, which would - * mean the checksum differs from the page contents. It doesn't matter if - * we include or exclude hints during the copy, as long as we write a - * valid page and associated checksum. + * We allocate the copy space once and use it over on each subsequent + * call. The point of palloc'ing here, rather than having a static char + * array, is first to ensure adequate alignment for the checksumming code + * and second to avoid wasting space in processes that never call this. */ - memcpy((char *) pageCopy, (char *) page, BLCKSZ); - PageSetChecksumInplace(pageCopy, blkno); - return (char *) pageCopy; + if (pageCopy == NULL) + pageCopy = MemoryContextAlloc(TopMemoryContext, BLCKSZ); + + memcpy(pageCopy, (char *) page, BLCKSZ); + ((PageHeader) pageCopy)->pd_checksum = pg_checksum_page(pageCopy, blkno); + return pageCopy; } /* - * Set checksum for page in private memory. + * Set checksum for a page in private memory. * - * This is a simpler version of PageSetChecksumCopy(). The more explicit API - * allows us to more easily see if we're making the correct call and reduces - * the amount of additional code specific to page verification. + * This must only be used when we know that no other process can be modifying + * the page buffer. */ void PageSetChecksumInplace(Page page, BlockNumber blkno) { - if (PageIsNew(page)) + /* If we don't need a checksum, just return */ + if (PageIsNew(page) || !DataChecksumsEnabled()) return; - if (DataChecksumsEnabled()) - { - PageHeader p = (PageHeader) page; - - p->pd_checksum = PageCalcChecksum16(page, blkno); - } - - return; -} - -/* - * Calculate checksum for a PostgreSQL Page. This includes the block number (to - * detect the case when a page is somehow moved to a different location), the - * page header (excluding the checksum itself), and the page data. - * - * Note that if the checksum validation fails we cannot tell the difference - * between a transposed block and failure from direct on-block corruption, - * though that is better than just ignoring transposed blocks altogether. - */ -static uint16 -PageCalcChecksum16(Page page, BlockNumber blkno) -{ - PageHeader phdr = (PageHeader) page; - uint16 save_checksum; - uint32 checksum; - - /* only calculate the checksum for properly-initialized pages */ - Assert(!PageIsNew(page)); - - /* - * Save pd_checksum and set it to zero, so that the checksum calculation - * isn't affected by the checksum stored on the page. We do this to allow - * optimization of the checksum calculation on the whole block in one go. - */ - save_checksum = phdr->pd_checksum; - phdr->pd_checksum = 0; - checksum = checksum_block(page, BLCKSZ); - phdr->pd_checksum = save_checksum; - - /* mix in the block number to detect transposed pages */ - checksum ^= blkno; - - /* - * Reduce to a uint16 (to fit in the pd_checksum field) with an offset of - * one. That avoids checksums of zero, which seems like a good idea. - */ - return (checksum % 65535) + 1; + ((PageHeader) page)->pd_checksum = pg_checksum_page((char *) page, blkno); } |