关于vacuum的基础知识,参考,本篇从源码层继续学习

https://blog.csdn.net/Hehuyi_In/article/details/102992065

https://blog.csdn.net/Hehuyi_In/article/details/128279210

一、 准备知识

为了方便后面的学习,这里把一部分后面函数经常出现的内容提到前面。

1. VacuumStmt结构体

表示vacuum与analyze语句的结构体,在parsenodes.h文件。虽然是两个语句,但用一个结构体就可以表示。

/* ----------------------*      Vacuum and Analyze Statements** Even though these are nominally two statements, it's convenient to use* just one node type for both.* ----------------------*/
typedef struct VacuumStmt
{NodeTag     type;List       *options;        /* list of DefElem nodes,详情参考下方 */List       *rels;           /* list of VacuumRelation, or NIL for all,待操作的表,为空表示所有表,详情参考下方*/bool        is_vacuumcmd;   /* true for VACUUM, false for ANALYZE,区分是vacuum还是analyze语句 */
} VacuumStmt;

2. VacuumRelation结构体

就是前面的 List       *rels; 待操作的表信息,包括表名、oid、列名等

/** Info about a single target table of 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.*/
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;

3. VacuumParams结构体

vacuum与analyze语句的参数,其中freeze相关参数含义参考:https://blog.csdn.net/Hehuyi_In/article/details/128309607

/** Parameters customizing behavior of VACUUM and ANALYZE.** Note that at least one of VACOPT_VACUUM and VACOPT_ANALYZE must be set* in options.*/
typedef struct VacuumParams
{bits32      options;        /* bitmask of VACOPT_*,下面会详细介绍 */int         freeze_min_age; /* min freeze age, -1 to use default */int         freeze_table_age;   /* age at which to scan whole table */int         multixact_freeze_min_age;   /* min multixact freeze age, -1 to* use default */int         multixact_freeze_table_age; /* multixact age at which to scan* whole table */bool        is_wraparound;  /* force a for-wraparound vacuum,强制进行用于事务回卷的vacuum? */int         log_min_duration;   /* minimum execution threshold in ms at  which  verbose logs are activated, -1 to use default,执行超过该时间被记录至日志,单位为ms */VacOptValue index_cleanup;  /* Do index vacuum and cleanup,进行索引vacuum和清理 */VacOptValue truncate;       /* Truncate empty pages at the end,truncate末端空页 *//** The number of parallel vacuum workers.  0 by default which means choose* based on the number of indexes.  -1 indicates parallel vacuum is* disabled. 并行vacuum workers数*/int         nworkers;
} VacuumParams;

4. VacuumParams->options标记位

这也是最前面VacuumStmt结构体的List       *options;

/* flag bits for VacuumParams->options */
#define VACOPT_VACUUM 0x01      /* do VACUUM */
#define VACOPT_ANALYZE 0x02     /* do ANALYZE */
#define VACOPT_VERBOSE 0x04     /* print progress info */
#define VACOPT_FREEZE 0x08      /* FREEZE option */
#define VACOPT_FULL 0x10        /* FULL (non-concurrent) vacuum */
#define VACOPT_SKIP_LOCKED 0x20 /* skip if cannot get lock */
#define VACOPT_PROCESS_TOAST 0x40   /* process the TOAST table, if any */
#define VACOPT_DISABLE_PAGE_SKIPPING 0x80   /* don't skip any pages */

二、 ExecVacuum()函数

vacuum相关操作在vacuum.c中,当手动执行vacuum及analyze命令,其主入口为ExecVacuum()函数——主要负责为做一系列准备工作(语句解析、选项设置与检查、参数设置等),核心是调用vacuum()函数。

主要参数

  • ParseState:解析阶段生成的语句,其定义在parse_node.h
  • VacuumStmt:vacuum和analyze的语句,参考前面
  • isTopLevel:是否为顶层语句
