#include "storage/relfilenode.h"
Go to the source code of this file.
Data Structures | |
struct | SharedInvalCatcacheMsg |
struct | SharedInvalCatalogMsg |
struct | SharedInvalRelcacheMsg |
struct | SharedInvalSmgrMsg |
struct | SharedInvalRelmapMsg |
union | SharedInvalidationMessage |
Defines | |
#define | SHAREDINVALCATALOG_ID (-1) |
#define | SHAREDINVALRELCACHE_ID (-2) |
#define | SHAREDINVALSMGR_ID (-3) |
#define | SHAREDINVALRELMAP_ID (-4) |
Functions | |
void | SendSharedInvalidMessages (const SharedInvalidationMessage *msgs, int n) |
void | ReceiveSharedInvalidMessages (void(*invalFunction)(SharedInvalidationMessage *msg), void(*resetFunction)(void)) |
void | HandleCatchupInterrupt (void) |
void | EnableCatchupInterrupt (void) |
bool | DisableCatchupInterrupt (void) |
int | xactGetCommittedInvalidationMessages (SharedInvalidationMessage **msgs, bool *RelcacheInitFileInval) |
void | ProcessCommittedInvalidationMessages (SharedInvalidationMessage *msgs, int nmsgs, bool RelcacheInitFileInval, Oid dbid, Oid tsid) |
Variables | |
uint64 | SharedInvalidMessageCounter |
#define SHAREDINVALCATALOG_ID (-1) |
Definition at line 64 of file sinval.h.
Referenced by LocalExecuteInvalidationMessage(), and xact_desc_commit().
#define SHAREDINVALRELCACHE_ID (-2) |
Definition at line 73 of file sinval.h.
Referenced by AddRelcacheInvalidationMessage(), LocalExecuteInvalidationMessage(), and xact_desc_commit().
#define SHAREDINVALRELMAP_ID (-4) |
Definition at line 93 of file sinval.h.
Referenced by LocalExecuteInvalidationMessage(), and xact_desc_commit().
#define SHAREDINVALSMGR_ID (-3) |
Definition at line 82 of file sinval.h.
Referenced by LocalExecuteInvalidationMessage(), and xact_desc_commit().
bool DisableCatchupInterrupt | ( | void | ) |
Definition at line 283 of file sinval.c.
References catchupInterruptEnabled.
Referenced by AutoVacLauncherMain(), client_read_ended(), die(), PostgresMain(), ProcessIncomingNotify(), ProcessInterrupts(), RecoveryConflictInterrupt(), and StatementCancelHandler().
{ bool result = (catchupInterruptEnabled != 0); catchupInterruptEnabled = 0; return result; }
void EnableCatchupInterrupt | ( | void | ) |
Definition at line 237 of file sinval.c.
References catchupInterruptEnabled, catchupInterruptOccurred, and ProcessCatchupEvent().
Referenced by AutoVacLauncherMain(), prepare_for_client_read(), and ProcessIncomingNotify().
{ /* * This code is tricky because we are communicating with a signal handler * that could interrupt us at any point. If we just checked * catchupInterruptOccurred and then set catchupInterruptEnabled, we could * fail to respond promptly to a signal that happens in between those two * steps. (A very small time window, perhaps, but Murphy's Law says you * can hit it...) Instead, we first set the enable flag, then test the * occurred flag. If we see an unserviced interrupt has occurred, we * re-clear the enable flag before going off to do the service work. (That * prevents re-entrant invocation of ProcessCatchupEvent() if another * interrupt occurs.) If an interrupt comes in between the setting and * clearing of catchupInterruptEnabled, then it will have done the service * work and left catchupInterruptOccurred zero, so we have to check again * after clearing enable. The whole thing has to be in a loop in case * another interrupt occurs while we're servicing the first. Once we get * out of the loop, enable is set and we know there is no unserviced * interrupt. * * NB: an overenthusiastic optimizing compiler could easily break this * code. Hopefully, they all understand what "volatile" means these days. */ for (;;) { catchupInterruptEnabled = 1; if (!catchupInterruptOccurred) break; catchupInterruptEnabled = 0; if (catchupInterruptOccurred) ProcessCatchupEvent(); } }
void HandleCatchupInterrupt | ( | void | ) |
Definition at line 166 of file sinval.c.
References catchupInterruptEnabled, catchupInterruptOccurred, CHECK_FOR_INTERRUPTS, ImmediateInterruptOK, proc_exit_inprogress, and ProcessCatchupEvent().
Referenced by procsignal_sigusr1_handler().
{ /* * Note: this is called by a SIGNAL HANDLER. You must be very wary what * you do here. */ /* Don't joggle the elbow of proc_exit */ if (proc_exit_inprogress) return; if (catchupInterruptEnabled) { bool save_ImmediateInterruptOK = ImmediateInterruptOK; /* * We may be called while ImmediateInterruptOK is true; turn it off * while messing with the catchup state. (We would have to save and * restore it anyway, because PGSemaphore operations inside * ProcessCatchupEvent() might reset it.) */ ImmediateInterruptOK = false; /* * I'm not sure whether some flavors of Unix might allow another * SIGUSR1 occurrence to recursively interrupt this routine. To cope * with the possibility, we do the same sort of dance that * EnableCatchupInterrupt must do --- see that routine for comments. */ catchupInterruptEnabled = 0; /* disable any recursive signal */ catchupInterruptOccurred = 1; /* do at least one iteration */ for (;;) { catchupInterruptEnabled = 1; if (!catchupInterruptOccurred) break; catchupInterruptEnabled = 0; if (catchupInterruptOccurred) { /* Here, it is finally safe to do stuff. */ ProcessCatchupEvent(); } } /* * Restore ImmediateInterruptOK, and check for interrupts if needed. */ ImmediateInterruptOK = save_ImmediateInterruptOK; if (save_ImmediateInterruptOK) CHECK_FOR_INTERRUPTS(); } else { /* * In this path it is NOT SAFE to do much of anything, except this: */ catchupInterruptOccurred = 1; } }
void ProcessCommittedInvalidationMessages | ( | SharedInvalidationMessage * | msgs, | |
int | nmsgs, | |||
bool | RelcacheInitFileInval, | |||
Oid | dbid, | |||
Oid | tsid | |||
) |
Definition at line 777 of file inval.c.
References DatabasePath, DEBUG4, elog, GetDatabasePath(), pfree(), RelationCacheInitFilePostInvalidate(), RelationCacheInitFilePreInvalidate(), SendSharedInvalidMessages(), and trace_recovery().
Referenced by xact_redo_commit_internal().
{ 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(); }
void ReceiveSharedInvalidMessages | ( | void(*)(SharedInvalidationMessage *msg) | invalFunction, | |
void(*)(void) | resetFunction | |||
) |
Definition at line 77 of file sinval.c.
References catchupInterruptOccurred, DEBUG4, elog, MAXINVALMSGS, SharedInvalidMessageCounter, SICleanupQueue(), and SIGetDataEntries().
Referenced by AcceptInvalidationMessages().
{ #define MAXINVALMSGS 32 static SharedInvalidationMessage messages[MAXINVALMSGS]; /* * We use volatile here to prevent bugs if a compiler doesn't realize that * recursion is a possibility ... */ static volatile int nextmsg = 0; static volatile int nummsgs = 0; /* Deal with any messages still pending from an outer recursion */ while (nextmsg < nummsgs) { SharedInvalidationMessage *msg = &messages[nextmsg++]; SharedInvalidMessageCounter++; invalFunction(msg); } do { int getResult; nextmsg = nummsgs = 0; /* Try to get some more messages */ getResult = SIGetDataEntries(messages, MAXINVALMSGS); if (getResult < 0) { /* got a reset message */ elog(DEBUG4, "cache state reset"); SharedInvalidMessageCounter++; resetFunction(); break; /* nothing more to do */ } /* Process them, being wary that a recursive call might eat some */ nextmsg = 0; nummsgs = getResult; while (nextmsg < nummsgs) { SharedInvalidationMessage *msg = &messages[nextmsg++]; SharedInvalidMessageCounter++; invalFunction(msg); } /* * We only need to loop if the last SIGetDataEntries call (which might * have been within a recursive call) returned a full buffer. */ } while (nummsgs == MAXINVALMSGS); /* * We are now caught up. If we received a catchup signal, reset that * flag, and call SICleanupQueue(). This is not so much because we need * to flush dead messages right now, as that we want to pass on the * catchup signal to the next slowest backend. "Daisy chaining" the * catchup signal this way avoids creating spikes in system load for what * should be just a background maintenance activity. */ if (catchupInterruptOccurred) { catchupInterruptOccurred = 0; elog(DEBUG4, "sinval catchup complete, cleaning queue"); SICleanupQueue(false, 0); } }
void SendSharedInvalidMessages | ( | const SharedInvalidationMessage * | msgs, | |
int | n | |||
) |
Definition at line 55 of file sinval.c.
References SIInsertDataEntries().
Referenced by AtEOXact_Inval(), CacheInvalidateRelmap(), CacheInvalidateSmgr(), FinishPreparedTransaction(), and ProcessCommittedInvalidationMessages().
{ SIInsertDataEntries(msgs, n); }
int xactGetCommittedInvalidationMessages | ( | SharedInvalidationMessage ** | msgs, | |
bool * | RelcacheInitFileInval | |||
) |
Definition at line 730 of file inval.c.
References Assert, TransInvalidationInfo::CurrentCmdInvalidMsgs, CurTransactionContext, MakeSharedInvalidMessagesArray(), MemoryContextSwitchTo(), NULL, numSharedInvalidMessagesArray, TransInvalidationInfo::parent, TransInvalidationInfo::PriorCmdInvalidMsgs, ProcessInvalidationMessagesMulti(), and TransInvalidationInfo::RelcacheInitFileInval.
Referenced by RecordTransactionCommit(), and StartPrepare().
{ MemoryContext oldcontext; /* 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. */ *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; }
uint64 SharedInvalidMessageCounter |
Definition at line 25 of file sinval.c.
Referenced by get_object_address(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelidExtended(), and ReceiveSharedInvalidMessages().