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

溫馨提示×

溫馨提示×

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

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

PostgreSQL的vacuum過程中heap_vacuum_rel函數分析

發布時間:2021-11-09 16:25:05 來源:億速云 閱讀:133 作者:iii 欄目:關系型數據庫

這篇文章主要介紹“PostgreSQL的vacuum過程中heap_vacuum_rel函數分析”,在日常操作中,相信很多人在PostgreSQL的vacuum過程中heap_vacuum_rel函數分析問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”PostgreSQL的vacuum過程中heap_vacuum_rel函數分析”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

本節簡單介紹了PostgreSQL手工執行vacuum的實現邏輯,主要分析了ExecVacuum->vacuum->vacuum_rel->heap_vacuum_rel函數的實現邏輯。

一、數據結構

宏定義
Vacuum和Analyze命令選項

/* ----------------------
 *      Vacuum and Analyze Statements
 *      Vacuum和Analyze命令選項
 * 
 * Even though these are nominally two statements, it's convenient to use
 * just one node type for both.  Note that at least one of VACOPT_VACUUM
 * and VACOPT_ANALYZE must be set in options.
 * 雖然在這里有兩種不同的語句,但只需要使用統一的Node類型即可.
 * 注意至少VACOPT_VACUUM/VACOPT_ANALYZE在選項中設置.
 * ----------------------
 */
typedef enum VacuumOption
{
    VACOPT_VACUUM = 1 << 0,     /* do VACUUM */
    VACOPT_ANALYZE = 1 << 1,    /* do ANALYZE */
    VACOPT_VERBOSE = 1 << 2,    /* print progress info */
    VACOPT_FREEZE = 1 << 3,     /* FREEZE option */
    VACOPT_FULL = 1 << 4,       /* FULL (non-concurrent) vacuum */
    VACOPT_SKIP_LOCKED = 1 << 5,    /* skip if cannot get lock */
    VACOPT_SKIPTOAST = 1 << 6,  /* don't process the TOAST table, if any */
    VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7   /* don't skip any pages */
} VacuumOption;

VacuumStmt
存儲vacuum命令的option&Relation鏈表

typedef struct VacuumStmt
{
    NodeTag     type;//Tag
    //VacuumOption位標記
    int         options;        /* OR of VacuumOption flags */
    //VacuumRelation鏈表,如為NIL-->所有Relation.
    List       *rels;           /* list of VacuumRelation, or NIL for all */
} VacuumStmt;

VacuumParams
vacuum命令參數

/*
 * Parameters customizing behavior of VACUUM and ANALYZE.
 * 客戶端調用VACUUM/ANALYZE時的定制化參數
 */
typedef struct VacuumParams
{
    //最小freeze age,-1表示使用默認
    int         freeze_min_age; /* min freeze age, -1 to use default */
    //掃描整個table的freeze age
    int         freeze_table_age;   /* age at which to scan whole table */
    //最小的multixact freeze age,-1表示默認
    int         multixact_freeze_min_age;   /* min multixact freeze age, -1 to
                                             * use default */
    //掃描全表的freeze age,-1表示默認
    int         multixact_freeze_table_age; /* multixact age at which to scan
                                             * whole table */
    //是否強制wraparound?
    bool        is_wraparound;  /* force a for-wraparound vacuum */
    //以毫秒為單位的最小執行閾值
    int         log_min_duration;   /* minimum execution threshold in ms at
                                     * which  verbose logs are activated, -1
                                     * to use default */
} VacuumParams;

VacuumRelation
VACUUM/ANALYZE命令的目標表信息

/*
 * Info about a single target table of VACUUM/ANALYZE.
 * VACUUM/ANALYZE命令的目標表信息.
 *  
 * If the OID field is set, it always identifies the table to process.
 * Then the relation field can be NULL; if it isn't, it's used only to report
 * failure to open/lock the relation.
 * 如設置了OID字段,該值通常是將要處理的數據表.
 * 那么關系字段可以為空;如果不是,則僅用于報告未能打開/鎖定關系。
 */
