亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么理解PostgreSQL的后臺進程autovacuum

發布時間:2021-11-08 14:11:56 來源:億速云 閱讀:131 作者:iii 欄目:關系型數據庫

本篇內容介紹了“怎么理解PostgreSQL的后臺進程autovacuum”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

一、數據結構

AutoVacuumShmem
主要的autovacuum共享內存結構體,存儲在shared memory中,同時WorkerInfo也會存儲在其中.

/*-------------
 * The main autovacuum shmem struct.  On shared memory we store this main
 * struct and the array of WorkerInfo structs.  This struct keeps:
 * 主要的autovacuum共享內存結構體,存儲在shared memory中,同時WorkerInfo也會存儲在其中.
 * 該結構體包括:
 *
 * av_signal        set by other processes to indicate various conditions
 * 其他進程設置用于提示不同的條件
 * av_launcherpid   the PID of the autovacuum launcher
 * autovacuum launcher的PID
 * av_freeWorkers   the WorkerInfo freelist
 * WorkerInfo空閑鏈表
 * av_runningWorkers the WorkerInfo non-free queue
 * WorkerInfo非空閑隊列
 * av_startingWorker pointer to WorkerInfo currently being started (cleared by
 *                  the worker itself as soon as it's up and running)
 * av_startingWorker指向當前正在啟動的WorkerInfo
 * av_workItems     work item array
 * av_workItems 工作條目數組
 *
 * This struct is protected by AutovacuumLock, except for av_signal and parts
 * of the worker list (see above).
 * 除了av_signal和worker list的一部分信息,該數據結構通過AutovacuumLock保護
 *-------------
 */
typedef struct
{
    sig_atomic_t av_signal[AutoVacNumSignals];
    pid_t       av_launcherpid;
    dlist_head  av_freeWorkers;
    dlist_head  av_runningWorkers;
    WorkerInfo  av_startingWorker;
    AutoVacuumWorkItem av_workItems[NUM_WORKITEMS];
} AutoVacuumShmemStruct;
static AutoVacuumShmemStruct *AutoVacuumShmem;

avw_dbase
用于跟蹤worker中的數據庫的結構體

/* struct to keep track of databases in worker */
//用于跟蹤worker中的數據庫的結構體
typedef struct avw_dbase
{
    Oid         adw_datid;
    char       *adw_name;
    TransactionId adw_frozenxid;
    MultiXactId adw_minmulti;
    PgStat_StatDBEntry *adw_entry;
} avw_dbase;

二、源碼解讀

rebuild_database_list用于構建出現變化后的DatabaseList,鏈表中的數據庫應出現在pgstats中,在autovacuum_naptime所設定的時間間隔范圍內均勻分布。
比如autovacuum_naptime = 60s,有4個數據庫db1->db4,那么每隔60s/4就會有啟動一個autovacuum worker對相應的DB進行處理。
可能的一個處理時間序列是:db1->XX(時):XX(分):18(秒),db4->XX:XX:33,db4->XX:XX:48,db4->XX:XX:03
后續如需要對db1->db4進行vacuum,那么db1->db4會在下一個18秒、33秒、48秒和03秒觸發autovacuum。

/*
 * Build an updated DatabaseList.  It must only contain databases that appear
 * in pgstats, and must be sorted by next_worker from highest to lowest,
 * distributed regularly across the next autovacuum_naptime interval.
 * 構建出現變化后的DatabaseList,鏈表中的數據庫應出現在pgstats中,通過next_worker從最高到最低排列,
 * 在autovacuum_naptime所設定的間隔范圍內均勻分布。
 * 比如autovacuum_naptime = 60s,有4個數據庫db1->db4,那么每隔60s/4就會有啟動一個autovacuum worker對相應的DB進行處理。
 * 可能的一個處理時間序列是:db1->XX:XX:18,db4->XX:XX:33,db4->XX:XX:48,db4->XX:XX:03
 *
 * Receives the Oid of the database that made this list be generated (we call
 * this the "new" database, because when the database was already present on
 * the list, we expect that this function is not called at all).  The
 * preexisting list, if any, will be used to preserve the order of the
 * databases in the autovacuum_naptime period.  The new database is put at the
 * end of the interval.  The actual values are not saved, which should not be
 * much of a problem.
 */
