diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 47f998f6ef..5ecd3c5725 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -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 diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index 0dfef0016f..04935ffd54 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -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. diff --git a/src/include/storage/sinval.h b/src/include/storage/sinval.h index 2105c63723..9f7bb2b2ee 100644 --- a/src/include/storage/sinval.h +++ b/src/include/storage/sinval.h @@ -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 */