Postgresql - 源码 - stats collector process

代码位置:

src/backend/postmaster/pgstat.c

所有的统计信息收集器的东西放在一个大的丑陋的文件。

TODO:

- Separate collector, postmaster and backend stuff into different files. 单独收集,postmaster和backend内容到不同的文件。

- Add some automatic call for pgstat vacuuming. 添加一些自动调用 pgstat vacuuming

- Add a pgstat config column to pg_database, so this entire thing can be enabled/disabled on a per db basis. 将pgstat config 列添加到pg_database,因此可以在每个DB的基础上启用/禁用整个事件。

从 postmaster 启动时或存在的 collector 进程死掉是调用。试图启动一个新的statistics collector。

int

pgstat_start(void)

{

    time_t      curtime;

    pid_t       pgStatPid;

    /* 检查套接字是否存在,否则 pgstat_init 失败,而且无能为力。 */

    if (pgStatSock == PGINVALID_SOCKET)

        return 0;

    /* 如果上次 collector 启动后不久,就什么都不做。这是一个安全阀,为了防止collector 在启动的时候死掉,连续重复尝试,注意,因为我们将从 postmaster main loop 重新调用,我们稍后会得到另一个机会启动。 */

    curtime = time(NULL);

    if ((unsigned int) (curtime - last_pgstat_start_time) <

        (unsigned int) PGSTAT_RESTART_INTERVAL)

        return 0;

    last_pgstat_start_time = curtime;

    /* collector 的岔口 */

#ifdef EXEC_BACKEND

    switch ((pgStatPid = pgstat_forkexec()))

#else

    switch ((pgStatPid = fork_process()))

#endif

    {

        case -1:

            ereport(LOG,

                    (errmsg("could not fork statistics collector: %m")));

            return 0;

#ifndef EXEC_BACKEND

        case 0:

            /* postmaster子进程 ... */

            InitPostmasterChild();

            /* 关闭 postmaster's 套接字 */

            ClosePostmasterPorts(false);

            /* 把我们连接到 postmaster 的共享内存 */

            dsm_detach_all();

            PGSharedMemoryDetach();

            /* pgstat collector 主函数 */

            PgstatCollectorMain(0, NULL);

            break;

#endif

        default:

            return (int) pgStatPid;

    }

    /* shouldn't get here */

    return 0;

}

****************************************************************************************************************************

/* 启动统计收集器过程。这是postmaster child process 的代码。

*  The argc/argv parameters are valid only in EXEC_BACKEND case.

*/

NON_EXEC_STATIC void

PgstatCollectorMain(int argc, char *argv[])

