PostgreSQL启动过程中的那些事十六:启动进程三:CheckPointGuts刷出共享内存里所有数据

话说启动进程调用StartupXLOG启动xlog,根据情况,如果需要就排除系统故障引起的数据库不一致状态,做相应的REDO或UNDO,然后创建一个检查点,把所有共享内存磁盘缓冲和提交数据缓冲写并文件同步到磁盘、把检查点插入xlog文件、更新控制文件,使数据库达到一种状态

这节接着讨论启动进程在创建检查点时调用的CheckPointGuts方法(在创建重启点时也会调用这个方法)。CheckPointGuts方法功能是刷出所有共享内存中的数据到磁盘并做文件同步,共享内存中的数据包括clogsubtransmultixactpredicaterelationmapbuffer(数据文件)和twophase相关数据。CheckPointGuts方法定义和“CheckPointGuts方法调用序列图”见下面。

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

}



CheckPointGuts方法调用序列图

CheckPointGuts方法主要是通过调用提交事务日志管理器的方法CheckPointClog,子事务日志管理器的方法CheckPointSUBTRANS,多事务日志管理器的方法CheckPointMultiXact,支持序列化事务隔离级别的谓词锁模块的方法CheckPointPredicate,目录/系统表到文件节点映射模块的方法CheckPointRelationMap,缓存管理器的方法CheckPointBuffers,两阶段提交模块的方法CheckPointTwoPhase把共享内存里的数据刷出并文件同步到磁盘。

其中提交事务日志管理器的方法CheckPointClog子事务日志管理器的方法CheckPointSUBTRANS、多事务日志管理器的方法CheckPointMultiXact、多事务日志管理器的方法CheckPointMultiXact、支持序列化事务隔离级别的谓词锁模块的方法CheckPointPredicate最后都调用了SLRU模块的SimpleLruFlush方法,把相关共享内存数据写到磁盘,并调用pg_fsync方法把相关内容文件同步到磁盘上对应文件。

在缓存管理器的方法CheckPointBuffers,两阶段提交模块的方法CheckPointTwoPhase里,因为没有使用SLRU算法,直接调用pg_fsync方法把相关内容文件同步到磁盘上对应文件。

在目录/系统表到文件节点映射模块的方法CheckPointRelationMap里,在释放RelationMappingLock时,会完成共享内存里相关系统表和对应物理文件映射的文件同步到磁盘工作。

我们看一下各种日志管理,日志对数据库是至关重要的一部分,出现系统故障时,数据库通过重放日志恢复数据,保证数据库一致性和完整性。

Pg里有XLOGCLOGSUBTRANS LOGMultiXactID LOG四种事务日志,XLOG是事务日志,就是平时常说的REDOLOG,记录了事务操作数据库的过程信息和事务最终状态;CLOGXLOG里事务的提交状态日志;SUBTRANS是子事务日志,为每一个事务存储父事务ID。这是嵌套事务实现的基础部分,SUBTRANS仅需要为当前打开的事务记住信息,没有必要在崩溃并重启后保留数据;MultiXactID是组合事务日志,由一组事务ID组成,是共享行锁shared-row-lock实现的基础部分,共享锁锁住的元组在其Xmax字段存储MultiXactId。各种日志都存放在对应的日志文件里。

有了文件就有了I/O,为了降低I/O开销,pg设置了各种日志的缓存区,由对应的日志管理器管理日志的写、文件同步和读等日志维护工作。Pg使用简单最近最少使用(SLRU)算法来管理事务日志。使用轻量锁LWLock的ControlLock锁保护整个缓冲区,其中的每个缓冲块(默认8K)还有一个LWLock锁保护,以控制并发操作。SLRU及事务日志的部分相关数据结构在下面。

为CLOG控制链接到共享内存数据结构

staticSlruCtlData ClogCtlData;

#define ClogCtl (&ClogCtlData)

为SUBTRANS控制链接到共享内存数据结构

staticSlruCtlData SubTransCtlData;

#define SubTransCtl(&SubTransCtlData)

为MultiXact控制链接到共享内存数据结构

staticSlruCtlData MultiXactOffsetCtlData;

staticSlruCtlData MultiXactMemberCtlData;

#define MultiXactOffsetCtl (&MultiXactOffsetCtlData)

#define MultiXactMemberCtl (&MultiXactMemberCtlData)

typedefSlruCtlData *SlruCtl;

/* SlruCtlData是指向共享内存里的活跃信息的非共享结构*/

typedefstruct SlruCtlData

{

SlruSharedshared;

/*这个标志告诉是否文件同步写(pg_clogmultixact成员是true,pg_subtranspg_notifyfalse */

bool do_fsync;

/*为截断目的决定两个页号哪一个是更旧的。为了用包裹 XID算法(with wraparound XID arithmetic)做正确的事,这儿我们需要用事务ID比较*/

bool (*PagePrecedes) (int,int);

/* SimpleLruInit期间目录被设置,并且从那以后不变。因为它总是相同的,它不必放到共享内存里。 */

char Dir[64];

} SlruCtlData;

共享内存状态

typedefstruct SlruSharedData

{

LWLockId ControlLock;

/* 由这个SLRU结构管理的缓存块号*/

int num_slots;

/*持有每一个缓存槽信息的数组。当状态是EMPTY缓存页/块号是未定义的,当作

page_lru_count*/

char **page_buffer;

SlruPageStatus *page_status;

bool *page_dirty;

int *page_number;

int *page_lru_count;

LWLockId *buffer_locks;

/*SLRU/块里的相关条目的WAL刷出LSN的可选数组。如果不是0/NULL,在写缓存页/块前我们必须刷出WALpg_clogtruemultixactpg_subtranspg_notifyfalse)。Group_lsn[]每缓存页/块槽有lsn_groups_per_page条目,在这个槽的缓存页/块上SLRU条目的一个临近组每一个缓存页/块槽包含最高已知LSN */

XLogRecPtr *group_lsn;

int lsn_groups_per_page;

/*我们通过设置page_lru_count[slotno] = ++cur_lru_count标记页“最近使用”;最老旧页因此是有表达式cur_lru_count - page_lru_count[slotno]值最高/大的那一个。这个数事实上包裹,但这个计算仍然工作和缓存页/块的年龄(超过了INT_MAX数)一样长。 */

int cur_lru_count;

/* latest_page_number是当前日志结尾的页/块号;这不是严格的数据,因为我们仅用它避免包裹swapping出了最后的页/块。 */

int latest_page_number;

} SlruSharedData;

typedefSlruSharedData *SlruShared;

/*页状态代码。注意这不包含dirty位。仅在VALID或者WRIT_IN_PROGRESS状态里page_dirty能是true;在后面的例子/情况里它暗示从这次写开始后页又被搞脏*/

typedefenum

{

SLRU_PAGE_EMPTY,/* buffer is not in use */

SLRU_PAGE_READ_IN_PROGRESS,/* page is beingread in */

SLRU_PAGE_VALID,/* page is valid and not being written */

SLRU_PAGE_WRITE_IN_PROGRESS/* page is beingwritten out */

} SlruPageStatus;

SLRU算法的缓存区操作在下面,其中包括了本节多次调用的SimpleLruFlush方法,将缓存数据刷出并文件同步到磁盘。

externSize SimpleLruShmemSize(int nslots,int nlsns);

externvoid SimpleLruInit(SlruCtl ctl,constchar *name,int nslots,int nlsns,

LWLockId ctllock,constchar *subdir);

externintSimpleLruZeroPage(SlruCtl ctl,int pageno);

externint SimpleLruReadPage(SlruCtl ctl,int pageno,bool write_ok,

TransactionId xid);

externint SimpleLruReadPage_ReadOnly(SlruCtl ctl,

TransactionId xid);

externvoid SimpleLruWritePage(SlruCtl ctl,int slotno);

externvoid SimpleLruFlush(SlruCtl ctl,bool checkpoint);

externvoid SimpleLruTruncate(SlruCtl ctl,int cutoffPage);

externbool SlruScanDirectory(SlruCtl ctl,int cutoffPage,bool doDeletions);

就到这儿吧。

------------ 转载请著明出处,来自博客: 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主备