PostgreSQL的vacuum过程中heap_vacuum_rel函数分析

分类:编程技术 时间:2024-02-20 15:52 浏览:0 评论:0
0
本文主要介绍《PostgreSQL的vacuum过程中的heap_vacuum_rel函数分析》。在日常操作中,相信很多人都对PostgreSQL的vacuum进程中的heap_vacuum_rel函数分析存在疑问。小编查阅了各种资料,整理出了一个简单又好的解决方案。使用的操作方法,希望能帮助您解答《PostgreSQL的vacuum过程中的heap_vacuum_rel函数分析》的疑惑!接下来就请跟随小编一起来学习吧!

本节简单介绍PostgreSQL手动vacuum执行的实现逻辑,主要分析ExecVacuum->vacuum->vacuum_rel->heap_vacuum_rel函数的实现逻辑。

1.数据结构

宏定义
真空和分析命令选项

/* -------------- --------- * 真空和分析语句 * 真空和分析命令选项 * * Eve尽管这些名义上是两个语句,但仅对这两个语句使用一种节点类型会很方便。请注意,必须在选项中至少设置 VACOPT_VACUUM * 和 VACOPT_ANALYZE 之一。 * 这里虽然有两种不同的语句,但是只需要使用相同的Node类型即可。 * 注意选项中至少设置了VACOPT_VACUUM/VACOPT_ANALYZE。 * ---------- ---------- */typedef enum VacuumOption{ VACOPT_VACUUM = 1 << 0, /* 执行 VACUUM */ VACOPT_ANALYZE = 1 << 1, /* 执行ANALYZE */ VACOPT_VERBOSE = 1 << 2, /* 打印进度信息 */ VACOPT_FREEZE = 1 << 3, /* FREEZE 选项 */ VACOPT_FULL = 1 << 4, /* FULL(非并发)真空 */ VACOPT_SKIP_LOCKED = 1 << 5, /* 如果无法获得锁则跳过 */ VACOPT_SKIPTOAST = 1 << 6, /* 不处理 TOAST 表(如果有) */ VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7 /* 不跳过任何页面 * /} VacuumOption;

VacuumStmt
存储vacuum命令的Option&Relation链表

typedef struct VacuumStmt{ NodeTag type;//Tag //VacuumOption 位标记 int options; /* VacuumOption 标志的或 */ //VacuumRelation 链表,如果 NIL-->all Relation。 List *rels;/* VacuumRelation 列表,或全部为 NIL */} VacuumStmt;

VacuumParams
vacuum 命令参数

/* * 参数定制 VACUUM 和 ANALYZE 的行为。 * 客户端调用VACUUM/ANALYZE时的自定义参数 */typedef struct VacuumParams{ //最小冻结年龄,-1表示使用默认的int freeze_min_age; /* min freeze Age, -1 to use default */ //扫描整个表的冻结年龄 int int freeze_table_age; /* 扫描全表的年龄 */ //最小的multixact冻结年龄,-1代表默认 int   multixact_freeze_min_age; /* 最小 multixact 冻结期限,-1 到 multixact_freeze_table_age; /* 扫描的多任务年龄 您想强制环绕吗?布尔 is_wraparound; /* 强制 for-wraparound 真空 */ //最小执行阈值(以毫秒为单位) int log_min_duration; /*最小执行阈值(以毫秒为单位) at                * 激活哪些详细日志,-1 } VacuumParams;

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

/* * 有关 VACUUM/ANALYZE 单个目标表的信息。 * VACUUM/ANALYZE命令的目标表信息。 * * 如果设置了OID字段,它总是标识要处理的表。 * 那么关系字段可以为NULL;如果不是,它仅用于报告打开/锁定关系失败。 * 如果设置了 OID 字段,则该值通常是已处理数据表的值。 * 那么关系字段可以为空;如果不是,则仅用于报告打开/锁定关系失败。 */typedef struct VacuumRelation{ NodeTag 类型; RangeVar *关系; /* 要处理的表名,或 NULL */ Oidoid; >< br/> 缓冲区访问策略对象

/* * 缓冲区标识符。 * 缓冲区标识符 * * 零无效,正数是共享缓冲区的索引(1..NBufferrs), * 负数是本地缓冲区的索引 (-1 .. -NLocBuffer)。 * 0表示无效,正整数表示共享缓冲区的索引(1..N),*负数表示本地缓冲区的索引(-1..-N) */typedef int Buffer;#define InvalidBuffer 0/ * * 缓冲区访问策略对象。 * 缓冲区访问策略对象 * * BufferAccessStrategyData 是 freelist.c 私有的 * BufferAccessStrategyData 是 freelist.c 私有的 */typedef struct BufferAccessStrategyData *BufferAccessStrategy; /* * 私有(非共享)状态,用于管理共享缓冲区环以供重用。 * 这是目前唯一一种 BufferAccessStrategy 对象,但有一天 * 我们可能会有更多种类。 * 私有状态,用于管理可重用的环形缓冲区。这样的缓冲区访问策略对象,但是将来你可以拥有更多。 */typedef struct BufferAccessStrategyData{ /* 总体策略类型 */ //全局策略类型 BufferAccessStrategyType btype; /* buffers[] 数组中的元素数量 */ //Tbuffers[] 中的元素数量 int intring_size; /* * 环中“当前”槽的索引,即 GetBufferFromRing 最近返回的槽。 * 环形缓冲区 索引中当前槽的索引,最近访问的槽由函数 GetBufferFromRing 返回。 */ int 当前; /* * 如果 StrategyGetBuffer 刚刚返回的缓冲区已经在环中,则为 True。已经在环缓冲区中,则返回 T */ bool current_was_in_ring; /* * 缓冲区编号数组。 InvalidBuffer(即零)表示我们尚未为此环槽选择缓冲区。对于隐式分配,这与 * 结构的固定字段一起 palloc'd。 * 缓冲区编号数组。 * InvalidBuffer(即:0)表示我们尚未为此插槽选择缓冲区。 * 为了简化分配,这是 palloc'd 结构的固定字段。 */ Buffer buffers[FLEXIBLE_ARRAY_MEMBER];}   BufferAccessStrategyData;//块结构体指针typedef void *Block;/* GetAccessStrategy()可能的参数 *///GetAccessStrategy()函数可以取值参数 typedef enum BufferAccessStrategyType{ //常规随机访问 BAS_NORMAL,                /* 普通随机访问 */ //大规模读取仅扫描 BAS_BULKREAD,                                                                                                                                                                ​(例如 COPY IN)  BAS_BULKWRITE, /* 大型多块写入(例如 COPY IN)*/ //VACUUM BAS_VACUUM /* VACUUM */} BufferAccessStrategyType;

LVRelSt at s

typedef struct LVRelStats{ /* hasindex = true 表示两遍策略; false 表示单遍 */ //T 表示两遍策略,F 表示单遍策略 bool hasindex; /* rel 的总体统计 */ / /rel 的全局统计 // pg_class.relpages 的前一个值 BlockNumber old_rel_pages; /* pg_class.relpages 的先前值 */ //总页数 BlockNumberrel_pages; /* 总页数 */ //扫描页数 BlockNumber Scanned_pa​​ges; /* 我们检查的页数 */ //由于 pin Skipped 页面 BlockNumber pinskipped_pa​​ges; /* 由于 pin 导致我们跳过的页面数 */ //跳过的冻结页面 BlockNumber freeze_pages; /* 我们跳过的冻结页数 */ //计算其元组的页数 块编号 tupcount_pages ; /* 我们统计了元组的页面 */ //pg_class.reltuples 的先前值 double old_live_tuples; /* pg_class.reltuples 的先前值 */ //新估计的元组总数 double new_rel_tuples; /* 新估计的元组总数 */ //新估计存活元组的数量 double new_live_tuples; /* 新估计的活元组总数 */ //新估计的死元组数量 double new_dead_tuples; /* 新估计的死元组总数 */ // 清除的页面 BlockNumber pages_removed ; //删除的元组 double tuples_deleted; //实际上非空页 + 1 BlockNumber nonempty_pages; /* 实际上,最后一个非空页 + 1 */ /* 我们要删除的元组 TID 列表 */ /* NB: 这个列表按 TID 地址排序 */ // 要删除的元组 TID 的链表 // 注意:链表已使用TID地址排序 //当前条目数/条目数 int num_dead_tuples; /* 当前条目数 */ // 已在数组槽中分配(丢弃元组的最大数量) int max_dead_tuples; /* # 在数组中分配的槽 */ //ItemPointerData 数组 ItemPointer dead_tuples; /* ItemPointerData 数组 */ //扫描的索引数量 int num_index_scans; //最后清除的交易ID TransactionIdlatestRemovedXid; /服务员存在吗? bool lock_waiter_Detected;} LVRelStats; 

PGRUsage
pg_rusage_init/pg_rusage_show的状态结构

/* 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_ut我; /* 使用的用户时间 */ struct timeval ru_stime; /* 使用的系统时间 */};struct timeval{__time_t tv_sec; /* 秒。秒。 */__suseconds_t tv_usec; ​​/* 微秒--> 这个英文注释有问题。 */};

2.源码解读

heap_vacuum_rel() — 对堆关系执行VACUUM
大致逻辑如下:
1.初始化相关变量,如局部变量/日志级别/访问策略等
2.调用vacuum_set_xid_limits计算最早的xmin和冻结截止点
3.确定是否执行全表扫描(不跳页)并将变量标记为aggressive
4.初始化统计信息结构vacrelstats
5.打开索引,执行函数lazy_scan_heap进行清理,关闭索引
6.更新pg_class中的统计信息
7.完成工作

/* * heap_vacuum_rel() -- perform 对一个堆关系进行 VACUUM * heap_vacuum_rel() -- 对堆关系执行 VACUUM * * 此例程会清理单个堆,清除其索引,并 * 更新其相关页和相关元组统计信息。编辑了一个事务并打开*并锁定了关系。 * 在调用入口处,我们创建了一个事务并打开并锁定了关系。 */voidheap_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; //写入速率 //我们应该扫描所有未冻结的页面吗?布尔攻击性; /* 我们应该扫描所有未冻结的页面吗? */ //实际上扫描了所有这样的页面?布尔扫描_全部_解冻; /* 实际上扫描了所有这样的页面? */ TransactionId xidFullScanLimit; MultiXactId mxactFullScanLimit;乙锁号new_rel_pages;区块编号 new_rel_allvisible;双new_live_tuples; TransactionId new_frozen_xid; MultiXactId new_min_multi;断言(参数!= NULL); /* 如果自动真空日志记录需要,则测量经过的时间 */ //如果需要自动真空日志记录,则测量所花费的时间 if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0) { pg_rusage_init(&ru0);开始时间 = GetCurrentTimestamp(); } if (options & VACOPT_VERBOSE) //需要 VERBOSE elevel = INFO;否则 elevel = DEBUG2; pgstat_progress_start_command(PROGRESS_COMMAN D_VACUUM,                                                                                                                                                RelationGetRelid(onerel)); vac_strategy = bstrategy;冻结截止点 //输出:OldestXmin/FreezeLimit/FreezeLimit/MultiXactCutoff/mxactFullScanLimitvacuum_set_xid_limits(onerel,   ; params->multixact_freeze_table_age, &OldestXmin, &FreezeLimit, &xidFullScanLimit, * 表的最小 MultiXactId 早于或等于请求的 * mxid 全表扫描限制;或者如果指定了 DISABLE_PAGE_SKIPPING。 * 如果表的冻结Xid现在大于或等于请求的Xid全表扫描限制,则请求主动扫描; mxid全表扫描限制; * 或者或者,如果指定了disable_page_skip。 */ //比较onerel->rd_rel->relfrozenxid & xidFullScanLimit //如果小于等于,aggressive为T,否则为Faggressive = TransactionIdPrecedesOrEquals(onerel->rd_rel->relfrozenxid,                                                                                                       xidFullScanLimit); ->relminmxid &mxactFullScanLimit //如果小于等于,aggressive为T //否则aggressive原值为T,否则为Faggressive |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid,bsp;统计数据 = (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; /* 打开关系的所有索引 */ //打开关系的所有索引 vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel); vacrelstats->hasindex = (nindexes > 0); /* 执行清理 */ //执行清理lazy_scan_heap(onerel, options, vacrelstats, Irel, nindexes,aggressive); /* Done with Indexes */ //完成索引处理 vac_close_indexes(nindexes, Irel, NoLock); /* * 计算我们是否真的扫描了所有未冻结的页面。如果我们这样做了,*我们可以调整 relfrozenxid 和 relminmxid. * 计算我们是否真正扫描了所有未冻结的页面。 * 如果是这样,我们需要调整relfrozenxid和relminmxid。 >rel_pages。 * 注意:我们需要在截断关系之前执行检查,因为这会改变 rel_pages。 */ if ((vacrelstats->scanned_pa​​ges + vacrelstats->frozenskipped_pa​​ges) < vacrelstats->rel_pages) { Scanned_all_unfrozen = false; } else   //扫描页数+冻结跳过页数>=总页数,则T Scanned_all_unfrozen = true; /* * 可选择截断关系。 * 可选,截断关系 */ if (should_attempt_truncation(vacrelstats))         lazy_truncate_heap( onerel, vacrelstats); /* 报告我们现在正在进行最终清理 */ //通知其他进程正在进行最终清理 pgstat_progress_update_param(PROGRESS_VACUUM_PHASE, PROGRESS_VACUUM_ PHASE_FINAL_CLEANUP); /* * 更新 pg_class 中的统计信息。 * 更新pg_class中的统计信息。 * * 这里的一个极端情况是,如果我们根本不扫描任何页面,因为每个 * 页面都是可见的,我们不应该更新 relpages/reltuples ,因为 * 我们没有新的信息可以贡献。特别是,这使我们无法用非零relpages和reltuples=0(意味着“零”*元组密度”)替换relpages=reltuples=0(意味着“未知元组*密度”),除非有一些实际证据支持后者。 * 这里的一个极端情况是,如果每个页面都是可见的并且根本没有页面被扫描, * 那么 relpages/reltuples 不应该被更新,因为我们没有新的信息要更新。 * 特别是,这阻止我们替换 relpages=reltuple =0(这意味着“未知的元组密度”)*具有非零relpages和reltuple=0(这意味着“零元组密度”密度”),*除非有关于后者的一些实际证据。 * 重要的是,我们使用 tupcount_pages 而不是 Scand_pages 来进行上述检查; Scand_pages 计算我们无法*获得清理锁定的页面数,以及仅出于 freezexid 目的而处理的页面数。 ** 我们确实更新了即使在极端情况下也是可见的,因为如果表 * 是所有可见的,我们肯定想知道这一点。但将值 * 限制为不大于我们设置的 relpages 的值。在极端情况下,我们也会更新relallvisible,因为如果表是所有可见的,那么我们肯定会想知道这一点。 * 但不能超过我们设置relpages的值。 * * * 另外,如果我们跳过任何页面,请不要更改 relfrozenxid/relminmxid, * 从那以后我们不确定所有元组都有更新的 xmin。我们无法确定是否所有元组都已更新 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);如果(new_rel_allvisible> new_rel_pages) new_rel_allvisible = new_rel_pages; new_frozen_xid = Scand_all_unfrozen ?免费 zeLimit : InvalidTransactionId; new_min_multi = Scand_all_unfrozen ? MultiXactCutoff :无效MultiXactId; //更新pg_class中的统计信息 vac_update_relstats (onerel, new_rel_pages, new_live_tuples,                                                                                                                                                                                                                                                                                ( min_multi,     false);D (onerl), OneRel-> RD_REL-> RELISSHARD, New_live_tuples, VacRELSTATS-> New_dead_tup莱斯); pgStat_progress_end_Command ();/*并记录操作 if appro Priant*//并记录操作 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;字符*msgfmt; TimestampDifference(开始时间, 结束时间, &secs, &usecs);读取率=0;写入速率=0; if ((秒 > 0) || (usecs > 0)) read_rate = (double) BLCKSZ * VacuumPageMiss / (1024 * 1024) / (秒 + usecs / 1000000.0); write_rate = (double) BLCKSZ * VacuumPageDirty / (1024* 1024) / (秒 + usecs / 1000000.0); /* * 这相当混乱,但我们将其分开,这样我们就可以跳过 * 在不适用时发出消息的各个部分。 */ initStringInfo(&buf); if (params->is_wraparound) { if (aggressive) msg​​fmt = _("自动主动真空以防止表 \"%s.%s.%s\" 的环绕:索引扫描:%d\n") ;真空以防止表 \"%s.%s.%s\" 环绕:索引扫描:%d\n");p; else else { if (aggressive) msg​​fmt = _("automatic aggressiv表 \"%s.%s.%s\" 的真空:索引扫描:%d\n");                                                                                                                                  表 \"%s.%s.%s\": 索引扫描: %d\n") ;appendStringInfo(&buf, msgfmt, get_database_name(MyDatabaseId), get_namespace_name(RelationGetNamespace(onerel)), RelationGetRelationName(onerel), vacrelstats->num_index_scans); appendStringInfo(&buf, _("页数:%u 已删除,%u 保留,%u 由于引脚而跳过,%u 已冻结\n"),                vacrelstats-> pages_removed,              vacrelstats->rel_pages, vacrelstats->pinskipped_pa​​ges, vacrelstats- >frozenskipped_pa​​ges ); appendStringInfo(&buf,                                                                                                                                                              vacrelstats->tuples_deleted,               vacrelstats->new_rel_tuples,             vacrelstats->new_dead_tuples,                                   最旧X分钟);appendStringInfo(&buf,                                    , %d 未命中, %d 脏\n"),                                                                                                                                                                            nbsp;                 VacuumPageDirty);             read_rate, write_rate);         appendStringInfo(&buf, _("系统使用情况: %s"), pg_rusage_show(&ru0));buf. data))); pfree(buf.data); } }}

三、跟踪分析

测试脚本

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

启动gdb,设置断点< br/>注:PG主线函数名已更改为heap_vacuum_rel,PG 11.1仍为lazy_vacuum_rel

(gdb) cContinuing.Breakpoint 1,lazy_vacuum_rel (onerel=0x7f226cd9e9a0, options=1, params=0x7ffe010d5b70 , bstrategy =0x1da9708) atvacuumlazy.c:197197 TimestampTz starttime = 0;(gdb)

输入参数
关系

(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_pubaction = 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_indcollat​​ion = 0x 0、rd_fdwroutine = 0x0、rd_toastoid = 0、pgstat_info = 0x1d5a030}(gdb)

真空参数

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

缓冲区访问策略对象

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

1.初始化相关变量,如局部变量/日志级别/访问策略等。

$4 = 0(gdb) n215 if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)(gdb) 221  if (选项 & 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

231vacuum_set_xid_limits(onerel,(gdb) 245aggressive = 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、判断是否进行全表扫描(不跳页) ,将变量标记为aggressive,值为F

(gdb) n247  aggressive |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid,(gdb) paggressive$11 = false(gdb) n249 if (选项 & VACOPT_DISABLE_PAGE_SKIPPING)(gdb) p onerel->rd_rel->relfrozenxid$12 = 144983(gdb) p xidFullScanLimit$13 = 4145274886(gdb)

4.初始化统计信息结构vacrelstats

(gdb) n252 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) 25 7 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, 扫描 ned_pa​​ges = 0, pinskipped_pa​​ges = 0, freeze_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用于清理,并关闭索引

(gdb) n262 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_pa​​ges + vacrelstats->frozenskipped_pa​​ges)(gdb) 278 rel_pages)(gdb) 277 if ((vacrelstats- >scanned_pa​​ges + vacrelstats->frozenskipped_pa​​ges)(gdb) 284 Scanned_all_unfrozen = true;(gdb) p *vacrelstats$15 = {hasindex = true, old_rel_pages = 75,&n bsp;rel_pages = 75, Scanned_pa​​ges = 75, pinskipped_pa​​ges = 0, freeze_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_de ad_tuples = 21825,dead_tuples = 0x1db5030,num_index_scans = 0 ,latestRemovedXid = 0,lock_waiter_Detected = false}(gdb) p vacrelstats->scanned_pa​​ges$16 = 75(gdb) p vacrel stats->frozenskipped_pa​​ges$17 = 0(gdb) p vacrelstats ->rel_pages$18 = 75(gdb)

6.更新pg_class中的统计信息

(gdb) n289 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) 325visibilitymap_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(g db) n329 new_frozen_xid = Scand_all_unfrozen ? FreezeLimit : InvalidTransactionId;(gdb) 330 new_min_multi = Scand_all_unfrozen ? MultiXactCutoff : InvalidMultiXactId;(gdb) 336 vac relstats->hasindex,(gdb) 332 vac_update_relstats(onerel,(gdb) p new_frozen_xid $21 = 4245274886(gdb) p new_min_multi$22 = 4289967297(gdb)

7. 完成工作

(gdb) n345 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) 34 9 如果 (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)(gdb)

完整调用

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

《PostgreSQL的vacuum过程中heap_vacuum_rel函数分析》的学习到此结束,希望可以可以解决大家的疑惑,理论与实践相结合,可以更好的帮助大家学习,快去尝试一下吧!如果您想继续学习更多相关知识,请继续关注网站,小编会继续努力的辛苦给大家带来更多实用的文章!

1. 本站所有资源来源于用户上传或网络,仅作为参考研究使用,如有侵权请邮件联系站长!
2. 本站积分货币获取途径以及用途的解读,想在本站混的好,请务必认真阅读!
3. 本站强烈打击盗版/破解等有损他人权益和违法作为,请各位会员支持正版!
4. 编程技术 > PostgreSQL的vacuum过程中heap_vacuum_rel函数分析

用户评论