I broke this up into several small patches. Notable changes are as follows:
* Adjusted to the tab completion code to work more like the VACUUM utility options. * Introduced a new ExecCheckpoint() function in checkpointer.c and moved the privilege check and options parsing there. * Removed the notes in the docs about when to use the CHECKPOINT command. I'm not opposed to adding something like that (in fact, I think it's a good idea), but IMHO we should bikeshed on that separately, maybe even in a new thread. Thoughts? -- nathan
>From e2ce33136bc7c994839ea07ba0679271cc68a31e Mon Sep 17 00:00:00 2001 From: Nathan Bossart <nat...@postgresql.org> Date: Tue, 17 Jun 2025 14:36:40 -0500 Subject: [PATCH v7 1/5] rename CHECKPOINT_FLUSH_ALL to CHECKPOINT_FLUSH_UNLOGGED --- 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 47ffc0a2307..7f816ce4a84 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 667aa0c0c78..5c4331688cc 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 ccb17be3955c4b3b88277cdc581ce10d29c940cb Mon Sep 17 00:00:00 2001 From: Christoph Berg <m...@debian.org> Date: Wed, 11 Jun 2025 16:32:23 +0200 Subject: [PATCH v7 2/5] rename CHECKPOINT_IMMEDIATE to CHECKPOINT_FAST --- 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 | 2 +- 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, 39 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 c67688cbf5f..a49eb8a2af9 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -28920,7 +28920,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..9be752fc12b 100644 --- a/doc/src/sgml/ref/pg_basebackup.sgml +++ b/doc/src/sgml/ref/pg_basebackup.sgml @@ -500,7 +500,7 @@ 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 (the default) (see <xref linkend="backup-lowlevel-base-backup"/>). </para> </listitem> diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 7f816ce4a84..3740bc5a4a8 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). @@ -8947,9 +8947,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 @@ -9077,11 +9076,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 5c4331688cc..8f80d160c54 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 25fe3d58016..cda86ad44b0 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 815634c9ade5aa89351beb876d05a261c3db7e92 Mon Sep 17 00:00:00 2001 From: Nathan Bossart <nat...@postgresql.org> Date: Tue, 17 Jun 2025 15:36:29 -0500 Subject: [PATCH v7 3/5] add option list to checkpoint command --- doc/src/sgml/ref/checkpoint.sgml | 12 +++++++++- src/backend/parser/gram.y | 7 ++++++ src/backend/postmaster/checkpointer.c | 33 +++++++++++++++++++++++++++ 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 ++ 7 files changed, 58 insertions(+), 12 deletions(-) diff --git a/doc/src/sgml/ref/checkpoint.sgml b/doc/src/sgml/ref/checkpoint.sgml index 10a433e4757..1294b7c528e 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,14 @@ CHECKPOINT </para> </refsect1> + <refsect1> + <title>Parameters</title> + + <para> + Coming soon... + </para> + </refsect1> + <refsect1> <title>Compatibility</title> diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 50f53159d58..5934810e805 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..58d863847c5 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,37 @@ 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 cda86ad44b0..2268709c5a7 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 2c0b4f28c14..f4b9ad3b26d 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -3125,6 +3125,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 ba12678d1cb..c4d1e9c8006 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -4015,6 +4015,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); -- 2.39.5 (Apple Git-154)
>From bafe6274481c008727db9412088208f811d0ba4d Mon Sep 17 00:00:00 2001 From: Nathan Bossart <nat...@postgresql.org> Date: Wed, 18 Jun 2025 10:40:27 -0500 Subject: [PATCH v7 4/5] add mode option to checkpoint command --- doc/src/sgml/ref/checkpoint.sgml | 35 ++++++++++++++++++++++++--- src/backend/postmaster/checkpointer.c | 26 ++++++++++++++++---- src/bin/psql/tab-complete.in.c | 13 ++++++++++ src/test/regress/expected/stats.out | 5 +++- src/test/regress/sql/stats.sql | 5 +++- 5 files changed, 73 insertions(+), 11 deletions(-) diff --git a/doc/src/sgml/ref/checkpoint.sgml b/doc/src/sgml/ref/checkpoint.sgml index 1294b7c528e..d66aa967afc 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,7 +41,8 @@ CHECKPOINT [ ( option [, ...] ) ] </para> <para> - The <command>CHECKPOINT</command> command forces a fast + When <literal>MODE</literal> is set to <literal>FAST</literal>, which is the + 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"/>). @@ -47,6 +50,14 @@ CHECKPOINT [ ( option [, ...] ) ] 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,9 +74,25 @@ CHECKPOINT [ ( option [, ...] ) ] <refsect1> <title>Parameters</title> - <para> - Coming soon... - </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 58d863847c5..723322e3e03 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,12 +988,27 @@ 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\"", opt->defname), + 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)) @@ -1005,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 f4b9ad3b26d..177615aff27 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -3128,6 +3128,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 776f1ad0e53..02cdc3cbcf6 100644 --- a/src/test/regress/expected/stats.out +++ b/src/test/regress/expected/stats.out @@ -926,7 +926,10 @@ 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. -CHECKPOINT; +-- +-- While at it, test checkpoint options. Note that we don't test MODE SPREAD +-- because it would prolong the test. +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 232ab8db8fa..5ed71d7054e 100644 --- a/src/test/regress/sql/stats.sql +++ b/src/test/regress/sql/stats.sql @@ -439,7 +439,10 @@ 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. -CHECKPOINT; +-- +-- While at it, test checkpoint options. Note that we don't test MODE SPREAD +-- because it would prolong the test. +CHECKPOINT (MODE FAST); CHECKPOINT; SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer; -- 2.39.5 (Apple Git-154)
>From 159dcdc121523d10aa6bf1030c35052a3a8c5e2b Mon Sep 17 00:00:00 2001 From: Nathan Bossart <nat...@postgresql.org> Date: Wed, 18 Jun 2025 11:08:26 -0500 Subject: [PATCH v7 5/5] add flush_unlogged option to checkpoint command --- 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 d66aa967afc..8054de78a9b 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> @@ -75,6 +76,17 @@ CHECKPOINT [ ( option [, ...] ) ] <title>Parameters</title> <variablelist> + <varlistentry> + <term><literal>FLUSH_UNLOGGED</literal></term> + <listitem> + <para> + Normally, <command>CHECKPOINT</command> does not flush data files for + unlogged relations. This option, which is disabled by default, enables + flushing unlogged relations. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><literal>MODE</literal></term> <listitem> @@ -92,6 +104,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 723322e3e03..a3e4e70ad66 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\"", opt->defname), 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 177615aff27..a3f46a205ec 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -3137,7 +3137,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 02cdc3cbcf6..6ebcc292834 100644 --- a/src/test/regress/expected/stats.out +++ b/src/test/regress/expected/stats.out @@ -930,7 +930,7 @@ DROP TABLE test_stats_temp; -- While at it, test checkpoint options. Note that we don't test MODE SPREAD -- because it would prolong the test. 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 5ed71d7054e..dab19918056 100644 --- a/src/test/regress/sql/stats.sql +++ b/src/test/regress/sql/stats.sql @@ -443,7 +443,7 @@ DROP TABLE test_stats_temp; -- While at it, test checkpoint options. Note that we don't test MODE SPREAD -- because it would prolong the test. 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)