初步学习pg_control文件之十二

简介:

接前问,初步学习pg_control文件之十一,再来看下面这个

XLogRecPtr    minRecoveryPoint;

看其注释:

     * minRecoveryPoint is updated to the latest replayed LSN whenever we
     * flush a data change during archive recovery. That guards against
     * starting archive recovery, aborting it, and restarting with an earlier
     * stop location. If we've already flushed data changes from WAL record X
     * to disk, we mustn't start up until we reach X again. Zero when not
     * doing archive recovery.

看来,是为了防止出现重复执行重做日志...它强调的是在 archive recovery的情况下。

启动时,如果处于Recovery状态,则要进行设置:

复制代码
/*                                    
 * This must be called ONCE during postmaster or standalone-backend startup                                    
 */                                    
void                                    
StartupXLOG(void)                                    
{                                    
    …                                
    CheckPoint    checkPoint;                            
    …                                
    /*                                
     * Read control file and check XLOG status looks valid.    
     * Note: in most control paths, *ControlFile is already valid and we need  
     * not do ReadControlFile() here, but might as well do it to be sure.                                
     */                                
    ReadControlFile();                                
                                    
    if (ControlFile->state < DB_SHUTDOWNED ||                                
        ControlFile->state > DB_IN_PRODUCTION ||                            
        !XRecOffIsValid(ControlFile->checkPoint.xrecoff))                            
        ereport(FATAL,                            
                (errmsg("control file contains invalid data")));                    
    …                                
                                    
    /* REDO */                                
    if (InRecovery)                                
    {                                
        …                            
        if (InArchiveRecovery)                            
        {                            
            /* initialize minRecoveryPoint if not set yet */                        
            if (XLByteLT(ControlFile->minRecoveryPoint, checkPoint.redo))                        
                ControlFile->minRecoveryPoint = checkPoint.redo;                    
        }                            
    …                                
    }                                
    …                                
}                                    
复制代码

在xlogredo函数中得到处理:

复制代码
/*                                    
 * XLOG resource manager's routines                                    
 *                                    
 * Definitions of info values are in include/catalog/pg_control.h, though                                    
 * not all record types are related to control file updates.                                    
 */                                    
void                                    
xlog_redo(XLogRecPtr lsn, XLogRecord *record)                                    
{                                    
    …                                
    if (info == XLOG_NEXTOID)                                
    {                                
        …                            
    }                                
    …                                
    else if (info == XLOG_BACKUP_END)                                
    {                                
        …                            
        if (XLByteEQ(ControlFile->backupStartPoint, startpoint))                            
        {                            
            /*                        
             * We have reached the end of base backup, the point where                        
             * pg_stop_backup() was done. The data on disk is now consistent.                        
             * Reset backupStartPoint, and update minRecoveryPoint to make                        
             * sure we don't allow starting up at an earlier point even if                        
             * recovery is stopped and restarted soon after this.                        
             */                        
            …                        
            LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);                        
                                    
            if (XLByteLT(ControlFile->minRecoveryPoint, lsn))                        
                ControlFile->minRecoveryPoint = lsn;                    
            MemSet(&ControlFile->backupStartPoint, 0, sizeof(XLogRecPtr));                        
            UpdateControlFile();                        
                                    
            LWLockRelease(ControlFileLock);                        
        }                            
    }                                
    else if (info == XLOG_PARAMETER_CHANGE)                                
    {                                
        …                            
        LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);                            
        ControlFile->MaxConnections = xlrec.MaxConnections;                            
        ControlFile->max_prepared_xacts = xlrec.max_prepared_xacts;                            
        ControlFile->max_locks_per_xact = xlrec.max_locks_per_xact;                            
        ControlFile->wal_level = xlrec.wal_level;                            
                                    
        /*                            
         * Update minRecoveryPoint to ensure that if recovery is aborted, we                            
         * recover back up to this point before allowing hot standby again.                            
         * This is particularly important if wal_level was set to 'archive'                            
         * before, and is now 'hot_standby', to ensure you don't run queries                            
         * against the WAL preceding the wal_level change. Same applies to                            
         * decreasing max_* settings.                            
         */                            
        minRecoveryPoint = ControlFile->minRecoveryPoint;                            
        if ((minRecoveryPoint.xlogid != 0 || minRecoveryPoint.xrecoff != 0)                            
            && XLByteLT(minRecoveryPoint, lsn))                        
        {                            
            ControlFile->minRecoveryPoint = lsn;                        
        }                            
                                    
        UpdateControlFile();                            
        LWLockRelease(ControlFileLock);                            
        …                            
    }                                
}                                    
复制代码

