91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

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

PostgreSQL 源碼解讀(236)- 后臺進程#14(autovacuum進程#2)

發布時間:2020-08-08 14:10:54 來源:ITPUB博客 閱讀:354 作者:husthxd 欄目:關系型數據庫

本節簡單介紹了PostgreSQL的后臺進程:autovacuum,主要分析了launch_worker函數的實現邏輯。

一、數據結構

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;

FullTransactionId
64 bit的事務ID

/*
 * A 64 bit value that contains an epoch and a TransactionId.  This is
 * wrapped in a struct to prevent implicit conversion to/from TransactionId.
 * Not all values represent valid normal XIDs.
 * 保護epoch和TransactionId的64 bit值.封裝在結構體中避免與事務ID的隱式轉換.并不是所有的值都表示有效的普通xid。
 */
typedef struct FullTransactionId
{
    uint64      value;
} FullTransactionId;

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;

WorkerInfo

/*
 * Structure to hold info passed by _beginthreadex() to the function it calls
 * via its single allowed argument.
 */
typedef struct
{
    ArchiveHandle *AH;          /* master database connection */
    ParallelSlot *slot;         /* this worker's parallel slot */
} WorkerInfo;

二、源碼解讀

主要的實現邏輯在do_start_worker中

/*
 * launch_worker
 *
 * Wrapper for starting a worker from the launcher.  Besides actually starting
 * it, update the database list to reflect the next time that another one will
 * need to be started on the selected database.  The actual database choice is
 * left to do_start_worker.
 * 從autovacuum launcher啟動worker的封裝器.
 * 除了實際啟動它之外,還要更新數據庫鏈表,以反映下一次需要在選定的數據庫上啟動另一個worker時的情況。
 *   實際的數據庫選擇留給do_start_worker。
 *
 * This routine is also expected to insert an entry into the database list if
 * the selected database was previously absent from the list.
 * 這段例程同樣希望在數據庫鏈表中插入一個新的條目,如果選定的數據庫先前在鏈表中出現.
 */
static void
launch_worker(TimestampTz now)
{
    Oid         dbid;
    dlist_iter  iter;
    dbid = do_start_worker();
    if (OidIsValid(dbid))
    {
        bool        found = false;
        /*
         * Walk the database list and update the corresponding entry.  If the
         * database is not on the list, we'll recreate the list.
         * 遍歷數據庫鏈表,更新相應的條目.
         * 如果數據庫不在鏈表鏈表中,重建鏈表.
         */
        dlist_foreach(iter, &DatabaseList)
        {
            avl_dbase  *avdb = dlist_container(avl_dbase, adl_node, iter.cur);
            if (avdb->adl_datid == dbid)
            {
                found = true;
                /*
                 * add autovacuum_naptime seconds to the current time, and use
                 * that as the new "next_worker" field for this database.
                 * 在當前時間上增加autovacuum_naptime,
                 *   并為該數據庫使用該時間作為新的next_worker字段的值.
                 */
                avdb->adl_next_worker =
                    TimestampTzPlusMilliseconds(now, autovacuum_naptime * 1000);
                dlist_move_head(&DatabaseList, iter.cur);
                break;
            }
        }
        /*
         * If the database was not present in the database list, we rebuild
         * the list.  It's possible that the database does not get into the
         * list anyway, for example if it's a database that doesn't have a
         * pgstat entry, but this is not a problem because we don't want to
         * schedule workers regularly into those in any case.
         * 如果數據庫不在數據庫鏈表中,重建鏈表.
         * 有可能該數據庫沒有進入過鏈表中,比如,該數據庫沒有pgstat條目入口,
         *   但這不是一個問題,因為我們不希望在任何情況調度到這些數據庫上面.
         */
        if (!found)
            rebuild_database_list(dbid);
    }
}

do_start_worker
選擇一個DB,算法如下:
選擇最近最小清理的DB,或者需要清理以防止XID回卷導致數據丟失的DB.
如果存在XID回卷風險的DB,那么選擇datfrozenxid最老的DB,而不管該DB做了多少次autovacuum.
自動忽略沒有連接過(統計信息為空)的DB.