static void
rebuild_database_list(Oid newdb)
{
    List       *dblist;
    ListCell   *cell;
    MemoryContext newcxt;
    MemoryContext oldcxt;
    MemoryContext tmpcxt;
    HASHCTL     hctl;
    int         score;
    int         nelems;
    HTAB       *dbhash;
    dlist_iter  iter;
    /* use fresh stats */
    autovac_refresh_stats();
    newcxt = AllocSetContextCreate(AutovacMemCxt,
                                   "AV dblist",
                                   ALLOCSET_DEFAULT_SIZES);
    tmpcxt = AllocSetContextCreate(newcxt,
                                   "tmp AV dblist",
                                   ALLOCSET_DEFAULT_SIZES);
    oldcxt = MemoryContextSwitchTo(tmpcxt);
    /*
     * Implementing this is not as simple as it sounds, because we need to put
     * the new database at the end of the list; next the databases that were
     * already on the list, and finally (at the tail of the list) all the
     * other databases that are not on the existing list.
     * 這里的實現并沒有看上去的那么簡單,因為需要把新數據庫放在鏈表的末尾;
     * 接下來是處理已經在鏈表上的數據庫,最后(在鏈表的末尾)是處理不在現有鏈表上的所有其他數據庫。
     *
     * To do this, we build an empty hash table of scored databases.  We will
     * start with the lowest score (zero) for the new database, then
     * increasing scores for the databases in the existing list, in order, and
     * lastly increasing scores for all databases gotten via
     * get_database_list() that are not already on the hash.
     * 為了實現這個目的,構建了一個空的哈希表用于存儲數據庫(已加權重值)。
     * 從最低分值(0)開始,賦予新的數據庫,然后為現存在鏈表中的數據庫增加分值,
     * 繼續為不在鏈表中的數據庫增加分值。
     *
     * Then we will put all the hash elements into an array, sort the array by
     * score, and finally put the array elements into the new doubly linked
     * list.
     * 完成上述工作后,會把所有哈希表中的元素放到數組中,通過分值進行排序,最后把數組元素放到新的雙向鏈接鏈表中。
     */
    hctl.keysize = sizeof(Oid);
    hctl.entrysize = sizeof(avl_dbase);
    hctl.hcxt = tmpcxt;
    dbhash = hash_create("db hash", 20, &hctl,  /* magic number here FIXME */
                         HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
    /* start by inserting the new database */
    score = 0;//分值從0開始
    if (OidIsValid(newdb))
    {
        avl_dbase  *db;
        PgStat_StatDBEntry *entry;
        /* only consider this database if it has a pgstat entry */
        //只關注存在pgstat條目的數據庫
        entry = pgstat_fetch_stat_dbentry(newdb);
        if (entry != NULL)
        {
            /* we assume it isn't found because the hash was just created */
            db = hash_search(dbhash, &newdb, HASH_ENTER, NULL);
            /* hash_search already filled in the key */
            db->adl_score = score++;
            /* next_worker is filled in later */
        }
    }
    /* Now insert the databases from the existing list */
    //從現存鏈表中插入到數據庫中
    dlist_foreach(iter, &DatabaseList)
    {
        avl_dbase  *avdb = dlist_container(avl_dbase, adl_node, iter.cur);
        avl_dbase  *db;
        bool        found;
        PgStat_StatDBEntry *entry;
        /*
         * skip databases with no stat entries -- in particular, this gets rid
         * of dropped databases
         * 跳過沒有統計信息的數據庫
         */
        entry = pgstat_fetch_stat_dbentry(avdb->adl_datid);
        if (entry == NULL)
            continue;
        db = hash_search(dbhash, &(avdb->adl_datid), HASH_ENTER, &found);
        if (!found)
        {
            /* hash_search already filled in the key */
            db->adl_score = score++;
            /* next_worker is filled in later */
        }
    }
    /* finally, insert all qualifying databases not previously inserted */
    //插入先前沒有處理過的數據庫
    dblist = get_database_list();
    foreach(cell, dblist)
    {
        avw_dbase  *avdb = lfirst(cell);
        avl_dbase  *db;
        bool        found;
        PgStat_StatDBEntry *entry;
        /* only consider databases with a pgstat entry */
        //只考慮存在pgstat的數據庫
        entry = pgstat_fetch_stat_dbentry(avdb->adw_datid);
        if (entry == NULL)
            continue;
        db = hash_search(dbhash, &(avdb->adw_datid), HASH_ENTER, &found);
        /* only update the score if the database was not already on the hash */
        if (!found)
        {
            /* hash_search already filled in the key */
            db->adl_score = score++;
            /* next_worker is filled in later */
        }
    }
    nelems = score;
    /* from here on, the allocated memory belongs to the new list */
    MemoryContextSwitchTo(newcxt);
    dlist_init(&DatabaseList);
    if (nelems > 0)
    {
        TimestampTz current_time;
        int         millis_increment;
        avl_dbase  *dbary;
        avl_dbase  *db;
        HASH_SEQ_STATUS seq;
        int         i;
        /* put all the hash elements into an array */
        //放到數組中
        dbary = palloc(nelems * sizeof(avl_dbase));
        i = 0;
        hash_seq_init(&seq, dbhash);
        while ((db = hash_seq_search(&seq)) != NULL)
            memcpy(&(dbary[i++]), db, sizeof(avl_dbase));
        /* sort the array */
        //排序
        qsort(dbary, nelems, sizeof(avl_dbase), db_comparator);
        /*
         * Determine the time interval between databases in the schedule. If
         * we see that the configured naptime would take us to sleep times
         * lower than our min sleep time (which launcher_determine_sleep is
         * coded not to allow), silently use a larger naptime (but don't touch
         * the GUC variable).
         */
        //確定數據庫之間的調度間隔:autovacuum_naptime/數據庫個數
        millis_increment = 1000.0 * autovacuum_naptime / nelems;
        if (millis_increment <= MIN_AUTOVAC_SLEEPTIME)
            millis_increment = MIN_AUTOVAC_SLEEPTIME * 1.1;
        current_time = GetCurrentTimestamp();
        /*
         * move the elements from the array into the dllist, setting the
         * next_worker while walking the array
         * 把數組中的元素移到dllist中,在遍歷數組時設置next_worker
         */
        for (i = 0; i < nelems; i++)
        {
            avl_dbase  *db = &(dbary[i]);
            current_time = TimestampTzPlusMilliseconds(current_time,
                                                       millis_increment);
            db->adl_next_worker = current_time;
            /* later elements should go closer to the head of the list */
            dlist_push_head(&DatabaseList, &db->adl_node);
        }
    }
    /* all done, clean up memory */
    if (DatabaseListCxt != NULL)
        MemoryContextDelete(DatabaseListCxt);
    MemoryContextDelete(tmpcxt);
    DatabaseListCxt = newcxt;
    MemoryContextSwitchTo(oldcxt);
}

三、跟蹤分析

啟動gdb,設置信號處理,設置斷點

(gdb) b rebuild_database_list
Breakpoint 1 at 0x82eb2a: file autovacuum.c, line 931.
(gdb) handle SIGINT print nostop pass
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) y
Signal        Stop  Print   Pass to program Description
SIGINT        No    Yes Yes     Interrupt
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.

