]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Add MODE option to CHECKPOINT command.
authorNathan Bossart <nathan@postgresql.org>
Fri, 11 Jul 2025 16:51:25 +0000 (11:51 -0500)
committerNathan Bossart <nathan@postgresql.org>
Fri, 11 Jul 2025 16:51:25 +0000 (11:51 -0500)
This option may be set to FAST (the default) to request the
checkpoint be completed as fast as possible, or SPREAD to request
the checkpoint be spread over a longer interval (based on the
checkpoint-related configuration parameters).  Note that the server
may consolidate the options for concurrently requested checkpoints.
For example, if one session requests a "fast" checkpoint and
another requests a "spread" checkpoint, the server may perform one
"fast" checkpoint.

Author: Christoph Berg <myon@debian.org>
Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Fujii Masao <masao.fujii@oss.nttdata.com>
Reviewed-by: Laurenz Albe <laurenz.albe@cybertec.at>
Reviewed-by: Dilip Kumar <dilipbalaut@gmail.com>
Discussion: https://postgr.es/m/aDnaKTEf-0dLiEfz%40msg.df7cb.de

doc/src/sgml/ref/checkpoint.sgml
src/backend/postmaster/checkpointer.c
src/bin/psql/tab-complete.in.c
src/test/regress/expected/stats.out
src/test/regress/sql/stats.sql

index fad5e982d03643849ca05b9737cd8bde1421a571..36a9e323f448791b7724298269de7ad530f04a2e 100644 (file)
@@ -24,6 +24,8 @@ PostgreSQL documentation
 CHECKPOINT [ ( option [, ...] ) ]
 
 <phrase>where <replaceable class="parameter">option</replaceable> can be one of:</phrase>
+
+    MODE { FAST | SPREAD }
 </synopsis>
  </refsynopsisdiv>
 
@@ -39,14 +41,24 @@ CHECKPOINT [ ( option [, ...] ) ]
   </para>
 
   <para>
-   The <command>CHECKPOINT</command> command forces a fast
+   By default, the <command>CHECKPOINT</command> command forces a fast
    checkpoint when the command is issued, without waiting for a
    regular checkpoint scheduled by the system (controlled by the settings in
    <xref linkend="runtime-config-wal-checkpoints"/>).
+   To request the checkpoint be spread over a longer interval, set the
+   <literal>MODE</literal> option to <literal>SPREAD</literal>.
    <command>CHECKPOINT</command> is not intended for use during normal
    operation.
   </para>
 
+  <para>
+   The server may consolidate concurrently requested checkpoints.  Such
+   consolidated requests will contain a combined set of options.  For example,
+   if one session requests a fast checkpoint and another requests a spread
+   checkpoint, the server may combine those requests and perform one fast
+   checkpoint.
+  </para>
+
   <para>
    If executed during recovery, the <command>CHECKPOINT</command> command
    will force a restartpoint (see <xref linkend="wal-configuration"/>)
@@ -63,8 +75,25 @@ CHECKPOINT [ ( option [, ...] ) ]
  <refsect1>
   <title>Parameters</title>
 
-  <para>
-  </para>
+  <variablelist>
+   <varlistentry>
+    <term><literal>MODE</literal></term>
+    <listitem>
+     <para>
+      When set to <literal>FAST</literal>, which is the default, the requested
+      checkpoint will be completed as fast as possible, which may result in a
+      significantly higher rate of I/O during the checkpoint.
+     </para>
+     <para>
+      <literal>MODE</literal> can also be set to <literal>SPREAD</literal> to
+      request the checkpoint be spread over a longer interval (controlled via
+      the settings in <xref linkend="runtime-config-wal-checkpoints"/>), like a
+      regular checkpoint scheduled by the system.  This can reduce the rate of
+      I/O during the checkpoint.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
  </refsect1>
 
  <refsect1>
index dc01f2382f18af43c116355d2412942fbadb66c8..9d77269a3744cfb2e9ee6206d2764956b157ff05 100644 (file)
@@ -43,6 +43,7 @@
 #include "access/xlog_internal.h"
 #include "access/xlogrecovery.h"
 #include "catalog/pg_authid.h"
