Ceph 源代码分析 -OS module

Ceph的src/os 中保存了 ObjectStore代码实现。

基本概念

对象
对象存储的概念,把对象作为存储的实体。 在Ceph 文件系统里,对象的命名空间分了两层, 第一层是Collection的概念,一个Collection就是许多Object的集合,相当于其他对象存储的group的概念,用coll_t来标识。 

ObjectStore 类 就代表了一个Object, 其继承关系为 FileStore 继承了 JournalingObjectStore,JournalingObjectStore继承了ObjectStore

事务
Transaction类代表了一个事务操作。所有的操作都必须通过一个transaction来执行。 一个transaction几乎实现了所有对对象和集合的操作。

ObjectMap的概念
ObjectMap, 就是一些key,value的map属性,其保存在Object里面。 在Ceph文件系统了,ObjectMap由levelDB这个google开源的KV数据库来实现。

还有一个attributes的 概念,attributes也是一些 key/value的属性值。

首先看一下对外的接口,我们可以通过src/test/filestore/store_test.cc文件来看一下其实如何运行的:
[cpp]  view plain copy
  1. virtual void SetUp() {  
  2.     ::mkdir("store_test_temp_dir", 0777);  
  3.     ObjectStore *store_ = new FileStore(string("store_test_temp_dir"), string("store_test_temp_journal"));  
  4.     store.reset(store_);  
  5.     store->mkfs();  
  6.     store->mount();  
  7.   }  
首先mkdir一个目录,store_test_temp_dir,  新建一个FileStore对象,其后面的参数分别是:文件的目录和日志的目录,分别也可以是一个block device.  调用mkfs 函数和 mount 函数,后面会详细介绍。

[cpp]  view plain copy
  1. ObjectStore::Transaction t;  
  2. t.create_collection(cid);  
  3. cerr << "create collection" << std::endl;  
  4. r = store->apply_transaction(t);  
  5. ASSERT_EQ(r, 0);  
这是一个创建collection的代码 先通过一个transaction 来创建,之后通过 store 的 apply_transaction 函数来应用日志,来完成创建一个collection。

[cpp]  view plain copy
  1. hobject_t hoid(sobject_t("Object 1", CEPH_NOSNAP));  
  2.  {  
  3.    ObjectStore::Transaction t;  
  4.    t.touch(cid, hoid);  
  5.    cerr << "Creating object " << hoid << std::endl;  
  6.    r = store->apply_transaction(t);  
  7.    ASSERT_EQ(r, 0);  
  8.  }  
同样的,可以通过transaction的接口touch来在一个collection 中创建一个对象。

在store_test.cc测试文件中,还有其它的测试操作其包括:

  • 创建/删除一个collection
  • 创建/删除一个collection 的 object
  • omap的set/get , 这里 omap也许不容易理解,就是key/value 的map队保存在object 中,所以叫omap
  • 属性的set/get
  • 其它collection的操作,这里就不详述。

总之,通过store_test.cc的测试文件,可以清晰的了解Object的对外的接口。



[cpp]  view plain copy
  1. 在了解Object, Collection, OMap 对象存储 的基本概念,之后大家需要了解文件系统的基本的知识,如transaction, journal等,这里就不详细介绍了。下面具体分析OS模块的代码。  

主要的类就是ObjectStore类,其内部有一个重要的transaction类。 JournalingObjectStore继承了ObjectStore的,添加了Journal的功能。FileStore继承了JournalingObjectStore类,实现了在文件中存储。

另一个模块就是Index,在这里实现了两层index,第一层是用来查找collection,第二层是在collection中查找一个object。 其基类为CollectionIndex,  LFNIndex 类继承了它,添加了long filename index (LFNIndex)。在第二层index,也就是查找object的index 实现了两类index ,一个是HashIndex, 另一个是FlatIndex,它们都继承了LFNIndex类。其管理功能的就是IndexManager类。

在这里,HashIndex, 指的是在一个Collection的 Object 是层次的结构,说白了,就是当存储对象的目录可以有子目录。而在FlatIndex里,Object 是没有层次结构的,说白了,就是在一个目录中。

我们主要看一个典型的对象操作流程,来看一下内部的操作。

其操作一般是   操作序列号(encode)--> 写入日志(write-journal) --> 写入对象
  1. t.create_collection(cid);  
  2. cerr << "create collection" << std::endl;  
  3. r = store->apply_transaction(t);  
如上图所示是一个典型的对象的操作, 我们在这里大概给出一个内部操作的流程:
1) t.create_collection(cid),  
[cpp]  view plain copy
  1. void create_collection(coll_t cid) {  
  2.      __u32 op = OP_MKCOLL;  
  3.      ::encode(op, tbl);  
  4.      ::encode(cid, tbl);  
  5.      ops++;  
  6.    }  
