在本系列的第一篇文章(
主函数入口 ) 中,介绍了mongodb会在系统启动同时,初始化了日志持久化服务,该功能貌似是1.7版本后引入到系统中的,主要用于解决因系统宕机时,内存中的数据 未写入磁盘而造成的数据丢失。其机制主要是通过log方式定时将操作日志(如cud操作等)记录到db的journal文件夹下,这样当系统再次重启时从 该文件夹下恢复丢失的(内存)数据。也就是在_initAndListen()函数体(db.cpp文件第511行)中下面这一行代码:
dur::startup();
今天就以这个函数为起点,看一下mongodb的日志持久化的流程,及实现方式。
在Mongodb中,提供持久化的类一般都以dur开头,比如下面几个:
dur.cpp:封装持久化主要方法和实现,以便外部使用
dur_commitjob.cpp:持久化任务工作(单元),封装延时队列TaskQueue < D > ,操作集合vector < shared_ptr < DurOp > > 等
dur_journal.cpp:提供日志文件 / 路径,创建,遍历等操作
dur_journalformat.h:日志文件格式定义
dur_preplogbuffer.cpp:构造用于输出的日志buffer
dur_recover.h:日志恢复类(后台任务方式BackgroupJob)
dur_stats.h:统计类,包括提交 / 同步数据次数等
dur_writetodatafiles.cpp:封装写入数据文件mongofile方法
durop.h:持久化操作类,提供序列化,创建操作(FileCreatedOp),DROP操作(DropDbOp)
dur_commitjob.cpp:持久化任务工作(单元),封装延时队列TaskQueue < D > ,操作集合vector < shared_ptr < DurOp > > 等
dur_journal.cpp:提供日志文件 / 路径,创建,遍历等操作
dur_journalformat.h:日志文件格式定义
dur_preplogbuffer.cpp:构造用于输出的日志buffer
dur_recover.h:日志恢复类(后台任务方式BackgroupJob)
dur_stats.h:统计类,包括提交 / 同步数据次数等
dur_writetodatafiles.cpp:封装写入数据文件mongofile方法
durop.h:持久化操作类,提供序列化,创建操作(FileCreatedOp),DROP操作(DropDbOp)
首先我们看一下dur::startup() 方法实现(dur.cpp),如下:
/*
* at startup, recover, and then start the journal threads
*/
void startup() {
if ( ! cmdLine.dur ) /* 判断命令行启动参数是否为持久化 */
return ;
DurableInterface::enableDurability(); // 对持久化变量 _impl 设置为DurableImpl方式
journalMakeDir(); /* 构造日志文件所要存储的路径:dur_journal.cpp */
try {
recover(); /* 从上一次系统crash中恢复数据日志信息:dur_recover.cpp */
}
catch (...) {
log() << " exception during recovery " << endl;
throw ;
}
preallocateFiles();
boost::thread t(durThread);
}
void startup() {
if ( ! cmdLine.dur ) /* 判断命令行启动参数是否为持久化 */
return ;
DurableInterface::enableDurability(); // 对持久化变量 _impl 设置为DurableImpl方式
journalMakeDir(); /* 构造日志文件所要存储的路径:dur_journal.cpp */
try {
recover(); /* 从上一次系统crash中恢复数据日志信息:dur_recover.cpp */
}
catch (...) {
log() << " exception during recovery " << endl;
throw ;
}
preallocateFiles();
boost::thread t(durThread);
}
注意:上面的DurableInterface,因为mongodb使用类似接口方式,从而约定不同的持久化方式实现,如下:
class
DurableInterface : boost::noncopyable {
virtual void * writingPtr( void * x, unsigned len) = 0 ;
virtual void createdFile( string filename, unsigned long long len) = 0 ;
virtual void declareWriteIntent( void * x, unsigned len) = 0 ;
virtual void * writingAtOffset( void * buf, unsigned ofs, unsigned len) = 0 ;
....
}
virtual void * writingPtr( void * x, unsigned len) = 0 ;
virtual void createdFile( string filename, unsigned long long len) = 0 ;
virtual void declareWriteIntent( void * x, unsigned len) = 0 ;
virtual void * writingAtOffset( void * buf, unsigned ofs, unsigned len) = 0 ;
....
}