Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d4cef0a

Browse files
committed
Improve vacuum code to track minimum Xids per table instead of per database.
To this end, add a couple of columns to pg_class, relminxid and relvacuumxid, based on which we calculate the pg_database columns after each vacuum. We now force all databases to be vacuumed, even template ones. A backend noticing too old a database (meaning pg_database.datminxid is in danger of falling behind Xid wraparound) will signal the postmaster, which in turn will start an autovacuum iteration to process the offending database. In principle this is only there to cope with frozen (non-connectable) databases without forcing users to set them to connectable, but it could force regular user database to go through a database-wide vacuum at any time. Maybe we should warn users about this somehow. Of course the real solution will be to use autovacuum all the time ;-) There are some additional improvements we could have in this area: for example the vacuum code could be smarter about not updating pg_database for each table when called by autovacuum, and do it only once the whole autovacuum iteration is done. I updated the system catalogs documentation, but I didn't modify the maintenance section. Also having some regression tests for this would be nice but it's not really a very straightforward thing to do. Catalog version bumped due to system catalog changes.
1 parent e627c9b commit d4cef0a

File tree

19 files changed

+543
-264
lines changed

19 files changed

+543
-264
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.125 2006/07/03 22:45:36 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.126 2006/07/10 16:20:49 alvherre Exp $ -->
22
<!--
33
Documentation of the system catalogs, directed toward PostgreSQL developers
44
-->
@@ -1639,6 +1639,30 @@
16391639
<entry>True if table has (or once had) any inheritance children</entry>
16401640
</row>
16411641

1642+
<row>
1643+
<entry><structfield>relminxid</structfield></entry>
1644+
<entry><type>xid</type></entry>
1645+
<entry></entry>
1646+
<entry>
1647+
The minimum transaction ID present in all rows in this table. This
1648+
value is used to determine the database-global
1649+
<structname>pg_database</>.<structfield>datminxid</> value.
1650+
</entry>
1651+
</row>
1652+
1653+
<row>
1654+
<entry><structfield>relvacuumxid</structfield></entry>
1655+
<entry><type>xid</type></entry>
1656+
<entry></entry>
1657+
<entry>
1658+
The transaction ID that was used as cleaning point as of the last vacuum
1659+
operation. All rows inserted, updated or deleted in this table by
1660+
transactions whose IDs are below this one have been marked as known good
1661+
or deleted. This is used to determine the database-global
1662+
<structname>pg_database</>.<structfield>datvacuumxid</> value.
1663+
</entry>
1664+
</row>
1665+
16421666
<row>
16431667
<entry><structfield>relacl</structfield></entry>
16441668
<entry><type>aclitem[]</type></entry>
@@ -2022,21 +2046,27 @@
20222046
<entry><type>xid</type></entry>
20232047
<entry></entry>
20242048
<entry>
2025-
All rows inserted or deleted by transaction IDs before this one
2026-
have been marked as known committed or known aborted in this database.
2027-
This is used to determine when commit-log space can be recycled.
2049+
The transaction ID that was used as cleaning point as of the last vacuum
2050+
operation. All rows inserted or deleted by transaction IDs before this one
2051+
have been marked as known good or deleted. This
2052+
is used to determine when commit-log space can be recycled.
2053+
If InvalidTransactionId, then the minimum is unknown and can be
2054+
determined by scanning <structname>pg_class</>.<structfield>relvacuumxid</>.
20282055
</entry>
20292056
</row>
20302057

20312058
<row>
2032-
<entry><structfield>datfrozenxid</structfield></entry>
2059+
<entry><structfield>datminxid</structfield></entry>
20332060
<entry><type>xid</type></entry>
20342061
<entry></entry>
20352062
<entry>
2063+
The minimum transaction ID present in all tables in this database.
20362064
All rows inserted by transaction IDs before this one have been
20372065
relabeled with a permanent (<quote>frozen</>) transaction ID in this
2038-
database. This is useful to check whether a database must be vacuumed
2039-
soon to avoid transaction ID wrap-around problems.
2066+
database. This is useful to check whether a database must be
2067+
vacuumed soon to avoid transaction ID wrap-around problems.
2068+
If InvalidTransactionId, then the minimum is unknown and can be
2069+
determined by scanning <structname>pg_class</>.<structfield>relminxid</>.
20402070
</entry>
20412071
</row>
20422072

src/backend/access/transam/varsup.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
77
*
88
* IDENTIFICATION
9-
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.70 2006/03/05 15:58:22 momjian Exp $
9+
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.71 2006/07/10 16:20:49 alvherre Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -168,28 +168,28 @@ ReadNewTransactionId(void)
168168