再就是checkpoint发生的时候,也做了处理:

CreateCheckPoint -->XLogFlush--> UpdateMinRecoveryPoint

复制代码
/*                                
 * Perform a checkpoint --- either during shutdown, or on-the-fly                                
 *                                
 * flags is a bitwise OR of the following:                                
 *    CHECKPOINT_IS_SHUTDOWN: checkpoint is for database shutdown.                            
 *    CHECKPOINT_END_OF_RECOVERY: checkpoint is for end of WAL recovery.                            
 *    CHECKPOINT_IMMEDIATE: finish the checkpoint ASAP,                            
 *        ignoring checkpoint_completion_target parameter.                        
 *    CHECKPOINT_FORCE: force a checkpoint even if no XLOG activity has occured                            
 *        since the last one (implied by CHECKPOINT_IS_SHUTDOWN or                        
 *        CHECKPOINT_END_OF_RECOVERY).                        
 *                                
 * Note: flags contains other bits, of interest here only for logging purposes.                                
 * In particular note that this routine is synchronous and does not pay                                
 * attention to CHECKPOINT_WAIT.                                
 */                                
void                                
CreateCheckPoint(int flags)                                
{                                
    …                            
    recptr = XLogInsert(RM_XLOG_ID,                            
                shutdown ? XLOG_CHECKPOINT_SHUTDOWN :                
                XLOG_CHECKPOINT_ONLINE,                
                &rdata);                
                                
    XLogFlush(recptr);                            
    …                            
}                                
复制代码
复制代码
/*                            
 * Ensure that all XLOG data through the given position is flushed to disk.                            
 *                            
 * NOTE: this differs from XLogWrite mainly in that the WALWriteLock is not                            
 * already held, and we try to avoid acquiring it if possible.                            
 */                            
void                            
XLogFlush(XLogRecPtr record)                            
{                            
    XLogRecPtr        WriteRqstPtr;                
    XLogwrtRqst WriteRqst;                        
                            
    /*                        
     * During REDO, we are reading not writing WAL.  Therefore, instead of                        
     * trying to flush the WAL, we should update minRecoveryPoint instead. We                        
     * test XLogInsertAllowed(), not InRecovery, because we need the bgwriter                        
     * to act this way too, and because when the bgwriter tries to write the                        
     * end-of-recovery checkpoint, it should indeed flush.                        
     */                        
    if (!XLogInsertAllowed())                        
    {                        
        UpdateMinRecoveryPoint(record, false);                    
        return;                    
    }                        
                            
    /* Quick exit if already known flushed */                        
    if (XLByteLE(record, LogwrtResult.Flush))                        
        return;                    
                            
    …                        
}                            
复制代码
复制代码
/*                                            
 * Advance minRecoveryPoint in control file.  
 * If we crash during recovery, we must reach this point again before the                                            
 * database is consistent.                   
 * If 'force' is true, 'lsn' argument is ignored. Otherwise, minRecoveryPoint 
 * is only updated if it's not already greater than or equal to 'lsn'. 
 */                                            