/*
 * do_start_worker
 *
 * Bare-bones procedure for starting an autovacuum worker from the launcher.
 * It determines what database to work on, sets up shared memory stuff and
 * signals postmaster to start the worker.  It fails gracefully if invoked when
 * autovacuum_workers are already active.
 * 啟動autovacuum worker。
 * 確定處理哪個庫,配置共享內存并通知postmaster啟動worker。
 * 如autovacuum_workers已處于活動狀態,則啟動失敗。
 *
 * Return value is the OID of the database that the worker is going to process,
 * or InvalidOid if no worker was actually started.
 * 返回正在處理的數據庫OID,如worker啟動不成功,則返回InvalidOid。
 */
static Oid
do_start_worker(void)
{
    List       *dblist;//數據庫鏈表
    ListCell   *cell;//臨時變量
    //typedef uint32 TransactionId;
    TransactionId xidForceLimit;//事務id,無符號32bit整型
    MultiXactId multiForceLimit;//
    bool        for_xid_wrap;
    bool        for_multi_wrap;
    avw_dbase  *avdb;
    TimestampTz current_time;//當前時間
    bool        skipit = false;//是否跳過?
    Oid         retval = InvalidOid;//返回的數據庫OID
    MemoryContext tmpcxt,
                oldcxt;//內存上下文
    /* return quickly when there are no free workers */
    //如無空閑的worker(AutoVacuumShmem數據結構維護),則退出
    LWLockAcquire(AutovacuumLock, LW_SHARED);
    if (dlist_is_empty(&AutoVacuumShmem->av_freeWorkers))
    {
        LWLockRelease(AutovacuumLock);
        return InvalidOid;
    }
    LWLockRelease(AutovacuumLock);
    /*
     * Create and switch to a temporary context to avoid leaking the memory
     * allocated for the database list.
     * 內存上下文切換
     */
    tmpcxt = AllocSetContextCreate(CurrentMemoryContext,
                                   "Start worker tmp cxt",
                                   ALLOCSET_DEFAULT_SIZES);
    oldcxt = MemoryContextSwitchTo(tmpcxt);
    /* use fresh stats */
    //統計信息刷新
    autovac_refresh_stats();
    /* Get a list of databases */
    //獲取數據庫鏈表
    dblist = get_database_list();
    /*
     * Determine the oldest datfrozenxid/relfrozenxid that we will allow to
     * pass without forcing a vacuum.  (This limit can be tightened for
     * particular tables, but not loosened.)
     * 確定最老的datfrozenxid/relfrozenxid,用以確定是否需要強制vacuum
     */
    recentXid = ReadNewTransactionId();
    xidForceLimit = recentXid - autovacuum_freeze_max_age;
    /* ensure it's a "normal" XID, else TransactionIdPrecedes misbehaves */
    /* this can cause the limit to go backwards by 3, but that's OK */
    //#define FirstNormalTransactionId  ((TransactionId) 3)
    //小于3(常規的XID),則減去3
    if (xidForceLimit < FirstNormalTransactionId)
        xidForceLimit -= FirstNormalTransactionId;
    /* Also determine the oldest datminmxid we will consider. */
    //確定需要考慮的最老的datminmxid
    //從MultiXactState->nextMXact中獲取MultiXactId
    recentMulti = ReadNextMultiXactId();
    multiForceLimit = recentMulti - MultiXactMemberFreezeThreshold();
    if (multiForceLimit < FirstMultiXactId)
        multiForceLimit -= FirstMultiXactId;
    /*
     * Choose a database to connect to.  We pick the database that was least
     * recently auto-vacuumed, or one that needs vacuuming to prevent Xid
     * wraparound-related data loss.  If any db at risk of Xid wraparound is
     * found, we pick the one with oldest datfrozenxid, independently of
     * autovacuum times; similarly we pick the one with the oldest datminmxid
     * if any is in MultiXactId wraparound.  Note that those in Xid wraparound
     * danger are given more priority than those in multi wraparound danger.
     *
     * Note that a database with no stats entry is not considered, except for
     * Xid wraparound purposes.  The theory is that if no one has ever
     * connected to it since the stats were last initialized, it doesn't need
     * vacuuming.
     *
     * XXX This could be improved if we had more info about whether it needs
     * vacuuming before connecting to it.  Perhaps look through the pgstats
     * data for the database's tables?  One idea is to keep track of the
     * number of new and dead tuples per database in pgstats.  However it
     * isn't clear how to construct a metric that measures that and not cause
     * starvation for less busy databases.
     * 選擇一個DB.
     * 算法:選擇最近最小清理的DB,或者需要清理以防止XID回卷導致數據丟失的DB.
     *      如果存在XID回卷風險的DB,那么選擇datfrozenxid最老的DB,而不管該DB做了多少次autovacuum.
     *      自動忽略沒有連接過(統計信息為空)的DB.
     */
    avdb = NULL;//待清理的DB
    for_xid_wrap = false;//xid回卷
    for_multi_wrap = false;
    current_time = GetCurrentTimestamp();//當前時間
    foreach(cell, dblist)//循環db鏈表
    {
        avw_dbase  *tmp = lfirst(cell);
        dlist_iter  iter;
        /* Check to see if this one is at risk of wraparound */
        //判斷是否存在回卷風險?
        //TransactionIdPrecedes --- is id1 logically < id2?
        if (TransactionIdPrecedes(tmp->adw_frozenxid, xidForceLimit))
        {
            if (avdb == NULL ||
                TransactionIdPrecedes(tmp->adw_frozenxid,
                                      avdb->adw_frozenxid))
                avdb = tmp;//選擇較舊的那個
            for_xid_wrap = true;
            continue;
        }
        else if (for_xid_wrap)
            continue;           /* ignore not-at-risk DBs */
        else if (MultiXactIdPrecedes(tmp->adw_minmulti, multiForceLimit))
        {
            if (avdb == NULL ||
                MultiXactIdPrecedes(tmp->adw_minmulti, avdb->adw_minmulti))
                avdb = tmp;
            for_multi_wrap = true;
            continue;
        }
        else if (for_multi_wrap)
            continue;           /* ignore not-at-risk DBs */
        /* Find pgstat entry if any */
        tmp->adw_entry = pgstat_fetch_stat_dbentry(tmp->adw_datid);
        /*
         * Skip a database with no pgstat entry; it means it hasn't seen any
         * activity.
         * 如無統計信息,跳過
         */
        if (!tmp->adw_entry)
            continue;
        /*
         * Also, skip a database that appears on the database list as having
         * been processed recently (less than autovacuum_naptime seconds ago).
         * We do this so that we don't select a database which we just
         * selected, but that pgstat hasn't gotten around to updating the last
         * autovacuum time yet.
         * 跳過出現在數據庫鏈表中已處理過的DB(先前小于autovacuum_naptime秒)
         * 執行該操作是為了避免選擇剛才才選擇的DB
         */
        skipit = false;
        dlist_reverse_foreach(iter, &DatabaseList)
        {
            avl_dbase  *dbp = dlist_container(avl_dbase, adl_node, iter.cur);
            if (dbp->adl_datid == tmp->adw_datid)
            {
                /*
                 * Skip this database if its next_worker value falls between
                 * the current time and the current time plus naptime.
                 * 未超過時(naptime定義)
                 */
                if (!TimestampDifferenceExceeds(dbp->adl_next_worker,
                                                current_time, 0) &&
                    !TimestampDifferenceExceeds(current_time,
                                                dbp->adl_next_worker,
                                                autovacuum_naptime * 1000))
                    skipit = true;
                break;
            }
        }
        if (skipit)
            continue;
        /*
         * Remember the db with oldest autovac time.  (If we are here, both
         * tmp->entry and db->entry must be non-null.)
         */
        if (avdb == NULL ||
            tmp->adw_entry->last_autovac_time < avdb->adw_entry->last_autovac_time)
            avdb = tmp;
    }
    /* Found a database -- process it */
    if (avdb != NULL)
    {
        WorkerInfo  worker;
        dlist_node *wptr;
        LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
        /*
         * Get a worker entry from the freelist.  We checked above, so there
         * really should be a free slot.
         * 從空閑鏈表中獲取一個worker
         */
        wptr = dlist_pop_head_node(&AutoVacuumShmem->av_freeWorkers);
        worker = dlist_container(WorkerInfoData, wi_links, wptr);
        worker->wi_dboid = avdb->adw_datid;
        worker->wi_proc = NULL;
        worker->wi_launchtime = GetCurrentTimestamp();
        AutoVacuumShmem->av_startingWorker = worker;
        LWLockRelease(AutovacuumLock);
        SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER);
        retval = avdb->adw_datid;
    }
    else if (skipit)
    {
        /*
         * If we skipped all databases on the list, rebuild it, because it
         * probably contains a dropped database.
         */
        rebuild_database_list(InvalidOid);
    }
    MemoryContextSwitchTo(oldcxt);
    MemoryContextDelete(tmpcxt);
    return retval;
}
/*
 * For callers that just need the XID part of the next transaction ID.
 */