/** Primary entry point for manual VACUUM and ANALYZE commands** This is mainly a preparation wrapper for the real operations that will* happen in vacuum().*/
void
ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
{VacuumParams params;bool        verbose = false;bool        skip_locked = false;bool        analyze = false;bool        freeze = false;bool        full = false;bool        disable_page_skipping = false;bool        process_toast = true;ListCell   *lc;/* index_cleanup and truncate values unspecified for now */params.index_cleanup = VACOPTVALUE_UNSPECIFIED;params.truncate = VACOPTVALUE_UNSPECIFIED;/* By default parallel vacuum is enabled */params.nworkers = 0;/* Parse options list,解析vacuum和analyze命令参数列表 */foreach(lc, vacstmt->options){DefElem    *opt = (DefElem *) lfirst(lc);/* Parse common options for VACUUM and ANALYZE,通用参数项verbose,skip_locked */if (strcmp(opt->defname, "verbose") == 0)verbose = defGetBoolean(opt);else if (strcmp(opt->defname, "skip_locked") == 0)skip_locked = defGetBoolean(opt);else if (!vacstmt->is_vacuumcmd)ereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR),errmsg("unrecognized ANALYZE option \"%s\"", opt->defname),parser_errposition(pstate, opt->location)));/* Parse options available on VACUUM
vacuum专用参数:analyze, freeze, full, disable_page_skipping, index_cleanup, process_toast,truncate,parallel */else if (strcmp(opt->defname, "analyze") == 0)analyze = defGetBoolean(opt);else if (strcmp(opt->defname, "freeze") == 0)freeze = defGetBoolean(opt);else if (strcmp(opt->defname, "full") == 0)full = defGetBoolean(opt);else if (strcmp(opt->defname, "disable_page_skipping") == 0)disable_page_skipping = defGetBoolean(opt);else if (strcmp(opt->defname, "index_cleanup") == 0){/* Interpret no string as the default, which is 'auto' */if (!opt->arg)params.index_cleanup = VACOPTVALUE_AUTO;else{char       *sval = defGetString(opt);/* Try matching on 'auto' string, or fall back on boolean */if (pg_strcasecmp(sval, "auto") == 0)params.index_cleanup = VACOPTVALUE_AUTO;elseparams.index_cleanup = get_vacoptval_from_boolean(opt);}}else if (strcmp(opt->defname, "process_toast") == 0)process_toast = defGetBoolean(opt);else if (strcmp(opt->defname, "truncate") == 0)params.truncate = get_vacoptval_from_boolean(opt);else if (strcmp(opt->defname, "parallel") == 0){if (opt->arg == NULL){ereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR),errmsg("parallel option requires a value between 0 and %d",MAX_PARALLEL_WORKER_LIMIT),parser_errposition(pstate, opt->location)));}else{int         nworkers;nworkers = defGetInt32(opt);if (nworkers < 0 || nworkers > MAX_PARALLEL_WORKER_LIMIT)ereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR),errmsg("parallel workers for vacuum must be between 0 and %d",MAX_PARALLEL_WORKER_LIMIT),parser_errposition(pstate, opt->location)));/** Disable parallel vacuum, if user has specified parallel* degree as zero.*/if (nworkers == 0)params.nworkers = -1;elseparams.nworkers = nworkers;}}elseereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR),errmsg("unrecognized VACUUM option \"%s\"", opt->defname),parser_errposition(pstate, opt->location)));}/* Set vacuum options,设置vacuum选项 */params.options =(vacstmt->is_vacuumcmd ? VACOPT_VACUUM : VACOPT_ANALYZE) |(verbose ? VACOPT_VERBOSE : 0) |(skip_locked ? VACOPT_SKIP_LOCKED : 0) |(analyze ? VACOPT_ANALYZE : 0) |(freeze ? VACOPT_FREEZE : 0) |(full ? VACOPT_FULL : 0) |(disable_page_skipping ? VACOPT_DISABLE_PAGE_SKIPPING : 0) |(process_toast ? VACOPT_PROCESS_TOAST : 0);/* sanity checks on options,检查vacuum选项*/Assert(params.options & (VACOPT_VACUUM | VACOPT_ANALYZE));Assert((params.options & VACOPT_VACUUM) ||!(params.options & (VACOPT_FULL | VACOPT_FREEZE)));if ((params.options & VACOPT_FULL) && params.nworkers > 0)ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),errmsg("VACUUM FULL cannot be performed in parallel")));/** Make sure VACOPT_ANALYZE is specified if any column lists are present. 如果语句中出现了column list,需要确保声明了analyze选项*/if (!(params.options & VACOPT_ANALYZE)){ListCell   *lc;foreach(lc, vacstmt->rels){VacuumRelation *vrel = lfirst_node(VacuumRelation, lc);if (vrel->va_cols != NIL)ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),errmsg("ANALYZE option must be specified when a column list is provided")));}}/** All freeze ages are zero if the FREEZE option is given; otherwise pass* them as -1 which means to use the default values.*/if (params.options & VACOPT_FREEZE){params.freeze_min_age = 0;params.freeze_table_age = 0;params.multixact_freeze_min_age = 0;params.multixact_freeze_table_age = 0;}else{params.freeze_min_age = -1;params.freeze_table_age = -1;params.multixact_freeze_min_age = -1;params.multixact_freeze_table_age = -1;}/* user-invoked vacuum is never "for wraparound" */params.is_wraparound = false;/* user-invoked vacuum never uses this parameter */params.log_min_duration = -1;/* Now go through the common routine,核心内容,调用vacuum函数 */vacuum(vacstmt->rels, &params, NULL, isTopLevel);
}