typedef struct VacuumRelation
{
    NodeTag     type;
    RangeVar   *relation;       /* table name to process, or NULL */
    Oid         oid;            /* table's OID; InvalidOid if not looked up */
    List       *va_cols;        /* list of column names, or NIL for all */
} VacuumRelation;

BufferAccessStrategy
Buffer訪問策略對象

/*
 * Buffer identifiers.
 * Buffer標識符
 * 
 * Zero is invalid, positive is the index of a shared buffer (1..NBuffers),
 * negative is the index of a local buffer (-1 .. -NLocBuffer).
 * 0表示無效,正整數表示共享buffer的索引(1..N),
 *   負數是本地buffer的索引(-1..-N)
 */
typedef int Buffer;
#define InvalidBuffer   0
/*
 * Buffer access strategy objects.
 * Buffer訪問策略對象
 *
 * BufferAccessStrategyData is private to freelist.c
 * BufferAccessStrategyData對freelist.c來說是私有的
 */
typedef struct BufferAccessStrategyData *BufferAccessStrategy;
 /*
 * Private (non-shared) state for managing a ring of shared buffers to re-use.
 * This is currently the only kind of BufferAccessStrategy object, but someday
 * we might have more kinds.
 * 私有狀態,用于管理可重用的環形緩沖區.
 * 目前只有這么一種緩沖區訪問策略對象,但未來某一天可以擁有更多.
 */
typedef struct BufferAccessStrategyData
{
    /* Overall strategy type */
    //全局的策略類型
    BufferAccessStrategyType btype;
    /* Number of elements in buffers[] array */
    //buffers[]中的元素個數
    int         ring_size;
    /*
     * Index of the "current" slot in the ring, ie, the one most recently
     * returned by GetBufferFromRing.
     * 環形緩沖區中當前slot的索引,最近訪問的通過函數GetBufferFromRing返回.
     */
    int         current;
    /*
     * True if the buffer just returned by StrategyGetBuffer had been in the
     * ring already.
     * 如正好通過StrategyGetBuffer返回的buffer已在環形緩沖區中,則返回T
     */
    bool        current_was_in_ring;
    /*
     * Array of buffer numbers.  InvalidBuffer (that is, zero) indicates we
     * have not yet selected a buffer for this ring slot.  For allocation
     * simplicity this is palloc'd together with the fixed fields of the
     * struct.
     * buffer編號數組.
     * InvalidBuffer(即:0)表示我們還沒有為該slot選擇buffer.
     * 為了分配的簡單性,這是palloc'd與結構的固定字段。
     */
    Buffer      buffers[FLEXIBLE_ARRAY_MEMBER];
}           BufferAccessStrategyData;
//Block結構體指針
typedef void *Block;
/* Possible arguments for GetAccessStrategy() */
//GetAccessStrategy()函數可取值的參數
typedef enum BufferAccessStrategyType
{
    //常規的隨機訪問
    BAS_NORMAL,                 /* Normal random access */
    //大規模的只讀掃描
    BAS_BULKREAD,               /* Large read-only scan (hint bit updates are
                                 * ok) */
    //大量的多塊寫(如 COPY IN)
    BAS_BULKWRITE,              /* Large multi-block write (e.g. COPY IN) */
    //VACUUM
    BAS_VACUUM                  /* VACUUM */
} BufferAccessStrategyType;

LVRelStats

