Skip to content

Commit 42edbd1

Browse files
During Hot Standby, set DatabasePath correctly during relcache init file
deletion, so that we attempt to unlink the correct filepath. unlink() errors are ignorable there, so lack of a DatabasePath initialization step did not cause visible problems until a related bug showed up on Solaris. Code refactored from xact_redo_commit() to ProcessCommittedInvalidationMessages() in inval.c. Recovery may replay shared invalidation messages for many databases, so we cannot SetDatabasePath() once as we do in normal backends. Read the databaseid from the shared invalidation messages, then set DatabasePath temporarily before calling RelationCacheInitFileInvalidate(). Problem report by Robert Treat, analysis and fix by me.
1 parent 510f350 commit 42edbd1

File tree

3 files changed

+113
-17
lines changed

3 files changed

+113
-17
lines changed

src/backend/access/transam/xact.c

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.279 2010/01/02 16:57:35 momjian Exp $
13+
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.280 2010/01/09 16:49:27 sriggs Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -4404,20 +4404,8 @@ xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid, XLogRecPtr lsn)
44044404
* maintain the same order of invalidation then release locks
44054405
* as occurs in .
44064406
*/
4407-
if (xlrec->nmsgs > 0)
4408-
{
4409-
/*
4410-
* Relcache init file invalidation requires processing both
4411-
* before and after we send the SI messages. See AtEOXact_Inval()
4412-
*/
4413-
if (XactCompletionRelcacheInitFileInval(xlrec))
4414-
RelationCacheInitFileInvalidate(true);
4415-
4416-
SendSharedInvalidMessages(inval_msgs, xlrec->nmsgs);
4417-
4418-
if (XactCompletionRelcacheInitFileInval(xlrec))
4419-
RelationCacheInitFileInvalidate(false);
4420-
}
4407+
ProcessCommittedInvalidationMessages(inval_msgs, xlrec->nmsgs,
4408+
XactCompletionRelcacheInitFileInval(xlrec));
44214409

44224410
/*
44234411
* Release locks, if any. We do this for both two phase and normal

src/backend/utils/cache/inval.c

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
* Portions Copyright (c) 1994, Regents of the University of California
8181
*
8282
* IDENTIFICATION
83-
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.91 2010/01/02 16:57:55 momjian Exp $
83+
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.92 2010/01/09 16:49:27 sriggs Exp $
8484
*
8585
*-------------------------------------------------------------------------
8686
*/
@@ -89,6 +89,7 @@
8989
#include "access/twophase_rmgr.h"
9090
#include "access/xact.h"
9191
#include "catalog/catalog.h"
92+
#include "catalog/pg_tablespace.h"
9293
#include "miscadmin.h"
9394
#include "storage/sinval.h"
9495
#include "storage/smgr.h"
@@ -871,6 +872,111 @@ xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
871872
return numSharedInvalidMessagesArray;
872873
}
873874

875+
#define RecoveryRelationCacheInitFileInvalidate(dbo, tbo, tf) \
876+
{ \
877+
DatabasePath = GetDatabasePath(dbo, tbo); \
878+
elog(trace_recovery(DEBUG4), "removing relcache init file in %s", DatabasePath); \
879+
RelationCacheInitFileInvalidate(tf); \
880+
pfree(DatabasePath); \
881+
}
882+
883+
/*
884+
* ProcessCommittedInvalidationMessages is executed by xact_redo_commit()
885+
* to process invalidation messages added to commit records.
886+
*
887+
* If we have to invalidate the relcache init file we need to extract
888+
* the database id from each message so we can correctly locate the database
889+
* path and so remove that database's init file. We note that the relcache
890+
* only contains entries for catalog tables from a single database, or
891+
* shared relations. There are smgr invalidations that reference other
892+
* databases but they never cause relcache file invalidations.
893+
* So we only need to access either global or default tablespaces and
894+
* never have need to scan pg_database to discover tablespace oids.
895+
*
896+
* Relcache init file invalidation requires processing both
897+
* before and after we send the SI messages. See AtEOXact_Inval()
898+
*
899+
* We deliberately avoid SetDatabasePath() since it is intended to be used
900+
* only once by normal backends, so we set DatabasePath directly then
901+
* pfree after use. See RecoveryRelationCacheInitFileInvalidate() macro.
902+
*/
903+
void
904+
ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
905+
int nmsgs, bool RelcacheInitFileInval)
906+
{
907+
Oid dboid = 0;
908+
bool invalidate_global = false;
909+
910+
if (nmsgs > 0)
911+
elog(trace_recovery(DEBUG4), "replaying commit with %d messages%s", nmsgs,
912+
(RelcacheInitFileInval ? " and relcache file invalidation" : ""));
913+
else
914+
return;
915+
916+
if (RelcacheInitFileInval)
917+
{
918+
int i;
919+
920+
/*
921+
* Check messages to record dboid
922+
*/
923+
for (i = 0; i < nmsgs; i++)
924+
{
925+
SharedInvalidationMessage *inval_msg = &(msgs[i]);
926+
Oid loop_dboid = 0;
927+
928+
/*
929+
* Extract the database Oid from the message
930+
*/
931+
if (inval_msg->id >= 0)
932+
loop_dboid = inval_msg->cc.dbId;
933+
else if (inval_msg->id == SHAREDINVALRELCACHE_ID)
934+
loop_dboid = inval_msg->rc.dbId;
935+
else
936+
{
937+
/*
938+
* Invalidation message is a SHAREDINVALSMGR_ID
939+
* which never cause relcache file invalidation,
940+
* so we ignore them, no matter which db they're for.
941+
*/
942+
continue;
943+
}
944+
945+
if (loop_dboid == 0)
946+
invalidate_global = true;
947+
else
948+
{
949+
Assert(dboid == 0 || dboid == loop_dboid);
950+
dboid = loop_dboid;
951+
}
952+
}
953+
954+
/*
955+
* If shared, dboid will be the global tablespace, otherwise it will
956+
* be a local catalog relation in the default tablespace.
957+
*/
958+
if (invalidate_global)
959+
RecoveryRelationCacheInitFileInvalidate(0, GLOBALTABLESPACE_OID, true);
960+
961+
if (dboid != 0)
962+
RecoveryRelationCacheInitFileInvalidate(dboid, DEFAULTTABLESPACE_OID, true);
963+
}
964+
965+
SendSharedInvalidMessages(msgs, nmsgs);
966+
967+
if (RelcacheInitFileInval)
968+
{
969+
/*
970+
* Second invalidation, very similar to above. See RelationCacheInitFileInvalidate()
971+
*/
972+
if (invalidate_global)
973+
RecoveryRelationCacheInitFileInvalidate(0, GLOBALTABLESPACE_OID, false);
974+
975+
if (dboid != 0)
976+
RecoveryRelationCacheInitFileInvalidate(dboid, DEFAULTTABLESPACE_OID, false);
977+
}
978+
}
979+
874980
/*
875981
* AtEOXact_Inval
876982
* Process queued-up invalidation messages at end of main transaction.

src/include/storage/sinval.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.55 2010/01/02 16:58:08 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.56 2010/01/09 16:49:27 sriggs Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -102,5 +102,7 @@ extern bool DisableCatchupInterrupt(void);
102102

103103
extern int xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
104104
bool *RelcacheInitFileInval);
105+
extern void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
106+
int nmsgs, bool RelcacheInitFileInval);
105107

106108
#endif /* SINVAL_H */

0 commit comments

Comments
 (0)