On Fri, 2010-01-08 at 01:26 +0000, Simon Riggs wrote:
> I'll test and commit tomorrow, since it's a fairly standalone problem

Fix attached, thanks for testing.

Works for me and I don't expect it to fail on Solaris, since the root
cause of the failure has been addressed and a correctly designed test
executed.

I will wait a day for your confirmation and/or other's comments.

-- 
 Simon Riggs           www.2ndQuadrant.com
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
***************
*** 4404,4423 **** 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);
! 		}
  
  		/*
  		 * Release locks, if any. We do this for both two phase and normal
--- 4404,4411 ----
  		 * maintain the same order of invalidation then release locks
  		 * as occurs in 	.
  		 */
! 		ProcessCommittedInvalidationMessages(inval_msgs, xlrec->nmsgs,
! 									XactCompletionRelcacheInitFileInval(xlrec));
  
  		/*
  		 * Release locks, if any. We do this for both two phase and normal
*** a/src/backend/utils/cache/inval.c
--- b/src/backend/utils/cache/inval.c
***************
*** 89,94 ****
--- 89,95 ----
  #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,876 **** xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
--- 872,981 ----
  	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 need not scan pg_database to discover tablespace oids, since
+  * we only have either global or default tablespaces. Just lucky, I guess.
+  *
+  * 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 just use DatabasePath directly and
+  * immediately pfree after use.
+  */
+ 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, whichever database they're for.
+ 				 */
+ 			}
+ 
+ 			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 shared 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.
+ 		 */
+ 		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.
*** a/src/include/storage/sinval.h
--- b/src/include/storage/sinval.h
***************
*** 102,106 **** extern bool DisableCatchupInterrupt(void);
--- 102,108 ----
  
  extern int xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
  										bool *RelcacheInitFileInval);
+ extern void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
+ 										int nmsgs, bool RelcacheInitFileInval);
  
  #endif   /* SINVAL_H */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to