Thanks all for the feedback.  Here is an updated patch set.

-- 
nathan
>From d862592acfb6470e34da9e993ff942c48cbf4e2f Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nat...@postgresql.org>
Date: Wed, 9 Jul 2025 10:05:10 -0500
Subject: [PATCH v9 1/5] Rename CHECKPOINT_FLUSH_ALL to
 CHECKPOINT_FLUSH_UNLOGGED.

The new name more accurately indicates the effects of this flag on
a requested checkpoint.  Checkpoint-related log messages (i.e.,
those controlled by the log_checkpoints configuration parameter)
will now say "flush-unlogged" instead of "flush-all", too.  This is
preparatory work for a follow-up commit that will add a
FLUSH_UNLOGGED option to the CHECKPOINT command.

Author: Christoph Berg <m...@debian.org>
Discussion: https://postgr.es/m/aDnaKTEf-0dLiEfz%40msg.df7cb.de
---
 src/backend/access/transam/xlog.c   | 6 +++---
 src/backend/commands/dbcommands.c   | 4 ++--
 src/backend/storage/buffer/bufmgr.c | 6 +++---
 src/include/access/xlog.h           | 3 +--
 4 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/src/backend/access/transam/xlog.c 
b/src/backend/access/transam/xlog.c
index a8cc6402d62..329519e95f0 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6847,7 +6847,7 @@ LogCheckpointStart(int flags, bool restartpoint)
                                                (flags & CHECKPOINT_WAIT) ? " 
wait" : "",
                                                (flags & CHECKPOINT_CAUSE_XLOG) 
? " wal" : "",
                                                (flags & CHECKPOINT_CAUSE_TIME) 
? " time" : "",
-                                               (flags & CHECKPOINT_FLUSH_ALL) 
? " flush-all" : "")));
+                                               (flags & 
CHECKPOINT_FLUSH_UNLOGGED) ? " flush-unlogged" : "")));
        else
                ereport(LOG,
                /* translator: the placeholders show checkpoint options */
@@ -6859,7 +6859,7 @@ LogCheckpointStart(int flags, bool restartpoint)
                                                (flags & CHECKPOINT_WAIT) ? " 
wait" : "",
                                                (flags & CHECKPOINT_CAUSE_XLOG) 
? " wal" : "",
                                                (flags & CHECKPOINT_CAUSE_TIME) 
? " time" : "",
-                                               (flags & CHECKPOINT_FLUSH_ALL) 
? " flush-all" : "")));
+                                               (flags & 
CHECKPOINT_FLUSH_UNLOGGED) ? " flush-unlogged" : "")));
 }
 
 /*
@@ -7047,7 +7047,7 @@ update_checkpoint_display(int flags, bool restartpoint, 
bool reset)
  *     CHECKPOINT_FORCE: force a checkpoint even if no XLOG activity has 
occurred
  *             since the last one (implied by CHECKPOINT_IS_SHUTDOWN or
  *             CHECKPOINT_END_OF_RECOVERY).
- *     CHECKPOINT_FLUSH_ALL: also flush buffers of unlogged tables.
+ *     CHECKPOINT_FLUSH_UNLOGGED: also flush buffers of unlogged tables.
  *
  * Note: flags contains other bits, of interest here only for logging purposes.
  * In particular note that this routine is synchronous and does not pay
diff --git a/src/backend/commands/dbcommands.c 
b/src/backend/commands/dbcommands.c
index c95eb945016..2d32ffd02c7 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -571,7 +571,7 @@ CreateDatabaseUsingFileCopy(Oid src_dboid, Oid dst_dboid, 
Oid src_tsid,
         */
        if (!IsBinaryUpgrade)
                RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE |
-                                                 CHECKPOINT_WAIT | 
CHECKPOINT_FLUSH_ALL);
+                                                 CHECKPOINT_WAIT | 
CHECKPOINT_FLUSH_UNLOGGED);
 
        /*
         * Iterate through all tablespaces of the template database, and copy 
each
@@ -2121,7 +2121,7 @@ movedb(const char *dbname, const char *tblspcname)
         * files, which would cause rmdir() to fail.
         */
        RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | 
CHECKPOINT_WAIT
-                                         | CHECKPOINT_FLUSH_ALL);
+                                         | CHECKPOINT_FLUSH_UNLOGGED);
 
        /* Close all smgr fds in all backends. */
        
WaitForProcSignalBarrier(EmitProcSignalBarrier(PROCSIGNAL_BARRIER_SMGRRELEASE));
diff --git a/src/backend/storage/buffer/bufmgr.c 
b/src/backend/storage/buffer/bufmgr.c
index bd68d7e0ca9..0b4b23e02a2 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -3341,8 +3341,8 @@ UnpinBufferNoOwner(BufferDesc *buf)
  * This is called at checkpoint time to write out all dirty shared buffers.
  * The checkpoint request flags should be passed in.  If CHECKPOINT_IMMEDIATE
  * is set, we disable delays between writes; if CHECKPOINT_IS_SHUTDOWN,
- * CHECKPOINT_END_OF_RECOVERY or CHECKPOINT_FLUSH_ALL is set, we write even
- * unlogged buffers, which are otherwise skipped.  The remaining flags
+ * CHECKPOINT_END_OF_RECOVERY or CHECKPOINT_FLUSH_UNLOGGED is set, we write
+ * even unlogged buffers, which are otherwise skipped.  The remaining flags
  * currently have no effect here.
  */
 static void
