<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.110 2005/07/31 17:19:16 tgl Exp $
+ $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.111 2005/08/11 21:11:41 tgl Exp $
-->
<chapter id="catalogs">
<entry>Multiplier for reltuples to add to
<structfield>anl_base_thresh</></entry>
</row>
+
+ <row>
+ <entry><structfield>vac_cost_delay</structfield></entry>
+ <entry><type>integer</type></entry>
+ <entry></entry>
+ <entry>Custom <varname>vacuum_cost_delay</> parameter</entry>
+ </row>
+
+ <row>
+ <entry><structfield>vac_cost_limit</structfield></entry>
+ <entry><type>integer</type></entry>
+ <entry></entry>
+ <entry>Custom <varname>vacuum_cost_limit</> parameter</entry>
+ </row>
</tbody>
</tgroup>
</table>
<para>
Any of the numerical fields can contain <literal>-1</> (or indeed
any negative value) to indicate that the system-wide default should
- be used for this particular value.
+ be used for this particular value. Observe that the
+ <structfield>vac_cost_delay</> variable inherits its default value from the
+ <varname>autovacuum_vacuum_cost_delay</> configuration parameter,
+ or from <varname>vacuum_cost_delay</> if the former is set to a negative
+ value. The same applies to <structfield>vac_cost_limit</>.
</para>
</sect1>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.343 2005/08/09 05:01:10 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.344 2005/08/11 21:11:42 tgl Exp $
-->
<chapter Id="runtime">
<para>
If on, collected statistics are zeroed out whenever the server
is restarted. If off, statistics are accumulated across server
- restarts. The default is <literal>on</>. This option can only
+ restarts. The default is <literal>off</>. This option can only
be set at server start.
</para>
</listitem>
</listitem>
</varlistentry>
+ <varlistentry id="guc-autovacuum-vacuum-cost-delay" xreflabel="autovacuum_vacuum_cost_delay">
+ <term><varname>autovacuum_vacuum_cost_delay</varname> (<type>integer</type>)</term>
+ <indexterm>
+ <primary><varname>autovacuum_vacuum_cost_delay</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies the cost delay value that will be used in automatic
+ <command>VACUUM</> operations. If -1 is specified (which is the
+ default), the regular
+ <xref linkend="guc-vacuum-cost-delay"> value will be used.
+ This setting can be overridden for individual tables by entries in
+ <structname>pg_autovacuum</>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-autovacuum-vacuum-cost-limit" xreflabel="autovacuum_vacuum_cost_limit">
+ <term><varname>autovacuum_vacuum_cost_limit</varname> (<type>integer</type>)</term>
+ <indexterm>
+ <primary><varname>autovacuum_vacuum_cost_limit</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies the cost limit value that will be used in automatic
+ <command>VACUUM</> operations. If -1 is specified (which is the
+ default), the regular
+ <xref linkend="guc-vacuum-cost-limit"> value will be used.
+ This setting can be overridden for individual tables by entries in
+ <structname>pg_autovacuum</>.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</sect2>
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.214 2005/07/30 14:15:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.215 2005/08/11 21:11:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/catversion.h"
#include "catalog/pg_control.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "postmaster/bgwriter.h"
#include "storage/bufpage.h"
#include "storage/fd.h"
/*
- * Becauase O_DIRECT bypasses the kernel buffers, and because we never
+ * Because O_DIRECT bypasses the kernel buffers, and because we never
* read those buffers except during crash recovery, it is a win to use
* it in all cases where we sync on each write(). We could allow O_DIRECT
* with fsync(), but because skipping the kernel buffer forces writes out
RmgrTable[rmid].rm_cleanup();
}
+ /*
+ * Reset pgstat data, because it may be invalid after recovery.
+ */
+ pgstat_reset_all();
+
/*
* Perform a new checkpoint to update our recovery activity to
* disk.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.146 2005/07/29 19:30:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.147 2005/08/11 21:11:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* dboid: gets database OID
* dbtablespace: gets database's default tablespace's OID
* dbfrozenxid: gets database's frozen XID
+ * dbvacuumxid: gets database's vacuum XID
*
* This is not much related to the other functions in hba.c, but we put it
* here because it uses the next_token() infrastructure.
*/
bool
read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
- Oid *dbtablespace, TransactionId *dbfrozenxid)
+ Oid *dbtablespace, TransactionId *dbfrozenxid,
+ TransactionId *dbvacuumxid)
{
char buf[MAX_TOKEN];
if (!isdigit((unsigned char) buf[0]))
elog(FATAL, "bad data in flat pg_database file");
*dbfrozenxid = atoxid(buf);
+ next_token(fp, buf, sizeof(buf));
+ if (!isdigit((unsigned char) buf[0]))
+ elog(FATAL, "bad data in flat pg_database file");
+ *dbvacuumxid = atoxid(buf);
/* expect EOL next */
if (next_token(fp, buf, sizeof(buf)))
elog(FATAL, "bad data in flat pg_database file");
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.2 2005/07/29 19:30:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.3 2005/08/11 21:11:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_autovacuum.h"
+#include "catalog/pg_database.h"
#include "commands/vacuum.h"
#include "libpq/hba.h"
#include "libpq/pqsignal.h"
int autovacuum_anl_thresh;
double autovacuum_anl_scale;
+int autovacuum_vac_cost_delay;
+int autovacuum_vac_cost_limit;
+
/* Flag to tell if we are in the autovacuum daemon process */
static bool am_autovacuum = false;
static time_t last_autovac_start_time = 0;
static time_t last_autovac_stop_time = 0;
+/* Memory context for long-lived data */
+static MemoryContext AutovacMemCxt;
+
/* struct to keep list of candidate databases for vacuum */
typedef struct autovac_dbase
{
Oid oid;
char *name;
TransactionId frozenxid;
+ TransactionId vacuumxid;
PgStat_StatDBEntry *entry;
int32 age;
} autovac_dbase;
+/* struct to keep track of tables to vacuum and/or analyze */
+typedef struct autovac_table
+{
+ Oid relid;
+ bool dovacuum;
+ bool doanalyze;
+ int vacuum_cost_delay;
+ int vacuum_cost_limit;
+} autovac_table;
+
#ifdef EXEC_BACKEND
static pid_t autovac_forkexec(void);
#endif
NON_EXEC_STATIC void AutoVacMain(int argc, char *argv[]);
-static void do_autovacuum(bool whole_db, PgStat_StatDBEntry *dbentry);
+static void process_whole_db(void);
+static void do_autovacuum(PgStat_StatDBEntry *dbentry);
static List *autovac_get_database_list(void);
static void test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
Form_pg_class classForm, Form_pg_autovacuum avForm,
- List **vacuum_tables, List **analyze_tables);
-static void autovacuum_do_vac_analyze(List *relids, bool dovacuum);
+ List **vacuum_tables);
+static void autovacuum_do_vac_analyze(List *relids, bool dovacuum,
+ bool doanalyze, bool freeze);
/*
/* Lose the postmaster's on-exit routines */
on_exit_reset();
+ /* Identify myself via ps */
+ init_ps_display("autovacuum process", "", "");
+ set_ps_display("");
+
+ SetProcessingMode(InitProcessing);
+
/*
* Set up signal handlers. We operate on databases much like a
* regular backend, so we use the same signal handling. See
pqsignal(SIGUSR1, CatchupInterruptHandler);
/* We don't listen for async notifies */
pqsignal(SIGUSR2, SIG_IGN);
+ pqsignal(SIGFPE, FloatExceptionHandler);
pqsignal(SIGCHLD, SIG_DFL);
- /* Identify myself via ps */
- init_ps_display("autovacuum process", "", "");
- set_ps_display("");
-
/* Early initialization */
BaseInit();
{
autovac_dbase *tmp = lfirst(cell);
bool this_whole_db;
+ int32 freeze_age,
+ vacuum_age;
/*
* We look for the database that most urgently needs a database-wide
* transactions sooner than vacuum.c's vac_truncate_clog() would
* decide to start giving warnings. If any such db is found, we
* ignore all other dbs.
+ *
+ * Unlike vacuum.c, we also look at vacuumxid. This is so that
+ * pg_clog can be kept trimmed to a reasonable size.
*/
- tmp->age = (int32) (nextXid - tmp->frozenxid);
- this_whole_db = (tmp->age > (int32) ((MaxTransactionId >> 3) * 3 - 100000));
+ freeze_age = (int32) (nextXid - tmp->frozenxid);
+ vacuum_age = (int32) (nextXid - tmp->vacuumxid);
+ tmp->age = Max(freeze_age, vacuum_age);
+
+ this_whole_db = (tmp->age >
+ (int32) ((MaxTransactionId >> 3) * 3 - 100000));
if (whole_db || this_whole_db)
{
if (!this_whole_db)
set_ps_display(db->name);
ereport(LOG,
(errmsg("autovacuum: processing database \"%s\"", db->name)));
+
+ /* Create the memory context where cross-transaction state is stored */
+ AutovacMemCxt = AllocSetContextCreate(TopMemoryContext,
+ "Autovacuum context",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+
/*
- * And do an appropriate amount of work on it
+ * And do an appropriate amount of work
*/
- do_autovacuum(whole_db, db->entry);
+ if (whole_db)
+ process_whole_db();
+ else
+ do_autovacuum(db->entry);
}
/* One iteration done, go away */
Oid db_id;
Oid db_tablespace;
TransactionId db_frozenxid;
+ TransactionId db_vacuumxid;
filename = database_getflatfilename();
db_file = AllocateFile(filename, "r");
errmsg("could not open file \"%s\": %m", filename)));
while (read_pg_database_line(db_file, thisname, &db_id,
- &db_tablespace, &db_frozenxid))
+ &db_tablespace, &db_frozenxid,
+ &db_vacuumxid))
{
autovac_dbase *db;
db->oid = db_id;
db->name = pstrdup(thisname);
db->frozenxid = db_frozenxid;
+ db->vacuumxid = db_vacuumxid;
/* these get set later: */
db->entry = NULL;
db->age = 0;
}
/*
- * Process a database.
- *
- * If whole_db is true, the database is processed as a whole, and the
- * dbentry parameter is ignored. If it's false, dbentry must be a valid
- * pointer to the database entry in the stats databases' hash table, and
- * it will be used to determine whether vacuum or analyze is needed on a
- * per-table basis.
+ * Process a whole database. If it's a template database or is disallowing
+ * connection by means of datallowconn=false, then issue a VACUUM FREEZE.
+ * Else use a plain VACUUM.
+ */
+static void
+process_whole_db(void)
+{
+ Relation dbRel;
+ ScanKeyData entry[1];
+ SysScanDesc scan;
+ HeapTuple tup;
+ Form_pg_database dbForm;
+ bool freeze;
+
+ /* Start a transaction so our commands have one to play into. */
+ StartTransactionCommand();
+
+ dbRel = heap_open(DatabaseRelationId, AccessShareLock);
+
+ /* Must use a table scan, since there's no syscache for pg_database */
+ ScanKeyInit(&entry[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(MyDatabaseId));
+
+ scan = systable_beginscan(dbRel, DatabaseOidIndexId, true,
+ SnapshotNow, 1, entry);
+
+ tup = systable_getnext(scan);
+
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
+
+ dbForm = (Form_pg_database) GETSTRUCT(tup);
+
+ if (!dbForm->datallowconn || dbForm->datistemplate)
+ freeze = true;
+ else
+ freeze = false;
+
+ systable_endscan(scan);
+
+ heap_close(dbRel, AccessShareLock);
+
+ elog(DEBUG2, "autovacuum: VACUUM%s whole database",
+ (freeze) ? " FREEZE" : "");
+
+ autovacuum_do_vac_analyze(NIL, true, false, freeze);
+
+ /* Finally close out the last transaction. */
+ CommitTransactionCommand();
+}
+
+/*
+ * Process a database table-by-table
*
- * Note that test_rel_for_autovac generates two separate lists, one for
- * vacuum and other for analyze. This is to facilitate processing all
- * analyzes first, and then all vacuums.
+ * dbentry must be a valid pointer to the database entry in the stats
+ * databases' hash table, and it will be used to determine whether vacuum or
+ * analyze is needed on a per-table basis.
*
* Note that CHECK_FOR_INTERRUPTS is supposed to be used in certain spots in
* order not to ignore shutdown commands for too long.
*/
static void
-do_autovacuum(bool whole_db, PgStat_StatDBEntry *dbentry)
+do_autovacuum(PgStat_StatDBEntry *dbentry)
{
Relation classRel,
avRel;
HeapTuple tuple;
HeapScanDesc relScan;
- List *vacuum_tables = NIL,
- *analyze_tables = NIL;
- MemoryContext AutovacMemCxt;
-
- Assert(whole_db || PointerIsValid(dbentry));
-
- /* Memory context where cross-transaction state is stored */
- AutovacMemCxt = AllocSetContextCreate(TopMemoryContext,
- "Autovacuum context",
- ALLOCSET_DEFAULT_MINSIZE,
- ALLOCSET_DEFAULT_INITSIZE,
- ALLOCSET_DEFAULT_MAXSIZE);
+ List *vacuum_tables = NIL;
+ ListCell *cell;
+ PgStat_StatDBEntry *shared;
/* Start a transaction so our commands have one to play into. */
StartTransactionCommand();
*/
MemoryContextSwitchTo(AutovacMemCxt);
- if (whole_db)
- {
- elog(DEBUG2, "autovacuum: VACUUM ANALYZE whole database");
- autovacuum_do_vac_analyze(NIL, true);
- }
- else
- {
- /* the hash entry where pgstat stores shared relations */
- PgStat_StatDBEntry *shared = pgstat_fetch_stat_dbentry(InvalidOid);
-
- classRel = heap_open(RelationRelationId, AccessShareLock);
- avRel = heap_open(AutovacuumRelationId, AccessShareLock);
-
- relScan = heap_beginscan(classRel, SnapshotNow, 0, NULL);
+ /* The database hash where pgstat keeps shared relations */
+ shared = pgstat_fetch_stat_dbentry(InvalidOid);
- /* Scan pg_class looking for tables to vacuum */
- while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
- {
- Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
- Form_pg_autovacuum avForm = NULL;
- PgStat_StatTabEntry *tabentry;
- SysScanDesc avScan;
- HeapTuple avTup;
- ScanKeyData entry[1];
- Oid relid;
-
- /* Skip non-table entries. */
- /* XXX possibly allow RELKIND_TOASTVALUE entries here too? */
- if (classForm->relkind != RELKIND_RELATION)
- continue;
+ classRel = heap_open(RelationRelationId, AccessShareLock);
+ avRel = heap_open(AutovacuumRelationId, AccessShareLock);
- /*
- * Skip temp tables (i.e. those in temp namespaces). We cannot
- * safely process other backends' temp tables.
- */
- if (isTempNamespace(classForm->relnamespace))
- continue;
+ relScan = heap_beginscan(classRel, SnapshotNow, 0, NULL);
- relid = HeapTupleGetOid(tuple);
+ /* Scan pg_class looking for tables to vacuum */
+ while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
+ {
+ Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
+ Form_pg_autovacuum avForm = NULL;
+ PgStat_StatTabEntry *tabentry;
+ SysScanDesc avScan;
+ HeapTuple avTup;
+ ScanKeyData entry[1];
+ Oid relid;
+
+ /* Skip non-table entries. */
+ /* XXX possibly allow RELKIND_TOASTVALUE entries here too? */
+ if (classForm->relkind != RELKIND_RELATION)
+ continue;
- /* See if we have a pg_autovacuum entry for this relation. */
- ScanKeyInit(&entry[0],
- Anum_pg_autovacuum_vacrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(relid));
+ /*
+ * Skip temp tables (i.e. those in temp namespaces). We cannot
+ * safely process other backends' temp tables.
+ */
+ if (isTempNamespace(classForm->relnamespace))
+ continue;
- avScan = systable_beginscan(avRel, AutovacuumRelidIndexId, true,
- SnapshotNow, 1, entry);
+ relid = HeapTupleGetOid(tuple);
- avTup = systable_getnext(avScan);
+ /* See if we have a pg_autovacuum entry for this relation. */
+ ScanKeyInit(&entry[0],
+ Anum_pg_autovacuum_vacrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relid));
- if (HeapTupleIsValid(avTup))
- avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
+ avScan = systable_beginscan(avRel, AutovacuumRelidIndexId, true,
+ SnapshotNow, 1, entry);
- if (classForm->relisshared && PointerIsValid(shared))
- tabentry = hash_search(shared->tables, &relid,
- HASH_FIND, NULL);
- else
- tabentry = hash_search(dbentry->tables, &relid,
- HASH_FIND, NULL);
+ avTup = systable_getnext(avScan);
- test_rel_for_autovac(relid, tabentry, classForm, avForm,
- &vacuum_tables, &analyze_tables);
+ if (HeapTupleIsValid(avTup))
+ avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
- systable_endscan(avScan);
- }
+ if (classForm->relisshared && PointerIsValid(shared))
+ tabentry = hash_search(shared->tables, &relid,
+ HASH_FIND, NULL);
+ else
+ tabentry = hash_search(dbentry->tables, &relid,
+ HASH_FIND, NULL);
- heap_endscan(relScan);
- heap_close(avRel, AccessShareLock);
- heap_close(classRel, AccessShareLock);
+ test_rel_for_autovac(relid, tabentry, classForm, avForm,
+ &vacuum_tables);
- CHECK_FOR_INTERRUPTS();
+ systable_endscan(avScan);
+ }
- /*
- * Perform operations on collected tables.
- */
+ heap_endscan(relScan);
+ heap_close(avRel, AccessShareLock);
+ heap_close(classRel, AccessShareLock);
- if (analyze_tables)
- autovacuum_do_vac_analyze(analyze_tables, false);
+ /*
+ * Perform operations on collected tables.
+ */
+ foreach(cell, vacuum_tables)
+ {
+ autovac_table *tab = lfirst(cell);
CHECK_FOR_INTERRUPTS();
- /* get back to proper context */
- MemoryContextSwitchTo(AutovacMemCxt);
+ /* Set the vacuum cost parameters for this table */
+ VacuumCostDelay = tab->vacuum_cost_delay;
+ VacuumCostLimit = tab->vacuum_cost_limit;
- if (vacuum_tables)
- autovacuum_do_vac_analyze(vacuum_tables, true);
+ autovacuum_do_vac_analyze(list_make1_oid(tab->relid),
+ tab->dovacuum,
+ tab->doanalyze,
+ false);
}
/* Finally close out the last transaction. */
* test_rel_for_autovac
*
* Check whether a table needs to be vacuumed or analyzed. Add it to the
- * respective list if so.
+ * output list if so.
*
* A table needs to be vacuumed if the number of dead tuples exceeds a
* threshold. This threshold is calculated as
test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
Form_pg_class classForm,
Form_pg_autovacuum avForm,
- List **vacuum_tables, List **analyze_tables)
+ List **vacuum_tables)
{
Relation rel;
float4 reltuples; /* pg_class.reltuples */
/* number of vacuum (resp. analyze) tuples at this time */
float4 vactuples,
anltuples;
+ /* cost-based vacuum delay parameters */
+ int vac_cost_limit;
+ int vac_cost_delay;
+ bool dovacuum;
+ bool doanalyze;
/* User disabled it in pg_autovacuum? */
if (avForm && !avForm->enabled)
*/
if (avForm != NULL)
{
- vac_scale_factor = (avForm->vac_scale_factor < 0) ?
- autovacuum_vac_scale : avForm->vac_scale_factor;
- vac_base_thresh = (avForm->vac_base_thresh < 0) ?
- autovacuum_vac_thresh : avForm->vac_base_thresh;
-
- anl_scale_factor = (avForm->anl_scale_factor < 0) ?
- autovacuum_anl_scale : avForm->anl_scale_factor;
- anl_base_thresh = (avForm->anl_base_thresh < 0) ?
- autovacuum_anl_thresh : avForm->anl_base_thresh;
+ vac_scale_factor = (avForm->vac_scale_factor >= 0) ?
+ avForm->vac_scale_factor : autovacuum_vac_scale;
+ vac_base_thresh = (avForm->vac_base_thresh >= 0) ?
+ avForm->vac_base_thresh : autovacuum_vac_thresh;
+
+ anl_scale_factor = (avForm->anl_scale_factor >= 0) ?
+ avForm->anl_scale_factor : autovacuum_anl_scale;
+ anl_base_thresh = (avForm->anl_base_thresh >= 0) ?
+ avForm->anl_base_thresh : autovacuum_anl_thresh;
+
+ vac_cost_limit = (avForm->vac_cost_limit >= 0) ?
+ avForm->vac_cost_limit :
+ ((autovacuum_vac_cost_limit >= 0) ?
+ autovacuum_vac_cost_limit : VacuumCostLimit);
+
+ vac_cost_delay = (avForm->vac_cost_delay >= 0) ?
+ avForm->vac_cost_delay :
+ ((autovacuum_vac_cost_delay >= 0) ?
+ autovacuum_vac_cost_delay : VacuumCostDelay);
}
else
{
anl_scale_factor = autovacuum_anl_scale;
anl_base_thresh = autovacuum_anl_thresh;
+
+ vac_cost_limit = (autovacuum_vac_cost_limit >= 0) ?
+ autovacuum_vac_cost_limit : VacuumCostLimit;
+
+ vac_cost_delay = (autovacuum_vac_cost_delay >= 0) ?
+ autovacuum_vac_cost_delay : VacuumCostDelay;
}
vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples;
RelationGetRelationName(rel),
vactuples, vacthresh, anltuples, anlthresh);
+ Assert(CurrentMemoryContext == AutovacMemCxt);
+
/* Determine if this table needs vacuum or analyze. */
- if (vactuples > vacthresh)
+ dovacuum = (vactuples > vacthresh);
+ doanalyze = (anltuples > anlthresh);
+
+ /* ANALYZE refuses to work with pg_statistics */
+ if (relid == StatisticRelationId)
+ doanalyze = false;
+
+ if (dovacuum || doanalyze)
{
- elog(DEBUG2, "will VACUUM ANALYZE %s",
+ autovac_table *tab;
+
+ elog(DEBUG2, "will%s%s %s",
+ (dovacuum ? " VACUUM" : ""),
+ (doanalyze ? " ANALYZE" : ""),
RelationGetRelationName(rel));
- *vacuum_tables = lappend_oid(*vacuum_tables, relid);
- }
- else if (anltuples > anlthresh)
- {
- /* ANALYZE refuses to work with pg_statistics */
- if (relid != StatisticRelationId)
- {
- elog(DEBUG2, "will ANALYZE %s",
- RelationGetRelationName(rel));
- *analyze_tables = lappend_oid(*analyze_tables, relid);
- }
+
+ tab = (autovac_table *) palloc(sizeof(autovac_table));
+ tab->relid = relid;
+ tab->dovacuum = dovacuum;
+ tab->doanalyze = doanalyze;
+ tab->vacuum_cost_limit = vac_cost_limit;
+ tab->vacuum_cost_delay = vac_cost_delay;
+
+ *vacuum_tables = lappend(*vacuum_tables, tab);
}
RelationClose(rel);
/*
* autovacuum_do_vac_analyze
- * Vacuum or analyze a list of tables; or all tables if relids = NIL
- *
- * We must be in AutovacMemCxt when this routine is called.
+ * Vacuum and/or analyze a list of tables; or all tables if relids = NIL
*/
static void
-autovacuum_do_vac_analyze(List *relids, bool dovacuum)
+autovacuum_do_vac_analyze(List *relids, bool dovacuum, bool doanalyze,
+ bool freeze)
{
- VacuumStmt *vacstmt = makeNode(VacuumStmt);
+ VacuumStmt *vacstmt;
+ MemoryContext old_cxt;
+
+ /*
+ * The node must survive transaction boundaries, so make sure we create it
+ * in a long-lived context
+ */
+ old_cxt = MemoryContextSwitchTo(AutovacMemCxt);
+
+ vacstmt = makeNode(VacuumStmt);
/*
* Point QueryContext to the autovac memory context to fake out the
/* Set up command parameters */
vacstmt->vacuum = dovacuum;
vacstmt->full = false;
- vacstmt->analyze = true;
- vacstmt->freeze = false;
+ vacstmt->analyze = doanalyze;
+ vacstmt->freeze = freeze;
vacstmt->verbose = false;
vacstmt->relation = NULL; /* all tables, or not used if relids != NIL */
vacstmt->va_cols = NIL;
vacuum(vacstmt, relids);
+
+ pfree(vacstmt);
+ MemoryContextSwitchTo(old_cxt);
}
/*
*
* Copyright (c) 2001-2005, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.104 2005/08/09 21:14:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.105 2005/08/11 21:11:44 tgl Exp $
* ----------
*/
#include "postgres.h"
* ----------
*/
bool pgstat_collect_startcollector = true;
-bool pgstat_collect_resetonpmstart = true;
+bool pgstat_collect_resetonpmstart = false;
bool pgstat_collect_querystring = false;
bool pgstat_collect_tuplelevel = false;
bool pgstat_collect_blocklevel = false;
* statistics on postmaster start, simply remove the stats file.
*/
if (!pgstat_collect_startcollector || pgstat_collect_resetonpmstart)
- unlink(PGSTAT_STAT_FILENAME);
+ pgstat_reset_all();
/*
* Nothing else required if collector will not get started
pgstat_collect_blocklevel = false;
}
+/*
+ * pgstat_reset_all() -
+ *
+ * Remove the stats file. This is used on server start if the
+ * stats_reset_on_server_start feature is enabled, or if WAL
+ * recovery is needed after a crash.
+ */
+void
+pgstat_reset_all(void)
+{
+ unlink(PGSTAT_STAT_FILENAME);
+}
#ifdef EXEC_BACKEND
if (pgStatSock < 0)
return;
- pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_BESTART);
- msg.m_databaseid = MyDatabaseId;
- msg.m_userid = GetSessionUserId();
- memcpy(&msg.m_clientaddr, &MyProcPort->raddr, sizeof(msg.m_clientaddr));
- pgstat_send(&msg, sizeof(msg));
+ /*
+ * We may not have a MyProcPort (eg, if this is the autovacuum process).
+ * For the moment, punt and don't send BESTART --- would be better to
+ * work out a clean way of handling "unknown clientaddr".
+ */
+ if (MyProcPort)
+ {
+ pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_BESTART);
+ msg.m_databaseid = MyDatabaseId;
+ msg.m_userid = GetSessionUserId();
+ memcpy(&msg.m_clientaddr, &MyProcPort->raddr, sizeof(msg.m_clientaddr));
+ pgstat_send(&msg, sizeof(msg));
+ }
/*
* Set up a process-exit hook to ensure we flush the last batch of
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.461 2005/07/29 19:30:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.462 2005/08/11 21:11:44 tgl Exp $
*
* NOTES
*
int syslogPipe[2];
#endif
char my_exec_path[MAXPGPATH];
+ char pkglib_path[MAXPGPATH];
char ExtraOptions[MAXPGPATH];
char lc_collate[LOCALE_NAME_BUFLEN];
char lc_ctype[LOCALE_NAME_BUFLEN];
StrNCpy(param->my_exec_path, my_exec_path, MAXPGPATH);
+ StrNCpy(param->pkglib_path, pkglib_path, MAXPGPATH);
+
StrNCpy(param->ExtraOptions, ExtraOptions, MAXPGPATH);
StrNCpy(param->lc_collate, setlocale(LC_COLLATE, NULL), LOCALE_NAME_BUFLEN);
StrNCpy(my_exec_path, param->my_exec_path, MAXPGPATH);
+ StrNCpy(pkglib_path, param->pkglib_path, MAXPGPATH);
+
StrNCpy(ExtraOptions, param->ExtraOptions, MAXPGPATH);
setlocale(LC_COLLATE, param->lc_collate);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.456 2005/08/08 03:12:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.457 2005/08/11 21:11:45 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
static void start_xact_command(void);
static void finish_xact_command(void);
static void SigHupHandler(SIGNAL_ARGS);
-static void FloatExceptionHandler(SIGNAL_ARGS);
static void log_disconnections(int code, Datum arg);
}
/* signal handler for floating point exception */
-static void
+void
FloatExceptionHandler(SIGNAL_ARGS)
{
ereport(ERROR,
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.13 2005/07/28 22:27:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.14 2005/08/11 21:11:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
char *datname;
Oid datoid;
Oid dattablespace;
- TransactionId datfrozenxid;
+ TransactionId datfrozenxid,
+ datvacuumxid;
datname = NameStr(dbform->datname);
datoid = HeapTupleGetOid(tuple);
dattablespace = dbform->dattablespace;
datfrozenxid = dbform->datfrozenxid;
+ datvacuumxid = dbform->datvacuumxid;
/*
* Identify the oldest datfrozenxid, ignoring databases that are not
}
/*
- * The file format is: "dbname" oid tablespace frozenxid
+ * The file format is: "dbname" oid tablespace frozenxid vacuumxid
*
- * The xid is not needed for backend startup, but may be of use
- * for forensic purposes.
+ * The xids are not needed for backend startup, but are of use to
+ * autovacuum, and might also be helpful for forensic purposes.
*/
fputs_quote(datname, fp);
- fprintf(fp, " %u %u %u\n", datoid, dattablespace, datfrozenxid);
+ fprintf(fp, " %u %u %u %u\n",
+ datoid, dattablespace, datfrozenxid, datvacuumxid);
}
heap_endscan(scan);
* base backup which may be far out of sync with the current state.
*
* In theory we could skip rebuilding the flat files if no WAL replay
- * occurred, but it seems safest to just do it always. We have to
- * scan pg_database to compute the XID wrap limit anyway.
+ * occurred, but it seems best to just do it always. We have to
+ * scan pg_database to compute the XID wrap limit anyway. Also, this
+ * policy means we need not force initdb to change the format of the
+ * flat files.
*
* In a standalone backend we pass database_only = true to skip processing
* the auth file. We won't need it, and building it could fail if there's
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.156 2005/08/08 03:12:14 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.157 2005/08/11 21:11:46 tgl Exp $
*
*
*-------------------------------------------------------------------------
#include <math.h>
#include <unistd.h>
+#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catalog.h"
+#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_database.h"
char *filename;
FILE *db_file;
char thisname[NAMEDATALEN];
- TransactionId frozenxid;
+ TransactionId dummyxid;
filename = database_getflatfilename();
db_file = AllocateFile(filename, "r");
errmsg("could not open file \"%s\": %m", filename)));
while (read_pg_database_line(db_file, thisname, db_id,
- db_tablespace, &frozenxid))
+ db_tablespace, &dummyxid,
+ &dummyxid))
{
if (strcmp(thisname, name) == 0)
{
ReverifyMyDatabase(const char *name)
{
Relation pgdbrel;
- HeapScanDesc pgdbscan;
+ SysScanDesc pgdbscan;
ScanKeyData key;
HeapTuple tup;
Form_pg_database dbform;
BTEqualStrategyNumber, F_NAMEEQ,
NameGetDatum(name));
- pgdbscan = heap_beginscan(pgdbrel, SnapshotNow, 1, &key);
+ pgdbscan = systable_beginscan(pgdbrel, DatabaseNameIndexId, true,
+ SnapshotNow, 1, &key);
- tup = heap_getnext(pgdbscan, ForwardScanDirection);
+ tup = systable_getnext(pgdbscan);
if (!HeapTupleIsValid(tup) ||
HeapTupleGetOid(tup) != MyDatabaseId)
{
}
}
- heap_endscan(pgdbscan);
+ systable_endscan(pgdbscan);
heap_close(pgdbrel, RowShareLock);
}
/* Initialize portal manager */
EnablePortalManager();
+ /*
+ * Set up process-exit callback to do pre-shutdown cleanup. This
+ * has to be after we've initialized all the low-level modules
+ * like the buffer manager, because during shutdown this has to
+ * run before the low-level modules start to close down. On the
+ * other hand, we want it in place before we begin our first
+ * transaction --- if we fail during the initialization transaction,
+ * as is entirely possible, we need the AbortTransaction call to
+ * clean up.
+ */
+ on_shmem_exit(ShutdownPostgres, 0);
+
/* start a new transaction here before access to db */
if (!bootstrap)
StartTransactionCommand();
/*
* Unless we are bootstrapping, double-check that InitMyDatabaseInfo()
* got a correct result. We can't do this until all the
- * database-access infrastructure is up.
+ * database-access infrastructure is up. (Also, it wants to know if
+ * the user is a superuser, so the above stuff has to happen first.)
*/
if (!bootstrap)
ReverifyMyDatabase(dbname);
/* initialize client encoding */
InitializeClientEncoding();
- /*
- * Initialize statistics collection for this backend. We do this
- * here because the shutdown hook it sets up needs to be invoked
- * at the corresponding phase of backend shutdown: after
- * ShutdownPostgres and before we drop access to shared memory.
- */
+ /* initialize statistics collection for this backend */
if (IsUnderPostmaster)
pgstat_bestart();
- /*
- * Set up process-exit callback to do pre-shutdown cleanup. This
- * should be last because we want shmem_exit to call this routine
- * before the exit callbacks that are registered by buffer manager,
- * lock manager, etc. We need to run this code before we close down
- * database access!
- */
- on_shmem_exit(ShutdownPostgres, 0);
-
/* close the transaction we started above */
if (!bootstrap)
CommitTransactionCommand();
/*
* Backend-shutdown callback. Do cleanup that we want to be sure happens
* before all the supporting modules begin to nail their doors shut via
- * their own callbacks. Note that because this has to be registered very
- * late in startup, it will not get called if we suffer a failure *during*
- * startup.
+ * their own callbacks.
*
* User-level cleanup, such as temp-relation removal and UNLISTEN, happens
* via separate callbacks that execute before this one. We don't combine the
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.280 2005/07/30 15:17:20 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.281 2005/08/11 21:11:47 tgl Exp $
*
*--------------------------------------------------------------------
*/
NULL
},
&pgstat_collect_resetonpmstart,
- true, NULL, NULL
+ false, NULL, NULL
},
{
{"stats_command_string", PGC_SUSET, STATS_COLLECTOR,
0, 0, 1000, NULL, NULL
},
+ {
+ {"autovacuum_vacuum_cost_delay", PGC_SIGHUP, AUTOVACUUM,
+ gettext_noop("Vacuum cost delay in milliseconds, for autovacuum."),
+ NULL
+ },
+ &autovacuum_vac_cost_delay,
+ -1, -1, 1000, NULL, NULL
+ },
+
+ {
+ {"autovacuum_vacuum_cost_limit", PGC_SIGHUP, AUTOVACUUM,
+ gettext_noop("Vacuum cost amount available before napping, for autovacuum."),
+ NULL
+ },
+ &autovacuum_vac_cost_limit,
+ -1, -1, 10000, NULL, NULL
+ },
+
{
{"max_files_per_process", PGC_POSTMASTER, RESOURCES_KERNEL,
gettext_noop("Sets the maximum number of simultaneously open files for each server process."),
#stats_command_string = off
#stats_block_level = off
#stats_row_level = off
-#stats_reset_on_server_start = on
+#stats_reset_on_server_start = off
#---------------------------------------------------------------------------
#autovacuum_analyze_threshold = 500 # min # of tuple updates before analyze
#autovacuum_vacuum_scale_factor = 0.4 # fraction of rel size before vacuum
#autovacuum_analyze_scale_factor = 0.2 # fraction of rel size before analyze
+#autovacuum_vacuum_cost_delay = -1 # default vacuum cost delay for autovac
+ # -1 means use vacuum_cost_delay
+#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for autovac
+ # -1 means use vacuum_cost_limit
#---------------------------------------------------------------------------
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.295 2005/08/01 20:31:14 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.296 2005/08/11 21:11:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200508011
+#define CATALOG_VERSION_NO 200508111
#endif
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_autovacuum.h,v 1.1 2005/07/14 05:13:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_autovacuum.h,v 1.2 2005/08/11 21:11:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
float4 vac_scale_factor; /* reltuples scaling factor */
int4 anl_base_thresh; /* base threshold value */
float4 anl_scale_factor; /* reltuples scaling factor */
+ int4 vac_cost_delay; /* vacuum cost-based delay */
+ int4 vac_cost_limit; /* vacuum cost limit */
} FormData_pg_autovacuum;
/* ----------------
* compiler constants for pg_autovacuum
* ----------------
*/
-#define Natts_pg_autovacuum 6
+#define Natts_pg_autovacuum 8
#define Anum_pg_autovacuum_vacrelid 1
#define Anum_pg_autovacuum_enabled 2
#define Anum_pg_autovacuum_vac_base_thresh 3
#define Anum_pg_autovacuum_vac_scale_factor 4
#define Anum_pg_autovacuum_anl_base_thresh 5
#define Anum_pg_autovacuum_anl_scale_factor 6
+#define Anum_pg_autovacuum_vac_cost_delay 7
+#define Anum_pg_autovacuum_vac_cost_limit 8
/* There are no preloaded tuples in pg_autovacuum.h */
* Interface to hba.c
*
*
- * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.39 2005/07/29 19:30:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.40 2005/08/11 21:11:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern int hba_getauthmethod(hbaPort *port);
extern int authident(hbaPort *port);
extern bool read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
- Oid *dbtablespace, TransactionId *dbfrozenxid);
+ Oid *dbtablespace, TransactionId *dbfrozenxid,
+ TransactionId *dbvacuumxid);
#endif /* HBA_H */
*
* Copyright (c) 2001-2005, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.34 2005/07/29 19:30:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.35 2005/08/11 21:11:49 tgl Exp $
* ----------
*/
#ifndef PGSTAT_H
extern void pgstat_init(void);
extern int pgstat_start(void);
extern void pgstat_beterm(int pid);
+extern void pgstat_reset_all(void);
#ifdef EXEC_BACKEND
extern void PgstatBufferMain(int argc, char *argv[]);
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/postmaster/autovacuum.h,v 1.1 2005/07/14 05:13:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/postmaster/autovacuum.h,v 1.2 2005/08/11 21:11:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern double autovacuum_vac_scale;
extern int autovacuum_anl_thresh;
extern double autovacuum_anl_scale;
+extern int autovacuum_vac_cost_delay;
+extern int autovacuum_vac_cost_limit;
/* Status inquiry functions */
extern bool AutoVacuumingActive(void);
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.76 2005/07/14 05:13:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.77 2005/08/11 21:11:50 tgl Exp $
*
* OLD COMMENTS
* This file was created so that other c files could get the two
extern void quickdie(SIGNAL_ARGS);
extern void authdie(SIGNAL_ARGS);
extern void StatementCancelHandler(SIGNAL_ARGS);
+extern void FloatExceptionHandler(SIGNAL_ARGS);
extern void prepare_for_client_read(void);
extern void client_read_ended(void);
extern int PostgresMain(int argc, char *argv[], const char *username);