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 #include #include + #include #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 * ---------- */