对PostgreSQL 的 background writer 的初步理解

代码缩略如下:

/*                                            

 * Main entry point for bgwriter process                                            

 *                                            

 * This is invoked from AuxiliaryProcessMain, which has already created the                                            

 * basic execution environment, but not enabled signals yet.                                            

 */                                            

void                                            

BackgroundWriterMain(void)                                            

{                                            

    ……                                        

    /*                                        

     * Properly accept or ignore signals the postmaster might send us.                                        

     *                                        

     * bgwriter doesn't participate in ProcSignal signalling, but a SIGUSR1                                        

     * handler is still needed for latch wakeups.                                        

     */                                        

    pqsignal(SIGHUP, BgSigHupHandler);                    /* set flag to read config file */                    

    pqsignal(SIGINT, SIG_IGN);                                        

    pqsignal(SIGTERM, ReqShutdownHandler);                    /* shutdown */                    

    pqsignal(SIGQUIT, bg_quickdie);                    /* hard crash time */                    

    pqsignal(SIGALRM, SIG_IGN);                                        

    pqsignal(SIGPIPE, SIG_IGN);                                        

    pqsignal(SIGUSR1, bgwriter_sigusr1_handler);                                        

    pqsignal(SIGUSR2, SIG_IGN);                                        

                                            

    /*                                        

     * Reset some signals that are accepted by postmaster but not here                                        

     */                                        

    pqsignal(SIGCHLD, SIG_DFL);                                        

    pqsignal(SIGTTIN, SIG_DFL);                                        

    pqsignal(SIGTTOU, SIG_DFL);                                        

    pqsignal(SIGCONT, SIG_DFL);                                        

    pqsignal(SIGWINCH, SIG_DFL);                                        

                                            

    /* We allow SIGQUIT (quickdie) at all times */                                        

    sigdelset(&BlockSig, SIGQUIT);                                        

                                            

    ……                                        

    /*                                        

     * Loop forever                                        

     */                                        

    for (;;)                                        

    {                                        

        bool        can_hibernate;                            

        int        rc;                            

                                            

        /* Clear any already-pending wakeups */                                    

        ResetLatch(&MyProc->procLatch);                                    

                                            

        if (got_SIGHUP)                                    

        {                                    

            got_SIGHUP = false;                                

            ProcessConfigFile(PGC_SIGHUP);                                

        }                                    

        if (shutdown_requested)                                    

        {                                    

            /*                                

             * From here on, elog(ERROR) should end with exit(1), not send                                

             * control back to the sigsetjmp block above                                

             */                                

            ExitOnAnyError = true;                                

            /* Normal exit from the bgwriter is here */                                

            proc_exit(0);        /* done */                        

        }                                    

                                            

        /*                                    

         * Do one cycle of dirty-buffer writing.                                    

         */                                    

        can_hibernate = BgBufferSync();                                    

                                            

        /*                                    

         * Send off activity statistics to the stats collector                                    

         */                                    

        pgstat_send_bgwriter();                                    

                                            

        if (FirstCallSinceLastCheckpoint())                                    

        {                                    

            /*                                

             * After any checkpoint, close all smgr files.                    This is so we            

             * won't hang onto smgr references to deleted files indefinitely.                                

             */                                

            smgrcloseall();                                

        }                                    

                                            

        /*                                    

         * Sleep until we are signaled or BgWriterDelay has elapsed.                                    

         *                                    

         * Note: the feedback control loop in BgBufferSync() expects that we                                    

         * will call it every BgWriterDelay msec.  While it's not critical for                                    

         * correctness that that be exact, the feedback loop might misbehave                                    

         * if we stray too far from that.  Hence, avoid loading this process                                    

         * down with latch events that are likely to happen frequently during                                    

         * normal operation.                                    

         */                                    

        rc = WaitLatch(&MyProc->procLatch,                                    

                   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,                            

                   BgWriterDelay /* ms */ );                            

                                            

        /*                                    

         * If no latch event and BgBufferSync says nothing's happening, extend                                    

         * the sleep in "hibernation" mode, where we sleep for much longer                                    

         * than bgwriter_delay says.  Fewer wakeups save electricity.  When a                                    

         * backend starts using buffers again, it will wake us up by setting                                    

         * our latch.  Because the extra sleep will persist only as long as no                                    

         * buffer allocations happen, this should not distort the behavior of                                    

         * BgBufferSync's control loop too badly; essentially, it will think                                    

         * that the system-wide idle interval didn't exist.                                    

         *                                    

         * There is a race condition here, in that a backend might allocate a                                    

         * buffer between the time BgBufferSync saw the alloc count as zero                                    

         * and the time we call StrategyNotifyBgWriter.  While it's not                                    

         * critical that we not hibernate anyway, we try to reduce the odds of                                    

         * that by only hibernating when BgBufferSync says nothing's happening                                    

         * for two consecutive cycles.    Also, we mitigate any possible                                

         * consequences of a missed wakeup by not hibernating forever.                                    

         */                                    

        if (rc == WL_TIMEOUT && can_hibernate && prev_hibernate)                                    

        {                                    

            /* Ask for notification at next buffer allocation */                                

            StrategyNotifyBgWriter(&MyProc->procLatch);                                

            /* Sleep ... */                                

            rc = WaitLatch(&MyProc->procLatch,                                

                           WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,                    

                           BgWriterDelay * HIBERNATE_FACTOR);                    

            /* Reset the notification request in case we timed out */                                

            StrategyNotifyBgWriter(NULL);                                

        }                                    

        ……                                    

    }                                        

}                                            

我的理解:其中最为关键的就是这一段:

/*
* Do one cycle of dirty-buffer writing.
*/
can_hibernate = BgBufferSync(); 

其位于 src\backend\storage\buffer 目录下的 bufmgr.c 中。

你可能感兴趣的:(PostgreSQL)