On Wed, Sep 14, 2011 at 6:21 PM, Kyotaro HORIGUCHI
<horiguchi.kyot...@oss.ntt.co.jp> wrote:
> Hi, This is a review for pg_last_xact_insert_timestamp patch.
> (https://commitfest.postgresql.org/action/patch_view?id=634)

Thanks for the review!

> Q1: The shmem entry for timestamp is not initialized on
> allocating. Is this OK? (I don't know that for OSs other than
> Linux) And zeroing double field is OK for all OSs?

CreateSharedBackendStatus() initializes that shmem entries by doing
MemSet(BackendStatusArray, 0, size). You think this is not enough?

> Nevertheless this is ok for all OSs, I don't know whether
> initializing TimestampTz(double, int64 is ok) field with 8 bytes
> zeros is OK or not, for all platforms. (It is ok for
> IEEE754-binary64).

Which code are you concerned about?

> == Modification detection protocol in pgstat.c
>
> In pgstat_report_xact_end_timestamp, `beentry->st_changecount
> protocol' is used. It is for avoiding reading halfway-updated
> beentry as described in pgstat.h. Meanwhile,
> beentry->st_xact_end_timestamp is not read or (re-)initialized in
> pgstat.c and xlog.c reads only this field of whole beentry and
> st_changecount is not get cared here..

No, st_changecount is used to read st_xact_end_timestamp.
st_xact_end_timestamp is read from the shmem to the local memory
in pgstat_read_current_status(), and this function always checks
st_changecount when reading the shmem value.

> == Code duplication in xact.c
>
> in xact.c, same lines inserted into the end of both IF and ELSE
> blocks.
>
> xact.c:1047>    pgstat_report_xact_end_timestamp(xlrec.xact_time);
> xact.c:1073>    pgstat_report_xact_end_timestamp(xlrec.xact_time);
>
> These two lines refer to xlrec.xact_time, both of which comes
> from xactStopTimestamp freezed at xact.c:986
>
> xact.c:986>     SetCurrentTransactionStopTimestamp();
> xact.c:1008>    xlrec.xact_time = xactStopTimestamp;
> xact.c:1051>    xlrec.xact_time = xactStopTimestamp;
>
> I think it is better to move this line to just after this ELSE
> block using xactStopTimestamp instead of xlrec.xact_time.

Okay, I've changed the patch in that way.

Regards,

-- 
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 13996,14001 **** SELECT set_config('log_statement_stats', 'off', false);
--- 13996,14004 ----
      <primary>pg_current_xlog_location</primary>
     </indexterm>
     <indexterm>
+     <primary>pg_last_xact_insert_timestamp</primary>
+    </indexterm>
+    <indexterm>
      <primary>pg_start_backup</primary>
     </indexterm>
     <indexterm>
***************
*** 14049,14054 **** SELECT set_config('log_statement_stats', 'off', false);
--- 14052,14064 ----
        </row>
        <row>
         <entry>
+         <literal><function>pg_last_xact_insert_timestamp()</function></literal>
+         </entry>
+        <entry><type>timestamp with time zone</type></entry>
+        <entry>Get last transaction log insert time stamp</entry>
+       </row>
+       <row>
+        <entry>
          <literal><function>pg_start_backup(<parameter>label</> <type>text</> <optional>, <parameter>fast</> <type>boolean</> </optional>)</function></literal>
          </entry>
         <entry><type>text</type></entry>
***************
*** 14175,14180 **** postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
--- 14185,14197 ----
     </para>
  
     <para>
+     <function>pg_last_xact_insert_timestamp</> displays the time stamp of last inserted
+     transaction. This is the time at which the commit or abort WAL record for that transaction.
+     If there has been no transaction committed or aborted yet since the server has started,
+     this function returns NULL.
+    </para>
+ 
+    <para>
      For details about proper usage of these functions, see
      <xref linkend="continuous-archiving">.
     </para>
*** a/doc/src/sgml/high-availability.sgml
--- b/doc/src/sgml/high-availability.sgml
***************
*** 867,872 **** primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
--- 867,881 ----
       <command>ps</> command (see <xref linkend="monitoring-ps"> for details).
      </para>
      <para>
+      You can also calculate the lag in time stamp by comparing the last
+      WAL insert time stamp on the primary with the last WAL replay
+      time stamp on the standby. They can be retrieved using
+      <function>pg_last_xact_insert_timestamp</> on the primary and
+      the <function>pg_last_xact_replay_timestamp</> on the standby,
+      respectively (see <xref linkend="functions-admin-backup-table"> and
+      <xref linkend="functions-recovery-info-table"> for details).
+     </para>
+     <para>
       You can retrieve a list of WAL sender processes via the
       <link linkend="monitoring-stats-views-table">
       <literal>pg_stat_replication</></link> view. Large differences between
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
***************
*** 1066,1071 **** RecordTransactionCommit(void)
--- 1066,1074 ----
  
  			(void) XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT_COMPACT, rdata);
  		}
+ 
+ 		/* Save timestamp of latest transaction commit record */
+ 		pgstat_report_xact_end_timestamp(xactStopTimestamp);
  	}
  
  	/*
***************
*** 1434,1439 **** RecordTransactionAbort(bool isSubXact)
--- 1437,1445 ----
  
  	(void) XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);
  
+ 	/* Save timestamp of latest transaction abort record */
+ 	pgstat_report_xact_end_timestamp(xlrec.xact_time);
+ 
  	/*
  	 * Report the latest async abort LSN, so that the WAL writer knows to
  	 * flush this abort. There's nothing to be gained by delaying this, since
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 5867,5872 **** pg_is_xlog_replay_paused(PG_FUNCTION_ARGS)
--- 5867,5907 ----
  }
  
  /*
+  * Returns timestamp of latest inserted commit/abort record.
+  *
+  * If there has been no transaction committed or aborted yet since
+  * the server has started, this function returns NULL.
+  */
+ Datum
+ pg_last_xact_insert_timestamp(PG_FUNCTION_ARGS)
+ {
+ 	TimestampTz result = 0;
+ 	TimestampTz	xtime;
+ 	PgBackendStatus *beentry;
+ 	int		i;
+ 
+ 	if (RecoveryInProgress())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ 				 errmsg("recovery is in progress"),
+ 				 errhint("WAL control functions cannot be executed during recovery.")));
+ 
+ 	beentry = pgstat_fetch_all_beentry();
+ 
+ 	for (i = 0; i < MaxBackends; i++, beentry++)
+ 	{
+ 		xtime = beentry->st_xact_end_timestamp;
+ 		if (result < xtime)
+ 			result = xtime;
+ 	}
+ 
+ 	if (result == 0)
+ 		PG_RETURN_NULL();
+ 
+ 	PG_RETURN_TIMESTAMPTZ(result);
+ }
+ 
+ /*
   * Save timestamp of latest processed commit/abort record.
   *
   * We keep this in XLogCtl, not a simple static variable, so that it can be
*** a/src/backend/postmaster/pgstat.c
--- b/src/backend/postmaster/pgstat.c
***************
*** 254,260 **** static PgStat_StatTabEntry *pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry,
  static void pgstat_write_statsfile(bool permanent);
  static HTAB *pgstat_read_statsfile(Oid onlydb, bool permanent);
  static void backend_read_statsfile(void);
! static void pgstat_read_current_status(void);
  
  static void pgstat_send_tabstat(PgStat_MsgTabstat *tsmsg);
  static void pgstat_send_funcstats(void);
--- 254,260 ----
  static void pgstat_write_statsfile(bool permanent);
  static HTAB *pgstat_read_statsfile(Oid onlydb, bool permanent);
  static void backend_read_statsfile(void);
! static void pgstat_read_current_status(bool all);
  
  static void pgstat_send_tabstat(PgStat_MsgTabstat *tsmsg);
  static void pgstat_send_funcstats(void);
***************
*** 2173,2179 **** pgstat_fetch_stat_funcentry(Oid func_id)
  PgBackendStatus *
  pgstat_fetch_stat_beentry(int beid)
  {
! 	pgstat_read_current_status();
  
  	if (beid < 1 || beid > localNumBackends)
  		return NULL;
--- 2173,2179 ----
  PgBackendStatus *
  pgstat_fetch_stat_beentry(int beid)
  {
! 	pgstat_read_current_status(false);
  
  	if (beid < 1 || beid > localNumBackends)
  		return NULL;
***************
*** 2192,2202 **** pgstat_fetch_stat_beentry(int beid)
  int
  pgstat_fetch_stat_numbackends(void)
  {
! 	pgstat_read_current_status();
  
  	return localNumBackends;
  }
  
  /*
   * ---------
   * pgstat_fetch_global() -
--- 2192,2220 ----
  int
  pgstat_fetch_stat_numbackends(void)
  {
! 	pgstat_read_current_status(false);
  
  	return localNumBackends;
  }
  
+ /* ----------
+  * pgstat_fetch_all_beentry() -
+  *
+  *	Support function for the SQL-callable pgstat* functions. Returns
+  *	our local copy of all backend entries.
+  *
+  *	NB: caller is responsible for a check if the user is permitted to see
+  *	this info (especially the querystring).
+  * ----------
+  */
+ PgBackendStatus *
+ pgstat_fetch_all_beentry(void)
+ {
+ 	pgstat_read_current_status(true);
+ 
+ 	return localBackendStatusTable;
+ }
+ 
  /*
   * ---------
   * pgstat_fetch_global() -
***************
*** 2414,2419 **** pgstat_bestart(void)
--- 2432,2442 ----
  	beentry->st_appname[NAMEDATALEN - 1] = '\0';
  	beentry->st_activity[pgstat_track_activity_query_size - 1] = '\0';
  
+ 	/*
+ 	 * Don't reset st_xact_end_timestamp because the previous value can still
+ 	 * be referenced to calculate the latest transaction insert timestamp.
+ 	 */
+ 
  	beentry->st_changecount++;
  	Assert((beentry->st_changecount & 1) == 0);
  
***************
*** 2560,2565 **** pgstat_report_xact_timestamp(TimestampTz tstamp)
--- 2583,2611 ----
  	Assert((beentry->st_changecount & 1) == 0);
  }
  
+ /*
+  * Report last transaction end timestamp as the specified value.
+  * Zero means there is no finished transaction.
+  */
+ void
+ pgstat_report_xact_end_timestamp(TimestampTz tstamp)
+ {
+ 	volatile PgBackendStatus *beentry = MyBEEntry;
+ 
+ 	if (!pgstat_track_activities || !beentry)
+ 		return;
+ 
+ 	/*
+ 	 * Update my status entry, following the protocol of bumping
+ 	 * st_changecount before and after.  We use a volatile pointer here to
+ 	 * ensure the compiler doesn't try to get cute.
+ 	 */
+ 	beentry->st_changecount++;
+ 	beentry->st_xact_end_timestamp = tstamp;
+ 	beentry->st_changecount++;
+ 	Assert((beentry->st_changecount & 1) == 0);
+ }
+ 
  /* ----------
   * pgstat_report_waiting() -
   *
***************
*** 2590,2600 **** pgstat_report_waiting(bool waiting)
   * pgstat_read_current_status() -
   *
   *	Copy the current contents of the PgBackendStatus array to local memory,
!  *	if not already done in this transaction.
   * ----------
   */
  static void
! pgstat_read_current_status(void)
  {
  	volatile PgBackendStatus *beentry;
  	PgBackendStatus *localtable;
--- 2636,2647 ----
   * pgstat_read_current_status() -
   *
   *	Copy the current contents of the PgBackendStatus array to local memory,
!  *	if not already done in this transaction. If all is true, the local
!  *	array includes all entries. Otherwise, it includes only valid ones.
   * ----------
   */
  static void
! pgstat_read_current_status(bool all)
  {
  	volatile PgBackendStatus *beentry;
  	PgBackendStatus *localtable;
***************
*** 2636,2642 **** pgstat_read_current_status(void)
  			int			save_changecount = beentry->st_changecount;
  
  			localentry->st_procpid = beentry->st_procpid;
! 			if (localentry->st_procpid > 0)
  			{
  				memcpy(localentry, (char *) beentry, sizeof(PgBackendStatus));
  
--- 2683,2689 ----
  			int			save_changecount = beentry->st_changecount;
  
  			localentry->st_procpid = beentry->st_procpid;
! 			if (localentry->st_procpid > 0 || all)
  			{
  				memcpy(localentry, (char *) beentry, sizeof(PgBackendStatus));
  
***************
*** 2659,2666 **** pgstat_read_current_status(void)
  		}
  
  		beentry++;
! 		/* Only valid entries get included into the local array */
! 		if (localentry->st_procpid > 0)
  		{
  			localentry++;
  			localappname += NAMEDATALEN;
--- 2706,2713 ----
  		}
  
  		beentry++;
! 		/* Only valid entries get included into the local array if all is false */
! 		if (localentry->st_procpid > 0 || all)
  		{
  			localentry++;
  			localappname += NAMEDATALEN;
*** a/src/include/access/xlog_internal.h
--- b/src/include/access/xlog_internal.h
***************
*** 272,277 **** extern Datum pg_current_xlog_location(PG_FUNCTION_ARGS);
--- 272,278 ----
  extern Datum pg_current_xlog_insert_location(PG_FUNCTION_ARGS);
  extern Datum pg_last_xlog_receive_location(PG_FUNCTION_ARGS);
  extern Datum pg_last_xlog_replay_location(PG_FUNCTION_ARGS);
+ extern Datum pg_last_xact_insert_timestamp(PG_FUNCTION_ARGS);
  extern Datum pg_last_xact_replay_timestamp(PG_FUNCTION_ARGS);
  extern Datum pg_xlogfile_name_offset(PG_FUNCTION_ARGS);
  extern Datum pg_xlogfile_name(PG_FUNCTION_ARGS);
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 2869,2874 **** DATA(insert OID = 2850 ( pg_xlogfile_name_offset	PGNSP PGUID 12 1 0 0 0 f f f t
--- 2869,2876 ----
  DESCR("xlog filename and byte offset, given an xlog location");
  DATA(insert OID = 2851 ( pg_xlogfile_name			PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 25 "25" _null_ _null_ _null_ _null_ pg_xlogfile_name _null_ _null_ _null_ ));
  DESCR("xlog filename, given an xlog location");
+ DATA(insert OID = 3831 ( pg_last_xact_insert_timestamp	PGNSP PGUID 12 1 0 0 0 f f f t f v 0 0 1184 "" _null_ _null_ _null_ _null_ pg_last_xact_insert_timestamp _null_ _null_ _null_ ));
+ DESCR("timestamp of last insert xact");
  
  DATA(insert OID = 3810 (  pg_is_in_recovery		PGNSP PGUID 12 1 0 0 0 f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_is_in_recovery _null_ _null_ _null_ ));
  DESCR("true if server is in recovery");
*** a/src/include/pgstat.h
--- b/src/include/pgstat.h
***************
*** 623,628 **** typedef struct PgBackendStatus
--- 623,631 ----
  	TimestampTz st_xact_start_timestamp;
  	TimestampTz st_activity_start_timestamp;
  
+ 	/* Time when last transaction ended */
+ 	TimestampTz st_xact_end_timestamp;
+ 
  	/* Database OID, owning user's OID, connection client address */
  	Oid			st_databaseid;
  	Oid			st_userid;
***************
*** 718,723 **** extern void pgstat_bestart(void);
--- 721,727 ----
  extern void pgstat_report_activity(const char *cmd_str);
  extern void pgstat_report_appname(const char *appname);
  extern void pgstat_report_xact_timestamp(TimestampTz tstamp);
+ extern void pgstat_report_xact_end_timestamp(TimestampTz tstamp);
  extern void pgstat_report_waiting(bool waiting);
  extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
  
***************
*** 795,800 **** extern void pgstat_send_bgwriter(void);
--- 799,805 ----
  extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid);
  extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid);
  extern PgBackendStatus *pgstat_fetch_stat_beentry(int beid);
+ extern PgBackendStatus *pgstat_fetch_all_beentry(void);
  extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
  extern int	pgstat_fetch_stat_numbackends(void);
  extern PgStat_GlobalStats *pgstat_fetch_global(void);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to