typedef struct LVRelStats
{
    /* hasindex = true means two-pass strategy; false means one-pass */
    //T表示two-pass strategy,F表示one-pass strategy
    bool        hasindex;
    /* Overall statistics about rel */
    //rel的全局統計信息
    //pg_class.relpages的上一個值
    BlockNumber old_rel_pages;  /* previous value of pg_class.relpages */
    //pages的總數
    BlockNumber rel_pages;      /* total number of pages */
    //掃描的pages
    BlockNumber scanned_pages;  /* number of pages we examined */
    //由于pin跳過的pages
    BlockNumber pinskipped_pages;   /* # of pages we skipped due to a pin */
    //跳過的frozen pages
    BlockNumber frozenskipped_pages;    /* # of frozen pages we skipped */
    //計算其元組的pages
    BlockNumber tupcount_pages; /* pages whose tuples we counted */
    //pg_class.reltuples的前值
    double      old_live_tuples;    /* previous value of pg_class.reltuples */
    //新估算的總元組數
    double      new_rel_tuples; /* new estimated total # of tuples */
    //新估算的存活元組數
    double      new_live_tuples;    /* new estimated total # of live tuples */
    //新估算的廢棄元組數
    double      new_dead_tuples;    /* new estimated total # of dead tuples */
    //已清除的pages
    BlockNumber pages_removed;
    //已刪除的tuples
    double      tuples_deleted;
    //實際上是非空page + 1
    BlockNumber nonempty_pages; /* actually, last nonempty page + 1 */
    /* List of TIDs of tuples we intend to delete */
    /* NB: this list is ordered by TID address */
    //將要刪除的元組TIDs鏈表
    //注意:該鏈表已使用TID地址排序
    //當前的入口/條目數
    int         num_dead_tuples;    /* current # of entries */
    //數組中已分配的slots(最大已廢棄元組數)
    int         max_dead_tuples;    /* # slots allocated in array */
    //ItemPointerData數組
    ItemPointer dead_tuples;    /* array of ItemPointerData */
    //掃描的索引數
    int         num_index_scans;
    //最后被清除的事務ID
    TransactionId latestRemovedXid;
    //是否存在waiter?
    bool        lock_waiter_detected;
} LVRelStats;

PGRUsage
pg_rusage_init/pg_rusage_show的狀態結構體

/* State structure for pg_rusage_init/pg_rusage_show */
//pg_rusage_init/pg_rusage_show的狀態結構體
typedef struct PGRUsage
{
    struct timeval tv;
    struct rusage ru;
} PGRUsage;
struct rusage
{
    struct timeval ru_utime;    /* user time used */
    struct timeval ru_stime;    /* system time used */
};
struct timeval
{
__time_t tv_sec;        /* 秒數.Seconds. */
__suseconds_t tv_usec;  /* 微秒數.Microseconds-->這個英文注釋有問題. */
};

二、源碼解讀

heap_vacuum_rel() — 為heap relation執行VACUUM
大體邏輯如下:
1.初始化相關變量,如本地變量/日志記錄級別/訪問策略等
2.調用vacuum_set_xid_limits計算最老的xmin和凍結截止點
3.判斷是否執行全表(不跳過pages)掃描,標記變量為aggressive
4.初始化統計信息結構體vacrelstats
5.打開索引,執行函數lazy_scan_heap進行vacuuming,關閉索引
6.更新pg_class中的統計信息
7.收尾工作

/*
 *  heap_vacuum_rel() -- perform VACUUM for one heap relation
 *  heap_vacuum_rel() -- 為heap relation執行VACUUM
 * 
 *      This routine vacuums a single heap, cleans out its indexes, and
 *      updates its relpages and reltuples statistics.
 *      該處理過程vacuum一個單獨的heap,清除索引并更新relpages和reltuples統計信息.
 *
 *      At entry, we have already established a transaction and opened
 *      and locked the relation.
 *      在該調用入口,我們已經給創建了事務并且已經打開&鎖定了relation.
 */
