mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
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.
This commit is contained in:
parent
510f3502eb
commit
42edbd16fb
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.279 2010/01/02 16:57:35 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.280 2010/01/09 16:49:27 sriggs Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -4404,20 +4404,8 @@ xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid, XLogRecPtr lsn)
|
||||
* maintain the same order of invalidation then release locks
|
||||
* as occurs in .
|
||||
*/
|
||||
if (xlrec->nmsgs > 0)
|
||||
{
|
||||
/*
|
||||
* Relcache init file invalidation requires processing both
|
||||
* before and after we send the SI messages. See AtEOXact_Inval()
|
||||
*/
|
||||
if (XactCompletionRelcacheInitFileInval(xlrec))
|
||||
RelationCacheInitFileInvalidate(true);
|
||||
|
||||
SendSharedInvalidMessages(inval_msgs, xlrec->nmsgs);
|
||||
|
||||
if (XactCompletionRelcacheInitFileInval(xlrec))
|
||||
RelationCacheInitFileInvalidate(false);
|
||||
}
|
||||
ProcessCommittedInvalidationMessages(inval_msgs, xlrec->nmsgs,
|
||||
XactCompletionRelcacheInitFileInval(xlrec));
|
||||
|
||||
/*
|
||||
* Release locks, if any. We do this for both two phase and normal
|
||||
|
108
src/backend/utils/cache/inval.c
vendored
108
src/backend/utils/cache/inval.c
vendored
@ -80,7 +80,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.91 2010/01/02 16:57:55 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.92 2010/01/09 16:49:27 sriggs Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -89,6 +89,7 @@
|
||||
#include "access/twophase_rmgr.h"
|
||||
#include "access/xact.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/pg_tablespace.h"
|
||||
#include "miscadmin.h"
|
||||
#include "storage/sinval.h"
|
||||
#include "storage/smgr.h"
|
||||
@ -871,6 +872,111 @@ xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
|
||||
return numSharedInvalidMessagesArray;
|
||||
}
|
||||
|
||||
#define RecoveryRelationCacheInitFileInvalidate(dbo, tbo, tf) \
|
||||
{ \
|
||||
DatabasePath = GetDatabasePath(dbo, tbo); \
|
||||
elog(trace_recovery(DEBUG4), "removing relcache init file in %s", DatabasePath); \
|
||||
RelationCacheInitFileInvalidate(tf); \
|
||||
pfree(DatabasePath); \
|
||||
}
|
||||
|
||||
/*
|
||||
* ProcessCommittedInvalidationMessages is executed by xact_redo_commit()
|
||||
* to process invalidation messages added to commit records.
|
||||
*
|
||||
* If we have to invalidate the relcache init file we need to extract
|
||||
* the database id from each message so we can correctly locate the database
|
||||
* path and so remove that database's init file. We note that the relcache
|
||||
* only contains entries for catalog tables from a single database, or
|
||||
* shared relations. There are smgr invalidations that reference other
|
||||
* databases but they never cause relcache file invalidations.
|
||||
* So we only need to access either global or default tablespaces and
|
||||
* never have need to scan pg_database to discover tablespace oids.
|
||||
*
|
||||
* Relcache init file invalidation requires processing both
|
||||
* before and after we send the SI messages. See AtEOXact_Inval()
|
||||
*
|
||||
* We deliberately avoid SetDatabasePath() since it is intended to be used
|
||||
* only once by normal backends, so we set DatabasePath directly then
|
||||
* pfree after use. See RecoveryRelationCacheInitFileInvalidate() macro.
|
||||
*/
|
||||
void
|
||||
ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
|
||||
int nmsgs, bool RelcacheInitFileInval)
|
||||
{
|
||||
Oid dboid = 0;
|
||||
bool invalidate_global = false;
|
||||
|
||||
if (nmsgs > 0)
|
||||
elog(trace_recovery(DEBUG4), "replaying commit with %d messages%s", nmsgs,
|
||||
(RelcacheInitFileInval ? " and relcache file invalidation" : ""));
|
||||
else
|
||||
return;
|
||||
|
||||
if (RelcacheInitFileInval)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Check messages to record dboid
|
||||
*/
|
||||
for (i = 0; i < nmsgs; i++)
|
||||
{
|
||||
SharedInvalidationMessage *inval_msg = &(msgs[i]);
|
||||
Oid loop_dboid = 0;
|
||||
|
||||
/*
|
||||
* Extract the database Oid from the message
|
||||
*/
|
||||
if (inval_msg->id >= 0)
|
||||
loop_dboid = inval_msg->cc.dbId;
|
||||
else if (inval_msg->id == SHAREDINVALRELCACHE_ID)
|
||||
loop_dboid = inval_msg->rc.dbId;
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Invalidation message is a SHAREDINVALSMGR_ID
|
||||
* which never cause relcache file invalidation,
|
||||
* so we ignore them, no matter which db they're for.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if (loop_dboid == 0)
|
||||
invalidate_global = true;
|
||||
else
|
||||
{
|
||||
Assert(dboid == 0 || dboid == loop_dboid);
|
||||
dboid = loop_dboid;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If shared, dboid will be the global tablespace, otherwise it will
|
||||
* be a local catalog relation in the default tablespace.
|
||||
*/
|
||||
if (invalidate_global)
|
||||
RecoveryRelationCacheInitFileInvalidate(0, GLOBALTABLESPACE_OID, true);
|
||||
|
||||
if (dboid != 0)
|
||||
RecoveryRelationCacheInitFileInvalidate(dboid, DEFAULTTABLESPACE_OID, true);
|
||||
}
|
||||
|
||||
SendSharedInvalidMessages(msgs, nmsgs);
|
||||
|
||||
if (RelcacheInitFileInval)
|
||||
{
|
||||
/*
|
||||
* Second invalidation, very similar to above. See RelationCacheInitFileInvalidate()
|
||||
*/
|
||||
if (invalidate_global)
|
||||
RecoveryRelationCacheInitFileInvalidate(0, GLOBALTABLESPACE_OID, false);
|
||||
|
||||
if (dboid != 0)
|
||||
RecoveryRelationCacheInitFileInvalidate(dboid, DEFAULTTABLESPACE_OID, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* AtEOXact_Inval
|
||||
* Process queued-up invalidation messages at end of main transaction.
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.55 2010/01/02 16:58:08 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.56 2010/01/09 16:49:27 sriggs Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -102,5 +102,7 @@ extern bool DisableCatchupInterrupt(void);
|
||||
|
||||
extern int xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
|
||||
bool *RelcacheInitFileInval);
|
||||
extern void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
|
||||
int nmsgs, bool RelcacheInitFileInval);
|
||||
|
||||
#endif /* SINVAL_H */
|
||||
|
Loading…
Reference in New Issue
Block a user