mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Integrate autovacuum functionality into the backend. There's still a
few loose ends to be dealt with, but it seems to work. Alvaro Herrera, based on the contrib code by Matthew O'Connor.
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
<!--
|
<!--
|
||||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.107 2005/07/07 20:39:56 tgl Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.108 2005/07/14 05:13:38 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="catalogs">
|
<chapter id="catalogs">
|
||||||
@ -88,6 +88,11 @@
|
|||||||
<entry>authorization identifier membership relationships</entry>
|
<entry>authorization identifier membership relationships</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><link linkend="catalog-pg-autovacuum"><structname>pg_autovacuum</structname></link></entry>
|
||||||
|
<entry>per-relation autovacuum configuration parameters</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><link linkend="catalog-pg-cast"><structname>pg_cast</structname></link></entry>
|
<entry><link linkend="catalog-pg-cast"><structname>pg_cast</structname></link></entry>
|
||||||
<entry>casts (data type conversions)</entry>
|
<entry>casts (data type conversions)</entry>
|
||||||
@ -1102,6 +1107,104 @@
|
|||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
|
||||||
|
<sect1 id="catalog-pg-autovacuum">
|
||||||
|
<title><structname>pg_autovacuum</structname></title>
|
||||||
|
|
||||||
|
<indexterm zone="catalog-pg-autovacuum">
|
||||||
|
<primary>pg_autovacuum</primary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The catalog <structname>pg_autovacuum</structname> stores optional
|
||||||
|
per-relation configuration parameters for <quote>autovacuum</>.
|
||||||
|
If there is an entry here for a particular relation, the given
|
||||||
|
parameters will be used for autovacuuming that table. If no entry
|
||||||
|
is present, the system-wide defaults will be used.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<title><structname>pg_autovacuum</> Columns</title>
|
||||||
|
|
||||||
|
<tgroup cols=4>
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Name</entry>
|
||||||
|
<entry>Type</entry>
|
||||||
|
<entry>References</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry><structfield>vacrelid</structfield></entry>
|
||||||
|
<entry><type>oid</type></entry>
|
||||||
|
<entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
|
||||||
|
<entry>The table this entry is for</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>enabled</structfield></entry>
|
||||||
|
<entry><type>bool</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>If false, this table is never autovacuumed</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>vac_base_thresh</structfield></entry>
|
||||||
|
<entry><type>integer</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Minimum number of modified tuples before vacuum</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>vac_scale_factor</structfield></entry>
|
||||||
|
<entry><type>float4</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Multiplier for reltuples to add to
|
||||||
|
<structfield>vac_base_thresh</></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>anl_base_thresh</structfield></entry>
|
||||||
|
<entry><type>integer</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Minimum number of modified tuples before analyze</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>anl_scale_factor</structfield></entry>
|
||||||
|
<entry><type>float4</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Multiplier for reltuples to add to
|
||||||
|
<structfield>anl_base_thresh</></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The autovacuum daemon will initiate a <command>VACUUM</> operation
|
||||||
|
on a particular table when the number of updated or deleted tuples
|
||||||
|
exceeds <structfield>vac_base_thresh</structfield> plus
|
||||||
|
<structfield>vac_scale_factor</structfield> times the number of
|
||||||
|
live tuples currently estimated to be in the relation.
|
||||||
|
Similarly, it will initiate an <command>ANALYZE</> operation
|
||||||
|
when the number of inserted, updated or deleted tuples
|
||||||
|
exceeds <structfield>anl_base_thresh</structfield> plus
|
||||||
|
<structfield>anl_scale_factor</structfield> times the number of
|
||||||
|
live tuples currently estimated to be in the relation.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<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.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
|
||||||
<sect1 id="catalog-pg-cast">
|
<sect1 id="catalog-pg-cast">
|
||||||
<title><structname>pg_cast</structname></title>
|
<title><structname>pg_cast</structname></title>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.337 2005/07/06 14:45:12 momjian Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.338 2005/07/14 05:13:38 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter Id="runtime">
|
<chapter Id="runtime">
|
||||||
@ -3173,7 +3173,7 @@ archive_command = 'copy "%p" /mnt/server/archivedir/"%f"' # Windows
|
|||||||
If on, collected statistics are zeroed out whenever the server
|
If on, collected statistics are zeroed out whenever the server
|
||||||
is restarted. If off, statistics are accumulated across 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>on</>. This option can only
|
||||||
be set at server start.
|
be set at server start.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -3182,6 +3182,127 @@ archive_command = 'copy "%p" /mnt/server/archivedir/"%f"' # Windows
|
|||||||
</sect3>
|
</sect3>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="runtime-config-autovacuum">
|
||||||
|
<title>Automatic Vacuuming</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Beginning in <productname>PostgreSQL</> 8.1, there is an optional server
|
||||||
|
process called the <firstterm>autovacuum daemon</>, whose purpose is
|
||||||
|
to automate the issuance of periodic <command>VACUUM</> and
|
||||||
|
<command>ANALYZE</> commands. When enabled, the autovacuum daemon
|
||||||
|
runs periodically and checks for tables that have had a large number
|
||||||
|
of updated or deleted tuples. This check uses the row-level statistics
|
||||||
|
collection facility; therefore, the autovacuum daemon cannot be used
|
||||||
|
unless <xref linkend="guc-stats-start-collector"> and
|
||||||
|
<xref linkend="guc-stats-row-level"> are set TRUE. Also, it's
|
||||||
|
important to allow a slot for the autovacuum process when choosing
|
||||||
|
the value of <xref linkend="guc-superuser-reserved-connections">.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
|
||||||
|
<varlistentry id="guc-autovacuum" xreflabel="autovacuum">
|
||||||
|
<term><varname>autovacuum</varname> (<type>boolean</type>)</term>
|
||||||
|
<indexterm>
|
||||||
|
<primary><varname>autovacuum</> configuration parameter</primary>
|
||||||
|
</indexterm>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Controls whether the server should start the
|
||||||
|
autovacuum subprocess. This is off by default.
|
||||||
|
This option can only be set at server start or in the
|
||||||
|
<filename>postgresql.conf</filename> file.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="guc-autovacuum-naptime" xreflabel="autovacuum_naptime">
|
||||||
|
<term><varname>autovacuum_naptime</varname> (<type>integer</type>)</term>
|
||||||
|
<indexterm>
|
||||||
|
<primary><varname>autovacuum_naptime</> configuration parameter</primary>
|
||||||
|
</indexterm>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Specifies the delay between activity rounds for the autovacuum
|
||||||
|
subprocess. In each round the subprocess examines one database
|
||||||
|
and issues <command>VACUUM</> and <command>ANALYZE</> commands
|
||||||
|
as needed for tables in that database. The delay is measured
|
||||||
|
in seconds, and the default is 60.
|
||||||
|
This option can only be set at server start or in the
|
||||||
|
<filename>postgresql.conf</filename> file.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="guc-autovacuum-vacuum-threshold" xreflabel="autovacuum_vacuum_threshold">
|
||||||
|
<term><varname>autovacuum_vacuum_threshold</varname> (<type>integer</type>)</term>
|
||||||
|
<indexterm>
|
||||||
|
<primary><varname>autovacuum_vacuum_threshold</> configuration parameter</primary>
|
||||||
|
</indexterm>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Specifies the minimum number of updated or deleted tuples needed
|
||||||
|
to trigger a <command>VACUUM</> in any one table.
|
||||||
|
The default is 1000.
|
||||||
|
This option can only be set at server start or in the
|
||||||
|
<filename>postgresql.conf</filename> file.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="guc-autovacuum-analyze-threshold" xreflabel="autovacuum_analyze_threshold">
|
||||||
|
<term><varname>autovacuum_analyze_threshold</varname> (<type>integer</type>)</term>
|
||||||
|
<indexterm>
|
||||||
|
<primary><varname>autovacuum_analyze_threshold</> configuration parameter</primary>
|
||||||
|
</indexterm>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Specifies the minimum number of inserted, updated or deleted tuples
|
||||||
|
needed to trigger an <command>ANALYZE</> in any one table.
|
||||||
|
The default is 500.
|
||||||
|
This option can only be set at server start or in the
|
||||||
|
<filename>postgresql.conf</filename> file.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="guc-autovacuum-vacuum-scale-factor" xreflabel="autovacuum_vacuum_scale_factor">
|
||||||
|
<term><varname>autovacuum_vacuum_scale_factor</varname> (<type>floating point</type>)</term>
|
||||||
|
<indexterm>
|
||||||
|
<primary><varname>autovacuum_vacuum_scale_factor</> configuration parameter</primary>
|
||||||
|
</indexterm>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Specifies a fraction of the table size to add to
|
||||||
|
<varname>autovacuum_vacuum_threshold</varname>
|
||||||
|
when deciding whether to trigger a <command>VACUUM</>.
|
||||||
|
The default is 0.4.
|
||||||
|
This option can only be set at server start or in the
|
||||||
|
<filename>postgresql.conf</filename> file.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="guc-autovacuum-analyze-scale-factor" xreflabel="autovacuum_analyze_scale_factor">
|
||||||
|
<term><varname>autovacuum_analyze_scale_factor</varname> (<type>floating point</type>)</term>
|
||||||
|
<indexterm>
|
||||||
|
<primary><varname>autovacuum_analyze_scale_factor</> configuration parameter</primary>
|
||||||
|
</indexterm>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Specifies a fraction of the table size to add to
|
||||||
|
<varname>autovacuum_analyze_threshold</varname>
|
||||||
|
when deciding whether to trigger an <command>ANALYZE</>.
|
||||||
|
The default is 0.2.
|
||||||
|
This option can only be set at server start or in the
|
||||||
|
<filename>postgresql.conf</filename> file.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="runtime-config-client">
|
<sect2 id="runtime-config-client">
|
||||||
<title>Client Connection Defaults</title>
|
<title>Client Connection Defaults</title>
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#
|
#
|
||||||
# Makefile for backend/catalog
|
# Makefile for backend/catalog
|
||||||
#
|
#
|
||||||
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.55 2005/07/07 20:39:57 tgl Exp $
|
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.56 2005/07/14 05:13:39 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ SUBSYS.o: $(OBJS)
|
|||||||
# indexing.h had better be last.
|
# indexing.h had better be last.
|
||||||
|
|
||||||
POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
|
POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
|
||||||
pg_proc.h pg_type.h pg_attribute.h pg_class.h \
|
pg_proc.h pg_type.h pg_attribute.h pg_class.h pg_autovacuum.h \
|
||||||
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h \
|
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h \
|
||||||
pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
|
pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
|
||||||
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
|
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.86 2005/05/06 17:24:53 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.87 2005/07/14 05:13:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -29,6 +29,7 @@
|
|||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
#include "parser/parse_oper.h"
|
#include "parser/parse_oper.h"
|
||||||
#include "parser/parse_relation.h"
|
#include "parser/parse_relation.h"
|
||||||
|
#include "pgstat.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/datum.h"
|
#include "utils/datum.h"
|
||||||
@ -77,7 +78,7 @@ static void compute_index_stats(Relation onerel, double totalrows,
|
|||||||
MemoryContext col_context);
|
MemoryContext col_context);
|
||||||
static VacAttrStats *examine_attribute(Relation onerel, int attnum);
|
static VacAttrStats *examine_attribute(Relation onerel, int attnum);
|
||||||
static int acquire_sample_rows(Relation onerel, HeapTuple *rows,
|
static int acquire_sample_rows(Relation onerel, HeapTuple *rows,
|
||||||
int targrows, double *totalrows);
|
int targrows, double *totalrows, double *totaldeadrows);
|
||||||
static double random_fract(void);
|
static double random_fract(void);
|
||||||
static double init_selection_state(int n);
|
static double init_selection_state(int n);
|
||||||
static double get_next_S(double t, int n, double *stateptr);
|
static double get_next_S(double t, int n, double *stateptr);
|
||||||
@ -108,7 +109,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
|||||||
AnlIndexData *indexdata;
|
AnlIndexData *indexdata;
|
||||||
int targrows,
|
int targrows,
|
||||||
numrows;
|
numrows;
|
||||||
double totalrows;
|
double totalrows,
|
||||||
|
totaldeadrows;
|
||||||
HeapTuple *rows;
|
HeapTuple *rows;
|
||||||
|
|
||||||
if (vacstmt->verbose)
|
if (vacstmt->verbose)
|
||||||
@ -309,6 +311,14 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
|||||||
*/
|
*/
|
||||||
if (attr_cnt <= 0 && !analyzableindex)
|
if (attr_cnt <= 0 && !analyzableindex)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* We report that the table is empty; this is just so that the
|
||||||
|
* autovacuum code doesn't go nuts trying to get stats about
|
||||||
|
* a zero-column table.
|
||||||
|
*/
|
||||||
|
if (!vacstmt->vacuum)
|
||||||
|
pgstat_report_analyze(RelationGetRelid(onerel), 0, 0);
|
||||||
|
|
||||||
vac_close_indexes(nindexes, Irel, AccessShareLock);
|
vac_close_indexes(nindexes, Irel, AccessShareLock);
|
||||||
relation_close(onerel, AccessShareLock);
|
relation_close(onerel, AccessShareLock);
|
||||||
return;
|
return;
|
||||||
@ -340,7 +350,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
|||||||
* Acquire the sample rows
|
* Acquire the sample rows
|
||||||
*/
|
*/
|
||||||
rows = (HeapTuple *) palloc(targrows * sizeof(HeapTuple));
|
rows = (HeapTuple *) palloc(targrows * sizeof(HeapTuple));
|
||||||
numrows = acquire_sample_rows(onerel, rows, targrows, &totalrows);
|
numrows = acquire_sample_rows(onerel, rows, targrows,
|
||||||
|
&totalrows, &totaldeadrows);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute the statistics. Temporary results during the calculations
|
* Compute the statistics. Temporary results during the calculations
|
||||||
@ -423,6 +434,10 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
|||||||
totalindexrows,
|
totalindexrows,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* report results to the stats collector, too */
|
||||||
|
pgstat_report_analyze(RelationGetRelid(onerel), totalrows,
|
||||||
|
totaldeadrows);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Done with indexes */
|
/* Done with indexes */
|
||||||
@ -752,23 +767,25 @@ BlockSampler_Next(BlockSampler bs)
|
|||||||
* the number of different blocks represented by the sample tends to be
|
* the number of different blocks represented by the sample tends to be
|
||||||
* too small. We can live with that for now. Improvements are welcome.
|
* too small. We can live with that for now. Improvements are welcome.
|
||||||
*
|
*
|
||||||
* We also estimate the total number of rows in the table, and return that
|
* We also estimate the total numbers of live and dead rows in the table,
|
||||||
* into *totalrows. An important property of this sampling method is that
|
* and return them into *totalrows and *totaldeadrows, respectively.
|
||||||
* because we do look at a statistically unbiased set of blocks, we should
|
*
|
||||||
* get an unbiased estimate of the average number of live rows per block.
|
* An important property of this sampling method is that because we do
|
||||||
* The previous sampling method put too much credence in the row density near
|
* look at a statistically unbiased set of blocks, we should get
|
||||||
* the start of the table.
|
* unbiased estimates of the average numbers of live and dead rows per
|
||||||
|
* block. The previous sampling method put too much credence in the row
|
||||||
|
* density near the start of the table.
|
||||||
*
|
*
|
||||||
* The returned list of tuples is in order by physical position in the table.
|
* The returned list of tuples is in order by physical position in the table.
|
||||||
* (We will rely on this later to derive correlation estimates.)
|
* (We will rely on this later to derive correlation estimates.)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||||
double *totalrows)
|
double *totalrows, double *totaldeadrows)
|
||||||
{
|
{
|
||||||
int numrows = 0; /* # rows collected */
|
int numrows = 0; /* # rows collected */
|
||||||
double liverows = 0; /* # rows seen */
|
double liverows = 0; /* # rows seen */
|
||||||
double deadrows = 0;
|
double deadrows = 0; /* # dead rows seen */
|
||||||
double rowstoskip = -1; /* -1 means not set yet */
|
double rowstoskip = -1; /* -1 means not set yet */
|
||||||
BlockNumber totalblocks;
|
BlockNumber totalblocks;
|
||||||
BlockSamplerData bs;
|
BlockSamplerData bs;
|
||||||
@ -864,11 +881,7 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/* Count dead rows, but not empty slots */
|
||||||
* Count dead rows, but not empty slots. This information
|
|
||||||
* is currently not used, but it seems likely we'll want
|
|
||||||
* it someday.
|
|
||||||
*/
|
|
||||||
if (targtuple.t_data != NULL)
|
if (targtuple.t_data != NULL)
|
||||||
deadrows += 1;
|
deadrows += 1;
|
||||||
}
|
}
|
||||||
@ -890,12 +903,18 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
|||||||
qsort((void *) rows, numrows, sizeof(HeapTuple), compare_rows);
|
qsort((void *) rows, numrows, sizeof(HeapTuple), compare_rows);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Estimate total number of live rows in relation.
|
* Estimate total numbers of rows in relation.
|
||||||
*/
|
*/
|
||||||
if (bs.m > 0)
|
if (bs.m > 0)
|
||||||
|
{
|
||||||
*totalrows = floor((liverows * totalblocks) / bs.m + 0.5);
|
*totalrows = floor((liverows * totalblocks) / bs.m + 0.5);
|
||||||
|
*totaldeadrows = floor((deadrows * totalblocks) / bs.m + 0.5);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
*totalrows = 0.0;
|
*totalrows = 0.0;
|
||||||
|
*totaldeadrows = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emit some interesting relation info
|
* Emit some interesting relation info
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.310 2005/06/14 22:15:32 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.311 2005/07/14 05:13:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -166,7 +166,8 @@ static TransactionId FreezeLimit;
|
|||||||
|
|
||||||
|
|
||||||
/* non-export function prototypes */
|
/* non-export function prototypes */
|
||||||
static List *get_rel_oids(const RangeVar *vacrel, const char *stmttype);
|
static List *get_rel_oids(List *relids, const RangeVar *vacrel,
|
||||||
|
const char *stmttype);
|
||||||
static void vac_update_dbstats(Oid dbid,
|
static void vac_update_dbstats(Oid dbid,
|
||||||
TransactionId vacuumXID,
|
TransactionId vacuumXID,
|
||||||
TransactionId frozenXID);
|
TransactionId frozenXID);
|
||||||
@ -221,9 +222,18 @@ static bool enough_space(VacPage vacpage, Size len);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Primary entry point for VACUUM and ANALYZE commands.
|
* Primary entry point for VACUUM and ANALYZE commands.
|
||||||
|
*
|
||||||
|
* relids is normally NIL; if it is not, then it provides the list of
|
||||||
|
* relation OIDs to be processed, and vacstmt->relation is ignored.
|
||||||
|
* (The non-NIL case is currently only used by autovacuum.)
|
||||||
|
*
|
||||||
|
* It is the caller's responsibility that both vacstmt and relids
|
||||||
|
* (if given) be allocated in a memory context that won't disappear
|
||||||
|
* at transaction commit. In fact this context must be QueryContext
|
||||||
|
* to avoid complaints from PreventTransactionChain.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
vacuum(VacuumStmt *vacstmt)
|
vacuum(VacuumStmt *vacstmt, List *relids)
|
||||||
{
|
{
|
||||||
const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
|
const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
|
||||||
TransactionId initialOldestXmin = InvalidTransactionId;
|
TransactionId initialOldestXmin = InvalidTransactionId;
|
||||||
@ -302,11 +312,14 @@ vacuum(VacuumStmt *vacstmt)
|
|||||||
ALLOCSET_DEFAULT_INITSIZE,
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
/* Assume we are processing everything unless one table is mentioned */
|
/* Remember whether we are processing everything in the DB */
|
||||||
all_rels = (vacstmt->relation == NULL);
|
all_rels = (relids == NIL && vacstmt->relation == NULL);
|
||||||
|
|
||||||
/* Build list of relations to process (note this lives in vac_context) */
|
/*
|
||||||
relations = get_rel_oids(vacstmt->relation, stmttype);
|
* Build list of relations to process, unless caller gave us one.
|
||||||
|
* (If we build one, we put it in vac_context for safekeeping.)
|
||||||
|
*/
|
||||||
|
relations = get_rel_oids(relids, vacstmt->relation, stmttype);
|
||||||
|
|
||||||
if (vacstmt->vacuum && all_rels)
|
if (vacstmt->vacuum && all_rels)
|
||||||
{
|
{
|
||||||
@ -512,11 +525,15 @@ vacuum(VacuumStmt *vacstmt)
|
|||||||
* per-relation transactions.
|
* per-relation transactions.
|
||||||
*/
|
*/
|
||||||
static List *
|
static List *
|
||||||
get_rel_oids(const RangeVar *vacrel, const char *stmttype)
|
get_rel_oids(List *relids, const RangeVar *vacrel, const char *stmttype)
|
||||||
{
|
{
|
||||||
List *oid_list = NIL;
|
List *oid_list = NIL;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
|
/* List supplied by VACUUM's caller? */
|
||||||
|
if (relids)
|
||||||
|
return relids;
|
||||||
|
|
||||||
if (vacrel)
|
if (vacrel)
|
||||||
{
|
{
|
||||||
/* Process a specific relation */
|
/* Process a specific relation */
|
||||||
@ -1146,6 +1163,10 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
|
|||||||
/* update statistics in pg_class */
|
/* update statistics in pg_class */
|
||||||
vac_update_relstats(RelationGetRelid(onerel), vacrelstats->rel_pages,
|
vac_update_relstats(RelationGetRelid(onerel), vacrelstats->rel_pages,
|
||||||
vacrelstats->rel_tuples, vacrelstats->hasindex);
|
vacrelstats->rel_tuples, vacrelstats->hasindex);
|
||||||
|
|
||||||
|
/* report results to the stats collector, too */
|
||||||
|
pgstat_report_vacuum(RelationGetRelid(onerel), vacstmt->analyze,
|
||||||
|
vacrelstats->rel_tuples);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.54 2005/05/19 21:35:46 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.55 2005/07/14 05:13:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -44,6 +44,7 @@
|
|||||||
#include "access/xlog.h"
|
#include "access/xlog.h"
|
||||||
#include "commands/vacuum.h"
|
#include "commands/vacuum.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "pgstat.h"
|
||||||
#include "storage/freespace.h"
|
#include "storage/freespace.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
@ -179,6 +180,10 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
|
|||||||
vacrelstats->rel_pages,
|
vacrelstats->rel_pages,
|
||||||
vacrelstats->rel_tuples,
|
vacrelstats->rel_tuples,
|
||||||
hasindex);
|
hasindex);
|
||||||
|
|
||||||
|
/* report results to the stats collector, too */
|
||||||
|
pgstat_report_vacuum(RelationGetRelid(onerel), vacstmt->analyze,
|
||||||
|
vacrelstats->rel_tuples);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# Makefile for src/backend/postmaster
|
# Makefile for src/backend/postmaster
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.20 2005/03/10 07:14:03 neilc Exp $
|
# $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.21 2005/07/14 05:13:40 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -12,7 +12,8 @@ subdir = src/backend/postmaster
|
|||||||
top_builddir = ../../..
|
top_builddir = ../../..
|
||||||
include $(top_builddir)/src/Makefile.global
|
include $(top_builddir)/src/Makefile.global
|
||||||
|
|
||||||
OBJS = bgwriter.o fork_process.o pgarch.o pgstat.o postmaster.o syslogger.o
|
OBJS = bgwriter.o autovacuum.o pgarch.o pgstat.o postmaster.o syslogger.o \
|
||||||
|
fork_process.o
|
||||||
|
|
||||||
all: SUBSYS.o
|
all: SUBSYS.o
|
||||||
|
|
||||||
|
750
src/backend/postmaster/autovacuum.c
Normal file
750
src/backend/postmaster/autovacuum.c
Normal file
@ -0,0 +1,750 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* autovacuum.c
|
||||||
|
*
|
||||||
|
* PostgreSQL Integrated Autovacuum Daemon
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* IDENTIFICATION
|
||||||
|
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.1 2005/07/14 05:13:40 tgl Exp $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "access/genam.h"
|
||||||
|
#include "access/heapam.h"
|
||||||
|
#include "catalog/indexing.h"
|
||||||
|
#include "catalog/pg_autovacuum.h"
|
||||||
|
#include "catalog/pg_database.h"
|
||||||
|
#include "commands/vacuum.h"
|
||||||
|
#include "libpq/hba.h"
|
||||||
|
#include "libpq/pqsignal.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
|
#include "pgstat.h"
|
||||||
|
#include "postmaster/autovacuum.h"
|
||||||
|
#include "postmaster/fork_process.h"
|
||||||
|
#include "postmaster/postmaster.h"
|
||||||
|
#include "storage/fd.h"
|
||||||
|
#include "storage/ipc.h"
|
||||||
|
#include "storage/proc.h"
|
||||||
|
#include "storage/sinval.h"
|
||||||
|
#include "tcop/tcopprot.h"
|
||||||
|
#include "utils/flatfiles.h"
|
||||||
|
#include "utils/fmgroids.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
|
#include "utils/ps_status.h"
|
||||||
|
#include "utils/relcache.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GUC parameters
|
||||||
|
*/
|
||||||
|
bool autovacuum_start_daemon = false;
|
||||||
|
int autovacuum_naptime;
|
||||||
|
int autovacuum_vac_thresh;
|
||||||
|
double autovacuum_vac_scale;
|
||||||
|
int autovacuum_anl_thresh;
|
||||||
|
double autovacuum_anl_scale;
|
||||||
|
|
||||||
|
/* Flag to tell if we are in the autovacuum daemon process */
|
||||||
|
static bool am_autovacuum = false;
|
||||||
|
|
||||||
|
/* Last time autovac daemon started/stopped (only valid in postmaster) */
|
||||||
|
static time_t last_autovac_start_time = 0;
|
||||||
|
static time_t last_autovac_stop_time = 0;
|
||||||
|
|
||||||
|
/* struct to keep list of candidate databases for vacuum */
|
||||||
|
typedef struct autovac_dbase
|
||||||
|
{
|
||||||
|
Oid oid;
|
||||||
|
char *name;
|
||||||
|
PgStat_StatDBEntry *entry;
|
||||||
|
} autovac_dbase;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef EXEC_BACKEND
|
||||||
|
static pid_t autovac_forkexec(void);
|
||||||
|
#endif
|
||||||
|
NON_EXEC_STATIC void AutoVacMain(int argc, char *argv[]);
|
||||||
|
static void autovac_check_wraparound(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);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main entry point for autovacuum controller process.
|
||||||
|
*
|
||||||
|
* This code is heavily based on pgarch.c, q.v.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
autovac_start(void)
|
||||||
|
{
|
||||||
|
time_t curtime;
|
||||||
|
pid_t AutoVacPID;
|
||||||
|
|
||||||
|
/* Do nothing if no autovacuum process needed */
|
||||||
|
if (!AutoVacuumingActive())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do nothing if too soon since last autovacuum exit. This limits
|
||||||
|
* how often the daemon runs. Since the time per iteration can be
|
||||||
|
* quite variable, it seems more useful to measure/control the time
|
||||||
|
* since last subprocess exit than since last subprocess launch.
|
||||||
|
*
|
||||||
|
* However, we *also* check the time since last subprocess launch;
|
||||||
|
* this prevents thrashing under fork-failure conditions.
|
||||||
|
*
|
||||||
|
* Note that since we will be re-called from the postmaster main loop,
|
||||||
|
* we will get another chance later if we do nothing now.
|
||||||
|
*
|
||||||
|
* XXX todo: implement sleep scale factor that existed in contrib code.
|
||||||
|
*/
|
||||||
|
curtime = time(NULL);
|
||||||
|
if ((unsigned int) (curtime - last_autovac_stop_time) <
|
||||||
|
(unsigned int) autovacuum_naptime)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((unsigned int) (curtime - last_autovac_start_time) <
|
||||||
|
(unsigned int) autovacuum_naptime)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
last_autovac_start_time = curtime;
|
||||||
|
|
||||||
|
#ifdef EXEC_BACKEND
|
||||||
|
switch((AutoVacPID = autovac_forkexec()))
|
||||||
|
#else
|
||||||
|
switch((AutoVacPID = fork_process()))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
ereport(LOG,
|
||||||
|
(errmsg("could not fork autovacuum process: %m")));
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#ifndef EXEC_BACKEND
|
||||||
|
case 0:
|
||||||
|
/* in postmaster child ... */
|
||||||
|
/* Close the postmaster's sockets */
|
||||||
|
ClosePostmasterPorts(false);
|
||||||
|
|
||||||
|
AutoVacMain(0, NULL);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return (int) AutoVacPID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shouldn't get here */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* autovac_stopped --- called by postmaster when subprocess exit is detected
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
autovac_stopped(void)
|
||||||
|
{
|
||||||
|
last_autovac_stop_time = time(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef EXEC_BACKEND
|
||||||
|
/*
|
||||||
|
* autovac_forkexec()
|
||||||
|
*
|
||||||
|
* Format up the arglist for the autovacuum process, then fork and exec.
|
||||||
|
*/
|
||||||
|
static pid_t
|
||||||
|
autovac_forkexec(void)
|
||||||
|
{
|
||||||
|
char *av[10];
|
||||||
|
int ac = 0;
|
||||||
|
|
||||||
|
av[ac++] = "postgres";
|
||||||
|
av[ac++] = "-forkautovac";
|
||||||
|
av[ac++] = NULL; /* filled in by postmaster_forkexec */
|
||||||
|
av[ac] = NULL;
|
||||||
|
|
||||||
|
Assert(ac < lengthof(av));
|
||||||
|
|
||||||
|
return postmaster_forkexec(ac, av);
|
||||||
|
}
|
||||||
|
#endif /* EXEC_BACKEND */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AutoVacMain
|
||||||
|
*/
|
||||||
|
NON_EXEC_STATIC void
|
||||||
|
AutoVacMain(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
ListCell *cell;
|
||||||
|
List *dblist;
|
||||||
|
autovac_dbase *db;
|
||||||
|
sigjmp_buf local_sigjmp_buf;
|
||||||
|
|
||||||
|
/* we are a postmaster subprocess now */
|
||||||
|
IsUnderPostmaster = true;
|
||||||
|
am_autovacuum = true;
|
||||||
|
|
||||||
|
/* reset MyProcPid */
|
||||||
|
MyProcPid = getpid();
|
||||||
|
|
||||||
|
/* Lose the postmaster's on-exit routines */
|
||||||
|
on_exit_reset();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up signal handlers. We operate on databases much like a
|
||||||
|
* regular backend, so we use the same signal handling. See
|
||||||
|
* equivalent code in tcop/postgres.c.
|
||||||
|
*
|
||||||
|
* Currently, we don't pay attention to postgresql.conf changes
|
||||||
|
* that happen during a single daemon iteration, so we can ignore
|
||||||
|
* SIGHUP.
|
||||||
|
*/
|
||||||
|
pqsignal(SIGHUP, SIG_IGN);
|
||||||
|
/*
|
||||||
|
* Presently, SIGINT will lead to autovacuum shutdown, because that's
|
||||||
|
* how we handle ereport(ERROR). It could be improved however.
|
||||||
|
*/
|
||||||
|
pqsignal(SIGINT, StatementCancelHandler);
|
||||||
|
pqsignal(SIGTERM, die);
|
||||||
|
pqsignal(SIGQUIT, quickdie);
|
||||||
|
pqsignal(SIGALRM, handle_sig_alarm);
|
||||||
|
|
||||||
|
pqsignal(SIGPIPE, SIG_IGN);
|
||||||
|
pqsignal(SIGUSR1, CatchupInterruptHandler);
|
||||||
|
/* We don't listen for async notifies */
|
||||||
|
pqsignal(SIGUSR2, SIG_IGN);
|
||||||
|
pqsignal(SIGCHLD, SIG_DFL);
|
||||||
|
|
||||||
|
/* Identify myself via ps */
|
||||||
|
init_ps_display("autovacuum process", "", "");
|
||||||
|
set_ps_display("");
|
||||||
|
|
||||||
|
/* Early initialization */
|
||||||
|
BaseInit();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If an exception is encountered, processing resumes here.
|
||||||
|
*
|
||||||
|
* See notes in postgres.c about the design of this coding.
|
||||||
|
*/
|
||||||
|
if (sigsetjmp(local_sigjmp_buf, 1) != 0)
|
||||||
|
{
|
||||||
|
/* Prevents interrupts while cleaning up */
|
||||||
|
HOLD_INTERRUPTS();
|
||||||
|
|
||||||
|
/* Report the error to the server log */
|
||||||
|
EmitErrorReport();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can now go away. Note that because we'll call InitProcess,
|
||||||
|
* a callback will be registered to do ProcKill, which will clean
|
||||||
|
* up necessary state.
|
||||||
|
*/
|
||||||
|
proc_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We can now handle ereport(ERROR) */
|
||||||
|
PG_exception_stack = &local_sigjmp_buf;
|
||||||
|
|
||||||
|
PG_SETMASK(&UnBlockSig);
|
||||||
|
|
||||||
|
/* Get a list of databases */
|
||||||
|
dblist = autovac_get_database_list();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Choose a database to connect to. We pick the database that was least
|
||||||
|
* recently auto-vacuumed.
|
||||||
|
*
|
||||||
|
* XXX This could be improved if we had more info about whether it needs
|
||||||
|
* vacuuming before connecting to it. Perhaps look through the pgstats
|
||||||
|
* data for the database's tables?
|
||||||
|
*
|
||||||
|
* XXX it is NOT good that we totally ignore databases that have no
|
||||||
|
* pgstats entry ...
|
||||||
|
*/
|
||||||
|
db = NULL;
|
||||||
|
|
||||||
|
foreach(cell, dblist)
|
||||||
|
{
|
||||||
|
autovac_dbase *tmp = lfirst(cell);
|
||||||
|
|
||||||
|
tmp->entry = pgstat_fetch_stat_dbentry(tmp->oid);
|
||||||
|
if (!tmp->entry)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't try to access a database that was dropped. This could only
|
||||||
|
* happen if we read the pg_database flat file right before it was
|
||||||
|
* modified, after the database was dropped from the pg_database
|
||||||
|
* table.
|
||||||
|
*/
|
||||||
|
if (tmp->entry->destroy != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!db ||
|
||||||
|
tmp->entry->last_autovac_time < db->entry->last_autovac_time)
|
||||||
|
db = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (db)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Connect to the selected database
|
||||||
|
*/
|
||||||
|
InitPostgres(db->name, NULL);
|
||||||
|
SetProcessingMode(NormalProcessing);
|
||||||
|
pgstat_report_autovac();
|
||||||
|
set_ps_display(db->name);
|
||||||
|
ereport(LOG,
|
||||||
|
(errmsg("autovacuum: processing database \"%s\"", db->name)));
|
||||||
|
/*
|
||||||
|
* And do an appropriate amount of work on it
|
||||||
|
*/
|
||||||
|
do_autovacuum(db->entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* One iteration done, go away */
|
||||||
|
proc_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* autovac_get_database_list
|
||||||
|
*
|
||||||
|
* Return a list of all databases. Note we cannot use pg_database,
|
||||||
|
* because we aren't connected yet; we use the flat database file.
|
||||||
|
*/
|
||||||
|
static List *
|
||||||
|
autovac_get_database_list(void)
|
||||||
|
{
|
||||||
|
char *filename;
|
||||||
|
List *dblist = NIL;
|
||||||
|
char thisname[NAMEDATALEN];
|
||||||
|
FILE *db_file;
|
||||||
|
Oid db_id;
|
||||||
|
Oid db_tablespace;
|
||||||
|
|
||||||
|
filename = database_getflatfilename();
|
||||||
|
db_file = AllocateFile(filename, "r");
|
||||||
|
if (db_file == NULL)
|
||||||
|
ereport(FATAL,
|
||||||
|
(errcode_for_file_access(),
|
||||||
|
errmsg("could not open file \"%s\": %m", filename)));
|
||||||
|
|
||||||
|
while (read_pg_database_line(db_file, thisname, &db_id, &db_tablespace))
|
||||||
|
{
|
||||||
|
autovac_dbase *db;
|
||||||
|
|
||||||
|
db = (autovac_dbase *) palloc(sizeof(autovac_dbase));
|
||||||
|
|
||||||
|
db->oid = db_id;
|
||||||
|
db->name = pstrdup(thisname);
|
||||||
|
/* this gets set later */
|
||||||
|
db->entry = NULL;
|
||||||
|
|
||||||
|
dblist = lappend(dblist, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeFile(db_file);
|
||||||
|
pfree(filename);
|
||||||
|
|
||||||
|
return dblist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process a database.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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(PgStat_StatDBEntry *dbentry)
|
||||||
|
{
|
||||||
|
Relation classRel,
|
||||||
|
avRel;
|
||||||
|
HeapTuple tuple;
|
||||||
|
HeapScanDesc relScan;
|
||||||
|
List *vacuum_tables = NIL,
|
||||||
|
*analyze_tables = NIL;
|
||||||
|
MemoryContext AutovacMemCxt;
|
||||||
|
|
||||||
|
/* Memory context where cross-transaction state is stored */
|
||||||
|
AutovacMemCxt = AllocSetContextCreate(TopMemoryContext,
|
||||||
|
"Autovacuum context",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
|
/* Start a transaction so our commands have one to play into. */
|
||||||
|
StartTransactionCommand();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StartTransactionCommand and CommitTransactionCommand will
|
||||||
|
* automatically switch to other contexts. We need this one
|
||||||
|
* to keep the list of relations to vacuum/analyze across
|
||||||
|
* transactions.
|
||||||
|
*/
|
||||||
|
MemoryContextSwitchTo(AutovacMemCxt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this database is old enough to need a whole-database VACUUM,
|
||||||
|
* don't bother checking each table. If that happens, this function
|
||||||
|
* will issue the VACUUM command and won't return.
|
||||||
|
*/
|
||||||
|
autovac_check_wraparound();
|
||||||
|
|
||||||
|
CHECK_FOR_INTERRUPTS();
|
||||||
|
|
||||||
|
classRel = heap_open(RelationRelationId, AccessShareLock);
|
||||||
|
avRel = heap_open(AutovacuumRelationId, AccessShareLock);
|
||||||
|
|
||||||
|
relScan = heap_beginscan(classRel, SnapshotNow, 0, NULL);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
relid = HeapTupleGetOid(tuple);
|
||||||
|
|
||||||
|
/* See if we have a pg_autovacuum entry for this relation. */
|
||||||
|
ScanKeyInit(&entry[0],
|
||||||
|
Anum_pg_autovacuum_vacrelid,
|
||||||
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
|
ObjectIdGetDatum(relid));
|
||||||
|
|
||||||
|
avScan = systable_beginscan(avRel, AutovacuumRelidIndexId, true,
|
||||||
|
SnapshotNow, 1, entry);
|
||||||
|
|
||||||
|
avTup = systable_getnext(avScan);
|
||||||
|
|
||||||
|
if (HeapTupleIsValid(avTup))
|
||||||
|
avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
|
||||||
|
|
||||||
|
tabentry = hash_search(dbentry->tables, &relid,
|
||||||
|
HASH_FIND, NULL);
|
||||||
|
|
||||||
|
test_rel_for_autovac(relid, tabentry, classForm, avForm,
|
||||||
|
&vacuum_tables, &analyze_tables);
|
||||||
|
|
||||||
|
systable_endscan(avScan);
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_endscan(relScan);
|
||||||
|
heap_close(avRel, AccessShareLock);
|
||||||
|
heap_close(classRel, AccessShareLock);
|
||||||
|
|
||||||
|
CHECK_FOR_INTERRUPTS();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform operations on collected tables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (analyze_tables)
|
||||||
|
autovacuum_do_vac_analyze(analyze_tables, false);
|
||||||
|
|
||||||
|
CHECK_FOR_INTERRUPTS();
|
||||||
|
|
||||||
|
/* get back to proper context */
|
||||||
|
MemoryContextSwitchTo(AutovacMemCxt);
|
||||||
|
|
||||||
|
if (vacuum_tables)
|
||||||
|
autovacuum_do_vac_analyze(vacuum_tables, true);
|
||||||
|
|
||||||
|
/* Finally close out the last transaction. */
|
||||||
|
CommitTransactionCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test_rel_for_autovac
|
||||||
|
*
|
||||||
|
* Check whether a table needs to be vacuumed or analyzed. Add it to the
|
||||||
|
* respective list if so.
|
||||||
|
*
|
||||||
|
* A table needs to be vacuumed if the number of dead tuples exceeds a
|
||||||
|
* threshold. This threshold is calculated as
|
||||||
|
*
|
||||||
|
* threshold = vac_base_thresh + vac_scale_factor * reltuples
|
||||||
|
*
|
||||||
|
* For analyze, the analysis done is that the number of tuples inserted,
|
||||||
|
* deleted and updated since the last analyze exceeds a threshold calculated
|
||||||
|
* in the same fashion as above. Note that the collector actually stores
|
||||||
|
* the number of tuples (both live and dead) that there were as of the last
|
||||||
|
* analyze. This is asymmetric to the VACUUM case.
|
||||||
|
*
|
||||||
|
* A table whose pg_autovacuum.enabled value is false, is automatically
|
||||||
|
* skipped. Thus autovacuum can be disabled for specific tables.
|
||||||
|
*
|
||||||
|
* A table whose vac_base_thresh value is <0 takes the base value from the
|
||||||
|
* autovacuum_vacuum_threshold GUC variable. Similarly, a vac_scale_factor
|
||||||
|
* value <0 is substituted with the value of
|
||||||
|
* autovacuum_vacuum_scale_factor GUC variable. Ditto for analyze.
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Relation rel;
|
||||||
|
float4 reltuples; /* pg_class.reltuples */
|
||||||
|
/* constants from pg_autovacuum or GUC variables */
|
||||||
|
int vac_base_thresh,
|
||||||
|
anl_base_thresh;
|
||||||
|
float4 vac_scale_factor,
|
||||||
|
anl_scale_factor;
|
||||||
|
/* thresholds calculated from above constants */
|
||||||
|
float4 vacthresh,
|
||||||
|
anlthresh;
|
||||||
|
/* number of vacuum (resp. analyze) tuples at this time */
|
||||||
|
float4 vactuples,
|
||||||
|
anltuples;
|
||||||
|
|
||||||
|
/* User disabled it in pg_autovacuum? */
|
||||||
|
if (avForm && !avForm->enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rel = RelationIdGetRelation(relid);
|
||||||
|
/* The table was recently dropped? */
|
||||||
|
if (rel == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Not found in stat hash? */
|
||||||
|
if (tabentry == NULL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Analyze this table. It will emit a stat message for the
|
||||||
|
* collector that will initialize the entry for the next time
|
||||||
|
* around, so we won't have to guess again.
|
||||||
|
*/
|
||||||
|
elog(DEBUG2, "table %s not known to stat system, will ANALYZE",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
*analyze_tables = lappend_oid(*analyze_tables, relid);
|
||||||
|
RelationClose(rel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reltuples = rel->rd_rel->reltuples;
|
||||||
|
vactuples = tabentry->n_dead_tuples;
|
||||||
|
anltuples = tabentry->n_live_tuples + tabentry->n_dead_tuples -
|
||||||
|
tabentry->last_anl_tuples;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is a tuple in pg_autovacuum, use it; else, use the GUC
|
||||||
|
* defaults. Note that the fields may contain "-1" (or indeed any
|
||||||
|
* negative value), which means use the GUC defaults for each setting.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vac_scale_factor = autovacuum_vac_scale;
|
||||||
|
vac_base_thresh = autovacuum_vac_thresh;
|
||||||
|
|
||||||
|
anl_scale_factor = autovacuum_anl_scale;
|
||||||
|
anl_base_thresh = autovacuum_anl_thresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples;
|
||||||
|
anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that we don't need to take special consideration for stat
|
||||||
|
* reset, because if that happens, the last vacuum and analyze counts
|
||||||
|
* will be reset too.
|
||||||
|
*/
|
||||||
|
|
||||||
|
elog(DEBUG2, "%s: vac: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
|
||||||
|
RelationGetRelationName(rel),
|
||||||
|
vactuples, vacthresh, anltuples, anlthresh);
|
||||||
|
|
||||||
|
/* Determine if this table needs vacuum or analyze. */
|
||||||
|
if (vactuples > vacthresh)
|
||||||
|
{
|
||||||
|
elog(DEBUG2, "will VACUUM ANALYZE %s",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
*vacuum_tables = lappend_oid(*vacuum_tables, relid);
|
||||||
|
}
|
||||||
|
else if (anltuples > anlthresh)
|
||||||
|
{
|
||||||
|
elog(DEBUG2, "will ANALYZE %s",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
*analyze_tables = lappend_oid(*analyze_tables, relid);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
autovacuum_do_vac_analyze(List *relids, bool dovacuum)
|
||||||
|
{
|
||||||
|
VacuumStmt *vacstmt = makeNode(VacuumStmt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Point QueryContext to the autovac memory context to fake out the
|
||||||
|
* PreventTransactionChain check inside vacuum(). Note that this
|
||||||
|
* is also why we palloc vacstmt instead of just using a local variable.
|
||||||
|
*/
|
||||||
|
QueryContext = CurrentMemoryContext;
|
||||||
|
|
||||||
|
/* Set up command parameters */
|
||||||
|
vacstmt->vacuum = dovacuum;
|
||||||
|
vacstmt->full = false;
|
||||||
|
vacstmt->analyze = true;
|
||||||
|
vacstmt->freeze = false;
|
||||||
|
vacstmt->verbose = false;
|
||||||
|
vacstmt->relation = NULL; /* all tables, or not used if relids != NIL */
|
||||||
|
vacstmt->va_cols = NIL;
|
||||||
|
|
||||||
|
vacuum(vacstmt, relids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* autovac_check_wraparound
|
||||||
|
* Check database Xid wraparound
|
||||||
|
*
|
||||||
|
* Check pg_database to see if the last database-wide VACUUM was too long ago,
|
||||||
|
* and issue one now if so. If this comes to pass, we do not return, as there
|
||||||
|
* is no point in checking individual tables -- they will all get vacuumed
|
||||||
|
* anyway.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
autovac_check_wraparound(void)
|
||||||
|
{
|
||||||
|
Relation relation;
|
||||||
|
ScanKeyData entry[1];
|
||||||
|
HeapScanDesc scan;
|
||||||
|
HeapTuple tuple;
|
||||||
|
Form_pg_database dbform;
|
||||||
|
int32 age;
|
||||||
|
bool whole_db;
|
||||||
|
|
||||||
|
relation = heap_open(DatabaseRelationId, AccessShareLock);
|
||||||
|
|
||||||
|
/* Must use a heap scan, since there's no syscache for pg_database */
|
||||||
|
ScanKeyInit(&entry[0],
|
||||||
|
ObjectIdAttributeNumber,
|
||||||
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
|
ObjectIdGetDatum(MyDatabaseId));
|
||||||
|
|
||||||
|
scan = heap_beginscan(relation, SnapshotNow, 1, entry);
|
||||||
|
|
||||||
|
tuple = heap_getnext(scan, ForwardScanDirection);
|
||||||
|
|
||||||
|
if (!HeapTupleIsValid(tuple))
|
||||||
|
elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
|
||||||
|
|
||||||
|
dbform = (Form_pg_database) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We decide to vacuum at the same point where vacuum.c's
|
||||||
|
* vac_truncate_clog() would decide to start giving warnings.
|
||||||
|
*/
|
||||||
|
age = (int32) (GetTopTransactionId() - dbform->datfrozenxid);
|
||||||
|
whole_db = (age > (int32) ((MaxTransactionId >> 3) * 3));
|
||||||
|
|
||||||
|
heap_endscan(scan);
|
||||||
|
heap_close(relation, AccessShareLock);
|
||||||
|
|
||||||
|
if (whole_db)
|
||||||
|
{
|
||||||
|
elog(LOG, "autovacuum: VACUUM ANALYZE whole database");
|
||||||
|
autovacuum_do_vac_analyze(NIL, true);
|
||||||
|
proc_exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AutoVacuumingActive
|
||||||
|
* Check GUC vars and report whether the autovacuum process should be
|
||||||
|
* running.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
AutoVacuumingActive(void)
|
||||||
|
{
|
||||||
|
if (!autovacuum_start_daemon || !pgstat_collect_startcollector ||
|
||||||
|
!pgstat_collect_tuplelevel)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* autovac_init
|
||||||
|
* This is called at postmaster initialization.
|
||||||
|
*
|
||||||
|
* Annoy the user if he got it wrong.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
autovac_init(void)
|
||||||
|
{
|
||||||
|
if (!autovacuum_start_daemon)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!pgstat_collect_startcollector || !pgstat_collect_tuplelevel)
|
||||||
|
{
|
||||||
|
ereport(WARNING,
|
||||||
|
(errmsg("autovacuum not started because of misconfiguration"),
|
||||||
|
errhint("Enable options \"stats_start_collector\" and \"stats_row_level\".")));
|
||||||
|
/*
|
||||||
|
* Set the GUC var so we don't fork autovacuum uselessly, and also to
|
||||||
|
* help debugging.
|
||||||
|
*/
|
||||||
|
autovacuum_start_daemon = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IsAutoVacuumProcess
|
||||||
|
* Return whether this process is an autovacuum process.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
IsAutoVacuumProcess(void)
|
||||||
|
{
|
||||||
|
return am_autovacuum;
|
||||||
|
}
|
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2001-2005, PostgreSQL Global Development Group
|
* Copyright (c) 2001-2005, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.99 2005/07/04 04:51:47 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.100 2005/07/14 05:13:40 tgl Exp $
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
@ -38,6 +38,7 @@
|
|||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "postmaster/autovacuum.h"
|
||||||
#include "postmaster/fork_process.h"
|
#include "postmaster/fork_process.h"
|
||||||
#include "postmaster/postmaster.h"
|
#include "postmaster/postmaster.h"
|
||||||
#include "storage/backendid.h"
|
#include "storage/backendid.h"
|
||||||
@ -167,7 +168,7 @@ static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
|
|||||||
int *numbackends);
|
int *numbackends);
|
||||||
static void backend_read_statsfile(void);
|
static void backend_read_statsfile(void);
|
||||||
|
|
||||||
static void pgstat_setheader(PgStat_MsgHdr *hdr, int mtype);
|
static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype);
|
||||||
static void pgstat_send(void *msg, int len);
|
static void pgstat_send(void *msg, int len);
|
||||||
|
|
||||||
static void pgstat_recv_bestart(PgStat_MsgBestart *msg, int len);
|
static void pgstat_recv_bestart(PgStat_MsgBestart *msg, int len);
|
||||||
@ -177,6 +178,9 @@ static void pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len);
|
|||||||
static void pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len);
|
static void pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len);
|
||||||
static void pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len);
|
static void pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len);
|
||||||
static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len);
|
static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len);
|
||||||
|
static void pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len);
|
||||||
|
static void pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len);
|
||||||
|
static void pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len);
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------
|
/* ------------------------------------------------------------
|
||||||
@ -618,6 +622,27 @@ pgstat_beterm(int pid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* pgstat_report_autovac() -
|
||||||
|
*
|
||||||
|
* Called from autovacuum.c to report startup of an autovacuum process.
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pgstat_report_autovac(void)
|
||||||
|
{
|
||||||
|
PgStat_MsgAutovacStart msg;
|
||||||
|
|
||||||
|
if (pgStatSock < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_AUTOVAC_START);
|
||||||
|
msg.m_databaseid = MyDatabaseId;
|
||||||
|
msg.m_start_time = GetCurrentTimestamp();
|
||||||
|
|
||||||
|
pgstat_send(&msg, sizeof(msg));
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------
|
/* ------------------------------------------------------------
|
||||||
* Public functions used by backends follow
|
* Public functions used by backends follow
|
||||||
*------------------------------------------------------------
|
*------------------------------------------------------------
|
||||||
@ -652,6 +677,51 @@ pgstat_bestart(void)
|
|||||||
on_proc_exit(pgstat_beshutdown_hook, 0);
|
on_proc_exit(pgstat_beshutdown_hook, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------
|
||||||
|
* pgstat_report_vacuum() -
|
||||||
|
*
|
||||||
|
* Tell the collector about the table we just vacuumed.
|
||||||
|
* ---------
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pgstat_report_vacuum(Oid tableoid, bool analyze, PgStat_Counter tuples)
|
||||||
|
{
|
||||||
|
PgStat_MsgVacuum msg;
|
||||||
|
|
||||||
|
if (pgStatSock < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_VACUUM);
|
||||||
|
msg.m_databaseid = MyDatabaseId;
|
||||||
|
msg.m_tableoid = tableoid;
|
||||||
|
msg.m_analyze = analyze;
|
||||||
|
msg.m_tuples = tuples;
|
||||||
|
pgstat_send(&msg, sizeof(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------
|
||||||
|
* pgstat_report_analyze() -
|
||||||
|
*
|
||||||
|
* Tell the collector about the table we just analyzed.
|
||||||
|
* --------
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pgstat_report_analyze(Oid tableoid, PgStat_Counter livetuples,
|
||||||
|
PgStat_Counter deadtuples)
|
||||||
|
{
|
||||||
|
PgStat_MsgAnalyze msg;
|
||||||
|
|
||||||
|
if (pgStatSock < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ANALYZE);
|
||||||
|
msg.m_databaseid = MyDatabaseId;
|
||||||
|
msg.m_tableoid = tableoid;
|
||||||
|
msg.m_live_tuples = livetuples;
|
||||||
|
msg.m_dead_tuples = deadtuples;
|
||||||
|
pgstat_send(&msg, sizeof(msg));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flush any remaining statistics counts out to the collector at process
|
* Flush any remaining statistics counts out to the collector at process
|
||||||
* exit. Without this, operations triggered during backend exit (such as
|
* exit. Without this, operations triggered during backend exit (such as
|
||||||
@ -1279,7 +1349,7 @@ pgstat_fetch_stat_numbackends(void)
|
|||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
pgstat_setheader(PgStat_MsgHdr *hdr, int mtype)
|
pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype)
|
||||||
{
|
{
|
||||||
hdr->m_type = mtype;
|
hdr->m_type = mtype;
|
||||||
hdr->m_backendid = MyBackendId;
|
hdr->m_backendid = MyBackendId;
|
||||||
@ -1653,6 +1723,18 @@ PgstatCollectorMain(int argc, char *argv[])
|
|||||||
nread);
|
nread);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PGSTAT_MTYPE_AUTOVAC_START:
|
||||||
|
pgstat_recv_autovac((PgStat_MsgAutovacStart *) &msg, nread);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PGSTAT_MTYPE_VACUUM:
|
||||||
|
pgstat_recv_vacuum((PgStat_MsgVacuum *) &msg, nread);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PGSTAT_MTYPE_ANALYZE:
|
||||||
|
pgstat_recv_analyze((PgStat_MsgAnalyze *) &msg, nread);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2049,6 +2131,7 @@ pgstat_get_db_entry(Oid databaseid)
|
|||||||
result->n_blocks_fetched = 0;
|
result->n_blocks_fetched = 0;
|
||||||
result->n_blocks_hit = 0;
|
result->n_blocks_hit = 0;
|
||||||
result->destroy = 0;
|
result->destroy = 0;
|
||||||
|
result->last_autovac_time = 0;
|
||||||
|
|
||||||
memset(&hash_ctl, 0, sizeof(hash_ctl));
|
memset(&hash_ctl, 0, sizeof(hash_ctl));
|
||||||
hash_ctl.keysize = sizeof(Oid);
|
hash_ctl.keysize = sizeof(Oid);
|
||||||
@ -2136,6 +2219,7 @@ pgstat_write_statsfile(void)
|
|||||||
PgStat_StatBeDead *deadbe;
|
PgStat_StatBeDead *deadbe;
|
||||||
FILE *fpout;
|
FILE *fpout;
|
||||||
int i;
|
int i;
|
||||||
|
int32 format_id;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open the statistics temp file to write out the current values.
|
* Open the statistics temp file to write out the current values.
|
||||||
@ -2150,6 +2234,12 @@ pgstat_write_statsfile(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the file header --- currently just a format ID.
|
||||||
|
*/
|
||||||
|
format_id = PGSTAT_FILE_FORMAT_ID;
|
||||||
|
fwrite(&format_id, sizeof(format_id), 1, fpout);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Walk through the database table.
|
* Walk through the database table.
|
||||||
*/
|
*/
|
||||||
@ -2182,7 +2272,7 @@ pgstat_write_statsfile(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write out the DB line including the number of life backends.
|
* Write out the DB line including the number of live backends.
|
||||||
*/
|
*/
|
||||||
fputc('D', fpout);
|
fputc('D', fpout);
|
||||||
fwrite(dbentry, sizeof(PgStat_StatDBEntry), 1, fpout);
|
fwrite(dbentry, sizeof(PgStat_StatDBEntry), 1, fpout);
|
||||||
@ -2216,7 +2306,7 @@ pgstat_write_statsfile(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At least we think this is still a life table. Print it's
|
* At least we think this is still a live table. Print its
|
||||||
* access stats.
|
* access stats.
|
||||||
*/
|
*/
|
||||||
fputc('T', fpout);
|
fputc('T', fpout);
|
||||||
@ -2312,6 +2402,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
|
|||||||
HASHCTL hash_ctl;
|
HASHCTL hash_ctl;
|
||||||
HTAB *tabhash = NULL;
|
HTAB *tabhash = NULL;
|
||||||
FILE *fpin;
|
FILE *fpin;
|
||||||
|
int32 format_id;
|
||||||
int maxbackends = 0;
|
int maxbackends = 0;
|
||||||
int havebackends = 0;
|
int havebackends = 0;
|
||||||
bool found;
|
bool found;
|
||||||
@ -2319,12 +2410,13 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
|
|||||||
int mcxt_flags;
|
int mcxt_flags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If running in the collector we use the DynaHashCxt memory context.
|
* If running in the collector or the autovacuum process, we use the
|
||||||
* If running in a backend, we use the TopTransactionContext instead,
|
* DynaHashCxt memory context. If running in a backend, we use the
|
||||||
* so the caller must only know the last XactId when this call
|
* TopTransactionContext instead, so the caller must only know the last
|
||||||
* happened to know if his tables are still valid or already gone!
|
* XactId when this call happened to know if his tables are still valid or
|
||||||
|
* already gone!
|
||||||
*/
|
*/
|
||||||
if (pgStatRunningInCollector)
|
if (pgStatRunningInCollector || IsAutoVacuumProcess())
|
||||||
{
|
{
|
||||||
use_mcxt = NULL;
|
use_mcxt = NULL;
|
||||||
mcxt_flags = 0;
|
mcxt_flags = 0;
|
||||||
@ -2363,6 +2455,17 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
|
|||||||
if ((fpin = AllocateFile(PGSTAT_STAT_FILENAME, PG_BINARY_R)) == NULL)
|
if ((fpin = AllocateFile(PGSTAT_STAT_FILENAME, PG_BINARY_R)) == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify it's of the expected format.
|
||||||
|
*/
|
||||||
|
if (fread(&format_id, 1, sizeof(format_id), fpin) != sizeof(format_id)
|
||||||
|
|| format_id != PGSTAT_FILE_FORMAT_ID)
|
||||||
|
{
|
||||||
|
ereport(pgStatRunningInCollector ? LOG : WARNING,
|
||||||
|
(errmsg("corrupted pgstat.stat file")));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We found an existing collector stats file. Read it and put all the
|
* We found an existing collector stats file. Read it and put all the
|
||||||
* hashtable entries into place.
|
* hashtable entries into place.
|
||||||
@ -2552,18 +2655,35 @@ done:
|
|||||||
*
|
*
|
||||||
* Because we store the hash tables in TopTransactionContext, the result
|
* Because we store the hash tables in TopTransactionContext, the result
|
||||||
* is good for the entire current main transaction.
|
* is good for the entire current main transaction.
|
||||||
|
*
|
||||||
|
* Inside the autovacuum process, the statfile is assumed to be valid
|
||||||
|
* "forever", that is one iteration, within one database. This means
|
||||||
|
* we only consider the statistics as they were when the autovacuum
|
||||||
|
* iteration started.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
backend_read_statsfile(void)
|
backend_read_statsfile(void)
|
||||||
{
|
{
|
||||||
TransactionId topXid = GetTopTransactionId();
|
if (IsAutoVacuumProcess())
|
||||||
|
|
||||||
if (!TransactionIdEquals(pgStatDBHashXact, topXid))
|
|
||||||
{
|
{
|
||||||
Assert(!pgStatRunningInCollector);
|
Assert(!pgStatRunningInCollector);
|
||||||
pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
|
/* already read it? */
|
||||||
|
if (pgStatDBHash)
|
||||||
|
return;
|
||||||
|
pgstat_read_statsfile(&pgStatDBHash, InvalidOid,
|
||||||
&pgStatBeTable, &pgStatNumBackends);
|
&pgStatBeTable, &pgStatNumBackends);
|
||||||
pgStatDBHashXact = topXid;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TransactionId topXid = GetTopTransactionId();
|
||||||
|
|
||||||
|
if (!TransactionIdEquals(pgStatDBHashXact, topXid))
|
||||||
|
{
|
||||||
|
Assert(!pgStatRunningInCollector);
|
||||||
|
pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
|
||||||
|
&pgStatBeTable, &pgStatNumBackends);
|
||||||
|
pgStatDBHashXact = topXid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2606,6 +2726,129 @@ pgstat_recv_beterm(PgStat_MsgBeterm *msg, int len)
|
|||||||
pgstat_sub_backend(msg->m_hdr.m_procpid);
|
pgstat_sub_backend(msg->m_hdr.m_procpid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* pgstat_recv_autovac() -
|
||||||
|
*
|
||||||
|
* Process an autovacuum signalling message.
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len)
|
||||||
|
{
|
||||||
|
PgStat_StatDBEntry *dbentry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup the database in the hashtable.
|
||||||
|
*
|
||||||
|
* XXX this creates the entry if it doesn't exist. Is this a problem? (We
|
||||||
|
* could leak an entry if we send an autovac message and the database is
|
||||||
|
* later destroyed, _and_ the messages are rearranged. Doesn't seem very
|
||||||
|
* likely though.) Not sure what to do about it.
|
||||||
|
*/
|
||||||
|
dbentry = pgstat_get_db_entry(msg->m_databaseid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store the last autovacuum time in the database entry.
|
||||||
|
*/
|
||||||
|
dbentry->last_autovac_time = msg->m_start_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* pgstat_recv_vacuum() -
|
||||||
|
*
|
||||||
|
* Process a VACUUM message.
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len)
|
||||||
|
{
|
||||||
|
PgStat_StatDBEntry *dbentry;
|
||||||
|
PgStat_StatTabEntry *tabentry;
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
dbentry = pgstat_get_db_entry(msg->m_databaseid);
|
||||||
|
|
||||||
|
tabentry = hash_search(dbentry->tables, &(msg->m_tableoid),
|
||||||
|
HASH_ENTER, &found);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are creating the entry, initialize it.
|
||||||
|
*/
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
tabentry->tableid = msg->m_tableoid;
|
||||||
|
|
||||||
|
tabentry->tuples_returned = 0;
|
||||||
|
tabentry->tuples_fetched = 0;
|
||||||
|
tabentry->tuples_inserted = msg->m_tuples;
|
||||||
|
tabentry->tuples_deleted = 0;
|
||||||
|
tabentry->tuples_updated = 0;
|
||||||
|
|
||||||
|
tabentry->n_live_tuples = msg->m_tuples;
|
||||||
|
tabentry->n_dead_tuples = 0;
|
||||||
|
|
||||||
|
if (msg->m_analyze)
|
||||||
|
tabentry->last_anl_tuples = msg->m_tuples;
|
||||||
|
else
|
||||||
|
tabentry->last_anl_tuples = 0;
|
||||||
|
|
||||||
|
tabentry->blocks_fetched = 0;
|
||||||
|
tabentry->blocks_hit = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tabentry->n_dead_tuples = 0;
|
||||||
|
tabentry->n_live_tuples = msg->m_tuples;
|
||||||
|
if (msg->m_analyze)
|
||||||
|
tabentry->last_anl_tuples = msg->m_tuples;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* pgstat_recv_analyze() -
|
||||||
|
*
|
||||||
|
* Process an ANALYZE message.
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len)
|
||||||
|
{
|
||||||
|
PgStat_StatDBEntry *dbentry;
|
||||||
|
PgStat_StatTabEntry *tabentry;
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
dbentry = pgstat_get_db_entry(msg->m_databaseid);
|
||||||
|
|
||||||
|
tabentry = hash_search(dbentry->tables, &(msg->m_tableoid),
|
||||||
|
HASH_ENTER, &found);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are creating the entry, initialize it.
|
||||||
|
*/
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
tabentry->tableid = msg->m_tableoid;
|
||||||
|
|
||||||
|
tabentry->tuples_returned = 0;
|
||||||
|
tabentry->tuples_fetched = 0;
|
||||||
|
tabentry->tuples_inserted = 0;
|
||||||
|
tabentry->tuples_deleted = 0;
|
||||||
|
tabentry->tuples_updated = 0;
|
||||||
|
|
||||||
|
tabentry->n_live_tuples = msg->m_live_tuples;
|
||||||
|
tabentry->n_dead_tuples = msg->m_dead_tuples;
|
||||||
|
tabentry->last_anl_tuples = msg->m_live_tuples + msg->m_dead_tuples;
|
||||||
|
|
||||||
|
tabentry->blocks_fetched = 0;
|
||||||
|
tabentry->blocks_hit = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tabentry->n_live_tuples = msg->m_live_tuples;
|
||||||
|
tabentry->n_dead_tuples = msg->m_dead_tuples;
|
||||||
|
tabentry->last_anl_tuples = msg->m_live_tuples + msg->m_dead_tuples;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* pgstat_recv_activity() -
|
* pgstat_recv_activity() -
|
||||||
@ -2690,6 +2933,10 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
|
|||||||
tabentry->tuples_deleted = tabmsg[i].t_tuples_deleted;
|
tabentry->tuples_deleted = tabmsg[i].t_tuples_deleted;
|
||||||
tabentry->blocks_fetched = tabmsg[i].t_blocks_fetched;
|
tabentry->blocks_fetched = tabmsg[i].t_blocks_fetched;
|
||||||
tabentry->blocks_hit = tabmsg[i].t_blocks_hit;
|
tabentry->blocks_hit = tabmsg[i].t_blocks_hit;
|
||||||
|
|
||||||
|
tabentry->n_live_tuples = tabmsg[i].t_tuples_inserted;
|
||||||
|
tabentry->n_dead_tuples = tabmsg[i].t_tuples_updated +
|
||||||
|
tabmsg[i].t_tuples_deleted;
|
||||||
|
|
||||||
tabentry->destroy = 0;
|
tabentry->destroy = 0;
|
||||||
}
|
}
|
||||||
@ -2706,6 +2953,10 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
|
|||||||
tabentry->tuples_deleted += tabmsg[i].t_tuples_deleted;
|
tabentry->tuples_deleted += tabmsg[i].t_tuples_deleted;
|
||||||
tabentry->blocks_fetched += tabmsg[i].t_blocks_fetched;
|
tabentry->blocks_fetched += tabmsg[i].t_blocks_fetched;
|
||||||
tabentry->blocks_hit += tabmsg[i].t_blocks_hit;
|
tabentry->blocks_hit += tabmsg[i].t_blocks_hit;
|
||||||
|
|
||||||
|
tabentry->n_live_tuples += tabmsg[i].t_tuples_inserted;
|
||||||
|
tabentry->n_dead_tuples += tabmsg[i].t_tuples_updated +
|
||||||
|
tabmsg[i].t_tuples_deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.458 2005/07/04 04:51:47 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.459 2005/07/14 05:13:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
*
|
*
|
||||||
@ -106,6 +106,7 @@
|
|||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "nodes/nodes.h"
|
#include "nodes/nodes.h"
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
|
#include "postmaster/autovacuum.h"
|
||||||
#include "postmaster/fork_process.h"
|
#include "postmaster/fork_process.h"
|
||||||
#include "postmaster/pgarch.h"
|
#include "postmaster/pgarch.h"
|
||||||
#include "postmaster/postmaster.h"
|
#include "postmaster/postmaster.h"
|
||||||
@ -207,6 +208,7 @@ char *preload_libraries_string = NULL;
|
|||||||
/* PIDs of special child processes; 0 when not running */
|
/* PIDs of special child processes; 0 when not running */
|
||||||
static pid_t StartupPID = 0,
|
static pid_t StartupPID = 0,
|
||||||
BgWriterPID = 0,
|
BgWriterPID = 0,
|
||||||
|
AutoVacPID = 0,
|
||||||
PgArchPID = 0,
|
PgArchPID = 0,
|
||||||
PgStatPID = 0,
|
PgStatPID = 0,
|
||||||
SysLoggerPID = 0;
|
SysLoggerPID = 0;
|
||||||
@ -872,8 +874,8 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
*
|
*
|
||||||
* CAUTION: when changing this list, check for side-effects on the signal
|
* CAUTION: when changing this list, check for side-effects on the signal
|
||||||
* handling setup of child processes. See tcop/postgres.c,
|
* handling setup of child processes. See tcop/postgres.c,
|
||||||
* bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/pgarch.c,
|
* bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/autovacuum.c,
|
||||||
* postmaster/pgstat.c, and postmaster/syslogger.c.
|
* postmaster/pgarch.c, postmaster/pgstat.c, and postmaster/syslogger.c.
|
||||||
*/
|
*/
|
||||||
pqinitmask();
|
pqinitmask();
|
||||||
PG_SETMASK(&BlockSig);
|
PG_SETMASK(&BlockSig);
|
||||||
@ -930,6 +932,11 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
*/
|
*/
|
||||||
PgStartTime = GetCurrentTimestamp();
|
PgStartTime = GetCurrentTimestamp();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the autovacuum daemon
|
||||||
|
*/
|
||||||
|
autovac_init();
|
||||||
|
|
||||||
status = ServerLoop();
|
status = ServerLoop();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1251,6 +1258,15 @@ ServerLoop(void)
|
|||||||
kill(BgWriterPID, SIGUSR2);
|
kill(BgWriterPID, SIGUSR2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start a new autovacuum process, if there isn't one running already.
|
||||||
|
* (It'll die relatively quickly.) We check that it's not started
|
||||||
|
* too frequently in autovac_start.
|
||||||
|
*/
|
||||||
|
if (AutoVacuumingActive() && AutoVacPID == 0 &&
|
||||||
|
StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
|
||||||
|
AutoVacPID = autovac_start();
|
||||||
|
|
||||||
/* If we have lost the archiver, try to start a new one */
|
/* If we have lost the archiver, try to start a new one */
|
||||||
if (XLogArchivingActive() && PgArchPID == 0 &&
|
if (XLogArchivingActive() && PgArchPID == 0 &&
|
||||||
StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
|
StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
|
||||||
@ -1818,6 +1834,8 @@ SIGHUP_handler(SIGNAL_ARGS)
|
|||||||
SignalChildren(SIGHUP);
|
SignalChildren(SIGHUP);
|
||||||
if (BgWriterPID != 0)
|
if (BgWriterPID != 0)
|
||||||
kill(BgWriterPID, SIGHUP);
|
kill(BgWriterPID, SIGHUP);
|
||||||
|
if (AutoVacPID != 0)
|
||||||
|
kill(AutoVacPID, SIGHUP);
|
||||||
if (PgArchPID != 0)
|
if (PgArchPID != 0)
|
||||||
kill(PgArchPID, SIGHUP);
|
kill(PgArchPID, SIGHUP);
|
||||||
if (SysLoggerPID != 0)
|
if (SysLoggerPID != 0)
|
||||||
@ -1869,6 +1887,16 @@ pmdie(SIGNAL_ARGS)
|
|||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("received smart shutdown request")));
|
(errmsg("received smart shutdown request")));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We won't wait out an autovacuum iteration ...
|
||||||
|
*/
|
||||||
|
if (AutoVacPID != 0)
|
||||||
|
{
|
||||||
|
/* Use statement cancel to shut it down */
|
||||||
|
kill(AutoVacPID, SIGINT);
|
||||||
|
break; /* let reaper() handle this */
|
||||||
|
}
|
||||||
|
|
||||||
if (DLGetHead(BackendList))
|
if (DLGetHead(BackendList))
|
||||||
break; /* let reaper() handle this */
|
break; /* let reaper() handle this */
|
||||||
|
|
||||||
@ -1905,13 +1933,15 @@ pmdie(SIGNAL_ARGS)
|
|||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("received fast shutdown request")));
|
(errmsg("received fast shutdown request")));
|
||||||
|
|
||||||
if (DLGetHead(BackendList))
|
if (DLGetHead(BackendList) || AutoVacPID != 0)
|
||||||
{
|
{
|
||||||
if (!FatalError)
|
if (!FatalError)
|
||||||
{
|
{
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("aborting any active transactions")));
|
(errmsg("aborting any active transactions")));
|
||||||
SignalChildren(SIGTERM);
|
SignalChildren(SIGTERM);
|
||||||
|
if (AutoVacPID != 0)
|
||||||
|
kill(AutoVacPID, SIGTERM);
|
||||||
/* reaper() does the rest */
|
/* reaper() does the rest */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1953,6 +1983,8 @@ pmdie(SIGNAL_ARGS)
|
|||||||
kill(StartupPID, SIGQUIT);
|
kill(StartupPID, SIGQUIT);
|
||||||
if (BgWriterPID != 0)
|
if (BgWriterPID != 0)
|
||||||
kill(BgWriterPID, SIGQUIT);
|
kill(BgWriterPID, SIGQUIT);
|
||||||
|
if (AutoVacPID != 0)
|
||||||
|
kill(AutoVacPID, SIGQUIT);
|
||||||
if (PgArchPID != 0)
|
if (PgArchPID != 0)
|
||||||
kill(PgArchPID, SIGQUIT);
|
kill(PgArchPID, SIGQUIT);
|
||||||
if (PgStatPID != 0)
|
if (PgStatPID != 0)
|
||||||
@ -2051,7 +2083,7 @@ reaper(SIGNAL_ARGS)
|
|||||||
/*
|
/*
|
||||||
* Go to shutdown mode if a shutdown request was pending.
|
* Go to shutdown mode if a shutdown request was pending.
|
||||||
* Otherwise, try to start the archiver and stats collector
|
* Otherwise, try to start the archiver and stats collector
|
||||||
* too.
|
* too. (We could, but don't, try to start autovacuum here.)
|
||||||
*/
|
*/
|
||||||
if (Shutdown > NoShutdown && BgWriterPID != 0)
|
if (Shutdown > NoShutdown && BgWriterPID != 0)
|
||||||
kill(BgWriterPID, SIGUSR2);
|
kill(BgWriterPID, SIGUSR2);
|
||||||
@ -2072,8 +2104,8 @@ reaper(SIGNAL_ARGS)
|
|||||||
if (BgWriterPID != 0 && pid == BgWriterPID)
|
if (BgWriterPID != 0 && pid == BgWriterPID)
|
||||||
{
|
{
|
||||||
BgWriterPID = 0;
|
BgWriterPID = 0;
|
||||||
if (exitstatus == 0 && Shutdown > NoShutdown &&
|
if (exitstatus == 0 && Shutdown > NoShutdown && !FatalError &&
|
||||||
!FatalError && !DLGetHead(BackendList))
|
!DLGetHead(BackendList) && AutoVacPID == 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Normal postmaster exit is here: we've seen normal exit
|
* Normal postmaster exit is here: we've seen normal exit
|
||||||
@ -2098,6 +2130,23 @@ reaper(SIGNAL_ARGS)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Was it the autovacuum process? Normal exit can be ignored;
|
||||||
|
* we'll start a new one at the next iteration of the postmaster's
|
||||||
|
* main loop, if necessary.
|
||||||
|
*
|
||||||
|
* An unexpected exit must crash the system.
|
||||||
|
*/
|
||||||
|
if (AutoVacPID != 0 && pid == AutoVacPID)
|
||||||
|
{
|
||||||
|
AutoVacPID = 0;
|
||||||
|
autovac_stopped();
|
||||||
|
if (exitstatus != 0)
|
||||||
|
HandleChildCrash(pid, exitstatus,
|
||||||
|
_("autovacuum process"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Was it the archiver? If so, just try to start a new one; no
|
* Was it the archiver? If so, just try to start a new one; no
|
||||||
* need to force reset of the rest of the system. (If fail, we'll
|
* need to force reset of the rest of the system. (If fail, we'll
|
||||||
@ -2156,7 +2205,8 @@ reaper(SIGNAL_ARGS)
|
|||||||
* StartupDataBase. (We can ignore the archiver and stats
|
* StartupDataBase. (We can ignore the archiver and stats
|
||||||
* processes here since they are not connected to shmem.)
|
* processes here since they are not connected to shmem.)
|
||||||
*/
|
*/
|
||||||
if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0)
|
if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0 ||
|
||||||
|
AutoVacPID != 0)
|
||||||
goto reaper_done;
|
goto reaper_done;
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("all server processes terminated; reinitializing")));
|
(errmsg("all server processes terminated; reinitializing")));
|
||||||
@ -2171,7 +2221,7 @@ reaper(SIGNAL_ARGS)
|
|||||||
|
|
||||||
if (Shutdown > NoShutdown)
|
if (Shutdown > NoShutdown)
|
||||||
{
|
{
|
||||||
if (DLGetHead(BackendList) || StartupPID != 0)
|
if (DLGetHead(BackendList) || StartupPID != 0 || AutoVacPID != 0)
|
||||||
goto reaper_done;
|
goto reaper_done;
|
||||||
/* Start the bgwriter if not running */
|
/* Start the bgwriter if not running */
|
||||||
if (BgWriterPID == 0)
|
if (BgWriterPID == 0)
|
||||||
@ -2239,7 +2289,7 @@ CleanupBackend(int pid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HandleChildCrash -- cleanup after failed backend or bgwriter.
|
* HandleChildCrash -- cleanup after failed backend, bgwriter, or autovacuum.
|
||||||
*
|
*
|
||||||
* The objectives here are to clean up our local state about the child
|
* The objectives here are to clean up our local state about the child
|
||||||
* process, and to signal all other remaining children to quickdie.
|
* process, and to signal all other remaining children to quickdie.
|
||||||
@ -2317,6 +2367,18 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
|
|||||||
kill(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
|
kill(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Take care of the autovacuum daemon too */
|
||||||
|
if (pid == AutoVacPID)
|
||||||
|
AutoVacPID = 0;
|
||||||
|
else if (AutoVacPID != 0 && !FatalError)
|
||||||
|
{
|
||||||
|
ereport(DEBUG2,
|
||||||
|
(errmsg_internal("sending %s to process %d",
|
||||||
|
(SendStop ? "SIGSTOP" : "SIGQUIT"),
|
||||||
|
(int) AutoVacPID)));
|
||||||
|
kill(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT));
|
||||||
|
}
|
||||||
|
|
||||||
/* Force a power-cycle of the pgarch process too */
|
/* Force a power-cycle of the pgarch process too */
|
||||||
/* (Shouldn't be necessary, but just for luck) */
|
/* (Shouldn't be necessary, but just for luck) */
|
||||||
if (PgArchPID != 0 && !FatalError)
|
if (PgArchPID != 0 && !FatalError)
|
||||||
@ -3154,6 +3216,7 @@ SubPostmasterMain(int argc, char *argv[])
|
|||||||
* can attach at the same address the postmaster used.
|
* can attach at the same address the postmaster used.
|
||||||
*/
|
*/
|
||||||
if (strcmp(argv[1], "-forkbackend") == 0 ||
|
if (strcmp(argv[1], "-forkbackend") == 0 ||
|
||||||
|
strcmp(argv[1], "-forkautovac") == 0 ||
|
||||||
strcmp(argv[1], "-forkboot") == 0)
|
strcmp(argv[1], "-forkboot") == 0)
|
||||||
PGSharedMemoryReAttach();
|
PGSharedMemoryReAttach();
|
||||||
|
|
||||||
@ -3205,6 +3268,17 @@ SubPostmasterMain(int argc, char *argv[])
|
|||||||
BootstrapMain(argc - 2, argv + 2);
|
BootstrapMain(argc - 2, argv + 2);
|
||||||
proc_exit(0);
|
proc_exit(0);
|
||||||
}
|
}
|
||||||
|
if (strcmp(argv[1], "-forkautovac") == 0)
|
||||||
|
{
|
||||||
|
/* Close the postmaster's sockets */
|
||||||
|
ClosePostmasterPorts(false);
|
||||||
|
|
||||||
|
/* Attached process to shared data structures */
|
||||||
|
CreateSharedMemoryAndSemaphores(false, 0);
|
||||||
|
|
||||||
|
AutoVacMain(argc - 2, argv + 2);
|
||||||
|
proc_exit(0);
|
||||||
|
}
|
||||||
if (strcmp(argv[1], "-forkarch") == 0)
|
if (strcmp(argv[1], "-forkarch") == 0)
|
||||||
{
|
{
|
||||||
/* Close the postmaster's sockets */
|
/* Close the postmaster's sockets */
|
||||||
@ -3300,7 +3374,11 @@ sigusr1_handler(SIGNAL_ARGS)
|
|||||||
* use of this.
|
* use of this.
|
||||||
*/
|
*/
|
||||||
if (Shutdown <= SmartShutdown)
|
if (Shutdown <= SmartShutdown)
|
||||||
|
{
|
||||||
SignalChildren(SIGUSR1);
|
SignalChildren(SIGUSR1);
|
||||||
|
if (AutoVacPID != 0)
|
||||||
|
kill(AutoVacPID, SIGUSR1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PgArchPID != 0 && Shutdown == NoShutdown)
|
if (PgArchPID != 0 && Shutdown == NoShutdown)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.453 2005/07/10 21:13:58 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.454 2005/07/14 05:13:41 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* this is the "main" module of the postgres backend and
|
* this is the "main" module of the postgres backend and
|
||||||
@ -2111,7 +2111,7 @@ authdie(SIGNAL_ARGS)
|
|||||||
* Query-cancel signal from postmaster: abort current transaction
|
* Query-cancel signal from postmaster: abort current transaction
|
||||||
* at soonest convenient time
|
* at soonest convenient time
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
StatementCancelHandler(SIGNAL_ARGS)
|
StatementCancelHandler(SIGNAL_ARGS)
|
||||||
{
|
{
|
||||||
int save_errno = errno;
|
int save_errno = errno;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.240 2005/06/30 00:00:51 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.241 2005/07/14 05:13:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -843,7 +843,7 @@ ProcessUtility(Node *parsetree,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_VacuumStmt:
|
case T_VacuumStmt:
|
||||||
vacuum((VacuumStmt *) parsetree);
|
vacuum((VacuumStmt *) parsetree, NIL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_ExplainStmt:
|
case T_ExplainStmt:
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.145 2005/07/04 04:51:50 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.146 2005/07/14 05:13:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -32,6 +32,7 @@
|
|||||||
#include "catalog/pg_authid.h"
|
#include "catalog/pg_authid.h"
|
||||||
#include "libpq/libpq-be.h"
|
#include "libpq/libpq-be.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "postmaster/autovacuum.h"
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
#include "storage/ipc.h"
|
#include "storage/ipc.h"
|
||||||
#include "storage/pg_shmem.h"
|
#include "storage/pg_shmem.h"
|
||||||
@ -394,7 +395,7 @@ void
|
|||||||
InitializeSessionUserIdStandalone(void)
|
InitializeSessionUserIdStandalone(void)
|
||||||
{
|
{
|
||||||
/* This function should only be called in a single-user backend. */
|
/* This function should only be called in a single-user backend. */
|
||||||
AssertState(!IsUnderPostmaster);
|
AssertState(!IsUnderPostmaster || IsAutoVacuumProcess());
|
||||||
|
|
||||||
/* call only once */
|
/* call only once */
|
||||||
AssertState(!OidIsValid(AuthenticatedUserId));
|
AssertState(!OidIsValid(AuthenticatedUserId));
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.152 2005/07/04 04:51:50 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.153 2005/07/14 05:13:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
@ -29,6 +29,7 @@
|
|||||||
#include "libpq/hba.h"
|
#include "libpq/hba.h"
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "postmaster/autovacuum.h"
|
||||||
#include "postmaster/postmaster.h"
|
#include "postmaster/postmaster.h"
|
||||||
#include "storage/backendid.h"
|
#include "storage/backendid.h"
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
@ -268,7 +269,8 @@ BaseInit(void)
|
|||||||
* InitPostgres
|
* InitPostgres
|
||||||
* Initialize POSTGRES.
|
* Initialize POSTGRES.
|
||||||
*
|
*
|
||||||
* In bootstrap mode neither of the parameters are used.
|
* In bootstrap mode neither of the parameters are used. In autovacuum
|
||||||
|
* mode, the username parameter is not used.
|
||||||
*
|
*
|
||||||
* The return value indicates whether the userID is a superuser. (That
|
* The return value indicates whether the userID is a superuser. (That
|
||||||
* can only be tested inside a transaction, so we want to do it during
|
* can only be tested inside a transaction, so we want to do it during
|
||||||
@ -282,6 +284,7 @@ bool
|
|||||||
InitPostgres(const char *dbname, const char *username)
|
InitPostgres(const char *dbname, const char *username)
|
||||||
{
|
{
|
||||||
bool bootstrap = IsBootstrapProcessingMode();
|
bool bootstrap = IsBootstrapProcessingMode();
|
||||||
|
bool autovacuum = IsAutoVacuumProcess();
|
||||||
bool am_superuser;
|
bool am_superuser;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -402,10 +405,11 @@ InitPostgres(const char *dbname, const char *username)
|
|||||||
RelationCacheInitializePhase2();
|
RelationCacheInitializePhase2();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Figure out our postgres user id. In standalone mode we use a fixed
|
* Figure out our postgres user id. In standalone mode and in the
|
||||||
* id, otherwise we figure it out from the authenticated user name.
|
* autovacuum process, we use a fixed id, otherwise we figure it out from
|
||||||
|
* the authenticated user name.
|
||||||
*/
|
*/
|
||||||
if (bootstrap)
|
if (bootstrap || autovacuum)
|
||||||
InitializeSessionUserIdStandalone();
|
InitializeSessionUserIdStandalone();
|
||||||
else if (!IsUnderPostmaster)
|
else if (!IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
@ -441,7 +445,7 @@ InitPostgres(const char *dbname, const char *username)
|
|||||||
/*
|
/*
|
||||||
* Check if user is a superuser.
|
* Check if user is a superuser.
|
||||||
*/
|
*/
|
||||||
if (bootstrap)
|
if (bootstrap || autovacuum)
|
||||||
am_superuser = true;
|
am_superuser = true;
|
||||||
else
|
else
|
||||||
am_superuser = superuser();
|
am_superuser = superuser();
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.273 2005/07/05 23:18:10 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.274 2005/07/14 05:13:42 tgl Exp $
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -45,6 +45,7 @@
|
|||||||
#include "optimizer/prep.h"
|
#include "optimizer/prep.h"
|
||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
#include "parser/parse_relation.h"
|
#include "parser/parse_relation.h"
|
||||||
|
#include "postmaster/autovacuum.h"
|
||||||
#include "postmaster/bgwriter.h"
|
#include "postmaster/bgwriter.h"
|
||||||
#include "postmaster/syslogger.h"
|
#include "postmaster/syslogger.h"
|
||||||
#include "postmaster/postmaster.h"
|
#include "postmaster/postmaster.h"
|
||||||
@ -286,6 +287,8 @@ const char *const config_group_names[] =
|
|||||||
gettext_noop("Statistics / Monitoring"),
|
gettext_noop("Statistics / Monitoring"),
|
||||||
/* STATS_COLLECTOR */
|
/* STATS_COLLECTOR */
|
||||||
gettext_noop("Statistics / Query and Index Statistics Collector"),
|
gettext_noop("Statistics / Query and Index Statistics Collector"),
|
||||||
|
/* AUTOVACUUM */
|
||||||
|
gettext_noop("Auto Vacuum"),
|
||||||
/* CLIENT_CONN */
|
/* CLIENT_CONN */
|
||||||
gettext_noop("Client Connection Defaults"),
|
gettext_noop("Client Connection Defaults"),
|
||||||
/* CLIENT_CONN_STATEMENT */
|
/* CLIENT_CONN_STATEMENT */
|
||||||
@ -678,6 +681,15 @@ static struct config_bool ConfigureNamesBool[] =
|
|||||||
false, NULL, NULL
|
false, NULL, NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
{"autovacuum", PGC_SIGHUP, AUTOVACUUM,
|
||||||
|
gettext_noop("Starts the auto vacuum subprocess."),
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
&autovacuum_start_daemon,
|
||||||
|
false, NULL, NULL
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{"trace_notify", PGC_USERSET, DEVELOPER_OPTIONS,
|
{"trace_notify", PGC_USERSET, DEVELOPER_OPTIONS,
|
||||||
gettext_noop("Generates debugging output for LISTEN and NOTIFY."),
|
gettext_noop("Generates debugging output for LISTEN and NOTIFY."),
|
||||||
@ -1389,6 +1401,31 @@ static struct config_int ConfigureNamesInt[] =
|
|||||||
BLCKSZ, BLCKSZ, BLCKSZ, NULL, NULL
|
BLCKSZ, BLCKSZ, BLCKSZ, NULL, NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
{"autovacuum_naptime", PGC_SIGHUP, AUTOVACUUM,
|
||||||
|
gettext_noop("Time to sleep between autovacuum runs, in seconds."),
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
&autovacuum_naptime,
|
||||||
|
60, 0, INT_MAX, NULL, NULL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
|
||||||
|
gettext_noop("Minimum number of tuple updates or deletes prior to vacuum."),
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
&autovacuum_vac_thresh,
|
||||||
|
1000, 0, INT_MAX, NULL, NULL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
|
||||||
|
gettext_noop("Minimum number of tuple inserts, updates or deletes prior to analyze."),
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
&autovacuum_anl_thresh,
|
||||||
|
500, 0, INT_MAX, NULL, NULL
|
||||||
|
},
|
||||||
|
|
||||||
/* End-of-list marker */
|
/* End-of-list marker */
|
||||||
{
|
{
|
||||||
{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL
|
{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL
|
||||||
@ -1487,6 +1524,23 @@ static struct config_real ConfigureNamesReal[] =
|
|||||||
0.5, 0.0, 1.0, assign_random_seed, show_random_seed
|
0.5, 0.0, 1.0, assign_random_seed, show_random_seed
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
{"autovacuum_vacuum_scale_factor", PGC_SIGHUP, AUTOVACUUM,
|
||||||
|
gettext_noop("Number of tuple updates or deletes prior to vacuum as a fraction of reltuples."),
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
&autovacuum_vac_scale,
|
||||||
|
0.4, 0.0, 100.0, NULL, NULL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{"autovacuum_analyze_scale_factor", PGC_SIGHUP, AUTOVACUUM,
|
||||||
|
gettext_noop("Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples."),
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
&autovacuum_anl_scale,
|
||||||
|
0.2, 0.0, 100.0, NULL, NULL
|
||||||
|
},
|
||||||
|
|
||||||
/* End-of-list marker */
|
/* End-of-list marker */
|
||||||
{
|
{
|
||||||
{NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL
|
{NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL
|
||||||
|
@ -284,6 +284,18 @@
|
|||||||
#stats_reset_on_server_start = on
|
#stats_reset_on_server_start = on
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# AUTOVACUUM PARAMETERS
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#autovacuum = false # enable autovacuum subprocess?
|
||||||
|
#autovacuum_naptime = 60 # time between autovacuum runs, in seconds
|
||||||
|
#autovacuum_vacuum_threshold = 1000 # min # of tuple updates before vacuum
|
||||||
|
#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
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# CLIENT CONNECTION DEFAULTS
|
# CLIENT CONNECTION DEFAULTS
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.288 2005/07/10 21:13:59 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.289 2005/07/14 05:13:42 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200507102
|
#define CATALOG_VERSION_NO 200507131
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.89 2005/07/07 20:39:59 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.90 2005/07/14 05:13:42 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -210,6 +210,8 @@ DECLARE_UNIQUE_INDEX(pg_type_oid_index,2703, on pg_type using btree(oid oid_ops)
|
|||||||
DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index,2704, on pg_type using btree(typname name_ops, typnamespace oid_ops));
|
DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index,2704, on pg_type using btree(typname name_ops, typnamespace oid_ops));
|
||||||
#define TypeNameNspIndexId 2704
|
#define TypeNameNspIndexId 2704
|
||||||
|
|
||||||
|
DECLARE_UNIQUE_INDEX(pg_autovacuum_vacrelid_index,1250, on pg_autovacuum using btree(vacrelid oid_ops));
|
||||||
|
#define AutovacuumRelidIndexId 1250
|
||||||
|
|
||||||
/* last step of initialization script: build the indexes declared above */
|
/* last step of initialization script: build the indexes declared above */
|
||||||
BUILD_INDICES
|
BUILD_INDICES
|
||||||
|
60
src/include/catalog/pg_autovacuum.h
Normal file
60
src/include/catalog/pg_autovacuum.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* pg_autovacuum.h
|
||||||
|
* definition of the system "autovacuum" relation (pg_autovacuum)
|
||||||
|
*
|
||||||
|
* 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 $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#ifndef PG_AUTOVACUUM_H
|
||||||
|
#define PG_AUTOVACUUM_H
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* postgres.h contains the system type definitions and the
|
||||||
|
* CATALOG(), BOOTSTRAP and DATA() sugar words so this file
|
||||||
|
* can be read by both genbki.sh and the C compiler.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* pg_autovacuum definition. cpp turns this into
|
||||||
|
* typedef struct FormData_pg_autovacuum
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
#define AutovacuumRelationId 1248
|
||||||
|
CATALOG(pg_autovacuum,1248) BKI_WITHOUT_OIDS
|
||||||
|
{
|
||||||
|
Oid vacrelid; /* OID of table */
|
||||||
|
bool enabled; /* enabled for this table? */
|
||||||
|
int4 vac_base_thresh; /* base threshold value */
|
||||||
|
float4 vac_scale_factor; /* reltuples scaling factor */
|
||||||
|
int4 anl_base_thresh; /* base threshold value */
|
||||||
|
float4 anl_scale_factor; /* reltuples scaling factor */
|
||||||
|
} FormData_pg_autovacuum;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* Form_pg_autovacuum corresponds to a pointer to a tuple with
|
||||||
|
* the format of pg_autovacuum relation.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
typedef FormData_pg_autovacuum *Form_pg_autovacuum;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* compiler constants for pg_autovacuum
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
#define Natts_pg_autovacuum 6
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* There are no preloaded tuples in pg_autovacuum.h */
|
||||||
|
|
||||||
|
#endif /* PG_AUTOVACUUM_H */
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.59 2004/12/31 22:03:28 pgsql Exp $
|
* $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.60 2005/07/14 05:13:43 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -125,7 +125,7 @@ extern DLLIMPORT int default_statistics_target; /* DLLIMPORT for PostGIS */
|
|||||||
|
|
||||||
|
|
||||||
/* in commands/vacuum.c */
|
/* in commands/vacuum.c */
|
||||||
extern void vacuum(VacuumStmt *vacstmt);
|
extern void vacuum(VacuumStmt *vacstmt, List *relids);
|
||||||
extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
|
extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
|
||||||
int *nindexes, Relation **Irel);
|
int *nindexes, Relation **Irel);
|
||||||
extern void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode);
|
extern void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2001-2005, PostgreSQL Global Development Group
|
* Copyright (c) 2001-2005, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/pgstat.h,v 1.32 2005/06/29 22:51:57 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/pgstat.h,v 1.33 2005/07/14 05:13:43 tgl Exp $
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
#ifndef PGSTAT_H
|
#ifndef PGSTAT_H
|
||||||
@ -20,14 +20,20 @@
|
|||||||
* The types of backend/postmaster -> collector messages
|
* The types of backend/postmaster -> collector messages
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
#define PGSTAT_MTYPE_DUMMY 0
|
typedef enum StatMsgType
|
||||||
#define PGSTAT_MTYPE_BESTART 1
|
{
|
||||||
#define PGSTAT_MTYPE_BETERM 2
|
PGSTAT_MTYPE_DUMMY,
|
||||||
#define PGSTAT_MTYPE_ACTIVITY 3
|
PGSTAT_MTYPE_BESTART,
|
||||||
#define PGSTAT_MTYPE_TABSTAT 4
|
PGSTAT_MTYPE_BETERM,
|
||||||
#define PGSTAT_MTYPE_TABPURGE 5
|
PGSTAT_MTYPE_ACTIVITY,
|
||||||
#define PGSTAT_MTYPE_DROPDB 6
|
PGSTAT_MTYPE_TABSTAT,
|
||||||
#define PGSTAT_MTYPE_RESETCOUNTER 7
|
PGSTAT_MTYPE_TABPURGE,
|
||||||
|
PGSTAT_MTYPE_DROPDB,
|
||||||
|
PGSTAT_MTYPE_RESETCOUNTER,
|
||||||
|
PGSTAT_MTYPE_AUTOVAC_START,
|
||||||
|
PGSTAT_MTYPE_VACUUM,
|
||||||
|
PGSTAT_MTYPE_ANALYZE
|
||||||
|
} StatMsgType;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* The data type used for counters.
|
* The data type used for counters.
|
||||||
@ -48,7 +54,7 @@ typedef int64 PgStat_Counter;
|
|||||||
*/
|
*/
|
||||||
typedef struct PgStat_MsgHdr
|
typedef struct PgStat_MsgHdr
|
||||||
{
|
{
|
||||||
int m_type;
|
StatMsgType m_type;
|
||||||
int m_size;
|
int m_size;
|
||||||
int m_backendid;
|
int m_backendid;
|
||||||
int m_procpid;
|
int m_procpid;
|
||||||
@ -114,6 +120,47 @@ typedef struct PgStat_MsgBeterm
|
|||||||
PgStat_MsgHdr m_hdr;
|
PgStat_MsgHdr m_hdr;
|
||||||
} PgStat_MsgBeterm;
|
} PgStat_MsgBeterm;
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* PgStat_MsgAutovacStart Sent by the autovacuum daemon to signal
|
||||||
|
* that a database is going to be processed
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
|
typedef struct PgStat_MsgAutovacStart
|
||||||
|
{
|
||||||
|
PgStat_MsgHdr m_hdr;
|
||||||
|
Oid m_databaseid;
|
||||||
|
TimestampTz m_start_time;
|
||||||
|
} PgStat_MsgAutovacStart;
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* PgStat_MsgVacuum Sent by the backend or autovacuum daemon
|
||||||
|
* after VACUUM or VACUUM ANALYZE
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
|
typedef struct PgStat_MsgVacuum
|
||||||
|
{
|
||||||
|
PgStat_MsgHdr m_hdr;
|
||||||
|
Oid m_databaseid;
|
||||||
|
Oid m_tableoid;
|
||||||
|
bool m_analyze;
|
||||||
|
PgStat_Counter m_tuples;
|
||||||
|
} PgStat_MsgVacuum;
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* PgStat_MsgAnalyze Sent by the backend or autovacuum daemon
|
||||||
|
* after ANALYZE
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
|
typedef struct PgStat_MsgAnalyze
|
||||||
|
{
|
||||||
|
PgStat_MsgHdr m_hdr;
|
||||||
|
Oid m_databaseid;
|
||||||
|
Oid m_tableoid;
|
||||||
|
PgStat_Counter m_live_tuples;
|
||||||
|
PgStat_Counter m_dead_tuples;
|
||||||
|
} PgStat_MsgAnalyze;
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* PgStat_MsgActivity Sent by the backends when they start
|
* PgStat_MsgActivity Sent by the backends when they start
|
||||||
* to parse a query.
|
* to parse a query.
|
||||||
@ -200,14 +247,22 @@ typedef union PgStat_Msg
|
|||||||
PgStat_MsgTabpurge msg_tabpurge;
|
PgStat_MsgTabpurge msg_tabpurge;
|
||||||
PgStat_MsgDropdb msg_dropdb;
|
PgStat_MsgDropdb msg_dropdb;
|
||||||
PgStat_MsgResetcounter msg_resetcounter;
|
PgStat_MsgResetcounter msg_resetcounter;
|
||||||
|
PgStat_MsgAutovacStart msg_autovacuum;
|
||||||
|
PgStat_MsgVacuum msg_vacuum;
|
||||||
|
PgStat_MsgAnalyze msg_analyze;
|
||||||
} PgStat_Msg;
|
} PgStat_Msg;
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------
|
/* ------------------------------------------------------------
|
||||||
* Statistic collector data structures follow
|
* Statistic collector data structures follow
|
||||||
|
*
|
||||||
|
* PGSTAT_FILE_FORMAT_ID should be changed whenever any of these
|
||||||
|
* data structures change.
|
||||||
* ------------------------------------------------------------
|
* ------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define PGSTAT_FILE_FORMAT_ID 0x01A5BC93
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* PgStat_StatDBEntry The collectors data per database
|
* PgStat_StatDBEntry The collectors data per database
|
||||||
* ----------
|
* ----------
|
||||||
@ -222,6 +277,7 @@ typedef struct PgStat_StatDBEntry
|
|||||||
PgStat_Counter n_blocks_fetched;
|
PgStat_Counter n_blocks_fetched;
|
||||||
PgStat_Counter n_blocks_hit;
|
PgStat_Counter n_blocks_hit;
|
||||||
int destroy;
|
int destroy;
|
||||||
|
TimestampTz last_autovac_time;
|
||||||
} PgStat_StatDBEntry;
|
} PgStat_StatDBEntry;
|
||||||
|
|
||||||
|
|
||||||
@ -282,6 +338,10 @@ typedef struct PgStat_StatTabEntry
|
|||||||
PgStat_Counter tuples_updated;
|
PgStat_Counter tuples_updated;
|
||||||
PgStat_Counter tuples_deleted;
|
PgStat_Counter tuples_deleted;
|
||||||
|
|
||||||
|
PgStat_Counter n_live_tuples;
|
||||||
|
PgStat_Counter n_dead_tuples;
|
||||||
|
PgStat_Counter last_anl_tuples;
|
||||||
|
|
||||||
PgStat_Counter blocks_fetched;
|
PgStat_Counter blocks_fetched;
|
||||||
PgStat_Counter blocks_hit;
|
PgStat_Counter blocks_hit;
|
||||||
|
|
||||||
@ -323,6 +383,11 @@ extern void pgstat_bestart(void);
|
|||||||
extern void pgstat_ping(void);
|
extern void pgstat_ping(void);
|
||||||
extern void pgstat_report_activity(const char *what);
|
extern void pgstat_report_activity(const char *what);
|
||||||
extern void pgstat_report_tabstat(void);
|
extern void pgstat_report_tabstat(void);
|
||||||
|
extern void pgstat_report_autovac(void);
|
||||||
|
extern void pgstat_report_vacuum(Oid tableoid, bool analyze,
|
||||||
|
PgStat_Counter tuples);
|
||||||
|
extern void pgstat_report_analyze(Oid tableoid, PgStat_Counter livetuples,
|
||||||
|
PgStat_Counter deadtuples);
|
||||||
extern int pgstat_vacuum_tabstat(void);
|
extern int pgstat_vacuum_tabstat(void);
|
||||||
|
|
||||||
extern void pgstat_reset_counters(void);
|
extern void pgstat_reset_counters(void);
|
||||||
|
38
src/include/postmaster/autovacuum.h
Normal file
38
src/include/postmaster/autovacuum.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* autovacuum.h
|
||||||
|
* header file for integrated autovacuum daemon
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 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 $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#ifndef AUTOVACUUM_H
|
||||||
|
#define AUTOVACUUM_H
|
||||||
|
|
||||||
|
/* GUC variables */
|
||||||
|
extern bool autovacuum_start_daemon;
|
||||||
|
extern int autovacuum_naptime;
|
||||||
|
extern int autovacuum_vac_thresh;
|
||||||
|
extern double autovacuum_vac_scale;
|
||||||
|
extern int autovacuum_anl_thresh;
|
||||||
|
extern double autovacuum_anl_scale;
|
||||||
|
|
||||||
|
/* Status inquiry functions */
|
||||||
|
extern bool AutoVacuumingActive(void);
|
||||||
|
extern bool IsAutoVacuumProcess(void);
|
||||||
|
|
||||||
|
/* Functions to start autovacuum process, called from postmaster */
|
||||||
|
extern void autovac_init(void);
|
||||||
|
extern int autovac_start(void);
|
||||||
|
extern void autovac_stopped(void);
|
||||||
|
|
||||||
|
#ifdef EXEC_BACKEND
|
||||||
|
extern void AutoVacMain(int argc, char *argv[]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* AUTOVACUUM_H */
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.75 2005/06/03 23:05:30 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.76 2005/07/14 05:13:44 tgl Exp $
|
||||||
*
|
*
|
||||||
* OLD COMMENTS
|
* OLD COMMENTS
|
||||||
* This file was created so that other c files could get the two
|
* This file was created so that other c files could get the two
|
||||||
@ -58,6 +58,7 @@ extern bool assign_max_stack_depth(int newval, bool doit, GucSource source);
|
|||||||
extern void die(SIGNAL_ARGS);
|
extern void die(SIGNAL_ARGS);
|
||||||
extern void quickdie(SIGNAL_ARGS);
|
extern void quickdie(SIGNAL_ARGS);
|
||||||
extern void authdie(SIGNAL_ARGS);
|
extern void authdie(SIGNAL_ARGS);
|
||||||
|
extern void StatementCancelHandler(SIGNAL_ARGS);
|
||||||
extern void prepare_for_client_read(void);
|
extern void prepare_for_client_read(void);
|
||||||
extern void client_read_ended(void);
|
extern void client_read_ended(void);
|
||||||
extern int PostgresMain(int argc, char *argv[], const char *username);
|
extern int PostgresMain(int argc, char *argv[], const char *username);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.19 2004/12/31 22:03:46 pgsql Exp $
|
* $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.20 2005/07/14 05:13:44 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -62,6 +62,7 @@ enum config_group
|
|||||||
STATS,
|
STATS,
|
||||||
STATS_MONITORING,
|
STATS_MONITORING,
|
||||||
STATS_COLLECTOR,
|
STATS_COLLECTOR,
|
||||||
|
AUTOVACUUM,
|
||||||
CLIENT_CONN,
|
CLIENT_CONN,
|
||||||
CLIENT_CONN_STATEMENT,
|
CLIENT_CONN_STATEMENT,
|
||||||
CLIENT_CONN_LOCALE,
|
CLIENT_CONN_LOCALE,
|
||||||
|
@ -40,6 +40,7 @@ SELECT relname, relhasindex
|
|||||||
pg_attribute | t
|
pg_attribute | t
|
||||||
pg_auth_members | t
|
pg_auth_members | t
|
||||||
pg_authid | t
|
pg_authid | t
|
||||||
|
pg_autovacuum | t
|
||||||
pg_cast | t
|
pg_cast | t
|
||||||
pg_class | t
|
pg_class | t
|
||||||
pg_constraint | t
|
pg_constraint | t
|
||||||
@ -66,7 +67,7 @@ SELECT relname, relhasindex
|
|||||||
shighway | t
|
shighway | t
|
||||||
tenk1 | t
|
tenk1 | t
|
||||||
tenk2 | t
|
tenk2 | t
|
||||||
(56 rows)
|
(57 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- another sanity check: every system catalog that has OIDs should have
|
-- another sanity check: every system catalog that has OIDs should have
|
||||||
|
Reference in New Issue
Block a user