Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1iyz8y-0004c1-TM for pgsql-hackers@arkaria.postgresql.org; Tue, 04 Feb 2020 14:25:37 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1iyz8x-0003wQ-CQ for pgsql-hackers@arkaria.postgresql.org; Tue, 04 Feb 2020 14:25:35 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1iyz8w-0003wJ-RY for pgsql-hackers@lists.postgresql.org; Tue, 04 Feb 2020 14:25:35 +0000 Received: from mail-wr1-x429.google.com ([2a00:1450:4864:20::429]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1iyz8s-0003IA-TO for pgsql-hackers@lists.postgresql.org; Tue, 04 Feb 2020 14:25:33 +0000 Received: by mail-wr1-x429.google.com with SMTP id w12so12383310wrt.2 for ; Tue, 04 Feb 2020 06:25:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=0sZzPhC0zpwug734o/Qomc5fnFuNZQqtZMDhFp0Y4pQ=; b=mJqroq2KxhM8CYkWdg5Jbjuwr7p+RnDCsif17VhM88sMzv2TRwGPlG6qW97OVfTcBo 8iZ48SO/tjtnGPqbkx6hIrHG7or00UWfPcbQBhTYOzyrFn71VT36elFroEwe/0RlW8uB W0r1b0yQvpGMPtV38YrczwyC1EG0gfAOyGA0Wlz57ZraPcV5pMh/OlrSJ4DwWdb+IJNU 0XfwUqzyNbB9WmHI7Y52xIb3h0jJVHhXlCTaUXA762dvkF8BoEQlQc1p+/bDLrTKcCax 4tQRX6+BBZob9a1Yg1tF3s7cqD3OtvAwbW06XmRX/+bCdj9rqNqv/jzA5Cpwc8Obnr/R LXSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=0sZzPhC0zpwug734o/Qomc5fnFuNZQqtZMDhFp0Y4pQ=; b=CSskB6ByYrK68mygI6cXWVVH2oP80Ye/dONMllmymkzJ8prnnGKZnUVPudKkEvLmSW Fv5icA9EiUKVFmXATFFNbEMwNUnYdd1uOryMbq88DH1PKQtyPNaeWTbT0VzGIbQAD52V 8qjlIRGVYeFNz8tT+TlItxVgQ3tXvALXw9qonTckI86UUkX0VFVfcKVP3nKRs8y4elcY +zls15gfy1NO4AVaPnvWyFro5rJSj/yt0KWzG56aakoZG9wNeUL3ld6GEqN02bWWqoM8 aN76AdtYBRq3iU5GOP2zjvFOuKl21e5T9Wh2OjxTDRv+JUCh1c+B5cCq1/CUH0kT7m8l 1iXg== X-Gm-Message-State: APjAAAUYgpLKU/QbBRUdUZzbYPgNovCdq43/VDcI2Ip5isRozNkypzjl 8nkxTGzjVuaxez1qObADQGo= X-Google-Smtp-Source: APXvYqwJJR6ruAeGuOVJYASEwbHAX9vSTAWILa9LIRMRCOPQsd9wqQW5oBS+3eAToXjBKiK4kH3unw== X-Received: by 2002:adf:ab49:: with SMTP id r9mr6159132wrc.351.1580826327886; Tue, 04 Feb 2020 06:25:27 -0800 (PST) Received: from nol ([2a01:e0a:c:bcf0:dbc8:f7e9:89ae:5cd7]) by smtp.gmail.com with ESMTPSA id v8sm30295845wrw.2.2020.02.04.06.25.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Feb 2020 06:25:25 -0800 (PST) Date: Tue, 4 Feb 2020 15:27:25 +0100 From: Julien Rouhaud To: Michael Paquier Cc: Tomas Vondra , Sergei Kornilov , Guillaume Lelarge , PostgreSQL Hackers Subject: Re: Expose lock group leader pid in pg_stat_activity Message-ID: <20200204142725.GA30965@nol> References: <20200116072727.GI3117@paquier.xyz> <20200116074912.GA98418@paquier.xyz> <20200118025102.GB230692@paquier.xyz> <20200128130910.anay3mlhaminob6w@development> <20200128135208.6tnr72gamv2dr262@development> <20200130130301.GC130922@paquier.xyz> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="9amGYk9869ThD9tj" Content-Disposition: inline In-Reply-To: <20200130130301.GC130922@paquier.xyz> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --9amGYk9869ThD9tj Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Thu, Jan 30, 2020 at 10:03:01PM +0900, Michael Paquier wrote: > On Tue, Jan 28, 2020 at 02:52:08PM +0100, Tomas Vondra wrote: > > On Tue, Jan 28, 2020 at 02:26:34PM +0100, Julien Rouhaud wrote: > >> There were already some dependencies between the rows since parallel > >> queries were added, as you could see eg. a parallel worker while no > >> query is currently active. This patch will make those corner cases > >> more obvious. > > I was reviewing the code and one thing that I was wondering is if it > would be better to make the code more defensive and return NULL when > the PID of the referenced leader is 0 or InvalidPid. However that > would mean that we have a dummy 2PC entry from PGPROC or something not > yet started, which makes no sense. So your simpler version is > actually fine. What you have here is that in the worst case you could > finish with an incorrect reference to shared memory if a PGPROC is > recycled between the moment you look for the leader field and the > moment the PID value is fetched. That's very unlikely to happen, and > I agree that it does not really justify the cost of taking extra locks > every time we scan pg_stat_activity. Ok. > > > Yeah, sure. I mean explicit dependencies, e.g. a column referencing > > values from another row, like leader_id does. > > + The leader_pid is NULL for processes not involved in parallel query. > This is missing two markups, one for "NULL" and a second for > "leader_pid". The extra "leader_pid" disappeared when I reworked the doc. I'm not sure what you meant here for NULL as I don't see any extra markup used in closeby documentation, so I hope this version is ok. > The documentation does not match the surroundings > either, so I would suggest a reformulation for the beginning: > PID of the leader process if this process is involved in parallel query. > And actually this paragraph is not completely true, because leader_pid > remains set even after one parallel query run has been finished for a > session when leader_pid = pid as lockGroupLeader is set to NULL only > once the process is stopped in ProcKill(). Oh good point, that's unfortunately not a super friendly behavior. I tried to adapt the documentation to address of all that. It's maybe slightly too verbose, but I guess that extra clarity is welcome here. > >> Should I document the possible inconsistencies? > > > > I think it's worth mentioning that as a comment in the code, say before > > the pg_stat_get_activity function. IMO we don't need to document all > > possible inconsistencies, a generic explanation is enough. > > Agreed that adding some information in the area when we look at the > PGPROC entries for wait events and such would be nice. I added some code comments to remind that we don't guarantee any consistency here. --9amGYk9869ThD9tj Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="pgsa-leader-pid-v5.diff" diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 8839699079..5e1f6c057b 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -622,6 +622,18 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser integer Process ID of this backend + + leader_pid + integer + + Process ID of the leader process if this process is or has been involved + in parallel query, or null. When a process wants to cooperate with + parallel workers, it becomes a parallel group leader, which means that + this field will be valued to its own process ID, and will remain a group + leader as long as the process exist. When a parallel worker starts up, + this field will be valued with the parallel group leader process ID. + + usesysid oid diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index c9e6060035..f681aafcf9 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -741,6 +741,7 @@ CREATE VIEW pg_stat_activity AS S.datid AS datid, D.datname AS datname, S.pid, + S.leader_pid, S.usesysid, U.rolname AS usename, S.application_name, diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 7b2da2b36f..f4bea2edd2 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -547,7 +547,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS) Datum pg_stat_get_activity(PG_FUNCTION_ARGS) { -#define PG_STAT_GET_ACTIVITY_COLS 29 +#define PG_STAT_GET_ACTIVITY_COLS 30 int num_backends = pgstat_fetch_stat_numbackends(); int curr_backend; int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0); @@ -686,33 +686,36 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) values[5] = CStringGetTextDatum(clipped_activity); pfree(clipped_activity); + nulls[29] = true; proc = BackendPidGetProc(beentry->st_procpid); + + /* + * For an auxiliary process, retrieve process info from + * AuxiliaryProcs stored in shared-memory. + */ + if (!proc && (beentry->st_backendType != B_BACKEND)) + proc = AuxiliaryPidGetProc(beentry->st_procpid); + + /* + * If we retrieved process info, display wait events and lock group + * leader info if any. To avoid extra overhead, no extra lock is + * being held, meaning that we don't guarantee consistency over the + * various rows being returned. + */ if (proc != NULL) { uint32 raw_wait_event; + PGPROC *leader; raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info); wait_event_type = pgstat_get_wait_event_type(raw_wait_event); wait_event = pgstat_get_wait_event(raw_wait_event); - } - else if (beentry->st_backendType != B_BACKEND) - { - /* - * For an auxiliary process, retrieve process info from - * AuxiliaryProcs stored in shared-memory. - */ - proc = AuxiliaryPidGetProc(beentry->st_procpid); - - if (proc != NULL) + leader = proc->lockGroupLeader; + if (leader) { - uint32 raw_wait_event; - - raw_wait_event = - UINT32_ACCESS_ONCE(proc->wait_event_info); - wait_event_type = - pgstat_get_wait_event_type(raw_wait_event); - wait_event = pgstat_get_wait_event(raw_wait_event); + values[29] = Int32GetDatum(leader->pid); + nulls[29] = false; } } diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 2228256907..226c904c04 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5175,9 +5175,9 @@ proname => 'pg_stat_get_activity', prorows => '100', proisstrict => 'f', proretset => 't', provolatile => 's', proparallel => 'r', prorettype => 'record', proargtypes => 'int4', - proallargtypes => '{int4,oid,int4,oid,text,text,text,text,text,timestamptz,timestamptz,timestamptz,timestamptz,inet,text,int4,xid,xid,text,bool,text,text,int4,bool,text,numeric,text,bool,text,bool}', - 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,o,o,o,o,o,o}', - proargnames => '{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,sslcompression,ssl_client_dn,ssl_client_serial,ssl_issuer_dn,gss_auth,gss_princ,gss_enc}', + proallargtypes => '{int4,oid,int4,oid,text,text,text,text,text,timestamptz,timestamptz,timestamptz,timestamptz,inet,text,int4,xid,xid,text,bool,text,text,int4,bool,text,numeric,text,bool,text,bool,int4}', + 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,o,o,o,o,o,o,o}', + proargnames => '{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,sslcompression,ssl_client_dn,ssl_client_serial,ssl_issuer_dn,gss_auth,gss_princ,gss_enc,leader_pid}', prosrc => 'pg_stat_get_activity' }, { oid => '3318', descr => 'statistics: information about progress of backends running maintenance command', diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 2ab2115fa1..634f8256f7 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1730,6 +1730,7 @@ pg_shmem_allocations| SELECT pg_get_shmem_allocations.name, pg_stat_activity| SELECT s.datid, d.datname, s.pid, + s.leader_pid, s.usesysid, u.rolname AS usename, s.application_name, @@ -1747,7 +1748,7 @@ pg_stat_activity| SELECT s.datid, s.backend_xmin, s.query, s.backend_type - FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc) + FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid) LEFT JOIN pg_database d ON ((s.datid = d.oid))) LEFT JOIN pg_authid u ON ((s.usesysid = u.oid))); pg_stat_all_indexes| SELECT c.oid AS relid, @@ -1851,7 +1852,7 @@ pg_stat_gssapi| SELECT s.pid, s.gss_auth AS gss_authenticated, s.gss_princ AS principal, s.gss_enc AS encrypted - FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc) + FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid) WHERE (s.client_port IS NOT NULL); pg_stat_progress_analyze| SELECT s.pid, s.datid, @@ -1984,7 +1985,7 @@ pg_stat_replication| SELECT s.pid, w.spill_txns, w.spill_count, w.spill_bytes - FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc) + FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid) JOIN pg_stat_get_wal_senders() w(pid, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, write_lag, flush_lag, replay_lag, sync_priority, sync_state, reply_time, spill_txns, spill_count, spill_bytes) ON ((s.pid = w.pid))) LEFT JOIN pg_authid u ON ((s.usesysid = u.oid))); pg_stat_ssl| SELECT s.pid, @@ -1996,7 +1997,7 @@ pg_stat_ssl| SELECT s.pid, s.ssl_client_dn AS client_dn, s.ssl_client_serial AS client_serial, s.ssl_issuer_dn AS issuer_dn - FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc) + FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid) WHERE (s.client_port IS NOT NULL); pg_stat_subscription| SELECT su.oid AS subid, su.subname, --9amGYk9869ThD9tj--