Skip to content

Commit 2d12c55

Browse files
committed
Repair pg_upgrade's failure to preserve relfrozenxid for matviews.
This oversight led to data corruption in matviews, manifesting as "could not access status of transaction" before our most recent releases, and "found xmin from before relfrozenxid" errors since then. The proximate cause of the problem seems to have been confusion between the task of preserving dropped-column status and the task of preserving frozenxid status. Those are required for distinct sets of relkinds, and the reasoning was entirely undocumented in the source code. In hopes of forestalling future errors of the same kind, try to improve the commentary in this area. In passing, also improve the remarkably unhelpful comments around pg_upgrade's set_frozenxids(). That's not actually buggy AFAICS, but good luck figuring out what it does from the old comments. Per report from Claudio Freire. It appears that bug #14852 from Alexey Ermakov is an earlier report of the same issue, and there may be other cases that we failed to identify at the time. Patch by me based on analysis by Andres Freund. The bug dates back to the introduction of matviews, so back-patch to all supported branches. Discussion: https://postgr.es/m/CAGTBQpbrY9CdRGGhyBZ9yqY4jWaGC85rUF4X+R7d-aim=mBNsw@mail.gmail.com Discussion: https://postgr.es/m/20171013115320.28049.86457@wrigleys.postgresql.org
1 parent e11b648 commit 2d12c55

File tree

2 files changed

+47
-13
lines changed

2 files changed

+47
-13
lines changed

contrib/pg_upgrade/pg_upgrade.c

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -437,13 +437,13 @@ static void
437437
prepare_new_databases(void)
438438
{
439439
/*
440-
* We set autovacuum_freeze_max_age to its maximum value so autovacuum
441-
* does not launch here and delete clog files, before the frozen xids are
442-
* set.
440+
* Before we restore anything, set frozenxids of initdb-created tables.
443441
*/
444-
445442
set_frozenxids(false);
446443

444+
/*
445+
* Now restore global objects (roles and tablespaces).
446+
*/
447447
prep_status("Restoring global objects in the new cluster");
448448

449449
/*
@@ -681,14 +681,25 @@ copy_clog_xlog_xid(void)
681681
/*
682682
* set_frozenxids()
683683
*
684-
* We have frozen all xids, so set datfrozenxid, relfrozenxid, and
685-
* relminmxid to be the old cluster's xid counter, which we just set
686-
* in the new cluster. User-table frozenxid and minmxid values will
687-
* be set by pg_dump --binary-upgrade, but objects not set by the pg_dump
688-
* must have proper frozen counters.
684+
* This is called on the new cluster before we restore anything, with
685+
* minmxid_only = false. Its purpose is to ensure that all initdb-created
686+
* vacuumable tables have relfrozenxid/relminmxid matching the old cluster's
687+
* xid/mxid counters. We also initialize the datfrozenxid/datminmxid of the
688+
* built-in databases to match.
689+
*
690+
* As we create user tables later, their relfrozenxid/relminmxid fields will
691+
* be restored properly by the binary-upgrade restore script. Likewise for
692+
* user-database datfrozenxid/datminmxid. However, if we're upgrading from a
693+
* pre-9.3 database, which does not store per-table or per-DB minmxid, then
694+
* the relminmxid/datminmxid values filled in by the restore script will just
695+
* be zeroes.
696+
*
697+
* Hence, with a pre-9.3 source database, a second call occurs after
698+
* everything is restored, with minmxid_only = true. This pass will
699+
* initialize all tables and databases, both those made by initdb and user
700+
* objects, with the desired minmxid value. frozenxid values are left alone.
689701
*/
690-
static
691-
void
702+
static void
692703
set_frozenxids(bool minmxid_only)
693704
{
694705
int dbnum;

src/bin/pg_dump/pg_dump.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13589,6 +13589,13 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
1358913589
* order. That also means we have to take care about setting
1359013590
* attislocal correctly, plus fix up any inherited CHECK constraints.
1359113591
* Analogously, we set up typed tables using ALTER TABLE / OF here.
13592+
*
13593+
* We process foreign tables here, even though they lack heap storage,
13594+
* because they can participate in inheritance relationships and we
13595+
* want this stuff to be consistent across the inheritance tree. We
13596+
* exclude indexes, toast tables, sequences and matviews, even though
13597+
* they have storage, because we don't support altering or dropping
13598+
* columns in them, nor can they be part of inheritance trees.
1359213599
*/
1359313600
if (binary_upgrade && (tbinfo->relkind == RELKIND_RELATION ||
1359413601
tbinfo->relkind == RELKIND_FOREIGN_TABLE))
@@ -13679,7 +13686,19 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
1367913686
fmtId(tbinfo->dobj.name),
1368013687
tbinfo->reloftype);
1368113688
}
13689+
}
1368213690

13691+
/*
13692+
* In binary_upgrade mode, arrange to restore the old relfrozenxid and
13693+
* relminmxid of all vacuumable relations. (While vacuum.c processes
13694+
* TOAST tables semi-independently, here we see them only as children
13695+
* of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
13696+
* child toast table is handled below.)
13697+
*/
13698+
if (binary_upgrade &&
13699+
(tbinfo->relkind == RELKIND_RELATION ||
13700+
tbinfo->relkind == RELKIND_MATVIEW))
13701+
{
1368313702
appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
1368413703
appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
1368513704
"SET relfrozenxid = '%u', relminmxid = '%u'\n"
@@ -13690,7 +13709,10 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
1369013709

1369113710
if (tbinfo->toast_oid)
1369213711
{
13693-
/* We preserve the toast oids, so we can use it during restore */
13712+
/*
13713+
* The toast table will have the same OID at restore, so we
13714+
* can safely target it by OID.
13715+
*/
1369413716
appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
1369513717
appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
1369613718
"SET relfrozenxid = '%u', relminmxid = '%u'\n"
@@ -13704,7 +13726,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
1370413726
* In binary_upgrade mode, restore matviews' populated status by
1370513727
* poking pg_class directly. This is pretty ugly, but we can't use
1370613728
* REFRESH MATERIALIZED VIEW since it's possible that some underlying
13707-
* matview is not populated even though this matview is.
13729+
* matview is not populated even though this matview is; in any case,
13730+
* we want to transfer the matview's heap storage, not run REFRESH.
1370813731
*/
1370913732
if (binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
1371013733
tbinfo->relispopulated)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy