Header And Logo

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

sinval.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * sinval.c
00004  *    POSTGRES shared cache invalidation communication code.
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/storage/ipc/sinval.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include "access/xact.h"
00018 #include "commands/async.h"
00019 #include "miscadmin.h"
00020 #include "storage/ipc.h"
00021 #include "storage/sinvaladt.h"
00022 #include "utils/inval.h"
00023 
00024 
00025 uint64      SharedInvalidMessageCounter;
00026 
00027 
00028 /*
00029  * Because backends sitting idle will not be reading sinval events, we
00030  * need a way to give an idle backend a swift kick in the rear and make
00031  * it catch up before the sinval queue overflows and forces it to go
00032  * through a cache reset exercise.  This is done by sending
00033  * PROCSIG_CATCHUP_INTERRUPT to any backend that gets too far behind.
00034  *
00035  * State for catchup events consists of two flags: one saying whether
00036  * the signal handler is currently allowed to call ProcessCatchupEvent
00037  * directly, and one saying whether the signal has occurred but the handler
00038  * was not allowed to call ProcessCatchupEvent at the time.
00039  *
00040  * NB: the "volatile" on these declarations is critical!  If your compiler
00041  * does not grok "volatile", you'd be best advised to compile this file
00042  * with all optimization turned off.
00043  */
00044 static volatile int catchupInterruptEnabled = 0;
00045 static volatile int catchupInterruptOccurred = 0;
00046 
00047 static void ProcessCatchupEvent(void);
00048 
00049 
00050 /*
00051  * SendSharedInvalidMessages
00052  *  Add shared-cache-invalidation message(s) to the global SI message queue.
00053  */
00054 void
00055 SendSharedInvalidMessages(const SharedInvalidationMessage *msgs, int n)
00056 {
00057     SIInsertDataEntries(msgs, n);
00058 }
00059 
00060 /*
00061  * ReceiveSharedInvalidMessages
00062  *      Process shared-cache-invalidation messages waiting for this backend
00063  *
00064  * We guarantee to process all messages that had been queued before the
00065  * routine was entered.  It is of course possible for more messages to get
00066  * queued right after our last SIGetDataEntries call.
00067  *
00068  * NOTE: it is entirely possible for this routine to be invoked recursively
00069  * as a consequence of processing inside the invalFunction or resetFunction.
00070  * Furthermore, such a recursive call must guarantee that all outstanding
00071  * inval messages have been processed before it exits.  This is the reason
00072  * for the strange-looking choice to use a statically allocated buffer array
00073  * and counters; it's so that a recursive call can process messages already
00074  * sucked out of sinvaladt.c.
00075  */
00076 void
00077 ReceiveSharedInvalidMessages(
00078                       void (*invalFunction) (SharedInvalidationMessage *msg),
00079                              void (*resetFunction) (void))
00080 {
00081 #define MAXINVALMSGS 32
00082     static SharedInvalidationMessage messages[MAXINVALMSGS];
00083 
00084     /*
00085      * We use volatile here to prevent bugs if a compiler doesn't realize that
00086      * recursion is a possibility ...
00087      */
00088     static volatile int nextmsg = 0;
00089     static volatile int nummsgs = 0;
00090 
00091     /* Deal with any messages still pending from an outer recursion */
00092     while (nextmsg < nummsgs)
00093     {
00094         SharedInvalidationMessage *msg = &messages[nextmsg++];
00095 
00096         SharedInvalidMessageCounter++;
00097         invalFunction(msg);
00098     }
00099 
00100     do
00101     {
00102         int         getResult;
00103 
00104         nextmsg = nummsgs = 0;
00105 
00106         /* Try to get some more messages */
00107         getResult = SIGetDataEntries(messages, MAXINVALMSGS);
00108 
00109         if (getResult < 0)
00110         {
00111             /* got a reset message */
00112             elog(DEBUG4, "cache state reset");
00113             SharedInvalidMessageCounter++;
00114             resetFunction();
00115             break;              /* nothing more to do */
00116         }
00117 
00118         /* Process them, being wary that a recursive call might eat some */
00119         nextmsg = 0;
00120         nummsgs = getResult;
00121 
00122         while (nextmsg < nummsgs)
00123         {
00124             SharedInvalidationMessage *msg = &messages[nextmsg++];
00125 
00126             SharedInvalidMessageCounter++;
00127             invalFunction(msg);
00128         }
00129 
00130         /*
00131          * We only need to loop if the last SIGetDataEntries call (which might
00132          * have been within a recursive call) returned a full buffer.
00133          */
00134     } while (nummsgs == MAXINVALMSGS);
00135 
00136     /*
00137      * We are now caught up.  If we received a catchup signal, reset that
00138      * flag, and call SICleanupQueue().  This is not so much because we need
00139      * to flush dead messages right now, as that we want to pass on the
00140      * catchup signal to the next slowest backend.  "Daisy chaining" the
00141      * catchup signal this way avoids creating spikes in system load for what
00142      * should be just a background maintenance activity.
00143      */
00144     if (catchupInterruptOccurred)
00145     {
00146         catchupInterruptOccurred = 0;
00147         elog(DEBUG4, "sinval catchup complete, cleaning queue");
00148         SICleanupQueue(false, 0);
00149     }
00150 }
00151 
00152 
00153 /*
00154  * HandleCatchupInterrupt
00155  *
00156  * This is called when PROCSIG_CATCHUP_INTERRUPT is received.
00157  *
00158  * If we are idle (catchupInterruptEnabled is set), we can safely
00159  * invoke ProcessCatchupEvent directly.  Otherwise, just set a flag
00160  * to do it later.  (Note that it's quite possible for normal processing
00161  * of the current transaction to cause ReceiveSharedInvalidMessages()
00162  * to be run later on; in that case the flag will get cleared again,
00163  * since there's no longer any reason to do anything.)
00164  */
00165 void
00166 HandleCatchupInterrupt(void)
00167 {
00168     /*
00169      * Note: this is called by a SIGNAL HANDLER. You must be very wary what
00170      * you do here.
00171      */
00172 
00173     /* Don't joggle the elbow of proc_exit */
00174     if (proc_exit_inprogress)
00175         return;
00176 
00177     if (catchupInterruptEnabled)
00178     {
00179         bool        save_ImmediateInterruptOK = ImmediateInterruptOK;
00180 
00181         /*
00182          * We may be called while ImmediateInterruptOK is true; turn it off
00183          * while messing with the catchup state.  (We would have to save and
00184          * restore it anyway, because PGSemaphore operations inside
00185          * ProcessCatchupEvent() might reset it.)
00186          */
00187         ImmediateInterruptOK = false;
00188 
00189         /*
00190          * I'm not sure whether some flavors of Unix might allow another
00191          * SIGUSR1 occurrence to recursively interrupt this routine. To cope
00192          * with the possibility, we do the same sort of dance that
00193          * EnableCatchupInterrupt must do --- see that routine for comments.
00194          */
00195         catchupInterruptEnabled = 0;    /* disable any recursive signal */
00196         catchupInterruptOccurred = 1;   /* do at least one iteration */
00197         for (;;)
00198         {
00199             catchupInterruptEnabled = 1;
00200             if (!catchupInterruptOccurred)
00201                 break;
00202             catchupInterruptEnabled = 0;
00203             if (catchupInterruptOccurred)
00204             {
00205                 /* Here, it is finally safe to do stuff. */
00206                 ProcessCatchupEvent();
00207             }
00208         }
00209 
00210         /*
00211          * Restore ImmediateInterruptOK, and check for interrupts if needed.
00212          */
00213         ImmediateInterruptOK = save_ImmediateInterruptOK;
00214         if (save_ImmediateInterruptOK)
00215             CHECK_FOR_INTERRUPTS();
00216     }
00217     else
00218     {
00219         /*
00220          * In this path it is NOT SAFE to do much of anything, except this:
00221          */
00222         catchupInterruptOccurred = 1;
00223     }
00224 }
00225 
00226 /*
00227  * EnableCatchupInterrupt
00228  *
00229  * This is called by the PostgresMain main loop just before waiting
00230  * for a frontend command.  We process any pending catchup events,
00231  * and enable the signal handler to process future events directly.
00232  *
00233  * NOTE: the signal handler starts out disabled, and stays so until
00234  * PostgresMain calls this the first time.
00235  */
00236 void
00237 EnableCatchupInterrupt(void)
00238 {
00239     /*
00240      * This code is tricky because we are communicating with a signal handler
00241      * that could interrupt us at any point.  If we just checked
00242      * catchupInterruptOccurred and then set catchupInterruptEnabled, we could
00243      * fail to respond promptly to a signal that happens in between those two
00244      * steps.  (A very small time window, perhaps, but Murphy's Law says you
00245      * can hit it...)  Instead, we first set the enable flag, then test the
00246      * occurred flag.  If we see an unserviced interrupt has occurred, we
00247      * re-clear the enable flag before going off to do the service work. (That
00248      * prevents re-entrant invocation of ProcessCatchupEvent() if another
00249      * interrupt occurs.) If an interrupt comes in between the setting and
00250      * clearing of catchupInterruptEnabled, then it will have done the service
00251      * work and left catchupInterruptOccurred zero, so we have to check again
00252      * after clearing enable.  The whole thing has to be in a loop in case
00253      * another interrupt occurs while we're servicing the first. Once we get
00254      * out of the loop, enable is set and we know there is no unserviced
00255      * interrupt.
00256      *
00257      * NB: an overenthusiastic optimizing compiler could easily break this
00258      * code. Hopefully, they all understand what "volatile" means these days.
00259      */
00260     for (;;)
00261     {
00262         catchupInterruptEnabled = 1;
00263         if (!catchupInterruptOccurred)
00264             break;
00265         catchupInterruptEnabled = 0;
00266         if (catchupInterruptOccurred)
00267             ProcessCatchupEvent();
00268     }
00269 }
00270 
00271 /*
00272  * DisableCatchupInterrupt
00273  *
00274  * This is called by the PostgresMain main loop just after receiving
00275  * a frontend command.  Signal handler execution of catchup events
00276  * is disabled until the next EnableCatchupInterrupt call.
00277  *
00278  * The PROCSIG_NOTIFY_INTERRUPT signal handler also needs to call this,
00279  * so as to prevent conflicts if one signal interrupts the other.  So we
00280  * must return the previous state of the flag.
00281  */
00282 bool
00283 DisableCatchupInterrupt(void)
00284 {
00285     bool        result = (catchupInterruptEnabled != 0);
00286 
00287     catchupInterruptEnabled = 0;
00288 
00289     return result;
00290 }
00291 
00292 /*
00293  * ProcessCatchupEvent
00294  *
00295  * Respond to a catchup event (PROCSIG_CATCHUP_INTERRUPT) from another
00296  * backend.
00297  *
00298  * This is called either directly from the PROCSIG_CATCHUP_INTERRUPT
00299  * signal handler, or the next time control reaches the outer idle loop
00300  * (assuming there's still anything to do by then).
00301  */
00302 static void
00303 ProcessCatchupEvent(void)
00304 {
00305     bool        notify_enabled;
00306 
00307     /* Must prevent notify interrupt while I am running */
00308     notify_enabled = DisableNotifyInterrupt();
00309 
00310     /*
00311      * What we need to do here is cause ReceiveSharedInvalidMessages() to run,
00312      * which will do the necessary work and also reset the
00313      * catchupInterruptOccurred flag.  If we are inside a transaction we can
00314      * just call AcceptInvalidationMessages() to do this.  If we aren't, we
00315      * start and immediately end a transaction; the call to
00316      * AcceptInvalidationMessages() happens down inside transaction start.
00317      *
00318      * It is awfully tempting to just call AcceptInvalidationMessages()
00319      * without the rest of the xact start/stop overhead, and I think that
00320      * would actually work in the normal case; but I am not sure that things
00321      * would clean up nicely if we got an error partway through.
00322      */
00323     if (IsTransactionOrTransactionBlock())
00324     {
00325         elog(DEBUG4, "ProcessCatchupEvent inside transaction");
00326         AcceptInvalidationMessages();
00327     }
00328     else
00329     {
00330         elog(DEBUG4, "ProcessCatchupEvent outside transaction");
00331         StartTransactionCommand();
00332         CommitTransactionCommand();
00333     }
00334 
00335     if (notify_enabled)
00336         EnableNotifyInterrupt();
00337 }