Re: Location for pgstat.stat - Mailing list pgsql-hackers

From Magnus Hagander
Subject Re: Location for pgstat.stat
Date
Msg-id 4896DCA2.4050106@hagander.net
Whole thread Raw
In response to Re: Location for pgstat.stat  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Location for pgstat.stat  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-hackers
Tom Lane wrote:
> Magnus Hagander <magnus@hagander.net> writes:
>> Tom Lane wrote:
>>> It doesn't seem to me that it'd be hard to support two locations for the
>>> stats file --- it'd just take another parameter to the read and write
>>> routines.  pgstat.c already knows the difference between a normal write
>>> and a shutdown write ...
>
>> Right. Should it be removed from the permanent location when the server
>> starts?
>
> Yes, I would say so.  There are two possible exit paths: normal shutdown
> (where we'd write a new file) and crash.  In a crash we'd wish to delete
> the file anyway for fear that it's corrupted.
>
>     Startup: read permanent file, then delete it.
>
>     Post-crash: remove any permanent file (same as now)
>
>     Shutdown: write permanent file.
>
>     Normal stats collector write: write temp file.
>
>     Backend stats fetch: read temp file.

Attached is a patch that implements this. I went with the option of just
storing it in a temporary directory that can be symlinked, and not
bothering with a GUC for it. Comments? (documentation updates are also
needed, but I'll wait with those until I hear patch comments :-P)


//Magnus
Index: backend/postmaster/pgstat.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/postmaster/pgstat.c,v
retrieving revision 1.176
diff -c -r1.176 pgstat.c
*** backend/postmaster/pgstat.c    30 Jun 2008 10:58:47 -0000    1.176
--- backend/postmaster/pgstat.c    4 Aug 2008 09:39:23 -0000
***************
*** 67,74 ****
   * Paths for the statistics files (relative to installation's $PGDATA).
   * ----------
   */
! #define PGSTAT_STAT_FILENAME    "global/pgstat.stat"
! #define PGSTAT_STAT_TMPFILE        "global/pgstat.tmp"

  /* ----------
   * Timer definitions.
--- 67,76 ----
   * Paths for the statistics files (relative to installation's $PGDATA).
   * ----------
   */
! #define PGSTAT_STAT_PERMANENT_FILENAME        "global/pgstat.stat"
! #define PGSTAT_STAT_PERMANENT_TMPFILE        "global/pgstat.tmp"
! #define PGSTAT_STAT_FILENAME                "pgstat_tmp/pgstat.stat"
! #define PGSTAT_STAT_TMPFILE                    "pgstat_tmp/pgstat.tmp"

  /* ----------
   * Timer definitions.
***************
*** 218,225 ****
  static void pgstat_beshutdown_hook(int code, Datum arg);

  static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create);
! static void pgstat_write_statsfile(void);
! static HTAB *pgstat_read_statsfile(Oid onlydb);
  static void backend_read_statsfile(void);
  static void pgstat_read_current_status(void);

--- 220,227 ----
  static void pgstat_beshutdown_hook(int code, Datum arg);

  static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create);
! 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);

***************
*** 509,514 ****
--- 511,517 ----
  pgstat_reset_all(void)
  {
      unlink(PGSTAT_STAT_FILENAME);
+     unlink(PGSTAT_STAT_PERMANENT_FILENAME);
  }

  #ifdef EXEC_BACKEND
***************
*** 2595,2601 ****
       * zero.
       */
      pgStatRunningInCollector = true;
!     pgStatDBHash = pgstat_read_statsfile(InvalidOid);

      /*
       * Setup the descriptor set for select(2).    Since only one bit in the set
--- 2598,2604 ----
       * zero.
       */
      pgStatRunningInCollector = true;
!     pgStatDBHash = pgstat_read_statsfile(InvalidOid, true);

      /*
       * Setup the descriptor set for select(2).    Since only one bit in the set
***************
*** 2635,2641 ****
              if (!PostmasterIsAlive(true))
                  break;

!             pgstat_write_statsfile();
              need_statwrite = false;
              need_timer = true;
          }
--- 2638,2644 ----
              if (!PostmasterIsAlive(true))
                  break;

!             pgstat_write_statsfile(false);
              need_statwrite = false;
              need_timer = true;
          }
***************
*** 2803,2809 ****
      /*
       * Save the final stats to reuse at next startup.
       */
!     pgstat_write_statsfile();

      exit(0);
  }
--- 2806,2812 ----
      /*
       * Save the final stats to reuse at next startup.
       */
!     pgstat_write_statsfile(true);

      exit(0);
  }
***************
*** 2891,2897 ****
   * ----------
   */
  static void
! pgstat_write_statsfile(void)
  {
      HASH_SEQ_STATUS hstat;
      HASH_SEQ_STATUS tstat;
--- 2894,2900 ----
   * ----------
   */
  static void
! pgstat_write_statsfile(bool permanent)
  {
      HASH_SEQ_STATUS hstat;
      HASH_SEQ_STATUS tstat;
***************
*** 2901,2917 ****
      PgStat_StatFuncEntry *funcentry;
      FILE       *fpout;
      int32        format_id;

      /*
       * Open the statistics temp file to write out the current values.
       */
!     fpout = fopen(PGSTAT_STAT_TMPFILE, PG_BINARY_W);
      if (fpout == NULL)
      {
          ereport(LOG,
                  (errcode_for_file_access(),
                   errmsg("could not open temporary statistics file \"%s\": %m",
!                         PGSTAT_STAT_TMPFILE)));
          return;
      }

--- 2904,2922 ----
      PgStat_StatFuncEntry *funcentry;
      FILE       *fpout;
      int32        format_id;
+     const char *tmpfile = permanent?PGSTAT_STAT_PERMANENT_TMPFILE:PGSTAT_STAT_TMPFILE;
+     const char *statfile = permanent?PGSTAT_STAT_PERMANENT_FILENAME:PGSTAT_STAT_FILENAME;

      /*
       * Open the statistics temp file to write out the current values.
       */
!     fpout = fopen(tmpfile, PG_BINARY_W);
      if (fpout == NULL)
      {
          ereport(LOG,
                  (errcode_for_file_access(),
                   errmsg("could not open temporary statistics file \"%s\": %m",
!                         tmpfile)));
          return;
      }

***************
*** 2978,3002 ****
          ereport(LOG,
                  (errcode_for_file_access(),
                 errmsg("could not write temporary statistics file \"%s\": %m",
!                       PGSTAT_STAT_TMPFILE)));
          fclose(fpout);
!         unlink(PGSTAT_STAT_TMPFILE);
      }
      else if (fclose(fpout) < 0)
      {
          ereport(LOG,
                  (errcode_for_file_access(),
                 errmsg("could not close temporary statistics file \"%s\": %m",
!                       PGSTAT_STAT_TMPFILE)));
!         unlink(PGSTAT_STAT_TMPFILE);
      }
!     else if (rename(PGSTAT_STAT_TMPFILE, PGSTAT_STAT_FILENAME) < 0)
      {
          ereport(LOG,
                  (errcode_for_file_access(),
                   errmsg("could not rename temporary statistics file \"%s\" to \"%s\": %m",
!                         PGSTAT_STAT_TMPFILE, PGSTAT_STAT_FILENAME)));
!         unlink(PGSTAT_STAT_TMPFILE);
      }
  }

--- 2983,3007 ----
          ereport(LOG,
                  (errcode_for_file_access(),
                 errmsg("could not write temporary statistics file \"%s\": %m",
!                       tmpfile)));
          fclose(fpout);
!         unlink(tmpfile);
      }
      else if (fclose(fpout) < 0)
      {
          ereport(LOG,
                  (errcode_for_file_access(),
                 errmsg("could not close temporary statistics file \"%s\": %m",
!                       tmpfile)));
!         unlink(tmpfile);
      }