@@ -3367,7 +3367,7 @@ BufferSync(int flags)
         * recovery, we write all dirty buffers.
         */
        if (!((flags & (CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_END_OF_RECOVERY |
-                                       CHECKPOINT_FLUSH_ALL))))
+                                       CHECKPOINT_FLUSH_UNLOGGED))))
                mask |= BM_PERMANENT;
 
        /*
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index d313099c027..80c42b5f80f 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -141,8 +141,7 @@ extern PGDLLIMPORT bool XLOG_DEBUG;
                                                                                
         * issued at end of WAL recovery */
 #define CHECKPOINT_IMMEDIATE   0x0004  /* Do it without delays */
 #define CHECKPOINT_FORCE               0x0008  /* Force even if no activity */
-#define CHECKPOINT_FLUSH_ALL   0x0010  /* Flush all pages, including those
-                                                                               
 * belonging to unlogged tables */
+#define CHECKPOINT_FLUSH_UNLOGGED      0x0010  /* Flush unlogged tables */
 /* These are important to RequestCheckpoint */
 #define CHECKPOINT_WAIT                        0x0020  /* Wait for completion 
*/
 #define CHECKPOINT_REQUESTED   0x0040  /* Checkpoint request has been made */
-- 
2.39.5 (Apple Git-154)

>From 85a80fe3daac63f6d3bc0014c6aed9a154815253 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nat...@postgresql.org>
Date: Wed, 9 Jul 2025 11:23:57 -0500
Subject: [PATCH v9 2/5] Rename CHECKPOINT_IMMEDIATE to CHECKPOINT_FAST.

The new name more accurately indicates the effects of this flag on
a requested checkpoint.  Checkpoint-related log messages (i.e.,
those controlled by the log_checkpoints configuration parameter)
will now say "fast" instead of "immediate", too.  And references to
"immediate" checkpoints in the documentation have been updated to
say "fast" instead.  This is preparatory work for a follow-up
commit that will add a MODE option to the CHECKPOINT command.

Author: Christoph Berg <m...@debian.org>
Discussion: https://postgr.es/m/aDnaKTEf-0dLiEfz%40msg.df7cb.de
---
 doc/src/sgml/backup.sgml                      |  2 +-
 doc/src/sgml/func.sgml                        |  2 +-
 doc/src/sgml/ref/checkpoint.sgml              |  2 +-
 doc/src/sgml/ref/pg_basebackup.sgml           |  3 ++-
 src/backend/access/transam/xlog.c             | 25 +++++++++----------
 src/backend/commands/dbcommands.c             | 10 ++++----
 src/backend/commands/tablespace.c             |  2 +-
 src/backend/postmaster/checkpointer.c         | 24 +++++++++---------
 src/backend/storage/buffer/bufmgr.c           |  4 +--
 src/backend/tcop/utility.c                    |  2 +-
 src/include/access/xlog.h                     |  2 +-
 .../recovery/t/041_checkpoint_at_promote.pl   |  2 +-
 12 files changed, 40 insertions(+), 40 deletions(-)

diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 25b8904baf7..5f7489afbd1 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -991,7 +991,7 @@ SELECT pg_backup_start(label => 'label', fast => false);
      usually preferable as it minimizes the impact on the running system.  If 
you
      want to start the backup as soon as possible, pass 
<literal>true</literal> as
      the second parameter to <function>pg_backup_start</function> and it will
-     request an immediate checkpoint, which will finish as fast as possible 
using
+     request a fast checkpoint, which will finish as fast as possible using
      as much I/O as possible.
     </para>
 
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index c28aa71f570..6b327d4fd81 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -28973,7 +28973,7 @@ LOG:  Grand total: 1651920 bytes in 201 blocks; 622360 
free (88 chunks); 1029560
         will be stored.)
         If the optional second parameter is given as <literal>true</literal>,
         it specifies executing <function>pg_backup_start</function> as quickly
-        as possible.  This forces an immediate checkpoint which will cause a
+        as possible.  This forces a fast checkpoint which will cause a
         spike in I/O operations, slowing any concurrently executing queries.
        </para>
        <para>
diff --git a/doc/src/sgml/ref/checkpoint.sgml b/doc/src/sgml/ref/checkpoint.sgml
index db011a47d04..10a433e4757 100644
--- a/doc/src/sgml/ref/checkpoint.sgml
+++ b/doc/src/sgml/ref/checkpoint.sgml
@@ -37,7 +37,7 @@ CHECKPOINT
   </para>
 
   <para>
-   The <command>CHECKPOINT</command> command forces an immediate
+   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"/>).
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml 
b/doc/src/sgml/ref/pg_basebackup.sgml
index 9659f76042c..fecee08b0a5 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -500,8 +500,9 @@ PostgreSQL documentation
       <term><option>--checkpoint={fast|spread}</option></term>
       <listitem>
        <para>
-        Sets checkpoint mode to fast (immediate) or spread (the default)
+        Sets checkpoint mode to fast or spread
         (see <xref linkend="backup-lowlevel-base-backup"/>).
+        The default is spread.
        </para>
       </listitem>
      </varlistentry>