void
heap_vacuum_rel(Relation onerel, int options, VacuumParams *params,
                BufferAccessStrategy bstrategy)
{
    LVRelStats *vacrelstats;//統計信息
    Relation   *Irel;//關系指針
    int         nindexes;
    PGRUsage    ru0;//狀態結構體
    TimestampTz starttime = 0;//時間戳
    long        secs;//秒數
    int         usecs;//微秒數
    double      read_rate,//讀比率
                write_rate;//寫比率
    //是否掃描所有未凍結的pages?
    bool        aggressive;     /* should we scan all unfrozen pages? */
    //實際上是否掃描了所有這樣的pages?
    bool        scanned_all_unfrozen;   /* actually scanned all such pages? */
    TransactionId xidFullScanLimit;
    MultiXactId mxactFullScanLimit;
    BlockNumber new_rel_pages;
    BlockNumber new_rel_allvisible;
    double      new_live_tuples;
    TransactionId new_frozen_xid;
    MultiXactId new_min_multi;
    Assert(params != NULL);
    /* measure elapsed time iff autovacuum logging requires it */
    //如autovacuum日志記錄需要,則測量耗費的時間
    if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
    {
        pg_rusage_init(&ru0);
        starttime = GetCurrentTimestamp();
    }
    if (options & VACOPT_VERBOSE)
        //需要VERBOSE
        elevel = INFO;
    else
        elevel = DEBUG2;
    pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM,
                                  RelationGetRelid(onerel));
    vac_strategy = bstrategy;
    //計算最老的xmin和凍結截止點
    //輸出:OldestXmin/FreezeLimit/FreezeLimit/MultiXactCutoff/mxactFullScanLimit
    vacuum_set_xid_limits(onerel,
                          params->freeze_min_age,
                          params->freeze_table_age,
                          params->multixact_freeze_min_age,
                          params->multixact_freeze_table_age,
                          &OldestXmin, &FreezeLimit, &xidFullScanLimit,
                          &MultiXactCutoff, &mxactFullScanLimit);
    /*
     * We request an aggressive scan if the table's frozen Xid is now older
     * than or equal to the requested Xid full-table scan limit; or if the
     * table's minimum MultiXactId is older than or equal to the requested
     * mxid full-table scan limit; or if DISABLE_PAGE_SKIPPING was specified.
     * 如果表的frozen Xid現在大于或等于請求的Xid全表掃描限制,則請求進行主動掃描;
     * 或者如果表的最小MultiXactId大于或等于請求的mxid全表掃描限制;
     * 或者,如果指定了disable_page_skip。
     */
    //比較onerel->rd_rel->relfrozenxid & xidFullScanLimit
    //如小于等于,則aggressive為T,否則為F
    aggressive = TransactionIdPrecedesOrEquals(onerel->rd_rel->relfrozenxid,
                                               xidFullScanLimit);
    //比較onerel->rd_rel->relminmxid &mxactFullScanLimit
    //如小于等于,則aggressive為T
    //否則aggressive原值為T,則為T,否則為F
    aggressive |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid,
                                              mxactFullScanLimit);
    if (options & VACOPT_DISABLE_PAGE_SKIPPING)
        //禁用跳過頁,則強制為T
        aggressive = true;
    //分配統計結構體內存
    vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats));
    //記錄統計信息
    vacrelstats->old_rel_pages = onerel->rd_rel->relpages;
    vacrelstats->old_live_tuples = onerel->rd_rel->reltuples;
    vacrelstats->num_index_scans = 0;
    vacrelstats->pages_removed = 0;
    vacrelstats->lock_waiter_detected = false;
    /* Open all indexes of the relation */
    //打開該relation所有的索引
    vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel);
    vacrelstats->hasindex = (nindexes > 0);
    /* Do the vacuuming */
    //執行vacuuming
    lazy_scan_heap(onerel, options, vacrelstats, Irel, nindexes, aggressive);
    /* Done with indexes */
    //已完成index的處理
    vac_close_indexes(nindexes, Irel, NoLock);
    /*
     * Compute whether we actually scanned the all unfrozen pages. If we did,
     * we can adjust relfrozenxid and relminmxid.
     * 計算我們實際上是否掃描了所有unfrozen pages.
     * 如果掃描了,則需要調整relfrozenxid和relminmxid.
     *
     * NB: We need to check this before truncating the relation, because that
     * will change ->rel_pages.
     * 注意:我們需要在截斷relation前執行檢查,因為這會改變rel_pages.
     */
    if ((vacrelstats->scanned_pages + vacrelstats->frozenskipped_pages)
        < vacrelstats->rel_pages)
    {
        Assert(!aggressive);
        scanned_all_unfrozen = false;
    }
    else
        //掃描pages + 凍結跳過的pages >= 總pages,則為T
        scanned_all_unfrozen = true;
    /*
     * Optionally truncate the relation.
     * 可選的,截斷relation
     */
    if (should_attempt_truncation(vacrelstats))
        lazy_truncate_heap(onerel, vacrelstats);
    /* Report that we are now doing final cleanup */
    //通知其他進程,正在進行最后的清理
    pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
                                 PROGRESS_VACUUM_PHASE_FINAL_CLEANUP);
    /*
     * Update statistics in pg_class.
     * 更新pg_class中的統計信息.
     *
     * A corner case here is that if we scanned no pages at all because every
     * page is all-visible, we should not update relpages/reltuples, because
     * we have no new information to contribute.  In particular this keeps us
     * from replacing relpages=reltuples=0 (which means "unknown tuple
     * density") with nonzero relpages and reltuples=0 (which means "zero
     * tuple density") unless there's some actual evidence for the latter.
     * 這里的一個極端情況是,如果每個頁面都是可見的,這時候根本沒有掃描任何頁面,
     *   那么就不應該更新relpages/reltuples,因為我們沒有新信息可以更新。
     * 特別地,這阻止我們將relpages=reltuple =0(這意味著“未知的元組密度”)替換
     *   為非零relpages和reltuple=0(這意味著“零元組密度”),
     *   除非有關于后者的一些實際的證據。
     *
     * It's important that we use tupcount_pages and not scanned_pages for the
     * check described above; scanned_pages counts pages where we could not
     * get cleanup lock, and which were processed only for frozenxid purposes.
     * 對于上面描述的檢查,使用tupcount_pages而不是scanned_pages是很重要的;
     * scanned_pages對無法獲得清理鎖的頁面進行計數,這些頁面僅用于frozenxid目的。
     *
     * We do update relallvisible even in the corner case, since if the table
     * is all-visible we'd definitely like to know that.  But clamp the value
     * to be not more than what we're setting relpages to.
     * 即使在極端情況下,我們也會更新relallvisible,因為如果表是all-visible的,那我們肯定想知道這個.
     * 但是不要超過我們設置relpages的值。
     *
     * Also, don't change relfrozenxid/relminmxid if we skipped any pages,
     * since then we don't know for certain that all tuples have a newer xmin.
     * 同時,如果我們跳過了所有的頁面,不能更新relfrozenxid/relminmxid,
     *   因為從那時起,我們不能確定所有元組是否都有更新的xmin.
     */
    new_rel_pages = vacrelstats->rel_pages;
    new_live_tuples = vacrelstats->new_live_tuples;
    if (vacrelstats->tupcount_pages == 0 && new_rel_pages > 0)
    {
        //實際處理的tuple為0而且總頁面不為0,則調整回原頁數
        new_rel_pages = vacrelstats->old_rel_pages;
        new_live_tuples = vacrelstats->old_live_tuples;
    }
    visibilitymap_count(onerel, &new_rel_allvisible, NULL);
    if (new_rel_allvisible > new_rel_pages)
        new_rel_allvisible = new_rel_pages;
    new_frozen_xid = scanned_all_unfrozen ? FreezeLimit : InvalidTransactionId;
    new_min_multi = scanned_all_unfrozen ? MultiXactCutoff : InvalidMultiXactId;
    //更新pg_class中的統計信息
    vac_update_relstats(onerel,
                        new_rel_pages,
                        new_live_tuples,
                        new_rel_allvisible,
                        vacrelstats->hasindex,
                        new_frozen_xid,
                        new_min_multi,
                        false);
    /* report results to the stats collector, too */
    //同時,發送結果給統計收集器
    pgstat_report_vacuum(RelationGetRelid(onerel),
                         onerel->rd_rel->relisshared,
                         new_live_tuples,
                         vacrelstats->new_dead_tuples);
    pgstat_progress_end_command();
    /* and log the action if appropriate */
    //并在適當的情況下記錄操作
    if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
    {
        //autovacuum && 參數log_min_duration >= 0
        TimestampTz endtime = GetCurrentTimestamp();
        if (params->log_min_duration == 0 ||
            TimestampDifferenceExceeds(starttime, endtime,
                                       params->log_min_duration))
        {
            StringInfoData buf;
            char       *msgfmt;
            TimestampDifference(starttime, endtime, &secs, &usecs);
            read_rate = 0;
            write_rate = 0;
            if ((secs > 0) || (usecs > 0))
            {
                read_rate = (double) BLCKSZ * VacuumPageMiss / (1024 * 1024) /
                    (secs + usecs / 1000000.0);
                write_rate = (double) BLCKSZ * VacuumPageDirty / (1024 * 1024) /
                    (secs + usecs / 1000000.0);
            }
            /*
             * This is pretty messy, but we split it up so that we can skip
             * emitting individual parts of the message when not applicable.
             */
            initStringInfo(&buf);
            if (params->is_wraparound)
            {
                if (aggressive)
                    msgfmt = _("automatic aggressive vacuum to prevent wraparound of table \"%s.%s.%s\": index scans: %d\n");
                else
                    msgfmt = _("automatic vacuum to prevent wraparound of table \"%s.%s.%s\": index scans: %d\n");
            }
            else
            {
                if (aggressive)
                    msgfmt = _("automatic aggressive vacuum of table \"%s.%s.%s\": index scans: %d\n");
                else
                    msgfmt = _("automatic vacuum of table \"%s.%s.%s\": index scans: %d\n");
            }
            appendStringInfo(&buf, msgfmt,
                             get_database_name(MyDatabaseId),
                             get_namespace_name(RelationGetNamespace(onerel)),
                             RelationGetRelationName(onerel),
                             vacrelstats->num_index_scans);
            appendStringInfo(&buf, _("pages: %u removed, %u remain, %u skipped due to pins, %u skipped frozen\n"),
                             vacrelstats->pages_removed,
                             vacrelstats->rel_pages,
                             vacrelstats->pinskipped_pages,
                             vacrelstats->frozenskipped_pages);
            appendStringInfo(&buf,
                             _("tuples: %.0f removed, %.0f remain, %.0f are dead but not yet removable, oldest xmin: %u\n"),
                             vacrelstats->tuples_deleted,
                             vacrelstats->new_rel_tuples,
                             vacrelstats->new_dead_tuples,
                             OldestXmin);
            appendStringInfo(&buf,
                             _("buffer usage: %d hits, %d misses, %d dirtied\n"),
                             VacuumPageHit,
                             VacuumPageMiss,
                             VacuumPageDirty);
            appendStringInfo(&buf, _("avg read rate: %.3f MB/s, avg write rate: %.3f MB/s\n"),
                             read_rate, write_rate);
            appendStringInfo(&buf, _("system usage: %s"), pg_rusage_show(&ru0));
            ereport(LOG,
                    (errmsg_internal("%s", buf.data)));
            pfree(buf.data);
        }
    }
}

