Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b6fb647

Browse files
committed
Add a generic command progress reporting facility.
Using this facility, any utility command can report the target relation upon which it is operating, if there is one, and up to 10 64-bit counters; the intent of this is that users should be able to figure out what a utility command is doing without having to resort to ugly hacks like attaching strace to a backend. As a demonstration, this adds very crude reporting to lazy vacuum; we just report the target relation and nothing else. A forthcoming patch will make VACUUM report a bunch of additional data that will make this much more interesting. But this gets the basic framework in place. Vinayak Pokale, Rahila Syed, Amit Langote, Robert Haas, reviewed by Kyotaro Horiguchi, Jim Nasby, Thom Brown, Masahiko Sawada, Fujii Masao, and Masanori Oyama.
1 parent 8776c15 commit b6fb647

File tree

7 files changed

+217
-1
lines changed

7 files changed

+217
-1
lines changed

src/backend/access/transam/xact.c

+4
Original file line numberDiff line numberDiff line change
@@ -2451,6 +2451,9 @@ AbortTransaction(void)
24512451
AbortBufferIO();
24522452
UnlockBuffers();
24532453

2454+
/* Clear command progress indicator */
2455+
pgstat_progress_end_command();
2456+
24542457
/* Reset WAL record construction state */
24552458
XLogResetInsertion();
24562459

@@ -4540,6 +4543,7 @@ AbortSubTransaction(void)
45404543

45414544
AbortBufferIO();
45424545
UnlockBuffers();
4546+
pgstat_progress_end_command();
45434547

45444548
/* Reset WAL record construction state */
45454549
XLogResetInsertion();

src/backend/commands/vacuumlazy.c

+4
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
207207
else
208208
elevel = DEBUG2;
209209

210+
pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM,
211+
RelationGetRelid(onerel));
212+
210213
vac_strategy = bstrategy;
211214

212215
vacuum_set_xid_limits(onerel,
@@ -320,6 +323,7 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
320323
onerel->rd_rel->relisshared,
321324
new_live_tuples,
322325
vacrelstats->new_dead_tuples);
326+
pgstat_progress_end_command();
323327

324328
/* and log the action if appropriate */
325329
if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)

src/backend/postmaster/pgstat.c

+73
Original file line numberDiff line numberDiff line change
@@ -2731,6 +2731,13 @@ pgstat_bestart(void)
27312731
beentry->st_clienthostname[NAMEDATALEN - 1] = '\0';
27322732
beentry->st_appname[NAMEDATALEN - 1] = '\0';
27332733
beentry->st_activity[pgstat_track_activity_query_size - 1] = '\0';
2734+
beentry->st_progress_command = PROGRESS_COMMAND_INVALID;
2735+
beentry->st_progress_command_target = InvalidOid;
2736+
/*
2737+
* we don't zero st_progress_param here to save cycles; nobody should
2738+
* examine it until st_progress_command has been set to something other
2739+
* than PROGRESS_COMMAND_INVALID
2740+
*/
27342741

27352742
pgstat_increment_changecount_after(beentry);
27362743

@@ -2851,6 +2858,72 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
28512858
pgstat_increment_changecount_after(beentry);
28522859
}
28532860