diff --git a/src/backend/access/transam/xlog.c 
b/src/backend/access/transam/xlog.c
index 329519e95f0..add4e9e9364 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6505,7 +6505,7 @@ PerformRecoveryXLogAction(void)
        else
        {
                RequestCheckpoint(CHECKPOINT_END_OF_RECOVERY |
-                                                 CHECKPOINT_IMMEDIATE |
+                                                 CHECKPOINT_FAST |
                                                  CHECKPOINT_WAIT);
        }
 
@@ -6814,7 +6814,7 @@ ShutdownXLOG(int code, Datum arg)
        WalSndWaitStopping();
 
        if (RecoveryInProgress())
-               CreateRestartPoint(CHECKPOINT_IS_SHUTDOWN | 
CHECKPOINT_IMMEDIATE);
+               CreateRestartPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_FAST);
        else
        {
                /*
@@ -6826,7 +6826,7 @@ ShutdownXLOG(int code, Datum arg)
                if (XLogArchivingActive())
                        RequestXLogSwitch(false);
 
-               CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);
+               CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_FAST);
        }
 }
 
@@ -6842,7 +6842,7 @@ LogCheckpointStart(int flags, bool restartpoint)
                                (errmsg("restartpoint 
starting:%s%s%s%s%s%s%s%s",
                                                (flags & 
CHECKPOINT_IS_SHUTDOWN) ? " shutdown" : "",
                                                (flags & 
CHECKPOINT_END_OF_RECOVERY) ? " end-of-recovery" : "",
-                                               (flags & CHECKPOINT_IMMEDIATE) 
? " immediate" : "",
+                                               (flags & CHECKPOINT_FAST) ? " 
fast" : "",
                                                (flags & CHECKPOINT_FORCE) ? " 
force" : "",
                                                (flags & CHECKPOINT_WAIT) ? " 
wait" : "",
                                                (flags & CHECKPOINT_CAUSE_XLOG) 
? " wal" : "",
@@ -6854,7 +6854,7 @@ LogCheckpointStart(int flags, bool restartpoint)
                                (errmsg("checkpoint starting:%s%s%s%s%s%s%s%s",
                                                (flags & 
CHECKPOINT_IS_SHUTDOWN) ? " shutdown" : "",
                                                (flags & 
CHECKPOINT_END_OF_RECOVERY) ? " end-of-recovery" : "",
-                                               (flags & CHECKPOINT_IMMEDIATE) 
? " immediate" : "",
+                                               (flags & CHECKPOINT_FAST) ? " 
fast" : "",
                                                (flags & CHECKPOINT_FORCE) ? " 
force" : "",
                                                (flags & CHECKPOINT_WAIT) ? " 
wait" : "",
                                                (flags & CHECKPOINT_CAUSE_XLOG) 
? " wal" : "",
@@ -7042,8 +7042,8 @@ update_checkpoint_display(int flags, bool restartpoint, 
bool reset)
  * flags is a bitwise OR of the following:
  *     CHECKPOINT_IS_SHUTDOWN: checkpoint is for database shutdown.
  *     CHECKPOINT_END_OF_RECOVERY: checkpoint is for end of WAL recovery.
- *     CHECKPOINT_IMMEDIATE: finish the checkpoint ASAP,
- *             ignoring checkpoint_completion_target parameter.
+ *     CHECKPOINT_FAST: finish the checkpoint ASAP, ignoring
+ *             checkpoint_completion_target parameter.
  *     CHECKPOINT_FORCE: force a checkpoint even if no XLOG activity has 
occurred
  *             since the last one (implied by CHECKPOINT_IS_SHUTDOWN or
  *             CHECKPOINT_END_OF_RECOVERY).
@@ -8946,9 +8946,8 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
  * backup state and tablespace map.
  *
  * Input parameters are "state" (the backup state), "fast" (if true, we do
- * the checkpoint in immediate mode to make it faster), and "tablespaces"
- * (if non-NULL, indicates a list of tablespaceinfo structs describing the
- * cluster's tablespaces.).
+ * the checkpoint in fast mode), and "tablespaces" (if non-NULL, indicates a
+ * list of tablespaceinfo structs describing the cluster's tablespaces.).
  *
  * The tablespace map contents are appended to passed-in parameter
  * tablespace_map and the caller is responsible for including it in the backup
@@ -9076,11 +9075,11 @@ do_pg_backup_start(const char *backupidstr, bool fast, 
List **tablespaces,
                         * during recovery means that checkpointer is running, 
we can use
                         * RequestCheckpoint() to establish a restartpoint.
                         *
-                        * We use CHECKPOINT_IMMEDIATE only if requested by 
user (via
-                        * passing fast = true).  Otherwise this can take 
awhile.
+                        * We use CHECKPOINT_FAST only if requested by user 
(via passing
+                        * fast = true).  Otherwise this can take awhile.
                         */
                        RequestCheckpoint(CHECKPOINT_FORCE | CHECKPOINT_WAIT |
-                                                         (fast ? 
CHECKPOINT_IMMEDIATE : 0));
+                                                         (fast ? 
CHECKPOINT_FAST : 0));
 
                        /*
                         * Now we need to fetch the checkpoint record location, 
and also
diff --git a/src/backend/commands/dbcommands.c 
b/src/backend/commands/dbcommands.c
index 2d32ffd02c7..502a45163c8 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -570,7 +570,7 @@ CreateDatabaseUsingFileCopy(Oid src_dboid, Oid dst_dboid, 
Oid src_tsid,
         * any CREATE DATABASE commands.
         */
        if (!IsBinaryUpgrade)
