PostgreSQL启动过程中的那些事十六:启动进程二

这节主要讨论启动进程到了StartupXLOG。根据情况,如果需要就排除系统故障引起的数据库不一致状态,做相应的REDO或UNDO,然后创建一个检查点,把所有共享内存磁盘缓冲和提交数据缓冲写并文件同步到磁盘、把检查点插入xlog文件、更新控制文件,使数据库达到一种状态,设置共享内存中XLogCtl、ShmemVariableCache等对象信息;如果不需要,就根据控制文件从xlog文件读取最后的检查点信息,设置共享内存中XLogCtl、ShmemVariableCache等对象信息;启动完XLOG,启动进程完成使命,自己做了了断,postmaster进程根据子进程结束信号响应句柄继续。

目前没有看到数据文件里记录了检查点,难道这个没有???

3

先上个图

方法调用序列示意图

4

上StartupXLog方法的处理流程示意图

StartupXLog 流程示意图

数据库在什么情况下需要恢复。如果出现事务故障、系统故障或者介质故障时,数据库需要恢复。出现诸如运算溢出、死锁、违反完整性约束等事务故障时数据库在运行时可以通过强制回滚自行处理。系统故障是主存数据丢失,未完成事务有些数据已写到物理数据库,此时数据库启动时需要事务回滚(UNDO/rollback)恢复。已完成事务有些或全部数据未写到物理数据库,此时数据库启动时需要重做(REDO)已提交事务。介质故障,需要从以前的备份做专门恢复。

话说到了XLogStartup方法,在这个方法里最主要的是根据情况判断是否需要恢复。如果不需要恢复,处理比较简单;如果需要恢复,根据不同状况做相应恢复。这儿这个状况就是判断系统是否在上次关闭时出现了系统故障。

XLogStartup方法,先读取控制文件pg_control到ControlFileData数据结构,再看是否有恢复命令文件recovery.conf(判断是否是归档模式,如果归档模式,需要恢复的话,就是归档恢复),读取内容并设置InArchiveRecovery = true,并根据情况,如果是hot standby的从系统,设置StandbyMode = true。接着读时间线历史文件。然后把来自控制文件的恢复目标时间线recoveryTargetTLI和归档清楚命令archive_cleanup_command保存于共享内存中的xlog控制结构XLogCtl的相关成员里以备其它进程查看。接着调用read_backup_label方法看是否有备份标签文件$PGDATA$/backup_label,如果有,从中取检查点记录位置赋给checkPointLoc,如果没有备份标签文件,把控制文件里的检查点位置赋给checkPointLoc。根据这个检查点位置指针checkPointLoc从xlog文件中读这个检查点的xlog记录解析到检查点对象checkpoint。根据其自身位置指针和其记录的下一个xlog记录位置指针,或者控制文件记录的数据库是否非正常关闭状态或ControlFile->state != DB_SHUTDOWNED者有无recover.conf文件,判断是否需要恢复。

如果不需要恢复,更新控制文件的state等于DB_IN_PRODUCTIONtime等于系统当前时间。接着设置共享内存里的XLogCtl的成员Write.lastSegSwitchTime为当前时间,根据控制文件初始化XLogCtl的最后的检查点的XID/epoch再初始化共享内存里缓存变量结构ShmemVariableCachelatestCompletedXid以备份事务IDShmemVariableCache->latestCompletedXid = ShmemVariableCache->nextXid然后调用RecoverPreparedTransactions()扫描pg_twophase文件夹重新为准备的事务加载共享内存状态。如果任何关键GUC参数改变了,在我们允许backend进程写WAL日志以前记录到日志。所有这些事搞定后,设置xlogctl->SharedRecoveryInProgress= false允许backend进程写WAL日志。然后退出启动进程,postmaster进程响应子进程退出信号其它相关进程。

如果需要恢复。这儿要处理的是崩溃时刻未完成事务已写入物理数据库的事务(处理方法是UNDO)和崩溃时刻已完成事务未写入物理数据库的事务(处理方法是REDO)。

根据数据库的运行模式(有无起归档,有无hot standby。有hot standby时,其主系统恢复和启归档情况一样进行恢复,从系统单独处理),调用ReadRecord方法从不同地方读取xlog日志记录,调用xlog的资源管理器xmgr的相应资源的重放方法做恢复。恢复完成后剩余步骤和不需要恢复的情况一样,处理后续事宜。然后退出启动进程,postmaster进程响应子进程退出信号其它相关进程。略详细过程见“XLogStartup流程示意图”

相关主要结构见下面:

控制文件的结构ControlFileData及检查点结构CheckPoint参见《PostgreSQL存储系统一:控制文件存储结构》。

XLog日志文件相关结构参见《PostgreSQL存储系统二:REDOLOG文件存储结构》。

VariableCache是共享内存里用来跟踪OID和XID分配状态的数据结构。由于历史原因,由不同的轻量锁LWLock保护这个结构中不同的字段。

typedefstruct VariableCacheData

{

/*这些字段由OidGenLock锁保护 */

OidnextOid;/* next OID to assign */

uint32oidCount;/* OIDs available before must do XLOG work */

/*这些字段由XidGenLock锁保护 */

TransactionIdnextXid;/* nextXID to assign */

TransactionIdoldestXid;/* cluster-wideminimum datfrozenxid */

TransactionIdxidVacLimit;/* start forcing autovacuumshere */

TransactionIdxidWarnLimit;/* start complaining here */

TransactionIdxidStopLimit;/* refuse to advance nextXid beyond here */

TransactionIdxidWrapLimit;/* where the world ends */

OidoldestXidDB;/* database with minimum datfrozenxid*/

/*这些字段由ProcArrayLock锁保护 */

TransactionIdlatestCompletedXid;/* newest XID that has committed or

* aborted */

}VariableCacheData;

typedefVariableCacheData *VariableCache;

XLOG的共享内存总状态

typedefstruct XLogCtlData

{

/* WALInsertLock锁保护 */

XLogCtlInsertInsert;

/* info_lck锁保护 */

XLogwrtRqstLogwrtRqst;

XLogwrtResultLogwrtResult;

uint32 ckptXidEpoch; /* nextXID & epoch of latest checkpoint*/

TransactionIdckptXid;

XLogRecPtr asyncXactLSN; /* LSN of newest async commit/abort */

uint32 lastRemovedLog; /* latest removed/recycled XLOG segment */

uint32 lastRemovedSeg;

/* WALWriteLock锁保护 */

XLogCtlWriteWrite;

/*尽管这些值可以变,但在启动后不再改变。是否可以读/写页面和块的值依赖于WALInsertLockWALWriteLock */

char*pages; /* buffers for unwritten XLOG pages */

XLogRecPtr*xlblocks; /* 1st byte ptr-s + XLOG_BLCKSZ */

intXLogCacheBlck; /* highest allocated xlog buffer index */

TimeLineID ThisTimeLineID;

TimeLineID RecoveryTargetTLI;

/* archiveCleanupCommand是从recovery.conf文件里读的,但需要放在共享内存里以使bgwriter进程能访问它 */

chararchiveCleanupCommand[MAXPGPATH];

/* SharedRecoveryInProgress指明本进程是否正在做崩溃或归档恢复。由

info_lck锁保护 */

bool SharedRecoveryInProgress;

/*

* SharedHotStandbyActive 指明本进程是否正在做崩溃或归档恢复。由

info_lck锁保护 */

bool SharedHotStandbyActive;

/*如果正在等WAL到达或者failover的触发器文件出现,recoveryWakeupLatch用于唤醒启动将成继续重放WAL */

Latch recoveryWakeupLatch;

/*在恢复期间,我们在这儿保存最后一个检查点的拷贝。当bgwriter想创建一个重启点restartpoint时由bgwriter进程使用。由info_lck锁保护。 */

XLogRecPtr lastCheckPointRecPtr;

CheckPoint lastCheckPoint;

/* 最后一个检查点或被重放的检查点的结束位置加1 */

XLogRecPtr replayEndRecPtr;

/*被重放的最后一个记录的结束位置加1 */

XLogRecPtr recoveryLastRecPtr;

/*最后被重放的 COMMIT/ABORT记录的时间戳 */

TimestampTzrecoveryLastXTime;

/*是否请求暂停恢复? */

bool recoveryPause;

slock_t info_lck; /* locks shared variables shown above */

} XLogCtlData;

static XLogCtlData *XLogCtl = NULL;

/* XLogInsert的共享状态数据结构*/

typedefstruct XLogCtlInsert

{

XLogwrtResultLogwrtResult; /* a recent value of LogwrtResult */

XLogRecPtr PrevRecord; /* start of previously-inserted record */

intcurridx; /* current block index in cache */

XLogPageHeadercurrpage; /* points to header of block in cache */

char*currpos; /* current insertion point in cache */

XLogRecPtr RedoRecPtr; /* current redo point for insertions */

bool forcePageWrites; /* forcing full-page writes for PITR? */

/*如果在进程里备份由pg_start_backup()开始,exclusiveBackuptruenonExclusiveBackups是计数器,指明进程里当前基于流备份的数目。当上面两个任一个非0时(即有上面的备份时),forcePageWritesturelastBackupStart是最后一个检查点的redo值(下一个xlog记录的位置指针),作为在线备份的起始点。 */

bool exclusiveBackup;

intnonExclusiveBackups;

XLogRecPtr lastBackupStart;

} XLogCtlInsert;

XLOG控制的共享内存数据结构,LogwrtRqst指出我们需要写/文件同步到日志的那个字节位置(在这个位置之前的所有记录必须被写或做文件同步)。LogwrtResult指出我们已经写/文件同步了的字节位置。

typedefstruct XLogwrtRqst

{

XLogRecPtr Write; /* last byte + 1 to write out */

XLogRecPtr Flush; /* last byte + 1 to flush */

} XLogwrtRqst;

typedefstruct XLogwrtResult

{

XLogRecPtr Write; /* last byte + 1 written out */

XLogRecPtr Flush; /* last byte + 1 flushed */

} XLogwrtResult;

指向XLOG里位置的指针。这个指针是64位,因为我们不想它有溢出的时候。

注意:用来指明一个无效的指针。这个没问题,因为我们在XLOG页头用了页头结构,因此XLOG记录不可能从页头开始。

注意:这儿容易引起理解错乱,这个xlogid(对应实际XLOG文件名字的中间八位)表示逻辑XLOG日志文件ID,因为组成XLOG逻辑文件的实际物理文件远小于4Gb。组成对应这个xlogid的逻辑日志文件的每一个实际物理文件是一个XLogSegSize字节大小的“段”("segment",段号是实际XLOG文件名字的后八位)。前面加上用八位表示的一个时间线ID、逻辑日志文件号和段号一起标识一个物理的XLOG日志文件(“段”)。段号和物理文件里的偏移量由xrecoff/XLogSegSize和xrecoff%XLogSegSize计算。

typedefstruct XLogRecPtr

{

uint32xlogid;/* log file #,0 based */

uint32xrecoff;/* byte offset of location in log file */

}XLogRecPtr;

/* XLogWrite/XLogFlush的共享内存里的状态数据结构 */

typedefstruct XLogCtlWrite

{

XLogwrtResultLogwrtResult; /* current value of LogwrtResult */

intcurridx; /* cache index of next block to write */

pg_time_t lastSegSwitchTime; /* time of last xlog segmentswitch */

} XLogCtlWrite;

/*系统状态指示器。 */

typedefenum DBState

{

DB_STARTUP = 0,

DB_SHUTDOWNED,

DB_SHUTDOWNED_IN_RECOVERY,

DB_SHUTDOWNING,

DB_IN_CRASH_RECOVERY,

DB_IN_ARCHIVE_RECOVERY,

DB_IN_PRODUCTION

} DBState;

XLogStartup流程示意图中的两个红色方框红色字的框是XLOG资源管理器xmgr的处理方法,这个XLOG的资源管理器内容较多,单列主题讨论。还有恢复完成后调用了方法CreateCheckPoint,创建一个检查点以将所有的恢复数据写到磁盘。

5 创建检查点

创建一个检查点,会将共享内存里的所有磁盘缓冲和提交日志缓冲刷出并文件同步到磁盘。

下面这些情况可能引起创建检查点,为了使用方便,把这些情况定义成如下标志,这些标志可以按位做或运算。检查点的起因不同,创建检查点的行为也略有不同。

#defineCHECKPOINT_IS_SHUTDOWN 0x0001/* Checkpoint is for shutdown */

#defineCHECKPOINT_END_OF_RECOVERY0x0002 /* Likeshutdown checkpoint,

* but issued at end of WAL

* recovery */

#defineCHECKPOINT_IMMEDIATE0x0004 /* Do it withoutdelays */

#define CHECKPOINT_FORCE0x0008 /* Force even if no activity */

/* These are important to RequestCheckpoint */

#define CHECKPOINT_WAIT0x0010 /* Wait for completion */

/* These indicate the cause of a checkpoint request */

#defineCHECKPOINT_CAUSE_XLOG0x0020 /* XLOGconsumption */

#define CHECKPOINT_CAUSE_TIME0x0040 /* Elapsed time */

创建检查点的基本过程是先让存储管理器smgr(以后单列状态讨论)为检查点做好准备,根据情况填充检查点结构的成员,CheckpointGuts方法把共享内存里的磁盘缓冲和提交日志缓冲输出到磁盘(即写数据文件)。接着调用XlogInsert把这个检查点插入xlog文件。然后更新控制文件相关成员。最后更新共享内存里XlogCtl的检查点相关成员和检查点的统计信息结构。相关结构定义和创建检查点流程示意图见下面。

