BackgroundWriterMain代码

来源:互联网 发布:投针法计算圆周率c语言 编辑:程序博客网 时间:2024/05/16 15:09

提示:
由于工作原因文章还没有弄完,请跳过,弄完后,会删除此提示

基础流程:

BackgroundWriterMainBgBuffferSync->SyncOneBuffer-> FlushBuffer()-> smgrwrite()

逻辑部分

首先代码定义一些基础类型和变量,例如:信号的处理,bgwrite的内存上下文,错误处理机制等。     然后,进入后台写进程,后台写进程是一个死循环进程,启动后,如果没有一些特殊情况(如:master死亡,关机等信号)就会一直运行。    此函数主要做一些简单的工作,如,监听信号(重新加载、关机等信号)确定是否退出或者重载。    调用落盘函数接口(BgBufferSync),将落盘动作返回的统计动作发送给stat统计表。    做一些简单的判断判断是否要进入一个长时间的睡眠(如果超过WL_TIMEOUT,并且连续两次没有落盘动作,就会进入一个长时间的睡眠)。    如果睡眠时间到,或者睡眠期间有内存的分配操作,就会醒来。然后再次循环。

代码部分

voidBackgroundWriterMain(void){    sigjmp_buf  local_sigjmp_buf;    //解析:定义错误恢复变量,保存错误后信号    MemoryContext bgwriter_context;    //解析:定义内存上下文    bool        prev_hibernate;    //解析:定义预先睡眠,后面用来确定是否进入一个深度睡眠    WritebackContext wb_context;    //解析:定义后台写进程上下文    //内存上下文解析:    //1.pg是基于进程的,每个进程拥有一块内存,分配内存上下文为了方便内存的处理。    //2.方便错误处理,自己进行内存的管理,方便错误发生时进行恢复操作。    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);    //上面是对一些信号的注册    CurrentResourceOwner = ResourceOwnerCreate(NULL, "Background Writer");    //创建一个资源所有者来与我们的资源保持联系    /*     * We just started, assume there has been either a shutdown or end-of-recovery 快照.     */    last_snapshot_ts = GetCurrentTimestamp();    bgwriter_context = AllocSetContextCreate(TopMemoryContext, "Background Writer",    ALLOCSET_DEFAULT_MINSIZE,ALLOCSET_DEFAULT_INITSIZE,ALLOCSET_DEFAULT_MAXSIZE);    //创建一个内存上下文,内存上下文的作用见:内存上下文篇                                         MemoryContextSwitchTo(bgwriter_context);    //切换内存上下文    WritebackContextInit(&wb_context, &bgwriter_flush_after);    //下面是做错误恢复和检查用的,后期做整理    if (sigsetjmp(local_sigjmp_buf, 1) != 0)    {        /* Since not using PG_TRY, must reset error stack by hand */        error_context_stack = NULL;        /* Prevent interrupts while cleaning up */        HOLD_INTERRUPTS();        /* Report the error to the server log */        EmitErrorReport();        /*         * These operations are really just a minimal subset of AbortTransaction().           * We don't have very many resources to worry  about in bgwriter, but we do have LWLocks, buffers, and temp files.         */        LWLockReleaseAll();        AbortBufferIO();        UnlockBuffers();        /*释放 buffer pins : */        ResourceOwnerRelease(CurrentResourceOwner,                             RESOURCE_RELEASE_BEFORE_LOCKS,                             false, true);        /* we needn't bother with the other ResourceOwnerRelease phases */        AtEOXact_Buffers(false);        AtEOXact_SMgr();        AtEOXact_Files();        AtEOXact_HashTables(false);        /*         * Now return to normal top-level context and clear ErrorContext for         * next time.         */        MemoryContextSwitchTo(bgwriter_context);        FlushErrorState();        /* Flush any leaked data in the top-level context */        MemoryContextResetAndDeleteChildren(bgwriter_context);        /* re-initilialize to avoid repeated errors causing problems */        WritebackContextInit(&wb_context, &bgwriter_flush_after);        /* Now we can allow interrupts again */        RESUME_INTERRUPTS();        /*         * Sleep at least 1 second after any error.           * A write error is likely to be repeated, and we don't want to be filling the error logs as  fast as we can.         */        pg_usleep(1000000L);        /*         * Close all open files after any error.  This is helpful on Windows,         * where holding deleted files open causes various strange errors.         * It's not clear we need it elsewhere, but shouldn't hurt.         */        smgrcloseall();        /* Report wait end here, when there is no further possibility of wait */        pgstat_report_wait_end();    }    /* We can now handle ereport(ERROR) */    PG_exception_stack = &local_sigjmp_buf;    /*     * Unblock signals (they were blocked when the postmaster forked us)     */    PG_SETMASK(&UnBlockSig);    /*     * Reset hibernation state after any error.     */    prev_hibernate = false;    //开始进入后台写进程的流程    for (;;)    {        bool        can_hibernate;        //定义bool变量确定是否进入长时间的睡眠,可以认为是一个开关变量        int         rc;        /* Clear any already-pending wakeups */        ResetLatch(MyLatch);        //判断是否接受到SIGHUP信号,接收到后重新加载配置文件        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 */        }        // 重中之重,进行一次脏数据的落盘操作,根据落盘状况重置开关变量can_hibernate,确定是否需要进入一次长时间睡眠。        can_hibernate = BgBufferSync(&wb_context);        //将统计数据发送到stats collector        pgstat_send_bgwriter();        //判断是否是checkpoint后的第一次操作        if (FirstCallSinceLastCheckpoint())        {            /*             * After any checkpoint, close all smgr files.              * This is so we won't hang onto smgr            * references to deleted files indefinitely.            *              */            smgrcloseall();        }         //判断Log记录level 并且系统没有在recovery。        if (XLogStandbyInfoActive() && !RecoveryInProgress())        {            TimestampTz timeout = 0;            TimestampTz now = GetCurrentTimestamp();            timeout =TimestampTzPlusMilliseconds(last_snapshot_ts,  LOG_SNAPSHOT_INTERVAL_MS);            /*             * only log if enough time has passed and some xlog record has been inserted.             * 只有xlog已经落盘足够时间             */            if (now >= timeout &&last_snapshot_lsn != GetXLogInsertRecPtr())            {                last_snapshot_lsn = LogStandbySnapshot();                last_snapshot_ts = now;            }        }     //判断WaitLatch是由于哪种原因造成的返回        rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, BgWriterDelay /* ms */ );        //如果没有latch 事件,并且BgBufferSync没有落盘脏数据,函数就会睡眠一个比较长的时间。一旦有内存的分配,它就会被唤醒.        if (rc == WL_TIMEOUT && can_hibernate && prev_hibernate)        {            /* Ask for notification at next buffer allocation */            StrategyNotifyBgWriter(MyProc->pgprocno);            /* Sleep ... */            rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, BgWriterDelay * HIBERNATE_FACTOR);            /* Reset the notification request in case we timed out */            StrategyNotifyBgWriter(-1);        }        //如果是由于master进程死亡造成的返回,进程退出,否则的话        if (rc & WL_POSTMASTER_DEATH)            exit(1);        prev_hibernate = can_hibernate;    }
1 0
原创粉丝点击