Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Functions | Variables

sinval.h File Reference

#include "storage/relfilenode.h"
Include dependency graph for sinval.h:
This graph shows which files directly or indirectly include this file:

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 Documentation

#define SHAREDINVALCATALOG_ID   (-1)

Definition at line 64 of file sinval.h.

Referenced by LocalExecuteInvalidationMessage(), and xact_desc_commit().

#define SHAREDINVALRELCACHE_ID   (-2)
#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().


Function Documentation

bool DisableCatchupInterrupt ( void   ) 
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 
)
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;
}


Variable Documentation