1、WAL预发式日志写进程
数据库开启后,调用main()->PostmasterMain()->ServerLoop()->StartWalwriter()->
AuxiliaryProcessMain()->WalWriterMain(),开启WalWriter的辅助进程负责wal日志的处理。
2、WalWriterMain()函数的主要执行步骤
1、变量初始化
2、注册各种信号函数
3、运行环境初始化
首先,在先前的AuxiliaryProcessMain()函数中,CreateAuxProcessResourceOwner()通过ResourceOwnerCreate函数创建一个名为”Wal Writer”的资源跟踪器 ,为WalWriter创建运行内存上下文。然后在WalWriterMain()函数中,并将运行环境切换到新创建的内存上下文中。
4、注册异常处理函数
5、进入主要的循环程序
首先,处理信号分支,接着,执行XLogBackgroundFlush()函数,负责xlog的写工作。Xlog写工作完成重新进入休眠。
6、WalWriter辅助进程退出。
3、XLogBackgroundFlush()函数的主要执行步骤
该函数的主要功能是定位需要写入磁盘的XLog日志的开始位置和结束位置,将其传给XLogWrite()函数。
1、变量初始化,判断数据库系统是否处在恢复状态,是的话就退出该函数。
2、请求获取一个spinlock轻量锁info_lock,在锁的保护下访问日志控制信息XLogCtl。
A、初始化当前请求写入系统缓冲区的日志位置WriteRqst = XLogCtl->LogwrtRqst;
B、初始化当前已经写入系统缓冲区和磁盘中的日志位置LogwrtResult = XLogCtl->
LogwrtResult;
C、把请求写入系统缓冲区的日志位置WriteRqst调整为页尾,使数据能够以页为单位刷新进磁盘,即WriteRqst.Write -= WriteRqst.Write % XLOG_BLCKSZ;
3、通过对WriteRqst.Write 和LogwrtResult.Flush进行比较,确定刷新进磁盘的头尾地址。
A、如果前者大于后者,说明当前的请求有需要刷新入系统缓冲区的日志,进入到第4)步
B、如果前者小于后者,说明当前的请求没有需要刷新入系统缓冲区的日志,需要再多考虑一下的异步日志的情况。在spinlock轻量锁的保护下,将XLogCtl->asyncXactLSN赋值给WriteRqst.Write,然后再次比较WriteRqst.Write 和LogwrtResult.Flush的大小,如果前者依旧小于后者,则退出当前的日志文件,否则进入第4)步。
4、请求获取一个WALWriteLock锁,在该锁的保护下调用XLogWrite()函数进行XLog日志文件的写工作。
4、XLogWrite()函数的主要执行步骤
该函数主要功能是根据传入的WriteRqst,进行XLog日志文件的写工作。
1、变量初始化
2、进入主要的程序循环
A、初始化需要刷新到磁盘的最后位置,并且打开相应的日志文件openLogFile,如果不存在该日志文件,则创建一个对应的日志文件。
B、判断当前是否满足以下三个条件之一,转入C,否则转入D 。三个条件分别是:1、 当前位置满一段;2、缓冲区全部刷新到磁盘;3、请求之前的日志记录全部刷新到磁盘
C、刷新缓存到磁盘,执行系统函数_write,将标记位置的日志记录刷新到磁盘(可能是缓冲区)。其中如果满一段,为了减少切换日志段文件带来的开销,应立即执行系统函数_commit强制将日志记录刷新到磁盘(真正的磁盘) ,唤醒WalSender进程和XlogArch日志归档进程,判断是否需要创建检查点。
D、判断这次写是否不足页,如果不足页则更新已经写出的日志位置为当前请求写日志的位置,不足页仅发生在这次写日志写最后一页的时候,因此请求写日志之前的日志已经全部写出,跳出循环。
E、更新需要刷新到磁盘的最后位置为下一页。
3、更新全局变量XLogCtl,释放锁。