三、跟蹤分析

測試腳本

11:45:37 (xdb@[local]:5432)testdb=# vacuum t1;

啟動gdb,設置斷點
注:PG主線函數名稱已改為heap_vacuum_rel,PG 11.1仍為lazy_vacuum_rel

(gdb) c
Continuing.
Breakpoint 1, lazy_vacuum_rel (onerel=0x7f226cd9e9a0, options=1, params=0x7ffe010d5b70, bstrategy=0x1da9708)
    at vacuumlazy.c:197
197     TimestampTz starttime = 0;
(gdb)

輸入參數
relation

(gdb) p *onerel
$1 = {rd_node = {spcNode = 1663, dbNode = 16402, relNode = 50820}, rd_smgr = 0x0, rd_refcnt = 1, rd_backend = -1, 
  rd_islocaltemp = false, rd_isnailed = false, rd_isvalid = true, rd_indexvalid = 0 '\000', rd_statvalid = false, 
  rd_createSubid = 0, rd_newRelfilenodeSubid = 0, rd_rel = 0x7f226cd9ebb8, rd_att = 0x7f226cd9ecd0, rd_id = 50820, 
  rd_lockInfo = {lockRelId = {relId = 50820, dbId = 16402}}, rd_rules = 0x0, rd_rulescxt = 0x0, trigdesc = 0x0, 
  rd_rsdesc = 0x0, rd_fkeylist = 0x0, rd_fkeyvalid = false, rd_partkeycxt = 0x0, rd_partkey = 0x0, rd_pdcxt = 0x0, 
  rd_partdesc = 0x0, rd_partcheck = 0x0, rd_indexlist = 0x0, rd_oidindex = 0, rd_pkindex = 0, rd_replidindex = 0, 
  rd_statlist = 0x0, rd_indexattr = 0x0, rd_projindexattr = 0x0, rd_keyattr = 0x0, rd_pkattr = 0x0, rd_idattr = 0x0, 
  rd_projidx = 0x0, rd_pubactions = 0x0, rd_options = 0x0, rd_index = 0x0, rd_indextuple = 0x0, rd_amhandler = 0, 
  rd_indexcxt = 0x0, rd_amroutine = 0x0, rd_opfamily = 0x0, rd_opcintype = 0x0, rd_support = 0x0, rd_supportinfo = 0x0, 
  rd_indoption = 0x0, rd_indexprs = 0x0, rd_indpred = 0x0, rd_exclops = 0x0, rd_exclprocs = 0x0, rd_exclstrats = 0x0, 
  rd_amcache = 0x0, rd_indcollation = 0x0, rd_fdwroutine = 0x0, rd_toastoid = 0, pgstat_info = 0x1d5a030}
