#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().
1.7.1