您好,登錄后才能下訂單哦!
這篇文章主要介紹MDLog的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
ReplayThread類:負責log的replay事件處理。
RecoveryThread類:負責log的recovery事件處理。
SubmitThread類:負責log的submit事件處理。
map<uint64_t, LogSegment*> segments; 記錄log的序列
set<LogSegment*> expiring_segments; 記錄expiring的log集合
set<LogSegment*> expired_segments; 記錄expired的log集合
uint64_t event_seq; 記錄log event的當前序列值
int expiring_events; 記錄expiring的log個數
int expired_events; 記錄expired的log個數
MDLog::write_head()
|__Journaler::write_head() 直接調用Journaler類對應的函數進行處理
MDLog::get_read_pos()
|__Journaler::get_read_pos()
MDLog::get_write_pos()
|__Journaler::get_write_pos()
MDLog::get_safe_pos()
|__Journaler::get_write_safe_pos()
MDLog::create()
|__創建C_GatherBuilder類對象
|__設置C_GatherBuilder類的finisher函數
|__確定inode的默認journal號,即:ino = MDS_INO_LOG_OFFSET+mds->get_nodeid()
|__創建Journaler類對象,該類對象寫入到metadata pool里
|__設置Journaler類對象的寫出錯處理函數
|__設置Journaler類對象可寫
|__Journaler::create()
|__Journaler::write_head()
|__創建JournalPointer類對象,該類對象寫入到metadata pool里
|__設置JournalPointer的front值為inode號
|__設置JournalPointer的back為0
|__JournalPointer::save()
|__C_GatherBuilder::activate()
|__SubmitThread::create() 創建SubmitThread線程
MDLog::open()
|__RecoveryThread::set_completion() 設置RecoveryThread的completion回調函數
|__RecoveryThread::create() 創建RecoveryThread線程
|__SubmitThread::create() 創建SubmitThread線程
MDLog::reopen()
|__刪除Journaler類對象
|__RecoveryThread::join() 等待RecoveryThread結束
|__RecoveryThread::set_completion() 設置RecoveryThrad結束時的回調函數MDLog::append()
|__RecoveryThread::create() 創建RecoveryThread線程
MDLog::append()
|__Journaler::set_read_pos(Journaler::get_write_pos()) 設置Journaler類對象的read/write position指向同一個地方
|__Journaler::set_expire_pos(Journaler::get_write_pos()) 設置Journaler類對象的expire position為write position
|__Journaler::set_writable() 設置Journaler為可寫
MDLog::_start_entry()
|__設置cur_event=e 設置cur_event為當前待處理的LogEvent
|__event_seq++ 增加Event的序列號
|__從LogEvent類對象中得到EMetaBlob對象,即:LogEvent::get_metablob()
|__設置EMetaBlob的event_seq為當前的event_seq,last_subtree_map為當前最后一個segment
MDLog::cancel_entry()
|__設置cur_event=NULL 清空cur_event
|__刪除LogEvent參數類對象
MDLog::_submit_entry()
|__設置cur_event = NULL
|__從segments集合中得到最后一個LogSegment類對象
|__增加LogSement類對象的event個數,即:num_events++
|__設置LogEvent::_segment=LogSement類對象
|__LogEvent::update_segment() 更新LogEvent的segment字段
|__以LogEvent作為參數,更新pending_events集合
|__num_events++ 增加events的個數
|__unflushed++ 增加unflushed的個數
|__若LogEvent的type是EVENT_SUBTREEMAP或EVENT_IMPORTFINISH且mds處于resolve狀態
|__直接退出
|__若LogSegment::end/Journaler::get_layout_period()!=LogSegment::offset/Journaler::get_layout_period()
|___start_new_segment()
|__若LogEvent的類型是EVENT_SUBTREEMAP_TEST
|__創建LogEvent類對象
|__設置LogEvent類對象的類型是EVENT_SUBTREEMAP_TEST
|___submit_entry()
MDLog::_submit_thread()
|__判斷當前MDS進程是否stopping,若是則直接退出
|__判斷mds_log_pause是否為真,若為真則調用submit_cond.Wait()
|__判斷pending_events集合是否為空,若為空則調用submit_cond.Wait()
|__從pending_event中得到PendingEvent類對象
|__若PendingEvent中包含有效的LogEvent
|__得到LogEvent和LogSegment
|__encode LogEvent到bufferlist中
|__設置LogEvent::set_start_off(write_pos) 設置LogEvent的start offset值為write position值
|__Journaler::append_entry(bufferlist) 將encoded LogEvent寫入到Journaler中
|__更新LogSegment::end為最新的write position
|__Journaler::wait_for_flush() 等待Journaler flush LogEvent到磁盤上,完成flush后調用回調函數設置MDLog::safe_pos=最新的write position
|__Journaler::flush()
|__刪除LogEvent類對象
|__若PendingEvent中沒有包含有效的LogEvent
|__Journaler::wait_for_flush() 等待Journaler flush LogEvent到磁盤上,完成flush后調用回調函數設置MDLog::safe_pos=Journaler::get_write_pos()
|__Journaler::flush()
MDLog::wait_for_safe() 若目前仍然還有pending的event,則不做wait_for_flush
|__判斷pending_events是否不為空
|__向pending_events集合的末尾添加一個NULL的PendingEvent類對象
|__設置no_pending=false
|__submit_cond.Signal()
|__判斷no_pending==true
|__Journaler::wait_for_flush()
MDLog::flush() 若目前仍然還有pending的event,則不做flush
|__判斷pending_events集合不為空
|__向pending_event集合末尾插入一個NULL的PendingEvent類對象
|__設置do_flush=false
|__判斷do_flush==true
|__Journaler::flush()
MDLog::shutdown()
|__判斷SubmitThread是否正在運行
|__SubmitThread::join() 等待SubmitThread進程停止
|__Journaler::shutdown() 調用Journaler的shutdown()函數
|__判斷ReplayThread是否正在運行
|__ReplayThread::join() 等待ReplayThread進程停止
|__判斷RecoveryThread是否正在運行
|__RecoveryThread::join() 等待RecoveryThread進程停止
MDLog::_prepare_new_segment()
|__得到seq的值為event_seq + 1
|__在segments[seq]處新創建一個LogSegment類對象
|__MDCache::advance_stray()
MDLog::_journal_segment_subtree_map()
|__MDCache::create_subtree_map() 從MDCache中得到一個ESubtreeMap
|__設置改ESubtreeMap的event_seq值為segment的最后一個元素
|___submit_entry()
MDLog::_start_new_segment()
|___prepare_new_segment()
|___journal_segment_subtree_map()
MDLog::trim()
|__根據配置文件得到max_segments和max_events
|__遍歷segments集合
|__若該LogSegment在pending_events集合中,則直接退出,不能進行trim操作
|__若該LogSegment在expiring_segments或expired_segments集合中,則遍歷下一個
|__將該LogSegment插入到expiring_segments集合中
|__try_expire()
|___trim_expired_segments()
MDLog::trim_all() 處理過程與MDLog::trim()類似,只不過是遍歷所有的segments并沒有trim數量上的限制
MDLog::try_expire()
|__從expiring_segments集合中刪除指定的LogSegment
|___expired()
|__將該LogSegment插入到expired_segments集合中
MDLog::_trim_expired_segments()
|__遍歷segments集合
|__判斷LogSegment是否在expired_segments集合中,若不在則停止遍歷
|__將LogSegment從expired_segments集合中刪除
|__將LogSegment從segments集合中刪除
|__刪除LogSegment
|__設置trim=true
|__若trim==true
|__Journaler::write_head(0)
MDLog::_maybe_expired()
|__try_expire()
MDLog::replay()
|__判斷Journaler的read pos是否和write pos一致
|__不需要replay,直接返回
|__waitfor_replay.push_back(c) 添加replay waiter
|__ReplayThread::create() 創建一個新的ReplayThread
MDLog::_replay_thread() 執行replay操作的獨立線程
|__判斷Journaler是否還有未讀數據
|__Journaler::wait_for_readable() 等待Journaler可讀并且沒有未讀的數據
|__判斷Journaler是否有出錯信息
|__處理Journaler的出錯信息
|__若Journaler不可讀并且Journaler的read pos==write pos
|__直接退出
|__得到Journaler的read position
|__Journaler::try_read_entry() 從Journaler類對象中讀取數據
|__得到LogEvent類對象
|__設置LogEvent的start offset為read position
|__LogEvent的類型是EVENT_SUBTREEMAP或EVENT_RESETJOURNAL
|__在segments集合中創建一個新的LogSegment類對象
|__若segments集合不為空
|__設置LogEvent::_segment=get_current_segment()
|__設置LogEvent::_segment->end = Journaler::get_read_pos()
|__LogEvent::replay()
|__設置safe_pos = Journaler::get_write_safe_pos()
MDLog::_recovery_thread()
|__創建JournalPointer類對象
|__JournalPointer::load(mds->objecter) 從JournalPointer處load出數據
|__若JournalPointer.back不為空,則說明有寫Journal未完成的情況
|__根據JournalPointer.back創建Journaler類對象
|__Journaler::recover() 調用Journaler類對象的recover()函數進行recover操作
|__從JournalPointer.front創建Journaler類對象
|__Journaler::recover() 調用Journaler類對象的recover()函數進行recover操作
|__若MDS處于standby replay模式或者stream_format() >= mds_journal_format
|__Journaler::set_write_error_handler() 設置Journaler的write error handler
|___reformat_journal()
MDLog::_reformat_journal()
|__根據參數JournalPointer的front值來確定JournalPointer的back值
|__根據參數JournalPointer的back,創建一個新的Journaler
|__Journaler::set_writeable()
|__Journaler::create()
|__Journaler::write_head()
|__從參數的old_journaler處讀取數據到bufferlist
|__Journaler::append_entry(bufferlist) 將old_journaler讀取到的數據寫入到新的Journaler中
|__Journaler::flush()
補充一下針對MDLog的理解:
MDLog::create()核心處理流程如下:
1、得到Journaler對應的inode號,即:MDS_INO_LOG_OFFSET+mds->get_nodeid()
2、創建Journaler類對象(Journaler寫入到metadata pool中)
3、創建JournalPointer類對象(以mds->get_nodeid()和metadata pool為參數)
4、設置JournalPointer類對象的front = inode,back = 0
5、保存JournalPointer類對象,即:jp->save(mds->objecter, gather.new_sub())
6、創建SubmitThread線程類,即:submit_thread.create(),之后執行SubmitThread類的entry()函數,即:_submit_thread()
MDLog::_submit_thread()主要處理流程如下:
1、遍歷pending_event數組,若數組為空或數組中的PendingEvent為空則重新遍歷
2、從pending_event數組中得到PendingEvent類對象
3、從PendingEvent類對象中得到LogEvent,之后從LogEvent類對象中得到LogSegment
4、對于LogSegment,序列化其header信息。序列化的header信息如下:
EVENT_NEW_ENCODING
1
_type
mdsmap->get_up_features()
5、得到當前Journaler類對象寫入日志的位置,即:journaler->get_write_pos()
6、將序列化的header信息寫入到journaler,即:journaler->append_entry(bl)
7、flush journaler到磁盤,即:journaler->wait_for_flush()
MDLog::_recovery_thread()
1、根據mds->get_nodeid()以及metadata pool得到JournalPointer類對象
2、讀取JournalPointer的object,即:jp.load(mds->objecter)
3、若JournalPointer沒有object,則創建一個JournalPointer的front inode號且保存JournalPointer(jp.save(mds->objecter))
4、若jp.back不為空,則說明之前日志回寫的時候有錯誤出現,因此需要刪除jp.back對應的日志
|__根據jp.back創建Journaler類對象
|__執行Journaler::recover()
|__執行Journaler::erase()
|__更新JournalPointer
|__設置jp.back=0
|__調用jp.save(mds->objecter)
5、根據jp.front創建Journaler類對象
6、執行Journaler::recover()
7、執行_reformat_journal()
MDLog::_reformat_journal() 將日志信息寫入到JournalPointer的back處,若寫入成功則設置JournalPointer的front=back以及back=0
1、得到JournalPointer的back值
2、保存JournalPointer類對象,即:jp.save()
3、根據jp.back創建Journaler類對象
4、從老的日志中讀取日志信息,即:old_journal->try_read_entry(bl)
5、將老的日志信息寫入到新的日志中,即:new_journal->append_entry(bl)
6、刷新日志到磁盤,即:new_journal->flush()
7、調換JournalPointer的front和back值且保存JournalPointer,即:jp.save()
8、刪除老的日志,即:old_journal->erase()
9、更新JournalPointer,即:jp.back=0且jp.save()
MDLog::_start_entry()
1、設置cur_event為當前待處理的entry
2、遞增event_seq的值
3、更新LogEvent的event_seq值和last_subtree_map值
MDLog::_submit_entry()
1、清空cur_event值
2、從segments數組的末尾得到LogSegment
3、設置LogEvent的_segment為segments數組中的LogSegment
4、更新pending_events數組,即:pending_events[ls->seq].push_back(PendingEvent(le, c))
5、更新num_events值和unflushed值
MDLog::_prepare_new_segment()
1、根據event_seq值,得到seq值,即:seq = event_seq + 1
2、更新segments數組,即:segments[seq] = new LogSegment(seq)
MDLog::trim()
MDLog::trim_all() 這兩個函數用于從segments數組中trim掉滿足條件的LogSegment。這里使用了兩個數組expiring_segments和expired_segments保存trim過程中的LogSegment。
MDLog::replay() 當journaler的read_pos和write_pos不一致時,需要進行replay操作
1、更新waitfor_replay數組
2、設置already_replayed=true
3、創建ReplayThread線程類,之后執行ReplayThread.entry()函數,即:執行_replay_thread()
MDLog::_replay_thread()
1、從Journaler中讀取日志內容,即:journaler->try_read_entry(bl)
2、從日志中解析出LogEvent,即:LogEvent::decode(bl)
3、更新segments數組,即:segments[event_seq] = new LogSegment(event_seq, pos)
4、更新LogEvent的_segment
5、執行LogEvent的replay()操作
以上是“MDLog的示例分析”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。