On 11.12.2019 7:26, Kyotaro Horiguchi wrote:
Still I'm not sure non-atomic write is acceptable, but I agree on the necessity of updating it during a transaction. Couldn't we update shared stats every n bytes (XLOG_BLCKSZ or such) or every command end? I think we should refrain from inserting an instruction within the WALInsertLock section, but I'm not sure which is better between "var += var" within the section and "if (inserted) var += var;" outside. If we can ignore the possitbility of the case where xlogswitch is omitted, the "if (inserted)" is not needed.
I think that 32-bit Postgres installations are really exotic, but I agree that showing incorrect result (even with very small probability) is not acceptable behavior in this case. I attached new versoin of the patch with use pg_atomic_write_u64 for updating walWritten field. As far as at 64-bit systems, pg_atomic_write_u64and pg_atomic_read_u64 are translated to ordinary memory access, them should not have some negative
impact on performance. -- Konstantin Knizhnik Postgres Professional: http://www.postgrespro.com The Russian Postgres Company
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 5f0ee50..6a4b209 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -1486,6 +1486,9 @@ CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata, currpos = GetXLogBuffer(CurrPos); freespace = INSERT_FREESPACE(CurrPos); + /* Accumulate amount of data written to WAL for pg_xact_activity */ + pg_atomic_write_u64(&MyProc->walWritten, pg_atomic_read_u64(&MyProc->walWritten) + write_len); + /* * there should be enough space for at least the first field (xl_tot_len) * on this page. diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 000cff3..037d313 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -758,6 +758,9 @@ CREATE VIEW pg_stat_activity AS LEFT JOIN pg_database AS D ON (S.datid = D.oid) LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid); +CREATE VIEW pg_stat_wal_activity AS + SELECT a.*,pg_stat_get_wal_activity(a.pid) as wal_written FROM pg_stat_activity a; + CREATE VIEW pg_stat_replication AS SELECT S.pid, diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index fff0628..c9a63a1 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -390,6 +390,8 @@ InitProcess(void) MyPgXact->xid = InvalidTransactionId; MyPgXact->xmin = InvalidTransactionId; MyProc->pid = MyProcPid; + pg_atomic_init_u64(&MyProc->walWritten, 0); + /* backendId, databaseId and roleId will be filled in later */ MyProc->backendId = InvalidBackendId; MyProc->databaseId = InvalidOid; diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 05240bf..1745815 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -919,6 +919,22 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) Datum +pg_stat_get_wal_activity(PG_FUNCTION_ARGS) +{ + int32 pid = PG_GETARG_INT32(0); + PGPROC* proc = BackendPidGetProc(pid); + if (proc == NULL) + { + proc = AuxiliaryPidGetProc(pid); + } + if (proc == NULL) + PG_RETURN_NULL(); + else + PG_RETURN_INT64(pg_atomic_read_u64(&proc->walWritten)); +} + + +Datum pg_backend_pid(PG_FUNCTION_ARGS) { PG_RETURN_INT32(MyProcPid); diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index b759b15..6d31afd 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5152,6 +5152,10 @@ 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}', prosrc => 'pg_stat_get_activity' }, +{ oid => '2121', descr => 'statistics: WAL activity', + proname => 'pg_stat_get_wal_activity', provolatile => 's', proisstrict => 't', + proparallel => 'r', prorettype => 'int8', proargtypes => 'int4', + prosrc => 'pg_stat_get_wal_activity' }, { oid => '3318', descr => 'statistics: information about progress of backends running maintenance command', proname => 'pg_stat_get_progress_info', prorows => '100', proretset => 't', diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 281e1db..3aa2efb 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -203,6 +203,11 @@ struct PGPROC PGPROC *lockGroupLeader; /* lock group leader, if I'm a member */ dlist_head lockGroupMembers; /* list of members, if I'm a leader */ dlist_node lockGroupLink; /* my member link, if I'm a member */ + + /* + * Amount of data written to the WAL by this process + */ + pg_atomic_uint64 walWritten; }; /* NOTE: "typedef struct PGPROC PGPROC" appears in storage/lock.h. */