static void                                            
UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)                                            
{                                            
    …                                        
    /*                                        
     * An invalid minRecoveryPoint means that we need to recover all the WAL,  
     * i.e., we're doing crash recovery.  We never modify the control file's
     * value in that case, so we can short-circuit future checks here too. 
     */                                        
    if (minRecoveryPoint.xlogid == 0 && minRecoveryPoint.xrecoff == 0)
        updateMinRecoveryPoint = false;                                    
    else if (force || XLByteLT(minRecoveryPoint, lsn))                                        
    {                                        
        /* use volatile pointer to prevent code rearrangement */                                    
        volatile XLogCtlData *xlogctl = XLogCtl;                                    
        XLogRecPtr        newMinRecoveryPoint;                            
                                            
        /*                                    
         * To avoid having to update the control file too often, we update it  
         * all the way to the last record being replayed, even though 'lsn'
         * would suffice for correctness.  This also allows the 'force' case  
         * to not need a valid 'lsn' value.                                    
         *                                    
         * Another important reason for doing it this way is that the passed  
         * 'lsn' value could be bogus, i.e., past the end of available WAL, if  
         * the caller got it from a corrupted heap page.  Accepting such a   
         * value as the min recovery point would prevent us from coming up at  
         * all.  Instead, we just log a warning and continue with recovery.  
         * (See also the comments about corrupt LSNs in XLogFlush.)                                    
         */                                    
        SpinLockAcquire(&xlogctl->info_lck);                                    
        newMinRecoveryPoint = xlogctl->replayEndRecPtr;                                    
        SpinLockRelease(&xlogctl->info_lck);                                    
                                            
        if (!force && XLByteLT(newMinRecoveryPoint, lsn))                                    
            elog(WARNING,                                
               "xlog min recovery request %X/%X is past current point %X/%X", 
                 lsn.xlogid, lsn.xrecoff,                            
                 newMinRecoveryPoint.xlogid, newMinRecoveryPoint.xrecoff);                            
                                            
        /* update control file */                                    
        if (XLByteLT(ControlFile->minRecoveryPoint, newMinRecoveryPoint))                                    
        {                                    
            ControlFile->minRecoveryPoint = newMinRecoveryPoint;                                
            UpdateControlFile();                                
            minRecoveryPoint = newMinRecoveryPoint;                                
                                            
            ereport(DEBUG2,                                
                    (errmsg("updated min recovery point to %X/%X",                        
                        minRecoveryPoint.xlogid, minRecoveryPoint.xrecoff)));                    
        }                                    
    }                                        
    LWLockRelease(ControlFileLock);                                        
}                                            
复制代码
目录
相关文章
|
关系型数据库 PostgreSQL 流计算
Pacemaker pgsql RA脚本分析
Pacemaker + Cronsync可以说是目前为止搭建PostgreSQL HA集群最简单靠谱的方式。而完成这一任务的主要是PostgreSQL的RA脚本文件pgsql。关于pgsql的使用说明请参考:http://clusterlabs.org/wiki/PgSQL_Replicated_Cluster 本文探讨一下pgsql的实现逻辑。
2449 0
|
8天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
7天前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
344 130
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
|
19天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1331 8
|
7天前
|
人工智能 Java API
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
本文介绍AI大模型的核心概念、分类及开发者学习路径,重点讲解如何选择与接入大模型。项目基于Spring Boot,使用阿里云灵积模型(Qwen-Plus),对比SDK、HTTP、Spring AI和LangChain4j四种接入方式,助力开发者高效构建AI应用。
333 122
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
|
6天前
|
监控 JavaScript Java
基于大模型技术的反欺诈知识问答系统
随着互联网与金融科技发展,网络欺诈频发,构建高效反欺诈平台成为迫切需求。本文基于Java、Vue.js、Spring Boot与MySQL技术,设计实现集欺诈识别、宣传教育、用户互动于一体的反欺诈系统,提升公众防范意识,助力企业合规与用户权益保护。
|
18天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
1419 87
|
6天前
|
JavaScript Java 大数据
基于JavaWeb的销售管理系统设计系统
本系统基于Java、MySQL、Spring Boot与Vue.js技术,构建高效、可扩展的销售管理平台,实现客户、订单、数据可视化等全流程自动化管理,提升企业运营效率与决策能力。