Index: src/backend/postmaster/pgstat.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/pgstat.c,v
retrieving revision 1.121
diff -c -r1.121 pgstat.c
*** src/backend/postmaster/pgstat.c	5 Mar 2006 15:58:36 -0000	1.121
--- src/backend/postmaster/pgstat.c	4 Apr 2006 19:53:36 -0000
***************
*** 28,33 ****
--- 28,34 ----
  #include <arpa/inet.h>
  #include <signal.h>
  #include <time.h>
+ #include <sys/stat.h>
  
  #include "pgstat.h"
  
***************
*** 66,77 ****
   * Timer definitions.
   * ----------
   */
! #define PGSTAT_STAT_INTERVAL	500		/* How often to write the status file;
! 										 * in milliseconds. */
  
! #define PGSTAT_DESTROY_DELAY	10000	/* How long to keep destroyed objects
  										 * known, to give delayed UDP packets
! 										 * time to arrive; in milliseconds. */
  
  #define PGSTAT_DESTROY_COUNT	(PGSTAT_DESTROY_DELAY / PGSTAT_STAT_INTERVAL)
  
--- 67,79 ----
   * Timer definitions.
   * ----------
   */
! #define PGSTAT_STAT_INTERVAL	(5*60*1000) /* How often to write the status file;
! 											 * in milliseconds. */
  
! #define PGSTAT_DESTROY_DELAY	(5*60*1000) /* How long to keep destroyed objects
  										 * known, to give delayed UDP packets
! 										 * time to arrive; in milliseconds. Must
! 										 * be at least PGSTAT_STAT_INTERVAL. */
  
  #define PGSTAT_DESTROY_COUNT	(PGSTAT_DESTROY_DELAY / PGSTAT_STAT_INTERVAL)
  
***************
*** 179,189 ****
  static void pgstat_write_statsfile(void);
  static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
  					  PgStat_StatBeEntry **betab,
! 					  int *numbackends);
  static void backend_read_statsfile(void);
  
  static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype);
  static void pgstat_send(void *msg, int len);
  
  static void pgstat_recv_bestart(PgStat_MsgBestart *msg, int len);
  static void pgstat_recv_beterm(PgStat_MsgBeterm *msg, int len);
--- 181,192 ----
  static void pgstat_write_statsfile(void);
  static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
  					  PgStat_StatBeEntry **betab,
! 					  int *numbackends, bool rewrite);
  static void backend_read_statsfile(void);
  
  static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype);
  static void pgstat_send(void *msg, int len);
+ static void pgstat_send_rewrite(void);
  
  static void pgstat_recv_bestart(PgStat_MsgBestart *msg, int len);
  static void pgstat_recv_beterm(PgStat_MsgBeterm *msg, int len);
***************
*** 1451,1456 ****
--- 1454,1477 ----
  #endif
  }
  
+ /*
+  * pgstat_send_rewrite() -
+  *
+  *	Send a command to the collector to rewrite the stats file.
+  * ----------
+  */
+ static void
+ pgstat_send_rewrite(void)
+ {
+     PgStat_MsgRewrite msg;
+ 
+ 	if (pgStatSock < 0)
+ 		return;
+ 
+ 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_REWRITE);
+ 	pgstat_send(&msg, sizeof(msg));
+ }
+ 
  
  /* ----------
   * PgstatBufferMain() -
***************
*** 1552,1557 ****
--- 1573,1579 ----
  	int			readPipe;
  	int			len = 0;
  	struct itimerval timeout;
+ 	struct itimerval canceltimeout;
  	HASHCTL		hash_ctl;
  	bool		need_timer = false;
  
***************
*** 1607,1618 ****
  	timeout.it_value.tv_sec = PGSTAT_STAT_INTERVAL / 1000;
  	timeout.it_value.tv_usec = PGSTAT_STAT_INTERVAL % 1000;
  
  	/*
  	 * Read in an existing statistics stats file or initialize the stats to
  	 * zero.
  	 */
  	pgStatRunningInCollector = true;
! 	pgstat_read_statsfile(&pgStatDBHash, InvalidOid, NULL, NULL);
  
  	/*
  	 * Create the dead backend hashtable
--- 1629,1643 ----
  	timeout.it_value.tv_sec = PGSTAT_STAT_INTERVAL / 1000;
  	timeout.it_value.tv_usec = PGSTAT_STAT_INTERVAL % 1000;
  
+ 	/* Values set to zero will cancel the active timer */
+ 	MemSet(&canceltimeout, 0, sizeof(struct itimerval));
+ 
  	/*
  	 * Read in an existing statistics stats file or initialize the stats to
  	 * zero.
  	 */
  	pgStatRunningInCollector = true;
! 	pgstat_read_statsfile(&pgStatDBHash, InvalidOid, NULL, NULL, false);
  
  	/*
  	 * Create the dead backend hashtable
***************
*** 1777,1782 ****
--- 1802,1813 ----
  					pgstat_recv_analyze((PgStat_MsgAnalyze *) &msg, nread);
  					break;
  
+ 				case PGSTAT_MTYPE_REWRITE:
+ 					need_statwrite = true;
+ 					/* Disable the timer - it will be restarted on next data update */
+ 					setitimer(ITIMER_REAL, &canceltimeout, NULL);
+ 					break;
+ 
  				default:
  					break;
  			}
***************
*** 2471,2477 ****
   */
  static void
  pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
