Hi.

Am Montag, den 17.09.2018, 20:45 -0400 schrieb Stephen Frost:
> > You're right it's not about the fsync, sorry for the confusion. My point
> > is that using the checkpoint LSN gives us a guarantee that write is no
> > longer in progress, and so we can't see a page torn because of it. And
> > if we see a partial write due to a new write, it's guaranteed to update
> > the page LSN (and we'll notice it).
> 
> Right, no worries about the confusion, I hadn't been fully thinking
> through the LSN bit either and that what we really need is some external
> confirmation of a write having *completed* (not just started) and that
> makes a definite difference.
> 
> > > Right, I'm in agreement with doing that and it's what is done in
> > > pgbasebackup and pgBackRest.
> > 
> > OK. All I'm saying is pg_verify_checksums should probably do the same
> > thing, i.e. grab checkpoint LSN and roll with that.
> 
> Agreed.

I've attached the patch I added to my branch to swap out the pg_sleep()
with a check against the checkpoint LSN on a recheck verification
failure.

Let me know if there are still issues with it. I'll send a new patch for
the whole online verification feature in a bit.


Michael

-- 
Michael Banck
Projektleiter / Senior Berater
Tel.: +49 2166 9901-171
Fax:  +49 2166 9901-100
Email: michael.ba...@credativ.de

credativ GmbH, HRB Mönchengladbach 12080
USt-ID-Nummer: DE204566209
Trompeterallee 108, 41189 Mönchengladbach
Geschäftsführung: Dr. Michael Meskes, Jörg Folz, Sascha Heuer

Unser Umgang mit personenbezogenen Daten unterliegt
folgenden Bestimmungen: https://www.credativ.de/datenschutz
commit 3b7d80fa7431098de4aab19a85f7d7b01c43f8a8
Author: Michael Banck <mba...@debian.org>
Date:   Tue Sep 18 11:53:36 2018 +0200

    Skip pages with new LSNs on recheck verification failure.
    
    Before, we only skipped new pages and added a pg_sleep during the recheck.
    This logic is broken, so replace it with a check against the (startup)
    checkpoint LSN on a verification failure on recheck. If the LSN in the page
    header is newer than the checkpoint LSN, we assume a torn page and skip it in
    this run of pg_verify_checksums.
    
    This now follows the logic during base backup checksum verification, however,
    contrary to that we do not skip a page immediately if the LSN is newer than the
    checkpoint, but try to (re-)verify it first and only skip it if its LSN is
    newer on a recheck verification failure.

diff --git a/src/bin/pg_verify_checksums/pg_verify_checksums.c b/src/bin/pg_verify_checksums/pg_verify_checksums.c
index 7c2a06390c..2f8b5bf167 100644
--- a/src/bin/pg_verify_checksums/pg_verify_checksums.c
+++ b/src/bin/pg_verify_checksums/pg_verify_checksums.c
@@ -26,6 +26,7 @@ static int64 files = 0;
 static int64 blocks = 0;
 static int64 badblocks = 0;
 static ControlFileData *ControlFile;
+static XLogRecPtr checkpointLSN;
 
 static char *only_relfilenode = NULL;
 static bool verbose = false;
@@ -125,14 +126,14 @@ scan_file(const char *fn, BlockNumber segmentno)
 			 * possible that we read the first 4K page of
 			 * the block just before postgres updated the
 			 * entire block so it ends up looking torn to
-			 * us. If there were less than 10 bad blocks so
-			 * far, we wait for 500ms before we retry.
+			 * us.  We only need to retry once because the
+			 * LSN should be updated to something we can
+			 * ignore on the next pass.  If the error
+			 * happens again then it is a true validation
+			 * failure.
 			 */
 			if (block_retry == false)
 			{
-				if (badblocks < 10)
-					pg_usleep(500);
-
 				/* Seek to the beginning of the failed block */
 				if (lseek(f, -BLCKSZ, SEEK_CUR) == -1)
 				{
@@ -150,6 +151,16 @@ scan_file(const char *fn, BlockNumber segmentno)
 				continue;
 			}
 
+			/* The checksum verification failed on retry as well.
+			 * Check if the page has been modified since the
+			 * checkpoint and skip it in this case.
+			 */
+			if (PageGetLSN(buf.data) > checkpointLSN)
+			{
+				block_retry = false;
+				continue;
+			}
+
 			if (ControlFile->data_checksum_version == PG_DATA_CHECKSUM_VERSION)
 				fprintf(stderr, _("%s: checksum verification failed in file \"%s\", block %u: calculated checksum %X but block contains %X\n"),
 						progname, fn, blockno, csum, header->pd_checksum);
@@ -344,6 +355,9 @@ main(int argc, char *argv[])
 		exit(1);
 	}
 
+	/* Get checkpoint LSN */
+	checkpointLSN = ControlFile->checkPoint;
+
 	/* Scan all files */
 	scan_directory(DataDir, "global");
 	scan_directory(DataDir, "base");

Reply via email to