static inline TransactionId
ReadNewTransactionId(void)
{
    return XidFromFullTransactionId(ReadNextFullTransactionId());
}
#define XidFromFullTransactionId(x)     ((uint32) (x).value)
/*
 * Read nextFullXid but don't allocate it.
 */
FullTransactionId
ReadNextFullTransactionId(void)
{
    FullTransactionId fullXid;
    LWLockAcquire(XidGenLock, LW_SHARED);
    fullXid = ShmemVariableCache->nextFullXid;
    LWLockRelease(XidGenLock);
    return fullXid;
}

三、跟蹤分析

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

(gdb) handle SIGINT print nostop pass
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) 
Please answer y or n.
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) b autovacuum.c:launch_worker
Breakpoint 1 at 0x82f3e7: file autovacuum.c, line 1338.
(gdb) b autovacuum.c:783
Breakpoint 2 at 0x82e8f0: file autovacuum.c, line 783.
(gdb) c
Continuing.

在其他session執行更新等操作

[pg12@localhost test]$ psql -c "update tbl set id = 1;"
Expanded display is used automatically.
UPDATE 2000000
[pg12@localhost test]$ psql -c "update t1 set id = 1;"
Expanded display is used automatically.
UPDATE 20000
[pg12@localhost test]$ psql -c "update t2 set id = 1;"
Expanded display is used automatically.
UPDATE 10000
[pg12@localhost test]$ psql -c "select txid_current();"
Expanded display is used automatically.
 txid_current 
