/* * xactGetCommittedInvalidationMessages() is executed by * RecordTransactionCommit() to add invalidation messages onto the * commit record. This applies only to commit message types, never to * abort records. Must always run before AtEOXact_Inval(), since that * removes the data we need to see. * * Remember that this runs before we have officially committed, so we * must not do anything here to change what might occur *if* we should * fail between here and the actual commit. * * see also xact_redo_commit() and xact_desc_commit() */ int xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs, bool *RelcacheInitFileInval) { MemoryContext oldcontext; /* Quick exit if we haven't done anything with invalidation messages. */ if (transInvalInfo == NULL) { *RelcacheInitFileInval = false; *msgs = NULL; return 0; } /* Must be at top of stack */ Assert(transInvalInfo->my_level == 1 && transInvalInfo->parent == NULL); /* * Relcache init file invalidation requires processing both before and * after we send the SI messages. However, we need not do anything unless * we committed. */ *RelcacheInitFileInval = transInvalInfo->RelcacheInitFileInval; /* * Walk through TransInvalidationInfo to collect all the messages into a * single contiguous array of invalidation messages. It must be contiguous * so we can copy directly into WAL message. Maintain the order that they * would be processed in by AtEOXact_Inval(), to ensure emulated behaviour * in redo is as similar as possible to original. We want the same bugs, * if any, not new ones. */ oldcontext = MemoryContextSwitchTo(CurTransactionContext); ProcessInvalidationMessagesMulti(&transInvalInfo->CurrentCmdInvalidMsgs, MakeSharedInvalidMessagesArray); ProcessInvalidationMessagesMulti(&transInvalInfo->PriorCmdInvalidMsgs, MakeSharedInvalidMessagesArray); MemoryContextSwitchTo(oldcontext); Assert(!(numSharedInvalidMessagesArray > 0 && SharedInvalidMessagesArray == NULL)); *msgs = SharedInvalidMessagesArray; return numSharedInvalidMessagesArray; }
/* * 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; }
/* * 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) { if (isCommit) { /* Must be at top of stack */ Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL); /* * 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) RelationCacheInitFileInvalidate(true); AppendInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs, &transInvalInfo->CurrentCmdInvalidMsgs); ProcessInvalidationMessagesMulti(&transInvalInfo->PriorCmdInvalidMsgs, SendSharedInvalidMessages); if (transInvalInfo->RelcacheInitFileInval) RelationCacheInitFileInvalidate(false); } else if (transInvalInfo != NULL) { /* Must be at top of stack */ Assert(transInvalInfo->parent == NULL); ProcessInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs, LocalExecuteInvalidationMessage); } /* Need not free anything explicitly */ transInvalInfo = NULL; }