On Thu, Mar 21, 2019 at 08:17:32AM +0100, Fabien COELHO wrote: > I can try, but I must admit that I'm fuzzy about the actual issue. Is there > a problem on a streaming replication with inconsistent checksum settings, or > not? > > You seem to suggest that the issue is more about how some commands or backup > tools operate on a cluster.
Yes. That's what I am writing about. Imagine for example this case with pg_rewind: - primary has checksums enabled. - standby has checksums disabled. - a hard crash of the primary happens, there is a failover to the standby which gets promoted. - The primary's host is restarted, it is started and stopped once cleanly to have a clear point in its past timeline where WAL forked thanks to the generation of at least the shutdown checkpoint generated by the clean stop. - pg_rewind is run, copying some pages from the promoted standby, which don't have checksums, to the primary with checksums enabled, and causing some pages to have an incorrect checksum. There is another tool I know of which is called pg_rman, which is a backup tool able to take incremental backups in the shape of a delta of relation blocks. Then imagine the following: - One instance of Postgres runs, has checksums disabled. - pg_rman takes a full backup of it. - Checksums are enabled on this instance. - An incremental backup from the previous full backup point is taken. If I recall correctly pg_rman takes a copy of the new control file as well, which tracks checksums as being enabled. - A crash happens, the data folder is dead. - Rollback to the previous backup is done, and we restore up to a point after the incremental backup. - And you finish with a cluster which has checksums enabled, but as the initial full backup had checksums disabled, not all the pages may be in a correct state. So I think that it makes sense to tell to be careful within the documentation, but being too much careful in the tool discards also many possibilities (see the example of the clean failover where it is possible to enable checksums with no actual downtime). And this part has a lot of value. > ISTM that this would not work: The control file update can only be done > *after* the fsync to describe the cluster actual status, otherwise it is > just a question of luck whether the cluster is corrupt on an crash while > fsyncing. The enforced order of operation, with a barrier in between, is the > important thing here. Done the switch for this case. For pg_rewind actually I think that this is an area where its logic could be improved a bit. So first the data folder is synced, and then the control file is updated. It took less time to change the code than to write this paragraph, including the code compilation and one run of the TAP tests, confirmed. I have added in the docs a warning about a host crash while doing the operation, with a recommendation to check the state of the checksums on the data folder should it happen, and the previous portion of the docs about clusters. Your suggestion sounds adapted. I would be tempted to add a bigger warning in pg_rewind or pg_basebackup about that, but that's a different story for another time. Does that look fine to you? -- Michael
From 7ef4a14421b9999d148fa24f3107e8ef8be8b348 Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@paquier.xyz> Date: Fri, 22 Mar 2019 09:21:18 +0900 Subject: [PATCH v9 1/2] Add options to enable and disable checksums in pg_checksums An offline cluster can now work with more modes in pg_checksums: - --enable can enable checksums in a cluster, updating all blocks with a correct checksum, and update the control file at the end. - --disable can disable checksums in a cluster, updating the the control file. - --check is an extra option able to verify checksums for a cluster. When running --enable or --disable, the data folder gets fsync'd for durability. If no mode is specified in the options, then --check is used for compatibility with older versions of pg_verify_checksums (now renamed to pg_checksums in v12). Author: Michael Banck Reviewed-by: Fabien Coelho, Michael Paquier Discussion: https://postgr.es/m/20181221201616.gd4...@nighthawk.caipicrew.dd-dns.de --- doc/src/sgml/ref/pg_checksums.sgml | 72 ++++++++++- src/bin/pg_checksums/pg_checksums.c | 175 ++++++++++++++++++++++---- src/bin/pg_checksums/t/002_actions.pl | 76 ++++++++--- src/tools/pgindent/typedefs.list | 1 + 4 files changed, 278 insertions(+), 46 deletions(-) diff --git a/doc/src/sgml/ref/pg_checksums.sgml b/doc/src/sgml/ref/pg_checksums.sgml index 6a47dda683..fda85e7ea0 100644 --- a/doc/src/sgml/ref/pg_checksums.sgml +++ b/doc/src/sgml/ref/pg_checksums.sgml @@ -16,7 +16,7 @@ PostgreSQL documentation <refnamediv> <refname>pg_checksums</refname> - <refpurpose>verify data checksums in a <productname>PostgreSQL</productname> database cluster</refpurpose> + <refpurpose>enable, disable or check data checksums in a <productname>PostgreSQL</productname> database cluster</refpurpose> </refnamediv> <refsynopsisdiv> @@ -36,10 +36,19 @@ PostgreSQL documentation <refsect1 id="r1-app-pg_checksums-1"> <title>Description</title> <para> - <application>pg_checksums</application> verifies data checksums in a - <productname>PostgreSQL</productname> cluster. The server must be shut - down cleanly before running <application>pg_checksums</application>. - The exit status is zero if there are no checksum errors, otherwise nonzero. + <application>pg_checksums</application> checks, enables or disables data + checksums in a <productname>PostgreSQL</productname> cluster. The server + must be shut down cleanly before running + <application>pg_checksums</application>. The exit status is zero if there + are no checksum errors when checking them, and nonzero if at least one + checksum failure is detected. If enabling or disabling checksums, the + exit status is nonzero if the operation failed. + </para> + + <para> + While checking or enabling checksums needs to scan or write every file in + the cluster, disabling checksums will only update the file + <filename>pg_control</filename>. </para> </refsect1> @@ -60,6 +69,37 @@ PostgreSQL documentation </listitem> </varlistentry> + <varlistentry> + <term><option>-c</option></term> + <term><option>--check</option></term> + <listitem> + <para> + Checks checksums. This is the default mode if nothing else is + specified. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>-d</option></term> + <term><option>--disable</option></term> + <listitem> + <para> + Disables checksums. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>-e</option></term> + <term><option>--enable</option></term> + <listitem> + <para> + Enables checksums. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><option>-v</option></term> <term><option>--verbose</option></term> @@ -119,4 +159,26 @@ PostgreSQL documentation </varlistentry> </variablelist> </refsect1> + + <refsect1> + <title>Notes</title> + <para> + When disabling or enabling checksums in a cluster of multiple instances, + it is recommended to stop all the instances of the cluster before doing + the switch to all the instances consistently. When using a cluster with + tools which perform direct copies of relation file blocks (for example + <xref linkend="app-pgrewind"/>), enabling or disabling checksums can + lead to page corruptions in the shape of incorrect checksums if the + operation is not done consistently across all nodes. Destroying all + the standbys in a cluster first, enabling or disabling checksums on + the primary and finally recreating the cluster nodes from scratch is + also safe. + </para> + <para> + If the event of a crash of the operating system while enabling or + disabling checksums, the data folder may have checksums in an inconsistent + state, in which case it is recommended to check the state of checksums + in the data folder. + </para> + </refsect1> </refentry> diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c index b7ebc11017..f640fda14b 100644 --- a/src/bin/pg_checksums/pg_checksums.c +++ b/src/bin/pg_checksums/pg_checksums.c @@ -1,7 +1,8 @@ /*------------------------------------------------------------------------- * * pg_checksums.c - * Verifies page level checksums in an offline cluster. + * Checks, enables or disables page level checksums for an offline + * cluster * * Copyright (c) 2010-2019, PostgreSQL Global Development Group * @@ -17,14 +18,15 @@ #include <sys/stat.h> #include <unistd.h> -#include "catalog/pg_control.h" +#include "access/xlog_internal.h" #include "common/controldata_utils.h" +#include "common/file_perm.h" +#include "common/file_utils.h" #include "getopt_long.h" #include "pg_getopt.h" #include "storage/bufpage.h" #include "storage/checksum.h" #include "storage/checksum_impl.h" -#include "storage/fd.h" static int64 files = 0; @@ -35,16 +37,38 @@ static ControlFileData *ControlFile; static char *only_relfilenode = NULL; static bool verbose = false; +typedef enum +{ + PG_MODE_CHECK, + PG_MODE_DISABLE, + PG_MODE_ENABLE +} PgChecksumMode; + +/* + * Filename components. + * + * XXX: fd.h is not declared here as frontend side code is not able to + * interact with the backend-side definitions for the various fsync + * wrappers. + */ +#define PG_TEMP_FILES_DIR "pgsql_tmp" +#define PG_TEMP_FILE_PREFIX "pgsql_tmp" + +static PgChecksumMode mode = PG_MODE_CHECK; + static const char *progname; static void usage(void) { - printf(_("%s verifies data checksums in a PostgreSQL database cluster.\n\n"), progname); + printf(_("%s enables, disables or verifies data checksums in a PostgreSQL database cluster.\n\n"), progname); printf(_("Usage:\n")); printf(_(" %s [OPTION]... [DATADIR]\n"), progname); printf(_("\nOptions:\n")); printf(_(" [-D, --pgdata=]DATADIR data directory\n")); + printf(_(" -c, --check check data checksums (default)\n")); + printf(_(" -d, --disable disable data checksums\n")); + printf(_(" -e, --enable enable data checksums\n")); printf(_(" -v, --verbose output verbose messages\n")); printf(_(" -r RELFILENODE check only relation with specified relfilenode\n")); printf(_(" -V, --version output version information, then exit\n")); @@ -90,8 +114,14 @@ scan_file(const char *fn, BlockNumber segmentno) PageHeader header = (PageHeader) buf.data; int f; BlockNumber blockno; + int flags; + + Assert(mode == PG_MODE_ENABLE || + mode == PG_MODE_CHECK); + + flags = (mode == PG_MODE_ENABLE) ? O_RDWR : O_RDONLY; + f = open(fn, PG_BINARY | flags, 0); - f = open(fn, O_RDONLY | PG_BINARY, 0); if (f < 0) { fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), @@ -121,18 +151,47 @@ scan_file(const char *fn, BlockNumber segmentno) continue; csum = pg_checksum_page(buf.data, blockno + segmentno * RELSEG_SIZE); - if (csum != header->pd_checksum) + if (mode == PG_MODE_CHECK) { - 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); - badblocks++; + if (csum != header->pd_checksum) + { + 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); + badblocks++; + } + } + else if (mode == PG_MODE_ENABLE) + { + /* Set checksum in page header */ + header->pd_checksum = csum; + + /* Seek back to beginning of block */ + if (lseek(f, -BLCKSZ, SEEK_CUR) < 0) + { + fprintf(stderr, _("%s: seek failed for block %d in file \"%s\": %s\n"), progname, blockno, fn, strerror(errno)); + exit(1); + } + + /* Write block with checksum */ + if (write(f, buf.data, BLCKSZ) != BLCKSZ) + { + fprintf(stderr, "%s: could not update checksum of block %d in file \"%s\": %s\n", + progname, blockno, fn, strerror(errno)); + exit(1); + } } } if (verbose) - fprintf(stderr, - _("%s: checksums verified in file \"%s\"\n"), progname, fn); + { + if (mode == PG_MODE_CHECK) + fprintf(stderr, + _("%s: checksums verified in file \"%s\"\n"), progname, fn); + if (mode == PG_MODE_ENABLE) + fprintf(stderr, + _("%s: checksums enabled in file \"%s\"\n"), progname, fn); + } close(f); } @@ -234,7 +293,10 @@ int main(int argc, char *argv[]) { static struct option long_options[] = { + {"check", no_argument, NULL, 'c'}, {"pgdata", required_argument, NULL, 'D'}, + {"disable", no_argument, NULL, 'd'}, + {"enable", no_argument, NULL, 'e'}, {"verbose", no_argument, NULL, 'v'}, {NULL, 0, NULL, 0} }; @@ -262,10 +324,19 @@ main(int argc, char *argv[]) } } - while ((c = getopt_long(argc, argv, "D:r:v", long_options, &option_index)) != -1) + while ((c = getopt_long(argc, argv, "cD:der:v", long_options, &option_index)) != -1) { switch (c) { + case 'c': + mode = PG_MODE_CHECK; + break; + case 'd': + mode = PG_MODE_DISABLE; + break; + case 'e': + mode = PG_MODE_ENABLE; + break; case 'v': verbose = true; break; @@ -312,6 +383,15 @@ main(int argc, char *argv[]) exit(1); } + /* Relfilenode checking only works in --check mode */ + if (mode != PG_MODE_CHECK && only_relfilenode) + { + fprintf(stderr, _("%s: relfilenode option only possible with --check\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); + exit(1); + } + /* Check if cluster is running */ ControlFile = get_controlfile(DataDir, progname, &crc_ok); if (!crc_ok) @@ -339,29 +419,72 @@ main(int argc, char *argv[]) if (ControlFile->state != DB_SHUTDOWNED && ControlFile->state != DB_SHUTDOWNED_IN_RECOVERY) { - fprintf(stderr, _("%s: cluster must be shut down to verify checksums\n"), progname); + fprintf(stderr, _("%s: cluster must be shut down\n"), progname); exit(1); } - if (ControlFile->data_checksum_version == 0) + if (ControlFile->data_checksum_version == 0 && + mode == PG_MODE_CHECK) { fprintf(stderr, _("%s: data checksums are not enabled in cluster\n"), progname); exit(1); } + if (ControlFile->data_checksum_version == 0 && + mode == PG_MODE_DISABLE) + { + fprintf(stderr, _("%s: data checksums are already disabled in cluster.\n"), progname); + exit(1); + } + if (ControlFile->data_checksum_version > 0 && + mode == PG_MODE_ENABLE) + { + fprintf(stderr, _("%s: data checksums are already enabled in cluster.\n"), progname); + exit(1); + } - /* Scan all files */ - scan_directory(DataDir, "global"); - scan_directory(DataDir, "base"); - scan_directory(DataDir, "pg_tblspc"); + /* Operate on all files if checking or enabling checksums */ + if (mode == PG_MODE_CHECK || mode == PG_MODE_ENABLE) + { + scan_directory(DataDir, "global"); + scan_directory(DataDir, "base"); + scan_directory(DataDir, "pg_tblspc"); - printf(_("Checksum scan completed\n")); - printf(_("Data checksum version: %d\n"), ControlFile->data_checksum_version); - printf(_("Files scanned: %s\n"), psprintf(INT64_FORMAT, files)); - printf(_("Blocks scanned: %s\n"), psprintf(INT64_FORMAT, blocks)); - printf(_("Bad checksums: %s\n"), psprintf(INT64_FORMAT, badblocks)); + printf(_("Checksum operation completed\n")); + printf(_("Files scanned: %s\n"), psprintf(INT64_FORMAT, files)); + printf(_("Blocks scanned: %s\n"), psprintf(INT64_FORMAT, blocks)); + if (mode == PG_MODE_CHECK) + { + printf(_("Bad checksums: %s\n"), psprintf(INT64_FORMAT, badblocks)); + printf(_("Data checksum version: %d\n"), ControlFile->data_checksum_version); - if (badblocks > 0) - return 1; + if (badblocks > 0) + exit(1); + } + } + + /* + * Finally make the data durable on disk if enabling or disabling + * checksums. Flush first the data directory for safety, and then + * update the control file to keep the switch consistency. + */ + if (mode == PG_MODE_ENABLE || mode == PG_MODE_DISABLE) + { + ControlFile->data_checksum_version = + (mode == PG_MODE_ENABLE) ? PG_DATA_CHECKSUM_VERSION : 0; + + printf(_("Syncing data directory\n")); + fsync_pgdata(DataDir, progname, PG_VERSION_NUM); + + printf(_("Updating control file\n")); + update_controlfile(DataDir, progname, ControlFile, true); + + if (verbose) + printf(_("Data checksum version: %d\n"), ControlFile->data_checksum_version); + if (mode == PG_MODE_ENABLE) + printf(_("Checksums enabled in cluster\n")); + else + printf(_("Checksums disabled in cluster\n")); + } return 0; } diff --git a/src/bin/pg_checksums/t/002_actions.pl b/src/bin/pg_checksums/t/002_actions.pl index 97284e8930..3ab18a6b89 100644 --- a/src/bin/pg_checksums/t/002_actions.pl +++ b/src/bin/pg_checksums/t/002_actions.pl @@ -5,7 +5,7 @@ use strict; use warnings; use PostgresNode; use TestLib; -use Test::More tests => 45; +use Test::More tests => 62; # Utility routine to create and check a table with corrupted checksums @@ -38,8 +38,8 @@ sub check_relation_corruption # Checksums are correct for single relfilenode as the table is not # corrupted yet. - command_ok(['pg_checksums', '-D', $pgdata, - '-r', $relfilenode_corrupted], + command_ok(['pg_checksums', '--check', '-D', $pgdata, '-r', + $relfilenode_corrupted], "succeeds for single relfilenode on tablespace $tablespace with offline cluster"); # Time to create some corruption @@ -49,15 +49,15 @@ sub check_relation_corruption close $file; # Checksum checks on single relfilenode fail - $node->command_checks_all([ 'pg_checksums', '-D', $pgdata, '-r', - $relfilenode_corrupted], + $node->command_checks_all([ 'pg_checksums', '--check', '-D', $pgdata, + '-r', $relfilenode_corrupted], 1, [qr/Bad checksums:.*1/], [qr/checksum verification failed/], "fails with corrupted data for single relfilenode on tablespace $tablespace"); # Global checksum checks fail as well - $node->command_checks_all([ 'pg_checksums', '-D', $pgdata], + $node->command_checks_all([ 'pg_checksums', '--check', '-D', $pgdata], 1, [qr/Bad checksums:.*1/], [qr/checksum verification failed/], @@ -67,22 +67,22 @@ sub check_relation_corruption $node->start; $node->safe_psql('postgres', "DROP TABLE $table;"); $node->stop; - $node->command_ok(['pg_checksums', '-D', $pgdata], + $node->command_ok(['pg_checksums', '--check', '-D', $pgdata], "succeeds again after table drop on tablespace $tablespace"); $node->start; return; } -# Initialize node with checksums enabled. +# Initialize node with checksums disabled. my $node = get_new_node('node_checksum'); -$node->init(extra => ['--data-checksums']); +$node->init(); my $pgdata = $node->data_dir; -# Control file should know that checksums are enabled. +# Control file should know that checksums are disabled. command_like(['pg_controldata', $pgdata], - qr/Data page checksum version:.*1/, - 'checksums enabled in control file'); + qr/Data page checksum version:.*0/, + 'checksums disabled in control file'); # These are correct but empty files, so they should pass through. append_to_file "$pgdata/global/99999", ""; @@ -100,13 +100,59 @@ append_to_file "$pgdata/global/pgsql_tmp_123", "foo"; mkdir "$pgdata/global/pgsql_tmp"; append_to_file "$pgdata/global/pgsql_tmp/1.1", "foo"; +# Enable checksums. +command_ok(['pg_checksums', '--enable', '-D', $pgdata], + "checksums successfully enabled in cluster"); + +# Successive attempt to enable checksums fails. +command_fails(['pg_checksums', '--enable', '-D', $pgdata], + "enabling checksums fails if already enabled"); + +# Control file should know that checksums are enabled. +command_like(['pg_controldata', $pgdata], + qr/Data page checksum version:.*1/, + 'checksums enabled in control file'); + +# Disable checksums again. +command_ok(['pg_checksums', '--disable', '-D', $pgdata], + "checksums successfully disabled in cluster"); + +# Successive attempt to disable checksums fails. +command_fails(['pg_checksums', '--disable', '-D', $pgdata], + "disabling checksums fails if already disabled"); + +# Control file should know that checksums are disabled. +command_like(['pg_controldata', $pgdata], + qr/Data page checksum version:.*0/, + 'checksums disabled in control file'); + +# Enable checksums again for follow-up tests. +command_ok(['pg_checksums', '--enable', '-D', $pgdata], + "checksums successfully enabled in cluster"); + +# Control file should know that checksums are enabled. +command_like(['pg_controldata', $pgdata], + qr/Data page checksum version:.*1/, + 'checksums enabled in control file'); + # Checksums pass on a newly-created cluster -command_ok(['pg_checksums', '-D', $pgdata], +command_ok(['pg_checksums', '--check', '-D', $pgdata], "succeeds with offline cluster"); +# Checksums are verified if no other arguments are specified +command_ok(['pg_checksums', '-D', $pgdata], + "verifies checksums as default action"); + +# Specific relation files cannot be requested when action is --disable +# or --enable. +command_fails(['pg_checksums', '--disable', '-r', '1234', '-D', $pgdata], + "fails when relfilenodes are requested and action is --disable"); +command_fails(['pg_checksums', '--enable', '-r', '1234', '-D', $pgdata], + "fails when relfilenodes are requested and action is --enable"); + # Checks cannot happen with an online cluster $node->start; -command_fails(['pg_checksums', '-D', $pgdata], +command_fails(['pg_checksums', '--check', '-D', $pgdata], "fails with online cluster"); # Check corruption of table on default tablespace. @@ -133,7 +179,7 @@ sub fail_corrupt my $file_name = "$pgdata/global/$file"; append_to_file $file_name, "foo"; - $node->command_checks_all([ 'pg_checksums', '-D', $pgdata], + $node->command_checks_all([ 'pg_checksums', '--check', '-D', $pgdata], 1, [qr/^$/], [qr/could not read block 0 in file.*$file\":/], diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index b301bce4b1..195b146974 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1710,6 +1710,7 @@ PgBenchExprType PgBenchFunction PgBenchValue PgBenchValueType +PgChecksumMode PgFdwAnalyzeState PgFdwDirectModifyState PgFdwModifyState -- 2.20.1
From cee5e9f3ed9e190569a99548545801564b087fec Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@paquier.xyz> Date: Fri, 22 Mar 2019 09:24:14 +0900 Subject: [PATCH v9 2/2] Add option -N/--no-sync to pg_checksums This is an option consistent with what pg_dump, pg_rewind and pg_basebackup provide which is useful for leveraging the I/O effort when testing things, not to be used in a production environment. Author: Michael Paquier Reviewed-by: Fabien Coelho Discussion: https://postgr.es/m/20181221201616.gd4...@nighthawk.caipicrew.dd-dns.de --- doc/src/sgml/ref/pg_checksums.sgml | 16 ++++++++++++++++ src/bin/pg_checksums/pg_checksums.c | 17 +++++++++++++---- src/bin/pg_checksums/t/002_actions.pl | 10 +++++----- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/doc/src/sgml/ref/pg_checksums.sgml b/doc/src/sgml/ref/pg_checksums.sgml index fda85e7ea0..ce761cc662 100644 --- a/doc/src/sgml/ref/pg_checksums.sgml +++ b/doc/src/sgml/ref/pg_checksums.sgml @@ -100,6 +100,22 @@ PostgreSQL documentation </listitem> </varlistentry> + <varlistentry> + <term><option>-N</option></term> + <term><option>--no-sync</option></term> + <listitem> + <para> + By default, <command>pg_checksums</command> will wait for all files + to be written safely to disk. This option causes + <command>pg_checksums</command> to return without waiting, which is + faster, but means that a subsequent operating system crash can leave + the updated data folder corrupt. Generally, this option is useful + for testing but should not be used on a production installation. + This option has no effect when using <literal>--check</literal>. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><option>-v</option></term> <term><option>--verbose</option></term> diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c index f640fda14b..5265a30d97 100644 --- a/src/bin/pg_checksums/pg_checksums.c +++ b/src/bin/pg_checksums/pg_checksums.c @@ -35,6 +35,7 @@ static int64 badblocks = 0; static ControlFileData *ControlFile; static char *only_relfilenode = NULL; +static bool do_sync = true; static bool verbose = false; typedef enum @@ -69,6 +70,7 @@ usage(void) printf(_(" -c, --check check data checksums (default)\n")); printf(_(" -d, --disable disable data checksums\n")); printf(_(" -e, --enable enable data checksums\n")); + printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n")); printf(_(" -v, --verbose output verbose messages\n")); printf(_(" -r RELFILENODE check only relation with specified relfilenode\n")); printf(_(" -V, --version output version information, then exit\n")); @@ -297,6 +299,7 @@ main(int argc, char *argv[]) {"pgdata", required_argument, NULL, 'D'}, {"disable", no_argument, NULL, 'd'}, {"enable", no_argument, NULL, 'e'}, + {"no-sync", no_argument, NULL, 'N'}, {"verbose", no_argument, NULL, 'v'}, {NULL, 0, NULL, 0} }; @@ -324,7 +327,7 @@ main(int argc, char *argv[]) } } - while ((c = getopt_long(argc, argv, "cD:der:v", long_options, &option_index)) != -1) + while ((c = getopt_long(argc, argv, "cD:deNr:v", long_options, &option_index)) != -1) { switch (c) { @@ -337,6 +340,9 @@ main(int argc, char *argv[]) case 'e': mode = PG_MODE_ENABLE; break; + case 'N': + do_sync = false; + break; case 'v': verbose = true; break; @@ -472,11 +478,14 @@ main(int argc, char *argv[]) ControlFile->data_checksum_version = (mode == PG_MODE_ENABLE) ? PG_DATA_CHECKSUM_VERSION : 0; - printf(_("Syncing data directory\n")); - fsync_pgdata(DataDir, progname, PG_VERSION_NUM); + if (do_sync) + { + printf(_("Syncing data directory\n")); + fsync_pgdata(DataDir, progname, PG_VERSION_NUM); + } printf(_("Updating control file\n")); - update_controlfile(DataDir, progname, ControlFile, true); + update_controlfile(DataDir, progname, ControlFile, do_sync); if (verbose) printf(_("Data checksum version: %d\n"), ControlFile->data_checksum_version); diff --git a/src/bin/pg_checksums/t/002_actions.pl b/src/bin/pg_checksums/t/002_actions.pl index 3ab18a6b89..41575c5245 100644 --- a/src/bin/pg_checksums/t/002_actions.pl +++ b/src/bin/pg_checksums/t/002_actions.pl @@ -101,11 +101,11 @@ mkdir "$pgdata/global/pgsql_tmp"; append_to_file "$pgdata/global/pgsql_tmp/1.1", "foo"; # Enable checksums. -command_ok(['pg_checksums', '--enable', '-D', $pgdata], +command_ok(['pg_checksums', '--enable', '--no-sync', '-D', $pgdata], "checksums successfully enabled in cluster"); # Successive attempt to enable checksums fails. -command_fails(['pg_checksums', '--enable', '-D', $pgdata], +command_fails(['pg_checksums', '--enable', '--no-sync', '-D', $pgdata], "enabling checksums fails if already enabled"); # Control file should know that checksums are enabled. @@ -113,12 +113,12 @@ command_like(['pg_controldata', $pgdata], qr/Data page checksum version:.*1/, 'checksums enabled in control file'); -# Disable checksums again. +# Disable checksums again. Flush result here as that should be cheap. command_ok(['pg_checksums', '--disable', '-D', $pgdata], "checksums successfully disabled in cluster"); # Successive attempt to disable checksums fails. -command_fails(['pg_checksums', '--disable', '-D', $pgdata], +command_fails(['pg_checksums', '--disable', '--no-sync', '-D', $pgdata], "disabling checksums fails if already disabled"); # Control file should know that checksums are disabled. @@ -127,7 +127,7 @@ command_like(['pg_controldata', $pgdata], 'checksums disabled in control file'); # Enable checksums again for follow-up tests. -command_ok(['pg_checksums', '--enable', '-D', $pgdata], +command_ok(['pg_checksums', '--enable', '--no-sync', '-D', $pgdata], "checksums successfully enabled in cluster"); # Control file should know that checksums are enabled. -- 2.20.1
signature.asc
Description: PGP signature