--------------
         2917
(1 row)

60s后在gdb console中continue

Breakpoint 2, AutoVacLauncherMain (argc=0, argv=0x0) at autovacuum.c:783
783         if (dlist_is_empty(&DatabaseList))
(gdb) n
804             avdb = dlist_tail_element(avl_dbase, adl_node, &DatabaseList);
(gdb) n
810             if (TimestampDifferenceExceeds(avdb->adl_next_worker,
(gdb) 
812                 launch_worker(current_time);
(gdb) p *avdb
$1 = {adl_datid = 16384, adl_next_worker = 628852948486950, adl_score = 0, adl_node = {
    prev = 0xfd9880 <DatabaseList>, next = 0xfd9880 <DatabaseList>}}
(gdb) step
Breakpoint 1, launch_worker (now=628853296722794) at autovacuum.c:1338
1338        dbid = do_start_worker();

進入do_start_worker

(gdb) step
do_start_worker () at autovacuum.c:1128
1128        bool        skipit = false;
(gdb) n
1129        Oid         retval = InvalidOid;
(gdb) 
1134        LWLockAcquire(AutovacuumLock, LW_SHARED);
(gdb) 
1135        if (dlist_is_empty(&AutoVacuumShmem->av_freeWorkers))

查看AutoVacuumShmem結構體

(gdb) p *AutoVacuumShmem
$2 = {av_signal = {0, 0}, av_launcherpid = 5476, av_freeWorkers = {head = {prev = 0x7f8ccf1a4938, 
      next = 0x7f8ccf1a49b8}}, av_runningWorkers = {head = {prev = 0x7f8ccf1a3520, next = 0x7f8ccf1a3520}}, 
  av_startingWorker = 0x0, av_workItems = {{avw_type = AVW_BRINSummarizeRange, avw_used = false, 
      avw_active = false, avw_database = 0, avw_relation = 0, avw_blockNumber = 0} <repeats 256 times>}}
(gdb) n
1140        LWLockRelease(AutovacuumLock);
(gdb) p AutoVacuumShmem->av_runningWorkers
$3 = {head = {prev = 0x7f8ccf1a3520, next = 0x7f8ccf1a3520}}
(gdb) n

找到需要vacuum的database

1146        tmpcxt = AllocSetContextCreate(CurrentMemoryContext,
(gdb) 
1149        oldcxt = MemoryContextSwitchTo(tmpcxt);
(gdb) 
1152        autovac_refresh_stats();
(gdb) n
1155        dblist = get_database_list();
(gdb) 
1162        recentXid = ReadNewTransactionId();
(gdb) p *dblist
$8 = {type = T_List, length = 5, head = 0x2382d48, tail = 0x2382f90}
(gdb) n
1163        xidForceLimit = recentXid - autovacuum_freeze_max_age;
(gdb) p recentXid
$9 = 2917
(gdb) p autovacuum_freeze_max_age
$10 = 200000000
(gdb) n
1166        if (xidForceLimit < FirstNormalTransactionId)
(gdb) p xidForceLimit
$11 = 4094970213
(gdb) p FirstNormalTransactionId
$12 = 3
(gdb) n
1170        recentMulti = ReadNextMultiXactId();
(gdb) 
1171        multiForceLimit = recentMulti - MultiXactMemberFreezeThreshold();
(gdb) 
1172        if (multiForceLimit < FirstMultiXactId)
(gdb) p recentMulti
$13 = 1
(gdb) p MultiXactMemberFreezeThreshold()
$14 = 400000000
(gdb) n
1196        avdb = NULL;
(gdb) 
1197        for_xid_wrap = false;
(gdb) 
1198        for_multi_wrap = false;
(gdb) 
1199        current_time = GetCurrentTimestamp();
(gdb) 
1200        foreach(cell, dblist)
(gdb) 
1202            avw_dbase  *tmp = lfirst(cell);
(gdb) 
1206            if (TransactionIdPrecedes(tmp->adw_frozenxid, xidForceLimit))
(gdb) p *tmp --> 這是postgres數據庫
$15 = {adw_datid = 13591, adw_name = 0x2382d20 "postgres", adw_frozenxid = 479, adw_minmulti = 1, 
  adw_entry = 0x0}
(gdb) n
1215            else if (for_xid_wrap)
(gdb) 
1217            else if (MultiXactIdPrecedes(tmp->adw_minmulti, multiForceLimit))
(gdb) 
1225            else if (for_multi_wrap)
(gdb) 
1229            tmp->adw_entry = pgstat_fetch_stat_dbentry(tmp->adw_datid);
(gdb) 
1235            if (!tmp->adw_entry)
(gdb) 
1236                continue;
(gdb) 
1200        foreach(cell, dblist)
(gdb) 
1202            avw_dbase  *tmp = lfirst(cell);
(gdb) 
1206            if (TransactionIdPrecedes(tmp->adw_frozenxid, xidForceLimit))
(gdb) p *tmp --> 這是testdb數據庫
$16 = {adw_datid = 16384, adw_name = 0x2382de0 "testdb", adw_frozenxid = 531, adw_minmulti = 1, adw_entry = 0x0}
(gdb) p tmp->adw_frozenxid
$17 = 531
(gdb) p xidForceLimit
$18 = 4094970213
(gdb) n
1215            else if (for_xid_wrap)
(gdb) 
1217            else if (MultiXactIdPrecedes(tmp->adw_minmulti, multiForceLimit))
(gdb) 
1225            else if (for_multi_wrap)
(gdb) 
1229            tmp->adw_entry = pgstat_fetch_stat_dbentry(tmp->adw_datid);
(gdb) 
1235            if (!tmp->adw_entry)
(gdb) 
1245            skipit = false;
(gdb) 
1247            dlist_reverse_foreach(iter, &DatabaseList)
(gdb) 
1249                avl_dbase  *dbp = dlist_container(avl_dbase, adl_node, iter.cur);
(gdb) 
1251                if (dbp->adl_datid == tmp->adw_datid)
(gdb) 
1257                    if (!TimestampDifferenceExceeds(dbp->adl_next_worker,
(gdb) 
1267            if (skipit)
(gdb) 
1274            if (avdb == NULL ||
(gdb) 
1276                avdb = tmp;
(gdb) n
1200        foreach(cell, dblist)
(gdb) 
1202            avw_dbase  *tmp = lfirst(cell);
(gdb) 
1206            if (TransactionIdPrecedes(tmp->adw_frozenxid, xidForceLimit))
(gdb) 
1215            else if (for_xid_wrap)
(gdb) p *tmp
$19 = {adw_datid = 1, adw_name = 0x2382e60 "template1", adw_frozenxid = 479, adw_minmulti = 1, adw_entry = 0x0}
(gdb) n
1217            else if (MultiXactIdPrecedes(tmp->adw_minmulti, multiForceLimit))
(gdb) 
1225            else if (for_multi_wrap)
(gdb) 
1229            tmp->adw_entry = pgstat_fetch_stat_dbentry(tmp->adw_datid);
(gdb) 
1235            if (!tmp->adw_entry)
(gdb) 
1236                continue; --> 沒有統計信息的,忽略
(gdb) 
1200        foreach(cell, dblist)
(gdb) 
1202            avw_dbase  *tmp = lfirst(cell);
(gdb) 
1206            if (TransactionIdPrecedes(tmp->adw_frozenxid, xidForceLimit))
(gdb) 
1215            else if (for_xid_wrap)
(gdb) 
1217            else if (MultiXactIdPrecedes(tmp->adw_minmulti, multiForceLimit))
(gdb) 
1225            else if (for_multi_wrap)
(gdb) 
1229            tmp->adw_entry = pgstat_fetch_stat_dbentry(tmp->adw_datid);
(gdb) 
1235            if (!tmp->adw_entry)
(gdb) 
1236                continue;
(gdb) 
1200        foreach(cell, dblist)
(gdb) 
1202            avw_dbase  *tmp = lfirst(cell);
(gdb) 
1206            if (TransactionIdPrecedes(tmp->adw_frozenxid, xidForceLimit))
(gdb) 
1215            else if (for_xid_wrap)
(gdb) 
1217            else if (MultiXactIdPrecedes(tmp->adw_minmulti, multiForceLimit))
(gdb) 
1225            else if (for_multi_wrap)
(gdb) 
1229            tmp->adw_entry = pgstat_fetch_stat_dbentry(tmp->adw_datid);
(gdb) 
1235            if (!tmp->adw_entry)
(gdb) 
1236                continue;
(gdb) 
1200        foreach(cell, dblist)
(gdb)

完成db遍歷,找到了需要處理的數據庫->testdb,接下來就是找空閑worker并啟動此worker執行vacuum

1280        if (avdb != NULL)
(gdb) 
1285            LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
(gdb) 
1291            wptr = dlist_pop_head_node(&AutoVacuumShmem->av_freeWorkers);
(gdb) 
1293            worker = dlist_container(WorkerInfoData, wi_links, wptr);
(gdb) p *wptr
$20 = {prev = 0x7f8ccf1a3510, next = 0x7f8ccf1a4978}
(gdb) n
1294            worker->wi_dboid = avdb->adw_datid;
(gdb) p *worker
$21 = {wi_links = {prev = 0x7f8ccf1a3510, next = 0x7f8ccf1a4978}, wi_dboid = 0, wi_tableoid = 0, wi_proc = 0x0, 
  wi_launchtime = 0, wi_dobalance = false, wi_sharedrel = false, wi_cost_delay = 0, wi_cost_limit = 0, 
  wi_cost_limit_base = 0}
(gdb) n
1295            worker->wi_proc = NULL;
(gdb) 
1296            worker->wi_launchtime = GetCurrentTimestamp();
(gdb) 
1298            AutoVacuumShmem->av_startingWorker = worker;
(gdb) 
1300            LWLockRelease(AutovacuumLock);
(gdb) 
1302            SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER);
(gdb) p *AutoVacuumShmem
$22 = {av_signal = {0, 0}, av_launcherpid = 5476, av_freeWorkers = {head = {prev = 0x7f8ccf1a4938, 
      next = 0x7f8ccf1a4978}}, av_runningWorkers = {head = {prev = 0x7f8ccf1a3520, next = 0x7f8ccf1a3520}}, 
  av_startingWorker = 0x7f8ccf1a49b8, av_workItems = {{avw_type = AVW_BRINSummarizeRange, avw_used = false, 
      avw_active = false, avw_database = 0, avw_relation = 0, avw_blockNumber = 0} <repeats 256 times>}}
(gdb) n
1304            retval = avdb->adw_datid;
(gdb) 
Program received signal SIGUSR2, User defined signal 2.
do_start_worker () at autovacuum.c:1304
1304            retval = avdb->adw_datid;
(gdb) 
avl_sigusr2_handler (postgres_signal_arg=32764) at autovacuum.c:1405
1405    {
(gdb)

DONE!

四、參考資料

PG Source Code

向AI問一下細節

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

AI

丰县| 酉阳| 津南区| 宁强县| 平乡县| 友谊县| 广昌县| 峡江县| 汝州市| 南昌市| 崇明县| 广宗县| 比如县| 宝兴县| 怀集县| 临邑县| 玉门市| 万盛区| 卓资县| 茶陵县| 乌拉特前旗| 历史| 阳原县| 肇庆市| 巴彦县| 班戈县| 平遥县| 余江县| 云阳县| 江西省| 铜鼓县| 紫阳县| 余姚市| 玉田县| 崇礼县| 吉林省| 阳朔县| 六安市| 晋城| 南召县| 德惠市|