我的编程空间,编程开发者的网络收藏夹
学习永远不晚

PostgreSQL中AutoVacLauncherMain函数的实现逻辑是什么

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

PostgreSQL中AutoVacLauncherMain函数的实现逻辑是什么

本篇内容介绍了“PostgreSQL中AutoVacLauncherMain函数的实现逻辑是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、数据结构

宏定义

#define GetProcessingMode() Mode
#define SetProcessingMode(mode) \
    do { \
        AssertArg((mode) == BootstrapProcessing || \
                  (mode) == InitProcessing || \
                  (mode) == NormalProcessing); \
        Mode = (mode); \
    } while(0)

二、源码解读

AutoVacLauncherMain函数,autovacuum进程主循环.


NON_EXEC_STATIC void
AutoVacLauncherMain(int argc, char *argv[])
{
    sigjmp_buf  local_sigjmp_buf;
    am_autovacuum_launcher = true;
    
    //进程ID
    init_ps_display(pgstat_get_backend_desc(B_AUTOVAC_LAUNCHER), "", "", "");
    ereport(DEBUG1,
            (errmsg("autovacuum launcher started")));
    if (PostAuthDelay)
        pg_usleep(PostAuthDelay * 1000000L);
    //设置进程模式
    SetProcessingMode(InitProcessing);
    
    pqsignal(SIGHUP, av_sighup_handler);
    pqsignal(SIGINT, StatementCancelHandler);
    pqsignal(SIGTERM, avl_sigterm_handler);
    pqsignal(SIGQUIT, quickdie);
    //建立SIGALRM控制器
    InitializeTimeouts();       
    pqsignal(SIGPIPE, SIG_IGN);//忽略SIGPIPE
    pqsignal(SIGUSR1, procsignal_sigusr1_handler);
    pqsignal(SIGUSR2, avl_sigusr2_handler);
    pqsignal(SIGFPE, FloatExceptionHandler);
    pqsignal(SIGCHLD, SIG_DFL);
    
    //基础初始化
    BaseInit();
    
#ifndef EXEC_BACKEND
    InitProcess();
#endif
    //初始化
    InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL, false);
    //设置进程模式
    SetProcessingMode(NormalProcessing);
    
    AutovacMemCxt = AllocSetContextCreate(TopMemoryContext,
                                          "Autovacuum Launcher",
                                          ALLOCSET_DEFAULT_SIZES);
    MemoryContextSwitchTo(AutovacMemCxt);
    
    if (sigsetjmp(local_sigjmp_buf, 1) != 0)
    {
        
        //由于没有使用PG_TRY,这里必须手工重置错误.
        error_context_stack = NULL;
        
        //在清理期间禁用中断
        HOLD_INTERRUPTS();
        
        //忽略所有QueryCancel或者超时请求
        disable_all_timeouts(false);
        QueryCancelPending = false; 
        
        //在服务器日志中记录日志.
        EmitErrorReport();
        
        //废弃当前事务,以准备恢复
        AbortCurrentTransaction();
        
        LWLockReleaseAll();
        pgstat_report_wait_end();
        AbortBufferIO();
        UnlockBuffers();
        
        //这可能是dead code,但可以保证安全
        if (AuxProcessResourceOwner)
            ReleaseAuxProcessResources(false);
        AtEOXact_Buffers(false);
        AtEOXact_SMgr();
        AtEOXact_Files(false);
        AtEOXact_HashTables(false);
        
        MemoryContextSwitchTo(AutovacMemCxt);
        FlushErrorState();
        
        //在top-level上下文刷新所有泄漏的数据
        MemoryContextResetAndDeleteChildren(AutovacMemCxt);
        
        //不要留下悬空指针来释放内存
        DatabaseListCxt = NULL;
        dlist_init(&DatabaseList);
        
        pgstat_clear_snapshot();
        
        //可以允许中断了
        RESUME_INTERRUPTS();
        
        //如处于shutdown模式,不需要继续后续的工作了,跳转到shutdown
        if (got_SIGTERM)
            goto shutdown;
        
        pg_usleep(1000000L);
    }
    
    //现在可以处理ereport(ERROR)了
    PG_exception_stack = &local_sigjmp_buf;
    
    //在调用rebuild_database_list前不能阻塞信号
    PG_SETMASK(&UnBlockSig);
    
    SetConfigOption("search_path", "", PGC_SUSET, PGC_S_OVERRIDE);
    
    SetConfigOption("zero_damaged_pages", "false", PGC_SUSET, PGC_S_OVERRIDE);
    
    SetConfigOption("statement_timeout", "0", PGC_SUSET, PGC_S_OVERRIDE);
    SetConfigOption("lock_timeout", "0", PGC_SUSET, PGC_S_OVERRIDE);
    SetConfigOption("idle_in_transaction_session_timeout", "0",
                    PGC_SUSET, PGC_S_OVERRIDE);
    
    SetConfigOption("default_transaction_isolation", "read committed",
                    PGC_SUSET, PGC_S_OVERRIDE);
    
    if (!AutoVacuumingActive())
    {
        if (!got_SIGTERM)
            do_start_worker();
        proc_exit(0);           
    }
    AutoVacuumShmem->av_launcherpid = MyProcPid;
    
    rebuild_database_list(InvalidOid);
    
    //循环,直至请求shutdown
    while (!got_SIGTERM)
    {
        struct timeval nap;
        TimestampTz current_time = 0;
        bool        can_launch;
        
        launcher_determine_sleep(!dlist_is_empty(&AutoVacuumShmem->av_freeWorkers),
                                 false, &nap);
        
        (void) WaitLatch(MyLatch,
                         WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
                         (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
                         WAIT_EVENT_AUTOVACUUM_MAIN);
        ResetLatch(MyLatch);
        
        //在休眠过程中,进程会捕获相关的中断.
        ProcessCatchupInterrupt();
        
        //shutdonw信号
        if (got_SIGTERM)
            break;
        if (got_SIGHUP)
        {
            //SIGHUP信号
            got_SIGHUP = false;
            ProcessConfigFile(PGC_SIGHUP);
            
            //在配置文件中已请求shutdown?
            if (!AutoVacuumingActive())
                break;
            
            //如默认的成本参数变化,则自动平衡.
            LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
            autovac_balance_cost();
            LWLockRelease(AutovacuumLock);
            
            //如naptime出现变化,重建链表
            rebuild_database_list(InvalidOid);
        }
        
        if (got_SIGUSR2)
        {
            //SIGUSR2信号
            got_SIGUSR2 = false;
            
            //如需要,重平衡成本限制
            if (AutoVacuumShmem->av_signal[AutoVacRebalance])
            {
                LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
                AutoVacuumShmem->av_signal[AutoVacRebalance] = false;
                autovac_balance_cost();
                LWLockRelease(AutovacuumLock);
            }
            if (AutoVacuumShmem->av_signal[AutoVacForkFailed])
            {
                
                AutoVacuumShmem->av_signal[AutoVacForkFailed] = false;
                pg_usleep(1000000L);    
                SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER);
                continue;
            }
        }
        
        current_time = GetCurrentTimestamp();
        LWLockAcquire(AutovacuumLock, LW_SHARED);
        can_launch = !dlist_is_empty(&AutoVacuumShmem->av_freeWorkers);
        if (AutoVacuumShmem->av_startingWorker != NULL)
        {
            int         waittime;
            WorkerInfo  worker = AutoVacuumShmem->av_startingWorker;
            
            waittime = Min(autovacuum_naptime, 60) * 1000;
            if (TimestampDifferenceExceeds(worker->wi_launchtime, current_time,
                                           waittime))
            {
                LWLockRelease(AutovacuumLock);
                LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
                
                if (AutoVacuumShmem->av_startingWorker != NULL)
                {
                    worker = AutoVacuumShmem->av_startingWorker;
                    worker->wi_dboid = InvalidOid;
                    worker->wi_tableoid = InvalidOid;
                    worker->wi_sharedrel = false;
                    worker->wi_proc = NULL;
                    worker->wi_launchtime = 0;
                    dlist_push_head(&AutoVacuumShmem->av_freeWorkers,
                                    &worker->wi_links);
                    AutoVacuumShmem->av_startingWorker = NULL;
                    elog(WARNING, "worker took too long to start; canceled");
                }
            }
            else
                can_launch = false;
        }
        //释放锁
        LWLockRelease(AutovacuumLock);  
        
        //什么都做不了,继续休眠
        if (!can_launch)
            continue;
        
        //现在可以启动新的worker  
        if (dlist_is_empty(&DatabaseList))
        {
            
            launch_worker(current_time);
        }
        else
        {
            
            avl_dbase  *avdb;
            avdb = dlist_tail_element(avl_dbase, adl_node, &DatabaseList);
            
            if (TimestampDifferenceExceeds(avdb->adl_next_worker,
                                           current_time, 0))
                launch_worker(current_time);
        }
    }
    
    //常规的退出.
shutdown:
    ereport(DEBUG1,
            (errmsg("autovacuum launcher shutting down")));
    AutoVacuumShmem->av_launcherpid = 0;
    proc_exit(0);               
}

“PostgreSQL中AutoVacLauncherMain函数的实现逻辑是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

PostgreSQL中AutoVacLauncherMain函数的实现逻辑是什么

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

编程热搜

目录