進入斷點

Breakpoint 1, rebuild_database_list (newdb=0) at autovacuum.c:931
931     autovac_refresh_stats();
(gdb) n
933     newcxt = AllocSetContextCreate(AutovacMemCxt,
(gdb) 
936     tmpcxt = AllocSetContextCreate(newcxt,
(gdb) 
939     oldcxt = MemoryContextSwitchTo(tmpcxt);
(gdb) 
957     hctl.keysize = sizeof(Oid);
(gdb) 
958     hctl.entrysize = sizeof(avl_dbase);
(gdb) 
959     hctl.hcxt = tmpcxt;

查看統計信息文件:pg_stat_tmp/global.stat

(gdb) p  *pgstat_stat_filename
$1 = 112 'p'
(gdb) p  pgstat_stat_filename
$2 = 0x203d7e0 "pg_stat_tmp/global.stat"
(gdb) n
960     dbhash = hash_create("db hash", 20, &hctl,  /* magic number here FIXME */
(gdb) 
###
[pg12@localhost pg_stat_tmp]$ pwd
/data/pgsql/pg121db/pg_stat_tmp
[pg12@localhost pg_stat_tmp]$ ll
total 4
-rw------- 1 pg12 pg12 237 Dec 11 16:40 global.stat
[pg12@localhost pg_stat_tmp]$

構建需處理的數據庫鏈表

964     score = 0;
(gdb) 
965     if (OidIsValid(newdb))
(gdb) p *hctl
Structure has no component named operator*.
(gdb) p hctl
$3 = {num_partitions = 140725872814104, ssize = 34131296, dsize = 32, max_dsize = 0, ffactor = 257, keysize = 4, entrysize = 40, hash = 0xc6afd3, match = 0x208cd60, keycopy = 0x0, alloc = 0x1, hcxt = 0x2090d80, 
  hctl = 0xfe3a00 <ConfigureNamesString+4864>}
(gdb) n
984     dlist_foreach(iter, &DatabaseList)
(gdb) p *DatabaseList
Structure has no component named operator*.
(gdb) p DatabaseList
$4 = {head = {prev = 0xfd9880 <DatabaseList>, next = 0xfd9880 <DatabaseList>}}
(gdb) n
1010        dblist = get_database_list();
(gdb) 
1011        foreach(cell, dblist)
(gdb) p *dblist
$5 = {type = T_List, length = 7, head = 0x2090ef8, tail = 0x2091240}
(gdb) p *dblist->head
$6 = {data = {ptr_value = 0x2090e98, int_value = 34147992, oid_value = 34147992}, next = 0x2090fb0}
(gdb) p *(Node *)dblist->head->data.ptr_value
$7 = {type = 13591}
(gdb) p *dblist->head->data.ptr_value
Attempt to dereference a generic pointer.
(gdb) n
1013            avw_dbase  *avdb = lfirst(cell);
(gdb)

如沒有統計信息,則不予處理

1019            entry = pgstat_fetch_stat_dbentry(avdb->adw_datid);
(gdb) p *avdb
$8 = {adw_datid = 13591, adw_name = 0x2090ed0 "postgres", adw_frozenxid = 479, adw_minmulti = 1, adw_entry = 0x0}
(gdb) n
1020            if (entry == NULL)
(gdb) 
1011        foreach(cell, dblist)
(gdb) 
1013            avw_dbase  *avdb = lfirst(cell);
(gdb) 
1019            entry = pgstat_fetch_stat_dbentry(avdb->adw_datid);
(gdb) p *avdb
$9 = {adw_datid = 16384, adw_name = 0x2090f90 "testdb", adw_frozenxid = 2921, adw_minmulti = 1, adw_entry = 0x0}
(gdb) step
pgstat_fetch_stat_dbentry (dbid=16384) at pgstat.c:2438
2438        backend_read_statsfile();
(gdb) step
backend_read_statsfile () at pgstat.c:5644
5644        TimestampTz min_ts = 0;
(gdb) n
5645        TimestampTz ref_ts = 0;
(gdb) 
5650        if (pgStatDBHash)
(gdb) 
5651            return;
(gdb) 
5766    }
(gdb) 
pgstat_fetch_stat_dbentry (dbid=16384) at pgstat.c:2443
2443        return (PgStat_StatDBEntry *) hash_search(pgStatDBHash,
(gdb) 
2446    }
(gdb) 
rebuild_database_list (newdb=0) at autovacuum.c:1020
1020            if (entry == NULL)
(gdb) n
1011        foreach(cell, dblist)
(gdb) 
1013            avw_dbase  *avdb = lfirst(cell);
(gdb) 
1019            entry = pgstat_fetch_stat_dbentry(avdb->adw_datid);
(gdb) 
1020            if (entry == NULL)
(gdb) 
1011        foreach(cell, dblist)
(gdb) 
1013            avw_dbase  *avdb = lfirst(cell);
(gdb) 
1019            entry = pgstat_fetch_stat_dbentry(avdb->adw_datid);
(gdb) 
1020            if (entry == NULL)
(gdb) 
1011        foreach(cell, dblist)
(gdb) 
1013            avw_dbase  *avdb = lfirst(cell);
(gdb) 
1019            entry = pgstat_fetch_stat_dbentry(avdb->adw_datid);
(gdb) 
1020            if (entry == NULL)
(gdb) 
1011        foreach(cell, dblist)
(gdb) 
1013            avw_dbase  *avdb = lfirst(cell);
(gdb) 
1019            entry = pgstat_fetch_stat_dbentry(avdb->adw_datid);
(gdb) 
1020            if (entry == NULL)
(gdb) 
1011        foreach(cell, dblist)
(gdb) 
1013            avw_dbase  *avdb = lfirst(cell);
(gdb) 
1019            entry = pgstat_fetch_stat_dbentry(avdb->adw_datid);
(gdb) 
1020            if (entry == NULL)
(gdb) 
1011        foreach(cell, dblist)
(gdb) 
1032        nelems = score;
(gdb) 
1035        MemoryContextSwitchTo(newcxt);
(gdb) n
1036        dlist_init(&DatabaseList);
(gdb)

所有數據庫都不需要處理,返回

1038        if (nelems > 0)
(gdb) p nelems
$10 = 0
(gdb) n
1089        if (DatabaseListCxt != NULL)
(gdb) 
1091        MemoryContextDelete(tmpcxt);
(gdb) 
1092        DatabaseListCxt = newcxt;
(gdb) 
1093        MemoryContextSwitchTo(oldcxt);
(gdb) 
1094    }
(gdb) 
AutoVacLauncherMain (argc=0, argv=0x0) at autovacuum.c:625
625     while (!got_SIGTERM)
(gdb)

“怎么理解PostgreSQL的后臺進程autovacuum”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

乐昌市| 临泽县| 南木林县| 雅安市| 安丘市| 湘阴县| 上思县| 集贤县| 巫山县| 卢湾区| 安顺市| 房山区| 浠水县| 凉山| 洪江市| 密云县| 南皮县| 平阳县| 竹山县| 渭南市| 长武县| 修文县| 台山市| 雅安市| 安丘市| 高安市| 金湖县| 保德县| 北川| 武冈市| 龙泉市| 紫云| 岳阳县| 科技| 微山县| 额济纳旗| 弥勒县| 辽阳县| 富宁县| 松桃| 塔河县|