!     else if (rename(tmpfile, statfile) < 0)
      {
          ereport(LOG,
                  (errcode_for_file_access(),
                   errmsg("could not rename temporary statistics file \"%s\" to \"%s\": %m",
!                         tmpfile, statfile)));
!         unlink(tmpfile);
      }
  }

***************
*** 3006,3015 ****
   *
   *    Reads in an existing statistics collector file and initializes the
   *    databases' hash table (whose entries point to the tables' hash tables).
   * ----------
   */
  static HTAB *
! pgstat_read_statsfile(Oid onlydb)
  {
      PgStat_StatDBEntry *dbentry;
      PgStat_StatDBEntry dbbuf;
--- 3011,3025 ----
   *
   *    Reads in an existing statistics collector file and initializes the
   *    databases' hash table (whose entries point to the tables' hash tables).
+  *
+  *    If reading from the permanent file (which happens during collector
+  *    startup, but never from backends), the file is removed once it's been
+  *    successfully read. The temporary file is also removed at this time,
+  *    to make sure backends don't read data from previous runs.
   * ----------
   */
  static HTAB *
! pgstat_read_statsfile(Oid onlydb, bool permanent)
  {
      PgStat_StatDBEntry *dbentry;
      PgStat_StatDBEntry dbbuf;
***************
*** 3024,3029 ****
--- 3034,3040 ----
      FILE       *fpin;
      int32        format_id;
      bool        found;
+     const char *statfile = permanent?PGSTAT_STAT_PERMANENT_FILENAME:PGSTAT_STAT_FILENAME;

      /*
       * The tables will live in pgStatLocalContext.
***************
*** 3052,3058 ****
       * return zero for anything and the collector simply starts from scratch
       * with empty counters.
       */
!     if ((fpin = AllocateFile(PGSTAT_STAT_FILENAME, PG_BINARY_R)) == NULL)
          return dbhash;

      /*
--- 3063,3069 ----
       * return zero for anything and the collector simply starts from scratch
       * with empty counters.
       */
!     if ((fpin = AllocateFile(statfile, PG_BINARY_R)) == NULL)
          return dbhash;

      /*
***************
*** 3241,3246 ****
--- 3252,3263 ----
  done:
      FreeFile(fpin);

+     if (permanent)
+     {
+         unlink(PGSTAT_STAT_PERMANENT_FILENAME);
+         unlink(PGSTAT_STAT_FILENAME);
+     }
+
      return dbhash;
  }

***************
*** 3259,3267 ****

      /* Autovacuum launcher wants stats about all databases */
      if (IsAutoVacuumLauncherProcess())
!         pgStatDBHash = pgstat_read_statsfile(InvalidOid);
      else
!         pgStatDBHash = pgstat_read_statsfile(MyDatabaseId);
  }


--- 3276,3284 ----

      /* Autovacuum launcher wants stats about all databases */
      if (IsAutoVacuumLauncherProcess())
!         pgStatDBHash = pgstat_read_statsfile(InvalidOid, false);
      else
!         pgStatDBHash = pgstat_read_statsfile(MyDatabaseId, false);
  }


Index: bin/initdb/initdb.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/initdb/initdb.c,v
retrieving revision 1.158
diff -c -r1.158 initdb.c
*** bin/initdb/initdb.c    19 Jul 2008 04:01:29 -0000    1.158
--- bin/initdb/initdb.c    4 Aug 2008 09:39:23 -0000
***************
*** 2461,2467 ****
          "pg_multixact/offsets",
          "base",
          "base/1",
!         "pg_tblspc"
      };

      progname = get_progname(argv[0]);
--- 2461,2468 ----
          "pg_multixact/offsets",
          "base",
          "base/1",
!         "pg_tblspc",
!         "pgstat_tmp"
      };

      progname = get_progname(argv[0]);

pgsql-hackers by date:

Previous
From: Gregory Stark
Date:
Subject: Re: Mini improvement: statement_cost_limit
Next
From: Gregory Stark
Date:
Subject: DROP DATABASE always seeing database in use