三、 vacuum()函数

VACUUM 和ANALYZE命令的内部入口。进行一些预检查、内存上下文分配与切换、构造待处理relation list,并确定是否要use_own_xacts,核心是调用vacuum_rel与analyze_rel函数对每个表进行处理。

主要参数:

  • relations:参考前面VacuumRelation。如果非空,表示指定要vacuum什么表,否则会处理db中的所有表。如果提供了OID,将处理该oid对应的表,否则由VacuumRelation的RangeVar参数(表名)指示。
  • params:参考前面
  • bstrategy:buffer的访问策略,通常是NULL,但在autovacuum中会被传值,用以在多个vacuum()函数使用相同策略
  • isTopLevel:由ProcessUtility函数传入

首先是一些预检查

/** Internal entry point for VACUUM and ANALYZE commands.** relations, if not NIL, is a list of VacuumRelation to process; otherwise,* we process all relevant tables in the database.  For each VacuumRelation,* if a valid OID is supplied, the table with that OID is what to process;* otherwise, the VacuumRelation's RangeVar indicates what to process.** params contains a set of parameters that can be used to customize the* behavior.** bstrategy is normally given as NULL, but in autovacuum it can be passed* in to use the same buffer strategy object across multiple vacuum() calls.** isTopLevel should be passed down from ProcessUtility.** It is the caller's responsibility that all parameters are allocated in a* memory context that will not disappear at transaction commit.*/
void
vacuum(List *relations, VacuumParams *params,BufferAccessStrategy bstrategy, bool isTopLevel)
{static bool in_vacuum = false;const char *stmttype;volatile bool in_outer_xact,use_own_xacts;Assert(params != NULL);stmttype = (params->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";/** We cannot run VACUUM inside a user transaction block; if we were inside* a transaction, then our commit- and start-transaction-command calls* would not have the intended effect!  There are numerous other subtle* dependencies on this, too.** ANALYZE (without VACUUM) can run either way.* 不能在事务块在运行vacuum,但可以运行analyze*/if (params->options & VACOPT_VACUUM){PreventInTransactionBlock(isTopLevel, stmttype);in_outer_xact = false;}elsein_outer_xact = IsInTransactionBlock(isTopLevel);/** Due to static variables vac_context, anl_context and vac_strategy,* vacuum() is not reentrant.  This matters when VACUUM FULL or ANALYZE* calls a hostile index expression that itself calls ANALYZE.*/if (in_vacuum)ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),errmsg("%s cannot be executed from VACUUM or ANALYZE",stmttype)));/** Sanity check DISABLE_PAGE_SKIPPING option.*/if ((params->options & VACOPT_FULL) != 0 &&(params->options & VACOPT_DISABLE_PAGE_SKIPPING) != 0)ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),errmsg("VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL")));/* sanity check for PROCESS_TOAST */if ((params->options & VACOPT_FULL) != 0 &&(params->options & VACOPT_PROCESS_TOAST) == 0)ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),errmsg("PROCESS_TOAST required with VACUUM FULL")));/** Send info about dead objects to the statistics collector, unless we are* in autovacuum --- autovacuum.c does this for itself.*/if ((params->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess())pgstat_vacuum_stat();

跨事务存储需要分配特殊的内存上下文,内存上下文切换,buffer访问策略设置

/** Create special memory context for cross-transaction storage.** Since it is a child of PortalContext, it will go away eventually even* if we suffer an error; there's no need for special abort cleanup logic.*/vac_context = AllocSetContextCreate(PortalContext,"Vacuum",ALLOCSET_DEFAULT_SIZES);/** If caller didn't give us a buffer strategy object, make one in the* cross-transaction memory context.*/if (bstrategy == NULL){MemoryContext old_context = MemoryContextSwitchTo(vac_context);bstrategy = GetAccessStrategy(BAS_VACUUM);MemoryContextSwitchTo(old_context);}vac_strategy = bstrategy;

若relations参数不为空,构造对应列表用于处理;否则,会处理db中所有表。

 /** Build list of relation(s) to process, putting any new data in* vac_context for safekeeping.*/if (relations != NIL){List       *newrels = NIL;ListCell   *lc;foreach(lc, relations){VacuumRelation *vrel = lfirst_node(VacuumRelation, lc);List       *sublist;MemoryContext old_context;sublist = expand_vacuum_rel(vrel, params->options);old_context = MemoryContextSwitchTo(vac_context);newrels = list_concat(newrels, sublist);MemoryContextSwitchTo(old_context);}relations = newrels;}elserelations = get_all_vacuum_rels(params->options);

确定是否需要开启/提交自己的事务use_own_xacts。

对于vacuum(无论是否有analyze),总是需要use_own_xacts,以便尽快释放锁。

对于analyze(非vacuum):

  • autovacuum worker进程处理,需要use_own_xacts,以便尽快释放锁。
  • 如果在一个事务块内部,则无法use_own_xacts。
  • 如果操作多个表而又不在一个事务块中,需要use_own_xacts,以便尽快释放锁。
  • 如果只操作一个表,没有必要use_own_xacts。
/** Decide whether we need to start/commit our own transactions.** For VACUUM (with or without ANALYZE): always do so, so that we can* release locks as soon as possible.  (We could possibly use the outer* transaction for a one-table VACUUM, but handling TOAST tables would be* problematic.)** For ANALYZE (no VACUUM): if inside a transaction block, we cannot* start/commit our own transactions.  Also, there's no need to do so if* only processing one relation.  For multiple relations when not within a* transaction block, and also in an autovacuum worker, use own* transactions so we can release locks sooner.*/if (params->options & VACOPT_VACUUM)use_own_xacts = true;else{Assert(params->options & VACOPT_ANALYZE);if (IsAutoVacuumWorkerProcess())use_own_xacts = true;else if (in_outer_xact)use_own_xacts = false;else if (list_length(relations) > 1)use_own_xacts = true;elseuse_own_xacts = false;}/** vacuum_rel expects to be entered with no transaction active; it will* start and commit its own transaction.  But we are called by an SQL* command, and so we are executing inside a transaction already. We* commit the transaction started in PostgresMain() here, and start* another one before exiting to match the commit waiting for us back in* PostgresMain().*/if (use_own_xacts){Assert(!in_outer_xact);/* ActiveSnapshot is not set by autovacuum */if (ActiveSnapshotSet())PopActiveSnapshot();/* matches the StartTransaction in PostgresMain() */CommitTransactionCommand();}

核心部分:vacuum_rel与analyze_rel函数负责对每个表进行处理

 /* Turn vacuum cost accounting on or off, and set/clear in_vacuum */PG_TRY();{ListCell   *cur;in_vacuum = true;VacuumCostActive = (VacuumCostDelay > 0);VacuumCostBalance = 0;VacuumPageHit = 0;VacuumPageMiss = 0;VacuumPageDirty = 0;VacuumCostBalanceLocal = 0;VacuumSharedCostBalance = NULL;VacuumActiveNWorkers = NULL;/** Loop to process each selected relation. 循环处理每个表*/foreach(cur, relations){VacuumRelation *vrel = lfirst_node(VacuumRelation, cur);if (params->options & VACOPT_VACUUM){if (!vacuum_rel(vrel->oid, vrel->relation, params))continue;}if (params->options & VACOPT_ANALYZE){/** If using separate xacts, start one for analyze. Otherwise,* we can use the outer transaction.*/if (use_own_xacts){StartTransactionCommand();/* functions in indexes may want a snapshot set */PushActiveSnapshot(GetTransactionSnapshot());}analyze_rel(vrel->oid, vrel->relation, params,vrel->va_cols, in_outer_xact, vac_strategy);if (use_own_xacts){PopActiveSnapshot();CommitTransactionCommand();}else{/** If we're not using separate xacts, better separate the* ANALYZE actions with CCIs.  This avoids trouble if user* says "ANALYZE t, t".*/CommandCounterIncrement();}}}}PG_FINALLY();{in_vacuum = false;VacuumCostActive = false;}PG_END_TRY();
…/** Clean up working storage --- note we must do this after* StartTransactionCommand, else we might be trying to delete the active* context!*/MemoryContextDelete(vac_context);vac_context = NULL;
}

由于本系列主要学习vacuum操作,analyze_rel函数的分析暂时跳过了。

三、 vacuum_rel()函数

vacuum分为两类——常规vacuum(lazy vacuum)与full vacuum,本函数的核心就是调用函数进行lazy vacuum(table_relation_vacuum函数)或者full vacuum(cluster_rel函数)。

如果是full模式,需要获取8级表锁,lazy模式则只需要4级表锁。若表打开或加锁失败,则报错退出。

/**  vacuum_rel() -- vacuum one heap relation**      Returns true if it's okay to proceed with a requested ANALYZE*      operation on this table.**      At entry and exit, we are not inside a transaction.*/
static bool
vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
{LOCKMODE    lmode;Relation    rel;LockRelId   lockrelid;Oid         toast_relid;Oid         save_userid;int         save_sec_context;int         save_nestlevel;Assert(params != NULL);/* Begin a transaction for vacuuming this relation */StartTransactionCommand();…/** Determine the type of lock we want --- hard exclusive lock for a FULL* vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either* way, we can be sure that no other backend is vacuuming the same table.*/lmode = (params->options & VACOPT_FULL) ?AccessExclusiveLock : ShareUpdateExclusiveLock;/* open the relation and get the appropriate lock on it */rel = vacuum_open_relation(relid, relation, params->options,params->log_min_duration >= 0, lmode);/* leave if relation could not be opened or locked */if (!rel){PopActiveSnapshot();CommitTransactionCommand();return false;}
  • 检查用户权限,是否需要跳过该表vacuum
  • 检查表是否可以vacuum
  • 跳过其他进程的temp表
  • 跳过分区表,分区表的vacuum应该针对它们的子表(已加入处理队列中)
 /** Check if relation needs to be skipped based on ownership.*/if (!vacuum_is_relation_owner(RelationGetRelid(rel),rel->rd_rel,params->options & VACOPT_VACUUM)){relation_close(rel, lmode);PopActiveSnapshot();CommitTransactionCommand();return false;}/** Check that it's of a vacuumable relkind.*/if (rel->rd_rel->relkind != RELKIND_RELATION &&rel->rd_rel->relkind != RELKIND_MATVIEW &&rel->rd_rel->relkind != RELKIND_TOASTVALUE &&rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE){ereport(WARNING,(errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",RelationGetRelationName(rel))));relation_close(rel, lmode);PopActiveSnapshot();CommitTransactionCommand();return false;}/** Silently ignore tables that are temp tables of other backends*/if (RELATION_IS_OTHER_TEMP(rel)){relation_close(rel, lmode);PopActiveSnapshot();CommitTransactionCommand();return false;}/** Silently ignore partitioned tables as there is no work to be done.  The* useful work is on their child partitions, which have been queued up for* us separately.*/if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE){relation_close(rel, lmode);PopActiveSnapshot();CommitTransactionCommand();/* It's OK to proceed with ANALYZE on this table */return true;}
  • 获取会话级锁,主要是用于vacuum toast表
  • 设置index_cleanup、truncate选项
  • 如果调用者要求处理toast表,非full模式下,获取其relid;full模式下,cluster_rel函数会自动重建toast表,因此不需要重复处理
 /** Get a session-level lock too. This will protect our access to the* relation across multiple transactions, so that we can vacuum the* relation's TOAST table (if any) secure in the knowledge that no one is* deleting the parent relation.** NOTE: this cannot block, even if someone else is waiting for access,* because the lock manager knows that both lock requests are from the* same process.*/lockrelid = rel->rd_lockInfo.lockRelId;LockRelationIdForSession(&lockrelid, lmode);/** Set index_cleanup option based on index_cleanup reloption if it wasn't* specified in VACUUM command, or when running in an autovacuum worker*/if (params->index_cleanup == VACOPTVALUE_UNSPECIFIED){StdRdOptIndexCleanup vacuum_index_cleanup;if (rel->rd_options == NULL)vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO;elsevacuum_index_cleanup =((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup;if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO)params->index_cleanup = VACOPTVALUE_AUTO;else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON)params->index_cleanup = VACOPTVALUE_ENABLED;else{Assert(vacuum_index_cleanup ==STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF);params->index_cleanup = VACOPTVALUE_DISABLED;}}/** Set truncate option based on truncate reloption if it wasn't specified* in VACUUM command, or when running in an autovacuum worker*/if (params->truncate == VACOPTVALUE_UNSPECIFIED){if (rel->rd_options == NULL ||((StdRdOptions *) rel->rd_options)->vacuum_truncate)params->truncate = VACOPTVALUE_ENABLED;elseparams->truncate = VACOPTVALUE_DISABLED;}/** Remember the relation's TOAST relation for later, if the caller asked* us to process it.  In VACUUM FULL, though, the toast table is* automatically rebuilt by cluster_rel so we shouldn't recurse to it.*/if ((params->options & VACOPT_PROCESS_TOAST) != 0 &&(params->options & VACOPT_FULL) == 0)toast_relid = rel->rd_rel->reltoastrelid;elsetoast_relid = InvalidOid;
…

核心工作——进行lazy vacuum(table_relation_vacuum函数)或者full vacuum(cluster_rel函数)。如果该表有toast表,会对toast表再调用vacuum_rel函数。

    /** Do the actual work --- either FULL or "lazy" vacuum*/if (params->options & VACOPT_FULL){ClusterParams cluster_params = {0};/* close relation before vacuuming, but hold lock until commit */relation_close(rel, NoLock);rel = NULL;if ((params->options & VACOPT_VERBOSE) != 0)cluster_params.options |= CLUOPT_VERBOSE;/* VACUUM FULL is now a variant of CLUSTER; see cluster.c */cluster_rel(relid, InvalidOid, &cluster_params);}elsetable_relation_vacuum(rel, params, vac_strategy);/* Roll back any GUC changes executed by index functions */AtEOXact_GUC(false, save_nestlevel);/* Restore userid and security context */SetUserIdAndSecContext(save_userid, save_sec_context);/* all done with this class, but hold lock until commit */if (rel)relation_close(rel, NoLock);/** Complete the transaction and free all temporary memory used.*/PopActiveSnapshot();CommitTransactionCommand();/** If the relation has a secondary toast rel, vacuum that too while we* still hold the session lock on the main table.  Note however that* "analyze" will not get done on the toast table.  This is good, because* the toaster always uses hardcoded index access and statistics are* totally unimportant for toast relations.*/if (toast_relid != InvalidOid)vacuum_rel(toast_relid, NULL, params);/** Now release the session-level lock on the main table.*/UnlockRelationIdForSession(&lockrelid, lmode);/* Report that we really did it. */return true;
}

后面,我们继续学习lazy vacuum(table_relation_vacuum函数)与full vacuum(cluster_rel函数)。

参考:

《PostgreSQL数据库内核分析》

PostgreSQL 源码解读(125)- MVCC#9(vacuum-主流程)_ITPUB博客

PostgreSQL 源码解读(126)- MVCC#10(vacuum过程)_ITPUB博客

http://blog.itpub.net/6906/viewspace-2564441/

postgresql源码学习(52)—— vacuum①-准备工作与主要流程相关推荐

  1. postgresql源码学习(49)—— MVCC⑤-cmin与cmax 同事务内的可见性判断

    一. 难以理解的场景 postgresql源码学习(十九)-- MVCC④-可见性判断 HeapTupleSatisfiesMVCC函数_Hehuyi_In的博客-CSDN博客 在前篇的可见性判断中有 ...

  2. PostgreSQL源码学习(1)--PG13代码结构

    PostgreSQL源码学习(1)–PG13代码结构 PostgreSQL代码结构 Bootstrap:用于支持Bootstrap运行模式,该模式主要用来创建初始的模板数据库. Main:主程序模块, ...

  3. PostgreSQL源码学习(一)编译安装与GDB入门

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 PostgreSQL源码学习(一)编译安装与GDB入门 前言 一.安装PostgreSQL 1.获取源码 2.配置 3.编译 3.安装 ...

  4. postgresql源码学习(27)—— 事务日志⑦-日志落盘上层函数 XLogFlush

    一. 预备知识 1. XLOG什么时候需要落盘 事务commit之前 log buffer被覆盖之前 后台进程定期落盘 2. 两个核心结构体 这两个结构体定义代码在xlog.c,它们在日志落盘过程中非 ...

  5. postgresql源码学习(51)—— 提交日志CLOG 原理 用途 管理函数

    一. CLOG是什么 CLOG(commit log)记录事务的最终状态. 物理上,是$PGDATA/pg_xact目录下的一些文件 逻辑上,是一个数组,下标为事务id,值为事务最终状态 1. 事务最 ...

  6. gallery3d源码学习总结(一)——绘制流程drawFocusItems

    eoe·Android开发者门户 标题: gallery3d源码学习总结(一)--绘制流程drawFocusItems [打印本页] 作者: specialbrian    时间: 2010-10-2 ...

  7. postgresql源码学习(53)—— vacuum②-lazy vacuum之heap_vacuum_rel函数

    一. table_relation_vacuum函数 1. 函数定义 前篇最后(https://blog.csdn.net/Hehuyi_In/article/details/128749517),我 ...

  8. postgresql源码学习(57)—— pg中的四种动态库加载方法

    一. 基础知识 1. 什么是库 库其实就是一些通用代码,可以在程序中重复使用,比如一些数学函数,可以不需要自己编写,直接调用相关函数即可实现,避免重复造轮子. 在linux中,支持两种类型的库: 1. ...

  9. postgresql源码学习(一)—— 源码编译安装与gdb调试入门

    一. postgresql源码编译安装 因为只是用来调试的测试环境,把基本的软件装好和库建好就可以,一切从简. 1. 创建用户和目录 mkdir -p /data/postgres/base/ mkd ...

最新文章

  1. java8 stream_使用Java Stream摘要统计
  2. 50个比特怎么生成10个码元_你们最关心的42个计算机网络基础问答
  3. springboot 不同环境不同的配置
  4. 嵌入式开发linux工具,嵌入式Linux开发入门之MfgTool工具的使用
  5. python中可选参数是什么意思_Python如何定义有可选参数的元类
  6. JavaScript垃圾回收
  7. ipad分屏大小怎么调整_flash怎么调整元素大小-Adobe flash统一图形大小的方法
  8. 轻量级自动化运维工具ansible之一:初步介绍及简单运用
  9. wsgiserver python 漏洞_python-简单测试wsgi
  10. 几组数据的相关性python_Python数据相关系数矩阵和热力图轻松实现(参数解释)...
  11. 计算机主机要系统,计算机系统(主机).ppt
  12. 优先深度搜索判断曲线相交_深度优先搜索(Depth-first search)是如何搜索一张图的?...
  13. 华为笔试题——分礼物
  14. linux mysql 视频教程_Linux视频教程基础入门到精通Shell高级编程实战/Nginx/MySQL运维视频教程下载...
  15. ASP.NET公司企业网站源码
  16. Qt5+vs2017 UI界面添加新控件后,提示没有类成员
  17. 还原html默认打开方式,怎么还原打开方式,详细教您Win10系统下如何还原程序默认打开方式...
  18. 安徽师范大学898专硕复习讲义
  19. 科罗拉多州立大学计算机科学,科罗拉多州立大学的世界排名
  20. AtCoder Grand Contest 012 E - Camel and Oases 状压dp

热门文章

  1. ubuntu 9.04 X3100 显卡开启3D特效
  2. error reconnecting to master ‘userName@192.168.1.88:3306‘ - retry-time: 60 maximum-retries: 86400
  3. 抖音、拼多多、趣头条告诉我们:一切商业均有机会
  4. WinForm调用摄像头扫码识别二维码
  5. 8g服务器虚拟机,T61P支持8G内存,VirtualPC跑32个WS08虚拟机,这世界太疯狂了!
  6. 拼题A 基础篇13 查询水果价格
  7. 大学计算机基础信息编码,大学计算机基础-编码.ppt
  8. OpenCore引导安装联想-M920x黑苹果之历程
  9. 我的专业我的梦作文计算机,我的世界,我的梦作文500字
  10. android+噪音测试,Android技术开发之:噪音测试