2861+
/*-----------
2862+
* pgstat_progress_start_command() -
2863+
*
2864+
* Set st_command in own backend entry. Also, zero-initialize
2865+
* st_progress_param array.
2866+
*-----------
2867+
*/
2868+
void
2869+
pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
2870+
{
2871+
volatile PgBackendStatus *beentry = MyBEEntry;
2872+
2873+
if (!beentry || !pgstat_track_activities)
2874+
return;
2875+
2876+
pgstat_increment_changecount_before(beentry);
2877+
beentry->st_progress_command = cmdtype;
2878+
beentry->st_progress_command_target = relid;
2879+
MemSet(&beentry->st_progress_param, 0, sizeof(beentry->st_progress_param));
2880+
pgstat_increment_changecount_after(beentry);
2881+
}
2882+
2883+
/*-----------
2884+
* pgstat_progress_update_param() -
2885+
*
2886+
* Update index'th member in st_progress_param[] of own backend entry.
2887+
*-----------
2888+
*/
2889+
void
2890+
pgstat_progress_update_param(int index, int64 val)
2891+
{
2892+
volatile PgBackendStatus *beentry = MyBEEntry;
2893+
2894+
Assert(index >= 0 && index < PGSTAT_NUM_PROGRESS_PARAM);
2895+
2896+
if (!beentry || !pgstat_track_activities)
2897+
return;
2898+
2899+
pgstat_increment_changecount_before(beentry);
2900+
beentry->st_progress_param[index] = val;
2901+
pgstat_increment_changecount_after(beentry);
2902+
}
2903+
2904+
/*-----------
2905+
* pgstat_progress_end_command() -
2906+
*
2907+
* Update index'th member in st_progress_param[] of own backend entry.
2908+
*-----------
2909+
*/
2910+
void
2911+
pgstat_progress_end_command(void)
2912+
{
2913+
volatile PgBackendStatus *beentry = MyBEEntry;
2914+
2915+
if (!beentry)
2916+
return;
2917+
if (!pgstat_track_activities
2918+
&& beentry->st_progress_command == PROGRESS_COMMAND_INVALID)
2919+
return;
2920+
2921+
pgstat_increment_changecount_before(beentry);
2922+
beentry->st_progress_command = PROGRESS_COMMAND_INVALID;
2923+
beentry->st_progress_command_target = InvalidOid;
2924+
pgstat_increment_changecount_after(beentry);
2925+
}
2926+
28542927
/* ----------
28552928
* pgstat_report_appname() -
28562929
*

src/backend/utils/adt/pgstatfuncs.c

+103
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ extern Datum pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS);
6464
extern Datum pg_stat_get_backend_start(PG_FUNCTION_ARGS);
6565
extern Datum pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS);
6666
extern Datum pg_stat_get_backend_client_port(PG_FUNCTION_ARGS);
67+
extern Datum pg_stat_get_progress_info(PG_FUNCTION_ARGS);
6768

6869
extern Datum pg_stat_get_db_numbackends(PG_FUNCTION_ARGS);
6970
extern Datum pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS);
@@ -524,6 +525,108 @@ pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
524525
}
525526
}
526527

528+
/*
529+
* Returns command progress information for the named command.
530+
*/
531+
Datum
532+
pg_stat_get_progress_info(PG_FUNCTION_ARGS)
533+
{
534+
#define PG_STAT_GET_PROGRESS_COLS PGSTAT_NUM_PROGRESS_PARAM + 3
535+
int num_backends = pgstat_fetch_stat_numbackends();
536+
int curr_backend;
537+
char *cmd = text_to_cstring(PG_GETARG_TEXT_PP(0));
538+
ProgressCommandType cmdtype;
539+
TupleDesc tupdesc;
540+
Tuplestorestate *tupstore;
541+
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
542+
MemoryContext per_query_ctx;
543+
MemoryContext oldcontext;
544+
545+
/* check to see if caller supports us returning a tuplestore */
546+
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
547+
ereport(ERROR,
548+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
549+
errmsg("set-valued function called in context that cannot accept a set")));
550+
if (!(rsinfo->allowedModes & SFRM_Materialize))
551+
ereport(ERROR,
552+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
553+
errmsg("materialize mode required, but it is not " \
554+
"allowed in this context")));
555+
556+
/* Build a tuple descriptor for our result type */
557+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
558+
elog(ERROR, "return type must be a row type");
559+
560+
/* Translate command name into command type code. */
561+
if (pg_strcasecmp(cmd, "VACUUM") == 0)
562+
cmdtype = PROGRESS_COMMAND_VACUUM;
563+
else
564+
ereport(ERROR,
565+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
566+
errmsg("invalid command name: \"%s\"", cmd)));
567+
568+
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
569+
oldcontext = MemoryContextSwitchTo(per_query_ctx);
570+
571+
tupstore = tuplestore_begin_heap(true, false, work_mem);
572+
rsinfo->returnMode = SFRM_Materialize;
573+
rsinfo->setResult = tupstore;
574+
rsinfo->setDesc = tupdesc;
575+
MemoryContextSwitchTo(oldcontext);
576+
577+
/* 1-based index */
578+
for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
579+
{
580+
LocalPgBackendStatus *local_beentry;
581+
PgBackendStatus *beentry;
582+
Datum values[PG_STAT_GET_PROGRESS_COLS];
583+
bool nulls[PG_STAT_GET_PROGRESS_COLS];
584+
int i;
585+
586+
MemSet(values, 0, sizeof(values));
587+
MemSet(nulls, 0, sizeof(nulls));
588+
589+
local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
590+
591+
if (!local_beentry)
592+
continue;
593+
594+
beentry = &local_beentry->backendStatus;
595+
596+
/*
597+
* Report values for only those backends which are running the given
598+
* command.
599+
*/
600+
if (!beentry || beentry->st_progress_command != cmdtype)
601+
continue;
602+
603+
/* Value available to all callers */
604+
values[0] = Int32GetDatum(beentry->st_procpid);
605+
values[1] = ObjectIdGetDatum(beentry->st_databaseid);
606+
607+
/* show rest of the values including relid only to role members */
608+
if (has_privs_of_role(GetUserId(), beentry->st_userid))
609+
{
610+
values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
611+
for(i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
612+
values[i+3] = UInt32GetDatum(beentry->st_progress_param[i]);
613+
}
614+
else
615+
{
616+
nulls[2] = true;
617+
for (i = 1; i < PGSTAT_NUM_PROGRESS_PARAM + 1; i++)
618+
nulls[i+3] = true;
619+
}
620+
621+
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
622+
}
623+
624+
/* clean up and return the tuplestore */
625+
tuplestore_donestoring(tupstore);
626+
627+
return (Datum) 0;
628+
}
629+
527630
/*
528631
* Returns activity of PG backends.
529632
*/

