千家信息网

PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析

发表于:2024-12-13 作者:千家信息网编辑
千家信息网最后更新 2024年12月13日,本篇内容主要讲解"PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学
千家信息网最后更新 2024年12月13日PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析

本篇内容主要讲解"PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析"吧!

一、数据结构

宏定义
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;

二、源码解读

HeapTupleSatisfiesVacuum
HeapTupleSatisfiesVacuum为VACUUM操作确定元组的状态.在这里,我们主要想知道的是一个元组是否可对所有正在运行中的事务可见.如可见,则不能通过VACUUM删除该元组.

主要处理流程如下:
0.获取tuple并执行相关校验
1.条件:插入事务未提交
1.1条件:无效的xmin,该元组已废弃可删除
1.2条件:旧版本(9.0-)的判断
1.3条件:xmin为当前事务ID
1.4条件:插入事务非当前事务,正在进行中
1.5条件:xmin事务确实已提交(通过clog判断)
1.6条件:其他情况
- 至此,可以确定xmin已提交
2.条件:xmax是无效的事务ID,直接返回LIVE
3.条件:xmax只是锁定
3.1条件:xmax事务未提交,分多事务&非多事务进行判断
3.2条件:只是锁定,返回LIVE
4.条件:存在子事务
4.1条件:xmax正在进行,返回事务进行中
4.2条件:xmax已提交,区分xmax在OldestXmin之前还是之后
4.3条件:xmax不在运行中/没有提交/没有回滚或崩溃,则设置xmax为无效事务ID
4.4默认返回LIVE
5.条件:xmax没有提交
5.1条件:删除过程中
5.2条件:通过clog判断,该事务已提交,设置事务标记位
5.3条件:其他情况,设置为无效事务ID
5.4默认返回LIVE
- 至此,可以确定xmax已提交
6.元组xmax≥OldestXmin,最近删除
7.默认元组已DEAD

