1. 程式人生 > >Postgresql - 原始碼 - stats collector process

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);

}