From bafe6274481c008727db9412088208f811d0ba4d Mon Sep 17 00:00:00 2001 From: Nathan Bossart 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 [, ...] ) ] 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,9 +74,25 @@ CHECKPOINT [ ( option [, ...] ) ] Parameters - - Coming soon... - + + + 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 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)