/* * HeapTupleSatisfiesVacuum * *  Determine the status of tuples for VACUUM purposes.  Here, what *  we mainly want to know is if a tuple is potentially visible to *any* *  running transaction.  If so, it can't be removed yet by VACUUM. *  为VACUUM确定元组的状态. *  在这里,我们主要想知道的是一个元组是否可对所有正在运行中的事务可见. *  如可见,则不能通过VACUUM删除该元组. * * OldestXmin is a cutoff XID (obtained from GetOldestXmin()).  Tuples * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might * still be visible to some open transaction, so we can't remove them, * even if we see that the deleting transaction has committed. * OldestXmin是一个cutoff XID(通过GetOldestXmin函数获得). * 通过XIDs >= OldestXmin删除的元组被视为"最近死亡",它们可能仍然对某些正在进行中的事务可见, *   因此就算删除事务已提交,我们仍然不能清除它们. */HTSV_ResultHeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,                         Buffer buffer){    //获取tuple    HeapTupleHeader tuple = htup->t_data;    //校验    Assert(ItemPointerIsValid(&htup->t_self));    Assert(htup->t_tableOid != InvalidOid);    /*     * Has inserting transaction committed?     * 插入事务已提交?     *     * If the inserting transaction aborted, then the tuple was never visible     * to any other transaction, so we can delete it immediately.     * 如果插入事务已回滚,元组对其他事务均不可见,因此可以马上删除.     */    if (!HeapTupleHeaderXminCommitted(tuple))    {        //1.插入事务未提交        if (HeapTupleHeaderXminInvalid(tuple))            //1-1.无效的xmin,该元组已废弃可删除            return HEAPTUPLE_DEAD;        /* Used by pre-9.0 binary upgrades */        //用于9.0以前版本的升级,HEAP_MOVED_OFF&HEAP_MOVED_IN已不再使用        else if (tuple->t_infomask & HEAP_MOVED_OFF)        {            TransactionId xvac = HeapTupleHeaderGetXvac(tuple);            if (TransactionIdIsCurrentTransactionId(xvac))                return HEAPTUPLE_DELETE_IN_PROGRESS;            if (TransactionIdIsInProgress(xvac))                return HEAPTUPLE_DELETE_IN_PROGRESS;            if (TransactionIdDidCommit(xvac))            {                SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,                            InvalidTransactionId);                return HEAPTUPLE_DEAD;            }            SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,                        InvalidTransactionId);        }        /* Used by pre-9.0 binary upgrades */        //用于9.0以前版本的升级        else if (tuple->t_infomask & HEAP_MOVED_IN)        {            TransactionId xvac = HeapTupleHeaderGetXvac(tuple);            if (TransactionIdIsCurrentTransactionId(xvac))                return HEAPTUPLE_INSERT_IN_PROGRESS;            if (TransactionIdIsInProgress(xvac))                return HEAPTUPLE_INSERT_IN_PROGRESS;            if (TransactionIdDidCommit(xvac))                SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,                            InvalidTransactionId);            else            {                SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,                            InvalidTransactionId);                return HEAPTUPLE_DEAD;            }        }        else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))        {            //1-3.xmin为当前事务ID            if (tuple->t_infomask & HEAP_XMAX_INVALID)  /* xid invalid */                //1-3-1.xmax无效,说明插入事务正在进行中                return HEAPTUPLE_INSERT_IN_PROGRESS;            /* only locked? run infomask-only check first, for performance */            //只是锁定?性能考虑,首先执行infomask-only检查            if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||                HeapTupleHeaderIsOnlyLocked(tuple))                //1-3-2.锁定状态(如for update之类),事务正在进行中                return HEAPTUPLE_INSERT_IN_PROGRESS;            /* inserted and then deleted by same xact */            //插入,然后删除            if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))                //1-3-3.插入,然后删除                return HEAPTUPLE_DELETE_IN_PROGRESS;            /* deleting subtransaction must have aborted */            //默认:插入事务正在进行中            return HEAPTUPLE_INSERT_IN_PROGRESS;        }        else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))        {            //1-4.插入事务非当前事务,正在进行中            /*             * It'd be possible to discern between INSERT/DELETE in progress             * here by looking at xmax - but that doesn't seem beneficial for             * the majority of callers and even detrimental for some. We'd             * rather have callers look at/wait for xmin than xmax. It's             * always correct to return INSERT_IN_PROGRESS because that's             * what's happening from the view of other backends.             * 通过查看xmax,可以区分正在进行的插入/删除操作 - 但这对于大多数调用者并没有好处,甚至有害             * 我们宁愿让调用者查看/等待xmin而不是xmax。             * 返回INSERT_IN_PROGRESS总是正确的,因为这是从其他后台进程视图中看到正在发生的。             */            return HEAPTUPLE_INSERT_IN_PROGRESS;        }        else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))            //1-5.xmin事务确实已提交(通过clog判断)            SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,                        HeapTupleHeaderGetRawXmin(tuple));        else        {            //1-5.其他情况            //既不在进行中,也没有提交,要么是回滚,要么是崩溃了            /*             * Not in Progress, Not Committed, so either Aborted or crashed             */            //设置标记位            SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,                        InvalidTransactionId);            //返回废弃标记            return HEAPTUPLE_DEAD;        }        /*         * At this point the xmin is known committed, but we might not have         * been able to set the hint bit yet; so we can no longer Assert that         * it's set.         * 在这个点上,xmin事务确认已提交,但这时候还是不能设置hint bit,         *   因此不能断定已设置标记.         */    }    /*     * Okay, the inserter committed, so it was good at some point.  Now what     * about the deleting transaction?     * 插入数据的事务已提交,现在可以看看删除事务的状态了.     */    if (tuple->t_infomask & HEAP_XMAX_INVALID)        //------- 2.xmax是无效的事务ID,直接返回LIVE        return HEAPTUPLE_LIVE;    if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))    {        //------- 3.锁定        /*         * "Deleting" xact really only locked it, so the tuple is live in any         * case.  However, we should make sure that either XMAX_COMMITTED or         * XMAX_INVALID gets set once the xact is gone, to reduce the costs of         * examining the tuple for future xacts.         * "Deleting"事务确实只是锁定该元组,因此该元组是存活状态.         * 但是,我们应该确保不管是XMAX_COMMITTED还是XMAX_INVALID标记,应该在事务完结后马上设置,         *   这样可以减少为了事务检查元组状态的成本.         */        if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))        {            //3.1 xmax事务未提交            if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)            {                //3.1.1 多事务                /*                 * If it's a pre-pg_upgrade tuple, the multixact cannot                 * possibly be running; otherwise have to check.                 * 如果是pre-pg_upgrade元组,多事务不可能运行,否则的话,只能执行检查                 */                if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&                    MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),                                         true))                    return HEAPTUPLE_LIVE;                //其他情况,根据clog重新设置事务状态标记位                SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);            }            else            {                //3.1.2 非多事务                if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))                    //xmax事务正在进行,返回LIVE                    return HEAPTUPLE_LIVE;                //否则,根据clog重新设置事务状态标记位                SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,                            InvalidTransactionId);            }        }        /*         * We don't really care whether xmax did commit, abort or crash. We         * know that xmax did lock the tuple, but it did not and will never         * actually update it.         * 我们确实不需要真正关心xmax是否提交/回滚/崩溃.         * 我们知道xmax事务锁定了元组,但没有而且"从未"更新过该元组.         */        //3.2 只是锁定,返回LIVE        return HEAPTUPLE_LIVE;    }    if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)    {        //4.存在子事务        //获取删除事务号xmax        TransactionId xmax = HeapTupleGetUpdateXid(tuple);        /* already checked above */        Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));        /* not LOCKED_ONLY, so it has to have an xmax */        //根据上述xmax的判断,到这里可以肯定xmax是有效的        Assert(TransactionIdIsValid(xmax));        if (TransactionIdIsInProgress(xmax))            //4.1 xmax正在进行,返回进行中            return HEAPTUPLE_DELETE_IN_PROGRESS;        else if (TransactionIdDidCommit(xmax))        {            //4.2 xmax已提交            /*             * The multixact might still be running due to lockers.  If the             * updater is below the xid horizon, we have to return DEAD             * regardless -- otherwise we could end up with a tuple where the             * updater has to be removed due to the horizon, but is not pruned             * away.  It's not a problem to prune that tuple, because any             * remaining lockers will also be present in newer tuple versions.             */            if (!TransactionIdPrecedes(xmax, OldestXmin))                //4.2.1 xmax在OldestXmin之后,                //表示在OldestXmin之后才删除,返回HEAPTUPLE_RECENTLY_DEAD                return HEAPTUPLE_RECENTLY_DEAD;            //4.2.2 xmax在OldestXmin之前,返回DEAD            return HEAPTUPLE_DEAD;        }        else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))        {            /*             * Not in Progress, Not Committed, so either Aborted or crashed.             * Mark the Xmax as invalid.             */            //4.3 xmax不在运行中/没有提交/没有回滚或崩溃,则设置xmax为无效事务ID            SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId);        }        //4.4 默认返回LIVE        return HEAPTUPLE_LIVE;    }    if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))    {        //5.xmax没有提交        if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))            //5.1 删除过程中            return HEAPTUPLE_DELETE_IN_PROGRESS;        else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))            //5.2 通过clog判断,该事务已提交,设置事务标记位            SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,                        HeapTupleHeaderGetRawXmax(tuple));        else        {            /*             * Not in Progress, Not Committed, so either Aborted or crashed             */            //5.3 其他情况,设置为无效事务ID            SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,                        InvalidTransactionId);            //返回LIVE            return HEAPTUPLE_LIVE;        }        /*         * At this point the xmax is known committed, but we might not have         * been able to set the hint bit yet; so we can no longer Assert that         * it's set.         */        //至此,xmax可以确认已提交    }    /*     * Deleter committed, but perhaps it was recent enough that some open     * transactions could still see the tuple.     */    if (!TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin))        //6.元组xmax≥OldestXmin,最近删除        return HEAPTUPLE_RECENTLY_DEAD;    /* Otherwise, it's dead and removable */    //7. 默认元组已DEAD    return HEAPTUPLE_DEAD;}

到此,相信大家对"PostgreSQL中vacuum过程HeapTupleSatisfiesVacuum函数分析"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0