Alvaro Herrera wrote:
> Darcy Buskermolen wrote:
> > On Thursday 13 September 2007 09:16:52 Alvaro Herrera wrote:
> > > Hi,
> > >
> > > Darcy Buskermolen noticed that when one has many databases, the autovac
> > > launcher starts eating too much CPU.
> > 
> > Don't forget the memory leak as well.  after 3 or 4 days of running I end 
> > up 
> > with a 2GB+ AVL..
> 
> Huh, sorry for not letting you know, I already fixed that :-)  (Please
> grab the latest CVS HEAD and confirm.)

Darcy, please also apply the following patch and see if it reduces the
CPU consumption to a reasonable level.

What this patch does is keep the pgstats data for 1 second in the
autovac launcher.  The idea is to avoid reading the data too frequently.
I coded it so that it doesn't affect the worker, because it would make
the table recheck code less effective.

-- 
Alvaro Herrera                 http://www.amazon.com/gp/registry/CTMLCN8V17R4
"MySQL is a toy compared to PostgreSQL."             (Randal L. Schwartz)
      (http://archives.postgresql.org/pgsql-general/2005-07/msg00517.php)
Index: src/backend/postmaster/autovacuum.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/postmaster/autovacuum.c,v
retrieving revision 1.58
diff -c -p -r1.58 autovacuum.c
*** src/backend/postmaster/autovacuum.c	12 Sep 2007 22:14:59 -0000	1.58
--- src/backend/postmaster/autovacuum.c	13 Sep 2007 22:13:29 -0000
*************** int			autovacuum_vac_cost_limit;
*** 116,121 ****
--- 116,124 ----
  
  int			Log_autovacuum = -1;
  
+ /* how long to keep pgstat data in the launcher, in milliseconds */
+ #define AUTOVAC_STATS_CACHE 1000
+ 
  
  /* Flags to tell if we are in an autovacuum process */
  static bool am_autovacuum_launcher = false;
*************** static void avl_sighup_handler(SIGNAL_AR
*** 291,296 ****
--- 294,300 ----
  static void avl_sigusr1_handler(SIGNAL_ARGS);
  static void avl_sigterm_handler(SIGNAL_ARGS);
  static void avl_quickdie(SIGNAL_ARGS);
+ static void autovac_refresh_stats(void);
  
  
  
*************** AutoVacLauncherMain(int argc, char *argv
*** 488,494 ****
  		DatabaseListCxt = NULL;
  		DatabaseList = NULL;
  
! 		/* Make sure pgstat also considers our stat data as gone */
  		pgstat_clear_snapshot();
  
  		/* Now we can allow interrupts again */
--- 492,501 ----
  		DatabaseListCxt = NULL;
  		DatabaseList = NULL;
  
! 		/*
! 		 * Make sure pgstat also considers our stat data as gone.  Note: we
! 		 * mustn't use autovac_refresh_stats here.
! 		 */
  		pgstat_clear_snapshot();
  
  		/* Now we can allow interrupts again */
*************** rebuild_database_list(Oid newdb)
*** 836,842 ****
  	HTAB	   *dbhash;
  
  	/* use fresh stats */
! 	pgstat_clear_snapshot();
  
  	newcxt = AllocSetContextCreate(AutovacMemCxt,
  								   "AV dblist",
--- 843,849 ----
  	HTAB	   *dbhash;
  
  	/* use fresh stats */
! 	autovac_refresh_stats();
  
  	newcxt = AllocSetContextCreate(AutovacMemCxt,
  								   "AV dblist",
*************** do_start_worker(void)
*** 1063,1069 ****
  	oldcxt = MemoryContextSwitchTo(tmpcxt);
  
  	/* use fresh stats */
! 	pgstat_clear_snapshot();
  
  	/* Get a list of databases */
  	dblist = get_database_list();
--- 1070,1076 ----
  	oldcxt = MemoryContextSwitchTo(tmpcxt);
  
  	/* use fresh stats */
! 	autovac_refresh_stats();
  
  	/* Get a list of databases */
  	dblist = get_database_list();
*************** do_start_worker(void)
*** 1106,1114 ****
  		avw_dbase  *tmp = lfirst(cell);
  		Dlelem	   *elem;
  
- 		/* Find pgstat entry if any */
- 		tmp->adw_entry = pgstat_fetch_stat_dbentry(tmp->adw_datid);
- 
  		/* Check to see if this one is at risk of wraparound */
  		if (TransactionIdPrecedes(tmp->adw_frozenxid, xidForceLimit))
  		{
--- 1113,1118 ----
*************** do_start_worker(void)
*** 1121,1129 ****
  		else if (for_xid_wrap)
  			continue;			/* ignore not-at-risk DBs */
  
  		/*
! 		 * Otherwise, skip a database with no pgstat entry; it means it
! 		 * hasn't seen any activity.
  		 */
  		if (!tmp->adw_entry)
  			continue;
--- 1125,1136 ----
  		else if (for_xid_wrap)
  			continue;			/* ignore not-at-risk DBs */
  
+ 		/* Find pgstat entry if any */
+ 		tmp->adw_entry = pgstat_fetch_stat_dbentry(tmp->adw_datid);
+ 
  		/*
! 		 * Skip a database with no pgstat entry; it means it hasn't seen any
! 		 * activity.
  		 */
  		if (!tmp->adw_entry)
  			continue;
*************** table_recheck_autovac(Oid relid)
*** 2258,2264 ****
  	PgStat_StatDBEntry *dbentry;
  
  	/* use fresh stats */
! 	pgstat_clear_snapshot();
  
  	shared = pgstat_fetch_stat_dbentry(InvalidOid);
  	dbentry = pgstat_fetch_stat_dbentry(MyDatabaseId);
--- 2265,2271 ----
  	PgStat_StatDBEntry *dbentry;
  
  	/* use fresh stats */
! 	autovac_refresh_stats();
  
  	shared = pgstat_fetch_stat_dbentry(InvalidOid);
  	dbentry = pgstat_fetch_stat_dbentry(MyDatabaseId);
*************** AutoVacuumShmemInit(void)
*** 2734,2736 ****
--- 2741,2769 ----
  	else
  		Assert(found);
  }
+ 
+ /*
+  * Refresh pgstats data in the autovacuum launcher process, at most every 500
+  * ms.  This is to avoid rereading the pgstats files too many times in quick
+  * succession.  Note: we don't do this in the worker, as it would be
+  * counterproductive.
+  */
+ static void
+ autovac_refresh_stats(void)
+ {
+ 	if (IsAutoVacuumLauncherProcess())
+ 	{
+ 		static TimestampTz	last_read = 0;
+ 		TimestampTz			current_time;
+ 
+ 		current_time = GetCurrentTimestamp();
+ 
+ 		if (!TimestampDifferenceExceeds(last_read, current_time,
+ 										AUTOVAC_STATS_CACHE))
+ 			return;
+ 
+ 		last_read = current_time;
+ 	}
+ 
+ 	pgstat_clear_snapshot();
+ }
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match

Reply via email to