Extend PageIsVerified() to handle more custom options
authorMichael Paquier <michael@paquier.xyz>
Mon, 26 Oct 2020 00:55:28 +0000 (09:55 +0900)
committerMichael Paquier <michael@paquier.xyz>
Mon, 26 Oct 2020 00:55:28 +0000 (09:55 +0900)
This is useful for checks of relation pages without having to load the
pages into the shared buffers, and two cases can make use of that: page
verification in base backups and the online, lock-safe, flavor.

Compatibility is kept with past versions using a macro that calls the
new extended routine with the set of options compatible with the
original version.

Extracted from a larger patch by the same author.

Author: Anastasia Lubennikova
Reviewed-by: Michael Paquier, Julien Rouhaud
Discussion: https://postgr.es/m/608f3476-0598-2514-2c03-e05c7d2b0cbd@postgrespro.ru

src/backend/catalog/storage.c
src/backend/storage/buffer/bufmgr.c
src/backend/storage/page/bufpage.c
src/include/storage/bufpage.h

index dbbd3aa31fe14281ba5d4fedf0d777be1022116e..d538f25726f4584c11a2e23b6328b19d6c25cb46 100644 (file)
@@ -443,7 +443,8 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
 
        smgrread(src, forkNum, blkno, buf.data);
 
-       if (!PageIsVerified(page, blkno))
+       if (!PageIsVerifiedExtended(page, blkno,
+                                   PIV_LOG_WARNING | PIV_REPORT_STAT))
            ereport(ERROR,
                    (errcode(ERRCODE_DATA_CORRUPTED),
                     errmsg("invalid page in block %u of relation %s",
index e549fa1d309fe5021e58877bbd21f80f9c0070d5..3eee86afe5c4748a3e3176cbf8e23d7a341b4b7e 100644 (file)
@@ -625,7 +625,8 @@ ReadBuffer(Relation reln, BlockNumber blockNum)
  *
  * In RBM_NORMAL mode, the page is read from disk, and the page header is
  * validated.  An error is thrown if the page header is not valid.  (But
- * note that an all-zero page is considered "valid"; see PageIsVerified().)
+ * note that an all-zero page is considered "valid"; see
+ * PageIsVerifiedExtended().)
  *
  * RBM_ZERO_ON_ERROR is like the normal mode, but if the page header is not
  * valid, the page is zeroed instead of throwing an error. This is intended
@@ -917,7 +918,8 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
            }
 
            /* check for garbage data */
-           if (!PageIsVerified((Page) bufBlock, blockNum))
+           if (!PageIsVerifiedExtended((Page) bufBlock, blockNum,
+                                       PIV_LOG_WARNING | PIV_REPORT_STAT))
            {
                if (mode == RBM_ZERO_ON_ERROR || zero_damaged_pages)
                {
index 4bc2bf955dfd5aa1d4b2c4f0dc606b442da57d34..ddf18079e2fbf714ae795a0c9beaddda9ed76c93 100644 (file)
@@ -61,7 +61,7 @@ PageInit(Page page, Size pageSize, Size specialSize)
 
 
 /*
- * PageIsVerified
+ * PageIsVerifiedExtended
  *     Check that the page header and checksum (if any) appear valid.
  *
  * This is called when a page has just been read in from disk.  The idea is
@@ -77,9 +77,15 @@ PageInit(Page page, Size pageSize, Size specialSize)
  * allow zeroed pages here, and are careful that the page access macros
  * treat such a page as empty and without free space.  Eventually, VACUUM
  * will clean up such a page and make it usable.
+ *
+ * If flag PIV_LOG_WARNING is set, a WARNING is logged in the event of
+ * a checksum failure.
+ *
+ * If flag PIV_REPORT_STAT is set, a checksum failure is reported directly
+ * to pgstat.
  */
 bool
-PageIsVerified(Page page, BlockNumber blkno)
+PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags)
 {
    PageHeader  p = (PageHeader) page;
    size_t     *pagebytes;
@@ -140,12 +146,14 @@ PageIsVerified(Page page, BlockNumber blkno)
     */
    if (checksum_failure)
    {
-       ereport(WARNING,
-               (errcode(ERRCODE_DATA_CORRUPTED),
-                errmsg("page verification failed, calculated checksum %u but expected %u",
-                       checksum, p->pd_checksum)));
+       if ((flags & PIV_LOG_WARNING) != 0)
+           ereport(WARNING,
+                   (errcode(ERRCODE_DATA_CORRUPTED),
+                    errmsg("page verification failed, calculated checksum %u but expected %u",
+                           checksum, p->pd_checksum)));
 
-       pgstat_report_checksum_failure();
+       if ((flags & PIV_REPORT_STAT) != 0)
+           pgstat_report_checksum_failure();
 
        if (header_sane && ignore_checksum_failure)
            return true;
index 51b8f994ac0ae973eb1e9f726e240005722fc3a9..d0a52f8e08fc926f5a061a12f87e08c8d197760c 100644 (file)
@@ -404,26 +404,36 @@ do { \
  *     extern declarations
  * ----------------------------------------------------------------
  */
+
+/* flags for PageAddItemExtended() */
 #define PAI_OVERWRITE          (1 << 0)
 #define PAI_IS_HEAP                (1 << 1)
 
+/* flags for PageIsVerifiedExtended() */
+#define PIV_LOG_WARNING            (1 << 0)
+#define PIV_REPORT_STAT            (1 << 1)
+
 #define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap) \
    PageAddItemExtended(page, item, size, offsetNumber, \
                        ((overwrite) ? PAI_OVERWRITE : 0) | \
                        ((is_heap) ? PAI_IS_HEAP : 0))
 
+#define PageIsVerified(page, blkno) \
+   PageIsVerifiedExtended(page, blkno, \
+                          PIV_LOG_WARNING | PIV_REPORT_STAT)
+
 /*
- * Check that BLCKSZ is a multiple of sizeof(size_t).  In PageIsVerified(),
- * it is much faster to check if a page is full of zeroes using the native
- * word size.  Note that this assertion is kept within a header to make
- * sure that StaticAssertDecl() works across various combinations of
- * platforms and compilers.
+ * Check that BLCKSZ is a multiple of sizeof(size_t).  In
+ * PageIsVerifiedExtended(), it is much faster to check if a page is
+ * full of zeroes using the native word size.  Note that this assertion
+ * is kept within a header to make sure that StaticAssertDecl() works
+ * across various combinations of platforms and compilers.
  */
 StaticAssertDecl(BLCKSZ == ((BLCKSZ / sizeof(size_t)) * sizeof(size_t)),
                 "BLCKSZ has to be a multiple of sizeof(size_t)");
 
 extern void PageInit(Page page, Size pageSize, Size specialSize);
-extern bool PageIsVerified(Page page, BlockNumber blkno);
+extern bool PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags);
 extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size,
                                        OffsetNumber offsetNumber, int flags);
 extern Page PageGetTempPage(Page page);