其调用了类transaction中的函数,把操作类型和参数通过 encode 函数 序列化到 tbl 中, 我们看到其他的操作都是类型的功能。
2) store->apply_transaction(t); 
这个函数调用了ObjectStore的函数
    首先调用  unsigned apply_transaction(Transaction& t, Context *ondisk=0)
       其调用 unsigned ObjectStore::apply_transactions(Sequencer *osr, list<Transaction*> &tls, Context *ondisk)
       最终调用函数
[cpp]  view plain copy
  1. int ObjectStore::queue_transactions(  
  2.   Sequencer *osr,  
  3.   list<Transaction*>& tls,  
  4.   Context *onreadable,  
  5.   Context *oncommit,  
  6.   Context *onreadable_sync,  
  7.   Context *oncomplete,  
  8.   TrackedOpRef op = TrackedOpRef())  
[cpp]  view plain copy
  1. int queue_transactions(Sequencer *osr, list<Transaction*>& tls,  
  2.              Context *onreadable, Context *ondisk=0,  
  3.              Context *onreadable_sync=0,  
  4.              TrackedOpRef op = TrackedOpRef()) {  
  5.     assert(!tls.empty());  
  6.     tls.back()->register_on_applied(onreadable);  
  7.     tls.back()->register_on_commit(ondisk);  
  8.     tls.back()->register_on_applied_sync(onreadable_sync);  
  9.     return queue_transactions(osr, tls, op);  
  10.   }  
最后调用了函数
[cpp]  view plain copy
  1. virtual int queue_transactions(  
  2.     Sequencer *osr, list<Transaction*>& tls,  
  3.     TrackedOpRef op = TrackedOpRef()) = 0;  
这个函数式virturl 函数,其实现在其继承类FileStore类函数中
[cpp]  view plain copy
  1. int FileStore::queue_transactions(Sequencer *posr, list<Transaction*> &tls,  
  2.                   TrackedOpRef osd_op)  
核心的处理模块就这这个函数里.

在这个函数里,主要分了两种情况:
1) 有日志处理的逻辑:
[cpp]  view plain copy
  1. if (journal && journal->is_writeable() && !m_filestore_journal_trailing) {  
[cpp]  view plain copy
  1. {  
  2.     Op *o = build_op(tls, onreadable, onreadable_sync, osd_op);  
  3.     op_queue_reserve_throttle(o);  
  4.     journal->throttle();  
  5.     uint64_t op_num = submit_manager.op_submit_start();  
  6.     o->op = op_num;  
  7.   
  8.   
  9.     if (m_filestore_do_dump)  
  10.       dump_transactions(o->tls, o->op, osr);  
  11.   
  12.   
  13.     if (m_filestore_journal_parallel) {  
  14.       dout(5) << "queue_transactions (parallel) " << o->op << " " << o->tls << dendl;  
  15.         
  16.       _op_journal_transactions(o->tls, o->op, ondisk, osd_op);  
  17.         
  18.       // queue inside submit_manager op submission lock  
  19.       queue_op(osr, o);  
  20.     } else if (m_filestore_journal_writeahead) {  
  21.       dout(5) << "queue_transactions (writeahead) " << o->op << " " << o->tls << dendl;  
  22.         
  23.       osr->queue_journal(o->op);  
  24.   
  25.   
  26.       _op_journal_transactions(o->tls, o->op,  
  27. <span style="white-space:pre">          </span>       new C_JournaledAhead(this, osr, o, ondisk),  
  28. <span style="white-space:pre">          </span>       osd_op);  
  29.     } else {  
  30.       assert(0);  
  31.     }  
  32.     submit_manager.op_submit_finish(op_num);  
  33.     return 0;  
  34.   }  
[cpp]  view plain copy
  1. }  



2) 无日志处理逻辑


在int FileStore::_do_transactions 函数里,我们可以看到各种对象的操作,以及如何实现的。


DBMap函数里: omap 保存在一个key/value的数据库里。

LevelDBStore *omap_store = new LevelDBStore(omap_dir);
    stringstream err;
    if (omap_store->create_and_open(err)) {
      delete omap_store;
      derr << "Error initializing leveldb: " << err.str() << dendl;
      ret = -1;
      goto close_current_fd;
    }
    DBObjectMap *dbomap = new DBObjectMap(omap_store);
    ret = dbomap->init(do_update);
    if (ret < 0) {
      delete dbomap;
      derr << "Error initializing DBObjectMap: " << ret << dendl;
      goto close_current_fd;
    }

attrs 设置在 文件的扩展属性里


转载于:https://my.oschina.net/guyson/blog/325855

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值