-               RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE |
+               RequestCheckpoint(CHECKPOINT_FAST | CHECKPOINT_FORCE |
                                                  CHECKPOINT_WAIT | 
CHECKPOINT_FLUSH_UNLOGGED);
 
        /*
@@ -673,7 +673,7 @@ CreateDatabaseUsingFileCopy(Oid src_dboid, Oid dst_dboid, 
Oid src_tsid,
         * strategy that avoids these problems.
         */
        if (!IsBinaryUpgrade)
-               RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE |
+               RequestCheckpoint(CHECKPOINT_FAST | CHECKPOINT_FORCE |
                                                  CHECKPOINT_WAIT);
 }
 
@@ -1870,7 +1870,7 @@ dropdb(const char *dbname, bool missing_ok, bool force)
         * Force a checkpoint to make sure the checkpointer has received the
         * message sent by ForgetDatabaseSyncRequests.
         */
-       RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | 
CHECKPOINT_WAIT);
+       RequestCheckpoint(CHECKPOINT_FAST | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
 
        /* Close all smgr fds in all backends. */
        
WaitForProcSignalBarrier(EmitProcSignalBarrier(PROCSIGNAL_BARRIER_SMGRRELEASE));
@@ -2120,7 +2120,7 @@ movedb(const char *dbname, const char *tblspcname)
         * On Windows, this also ensures that background procs don't hold any 
open
         * files, which would cause rmdir() to fail.
         */
-       RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | 
CHECKPOINT_WAIT
+       RequestCheckpoint(CHECKPOINT_FAST | CHECKPOINT_FORCE | CHECKPOINT_WAIT
                                          | CHECKPOINT_FLUSH_UNLOGGED);
 
        /* Close all smgr fds in all backends. */
@@ -2252,7 +2252,7 @@ movedb(const char *dbname, const char *tblspcname)
                 * any unlogged operations done in the new DB tablespace before 
the
                 * next checkpoint.
                 */
-               RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | 
CHECKPOINT_WAIT);
+               RequestCheckpoint(CHECKPOINT_FAST | CHECKPOINT_FORCE | 
CHECKPOINT_WAIT);
 
                /*
                 * Force synchronous commit, thus minimizing the window between
diff --git a/src/backend/commands/tablespace.c 
b/src/backend/commands/tablespace.c
index a9005cc7212..df31eace47a 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -500,7 +500,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
                 * mustn't delete.  So instead, we force a checkpoint which 
will clean
                 * out any lingering files, and try again.
                 */
-               RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | 
CHECKPOINT_WAIT);
+               RequestCheckpoint(CHECKPOINT_FAST | CHECKPOINT_FORCE | 
CHECKPOINT_WAIT);
 
                /*
                 * On Windows, an unlinked file persists in the directory 
listing
diff --git a/src/backend/postmaster/checkpointer.c 
b/src/backend/postmaster/checkpointer.c
index fda91ffd1ce..0d8696bfb5e 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -161,7 +161,7 @@ static pg_time_t last_xlog_switch_time;
 static void ProcessCheckpointerInterrupts(void);
 static void CheckArchiveTimeout(void);
 static bool IsCheckpointOnSchedule(double progress);
-static bool ImmediateCheckpointRequested(void);
+static bool FastCheckpointRequested(void);
 static bool CompactCheckpointerRequestQueue(void);
 static void UpdateSharedMemoryConfig(void);
 
@@ -734,12 +734,12 @@ CheckArchiveTimeout(void)
 }
 
 /*
- * Returns true if an immediate checkpoint request is pending.  (Note that
- * this does not check the *current* checkpoint's IMMEDIATE flag, but whether
- * there is one pending behind it.)
+ * Returns true if a fast checkpoint request is pending.  (Note that this does
+ * not check the *current* checkpoint's FAST flag, but whether there is one
+ * pending behind it.)
  */
 static bool
-ImmediateCheckpointRequested(void)
+FastCheckpointRequested(void)
 {
        volatile CheckpointerShmemStruct *cps = CheckpointerShmem;
 
@@ -747,7 +747,7 @@ ImmediateCheckpointRequested(void)
         * We don't need to acquire the ckpt_lck in this case because we're only
         * looking at a single flag bit.
         */
-       if (cps->ckpt_flags & CHECKPOINT_IMMEDIATE)
+       if (cps->ckpt_flags & CHECKPOINT_FAST)
                return true;
        return false;
 }
@@ -760,7 +760,7 @@ ImmediateCheckpointRequested(void)
  * checkpoint_completion_target.
  *
  * The checkpoint request flags should be passed in; currently the only one
- * examined is CHECKPOINT_IMMEDIATE, which disables delays between writes.
+ * examined is CHECKPOINT_FAST, which disables delays between writes.
  *
  * 'progress' is an estimate of how much of the work has been done, as a
  * fraction between 0.0 meaning none, and 1.0 meaning all done.
@@ -778,10 +778,10 @@ CheckpointWriteDelay(int flags, double progress)
         * Perform the usual duties and take a nap, unless we're behind 
schedule,
         * in which case we just try to catch up as quickly as possible.
         */
