/* * ProcessCommittedInvalidationMessages is executed by xact_redo_commit() * to process invalidation messages added to commit records. * * Relcache init file invalidation requires processing both * before and after we send the SI messages. See AtEOXact_Inval() */ void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs, int nmsgs, bool RelcacheInitFileInval, Oid dbid, Oid tsid) { if (nmsgs <= 0) return; elog(trace_recovery(DEBUG4), "replaying commit with %d messages%s", nmsgs, (RelcacheInitFileInval ? " and relcache file invalidation" : "")); if (RelcacheInitFileInval) { /* * RelationCacheInitFilePreInvalidate requires DatabasePath to be set, * but we should not use SetDatabasePath during recovery, since it is * intended to be used only once by normal backends. Hence, a quick * hack: set DatabasePath directly then unset after use. */ DatabasePath = GetDatabasePath(dbid, tsid); elog(trace_recovery(DEBUG4), "removing relcache init file in \"%s\"", DatabasePath); RelationCacheInitFilePreInvalidate(); pfree(DatabasePath); DatabasePath = NULL; } SendSharedInvalidMessages(msgs, nmsgs); if (RelcacheInitFileInval) RelationCacheInitFilePostInvalidate(); }
/* * AtEOXact_Inval * Process queued-up invalidation messages at end of main transaction. * * If isCommit, we must send out the messages in our PriorCmdInvalidMsgs list * to the shared invalidation message queue. Note that these will be read * not only by other backends, but also by our own backend at the next * transaction start (via AcceptInvalidationMessages). This means that * we can skip immediate local processing of anything that's still in * CurrentCmdInvalidMsgs, and just send that list out too. * * If not isCommit, we are aborting, and must locally process the messages * in PriorCmdInvalidMsgs. No messages need be sent to other backends, * since they'll not have seen our changed tuples anyway. We can forget * about CurrentCmdInvalidMsgs too, since those changes haven't touched * the caches yet. * * In any case, reset the various lists to empty. We need not physically * free memory here, since TopTransactionContext is about to be emptied * anyway. * * Note: * This should be called as the last step in processing a transaction. */ void AtEOXact_Inval(bool isCommit) { /* Quick exit if no messages */ if (transInvalInfo == NULL) return; /* Must be at top of stack */ Assert(transInvalInfo->my_level == 1 && transInvalInfo->parent == NULL); if (isCommit) { /* * Relcache init file invalidation requires processing both before and * after we send the SI messages. However, we need not do anything * unless we committed. */ if (transInvalInfo->RelcacheInitFileInval) RelationCacheInitFilePreInvalidate(); AppendInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs, &transInvalInfo->CurrentCmdInvalidMsgs); ProcessInvalidationMessagesMulti(&transInvalInfo->PriorCmdInvalidMsgs, SendSharedInvalidMessages); if (transInvalInfo->RelcacheInitFileInval) RelationCacheInitFilePostInvalidate(); } else { ProcessInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs, LocalExecuteInvalidationMessage); } /* Need not free anything explicitly */ transInvalInfo = NULL; SharedInvalidMessagesArray = NULL; numSharedInvalidMessagesArray = 0; }
/* * inval_twophase_postcommit * Process an invalidation message from the 2PC state file. */ void inval_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len) { SharedInvalidationMessage *msg; switch (info) { case TWOPHASE_INFO_MSG: msg = (SharedInvalidationMessage *) recdata; Assert(len == sizeof(SharedInvalidationMessage)); SendSharedInvalidMessage(msg); break; case TWOPHASE_INFO_FILE_BEFORE: RelationCacheInitFilePreInvalidate(); break; case TWOPHASE_INFO_FILE_AFTER: RelationCacheInitFilePostInvalidate(); break; default: Assert(false); break; } }