From bfba87a017b3f7d98e44387838761980fe02708f Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Wed, 9 Jul 2025 13:52:14 -0500 Subject: [PATCH v8 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 Reviewed-by: Andres Freund Reviewed-by: Fujii Masao Reviewed-by: Laurenz Albe Discussion: https://postgr.es/m/aDnaKTEf-0dLiEfz%40msg.df7cb.de --- doc/src/sgml/ref/checkpoint.sgml | 34 ++++++++++++++++++++++++--- src/backend/postmaster/checkpointer.c | 28 ++++++++++++++++++---- 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, 75 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/ref/checkpoint.sgml b/doc/src/sgml/ref/checkpoint.sgml index fad5e982d03..d66aa967afc 100644 --- a/doc/src/sgml/ref/checkpoint.sgml +++ b/doc/src/sgml/ref/checkpoint.sgml @@ -24,6 +24,8 @@ PostgreSQL documentation CHECKPOINT [ ( option [, ...] ) ] where option can be one of: + + MODE { FAST | SPREAD } @@ -39,7 +41,8 @@ CHECKPOINT [ ( option [, ...] ) ] - The CHECKPOINT command forces a fast + When MODE is set to FAST, which is the + default, the CHECKPOINT 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 ). @@ -47,6 +50,14 @@ CHECKPOINT [ ( option [, ...] ) ] operation. + + 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. + + If executed during recovery, the CHECKPOINT command will force a restartpoint (see ) @@ -63,8 +74,25 @@ CHECKPOINT [ ( option [, ...] ) ] Parameters - - + + + MODE + + + When set to FAST, 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. + + + MODE can also be set to SPREAD to + request the checkpoint be spread over a longer interval (controlled via + the settings in ), like a + regular checkpoint scheduled by the system. This can reduce the rate of + I/O during the checkpoint. + + + + diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index dc01f2382f1..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,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\"", 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)) 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 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)