/*检查点统计信息 */

typedefstructCheckpointStatsData

{

TimestampTzckpt_start_t;/* startof checkpoint */

TimestampTzckpt_write_t;/* startof flushing buffers */

TimestampTzckpt_sync_t;/* start of fsyncs*/

TimestampTzckpt_sync_end_t;/* end of fsyncs*/

TimestampTzckpt_end_t;/* end ofcheckpoint */

intckpt_bufs_written;/* # ofbuffers written */

intckpt_segs_added;/* # of new xlog segments created */

intckpt_segs_removed;/* # of xlogsegments deleted */

intckpt_segs_recycled;/* # of xlogsegments recycled */

intckpt_sync_rels;/* # of relations synced */

uint64 ckpt_longest_sync;/* Longest sync for one relation */

uint64 ckpt_agg_sync_time;/* The sum of all the individual sync

* times,which is not necessarily the

* same as the total elapsed time for

* the entire sync phase. */

}CheckpointStatsData;

当前检查点的统计信息收集在这个全局结构变量里。

CheckpointStatsDataCheckpointStats;

创建检查点流程示意图

上图中,其中CheckPointGuts方法的定义见下面,刷出所有共享内存中的数据到磁盘并做文件同步。方法定义见下面,把clogsubtransmultixactpredicaterelationmapbuffer(数据文件)和twophase相关数据统统刷和文件同步到磁盘。这儿先不深入讨论这个方法了。

staticvoid

CheckPointGuts(XLogRecPtrcheckPointRedo,int flags)

{

CheckPointCLOG();

CheckPointSUBTRANS();

CheckPointMultiXact();

CheckPointPredicate();

CheckPointRelationMap();

CheckPointBuffers(flags); /* performs all required fsyncs */

/* We deliberately delay 2PC checkpointingas long as possible */

CheckPointTwoPhase(checkPointRedo);

}

结果这么多逻辑严谨的一系列行为后,数据库达到了正常状态,启动进程寿终正寝。然后,postmaster进程响应该子进程退出,分别依次forkbgwriter进程、walwriter进程、autovaclauncher进程、archiver进程、pgstat进程,然后抛出一句database system is ready to acceptconnections。然后进入serverloop,等待客户端请求到达,启动postgres服务进程,开始履行使命。

Serverloop还检查bgwriter进程、walwriter进程、autovaclauncher进程、archiver进程、pgstat进程,还有前面启动的系统日志进程sysloger这些辅助检查是否正常运行,如果没有,就重启这些进程。此时,pg服务器端有postmaster进程和这六个辅助进程运行,准备好为客户端进程提供服务,提供的服务由postgres服务进程完成。

