From beb8d3a94a567aecb21e3ffaf7ae3a051063c2c7 Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Tue, 24 Nov 2020 22:14:59 +0000 Subject: [PATCH v1 1/1] Add FORCE, IMMEDIATE, and WAIT options to CHECKPOINT. --- doc/src/sgml/ref/checkpoint.sgml | 93 ++++++++++++++++++++++++++++---- src/backend/parser/gram.y | 36 ++++++++++++- src/backend/postmaster/checkpointer.c | 47 ++++++++++++++++ src/backend/tcop/utility.c | 8 +-- src/include/nodes/parsenodes.h | 1 + src/include/postmaster/bgwriter.h | 3 ++ src/test/regress/expected/checkpoint.out | 22 ++++++++ src/test/regress/parallel_schedule | 9 ++-- src/test/regress/serial_schedule | 1 + src/test/regress/sql/checkpoint.sql | 16 ++++++ 10 files changed, 213 insertions(+), 23 deletions(-) create mode 100644 src/test/regress/expected/checkpoint.out create mode 100644 src/test/regress/sql/checkpoint.sql diff --git a/doc/src/sgml/ref/checkpoint.sgml b/doc/src/sgml/ref/checkpoint.sgml index 2afee6d7b5..ee5b674104 100644 --- a/doc/src/sgml/ref/checkpoint.sgml +++ b/doc/src/sgml/ref/checkpoint.sgml @@ -21,7 +21,13 @@ PostgreSQL documentation -CHECKPOINT +CHECKPOINT [ ( option [, ...] ) ] + +where option can be one of: + + FORCE [ boolean ] + IMMEDIATE [ boolean ] + WAIT [ boolean ] @@ -33,22 +39,24 @@ CHECKPOINT all data files have been updated to reflect the information in the log. All data files will be flushed to disk. Refer to for more details about what happens - during a checkpoint. + during a checkpoint. Since automatic checkpoints are regularly scheduled by + the system (controlled by the settings in + ), it is not necessary to use + the CHECKPOINT command during normal operation. - The CHECKPOINT command forces an immediate - checkpoint when the command is issued, without waiting for a - regular checkpoint scheduled by the system (controlled by the settings in - ). - CHECKPOINT is not intended for use during normal - operation. + If executed during recovery, the CHECKPOINT command + will create a restartpoint (see ) + rather than writing a new checkpoint. - If executed during recovery, the CHECKPOINT command - will force a restartpoint (see ) - rather than writing a new checkpoint. + Note that the server may consolidate concurrently requested checkpoints or + restartpoints. Such consolidated requests will contain a combined set of + options. For example, if one session requested an immediate checkpoint and + another session requested a non-immediate checkpoint, the server may combine + these requests and perform one immediate checkpoint. @@ -56,6 +64,69 @@ CHECKPOINT + + Parameters + + + + FORCE + + + Specifies that CHECKPOINT should create a checkpoint + even if no transaction log activity has occurred since the last one. If + this option is disabled and no transaction log activity has occurred since + the last checkpoint, CHECKPOINT will not initiate a new + checkpoint. By default, FORCE is enabled. However, + this option is ignored if CHECKPOINT is executed during + recovery, as restartpoints cannot be initiated when no transaction log + activity has occurred. + + + + + + IMMEDIATE + + + Specifies that CHECKPOINT should create a checkpoint or + restartpoint as fast as possible. If this option is disabled, the + checkpoint activity is throttled based on the setting for the + parameter. By default, + IMMEDIATE is enabled, and the checkpoint activity is + not throttled. + + + + + + WAIT + + + Specifies that CHECKPOINT should wait for the + checkpoint or restartpoint to complete before returning. If this option + is disabled, CHECKPOINT requests a checkpoint or + restartpoint but does not wait for it to complete before returning. By + default, WAIT is enabled. + + + + + + boolean + + + Specifies whether the selected option should be turned on or off. + You can write TRUE, ON, or + 1 to enable the option, and FALSE, + OFF, or 0 to disable it. The + boolean value can also + be omitted, in which case TRUE is assumed. + + + + + + Compatibility diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index efc9c99754..b36f4a1d30 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -314,6 +314,10 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); transaction_mode_item create_extension_opt_item alter_extension_opt_item +%type opt_chkpt_option_list chkpt_option_list +%type chkpt_option_elem +%type chkpt_option_arg + %type opt_lock lock_type cast_context %type vac_analyze_option_name %type vac_analyze_option_elem @@ -1777,13 +1781,43 @@ constraints_set_mode: * Checkpoint statement */ CheckPointStmt: - CHECKPOINT + CHECKPOINT opt_chkpt_option_list { CheckPointStmt *n = makeNode(CheckPointStmt); + n->options = $2; $$ = (Node *)n; } ; +opt_chkpt_option_list: + '(' chkpt_option_list ')' { $$ = $2; } + | /* EMPTY */ { $$ = NIL; } + ; + +chkpt_option_list: + chkpt_option_elem + { + $$ = list_make1($1); + } + | chkpt_option_list ',' chkpt_option_elem + { + $$ = lappend($1, $3); + } + ; + +chkpt_option_elem: + NonReservedWord chkpt_option_arg + { + $$ = makeDefElem($1, $2, @1); + } + ; + +chkpt_option_arg: + opt_boolean_or_string { $$ = (Node *) makeString($1); } + | NumericOnly { $$ = (Node *) $1; } + | /* EMPTY */ { $$ = NULL; } + ; + /***************************************************************************** * diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index 429c8010ef..2cb2a73d54 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -41,6 +41,7 @@ #include "access/xlog.h" #include "access/xlog_internal.h" +#include "commands/defrem.h" #include "libpq/pqsignal.h" #include "miscadmin.h" #include "pgstat.h" @@ -895,6 +896,52 @@ CheckpointerShmemInit(void) } } +/* + * ExecCheckPointStmt + * Primary entry point for CHECKPOINT commands + */ +void +ExecCheckPointStmt(ParseState *pstate, CheckPointStmt *stmt) +{ + ListCell *lc; + bool immediate = true; + bool wait = true; + bool force = true; + int flags; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to do CHECKPOINT"))); + + foreach(lc, stmt->options) + { + DefElem *opt = (DefElem *) lfirst(lc); + + if (strcmp(opt->defname, "immediate") == 0) + immediate = defGetBoolean(opt); + else if (strcmp(opt->defname, "wait") == 0) + wait = defGetBoolean(opt); + else if (strcmp(opt->defname, "force") == 0) + force = defGetBoolean(opt); + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unrecognized CHECKPOINT option \"%s\"", opt->defname), + parser_errposition(pstate, opt->location))); + } + + /* not possible to force a restartpoint */ + if (RecoveryInProgress()) + force = false; + + flags = (immediate ? CHECKPOINT_IMMEDIATE : 0) | + (wait ? CHECKPOINT_WAIT : 0) | + (force ? CHECKPOINT_FORCE : 0); + + RequestCheckpoint(flags); +} + /* * RequestCheckpoint * Called in backend processes to request a checkpoint diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 81ac9b1cb2..4af8de0a26 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -906,13 +906,7 @@ standard_ProcessUtility(PlannedStmt *pstmt, break; case T_CheckPointStmt: - if (!superuser()) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to do CHECKPOINT"))); - - RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT | - (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE)); + ExecCheckPointStmt(pstate, (CheckPointStmt *) parsetree); break; case T_ReindexStmt: diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index d1f9ef29ca..f1d9d46f69 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -3297,6 +3297,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 0a5708b32e..d945009707 100644 --- a/src/include/postmaster/bgwriter.h +++ b/src/include/postmaster/bgwriter.h @@ -15,6 +15,8 @@ #ifndef _BGWRITER_H #define _BGWRITER_H +#include "nodes/parsenodes.h" +#include "parser/parse_node.h" #include "storage/block.h" #include "storage/relfilenode.h" #include "storage/smgr.h" @@ -30,6 +32,7 @@ extern double CheckPointCompletionTarget; extern void BackgroundWriterMain(void) pg_attribute_noreturn(); extern void CheckpointerMain(void) pg_attribute_noreturn(); +extern void ExecCheckPointStmt(ParseState *pstate, CheckPointStmt *stmt); extern void RequestCheckpoint(int flags); extern void CheckpointWriteDelay(int flags, double progress); diff --git a/src/test/regress/expected/checkpoint.out b/src/test/regress/expected/checkpoint.out new file mode 100644 index 0000000000..7a92e92c7a --- /dev/null +++ b/src/test/regress/expected/checkpoint.out @@ -0,0 +1,22 @@ +-- CHECKPOINT +CHECKPOINT; +CHECKPOINT (FORCE); +CHECKPOINT (IMMEDIATE); +CHECKPOINT (WAIT); +CHECKPOINT (FORCE true, IMMEDIATE 0); +CHECKPOINT (IMMEDIATE, WAIT off); +CHECKPOINT (FORCE, IMMEDIATE, WAIT); +CHECKPOINT (FORCE 1, IMMEDIATE true, WAIT on); +CHECKPOINT (FORCE false, IMMEDIATE off, WAIT 0); +CHECKPOINT (FORCE = false); +ERROR: syntax error at or near "=" +LINE 1: CHECKPOINT (FORCE = false); + ^ +CHECKPOINT (IMMEDIATE 2, WAIT); +ERROR: immediate requires a Boolean value +CHECKPOINT (WAIT no, FORCE no); +ERROR: wait requires a Boolean value +CHECKPOINT (NONEXISTENT); +ERROR: unrecognized CHECKPOINT option "nonexistent" +LINE 1: CHECKPOINT (NONEXISTENT); + ^ diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index ae89ed7f0b..354dda263f 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -5,10 +5,11 @@ # this limits the number of connections needed to run the tests. # ---------- -# run tablespace by itself, and first, because it forces a checkpoint; -# we'd prefer not to have checkpoints later in the tests because that -# interferes with crash-recovery testing. -test: tablespace +# ---------- +# Run tests that force checkpoints first. We'd prefer to not have checkpoints +# later in the tests because that interferes with crash-recovery testing. +# ---------- +test: checkpoint tablespace # ---------- # The first group of parallel tests diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index 525bdc804f..49901521f4 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -1,5 +1,6 @@ # src/test/regress/serial_schedule # This should probably be in an order similar to parallel_schedule. +test: checkpoint test: tablespace test: boolean test: char diff --git a/src/test/regress/sql/checkpoint.sql b/src/test/regress/sql/checkpoint.sql new file mode 100644 index 0000000000..bc3ae1aa03 --- /dev/null +++ b/src/test/regress/sql/checkpoint.sql @@ -0,0 +1,16 @@ +-- CHECKPOINT + +CHECKPOINT; +CHECKPOINT (FORCE); +CHECKPOINT (IMMEDIATE); +CHECKPOINT (WAIT); +CHECKPOINT (FORCE true, IMMEDIATE 0); +CHECKPOINT (IMMEDIATE, WAIT off); +CHECKPOINT (FORCE, IMMEDIATE, WAIT); +CHECKPOINT (FORCE 1, IMMEDIATE true, WAIT on); +CHECKPOINT (FORCE false, IMMEDIATE off, WAIT 0); + +CHECKPOINT (FORCE = false); +CHECKPOINT (IMMEDIATE 2, WAIT); +CHECKPOINT (WAIT no, FORCE no); +CHECKPOINT (NONEXISTENT); -- 2.16.6