From 9e55ad5e1e1319cc32237e2ba79a097527d07fed Mon Sep 17 00:00:00 2001 From: Nitin Jadhav Date: Wed, 23 Feb 2022 13:17:16 +0000 Subject: [PATCH] pg_stat_progress-checkpoint view --- doc/src/sgml/monitoring.sgml | 357 ++++++++++++++++++++++++++ src/backend/access/transam/xlog.c | 132 ++++++++++ src/backend/catalog/system_views.sql | 36 +++ src/backend/postmaster/checkpointer.c | 14 +- src/backend/storage/buffer/bufmgr.c | 7 + src/backend/storage/sync/sync.c | 6 + src/backend/utils/adt/pgstatfuncs.c | 59 +++++ src/include/access/xlog.h | 4 + src/include/catalog/pg_proc.dat | 9 + src/include/commands/progress.h | 28 ++ src/include/utils/backend_progress.h | 3 +- src/test/regress/expected/rules.out | 33 +++ 12 files changed, 684 insertions(+), 4 deletions(-) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index bf7625d988..1e7112eb78 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -401,6 +401,13 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser See . + + + pg_stat_progress_checkpointpg_stat_progress_checkpoint + One row only, showing the progress of the CHECKPOINT. + See . + + @@ -6895,6 +6902,356 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid, + + CHECKPOINT Progress Reporting + + + pg_stat_progress_checkpoint + + + + Whenever the checkpoint operation is running, the + pg_stat_progress_checkpoint view will contain a + single row indicating the progress of the checkpoint. The tables below + describe the information that will be reported and provide information about + how to interpret it. + + + + <structname>pg_stat_progress_checkpoint</structname> View + + + + + Column Type + + + Description + + + + + + + + pid integer + + + Process ID of a CHECKPOINTER process. + + + + + + type text + + + Type of checkpoint. See . + + + + + + kind text + + + Kind of checkpoint. See . + + + + + + start_lsn text + + + The checkpoint start location. + + + + + + elapsed_time text + + + Elapsed time of the checkpoint. + + + + + + phase text + + + Current processing phase. See . + + + + + + buffers_total bigint + + + Total number of buffers to be written. This is estimated and reported + as of the beginning of buffer write operation. + + + + + + buffers_processed bigint + + + Number of buffers processed. This counter increases when the targeted + buffer is processed. This number will eventually become equal to + total_buffer_writes when the checkpoint is + complete. + + + + + + buffers_written bigint + + + Number of buffers written. This counter only advances when the targeted + buffers is written. Note that some of the buffers are processed but may + not required to be written. So this count will always be less than or + equal to total_buffer_writes. + + + + + + files_total bigint + + + Total number of files to be synced. This is estimated and reported as of + the beginning of sync operation. + + + + + + files_synced bigint + + + Number of files synced. This counter advances when the targeted file is + synced. This number will eventually become equal to + total_file_syncs when the checkpoint is complete. + + + + +
+ + + CHECKPOINT types + + + + + + Types + Description + + + + + checkpoint + + The current operation is checkpoint. + + + + restartpoint + + The current operation is restartpoint. + + + + +
+ + + CHECKPOINT kinds + + + + + + Kinds + Description + + + + + shutdown + + The checkpoint is for shutdown. + + + + end-of-recovery + + The checkpoint is for end-of-recovery. + + + + immediate + + The checkpoint is happens without delays. + + + + force + + The checkpoint is started because some operation forced a checkpoint. + + + + flush all + + The checkpoint flushes all pages, including those belonging to unlogged + tables. + + + + wait + + Wait for completion before returning. + + + + requested + + The checkpoint request has been made. + + + + wal + + The checkpoint is started because max_wal_size is + reached. + + + + time + + The checkpoint is started because checkpoint_timeout + expired. + + + + +
+ + + CHECKPOINT phases + + + + + + Phase + Description + + + + + initializing + + The CHECKPOINTER process is preparing to begin the checkpoint operation. + This phase is expected to be very brief. + + + + checkpointing replication slots + + The CHECKPOINTER process is currently flushing all the replication slots + to disk. + + + + checkpointing snapshots + + The CHECKPOINTER process is currently removing all the serialized + snapshots that are not required anymore. + + + + checkpointing logical rewrite mappings + + The CHECKPOINTER process is currently removing/flushing the logical + rewrite mappings. + + + + checkpointing CLOG pages + + The CHECKPOINTER process is currently writing CLOG pages to disk. + + + + checkpointing Commit time stamp pages + + The CHECKPOINTER process is currently writing Commit time stamp pages to + disk. + + + + checkpointing SUBTRANS pages + + The CHECKPOINTER process is currently writing SUBTRANS pages to disk. + + + + checkpointing MULTIXACT pages + + The CHECKPOINTER process is currently writing MULTIXACT pages to disk. + + + + checkpointing SLRU pages + + The CHECKPOINTER process is currently writing SLRU pages to disk. + + + + checkpointing buffers + + The CHECKPOINTER process is currently writing buffers to disk. + + + + performing sync requests + + The CHECKPOINTER process is currently performing sync requests. + + + + performing two phase checkpoint + + The CHECKPOINTER process is currently performing two phase checkpoint. + + + + recycling old XLOG files + + The CHECKPOINTER process is currently recycling old XLOG files. + + + + finalizing + + The CHECKPOINTER process is finalizing the checkpoint operation. + + + + +
+ +
+ diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 0d2bd7a357..e5a19f3cc3 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -65,6 +65,7 @@ #include "catalog/catversion.h" #include "catalog/pg_control.h" #include "catalog/pg_database.h" +#include "commands/progress.h" #include "common/controldata_utils.h" #include "executor/instrument.h" #include "miscadmin.h" @@ -653,6 +654,9 @@ static bool updateMinRecoveryPoint = true; static int MyLockNo = 0; static bool holdingAllLocks = false; +/* Copy of checkpoint flags. */ +static int ckpt_flags = 0; + #ifdef WAL_DEBUG static MemoryContext walDebugCxt = NULL; #endif @@ -6296,6 +6300,9 @@ CreateCheckPoint(int flags) MemSet(&CheckpointStats, 0, sizeof(CheckpointStats)); CheckpointStats.ckpt_start_t = GetCurrentTimestamp(); + /* Prepare to report progress of the checkpoint. */ + checkpoint_progress_start(flags); + /* * Use a critical section to force system panic if we have trouble. */ @@ -6394,6 +6401,7 @@ CreateCheckPoint(int flags) curInsert += SizeOfXLogShortPHD; } checkPoint.redo = curInsert; + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_LSN, checkPoint.redo); /* * Here we update the shared RedoRecPtr for future XLogInsert calls; this @@ -6629,8 +6637,12 @@ CreateCheckPoint(int flags) KeepLogSeg(recptr, &_logSegNo); } _logSegNo--; + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_OLD_XLOG_RECYCLE); RemoveOldXlogFiles(_logSegNo, RedoRecPtr, recptr, checkPoint.ThisTimeLineID); + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_FINALIZE); /* * Make more log segments if needed. (Do this after recycling old log @@ -6652,6 +6664,9 @@ CreateCheckPoint(int flags) /* Real work is done; log and update stats. */ LogCheckpointEnd(false); + /* Stop reporting progress of the checkpoint. */ + checkpoint_progress_end(); + /* Reset the process title */ update_checkpoint_display(flags, false, true); @@ -6808,29 +6823,60 @@ static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags) { CheckPointRelationMap(); + + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_REPLI_SLOTS); CheckPointReplicationSlots(); + + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_SNAPSHOTS); CheckPointSnapBuild(); + + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_LOGICAL_REWRITE_MAPPINGS); CheckPointLogicalRewriteHeap(); CheckPointReplicationOrigin(); /* Write out all dirty data in SLRUs and the main buffer pool */ TRACE_POSTGRESQL_BUFFER_CHECKPOINT_START(flags); CheckpointStats.ckpt_write_t = GetCurrentTimestamp(); + + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_CLOG_PAGES); CheckPointCLOG(); + + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_COMMITTS_PAGES); CheckPointCommitTs(); + + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_SUBTRANS_PAGES); CheckPointSUBTRANS(); + + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_MULTIXACT_PAGES); CheckPointMultiXact(); + + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_SLRU_PAGES); CheckPointPredicate(); + + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_BUFFERS); CheckPointBuffers(flags); /* Perform all queued up fsyncs */ TRACE_POSTGRESQL_BUFFER_CHECKPOINT_SYNC_START(); CheckpointStats.ckpt_sync_t = GetCurrentTimestamp(); + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_FILE_SYNC); ProcessSyncRequests(); CheckpointStats.ckpt_sync_end_t = GetCurrentTimestamp(); TRACE_POSTGRESQL_BUFFER_CHECKPOINT_DONE(); /* We deliberately delay 2PC checkpointing as long as possible */ + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_TWO_PHASE); CheckPointTwoPhase(checkPointRedo); } @@ -6977,6 +7023,9 @@ CreateRestartPoint(int flags) MemSet(&CheckpointStats, 0, sizeof(CheckpointStats)); CheckpointStats.ckpt_start_t = GetCurrentTimestamp(); + /* Prepare to report progress of the restartpoint. */ + checkpoint_progress_start(flags); + if (log_checkpoints) LogCheckpointStart(flags, true); @@ -7077,7 +7126,11 @@ CreateRestartPoint(int flags) if (!RecoveryInProgress()) replayTLI = XLogCtl->InsertTimeLineID; + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_OLD_XLOG_RECYCLE); RemoveOldXlogFiles(_logSegNo, RedoRecPtr, endptr, replayTLI); + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_PHASE_FINALIZE); /* * Make more log segments if needed. (Do this after recycling old log @@ -7098,6 +7151,9 @@ CreateRestartPoint(int flags) /* Real work is done; log and update stats. */ LogCheckpointEnd(true); + /* Stop reporting progress of the restartpoint. */ + checkpoint_progress_end(); + /* Reset the process title */ update_checkpoint_display(flags, true, true); @@ -9197,3 +9253,79 @@ SetWalWriterSleeping(bool sleeping) XLogCtl->WalWriterSleeping = sleeping; SpinLockRelease(&XLogCtl->info_lck); } + +/* + * Start reporting progress of the checkpoint. + */ +void +checkpoint_progress_start(int flags) +{ + /* In bootstrap mode, we don't actually record anything. */ + if (IsBootstrapProcessingMode()) + return; + + ckpt_flags = flags; + + /* + * Cannot access pg_stat_progress_checkpoint view in case of checkpoint + * during shutdown and end-of-recovery. + */ + if ((ckpt_flags & + (CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_END_OF_RECOVERY)) == 0) + { + const int index[] = { + PROGRESS_CHECKPOINT_TIMELINE, + PROGRESS_CHECKPOINT_KIND, + PROGRESS_CHECKPOINT_PHASE, + PROGRESS_CHECKPOINT_START_TIMESTAMP + }; + int64 val[4]; + + pgstat_progress_start_command(PROGRESS_COMMAND_CHECKPOINT, InvalidOid); + + val[0] = XLogCtl->InsertTimeLineID; + val[1] = flags; + val[2] = PROGRESS_CHECKPOINT_PHASE_INIT; + val[3] = CheckpointStats.ckpt_start_t; + + pgstat_progress_update_multi_param(4, index, val); + } +} + +/* + * Update index'th member in st_progress_param[] array with the latest value. + */ +void +checkpoint_progress_update_param(int index, int64 val) +{ + /* In bootstrap mode, we don't actually record anything. */ + if (IsBootstrapProcessingMode()) + return; + + /* + * Cannot access pg_stat_progress_checkpoint view in case of checkpoint + * during shutdown and end-of-recovery. + */ + if ((ckpt_flags & + (CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_END_OF_RECOVERY)) == 0) + pgstat_progress_update_param(index, val); +} + +/* + * Stop reporting progress of the checkpoint. + */ +void +checkpoint_progress_end(void) +{ + /* In bootstrap mode, we don't actually record anything. */ + if (IsBootstrapProcessingMode()) + return; + + /* + * Cannot access pg_stat_progress_checkpoint view in case of checkpoint + * during shutdown and end-of-recovery. + */ + if ((ckpt_flags & + (CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_END_OF_RECOVERY)) == 0) + pgstat_progress_end_command(); +} \ No newline at end of file diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 3cb69b1f87..6dc5b0feb6 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1286,3 +1286,39 @@ CREATE VIEW pg_stat_subscription_workers AS FROM pg_subscription_rel) sr, LATERAL pg_stat_get_subscription_worker(sr.subid, sr.relid) w JOIN pg_subscription s ON (w.subid = s.oid); + +CREATE VIEW pg_stat_progress_checkpoint AS + SELECT + S.pid AS pid, + pg_stat_get_progress_checkpoint_type(S.param1) AS type, + pg_stat_get_progress_checkpoint_kind(S.param2) AS kind, + ( SELECT '0/0'::pg_lsn + + ((CASE + WHEN stat.lsn_int64 < 0 THEN pow(2::numeric, 64::numeric)::numeric + ELSE 0::numeric + END) + + stat.lsn_int64::numeric) + FROM (SELECT s.param3::bigint) AS stat(lsn_int64) + ) AS start_lsn, + pg_stat_get_progress_checkpoint_elapsed(S.param4) AS elapsed_time, + CASE S.param5 WHEN 0 THEN 'initializing' + WHEN 1 THEN 'checkpointing replication slots' + WHEN 2 THEN 'checkpointing snapshots' + WHEN 3 THEN 'checkpointing logical rewrite mappings' + WHEN 4 THEN 'checkpointing CLOG pages' + WHEN 5 THEN 'checkpointing CommitTs pages' + WHEN 6 THEN 'checkpointing SUBTRANS pages' + WHEN 7 THEN 'checkpointing MULTIXACT pages' + WHEN 8 THEN 'checkpointing SLRU pages' + WHEN 9 THEN 'checkpointing buffers' + WHEN 10 THEN 'performing sync requests' + WHEN 11 THEN 'performing two phase checkpoint' + WHEN 12 THEN 'recycling old XLOG files' + WHEN 13 THEN 'Finalizing' + END AS phase, + S.param6 AS total_buffer_writes, + S.param7 AS buffers_processed, + S.param8 AS buffers_written, + S.param9 AS total_file_syncs, + S.param10 AS files_synced + FROM pg_stat_get_progress_info('CHECKPOINT') AS S; diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index 4488e3a443..2ff7e77b3e 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -39,6 +39,7 @@ #include "access/xlog.h" #include "access/xlog_internal.h" #include "access/xlogrecovery.h" +#include "commands/progress.h" #include "libpq/pqsignal.h" #include "miscadmin.h" #include "pgstat.h" @@ -163,7 +164,7 @@ static pg_time_t last_xlog_switch_time; static void HandleCheckpointerInterrupts(void); static void CheckArchiveTimeout(void); static bool IsCheckpointOnSchedule(double progress); -static bool ImmediateCheckpointRequested(void); +static bool ImmediateCheckpointRequested(int flags); static bool CompactCheckpointerRequestQueue(void); static void UpdateSharedMemoryConfig(void); @@ -658,16 +659,23 @@ CheckArchiveTimeout(void) * there is one pending behind it.) */ static bool -ImmediateCheckpointRequested(void) +ImmediateCheckpointRequested(int flags) { volatile CheckpointerShmemStruct *cps = CheckpointerShmem; + int updated_flags = flags; /* * We don't need to acquire the ckpt_lck in this case because we're only * looking at a single flag bit. */ if (cps->ckpt_flags & CHECKPOINT_IMMEDIATE) + { + updated_flags |= CHECKPOINT_IMMEDIATE; + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_KIND, + updated_flags); return true; + } + return false; } @@ -699,7 +707,7 @@ CheckpointWriteDelay(int flags, double progress) */ if (!(flags & CHECKPOINT_IMMEDIATE) && !ShutdownRequestPending && - !ImmediateCheckpointRequested() && + !ImmediateCheckpointRequested(flags) && IsCheckpointOnSchedule(progress)) { if (ConfigReloadPending) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index f5459c68f8..156130ef43 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -38,6 +38,7 @@ #include "access/xlogutils.h" #include "catalog/catalog.h" #include "catalog/storage.h" +#include "commands/progress.h" #include "executor/instrument.h" #include "lib/binaryheap.h" #include "miscadmin.h" @@ -2012,6 +2013,8 @@ BufferSync(int flags) WritebackContextInit(&wb_context, &checkpoint_flush_after); TRACE_POSTGRESQL_BUFFER_SYNC_START(NBuffers, num_to_scan); + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_BUFFERS_TOTAL, + num_to_scan); /* * Sort buffers that need to be written to reduce the likelihood of random @@ -2129,6 +2132,8 @@ BufferSync(int flags) bufHdr = GetBufferDescriptor(buf_id); num_processed++; + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_BUFFERS_PROCESSED, + num_processed); /* * We don't need to acquire the lock here, because we're only looking @@ -2149,6 +2154,8 @@ BufferSync(int flags) TRACE_POSTGRESQL_BUFFER_SYNC_WRITTEN(buf_id); PendingCheckpointerStats.m_buf_written_checkpoints++; num_written++; + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_BUFFERS_WRITTEN, + num_written); } } diff --git a/src/backend/storage/sync/sync.c b/src/backend/storage/sync/sync.c index e161d57761..f0441d4de8 100644 --- a/src/backend/storage/sync/sync.c +++ b/src/backend/storage/sync/sync.c @@ -23,6 +23,7 @@ #include "access/multixact.h" #include "access/xlog.h" #include "access/xlogutils.h" +#include "commands/progress.h" #include "commands/tablespace.h" #include "miscadmin.h" #include "pgstat.h" @@ -356,6 +357,9 @@ ProcessSyncRequests(void) /* Now scan the hashtable for fsync requests to process */ absorb_counter = FSYNCS_PER_ABSORB; hash_seq_init(&hstat, pendingOps); + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_FILES_TOTAL, + hash_get_num_entries(pendingOps)); + while ((entry = (PendingFsyncEntry *) hash_seq_search(&hstat)) != NULL) { int failures; @@ -419,6 +423,8 @@ ProcessSyncRequests(void) longest = elapsed; total_elapsed += elapsed; processed++; + checkpoint_progress_update_param(PROGRESS_CHECKPOINT_FILES_SYNCED, + processed); if (log_checkpoints) elog(DEBUG1, "checkpoint sync: number=%d file=%s time=%.3f ms", diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 30e8dfa7c1..32c35f0bd0 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -494,6 +494,8 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS) cmdtype = PROGRESS_COMMAND_BASEBACKUP; else if (pg_strcasecmp(cmd, "COPY") == 0) cmdtype = PROGRESS_COMMAND_COPY; + else if (pg_strcasecmp(cmd, "CHECKPOINT") == 0) + cmdtype = PROGRESS_COMMAND_CHECKPOINT; else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -2495,3 +2497,60 @@ pg_stat_get_subscription_worker(PG_FUNCTION_ARGS) /* Returns the record as Datum */ PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); } + +/* + * Return checkpoint type (either checkpoint or restartpoint). + */ +Datum +pg_stat_get_progress_checkpoint_type(PG_FUNCTION_ARGS) +{ + TimeLineID cur_timeline = (TimeLineID) PG_GETARG_INT64(0); + + if (RecoveryInProgress() || (GetWALInsertionTimeLine() != cur_timeline)) + PG_RETURN_TEXT_P(CStringGetTextDatum("restartpoint")); + else + PG_RETURN_TEXT_P(CStringGetTextDatum("checkpoint")); +} + +/* + * Return checkpoint kind based on the flags set. + */ +Datum +pg_stat_get_progress_checkpoint_kind(PG_FUNCTION_ARGS) +{ + int64 flags = PG_GETARG_INT64(0); + char ckpt_kind[MAXPGPATH]; + + MemSet(ckpt_kind, 0, MAXPGPATH); + snprintf(ckpt_kind, MAXPGPATH, "%s%s%s%s%s%s%s%s%s", + (flags == 0) ? "unknown" : "", + (flags & CHECKPOINT_IS_SHUTDOWN) ? "shutdown " : "", + (flags & CHECKPOINT_END_OF_RECOVERY) ? "end-of-recovery " : "", + (flags & CHECKPOINT_IMMEDIATE) ? "immediate " : "", + (flags & CHECKPOINT_FORCE) ? "force " : "", + (flags & CHECKPOINT_WAIT) ? "wait " : "", + (flags & CHECKPOINT_CAUSE_XLOG) ? "wal " : "", + (flags & CHECKPOINT_CAUSE_TIME) ? "time " : "", + (flags & CHECKPOINT_FLUSH_ALL) ? "flush-all" : ""); + + PG_RETURN_TEXT_P(CStringGetTextDatum(ckpt_kind)); +} + +/* + * Return elapsed time (in seconds) of the checkpoint. + */ +Datum +pg_stat_get_progress_checkpoint_elapsed(PG_FUNCTION_ARGS) +{ + TimestampTz start = PG_GETARG_INT64(0); + TimestampTz now = GetCurrentTimestamp(); + char elapsed_time[NAMEDATALEN]; + long secs; + int usecs; + + TimestampDifference(start, now, &secs, &usecs); + snprintf(elapsed_time, sizeof(elapsed_time), "%ld.%02d s", secs, + (usecs / 10000)); + + PG_RETURN_TEXT_P(CStringGetTextDatum(elapsed_time)); +} \ No newline at end of file diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 4b45ac64db..c0a3f57689 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -288,6 +288,10 @@ extern void do_pg_abort_backup(int code, Datum arg); extern void register_persistent_abort_backup_handler(void); extern SessionBackupState get_backup_status(void); +extern void checkpoint_progress_start(int flags); +extern void checkpoint_progress_update_param(int index, int64 val); +extern void checkpoint_progress_end(void); + /* File path names (all relative to $PGDATA) */ #define RECOVERY_SIGNAL_FILE "recovery.signal" #define STANDBY_SIGNAL_FILE "standby.signal" diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 7f1ee97f55..40f993c9b1 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5353,6 +5353,15 @@ proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', proargnames => '{cmdtype,pid,datid,relid,param1,param2,param3,param4,param5,param6,param7,param8,param9,param10,param11,param12,param13,param14,param15,param16,param17,param18,param19,param20}', prosrc => 'pg_stat_get_progress_info' }, +{ oid => '560', descr => 'return checkpoint type', + proname => 'pg_stat_get_progress_checkpoint_type', prorettype => 'text', + proargtypes => 'int8', prosrc => 'pg_stat_get_progress_checkpoint_type' }, +{ oid => '561', descr => 'return checkpoint kind', + proname => 'pg_stat_get_progress_checkpoint_kind', prorettype => 'text', + proargtypes => 'int8', prosrc => 'pg_stat_get_progress_checkpoint_kind' }, +{ oid => '562', descr => 'return elapsed time of the checkpoint', + proname => 'pg_stat_get_progress_checkpoint_elapsed', prorettype => 'text', + proargtypes => 'int8', prosrc => 'pg_stat_get_progress_checkpoint_elapsed' }, { oid => '3099', descr => 'statistics: information about currently active replication', proname => 'pg_stat_get_wal_senders', prorows => '10', proisstrict => 'f', diff --git a/src/include/commands/progress.h b/src/include/commands/progress.h index a28938caf4..19734405ed 100644 --- a/src/include/commands/progress.h +++ b/src/include/commands/progress.h @@ -151,4 +151,32 @@ #define PROGRESS_COPY_TYPE_PIPE 3 #define PROGRESS_COPY_TYPE_CALLBACK 4 +/* Progress parameters for checkpoint */ +#define PROGRESS_CHECKPOINT_TIMELINE 0 +#define PROGRESS_CHECKPOINT_KIND 1 +#define PROGRESS_CHECKPOINT_LSN 2 +#define PROGRESS_CHECKPOINT_START_TIMESTAMP 3 +#define PROGRESS_CHECKPOINT_PHASE 4 +#define PROGRESS_CHECKPOINT_BUFFERS_TOTAL 5 +#define PROGRESS_CHECKPOINT_BUFFERS_PROCESSED 6 +#define PROGRESS_CHECKPOINT_BUFFERS_WRITTEN 7 +#define PROGRESS_CHECKPOINT_FILES_TOTAL 8 +#define PROGRESS_CHECKPOINT_FILES_SYNCED 9 + +/* Phases of checkpoint (as advertised via PROGRESS_CHECKPOINT_PHASE) */ +#define PROGRESS_CHECKPOINT_PHASE_INIT 0 +#define PROGRESS_CHECKPOINT_PHASE_REPLI_SLOTS 1 +#define PROGRESS_CHECKPOINT_PHASE_SNAPSHOTS 2 +#define PROGRESS_CHECKPOINT_PHASE_LOGICAL_REWRITE_MAPPINGS 3 +#define PROGRESS_CHECKPOINT_PHASE_CLOG_PAGES 4 +#define PROGRESS_CHECKPOINT_PHASE_COMMITTS_PAGES 5 +#define PROGRESS_CHECKPOINT_PHASE_SUBTRANS_PAGES 6 +#define PROGRESS_CHECKPOINT_PHASE_MULTIXACT_PAGES 7 +#define PROGRESS_CHECKPOINT_PHASE_SLRU_PAGES 8 +#define PROGRESS_CHECKPOINT_PHASE_BUFFERS 9 +#define PROGRESS_CHECKPOINT_PHASE_FILE_SYNC 10 +#define PROGRESS_CHECKPOINT_PHASE_TWO_PHASE 11 +#define PROGRESS_CHECKPOINT_PHASE_OLD_XLOG_RECYCLE 12 +#define PROGRESS_CHECKPOINT_PHASE_FINALIZE 13 + #endif diff --git a/src/include/utils/backend_progress.h b/src/include/utils/backend_progress.h index 47bf8029b0..02d51fb948 100644 --- a/src/include/utils/backend_progress.h +++ b/src/include/utils/backend_progress.h @@ -27,7 +27,8 @@ typedef enum ProgressCommandType PROGRESS_COMMAND_CLUSTER, PROGRESS_COMMAND_CREATE_INDEX, PROGRESS_COMMAND_BASEBACKUP, - PROGRESS_COMMAND_COPY + PROGRESS_COMMAND_COPY, + PROGRESS_COMMAND_CHECKPOINT } ProgressCommandType; #define PGSTAT_NUM_PROGRESS_PARAM 20 diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 1420288d67..fe6e31ca27 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1897,6 +1897,39 @@ pg_stat_progress_basebackup| SELECT s.pid, s.param4 AS tablespaces_total, s.param5 AS tablespaces_streamed FROM pg_stat_get_progress_info('BASEBACKUP'::text) s(pid, datid, relid, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20); +pg_stat_progress_checkpoint| SELECT s.pid, + pg_stat_get_progress_checkpoint_type(s.param1) AS type, + pg_stat_get_progress_checkpoint_kind(s.param2) AS kind, + ( SELECT ('0/0'::pg_lsn + ( + CASE + WHEN (stat.lsn_int64 < 0) THEN pow((2)::numeric, (64)::numeric) + ELSE (0)::numeric + END + (stat.lsn_int64)::numeric)) + FROM ( SELECT s.param3) stat(lsn_int64)) AS start_lsn, + pg_stat_get_progress_checkpoint_elapsed(s.param4) AS elapsed_time, + CASE s.param5 + WHEN 0 THEN 'initializing'::text + WHEN 1 THEN 'checkpointing replication slots'::text + WHEN 2 THEN 'checkpointing snapshots'::text + WHEN 3 THEN 'checkpointing logical rewrite mappings'::text + WHEN 4 THEN 'checkpointing CLOG pages'::text + WHEN 5 THEN 'checkpointing CommitTs pages'::text + WHEN 6 THEN 'checkpointing SUBTRANS pages'::text + WHEN 7 THEN 'checkpointing MULTIXACT pages'::text + WHEN 8 THEN 'checkpointing SLRU pages'::text + WHEN 9 THEN 'checkpointing buffers'::text + WHEN 10 THEN 'performing sync requests'::text + WHEN 11 THEN 'performing two phase checkpoint'::text + WHEN 12 THEN 'recycling old XLOG files'::text + WHEN 13 THEN 'Finalizing'::text + ELSE NULL::text + END AS phase, + s.param6 AS total_buffer_writes, + s.param7 AS buffers_processed, + s.param8 AS buffers_written, + s.param9 AS total_file_syncs, + s.param10 AS files_synced + FROM pg_stat_get_progress_info('CHECKPOINT'::text) s(pid, datid, relid, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20); pg_stat_progress_cluster| SELECT s.pid, s.datid, d.datname, -- 2.25.1