(gdb)

vacuum參數

(gdb) p *params
$2 = {freeze_min_age = -1, freeze_table_age = -1, multixact_freeze_min_age = -1, multixact_freeze_table_age = -1, 
  is_wraparound = false, log_min_duration = -1}
(gdb)

buffer訪問策略對象

(gdb) p *bstrategy
$3 = {btype = BAS_VACUUM, ring_size = 32, current = 0, current_was_in_ring = false, buffers = 0x1da9718}
(gdb) 
(gdb) p *bstrategy->buffers
$4 = 0
(gdb)

1.初始化相關變量,如本地變量/日志記錄級別/訪問策略等

$4 = 0
(gdb) n
215     if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
(gdb) 
221     if (options & VACOPT_VERBOSE)
(gdb) 
224         elevel = DEBUG2;
(gdb) 
226     pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM,
(gdb) 
229     vac_strategy = bstrategy;
(gdb)

2.調用vacuum_set_xid_limits計算最老的xmin和凍結截止點
返回值均為默認值,其中OldestXmin是當前最小的活動事務ID

231     vacuum_set_xid_limits(onerel,
(gdb) 
245     aggressive = TransactionIdPrecedesOrEquals(onerel->rd_rel->relfrozenxid,
(gdb) p OldestXmin
$5 = 307590
(gdb) p FreezeLimit
$6 = 4245274886
(gdb) p xidFullScanLimit
$10 = 4145274886
(gdb) p MultiXactCutoff
$8 = 4289967297
(gdb) p mxactFullScanLimit
$9 = 4144967297
(gdb)

3.判斷是否執行全表(不跳過pages)掃描,標記變量為aggressive,值為F

(gdb) n
247     aggressive |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid,
(gdb) p aggressive
$11 = false
(gdb) n
249     if (options & VACOPT_DISABLE_PAGE_SKIPPING)
(gdb) p onerel->rd_rel->relfrozenxid
$12 = 144983
(gdb) p xidFullScanLimit
$13 = 4145274886
(gdb)

4.初始化統計信息結構體vacrelstats

(gdb) n
252     vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats));
(gdb) 
254     vacrelstats->old_rel_pages = onerel->rd_rel->relpages;
(gdb) 
255     vacrelstats->old_live_tuples = onerel->rd_rel->reltuples;
(gdb) 
256     vacrelstats->num_index_scans = 0;
(gdb) 
257     vacrelstats->pages_removed = 0;
(gdb) 
258     vacrelstats->lock_waiter_detected = false;
(gdb) 
261     vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel);
(gdb) p *vacrelstats
$14 = {hasindex = false, old_rel_pages = 75, rel_pages = 0, scanned_pages = 0, pinskipped_pages = 0, 
  frozenskipped_pages = 0, tupcount_pages = 0, old_live_tuples = 10000, new_rel_tuples = 0, new_live_tuples = 0, 
  new_dead_tuples = 0, pages_removed = 0, tuples_deleted = 0, nonempty_pages = 0, num_dead_tuples = 0, max_dead_tuples = 0, 
  dead_tuples = 0x0, num_index_scans = 0, latestRemovedXid = 0, lock_waiter_detected = false}
