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 [, ...] ) ] where option can be one of: + + MODE { FAST | SPREAD } @@ -39,14 +41,24 @@ CHECKPOINT [ ( option [, ...] ) ] - The CHECKPOINT command forces a fast + By 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 ). + To request the checkpoint be spread over a longer interval, set the + MODE option to SPREAD. CHECKPOINT is not intended for use during normal 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 +75,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..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;