+#include "commands/defrem.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "pgstat.h"
@@ -987,11 +988,28 @@ CheckpointerShmemInit(void)
 void
 ExecCheckpoint(ParseState *pstate, CheckPointStmt *stmt)
 {
+       bool            fast = true;
+
        foreach_ptr(DefElem, opt, stmt->options)
-               ereport(ERROR,
-                               (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("unrecognized CHECKPOINT option \"%s\"", opt->defname),
-                                parser_errposition(pstate, opt->location)));
+       {
+               if (strcmp(opt->defname, "mode") == 0)
+               {
+                       char       *mode = defGetString(opt);
+
+                       if (strcmp(mode, "spread") == 0)
+                               fast = false;
+                       else if (strcmp(mode, "fast") != 0)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_SYNTAX_ERROR),
+                                                errmsg("unrecognized MODE option \"%s\"", mode),
+                                                parser_errposition(pstate, opt->location)));
+               }
+               else
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_SYNTAX_ERROR),
+                                        errmsg("unrecognized CHECKPOINT option \"%s\"", opt->defname),
+                                        parser_errposition(pstate, opt->location)));
+       }
 
        if (!has_privs_of_role(GetUserId(), ROLE_PG_CHECKPOINT))
                ereport(ERROR,
@@ -1003,7 +1021,7 @@ ExecCheckpoint(ParseState *pstate, CheckPointStmt *stmt)
                                                   "pg_checkpoint")));
 
        RequestCheckpoint(CHECKPOINT_WAIT |
-                                         CHECKPOINT_FAST |
+                                         (fast ? CHECKPOINT_FAST : 0) |
                                          (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
 }
 
index 089fe367d9f3bc15acb05480aa1ed624840349e9..a7db04efd93e476dc1c2faa85833bdffc10eaa4e 100644 (file)
@@ -3156,6 +3156,19 @@ match_previous_words(int pattern_id,
 /* CHECKPOINT */
        else if (Matches("CHECKPOINT"))
                COMPLETE_WITH("(");
+       else if (HeadMatches("CHECKPOINT", "(*") &&
+                        !HeadMatches("CHECKPOINT", "(*)"))
+       {
+               /*
+                * This fires if we're in an unfinished parenthesized option list.
+                * get_previous_words treats a completed parenthesized option list as
+                * one word, so the above test is correct.
+                */
+               if (ends_with(prev_wd, '(') || ends_with(prev_wd, ','))
+                       COMPLETE_WITH("MODE");
+               else if (TailMatches("MODE"))
+                       COMPLETE_WITH("FAST", "SPREAD");
+       }
 /* CLOSE */
        else if (Matches("CLOSE"))
                COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_cursors,
index 9b865ae5f6cc7c2ca0014d1d67be5a43832dd73a..b4df9ad596007028812e2b5a3b6d6b219add60f2 100644 (file)
@@ -927,12 +927,17 @@ DROP TABLE test_stats_temp;
 -- of the checkpoint. But after a second checkpoint we'll see at least the
 -- results of the first.
 --
--- While at it, test checkpoint options.
+-- While at it, test checkpoint options.  Note that we don't test MODE SPREAD
+-- because it would prolong the test.
 CHECKPOINT (WRONG);
 ERROR:  unrecognized CHECKPOINT option "wrong"
 LINE 1: CHECKPOINT (WRONG);
                     ^
-CHECKPOINT;
+CHECKPOINT (MODE WRONG);
+ERROR:  unrecognized MODE option "wrong"
+LINE 1: CHECKPOINT (MODE WRONG);
+                    ^
+CHECKPOINT (MODE FAST);
 CHECKPOINT;
 SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
index 97b50926aa67c45638edc388861e7b50074ff9b9..0868b250a649a11878149ab498324da33f0eb8cf 100644 (file)
@@ -440,9 +440,11 @@ DROP TABLE test_stats_temp;
 -- of the checkpoint. But after a second checkpoint we'll see at least the
 -- results of the first.
 --
--- While at it, test checkpoint options.
+-- While at it, test checkpoint options.  Note that we don't test MODE SPREAD
+-- because it would prolong the test.
 CHECKPOINT (WRONG);
-CHECKPOINT;
+CHECKPOINT (MODE WRONG);
+CHECKPOINT (MODE FAST);
 CHECKPOINT;
 
 SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;