(gdb)

5.打開索引,執行函數lazy_scan_heap進行vacuuming,關閉索引

(gdb) n
262     vacrelstats->hasindex = (nindexes > 0);
(gdb) 
265     lazy_scan_heap(onerel, options, vacrelstats, Irel, nindexes, aggressive);
(gdb) 
268     vac_close_indexes(nindexes, Irel, NoLock);
(gdb) 
(gdb) 
277     if ((vacrelstats->scanned_pages + vacrelstats->frozenskipped_pages)
(gdb) 
278         < vacrelstats->rel_pages)
(gdb) 
277     if ((vacrelstats->scanned_pages + vacrelstats->frozenskipped_pages)
(gdb) 
284         scanned_all_unfrozen = true;
(gdb) p *vacrelstats
$15 = {hasindex = true, old_rel_pages = 75, rel_pages = 75, scanned_pages = 75, pinskipped_pages = 0, 
  frozenskipped_pages = 0, tupcount_pages = 75, old_live_tuples = 10000, new_rel_tuples = 10154, new_live_tuples = 10000, 
  new_dead_tuples = 154, pages_removed = 0, tuples_deleted = 0, nonempty_pages = 75, num_dead_tuples = 0, 
  max_dead_tuples = 21825, dead_tuples = 0x1db5030, num_index_scans = 0, latestRemovedXid = 0, lock_waiter_detected = false}
(gdb) p vacrelstats->scanned_pages
$16 = 75
(gdb) p vacrelstats->frozenskipped_pages
$17 = 0
(gdb) p vacrelstats->rel_pages
$18 = 75
(gdb)

6.更新pg_class中的統計信息

(gdb) n
289     if (should_attempt_truncation(vacrelstats))
(gdb) 
293     pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
(gdb) 
317     new_rel_pages = vacrelstats->rel_pages;
(gdb) 
318     new_live_tuples = vacrelstats->new_live_tuples;
(gdb) 
319     if (vacrelstats->tupcount_pages == 0 && new_rel_pages > 0)
(gdb) 
325     visibilitymap_count(onerel, &new_rel_allvisible, NULL);
(gdb) 
326     if (new_rel_allvisible > new_rel_pages)
(gdb) p new_rel_allvisible
$19 = 0
(gdb) p new_rel_pages
$20 = 75
(gdb) n
329     new_frozen_xid = scanned_all_unfrozen ? FreezeLimit : InvalidTransactionId;
(gdb) 
330     new_min_multi = scanned_all_unfrozen ? MultiXactCutoff : InvalidMultiXactId;
(gdb) 
336                         vacrelstats->hasindex,
(gdb) 
332     vac_update_relstats(onerel,
(gdb) p new_frozen_xid
$21 = 4245274886
(gdb) p new_min_multi
$22 = 4289967297
(gdb)

7.收尾工作

(gdb) n
345                          vacrelstats->new_dead_tuples);
(gdb) 
342     pgstat_report_vacuum(RelationGetRelid(onerel),
(gdb) 
343                          onerel->rd_rel->relisshared,
(gdb) 
342     pgstat_report_vacuum(RelationGetRelid(onerel),
(gdb) 
346     pgstat_progress_end_command();
(gdb) 
349     if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
(gdb)

完成調用

411 }
(gdb) 
vacuum_rel (relid=50820, relation=0x1cdb8d0, options=1, params=0x7ffe010d5b70) at vacuum.c:1560
1560        AtEOXact_GUC(false, save_nestlevel);
(gdb)

到此,關于“PostgreSQL的vacuum過程中heap_vacuum_rel函數分析”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

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

AI

南昌县| 营口市| 南开区| 江油市| 肃北| 从江县| 吉隆县| 建昌县| 磴口县| 嘉祥县| 工布江达县| 新余市| 芮城县| 马尔康县| 抚远县| 苍梧县| 太和县| 静海县| 永州市| 安平县| 青川县| 连南| 五原县| 加查县| 阿勒泰市| 灵宝市| 电白县| 含山县| 九江市| 中江县| 台江县| 普定县| 荃湾区| 庄浪县| 青海省| 云南省| 周口市| 白山市| 五家渠市| 定陶县| 屏东县|