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

Commit 76d5667

Browse files
committed
Fix recently-identified PITR recovery hazard: the base backup could contain
stale relcache init files (pg_internal.init), and there is no mechanism for updating them during WAL replay. Easiest solution is just to delete the init files at conclusion of startup, and let the first backend started in each database take care of rebuilding the init file. Simon Riggs and Tom Lane. Back-patched to 8.1. Arguably this should be fixed in 8.0 too, but it would require significantly more code since 8.0 has no handy startup-time scan of pg_database to piggyback on. Manual solution of the problem is possible in 8.0 (just delete the pg_internal.init files before starting WAL replay), so that may be a sufficient answer.
1 parent 48188e1 commit 76d5667

File tree

3 files changed

+50
-6
lines changed

3 files changed

+50
-6
lines changed

src/backend/utils/cache/relcache.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.249 2006/10/04 00:30:00 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.250 2006/11/05 23:40:30 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -3586,3 +3586,25 @@ RelationCacheInitFileInvalidate(bool beforeSend)
35863586
LWLockRelease(RelCacheInitLock);
35873587
}
35883588
}
3589+
3590+
/*
3591+
* Remove the init file for a given database during postmaster startup.
3592+
*
3593+
* We used to keep the init file across restarts, but that is unsafe in PITR
3594+
* scenarios, and even in simple crash-recovery cases there are windows for
3595+
* the init file to become out-of-sync with the database. So now we just
3596+
* remove it during startup and expect the first backend launch to rebuild it.
3597+
* Of course, this has to happen in each database of the cluster. For
3598+
* simplicity this is driven by flatfiles.c, which has to scan pg_database
3599+
* anyway.
3600+
*/
3601+
void
3602+
RelationCacheInitFileRemove(const char *dbPath)
3603+
{
3604+
char initfilename[MAXPGPATH];
3605+
3606+
snprintf(initfilename, sizeof(initfilename), "%s/%s",
3607+
dbPath, RELCACHE_INIT_FILENAME);
3608+
unlink(initfilename);
3609+
/* ignore any error, since it might not be there at all */
3610+
}

src/backend/utils/init/flatfiles.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
2424
* Portions Copyright (c) 1994, Regents of the University of California
2525
*
26-
* $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.22 2006/11/05 22:42:09 tgl Exp $
26+
* $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.23 2006/11/05 23:40:31 tgl Exp $
2727
*
2828
*-------------------------------------------------------------------------
2929
*/
@@ -36,6 +36,7 @@
3636
#include "access/transam.h"
3737
#include "access/twophase_rmgr.h"
3838
#include "access/xact.h"
39+
#include "catalog/catalog.h"
3940
#include "catalog/pg_auth_members.h"
4041
#include "catalog/pg_authid.h"
4142
#include "catalog/pg_database.h"
@@ -47,6 +48,7 @@
4748
#include "storage/pmsignal.h"
4849
#include "utils/builtins.h"
4950
#include "utils/flatfiles.h"
51+
#include "utils/relcache.h"
5052
#include "utils/resowner.h"
5153

5254

@@ -165,9 +167,14 @@ name_okay(const char *str)
165167
*
166168
* A side effect is to determine the oldest database's datfrozenxid
167169
* so we can set or update the XID wrap limit.
170+
*
171+
* Also, if "startup" is true, we tell relcache.c to clear out the relcache
172+
* init file in each database. That's a bit nonmodular, but scanning
173+
* pg_database twice during system startup seems too high a price for keeping
174+
* things better separated.
168175
*/
169176
static void
170-
write_database_file(Relation drel)
177+
write_database_file(Relation drel, bool startup)
171178
{
172179
char *filename,
173180
*tempname;
@@ -248,6 +255,17 @@ write_database_file(Relation drel)
248255
fputs_quote(datname, fp);
249256
fprintf(fp, " %u %u %u\n",
250257
datoid, dattablespace, datfrozenxid);
258+
259+
/*
260+
* Also clear relcache init file for each DB if starting up.
261+
*/
262+
if (startup)
263+
{
264+
char *dbpath = GetDatabasePath(datoid, dattablespace);
265+
266+
RelationCacheInitFileRemove(dbpath);
267+
pfree(dbpath);
268+
}
251269
}
252270
heap_endscan(scan);
253271

@@ -669,6 +687,9 @@ write_auth_file(Relation rel_authid, Relation rel_authmem)
669687
* policy means we need not force initdb to change the format of the
670688
* flat files.
671689
*
690+
* We also cause relcache init files to be flushed, for largely the same
691+
* reasons.
692+
*
672693
* In a standalone backend we pass database_only = true to skip processing
673694
* the auth file. We won't need it, and building it could fail if there's
674695
* something corrupt in the authid/authmem catalogs.
@@ -699,7 +720,7 @@ BuildFlatFiles(bool database_only)
699720

700721
/* No locking is needed because no one else is alive yet */
701722
rel_db = XLogOpenRelation(rnode);
702-
write_database_file(rel_db);
723+
write_database_file(rel_db, true);
703724

704725
if (!database_only)
705726
{
@@ -811,7 +832,7 @@ AtEOXact_UpdateFlatFiles(bool isCommit)
811832
if (database_file_update_subid != InvalidSubTransactionId)
812833
{
813834
database_file_update_subid = InvalidSubTransactionId;
814-
write_database_file(drel);
835+
write_database_file(drel, false);
815836
heap_close(drel, NoLock);
816837
}
817838

src/include/utils/relcache.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/utils/relcache.h,v 1.55 2006/07/31 20:09:10 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/utils/relcache.h,v 1.56 2006/11/05 23:40:31 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -69,6 +69,7 @@ extern void AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid,
6969
*/
7070
extern bool RelationIdIsInInitFile(Oid relationId);
7171
extern void RelationCacheInitFileInvalidate(bool beforeSend);
72+
extern void RelationCacheInitFileRemove(const char *dbPath);
7273

7374
/* should be used only by relcache.c and catcache.c */
7475
extern bool criticalRelcachesBuilt;

0 commit comments

Comments
 (0)