《ceph源碼分析之讀寫操作流程(2)》由會員分享,可在線閱讀,更多相關《ceph源碼分析之讀寫操作流程(2)(9頁珍藏版)》請在裝配圖網上搜索。
1、
ceph源碼分析之讀寫操作流程(2)
上一篇介紹了ceph存儲在上兩層的消息邏輯,這一篇主要介紹一下讀寫操作在底兩層的流程。下圖是上一篇消息流程的一個總結。上在ceph中,讀寫操作由于分布式存儲的原因,故走了不同流程。
對于讀操作而言:
1.客戶端直接計算出存儲數據所屬于的主osd,直接給主osd上發(fā)送消息。
2.主osd收到消息后,可以調用Filestore直接讀取處在底層文件系統中的主pg里面的內容然后返回給客戶端。具體調用函數在ReplicatedPG::do_osd_ops中實現。讀操作代碼流程如圖:如我們之前說的,當確定讀操作為主osd的消息時(CEPH_MS
2、G_OSD_OP類型),會調用到ReplicatePG::do_osd_op函數,該函數對類型做進一步判斷,當發(fā)現為讀類型(CEPH_OSD_OP_READ)時,會調用FileStore中的函數對磁盤上數據進行讀。
[cpp] view plain copy int ReplicatedPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops) { …… switch (op.op) { …… case CEPH_OSD_OP_READ: ++ct
3、x->num_read; { // read into a buffer bufferlist bl; int r = osd->store->read(coll, soid, op.extent.offset, op.extent.length, bl);
授課:XXX
// 調用FileStore::read從底層文件系統讀取 …… } case CEPH_OSD_OP_WRITE
4、: ++ctx->num_write; { ……//寫操作只是做準備工作,并不實際的寫 } …… } } FileStore::read函數是底層具體的實現,會通過調用系統函數如::open,::pread,::close等函數來完成具體的操作。[cpp] view plain copy int FileStore::read( coll_t cid, const ghobject_t& oid, uint64_t offset, siz
5、e_t len, bufferlist& bl, bool allow_eio) { …… int r = lfn_open(cid, oid, false, &fd); …… got = safe_pread(**fd, bptr.c_str(), len, offset); //FileStore::safe_pread中調用了::pread …… lfn_close(fd); …… } 而對于寫操作而言,由于要保證數據寫入的同步性就會復雜很多:
1.首先客戶端會將數據發(fā)送給
6、主osd,
2.主osd同樣要先進行寫操作預處理,完成后它要發(fā)送寫消息給其他的從osd,讓他們對副本pg進行更改,
3.從osd通過FileJournal完成寫操作到Journal中后發(fā)送消息告訴主osd說完成,進入5
授課:XXX
4.當主osd收到所有的從osd完成寫操作的消息后,會通過FileJournal完成自身的寫操作到Journal中。完成后會通知客戶端,已經完成了寫操作。
5.主osd,從osd的線程開始工作調用Filestore將Journal中的數據寫入到底層文件系統中。在介紹寫操作的流程前,需要先介紹一下ceph中的callback函數。
Context
7、類定義在src/include文件中,該類是一個回調函數類的抽象類,繼承它的類只要在子類實現它的finish函數,在finish函數調用自己需要回調的函數,就可以完成回調。
[cpp] view plain copy class Context { Context(const Context& other); const Context& operator=(const Context& other); protected: virtual void finish(int r) = 0; public: Context(
8、) {} virtual ~Context() {} // we want a virtual destructor!!! virtual void complete(int r) { finish(r); delete this; } }; Finisher類是在src/common中定義的一個專門查看操作是否結束的一個類。在這個類里面擁有一個線程finisher_thread和一個類型為Context指針的隊列finisher_queue。當一個操作線程完成自己的操作后,會將Context類型對象送入隊列。此時f
9、inisher_thread線程循環(huán)監(jiān)視著自己的finisher_queue隊列,當發(fā)現了有新進入的Context時,會調用這個Context::complete函數,這個函數則會調用到Context子類自己實現的finish函數。來處理操作完成后的后續(xù)工作。
授課:XXX
[cpp] view plain copy class Finisher { CephContext *cct; …… vector<Context*> finisher_queue; …… void *finisher_thread_entry()
10、; struct FinisherThread : public Thread { Finisher *fin; FinisherThread(Finisher *f) : fin(f) {} void* entry() { return (void*)fin->finisher_thread_entry(); } } finisher_thread; …… } void *Finisher::finisher_thread_entry() { …… while(!f
11、inisher_stop){ while(!finisher_queue.empty()){ …… vector<Context*> ls ls.swap(finisher_queue); for (vector<Context*>::iterator p = ls.begin(); p != ls.end(); ++p) { if (*p) {
12、 //這里面調用Context子類實現的finish函數 (*p)->complete(0); } } } } } 在寫操作中涉及了多個線程和消息隊列的協同工作,需要注意的是一個類擁有一個Finisher成員時,以為著它同時獲得了一個隊列和一個執(zhí)行線程。
授課:XXX
OSD中處理讀寫操作是線程池和消息隊列(有很多,其他暫時不討論):
[cpp] view plain copy ThreadPool op_tp
13、; ThreadPool::WorkQueueVal<pair<PGRef,OpRequestRef>, PGRef> &op_wq;
FileJournal中擁有的線程和消息隊列:
[cpp] view plain copy Write write_thread; deque<write_item> writeq;
其父類Journal中擁有線程和消息隊列(引用自之前說的JournalingObjectStore類中):
[cpp] view plain copy Finisher finisher_
14、thread;
FileStore中擁有的線程和消息隊列:
[cpp] view plain copy ThreadPool op_tp; OpWQ op_wq;//Filestore中實現,繼承自ThreadPool::WorkQueue<OpSequencer> Finisher ondisk_finisher; Finisher op_finisher; 前一章說過在前兩層,OSD根據不同的消息類型,選擇了主OSD處理和從OSD的處理,以下介紹的寫流程,就是在收到具體寫操作以后,本地OSD開始的工作。
授課:X
15、XX
寫的邏輯流程圖如圖:從圖中我們可以看到寫操作分為以下幾步:
1.OSD::op_tp線程從OSD::op_wq中拿出來操作如本文開始的圖上描述,具體代碼流是 ReplicatePG::apply_repop中創(chuàng)建回調類C_OSD_OpCommit和C_OSD_OpApplied
FileStore::queue_transactions中創(chuàng)建了回調類C_JournaledAhead
2.FileJournal::write_thread線程從FileJournal::writeq中拿出來操作,主要就是寫數據到具體的journal中,具體代碼流:3.Journ
16、al::Finisher.finisher_thread線程從Journal::Finisher.finish_queue中拿出來操作,通過調用C_JournalAhead留下的回調函數FileStore:_journaled_ahead,該線程開始工作兩件事:首先入底層FileStore::op_wq通知開始寫,再入FileStore::ondisk_finisher.finisher_queue通知可以返回。具體代碼流:4.FileStore::ondisk_finisher.finisher_thread線程從FileStore::ondisk_finisher.finisher_que
17、ue中拿出來操作,通過調用C_OSD_OpCommit留下來的回調函數ReplicatePG::op_commit,通知客戶端寫操作成功5.FileStore::op_tp線程池從FileStore::op_wq中拿出操作(此處的OP_WQ繼承了父類ThreadPool::WorkQueue重寫了_process和_process_finish等函數,所以不同于OSD::op_wq,它有自己的工作流程),首先調用FileStore::_do_op,完成后調用FileStore::_finish_op。6. FileStore::op_finisher.finisher_thread線程從FileStore::op_finisher.finisher_queue中拿出來操作,通過調用C_OSD_OpApplied留下來的回調函數ReplicatePG::op_applied,通知數據可讀。
(注:可編輯下載,若有不當之處,請指正,謝謝!)
授課:XXX