src/include/catalog/catversion.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201603051
56+
#define CATALOG_VERSION_NO 201603091
5757

5858
#endif

src/include/catalog/pg_proc.h

+2
Original file line numberDiff line numberDiff line change
@@ -2710,6 +2710,8 @@ DATA(insert OID = 1936 ( pg_stat_get_backend_idset PGNSP PGUID 12 1 100 0 0 f
27102710
DESCR("statistics: currently active backend IDs");
27112711
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_ ));
27122712
DESCR("statistics: information about currently active backends");
2713+
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_ ));
2714+
DESCR("statistics: information about progress of backends running maintenance command");
27132715
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_ ));
27142716
DESCR("statistics: information about currently active replication");
27152717
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_ ));

src/include/pgstat.h

+30
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,18 @@ typedef enum BackendState
695695
STATE_DISABLED
696696
} BackendState;
697697

698+
/* ----------
699+
* Command type for progress reporting purposes
700+
* ----------
701+
*/
702+
typedef enum ProgressCommandType
703+
{
704+
PROGRESS_COMMAND_INVALID,
705+
PROGRESS_COMMAND_VACUUM,
706+
} ProgressCommandType;
707+
708+
#define PGSTAT_NUM_PROGRESS_PARAM 10
709+
698710
/* ----------
699711
* Shared-memory data structures
700712
* ----------
@@ -776,6 +788,19 @@ typedef struct PgBackendStatus
776788

777789
/* current command string; MUST be null-terminated */
778790
char *st_activity;
791+
792+
/*
793+
* Command progress reporting. Any command which wishes can advertise
794+
* that it is running by setting st_progress_command,
795+
* st_progress_command_target, and st_progress_command[].
796+
* st_progress_command_target should be the OID of the relation which the
797+
* command targets (we assume there's just one, as this is meant for
798+
* utility commands), but the meaning of each element in the
799+
* st_progress_param array is command-specific.
800+
*/
801+
ProgressCommandType st_progress_command;
802+
Oid st_progress_command_target;
803+
int64 st_progress_param[PGSTAT_NUM_PROGRESS_PARAM];
779804
} PgBackendStatus;
780805

781806
/*
@@ -936,6 +961,11 @@ extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
936961
extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
937962
int buflen);
938963

964+
extern void pgstat_progress_start_command(ProgressCommandType cmdtype,
965+
Oid relid);
966+
extern void pgstat_progress_update_param(int index, int64 val);
967+
extern void pgstat_progress_end_command(void);
968+
939969
extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id);
940970
extern PgStat_BackendFunctionEntry *find_funcstat_entry(Oid func_id);
941971

0 commit comments

Comments
 (0)