v9_autovacuum_on_partitioned_table.patch
application/octet-stream
Filename: v9_autovacuum_on_partitioned_table.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
Series: patch v9
| File | + | − |
|---|---|---|
| doc/src/sgml/ref/create_table.sgml | 0 | 2 |
| src/backend/access/common/reloptions.c | 7 | 8 |
| src/backend/catalog/system_views.sql | 2 | 2 |
| src/backend/commands/analyze.c | 4 | 6 |
| src/backend/commands/vacuum.c | 1 | 0 |
| src/backend/postmaster/autovacuum.c | 43 | 7 |
| src/backend/postmaster/pgstat.c | 98 | 4 |
| src/include/pgstat.h | 1 | 1 |
| src/test/regress/expected/rules.out | 2 | 2 |
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index dc688c415f..1f212b4d68 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -1322,8 +1322,6 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
If a table parameter value is set and the
equivalent <literal>toast.</literal> parameter is not, the TOAST table
will use the table's parameter value.
- Specifying these parameters for partitioned tables is not supported,
- but you may specify them for individual leaf partitions.
</para>
<variablelist>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 8ccc228a8c..35bc2e5bdb 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -108,7 +108,7 @@ static relopt_bool boolRelOpts[] =
{
"autovacuum_enabled",
"Enables autovacuum in this relation",
- RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+ RELOPT_KIND_HEAP | RELOPT_KIND_TOAST | RELOPT_KIND_PARTITIONED,
ShareUpdateExclusiveLock
},
true
@@ -246,7 +246,7 @@ static relopt_int intRelOpts[] =
{
"autovacuum_analyze_threshold",
"Minimum number of tuple inserts, updates or deletes prior to analyze",
- RELOPT_KIND_HEAP,
+ RELOPT_KIND_HEAP | RELOPT_KIND_PARTITIONED,
ShareUpdateExclusiveLock
},
-1, 0, INT_MAX
@@ -420,7 +420,7 @@ static relopt_real realRelOpts[] =
{
"autovacuum_analyze_scale_factor",
"Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
- RELOPT_KIND_HEAP,
+ RELOPT_KIND_HEAP | RELOPT_KIND_PARTITIONED,
ShareUpdateExclusiveLock
},
-1, 0.0, 100.0
@@ -1961,13 +1961,12 @@ build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
bytea *
partitioned_table_reloptions(Datum reloptions, bool validate)
{
+
/*
- * There are no options for partitioned tables yet, but this is able to do
- * some validation.
+ * autovacuum_enabled, autovacuum_analyze_threshold and
+ * autovacuum_analyze_scale_factor are supported for partitioned tables.
*/
- return (bytea *) build_reloptions(reloptions, validate,
- RELOPT_KIND_PARTITIONED,
- 0, NULL, 0);
+ return default_reloptions(reloptions, validate, RELOPT_KIND_PARTITIONED);
}
/*
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 8625cbeab6..60f311f4f2 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -585,7 +585,7 @@ CREATE VIEW pg_stat_all_tables AS
FROM pg_class C LEFT JOIN
pg_index I ON C.oid = I.indrelid
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
- WHERE C.relkind IN ('r', 't', 'm')
+ WHERE C.relkind IN ('r', 't', 'm', 'p')
GROUP BY C.oid, N.nspname, C.relname;
CREATE VIEW pg_stat_xact_all_tables AS
@@ -605,7 +605,7 @@ CREATE VIEW pg_stat_xact_all_tables AS
FROM pg_class C LEFT JOIN
pg_index I ON C.oid = I.indrelid
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
- WHERE C.relkind IN ('r', 't', 'm')
+ WHERE C.relkind IN ('r', 't', 'm', 'p')
GROUP BY C.oid, N.nspname, C.relname;
CREATE VIEW pg_stat_sys_tables AS
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 8af12b5c6b..4c91e48a21 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -644,13 +644,11 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
}
/*
- * Report ANALYZE to the stats collector, too. However, if doing
- * inherited stats we shouldn't report, because the stats collector only
- * tracks per-table stats. Reset the changes_since_analyze counter only
- * if we analyzed all columns; otherwise, there is still work for
- * auto-analyze to do.
+ * Report ANALYZE to the stats collector, too. Reset the
+ * changes_since_analyze counter only if we analyzed all columns;
+ * otherwise, there is still work for auto-analyze to do.
*/
- if (!inh)
+ if (!inh || onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
pgstat_report_analyze(onerel, totalrows, totaldeadrows,
(va_cols == NIL));
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 23eb605d4c..d274852a78 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -829,6 +829,7 @@ expand_vacuum_rel(VacuumRelation *vrel, int options)
vacrels = lappend(vacrels, makeVacuumRelation(NULL,
part_oid,
vrel->va_cols));
+
MemoryContextSwitchTo(oldcontext);
}
}
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index c6ec657a93..3154d8fd4d 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -75,6 +75,7 @@
#include "catalog/dependency.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_inherits.h"
#include "commands/dbcommands.h"
#include "commands/vacuum.h"
#include "lib/ilist.h"
@@ -2036,11 +2037,11 @@ do_autovacuum(void)
* Scan pg_class to determine which tables to vacuum.
*
* We do this in two passes: on the first one we collect the list of plain
- * relations and materialized views, and on the second one we collect
- * TOAST tables. The reason for doing the second pass is that during it we
- * want to use the main relation's pg_class.reloptions entry if the TOAST
- * table does not have any, and we cannot obtain it unless we know
- * beforehand what's the main table OID.
+ * relations, materialized views and partitioned tables, and on the second
+ * one we collect TOAST tables. The reason for doing the second pass is that
+ * during it we want to use the main relation's pg_class.reloptions entry
+ * if the TOAST table does not have any, and we cannot obtain it unless we
+ * know beforehand what's the main table OID.
*
* We need to check TOAST tables separately because in cases with short,
* wide tables there might be proportionally much more activity in the
@@ -2063,7 +2064,8 @@ do_autovacuum(void)
bool wraparound;
if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW)
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
continue;
relid = classForm->oid;
@@ -2726,6 +2728,7 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
+ ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_PARTITIONED_TABLE ||
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
relopts = extractRelOptions(tup, pg_class_desc, NULL);
@@ -3075,7 +3078,40 @@ relation_needs_vacanalyze(Oid relid,
*/
if (PointerIsValid(tabentry) && AutoVacuumingActive())
{
- reltuples = classForm->reltuples;
+ if (classForm->relkind != RELKIND_PARTITIONED_TABLE)
+ reltuples = classForm->reltuples;
+ else
+ {
+ /*
+ * If the relation is a partitioned table, we must add up childrens'
+ * reltuples.
+ */
+ List *children;
+ ListCell *lc;
+
+ reltuples = 0;
+
+ /* Find all members of inheritance set taking AccessShareLock */
+ children = find_all_inheritors(relid, AccessShareLock, NULL);
+
+ foreach(lc, children)
+ {
+ Oid childOID = lfirst_oid(lc);
+ HeapTuple childtuple;
+ Form_pg_class childclass;
+
+ childtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(childOID));
+ childclass = (Form_pg_class) GETSTRUCT(childtuple);
+
+ /* Skip foreign partitions */
+ if (childclass->relkind == RELKIND_FOREIGN_TABLE)
+ continue;
+
+ /* Sum up the child's reltuples for its parent table */
+ reltuples += childclass->reltuples;
+ }
+ }
+
vactuples = tabentry->n_dead_tuples;
instuples = tabentry->inserts_since_vacuum;
anltuples = tabentry->changes_since_analyze;
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 73ce944fb1..5730c418c9 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -38,6 +38,7 @@
#include "access/transam.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
+#include "catalog/partition.h"
#include "catalog/pg_database.h"
#include "catalog/pg_proc.h"
#include "common/ip.h"
@@ -1529,8 +1530,12 @@ pgstat_report_analyze(Relation rel,
msg.m_autovacuum = IsAutoVacuumWorkerProcess();
msg.m_resetcounter = resetcounter;
msg.m_analyzetime = GetCurrentTimestamp();
- msg.m_live_tuples = livetuples;
- msg.m_dead_tuples = deadtuples;
+ msg.m_live_tuples = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ ? 0 /* partitioned tables don't have any data, so it's 0 */
+ : livetuples;
+ msg.m_dead_tuples = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ ? 0 /* partitioned tables don't have any data, so it's 0 */
+ : deadtuples;
pgstat_send(&msg, sizeof(msg));
}
@@ -1807,7 +1812,8 @@ pgstat_initstats(Relation rel)
char relkind = rel->rd_rel->relkind;
/* We only count stats for things that have storage */
- if (!RELKIND_HAS_STORAGE(relkind))
+ if (!RELKIND_HAS_STORAGE(relkind) ||
+ relkind == RELKIND_PARTITIONED_TABLE)
{
rel->pgstat_info = NULL;
return;
@@ -2003,6 +2009,28 @@ pgstat_count_heap_insert(Relation rel, PgStat_Counter n)
/* We have to log the effect at the proper transactional level */
int nest_level = GetCurrentTransactionNestLevel();
+ /*
+ * If this relation is partitioned, we store all ancestors' oid
+ * to propagate its changed_tuples to their parents when this
+ * transaction is committed.
+ */
+ if (rel->rd_rel->relispartition && pgstat_info->ancestors == NULL)
+ {
+ List *ancestors;
+ ListCell *lc;
+ int i = 0;
+
+ ancestors = get_partition_ancestors(rel->rd_rel->oid);
+ pgstat_info->ancestors =
+ (Oid *) MemoryContextAllocZero(TopTransactionContext,
+ sizeof(Oid) * (ancestors->length + 1));
+ foreach(lc, ancestors)
+ {
+ pgstat_info->ancestors[i] = lfirst_oid(lc);
+ ++i;
+ }
+ }
+
if (pgstat_info->trans == NULL ||
pgstat_info->trans->nest_level != nest_level)
add_tabstat_xact_level(pgstat_info, nest_level);
@@ -2024,6 +2052,28 @@ pgstat_count_heap_update(Relation rel, bool hot)
/* We have to log the effect at the proper transactional level */
int nest_level = GetCurrentTransactionNestLevel();
+ /*
+ * If this relation is partitioned, we store all ancestors' oid
+ * to propagate its changed_tuples to their parents when this
+ * transaction is committed.
+ */
+ if (rel->rd_rel->relispartition && pgstat_info->ancestors == NULL)
+ {
+ List *ancestors;
+ ListCell *lc;
+ int i = 0;
+
+ ancestors = get_partition_ancestors(rel->rd_rel->oid);
+ pgstat_info->ancestors =
+ (Oid *) MemoryContextAllocZero(TopTransactionContext,
+ sizeof(Oid) * (ancestors->length + 1));
+ foreach(lc, ancestors)
+ {
+ pgstat_info->ancestors[i] = lfirst_oid(lc);
+ ++i;
+ }
+ }
+
if (pgstat_info->trans == NULL ||
pgstat_info->trans->nest_level != nest_level)
add_tabstat_xact_level(pgstat_info, nest_level);
@@ -2049,6 +2099,28 @@ pgstat_count_heap_delete(Relation rel)
/* We have to log the effect at the proper transactional level */
int nest_level = GetCurrentTransactionNestLevel();
+ /*
+ * If this relation is partitioned, we store all ancestors' oid
+ * to propagate its changed_tuples to their parents when this
+ * transaction is committed.
+ */
+ if (rel->rd_rel->relispartition && pgstat_info->ancestors == NULL)
+ {
+ List *ancestors;
+ ListCell *lc;
+ int i = 0;
+
+ ancestors = get_partition_ancestors(rel->rd_rel->oid);
+ pgstat_info->ancestors =
+ (Oid *) MemoryContextAllocZero(TopTransactionContext,
+ sizeof(Oid) * (ancestors->length + 1));
+ foreach(lc, ancestors)
+ {
+ pgstat_info->ancestors[i] = lfirst_oid(lc);
+ ++i;
+ }
+ }
+
if (pgstat_info->trans == NULL ||
pgstat_info->trans->nest_level != nest_level)
add_tabstat_xact_level(pgstat_info, nest_level);
@@ -2203,6 +2275,29 @@ AtEOXact_PgStat(bool isCommit, bool parallel)
tabstat->t_counts.t_changed_tuples +=
trans->tuples_inserted + trans->tuples_updated +
trans->tuples_deleted;
+
+ /*
+ * If this relation is partitioned, propagate its own
+ * changed_tuples to their all ancestors.
+ */
+ if (tabstat->ancestors != NULL)
+ {
+ int i = 0;
+
+ for(;;)
+ {
+ PgStat_TableStatus *entry;
+ Oid relid = tabstat->ancestors[i];
+
+ if(relid == InvalidOid)
+ break;
+
+ entry = get_tabstat_entry(relid, false);
+ entry->t_counts.t_changed_tuples +=
+ tabstat->t_counts.t_changed_tuples;
+ ++i;
+ }
+ }
}
else
{
@@ -6358,7 +6453,6 @@ pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len)
}
}
-
/* ----------
* pgstat_recv_archiver() -
*
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 1387201382..239e7e688a 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -156,6 +156,7 @@ typedef enum PgStat_Single_Reset_Type
typedef struct PgStat_TableStatus
{
Oid t_id; /* table's OID */
+ Oid *ancestors; /* all ancestors */
bool t_shared; /* is it a shared catalog? */
struct PgStat_TableXactStatus *trans; /* lowest subxact's counts */
PgStat_TableCounts t_counts; /* event counts to be sent */
@@ -403,7 +404,6 @@ typedef struct PgStat_MsgAnalyze
PgStat_Counter m_dead_tuples;
} PgStat_MsgAnalyze;
-
/* ----------
* PgStat_MsgArchiver Sent by the archiver to update statistics.
* ----------
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 601734a6f1..14d8af91c1 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1794,7 +1794,7 @@ pg_stat_all_tables| SELECT c.oid AS relid,
FROM ((pg_class c
LEFT JOIN pg_index i ON ((c.oid = i.indrelid)))
LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
- WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"]))
+ WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char", 'p'::"char"]))
GROUP BY c.oid, n.nspname, c.relname;
pg_stat_archiver| SELECT s.archived_count,
s.last_archived_wal,
@@ -2150,7 +2150,7 @@ pg_stat_xact_all_tables| SELECT c.oid AS relid,
FROM ((pg_class c
LEFT JOIN pg_index i ON ((c.oid = i.indrelid)))
LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
- WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"]))
+ WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char", 'p'::"char"]))
GROUP BY c.oid, n.nspname, c.relname;
pg_stat_xact_sys_tables| SELECT pg_stat_xact_all_tables.relid,
pg_stat_xact_all_tables.schemaname,