169169
/*
170170
* Determine the last safe XID to allocate given the currently oldest
171-
* datfrozenxid (ie, the oldest XID that might exist in any database
171+
* datminxid (ie, the oldest XID that might exist in any database
172172
* of our cluster).
173173
*/
174174
void
175-
SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
175+
SetTransactionIdLimit(TransactionId oldest_datminxid,
176176
Name oldest_datname)
177177
{
178178
TransactionId xidWarnLimit;
179179
TransactionId xidStopLimit;
180180
TransactionId xidWrapLimit;
181181
TransactionId curXid;
182182

183-
Assert(TransactionIdIsValid(oldest_datfrozenxid));
183+
Assert(TransactionIdIsValid(oldest_datminxid));
184184

185185
/*
186186
* The place where we actually get into deep trouble is halfway around
187-
* from the oldest potentially-existing XID. (This calculation is
188-
* probably off by one or two counts, because the special XIDs reduce the
189-
* size of the loop a little bit. But we throw in plenty of slop below,
190-
* so it doesn't matter.)
187+
* from the oldest existing XID. (This calculation is probably off by one
188+
* or two counts, because the special XIDs reduce the size of the loop a
189+
* little bit. But we throw in plenty of slop below, so it doesn't
190+
* matter.)
191191
*/
192-
xidWrapLimit = oldest_datfrozenxid + (MaxTransactionId >> 1);
192+
xidWrapLimit = oldest_datminxid + (MaxTransactionId >> 1);
193193
if (xidWrapLimit < FirstNormalTransactionId)
194194
xidWrapLimit += FirstNormalTransactionId;
195195

src/backend/catalog/heap.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.305 2006/07/08 20:45:38 alvherre Exp $
11+
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.306 2006/07/10 16:20:49 alvherre Exp $
1212
*
1313
*
1414
* INTERFACE ROUTINES
@@ -597,6 +597,8 @@ InsertPgClassTuple(Relation pg_class_desc,
597597
values[Anum_pg_class_relhaspkey - 1] = BoolGetDatum(rd_rel->relhaspkey);
598598
values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules);
599599
values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
600+
values[Anum_pg_class_relminxid - 1] = TransactionIdGetDatum(rd_rel->relminxid);
601+
values[Anum_pg_class_relvacuumxid - 1] = TransactionIdGetDatum(rd_rel->relvacuumxid);
600602
/* start out with empty permissions */
601603
nulls[Anum_pg_class_relacl - 1] = 'n';
602604
if (reloptions != (Datum) 0)
@@ -644,6 +646,35 @@ AddNewRelationTuple(Relation pg_class_desc,
644646
*/
645647
new_rel_reltup = new_rel_desc->rd_rel;
646648

649+
/* Initialize relminxid and relvacuumxid */
650+
if (relkind == RELKIND_RELATION ||
651+
relkind == RELKIND_TOASTVALUE)
652+
{
653+
/*
654+
* Only real tables have Xids stored in them; initialize our known
655+
* value to the minimum Xid that could put tuples in the new table.
656+
*/
657+
if (!IsBootstrapProcessingMode())
658+
{
659+
new_rel_reltup->relminxid = RecentXmin;
660+
new_rel_reltup->relvacuumxid = RecentXmin;
661+
}
662+
else
663+
{
664+
new_rel_reltup->relminxid = FirstNormalTransactionId;
665+
new_rel_reltup->relvacuumxid = FirstNormalTransactionId;
666+
}
667+
}
668+
else
669+
{
670+
/*
671+
* Other relations will not have Xids in them, so set the initial value
672+
* to InvalidTransactionId.
673+
*/
674+
new_rel_reltup->relminxid = InvalidTransactionId;
675+
new_rel_reltup->relvacuumxid = InvalidTransactionId;
676+
}
677+
647678
switch (relkind)
648679
{
649680
case RELKIND_RELATION:

src/backend/commands/analyze.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.93 2006/03/23 00:19:28 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.94 2006/07/10 16:20:50 alvherre Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -424,8 +424,9 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
424424
{
425425
vac_update_relstats(RelationGetRelid(onerel),
426426
RelationGetNumberOfBlocks(onerel),
427-
totalrows,
428-
hasindex);
427+
totalrows, hasindex,
428+
InvalidTransactionId, InvalidTransactionId);
429+
429430
for (ind = 0; ind < nindexes; ind++)
430431
{
431432
AnlIndexData *thisdata = &indexdata[ind];
@@ -434,8 +435,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
434435
totalindexrows = ceil(thisdata->tupleFract * totalrows);
435436
vac_update_relstats(RelationGetRelid(Irel[ind]),
436437
RelationGetNumberOfBlocks(Irel[ind]),
437-
totalindexrows,
438-
false);
438+
totalindexrows, false,
439+
InvalidTransactionId, InvalidTransactionId);
439440
}
440441

441442
/* report results to the stats collector, too */

src/backend/commands/dbcommands.c

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.181 2006/05/04 16:07:29 tgl Exp $
16+
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.182 2006/07/10 16:20:50 alvherre Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -55,7 +55,7 @@ static bool get_db_info(const char *name, LOCKMODE lockmode,
5555
Oid *dbIdP, Oid *ownerIdP,
5656
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
5757
Oid *dbLastSysOidP,
58-
TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
58+
TransactionId *dbVacuumXidP, TransactionId *dbMinXidP,
5959
Oid *dbTablespace);
6060
static bool have_createdb_privilege(void);
6161
static void remove_dbtablespaces(Oid db_id);
@@ -76,7 +76,7 @@ createdb(const CreatedbStmt *stmt)
7676
bool src_allowconn;
7777
Oid src_lastsysoid;
7878
TransactionId src_vacuumxid;
79-
TransactionId src_frozenxid;
79+
TransactionId src_minxid;
8080
Oid src_deftablespace;
8181
volatile Oid dst_deftablespace;
8282
Relation pg_database_rel;
@@ -228,7 +228,7 @@ createdb(const CreatedbStmt *stmt)
228228
if (!get_db_info(dbtemplate, ShareLock,
229229
&src_dboid, &src_owner, &src_encoding,
230230
&src_istemplate, &src_allowconn, &src_lastsysoid,
231-
&src_vacuumxid, &src_frozenxid, &src_deftablespace))
231+
&src_vacuumxid, &src_minxid, &src_deftablespace))
232232
ereport(ERROR,
233233
(errcode(ERRCODE_UNDEFINED_DATABASE),
234234
errmsg("template database \"%s\" does not exist",
@@ -326,16 +326,6 @@ createdb(const CreatedbStmt *stmt)
326326
/* Note there is no additional permission check in this path */
327327
}
328328

329-
/*
330-
* Normally we mark the new database with the same datvacuumxid and
331-
* datfrozenxid as the source. However, if the source is not allowing
332-
* connections then we assume it is fully frozen, and we can set the
333-
* current transaction ID as the xid limits. This avoids immediately
334-
* starting to generate warnings after cloning template0.
335-
*/
336-
if (!src_allowconn)
337-
src_vacuumxid = src_frozenxid = GetCurrentTransactionId();
338-
339329
/*
340330
* Check for db name conflict. This is just to give a more friendly
341331
* error message than "unique index violation". There's a race condition
@@ -367,7 +357,7 @@ createdb(const CreatedbStmt *stmt)
367357
new_record[Anum_pg_database_datconnlimit - 1] = Int32GetDatum(dbconnlimit);
368358
new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
369359
new_record[Anum_pg_database_datvacuumxid - 1] = TransactionIdGetDatum(src_vacuumxid);
370-
new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid);
360+
new_record[Anum_pg_database_datminxid - 1] = TransactionIdGetDatum(src_minxid);
371361
new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
372362

373363
/*
@@ -1066,7 +1056,7 @@ get_db_info(const char *name, LOCKMODE lockmode,
10661056
Oid *dbIdP, Oid *ownerIdP,
10671057
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
10681058
Oid *dbLastSysOidP,
1069-
TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
1059+
TransactionId *dbVacuumXidP, TransactionId *dbMinXidP,
10701060
Oid *dbTablespace)
10711061
{
10721062
bool result = false;
@@ -1155,9 +1145,9 @@ get_db_info(const char *name, LOCKMODE lockmode,
11551145
/* limit of vacuumed XIDs */
11561146
if (dbVacuumXidP)
11571147
*dbVacuumXidP = dbform->datvacuumxid;
1158-
/* limit of frozen XIDs */
1159-
if (dbFrozenXidP)
1160-
*dbFrozenXidP = dbform->datfrozenxid;
1148+
/* limit of min XIDs */
1149+
if (dbMinXidP)
1150+
*dbMinXidP = dbform->datminxid;
11611151
/* default tablespace for this database */
11621152
if (dbTablespace)
11631153
*dbTablespace = dbform->dattablespace;

0 commit comments

Comments
 (0)