#include "postgres.h"#include "access/xact.h"#include "commands/async.h"#include "miscadmin.h"#include "storage/ipc.h"#include "storage/sinvaladt.h"#include "utils/inval.h"
Go to the source code of this file.
Defines | |
| #define | MAXINVALMSGS 32 |
Functions | |
| static void | ProcessCatchupEvent (void) |
| 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) |
Variables | |
| uint64 | SharedInvalidMessageCounter |
| static volatile int | catchupInterruptEnabled = 0 |
| static volatile int | catchupInterruptOccurred = 0 |
| #define MAXINVALMSGS 32 |
Referenced by ReceiveSharedInvalidMessages().
| 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;
}
}
| static void ProcessCatchupEvent | ( | void | ) | [static] |
Definition at line 303 of file sinval.c.
References AcceptInvalidationMessages(), CommitTransactionCommand(), DEBUG4, DisableNotifyInterrupt(), elog, EnableNotifyInterrupt(), IsTransactionOrTransactionBlock(), and StartTransactionCommand().
Referenced by EnableCatchupInterrupt(), and HandleCatchupInterrupt().
{
bool notify_enabled;
/* Must prevent notify interrupt while I am running */
notify_enabled = DisableNotifyInterrupt();
/*
* What we need to do here is cause ReceiveSharedInvalidMessages() to run,
* which will do the necessary work and also reset the
* catchupInterruptOccurred flag. If we are inside a transaction we can
* just call AcceptInvalidationMessages() to do this. If we aren't, we
* start and immediately end a transaction; the call to
* AcceptInvalidationMessages() happens down inside transaction start.
*
* It is awfully tempting to just call AcceptInvalidationMessages()
* without the rest of the xact start/stop overhead, and I think that
* would actually work in the normal case; but I am not sure that things
* would clean up nicely if we got an error partway through.
*/
if (IsTransactionOrTransactionBlock())
{
elog(DEBUG4, "ProcessCatchupEvent inside transaction");
AcceptInvalidationMessages();
}
else
{
elog(DEBUG4, "ProcessCatchupEvent outside transaction");
StartTransactionCommand();
CommitTransactionCommand();
}
if (notify_enabled)
EnableNotifyInterrupt();
}
| 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);
}
volatile int catchupInterruptEnabled = 0 [static] |
Definition at line 44 of file sinval.c.
Referenced by DisableCatchupInterrupt(), EnableCatchupInterrupt(), and HandleCatchupInterrupt().
volatile int catchupInterruptOccurred = 0 [static] |
Definition at line 45 of file sinval.c.
Referenced by EnableCatchupInterrupt(), HandleCatchupInterrupt(), and ReceiveSharedInvalidMessages().
| uint64 SharedInvalidMessageCounter |
Definition at line 25 of file sinval.c.
Referenced by get_object_address(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelidExtended(), and ReceiveSharedInvalidMessages().
1.7.1