-       if (!(flags & CHECKPOINT_IMMEDIATE) &&
+       if (!(flags & CHECKPOINT_FAST) &&
                !ShutdownXLOGPending &&
                !ShutdownRequestPending &&
-               !ImmediateCheckpointRequested() &&
+               !FastCheckpointRequested() &&
                IsCheckpointOnSchedule(progress))
        {
                if (ConfigReloadPending)
@@ -983,11 +983,11 @@ CheckpointerShmemInit(void)
  * flags is a bitwise OR of the following:
  *     CHECKPOINT_IS_SHUTDOWN: checkpoint is for database shutdown.
  *     CHECKPOINT_END_OF_RECOVERY: checkpoint is for end of WAL recovery.
- *     CHECKPOINT_IMMEDIATE: finish the checkpoint ASAP,
+ *     CHECKPOINT_FAST: finish the checkpoint ASAP,
  *             ignoring checkpoint_completion_target parameter.
  *     CHECKPOINT_FORCE: force a checkpoint even if no XLOG activity has 
occurred
  *             since the last one (implied by CHECKPOINT_IS_SHUTDOWN or
- *             CHECKPOINT_END_OF_RECOVERY).
+ *             CHECKPOINT_END_OF_RECOVERY, and the CHECKPOINT command).
  *     CHECKPOINT_WAIT: wait for completion before returning (otherwise,
  *             just signal checkpointer to do it, and return).
  *     CHECKPOINT_CAUSE_XLOG: checkpoint is requested due to xlog filling.
@@ -1009,7 +1009,7 @@ RequestCheckpoint(int flags)
                 * There's no point in doing slow checkpoints in a standalone 
backend,
                 * because there's no other backends the checkpoint could 
disrupt.
                 */
-               CreateCheckPoint(flags | CHECKPOINT_IMMEDIATE);
+               CreateCheckPoint(flags | CHECKPOINT_FAST);
 
                /* Free all smgr objects, as CheckpointerMain() normally would. 
*/
                smgrdestroyall();
diff --git a/src/backend/storage/buffer/bufmgr.c 
b/src/backend/storage/buffer/bufmgr.c
index 0b4b23e02a2..6afdd28dba6 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -3339,8 +3339,8 @@ UnpinBufferNoOwner(BufferDesc *buf)
  * BufferSync -- Write out all dirty buffers in the pool.
  *
  * This is called at checkpoint time to write out all dirty shared buffers.
- * The checkpoint request flags should be passed in.  If CHECKPOINT_IMMEDIATE
- * is set, we disable delays between writes; if CHECKPOINT_IS_SHUTDOWN,
+ * The checkpoint request flags should be passed in.  If CHECKPOINT_FAST is
+ * set, we disable delays between writes; if CHECKPOINT_IS_SHUTDOWN,
  * CHECKPOINT_END_OF_RECOVERY or CHECKPOINT_FLUSH_UNLOGGED is set, we write
  * even unlogged buffers, which are otherwise skipped.  The remaining flags
  * currently have no effect here.
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index aff8510755f..a628da4b145 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -952,7 +952,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                                 errdetail("Only roles with 
privileges of the \"%s\" role may execute this command.",
                                                                   
"pg_checkpoint")));
 
-                       RequestCheckpoint(CHECKPOINT_IMMEDIATE | 
CHECKPOINT_WAIT |
+                       RequestCheckpoint(CHECKPOINT_FAST | CHECKPOINT_WAIT |
                                                          (RecoveryInProgress() 
? 0 : CHECKPOINT_FORCE));
                        break;
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 80c42b5f80f..d12798be3d8 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -139,7 +139,7 @@ extern PGDLLIMPORT bool XLOG_DEBUG;
 #define CHECKPOINT_IS_SHUTDOWN 0x0001  /* Checkpoint is for shutdown */
 #define CHECKPOINT_END_OF_RECOVERY     0x0002  /* Like shutdown checkpoint, but
                                                                                
         * issued at end of WAL recovery */
-#define CHECKPOINT_IMMEDIATE   0x0004  /* Do it without delays */
+#define CHECKPOINT_FAST                        0x0004  /* Do it without delays 
*/
 #define CHECKPOINT_FORCE               0x0008  /* Force even if no activity */
 #define CHECKPOINT_FLUSH_UNLOGGED      0x0010  /* Flush unlogged tables */
 /* These are important to RequestCheckpoint */
diff --git a/src/test/recovery/t/041_checkpoint_at_promote.pl 
b/src/test/recovery/t/041_checkpoint_at_promote.pl
index cb63ac8d5c9..12750ff7d4f 100644
--- a/src/test/recovery/t/041_checkpoint_at_promote.pl
+++ b/src/test/recovery/t/041_checkpoint_at_promote.pl
@@ -91,7 +91,7 @@ $node_standby->wait_for_event('checkpointer', 
'create-restart-point');
 # Check the logs that the restart point has started on standby.  This is
 # optional, but let's be sure.
 ok( $node_standby->log_contains(
-               "restartpoint starting: immediate wait", $logstart),
+               "restartpoint starting: fast wait", $logstart),
        "restartpoint has started");
 
 # Trigger promotion during the restart point.
-- 
2.39.5 (Apple Git-154)

>From ea9662ffbef53e0d26b49065630eea02db3707ba Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nat...@postgresql.org>
Date: Wed, 9 Jul 2025 13:13:01 -0500
Subject: [PATCH v9 3/5] Add option list to CHECKPOINT command.