------------ 转载请著明出处,来自博客: blog.csdn.net/beiigang beigang.iteye.com

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读601次。Oracle的数据导入导出是一项基本的技能,但是对于懂数据库却不熟悉Oracle的同学可能会有一定的障碍。正好在最近的一个项目中碰到了这样一个任务,于是研究了一下Oracle的数据导入导出,在这里跟大家分享一下。......_oracle 迁移方法 对比
文章浏览阅读553次。开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群(共700多人左右 1 + 2)。最近我们在使用MYSQL 8 的情况下(8.025)在数据库运行中出现一个问题 参数prefer_order_i..._mysql prefer_ordering_index
文章浏览阅读3.5k次,点赞3次,收藏7次。折腾了两个小时多才成功连上,在这分享一下我的经验,也仅仅是经验分享,有不足的地方欢迎大家在评论区补充交流。_navicat连接opengauss
文章浏览阅读2.7k次。JSON 代表 JavaScript Object Notation。它是一种开放标准格式,将数据组织成中详述的键/值对和数组。_postgresql json
文章浏览阅读2.9k次,点赞2次,收藏6次。navicat 连接postgresql 注:navicat老版本可能报错。1.在springboot中引入我们需要的依赖以及相应版本。用代码生成器生成代码后,即可进行增删改查(略)安装好postgresql 略。更改配置信息(注释中有)_mybatisplus postgresql
文章浏览阅读1.4k次。postgre进阶sql,包含分组排序、JSON解析、修改、删除、更新、强制踢出数据库所有使用用户、连表更新与删除、获取今年第一天、获取近12个月的年月、锁表处理、系统表使用(查询所有表和字段及注释、查询表占用空间)、指定数据库查找模式search_path、postgre备份及还原_pgsql分组取每组第一条
文章浏览阅读3.3k次。上一篇我们学习了日志清理,日志清理虽然解决了日志膨胀的问题,但就无法再恢复检查点之前的一致性状态。因此,我们还需要日志归档,pg的日志归档原理和Oracle类似,不过归档命令需要自己配置。以下代码在postmaster.c除了开启归档外,还需要保证wal_level不能是MINIMAL状态(因为该状态下有些操作不会记录日志)。在db启动时,会同时检查archive_mode和wal_level。以下代码也在postmaster.c(PostmasterMain函数)。......_postgresql archive_mode
文章浏览阅读3k次。系统:ubuntu22.04.3目的:利用向日葵实现windows远程控制ubuntu。_csdn局域网桌面控制ubuntu
文章浏览阅读1.6k次。表分区是解决一些因单表过大引用的性能问题的方式,比如某张表过大就会造成查询变慢,可能分区是一种解决方案。一般建议当单表大小超过内存就可以考虑表分区了。1,继承式分区,分为触发器(trigger)和规则(rule)两种方式触发器的方式1)创建表CREATE TABLE "public"."track_info_trigger_partition" ( "id" serial, "object_type" int2 NOT NULL DEFAULT 0, "object_name..._pg数据表分区的实现
文章浏览阅读3.3k次。物联网平台开源的有几个,就我晓得的有、、thingskit、JetLink、DG-iot(还有其他开源的,欢迎在评论区留言哦!),然后重点分析了下ThingsBoard、ThingsPanel和JetLink,ThingsBoard和Jetlinks是工程师思维产品,可以更多的通过配置去实现开发的目的,ThingsPanel是业务人员思路产品,或者开发或者用,避免了复杂的配置带来的较高学习门槛。ThingsBoard和Jetlinks是Java技术体系的,ThingsPanel是PHP开发的。_jetlinks和thingsboard
文章浏览阅读3.8k次。PostgreSQL 数据类型转换_pgsql数字转字符串
文章浏览阅读7k次,点赞3次,收藏14次。在做数据统计页面时,总会遇到统计某段时间内,每天、每月、每年的数据视图(柱状图、折线图等)。这些统计数据一眼看过去也简单呀,不就是按照时间周期(天、月、年)对统计数据进行分个组就完了嘛?但是会有一个问题,简单的写个sql对周期分组,获取到的统计数据是缺失的,即没有数据的那天,整条记录也都没有了。如下图需求:以当前月份(2023年2月)为起点,往后倒推一年,查询之前一年里每个月的统计数据。可见图中的数据其实是缺少的,这条sql只查询到了有数据的月份(23年的1月、2月,22年的12月)_如何用一条sql查出按年按月按天的汇总
文章浏览阅读3.8k次,点赞66次,收藏51次。PostgreSQL全球开发小组与2022年10月13日,宣布发布PostgreSQL15,这是世界上最先进的开源数据库的最新版本_mysql8 postgresql15
文章浏览阅读1.3k次。上文介绍了磁盘管理器中VFD的实现原理,本篇将从上层角度讲解磁盘管理器的工作细节。_smgrrelationdata
文章浏览阅读1.1k次。PostgreSQL设置中文语言界面和局域网访问_postgressql汉化
文章浏览阅读4.2k次。PostgreSQL 修改数据存储路径_如何设置postgresql 数据目录
文章浏览阅读4.7k次。在项目中用到了多数据源,在连接postgres数据库时,项目启动报错,说数据库连接错误,说dual不存在,网上好多教程都是说数据库查询的时候的大小写问题,而这个仅仅是连接,咋鞥却处理方法是修改application-dev.yml中的配置文件.项目中的druid参数是这样的:确实在配置文件中有个查询语句。_relation "dual" does not exist
文章浏览阅读4.9k次。PostgreSQL是一款强大的关系型数据库,但在实际使用过程中,许多用户经常会遇到慢SQL的问题。这些问题不仅会降低数据库性能,还会直接影响业务流程和用户体验。因此,本文将会深入分析PostgreSQL慢SQL的原因和优化方案,帮助用户更好地利用这个优秀的数据库系统。无论你是初学者还是专业开发者,本文都将为你提供实用的技巧和方法,让你的PostgreSQL数据库始终保持高效快速。_postgresql数据库优化
文章浏览阅读1.6k次。Linux配置postgresql开机自启_linux 启动pgsql
文章浏览阅读2k次。本篇介绍如何在centos7系统搭建一个postgresql主备集群实现最近的HA(高可用)架构。后续更高级的HA模式都是基于这个最基本的主备搭建。_postgresql主备