From 31a1e00f172eedd365ccd576e9d4122cb5fb0af2 Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Sat, 5 Dec 2020 00:07:18 +0000 Subject: [PATCH v4 1/1] Add SPREAD option to CHECKPOINT. --- doc/src/sgml/ref/checkpoint.sgml | 50 ++++++++++++++++++++++++++++++-- src/backend/parser/gram.y | 9 +++++- src/backend/postmaster/checkpointer.c | 37 +++++++++++++++++++++++ src/backend/tcop/utility.c | 8 +---- src/include/nodes/parsenodes.h | 1 + src/include/postmaster/bgwriter.h | 3 ++ src/test/regress/expected/checkpoint.out | 12 ++++++++ src/test/regress/parallel_schedule | 9 +++--- src/test/regress/serial_schedule | 1 + src/test/regress/sql/checkpoint.sql | 10 +++++++ 10 files changed, 126 insertions(+), 14 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..2b1e56fbd7 100644 --- a/doc/src/sgml/ref/checkpoint.sgml +++ b/doc/src/sgml/ref/checkpoint.sgml @@ -21,7 +21,11 @@ PostgreSQL documentation -CHECKPOINT +CHECKPOINT [ ( option [, ...] ) ] + +where option can be one of: + + SPREAD [ boolean ] @@ -37,7 +41,7 @@ CHECKPOINT - The CHECKPOINT command forces an immediate + The CHECKPOINT command forces a checkpoint when the command is issued, without waiting for a regular checkpoint scheduled by the system (controlled by the settings in ). @@ -51,11 +55,53 @@ CHECKPOINT 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 a spread checkpoint and + another session requested a fast checkpoint, the server may combine these + requests and perform one fast checkpoint. + + Only superusers can call CHECKPOINT. + + Parameters + + + + SPREAD + + + Specifies that checkpoint activity should be throttled based on the + setting for the + parameter. If the option is turned off, CHECKPOINT + creates a checkpoint or restartpoint as fast as possible. By default, + SPREAD is turned off, and the checkpoint activity is + not throttled. + + + + + + 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 ecff4cd2ac..c5b7a74c20 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -1773,7 +1773,14 @@ CheckPointStmt: CHECKPOINT { CheckPointStmt *n = makeNode(CheckPointStmt); - $$ = (Node *)n; + n->options = NIL; + $$ = (Node *) n; + } + | CHECKPOINT '(' utility_option_list ')' + { + CheckPointStmt *n = makeNode(CheckPointStmt); + n->options = $3; + $$ = (Node *) n; } ; diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index 429c8010ef..11fd93a18a 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,42 @@ CheckpointerShmemInit(void) } } +/* + * ExecCheckPointStmt + * Primary entry point for CHECKPOINT commands + */ +void +ExecCheckPointStmt(ParseState *pstate, CheckPointStmt *stmt) +{ + ListCell *lc; + bool spread = false; + 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, "spread") == 0) + spread = defGetBoolean(opt); + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unrecognized CHECKPOINT option \"%s\"", opt->defname), + parser_errposition(pstate, opt->location))); + } + + flags = CHECKPOINT_WAIT | + (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE) | + (spread ? 0 : CHECKPOINT_IMMEDIATE); + + 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 a42ead7d69..caf622d516 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -907,13 +907,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 ec14fc2036..313a3a6d43 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -3292,6 +3292,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..040110a522 --- /dev/null +++ b/src/test/regress/expected/checkpoint.out @@ -0,0 +1,12 @@ +-- CHECKPOINT +CHECKPOINT; +CHECKPOINT (SPREAD); +CHECKPOINT (SPREAD FALSE); +CHECKPOINT (SPREAD ON); +CHECKPOINT (SPREAD 0); +CHECKPOINT (SPREAD 2); +ERROR: spread 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..7d612be237 --- /dev/null +++ b/src/test/regress/sql/checkpoint.sql @@ -0,0 +1,10 @@ +-- CHECKPOINT + +CHECKPOINT; +CHECKPOINT (SPREAD); +CHECKPOINT (SPREAD FALSE); +CHECKPOINT (SPREAD ON); +CHECKPOINT (SPREAD 0); + +CHECKPOINT (SPREAD 2); +CHECKPOINT (NONEXISTENT); -- 2.16.6