This commit adds the boilerplate code for supporting a list of
options in CHECKPOINT commands.  No actual options are supported
yet, but follow-up commits will add support for MODE and
FLUSH_UNLOGGED.  While at it, this commit refactors the code for
executing CHECKPOINT commands to its own function since it's about
to become significantly longer.

Author: Christoph Berg <m...@debian.org>
Reviewed-by: Fujii Masao <masao.fu...@oss.nttdata.com>
Discussion: https://postgr.es/m/aDnaKTEf-0dLiEfz%40msg.df7cb.de
---
 doc/src/sgml/ref/checkpoint.sgml      | 11 +++++++++-
 src/backend/parser/gram.y             |  7 ++++++
 src/backend/postmaster/checkpointer.c | 31 +++++++++++++++++++++++++++
 src/backend/tcop/utility.c            | 12 +----------
 src/bin/psql/tab-complete.in.c        |  3 +++
 src/include/nodes/parsenodes.h        |  1 +
 src/include/postmaster/bgwriter.h     |  2 ++
 src/test/regress/expected/stats.out   |  6 ++++++
 src/test/regress/sql/stats.sql        |  3 +++
 9 files changed, 64 insertions(+), 12 deletions(-)

diff --git a/doc/src/sgml/ref/checkpoint.sgml b/doc/src/sgml/ref/checkpoint.sgml
index 10a433e4757..fad5e982d03 100644
--- a/doc/src/sgml/ref/checkpoint.sgml
+++ b/doc/src/sgml/ref/checkpoint.sgml
@@ -21,7 +21,9 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CHECKPOINT
+CHECKPOINT [ ( option [, ...] ) ]
+
+<phrase>where <replaceable class="parameter">option</replaceable> can be one 
of:</phrase>
 </synopsis>
  </refsynopsisdiv>
 
@@ -58,6 +60,13 @@ CHECKPOINT
   </para>
  </refsect1>
 
+ <refsect1>
+  <title>Parameters</title>
+
+  <para>
+  </para>
+ </refsect1>
+
  <refsect1>
   <title>Compatibility</title>
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 70a0d832a11..73345bb3c70 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -2034,6 +2034,13 @@ CheckPointStmt:
 
                                        $$ = (Node *) n;
                                }
+                       | CHECKPOINT '(' utility_option_list ')'
+                               {
+                                       CheckPointStmt *n = 
makeNode(CheckPointStmt);
+
+                                       $$ = (Node *) n;
+                                       n->options = $3;
+                               }
                ;
 
 
diff --git a/src/backend/postmaster/checkpointer.c 
b/src/backend/postmaster/checkpointer.c
index 0d8696bfb5e..dc01f2382f1 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -42,6 +42,7 @@
 #include "access/xlog.h"
 #include "access/xlog_internal.h"
 #include "access/xlogrecovery.h"
+#include "catalog/pg_authid.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "pgstat.h"
@@ -61,6 +62,7 @@
 #include "storage/shmem.h"
 #include "storage/smgr.h"
 #include "storage/spin.h"
+#include "utils/acl.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
 #include "utils/resowner.h"
@@ -976,6 +978,35 @@ CheckpointerShmemInit(void)
        }
 }
 