{

    int         len;

    PgStat_Msg  msg;

    int         wr;

    /* 忽略所有信号,通常绑定到postmaster 的某些行动,除了SIGHUP 和 SIGQUIT 。注意,我们不需要 SIGUSR1 处理器来支持闩锁操作,因为我们只使用本地锁存器。 */

    pqsignal(SIGHUP, pgstat_sighup_handler);

    pqsignal(SIGINT, SIG_IGN);

    pqsignal(SIGTERM, SIG_IGN);

    pqsignal(SIGQUIT, pgstat_exit);

    pqsignal(SIGALRM, SIG_IGN);

    pqsignal(SIGPIPE, SIG_IGN);

    pqsignal(SIGUSR1, SIG_IGN);

    pqsignal(SIGUSR2, SIG_IGN);

    pqsignal(SIGCHLD, SIG_DFL);

    pqsignal(SIGTTIN, SIG_DFL);

    pqsignal(SIGTTOU, SIG_DFL);

    pqsignal(SIGCONT, SIG_DFL);

    pqsignal(SIGWINCH, SIG_DFL);

    PG_SETMASK(&UnBlockSig);

    /* 通过ps 确定自己 */

    init_ps_display("stats collector", "", "", "");

    /* 读取现有的统计文件或初始化统计数据为零。 */

    pgStatRunningInCollector = true;

    pgStatDBHash = pgstat_read_statsfiles(InvalidOid, true, true);

    /* 循环处理消息,直到我们得到 SIGQUIT 或检测到我们的父进程 postmaster 死掉。出于性能原因,我们不希望在每个消息之后都执行ResetLatch/WaitLatch ;相反,只有在 recv() 无法获得消息之后才这样做。这实际上意味着,如果后端疯狂的发送给我们的东西,我们将不会注意到postmaster 进程死掉,直到事情有点松懈,这似乎是好的。为了做到这一点,我们有一个内部循环,只要 recv() 成功就可以迭代。我们确实在内部循环中识别 got_SIGHUP ,这意味着此类中断将得到处理,但是锁存器直到下一次动作中断时才会被清除。*/

    for (;;)

    {

        /* 清除任何已挂起的唤醒 */

        ResetLatch(MyLatch);

        /* 如果我们从postmaster得到 SIGQUIT,退出 */

        if (need_exit)

            break;

        /* 只要我们继续获取消息,没有收到 need_exit 设置,就会一直loop。 */

        while (!need_exit)

        {

            /* 如果我们从 postmaster 收到 SIGHUP ,重新加载配置 */

            if (got_SIGHUP)

            {

                got_SIGHUP = false;

                ProcessConfigFile(PGC_SIGHUP);

            }

            /* 如果一个新的请求已被现有文件不满足,则写入stats 文件。 */

            if (pgstat_write_statsfile_needed())

                pgstat_write_statsfiles(false, false);

            /* 尝试接收和处理消息。由于套接字被设置为非阻塞模式,所以这不会阻塞。在Windows上,我们不得不强制与 pgwin32_recv 协作,尽管以前在套接字上使用pg_set_noblock()。这是非常不好的的,应该有一天被修复。 */

#ifdef WIN32

            pgwin32_noblock = 1;

#endif

            len = recv(pgStatSock, (char *) &msg,

                     sizeof(PgStat_Msg), 0);

#ifdef WIN32

            pgwin32_noblock = 0;

#endif

            if (len < 0)

            {

                if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)

                    break;      /* out of inner loop */

                ereport(ERROR,

                        (errcode_for_socket_access(),

                         errmsg("could not read statistics message: %m")));

            }

            /* 我们忽略比我们的普通的报头小的消息。 */

            if (len < sizeof(PgStat_MsgHdr))

                continue;

            /* 接收的长度必须与标题中的长度相匹配。 */

            if (msg.msg_hdr.m_size != len)

                continue;

            /* 我们接受这个消息。处理它。 */

            switch (msg.msg_hdr.m_type)

            {

                case PGSTAT_MTYPE_DUMMY:

                    break;

                case PGSTAT_MTYPE_INQUIRY:

                    pgstat_recv_inquiry((PgStat_MsgInquiry *) &msg, len);

                    break;

                case PGSTAT_MTYPE_TABSTAT:

                    pgstat_recv_tabstat((PgStat_MsgTabstat *) &msg, len);

                    break;

                case PGSTAT_MTYPE_TABPURGE:

                    pgstat_recv_tabpurge((PgStat_MsgTabpurge *) &msg, len);

                    break;

                case PGSTAT_MTYPE_DROPDB:

                    pgstat_recv_dropdb((PgStat_MsgDropdb *) &msg, len);

                    break;

                case PGSTAT_MTYPE_RESETCOUNTER:

                    pgstat_recv_resetcounter((PgStat_MsgResetcounter *) &msg,

                                             len);

                    break;

                case PGSTAT_MTYPE_RESETSHAREDCOUNTER:

                    pgstat_recv_resetsharedcounter(

                                                 (PgStat_MsgResetsharedcounter *) &msg,

                                                 len);

                    break;

                case PGSTAT_MTYPE_RESETSINGLECOUNTER:

                    pgstat_recv_resetsinglecounter(

                                                 (PgStat_MsgResetsinglecounter *) &msg,

                                                 len);

                    break;

                case PGSTAT_MTYPE_AUTOVAC_START:

                    pgstat_recv_autovac((PgStat_MsgAutovacStart *) &msg, len);

                    break;

                case PGSTAT_MTYPE_VACUUM:

                    pgstat_recv_vacuum((PgStat_MsgVacuum *) &msg, len);

                    break;

                case PGSTAT_MTYPE_ANALYZE:

                    pgstat_recv_analyze((PgStat_MsgAnalyze *) &msg, len);

                    break;

                case PGSTAT_MTYPE_ARCHIVER:

                    pgstat_recv_archiver((PgStat_MsgArchiver *) &msg, len);

                    break;

                case PGSTAT_MTYPE_BGWRITER:

                    pgstat_recv_bgwriter((PgStat_MsgBgWriter *) &msg, len);

                    break;

                case PGSTAT_MTYPE_FUNCSTAT:

                    pgstat_recv_funcstat((PgStat_MsgFuncstat *) &msg, len);

                    break;

                case PGSTAT_MTYPE_FUNCPURGE:

                    pgstat_recv_funcpurge((PgStat_MsgFuncpurge *) &msg, len);

                    break;

                case PGSTAT_MTYPE_RECOVERYCONFLICT:

                    pgstat_recv_recoveryconflict((PgStat_MsgRecoveryConflict *) &msg, len);

                    break;

                case PGSTAT_MTYPE_DEADLOCK:

                    pgstat_recv_deadlock((PgStat_MsgDeadlock *) &msg, len);

                    break;

                case PGSTAT_MTYPE_TEMPFILE:

                    pgstat_recv_tempfile((PgStat_MsgTempFile *) &msg, len);

                    break;

                default:

                    break;

            }

        }                       /* 内部消息处理循环结束 */

        /* Sleep 直到有事情要做 */

#ifndef WIN32

        wr = WaitLatchOrSocket(MyLatch,

                             WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_SOCKET_READABLE,

                             pgStatSock, -1L,

                             WAIT_EVENT_PGSTAT_MAIN);

#else

        /* Windows,至少在Windows Server 2003 R2体现,有时会丢失 FD_READ 事件。唤醒并重试 recv() 修复,所以不要无限期sleep。这只是开头,但是除非有人想调试那里到底发生了什么,否则这是我们所能做的最好的事情。2秒的超时时间与我们在9.2之前的行为相匹配,并且需要足够短,以免引发 backend_read_statsfile 的“使用陈旧的统计数据”投诉。 */

        wr = WaitLatchOrSocket(MyLatch,

                             WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_SOCKET_READABLE | WL_TIMEOUT,

                             pgStatSock,

                             2 * 1000L /* msec */ ,

                             WAIT_EVENT_PGSTAT_MAIN);

#endif

        /* 如果 postmaster 死了,将紧急救助。这是为了避免对所有 postmaster 的子进程进行手工清理。 */

        if (wr & WL_POSTMASTER_DEATH)

            break;

    }                           /* end of outer loop */

    /* 在下一次启动时保存最终统计数据以重用。 */

    pgstat_write_statsfiles(true, true);

    exit(0);

}

猜你喜欢

转载自blog.csdn.net/chuckchen1222/article/details/83149781