MongoDB 一个page的生命周期

环境

MacBook Pro

前言

在MongoDB中文社区看到一篇文章时,感觉文章里面的图画的不太对,
所以自己又重新画了下。

是关于MongoDB中一个page的生命周期的图:

MongoDB 一个page的生命周期

讲解:

1、从磁盘起点那里开始,数据从磁盘读取到内存(page in memory
2、数据在内存中被修改,此时该page变成了一个脏的page;其将会被reconcile调和????page updated in memory)
3、修改的数据被reconcile后,将会交给evict线程做磁盘写入和丢去处理
4、evict线程会把干净page直接丢弃掉,所谓干净的page,我个人认为,应该就是没有发生修改的page
对于脏的page,在调和后将数据写入磁盘,再将page丢弃掉。

比如wt使用的HazardPointer,对page刷盘时,其实就是对该页的Hazard Pointer的’写获取’操作,并且在刷盘时保持 原有磁盘上的page不变,直接找一个新的page空间,把内存里page的修改(保存在page的modify_list中)变成磁盘page的结构写入 ,这个page刷盘的过程称为reconcile

Q:我有个疑问,这里到底有没有刷入磁盘中?
A:应该是刷入了
Q:比如wt使用的HazardPointer,对page刷盘时,其实就是对该页的HazardPointer的’写获取’操作 — 这句话理解起来非常拗口,到底什么意思?
A : 我觉得应该去掉“对”字,改为:其实就是该页的HazardPointer的’写获取’操作

Hazard pointer 是怎样应用在 WT 中呢?我们这样来看待这个事情,把内存 page 的读写看做 hazard pointer 的读操作,把 page 从内存淘汰到磁盘上的过程看做 hazard pointer 的写操作,这样瞬间就能明白为什么 WT 在页的操作上可以不遵守 The FIX Rules 规则,而是采用无锁并发的页操作。要达到这种访问方式有个条件就是内存中 page 本身的结构要支持 lock free 访问,这个在剖析 WiredTiger 数据页无锁及压缩一文中介绍过了。从上面的描述可以看出 evict page 的过程中首先要做一次 hazard pointer 写操作检查,而后才能进行 page 的 reconcile 和数据落盘。

HazardPointer

是一个无锁并发技术,其应用场景是单个线程写和多个线程读的场景,大致的原理是这样的,每个读的线程设计一个与之对应的无锁数组用于标记这个线程引用的 hazard pointer 对象。读线程的步骤如下:

读线程在访问某个 hazard pointer 对象时,先将在自己的标记数组中标记访问的对象。
读线程在访问完毕某个 hazard pointer 对象时,将其对应的标记从标记数组中删除。

写线程的步骤大致是这样的,写线程如果需要对某个 hazard pointer 对象写时,先判断所有读线程是否标记了这个对象,如果标记了,放弃写。如果未标记,进行写。

参考地址:
MongoDB WiredTiger 存储引擎cache_pool设计 (上) – 原理篇

WiredTiger实现:一个LRU cache深坑引发的分析

实现无锁的栈与队列(5):Hazard Pointer