aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/transam/xact.c4
-rw-r--r--src/backend/commands/vacuumlazy.c4
-rw-r--r--src/backend/postmaster/pgstat.c73
-rw-r--r--src/backend/utils/adt/pgstatfuncs.c103
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_proc.h2
-rw-r--r--src/include/pgstat.h30
7 files changed, 217 insertions, 1 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index b0d5440ca33..b491735d2e2 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -2451,6 +2451,9 @@ AbortTransaction(void)
AbortBufferIO();
UnlockBuffers();
+ /* Clear command progress indicator */
+ pgstat_progress_end_command();
+
/* Reset WAL record construction state */
XLogResetInsertion();
@@ -4540,6 +4543,7 @@ AbortSubTransaction(void)
AbortBufferIO();
UnlockBuffers();
+ pgstat_progress_end_command();
/* Reset WAL record construction state */
XLogResetInsertion();
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index 363b2d0d10c..3bed8003627 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -207,6 +207,9 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
else
elevel = DEBUG2;
+ pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM,
+ RelationGetRelid(onerel));
+
vac_strategy = bstrategy;
vacuum_set_xid_limits(onerel,
@@ -320,6 +323,7 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
onerel->rd_rel->relisshared,
new_live_tuples,
vacrelstats->new_dead_tuples);
+ pgstat_progress_end_command();
/* and log the action if appropriate */
if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index da768c60297..ce5da3e292e 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2731,6 +2731,13 @@ pgstat_bestart(void)
beentry->st_clienthostname[NAMEDATALEN - 1] = '\0';
beentry->st_appname[NAMEDATALEN - 1] = '\0';
beentry->st_activity[pgstat_track_activity_query_size - 1] = '\0';
+ beentry->st_progress_command = PROGRESS_COMMAND_INVALID;
+ beentry->st_progress_command_target = InvalidOid;
+ /*
+ * we don't zero st_progress_param here to save cycles; nobody should
+ * examine it until st_progress_command has been set to something other
+ * than PROGRESS_COMMAND_INVALID
+ */
pgstat_increment_changecount_after(beentry);
@@ -2851,6 +2858,72 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
pgstat_increment_changecount_after(beentry);
}
+/*-----------
+ * pgstat_progress_start_command() -
+ *
+ * Set st_command in own backend entry. Also, zero-initialize
+ * st_progress_param array.
+ *-----------
+ */
+void
+pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
+{
+ volatile PgBackendStatus *beentry = MyBEEntry;
+
+ if (!beentry || !pgstat_track_activities)
+ return;
+
+ pgstat_increment_changecount_before(beentry);
+ beentry->st_progress_command = cmdtype;
+ beentry->st_progress_command_target = relid;
+ MemSet(&beentry->st_progress_param, 0, sizeof(beentry->st_progress_param));
+ pgstat_increment_changecount_after(beentry);
+}
+
+/*-----------
+ * pgstat_progress_update_param() -
+ *
+ * Update index'th member in st_progress_param[] of own backend entry.
+ *-----------
+ */
+void
+pgstat_progress_update_param(int index, int64 val)
+{
+ volatile PgBackendStatus *beentry = MyBEEntry;
+
+ Assert(index >= 0 && index < PGSTAT_NUM_PROGRESS_PARAM);
+
+ if (!beentry || !pgstat_track_activities)
+ return;
+
+ pgstat_increment_changecount_before(beentry);
+ beentry->st_progress_param[index] = val;
+ pgstat_increment_changecount_after(beentry);
+}
+
+/*-----------
+ * pgstat_progress_end_command() -
+ *
+ * Update index'th member in st_progress_param[] of own backend entry.
+ *-----------
+ */
+void
+pgstat_progress_end_command(void)
+{
+ volatile PgBackendStatus *beentry = MyBEEntry;
+
+ if (!beentry)
+ return;
+ if (!pgstat_track_activities
+ && beentry->st_progress_command == PROGRESS_COMMAND_INVALID)
+ return;
+
+ pgstat_increment_changecount_before(beentry);
+ beentry->st_progress_command = PROGRESS_COMMAND_INVALID;
+ beentry->st_progress_command_target = InvalidOid;
+ pgstat_increment_changecount_after(beentry);
+}
+
/* ----------
* pgstat_report_appname() -
*
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 1b22fcc3a1a..0c790ff3ec5 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -64,6 +64,7 @@ extern Datum pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_backend_start(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_backend_client_port(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_progress_info(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_db_numbackends(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS);
@@ -525,6 +526,108 @@ pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
}
/*
+ * Returns command progress information for the named command.
+ */
+Datum
+pg_stat_get_progress_info(PG_FUNCTION_ARGS)
+{
+#define PG_STAT_GET_PROGRESS_COLS PGSTAT_NUM_PROGRESS_PARAM + 3
+ int num_backends = pgstat_fetch_stat_numbackends();
+ int curr_backend;
+ char *cmd = text_to_cstring(PG_GETARG_TEXT_PP(0));
+ ProgressCommandType cmdtype;
+ TupleDesc tupdesc;
+ Tuplestorestate *tupstore;
+ ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ MemoryContext per_query_ctx;
+ MemoryContext oldcontext;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
+
+ /* Build a tuple descriptor for our result type */
+ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+ elog(ERROR, "return type must be a row type");
+
+ /* Translate command name into command type code. */
+ if (pg_strcasecmp(cmd, "VACUUM") == 0)
+ cmdtype = PROGRESS_COMMAND_VACUUM;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid command name: \"%s\"", cmd)));
+
+ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+ oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+ tupstore = tuplestore_begin_heap(true, false, work_mem);
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+ MemoryContextSwitchTo(oldcontext);
+
+ /* 1-based index */
+ for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
+ {
+ LocalPgBackendStatus *local_beentry;
+ PgBackendStatus *beentry;
+ Datum values[PG_STAT_GET_PROGRESS_COLS];
+ bool nulls[PG_STAT_GET_PROGRESS_COLS];
+ int i;
+
+ MemSet(values, 0, sizeof(values));
+ MemSet(nulls, 0, sizeof(nulls));
+
+ local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
+
+ if (!local_beentry)
+ continue;
+
+ beentry = &local_beentry->backendStatus;
+
+ /*
+ * Report values for only those backends which are running the given
+ * command.
+ */
+ if (!beentry || beentry->st_progress_command != cmdtype)
+ continue;
+
+ /* Value available to all callers */
+ values[0] = Int32GetDatum(beentry->st_procpid);
+ values[1] = ObjectIdGetDatum(beentry->st_databaseid);
+
+ /* show rest of the values including relid only to role members */
+ if (has_privs_of_role(GetUserId(), beentry->st_userid))
+ {
+ values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
+ for(i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
+ values[i+3] = UInt32GetDatum(beentry->st_progress_param[i]);
+ }
+ else
+ {
+ nulls[2] = true;
+ for (i = 1; i < PGSTAT_NUM_PROGRESS_PARAM + 1; i++)
+ nulls[i+3] = true;
+ }
+
+ tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+ }
+
+ /* clean up and return the tuplestore */
+ tuplestore_donestoring(tupstore);
+
+ return (Datum) 0;
+}
+
+/*
* Returns activity of PG backends.
*/
Datum
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 16cd304f1b7..62868915dc5 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201603051
+#define CATALOG_VERSION_NO 201603091
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index cbbb8835c46..a0f821ac684 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2710,6 +2710,8 @@ DATA(insert OID = 1936 ( pg_stat_get_backend_idset PGNSP PGUID 12 1 100 0 0 f
DESCR("statistics: currently active backend IDs");
DATA(insert OID = 2022 ( pg_stat_get_activity PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
DESCR("statistics: information about currently active backends");
+DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "25" "{25,23,26,26,20,20,20,20,20,20,20,20,20,20}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{cmdtype,pid,datid,relid,param1,param2,param3,param4,param5,param6,param7,param8,param9,param10}" _null_ _null_ pg_stat_get_progress_info _null_ _null_ _null_ ));
+DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,23,25}" "{o,o,o,o,o,o,o,o}" "{pid,state,sent_location,write_location,flush_location,replay_location,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 65e968eff6d..eae6a0fee29 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -696,6 +696,18 @@ typedef enum BackendState
} BackendState;
/* ----------
+ * Command type for progress reporting purposes
+ * ----------
+ */
+typedef enum ProgressCommandType
+{
+ PROGRESS_COMMAND_INVALID,
+ PROGRESS_COMMAND_VACUUM,
+} ProgressCommandType;
+
+#define PGSTAT_NUM_PROGRESS_PARAM 10
+
+/* ----------
* Shared-memory data structures
* ----------
*/
@@ -776,6 +788,19 @@ typedef struct PgBackendStatus
/* current command string; MUST be null-terminated */
char *st_activity;
+
+ /*
+ * Command progress reporting. Any command which wishes can advertise
+ * that it is running by setting st_progress_command,
+ * st_progress_command_target, and st_progress_command[].
+ * st_progress_command_target should be the OID of the relation which the
+ * command targets (we assume there's just one, as this is meant for
+ * utility commands), but the meaning of each element in the
+ * st_progress_param array is command-specific.
+ */
+ ProgressCommandType st_progress_command;
+ Oid st_progress_command_target;
+ int64 st_progress_param[PGSTAT_NUM_PROGRESS_PARAM];
} PgBackendStatus;
/*
@@ -936,6 +961,11 @@ extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
int buflen);
+extern void pgstat_progress_start_command(ProgressCommandType cmdtype,
+ Oid relid);
+extern void pgstat_progress_update_param(int index, int64 val);
+extern void pgstat_progress_end_command(void);
+
extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id);
extern PgStat_BackendFunctionEntry *find_funcstat_entry(Oid func_id);