+/*
+ * ExecCheckpoint
+ *             Primary entry point for manual CHECKPOINT commands
+ *
+ * This is mainly a wrapper for RequestCheckpoint().
+ */
+void
+ExecCheckpoint(ParseState *pstate, CheckPointStmt *stmt)
+{
+       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 (!has_privs_of_role(GetUserId(), ROLE_PG_CHECKPOINT))
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+               /* translator: %s is name of an SQL command (e.g., CHECKPOINT) 
*/
+                                errmsg("permission denied to execute %s 
command",
+                                               "CHECKPOINT"),
+                                errdetail("Only roles with privileges of the 
\"%s\" role may execute this command.",
+                                                  "pg_checkpoint")));
+
+       RequestCheckpoint(CHECKPOINT_WAIT |
+                                         CHECKPOINT_FAST |
+                                         (RecoveryInProgress() ? 0 : 
CHECKPOINT_FORCE));
+}
+
 /*
  * RequestCheckpoint
  *             Called in backend processes to request a checkpoint
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index a628da4b145..4c1faf5575c 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -943,17 +943,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                        break;
 
                case T_CheckPointStmt:
-                       if (!has_privs_of_role(GetUserId(), ROLE_PG_CHECKPOINT))
-                               ereport(ERROR,
-                                               
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                               /* translator: %s is name of a SQL command, eg 
CHECKPOINT */
-                                                errmsg("permission denied to 
execute %s command",
-                                                               "CHECKPOINT"),
-                                                errdetail("Only roles with 
privileges of the \"%s\" role may execute this command.",
-                                                                  
"pg_checkpoint")));
-
-                       RequestCheckpoint(CHECKPOINT_FAST | CHECKPOINT_WAIT |
-                                                         (RecoveryInProgress() 
? 0 : CHECKPOINT_FORCE));
+                       ExecCheckpoint(pstate, (CheckPointStmt *) parsetree);
                        break;
 
                        /*
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 5ba45a0bcb3..089fe367d9f 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -3153,6 +3153,9 @@ match_previous_words(int pattern_id,
                
COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(Query_for_list_of_procedures);
        else if (Matches("CALL", MatchAny))
                COMPLETE_WITH("(");
+/* CHECKPOINT */
+       else if (Matches("CHECKPOINT"))
+               COMPLETE_WITH("(");
 /* CLOSE */
        else if (Matches("CLOSE"))
                COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_cursors,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 28e2e8dc0fd..86a236bd58b 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -4047,6 +4047,7 @@ typedef struct RefreshMatViewStmt
 typedef struct CheckPointStmt
 {
        NodeTag         type;
+       List       *options;            /* list of DefElem nodes */
 } CheckPointStmt;
 
 /* ----------------------
diff --git a/src/include/postmaster/bgwriter.h 
b/src/include/postmaster/bgwriter.h
index 800ecbfd13b..97001f4e7f6 100644
--- a/src/include/postmaster/bgwriter.h
+++ b/src/include/postmaster/bgwriter.h
@@ -15,6 +15,7 @@
 #ifndef _BGWRITER_H
 #define _BGWRITER_H
 
+#include "parser/parse_node.h"
 #include "storage/block.h"
 #include "storage/relfilelocator.h"
 #include "storage/smgr.h"
@@ -30,6 +31,7 @@ extern PGDLLIMPORT double CheckPointCompletionTarget;
 pg_noreturn extern void BackgroundWriterMain(const void *startup_data, size_t 
startup_data_len);
 pg_noreturn extern void CheckpointerMain(const void *startup_data, size_t 
startup_data_len);
 
+extern void ExecCheckpoint(ParseState *pstate, CheckPointStmt *stmt);
 extern void RequestCheckpoint(int flags);
 extern void CheckpointWriteDelay(int flags, double progress);
 
diff --git a/src/test/regress/expected/stats.out 
b/src/test/regress/expected/stats.out
index 776f1ad0e53..9b865ae5f6c 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -926,6 +926,12 @@ DROP TABLE test_stats_temp;
 -- Checkpoint twice: The checkpointer reports stats after reporting completion
 -- of the checkpoint. But after a second checkpoint we'll see at least the
 -- results of the first.
+--
+-- While at it, test checkpoint options.
+CHECKPOINT (WRONG);
+ERROR:  unrecognized CHECKPOINT option "wrong"
+LINE 1: CHECKPOINT (WRONG);
+                    ^
 CHECKPOINT;
 CHECKPOINT;
 SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 232ab8db8fa..97b50926aa6 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -439,6 +439,9 @@ DROP TABLE test_stats_temp;
 -- Checkpoint twice: The checkpointer reports stats after reporting completion
 -- of the checkpoint. But after a second checkpoint we'll see at least the
 -- results of the first.
+--
+-- While at it, test checkpoint options.
+CHECKPOINT (WRONG);
 CHECKPOINT;
 CHECKPOINT;
 
-- 
2.39.5 (Apple Git-154)

>From c7365281d57cfb3428ffba6ae1b7a1ada42e5ebc Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nat...@postgresql.org>
Date: Thu, 10 Jul 2025 10:30:35 -0500
Subject: [PATCH v9 4/5] Add MODE option to CHECKPOINT command.

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 <m...@debian.org>
Reviewed-by: Andres Freund <and...@anarazel.de>
Reviewed-by: Fujii Masao <masao.fu...@oss.nttdata.com>
Reviewed-by: Laurenz Albe <laurenz.a...@cybertec.at>
Reviewed-by: Dilip Kumar <dilipbal...@gmail.com>
Discussion: https://postgr.es/m/aDnaKTEf-0dLiEfz%40msg.df7cb.de
---
 doc/src/sgml/ref/checkpoint.sgml      | 35 ++++++++++++++++++++++++---
 src/backend/postmaster/checkpointer.c | 28 +++++++++++++++++----
 src/bin/psql/tab-complete.in.c        | 13 ++++++++++
 src/test/regress/expected/stats.out   |  9 +++++--
 src/test/regress/sql/stats.sql        |  6 +++--
 5 files changed, 79 insertions(+), 12 deletions(-)

diff --git a/doc/src/sgml/ref/checkpoint.sgml b/doc/src/sgml/ref/checkpoint.sgml
index fad5e982d03..36a9e323f44 100644
--- a/doc/src/sgml/ref/checkpoint.sgml
+++ b/doc/src/sgml/ref/checkpoint.sgml
@@ -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>
diff --git a/src/backend/postmaster/checkpointer.c 
b/src/backend/postmaster/checkpointer.c
index dc01f2382f1..9d77269a374 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -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));
 }
 
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 089fe367d9f..a7db04efd93 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -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,
diff --git a/src/test/regress/expected/stats.out 
b/src/test/regress/expected/stats.out
index 9b865ae5f6c..b4df9ad5960 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -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? 
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 97b50926aa6..0868b250a64 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -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;
-- 
2.39.5 (Apple Git-154)

>From 0269d61a12e604bc7679d8724e0924a4be2e2cc1 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nat...@postgresql.org>
Date: Thu, 10 Jul 2025 10:47:55 -0500
Subject: [PATCH v9 5/5] Add FLUSH_UNLOGGED option to CHECKPOINT command.

This option, which is disabled by default, can be used to request
the checkpoint also flush data files for unlogged relations.  As
with the MODE option, the server may consolidate the options for
concurrently requested checkpoints.  For example, if one session
uses (FLUSH_UNLOGGED FALSE) and another uses (FLUSH_UNLOGGED TRUE),
the server may perform one checkpoint with FLUSH_UNLOGGED enabled.

Author: Christoph Berg <m...@debian.org>
Reviewed-by: Laurenz Albe <laurenz.a...@cybertec.at>
Reviewed-by: Fujii Masao <masao.fu...@oss.nttdata.com>
Reviewed-by: Dilip Kumar <dilipbal...@gmail.com>
Discussion: https://postgr.es/m/aDnaKTEf-0dLiEfz%40msg.df7cb.de
---
 doc/src/sgml/ref/checkpoint.sgml      | 26 ++++++++++++++++++++++++++
 src/backend/postmaster/checkpointer.c |  4 ++++
 src/bin/psql/tab-complete.in.c        |  2 +-
 src/test/regress/expected/stats.out   |  2 +-
 src/test/regress/sql/stats.sql        |  2 +-
 5 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/ref/checkpoint.sgml b/doc/src/sgml/ref/checkpoint.sgml
index 36a9e323f44..cd981cf2cab 100644
--- a/doc/src/sgml/ref/checkpoint.sgml
+++ b/doc/src/sgml/ref/checkpoint.sgml
@@ -25,6 +25,7 @@ CHECKPOINT [ ( option [, ...] ) ]
 
 <phrase>where <replaceable class="parameter">option</replaceable> can be one 
of:</phrase>
 
+    FLUSH_UNLOGGED [ <replaceable class="parameter">boolean</replaceable> ]
     MODE { FAST | SPREAD }
 </synopsis>
  </refsynopsisdiv>
@@ -76,6 +77,17 @@ CHECKPOINT [ ( option [, ...] ) ]
   <title>Parameters</title>
 
   <variablelist>
+   <varlistentry>
+    <term><literal>FLUSH_UNLOGGED</literal></term>
+    <listitem>
+     <para>
+      Normally, <command>CHECKPOINT</command> does not flush dirty buffers of
+      unlogged relations.  This option, which is disabled by default, enables
+      flushing unlogged relations to disk.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><literal>MODE</literal></term>
     <listitem>
@@ -93,6 +105,20 @@ CHECKPOINT [ ( option [, ...] ) ]
      </para>
     </listitem>
    </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="parameter">boolean</replaceable></term>
+    <listitem>
+     <para>
+      Specifies whether the selected option should be turned on or off.
+      You can write <literal>TRUE</literal>, <literal>ON</literal>, or
+      <literal>1</literal> to enable the option, and <literal>FALSE</literal>,
+      <literal>OFF</literal>, or <literal>0</literal> to disable it.  The
+      <replaceable class="parameter">boolean</replaceable> value can also
+      be omitted, in which case <literal>TRUE</literal> is assumed.
+     </para>
+    </listitem>
+   </varlistentry>
   </variablelist>
  </refsect1>
 
diff --git a/src/backend/postmaster/checkpointer.c 
b/src/backend/postmaster/checkpointer.c
index 9d77269a374..2809e298a44 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -989,6 +989,7 @@ void
 ExecCheckpoint(ParseState *pstate, CheckPointStmt *stmt)
 {
        bool            fast = true;
+       bool            unlogged = false;
 
        foreach_ptr(DefElem, opt, stmt->options)
        {
@@ -1004,6 +1005,8 @@ ExecCheckpoint(ParseState *pstate, CheckPointStmt *stmt)
                                                 errmsg("unrecognized MODE 
option \"%s\"", mode),
                                                 parser_errposition(pstate, 
opt->location)));
                }
+               else if (strcmp(opt->defname, "flush_unlogged") == 0)
+                       unlogged = defGetBoolean(opt);
                else
                        ereport(ERROR,
                                        (errcode(ERRCODE_SYNTAX_ERROR),
@@ -1022,6 +1025,7 @@ ExecCheckpoint(ParseState *pstate, CheckPointStmt *stmt)
 
        RequestCheckpoint(CHECKPOINT_WAIT |
                                          (fast ? CHECKPOINT_FAST : 0) |
+                                         (unlogged ? CHECKPOINT_FLUSH_UNLOGGED 
: 0) |
                                          (RecoveryInProgress() ? 0 : 
CHECKPOINT_FORCE));
 }
 
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index a7db04efd93..6872653c6c8 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -3165,7 +3165,7 @@ match_previous_words(int pattern_id,
                 * one word, so the above test is correct.
                 */
                if (ends_with(prev_wd, '(') || ends_with(prev_wd, ','))
-                       COMPLETE_WITH("MODE");
+                       COMPLETE_WITH("MODE", "FLUSH_UNLOGGED");
                else if (TailMatches("MODE"))
                        COMPLETE_WITH("FAST", "SPREAD");
        }
diff --git a/src/test/regress/expected/stats.out 
b/src/test/regress/expected/stats.out
index b4df9ad5960..b9dd5317163 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -938,7 +938,7 @@ ERROR:  unrecognized MODE option "wrong"
 LINE 1: CHECKPOINT (MODE WRONG);
                     ^
 CHECKPOINT (MODE FAST);
-CHECKPOINT;
+CHECKPOINT (FLUSH_UNLOGGED);
 SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 0868b250a64..3c6837c5c94 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -445,7 +445,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT (WRONG);
 CHECKPOINT (MODE WRONG);
 CHECKPOINT (MODE FAST);
-CHECKPOINT;
+CHECKPOINT (FLUSH_UNLOGGED);
 
 SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
-- 
2.39.5 (Apple Git-154)

Reply via email to