! 					  PgStat_StatBeEntry **betab, int *numbackends)
  {
  	PgStat_StatDBEntry *dbentry;
  	PgStat_StatDBEntry dbbuf;
--- 2502,2508 ----
   */
  static void
  pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
! 					  PgStat_StatBeEntry **betab, int *numbackends, bool rewrite)
  {
  	PgStat_StatDBEntry *dbentry;
  	PgStat_StatDBEntry dbbuf;
***************
*** 2490,2495 ****
--- 2521,2591 ----
  	MemoryContext use_mcxt;
  	int			mcxt_flags;
  
+ 
+ 	if (rewrite)
+ 	{
+ 		/*
+ 		 * To force a rewrite of the stats file from the collector, send
+ 		 * a REWRITE message to the stats collector. Then wait for the file
+ 		 * to change. On Unix, we wait for the inode to change (as the file
+ 		 * is renamed into place from a different file). Win32 has no concept
+ 		 * of inodes, so we wait for the date on the file to change instead.
+ 		 * We can do this on win32 because we have high-res timing on the 
+ 		 * file dates, but we can't on unix, because it has 1sec resolution
+ 		 * on the fields in struct stat.
+ 		 */
+ 		int i;
+ #ifndef WIN32
+ 		struct stat st1, st2;
+ 
+ 		if (stat(PGSTAT_STAT_FILENAME, &st1))
+ 		{
+ 			/* Assume no file there yet */
+ 			st1.st_ino = 0;
+ 		}
+ 		st2.st_ino = 0;
+ #else
+ 		WIN32_FILE_ATTRIBUTE_DATA fd1, fd2;
+ 
+ 		if (!GetFileAttributesEx(PGSTAT_STAT_FILENAME, GetFileExInfoStandard, &fd1))
+ 		{
+ 			fd1.ftLastWriteTime.dwLowDateTime = 0;
+ 			fd1.ftLastWriteTime.dwHighDateTime = 0;
+ 		}
+ 		fd2.ftLastWriteTime.dwLowDateTime = 0;
+ 		fd2.ftLastWriteTime.dwHighDateTime = 0;
+ #endif
+ 
+ 
+ 		/* Send rewrite message */
+ 		pgstat_send_rewrite();
+ 
+ 		/* Now wait for the file to change */
+ 		for (i=0; i < 50; i++)
+ 		{
+ #ifndef WIN32
+ 			if (!stat(PGSTAT_STAT_FILENAME, &st2))
+ 			{
+ 				if (st2.st_ino != st1.st_ino)
+ 					break;
+ 			}
+ #else
+ 			if (GetFileAttributesEx(PGSTAT_STAT_FILENAME, GetFileExInfoStandard, &fd2))
+ 			{
+ 				if (fd1.ftLastWriteTime.dwLowDateTime != fd2.ftLastWriteTime.dwLowDateTime ||
+ 					fd1.ftLastWriteTime.dwHighDateTime != fd2.ftLastWriteTime.dwHighDateTime)
+ 					break;
+ 			}
+ #endif
+ 
+ 			pg_usleep(50000); 
+ 		}
+ 		if (i >= 50)
+ 			ereport(WARNING,
+ 				(errmsg("pgstat update timeout")));
+ 		/* Fallthrough and read the old file anyway - old data better than no data */
+ 	}
+ 
  	/*
  	 * If running in the collector or the autovacuum process, we use the
  	 * DynaHashCxt memory context.	If running in a backend, we use the
***************
*** 2809,2815 ****
  			return;
  		Assert(!pgStatRunningInCollector);
  		pgstat_read_statsfile(&pgStatDBHash, InvalidOid,
! 							  &pgStatBeTable, &pgStatNumBackends);
  	}
  	else
  	{
--- 2905,2911 ----
  			return;
  		Assert(!pgStatRunningInCollector);
  		pgstat_read_statsfile(&pgStatDBHash, InvalidOid,
! 							  &pgStatBeTable, &pgStatNumBackends, true);
  	}
  	else
  	{
***************
*** 2819,2825 ****
  		{
  			Assert(!pgStatRunningInCollector);
  			pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
! 								  &pgStatBeTable, &pgStatNumBackends);
  			pgStatDBHashXact = topXid;
  		}
  	}
--- 2915,2921 ----
  		{
  			Assert(!pgStatRunningInCollector);
  			pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
! 								  &pgStatBeTable, &pgStatNumBackends, true);
  			pgStatDBHashXact = topXid;
  		}
  	}
Index: src/include/pgstat.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/pgstat.h,v
retrieving revision 1.42
diff -c -r1.42 pgstat.h
*** src/include/pgstat.h	5 Mar 2006 15:58:53 -0000	1.42
--- src/include/pgstat.h	4 Apr 2006 19:53:36 -0000
***************
*** 32,38 ****
  	PGSTAT_MTYPE_RESETCOUNTER,
  	PGSTAT_MTYPE_AUTOVAC_START,
  	PGSTAT_MTYPE_VACUUM,
! 	PGSTAT_MTYPE_ANALYZE
  } StatMsgType;
  
  /* ----------
--- 32,39 ----
  	PGSTAT_MTYPE_RESETCOUNTER,
  	PGSTAT_MTYPE_AUTOVAC_START,
  	PGSTAT_MTYPE_VACUUM,
! 	PGSTAT_MTYPE_ANALYZE,
! 	PGSTAT_MTYPE_REWRITE
  } StatMsgType;
  
  /* ----------
***************
*** 108,113 ****
--- 109,123 ----
  } PgStat_MsgDummy;
  
  /* ----------
+  * PgStat_MsgRewrite            Sent by backends to cause a rewrite of the stats file
+  * ----------
+  */
+ typedef struct Pgstat_MsgRewrite
+ {
+ 	PgStat_MsgHdr m_hdr;
+ } PgStat_MsgRewrite;
+ 
+ /* ----------
   * PgStat_MsgBestart			Sent by the backend on startup
   * ----------
   */
