1313 *
1414 * Copyright (c) 2001-2006, PostgreSQL Global Development Group
1515 *
16- * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.123 2006/04/20 10:51:32 momjian Exp $
16+ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.124 2006/04/27 00:06:58 momjian Exp $
1717 * ----------
1818 */
1919#include "postgres.h"
2828#include <arpa/inet.h>
2929#include <signal.h>
3030#include <time.h>
31+ #include <sys/stat.h>
3132
3233#include "pgstat.h"
3334
6667 * Timer definitions.
6768 * ----------
6869 */
69- #define PGSTAT_STAT_INTERVAL 500 /* How often to write the status file;
70- * in milliseconds. */
7170
72- #define PGSTAT_RESTART_INTERVAL 60 /* How often to attempt to restart a
73- * failed statistics collector; in
74- * seconds. */
71+ /* How often to write the status file, in milliseconds. */
72+ #define PGSTAT_STAT_INTERVAL (5*60*1000)
73+
74+ /*
75+ * How often to attempt to restart a failed statistics collector; in ms.
76+ * Must be at least PGSTAT_STAT_INTERVAL.
77+ */
78+ #define PGSTAT_RESTART_INTERVAL (5*60*1000)
7579
7680/* ----------
7781 * Amount of space reserved in pgstat_recvbuffer().
@@ -172,11 +176,12 @@ static void pgstat_drop_database(Oid databaseid);
172176static void pgstat_write_statsfile (void );
173177static void pgstat_read_statsfile (HTAB * * dbhash , Oid onlydb ,
174178 PgStat_StatBeEntry * * betab ,
175- int * numbackends );
179+ int * numbackends , bool rewrite );
176180static void backend_read_statsfile (void );
177181
178182static void pgstat_setheader (PgStat_MsgHdr * hdr , StatMsgType mtype );
179183static void pgstat_send (void * msg , int len );
184+ static void pgstat_send_rewrite (void );
180185
181186static void pgstat_recv_bestart (PgStat_MsgBestart * msg , int len );
182187static void pgstat_recv_beterm (PgStat_MsgBeterm * msg , int len );
@@ -1449,6 +1454,24 @@ pgstat_send(void *msg, int len)
14491454#endif
14501455}
14511456
1457+ /*
1458+ * pgstat_send_rewrite() -
1459+ *
1460+ * Send a command to the collector to rewrite the stats file.
1461+ * ----------
1462+ */
1463+ static void
1464+ pgstat_send_rewrite (void )
1465+ {
1466+ PgStat_MsgRewrite msg ;
1467+
1468+ if (pgStatSock < 0 )
1469+ return ;
1470+
1471+ pgstat_setheader (& msg .m_hdr , PGSTAT_MTYPE_REWRITE );
1472+ pgstat_send (& msg , sizeof (msg ));
1473+ }
1474+
14521475
14531476/* ----------
14541477 * PgstatBufferMain() -
@@ -1549,7 +1572,7 @@ PgstatCollectorMain(int argc, char *argv[])
15491572 fd_set rfds ;
15501573 int readPipe ;
15511574 int len = 0 ;
1552- struct itimerval timeout ;
1575+ struct itimerval timeout , canceltimeout ;
15531576 bool need_timer = false;
15541577
15551578 MyProcPid = getpid (); /* reset MyProcPid */
@@ -1604,12 +1627,15 @@ PgstatCollectorMain(int argc, char *argv[])
16041627 timeout .it_value .tv_sec = PGSTAT_STAT_INTERVAL / 1000 ;
16051628 timeout .it_value .tv_usec = PGSTAT_STAT_INTERVAL % 1000 ;
16061629
1630+ /* Values set to zero will cancel the active timer */
1631+ MemSet (& canceltimeout , 0 , sizeof (struct itimerval ));
1632+
16071633 /*
16081634 * Read in an existing statistics stats file or initialize the stats to
16091635 * zero.
16101636 */
16111637 pgStatRunningInCollector = true;
1612- pgstat_read_statsfile (& pgStatDBHash , InvalidOid , NULL , NULL );
1638+ pgstat_read_statsfile (& pgStatDBHash , InvalidOid , NULL , NULL , false );
16131639
16141640 /*
16151641 * Create the known backends table
@@ -1764,6 +1790,12 @@ PgstatCollectorMain(int argc, char *argv[])
17641790 pgstat_recv_analyze ((PgStat_MsgAnalyze * ) & msg , nread );
17651791 break ;
17661792
1793+ case PGSTAT_MTYPE_REWRITE :
1794+ need_statwrite = true;
1795+ /* Disable the timer - it will be restarted on next data update */
1796+ setitimer (ITIMER_REAL , & canceltimeout , NULL );
1797+ break ;
1798+
17671799 default :
17681800 break ;
17691801 }
@@ -2344,7 +2376,7 @@ comparePids(const void *v1, const void *v2)
23442376 */
23452377static void
23462378pgstat_read_statsfile (HTAB * * dbhash , Oid onlydb ,
2347- PgStat_StatBeEntry * * betab , int * numbackends )
2379+ PgStat_StatBeEntry * * betab , int * numbackends , bool rewrite )
23482380{
23492381 PgStat_StatDBEntry * dbentry ;
23502382 PgStat_StatDBEntry dbbuf ;
@@ -2363,6 +2395,71 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
23632395 MemoryContext use_mcxt ;
23642396 int mcxt_flags ;
23652397
2398+
2399+ if (rewrite )
2400+ {
2401+ /*
2402+ * To force a rewrite of the stats file from the collector, send
2403+ * a REWRITE message to the stats collector. Then wait for the file
2404+ * to change. On Unix, we wait for the inode to change (as the file
2405+ * is renamed into place from a different file). Win32 has no concept
2406+ * of inodes, so we wait for the date on the file to change instead.
2407+ * We can do this on win32 because we have high-res timing on the
2408+ * file dates, but we can't on unix, because it has 1sec resolution
2409+ * on the fields in struct stat.
2410+ */
2411+ int i ;
2412+ #ifndef WIN32
2413+ struct stat st1 , st2 ;
2414+
2415+ if (stat (PGSTAT_STAT_FILENAME , & st1 ))
2416+ {
2417+ /* Assume no file there yet */
2418+ st1 .st_ino = 0 ;
2419+ }
2420+ st2 .st_ino = 0 ;
2421+ #else
2422+ WIN32_FILE_ATTRIBUTE_DATA fd1 , fd2 ;
2423+
2424+ if (!GetFileAttributesEx (PGSTAT_STAT_FILENAME , GetFileExInfoStandard , & fd1 ))
2425+ {
2426+ fd1 .ftLastWriteTime .dwLowDateTime = 0 ;
2427+ fd1 .ftLastWriteTime .dwHighDateTime = 0 ;
2428+ }
2429+ fd2 .ftLastWriteTime .dwLowDateTime = 0 ;
2430+ fd2 .ftLastWriteTime .dwHighDateTime = 0 ;
2431+ #endif
2432+
2433+
2434+ /* Send rewrite message */
2435+ pgstat_send_rewrite ();
2436+
2437+ /* Now wait for the file to change */
2438+ for (i = 0 ; i < 50 ; i ++ )
2439+ {
2440+ #ifndef WIN32
2441+ if (!stat (PGSTAT_STAT_FILENAME , & st2 ))
2442+ {
2443+ if (st2 .st_ino != st1 .st_ino )
2444+ break ;
2445+ }
2446+ #else
2447+ if (GetFileAttributesEx (PGSTAT_STAT_FILENAME , GetFileExInfoStandard , & fd2 ))
2448+ {
2449+ if (fd1 .ftLastWriteTime .dwLowDateTime != fd2 .ftLastWriteTime .dwLowDateTime ||
2450+ fd1 .ftLastWriteTime .dwHighDateTime != fd2 .ftLastWriteTime .dwHighDateTime )
2451+ break ;
2452+ }
2453+ #endif
2454+
2455+ pg_usleep (50000 );
2456+ }
2457+ if (i >= 50 )
2458+ ereport (WARNING ,
2459+ (errmsg ("pgstat update timeout" )));
2460+ /* Fallthrough and read the old file anyway - old data better than no data */
2461+ }
2462+
23662463 /*
23672464 * If running in the collector or the autovacuum process, we use the
23682465 * DynaHashCxt memory context. If running in a backend, we use the
@@ -2681,7 +2778,7 @@ backend_read_statsfile(void)
26812778 return ;
26822779 Assert (!pgStatRunningInCollector );
26832780 pgstat_read_statsfile (& pgStatDBHash , InvalidOid ,
2684- & pgStatBeTable , & pgStatNumBackends );
2781+ & pgStatBeTable , & pgStatNumBackends , true );
26852782 }
26862783 else
26872784 {
@@ -2691,7 +2788,7 @@ backend_read_statsfile(void)
26912788 {
26922789 Assert (!pgStatRunningInCollector );
26932790 pgstat_read_statsfile (& pgStatDBHash , MyDatabaseId ,
2694- & pgStatBeTable , & pgStatNumBackends );
2791+ & pgStatBeTable , & pgStatNumBackends , true );
26952792 pgStatDBHashXact = topXid ;
26962793 }
26972794 }
0 commit comments