欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ObjectStore::Transaction

程序员文章站 2024-01-12 17:37:10
...

事务:一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务的特性:ACID。
Atomicity:事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。
Consistency:事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
Isolation:一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
Durablility:持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
这些是数据库系统开发所遵循的原则。本文能主要是介绍ceph中OjectStore中Transaction的实现。
OjectStore::Transation在实现过程中也尽可能的遵守了ACID原则,它抽象成ObjectStore中的一个内部类,一个事务对象中包含了一系列的原子性op操作,除此之外还包括op操作的数据体。

OjectStore::Transaction中核心的数据结构:

1. 操作标识符 ,每种不同的操作都有一个具体的标识来代表。

  ¦ enum {                                                                                                
  ¦ ¦ OP_NOP =          0,                                                                                                           
  ¦ ¦ OP_TOUCH =        9,   // cid, oid                                                                  
  ¦ ¦ OP_WRITE =        10,  // cid, oid, offset, len, bl                                                 
  ¦ ¦ OP_ZERO =         11,  // cid, oid, offset, len                                                     
  ¦ ¦ OP_TRUNCATE =     12,  // cid, oid, len                                                             
  ¦ ¦ OP_REMOVE =       13,  // cid, oid                                                                  
  ¦ ¦ OP_SETATTR =      14,  // cid, oid, attrname, bl                                                    
  ¦ ¦ OP_SETATTRS =     15,  // cid, oid, attrset                                                         
  ¦ ¦ OP_RMATTR =       16,  // cid, oid, attrname                                                        
  ¦ ¦ OP_CLONE =        17,  // cid, oid, newoid                                                          
  ¦ ¦ OP_CLONERANGE =   18,  // cid, oid, newoid, offset, len                                             
  ¦ ¦ OP_CLONERANGE2 =  30,  // cid, oid, newoid, srcoff, len, dstoff  
  。。。

2.操作抽象结构体,详细描述了一个op操作。

 ¦ struct Op {
  ¦ ¦ __le32 op;
  ¦ ¦ __le32 cid;
  ¦ ¦ __le32 oid;
  ¦ ¦ __le64 off;
  ¦ ¦ __le64 len;
  ¦ ¦ __le32 dest_cid;
  ¦ ¦ __le32 dest_oid;                  //OP_CLONE, OP_CLONERANGE
  ¦ ¦ __le64 dest_off;                  //OP_CLONERANGE
  ¦ ¦ union {
        struct {
        ¦ __le32 hint_type;             //OP_COLL_HINT
        };
        struct {
        ¦ __le32 alloc_hint_flags;      //OP_SETALLOCHINT
        };
  ¦ ¦ };
  ¦ ¦ __le64 expected_object_size;      //OP_SETALLOCHINT
  ¦ ¦ __le64 expected_write_size;       //OP_SETALLOCHINT
  ¦ ¦ __le32 split_bits;                //OP_SPLIT_COLLECTION2,OP_COLL_SET_BITS,
  ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦                   //OP_MKCOLL
  ¦ ¦ __le32 split_rem;                 //OP_SPLIT_COLLECTION2                                                                       
  ¦ } __attribute__ ((packed)) ;

3.TransactionData,记录事务中op(操作)的个数,op操作数据体最大的相关信息。

  ¦ struct TransactionData {
  ¦ ¦ __le64 ops;
  ¦ ¦ __le32 largest_data_len;
  ¦ ¦ __le32 largest_data_off;
  ¦ ¦ __le32 largest_data_off_in_data_bl;
  ¦ ¦ __le32 fadvise_flags;
。。。
}

ObjectStore::Transaction中重要的属性:

data(TransactionData):              //记录该事务中op数,及最大一次数据体操作信息。
osr(void*):                         //定序器。
coll_index(map<coll_t, __le32>//coll_t到其coll_t id的映射表。
object_index(map<ghobject_t, __le32>//ghobject_t到其ghobject id的映射表。
data_bl(bufferlist):                // op操作的数据体。
op_bl(bufferlist):                  //一组op被系列化之后的存储在该bufferlist中。
//回调
on_applied(list<Context*>//op的操作结果可读时,触发该回调(Finisher Thread)
on_applied_sync(list<Context*>//op操作到目标对象之后,触发该回调。(ObjectStore执行线程)
on_commit(list<Context*>//事务提交到磁盘后,触发该回调。(Finisher Thread)

其中data_bl与op_bl是存在对应关系的,op_bl中的op只记录了op操作的元信息,操作数据保存在data_bl中。两者之间有着严格的位置对应关系。
data中记录了op的个数,op中的len记录了操作数的大小,按照这种对应关系就可以从一个事务中解析出一个完整的op操作(元信息+数据体)。
ObjectStore::Transaction的序列化与反序列化:

1.Transaction中哪些数据需要序列化:

data_bl + op_bl + coll_index + object_index + data

2.序列化&反序列化格式:

ObjectStore::Transaction

3.序列化&反序列化的实现:

  ¦ void encode(bufferlist& bl) const {
  ¦ ¦ //layout: data_bl + op_bl + coll_index + object_index + data
  ¦ ¦ ENCODE_START(9, 9, bl);
  ¦ ¦ ::encode(data_bl, bl);
  ¦ ¦ ::encode(op_bl, bl);
  ¦ ¦ ::encode(coll_index, bl);
  ¦ ¦ ::encode(object_index, bl);
  ¦ ¦ data.encode(bl);
  ¦ ¦ ENCODE_FINISH(bl);
  ¦ }

  ¦ void decode(bufferlist::iterator &bl) {
  ¦ ¦ DECODE_START(9, bl);
  ¦ ¦ DECODE_OLDEST(9);

  ¦ ¦ ::decode(data_bl, bl);
  ¦ ¦ ::decode(op_bl, bl);
  ¦ ¦ ::decode(coll_index, bl);
  ¦ ¦ ::decode(object_index, bl);
  ¦ ¦ data.decode(bl);
  ¦ ¦ coll_id = coll_index.size();
  ¦ ¦ object_id = object_index.size();                                                                                               

  ¦ ¦ DECODE_FINISH(bl);
  ¦ }

添加op操作到事务中,如:写入数据:

  ¦ /**
  ¦ ¦* Write data to an offset within an object. If the object is too
  ¦ ¦* small, it is expanded as needed.  It is possible to specify an                                                                
  ¦ ¦* offset beyond the current end of an object and it will be
  ¦ ¦* expanded as needed. Simple implementations of ObjectStore will
  ¦ ¦* just zero the data between the old end of the object and the
  ¦ ¦* newly provided data. More sophisticated implementations of
  ¦ ¦* ObjectStore will omit the untouched data and store it as a
  ¦ ¦* "hole" in the file.
  ¦ ¦*/
  //cid 操作对象所在目录,在内存中的结构对象
  //oid 操作对象
  //off 操作对象中的偏移位置
  //len 要写入的数据长度
  //write_data 要写入的数
  ¦ void write(const coll_t& cid, const ghobject_t& oid, uint64_t off, uint64_t len,
        ¦ ¦ ¦ ¦const bufferlist& write_data, uint32_t flags = 0) {
  ¦ ¦ uint32_t orig_len = data_bl.length();
  ¦ ¦ Op* _op = _get_next_op(); //申请一个op对象,该对象内存空间在op_bl中,初始化该op。
  ¦ ¦ _op->op = OP_WRITE;       // 写入操作
  ¦ ¦ _op->cid = _get_coll_id(cid);  //cid(coll_t)对应的id
  ¦ ¦ _op->oid = _get_object_id(oid); //oid(ghobject)对应的id
  ¦ ¦ _op->off = off;   //写入对象中的偏移位置
  ¦ ¦ _op->len = len;   //写入数据的长度
  ¦ ¦ ::encode(write_data, data_bl);  //把要写入的数据保存到data_bl中。
//判断当前op操作的数据体是不是最大的,若是,则更新data相应数据
  ¦ ¦ assert(len == write_data.length());
  ¦ ¦ data.fadvise_flags = data.fadvise_flags | flags;
  ¦ ¦ if (write_data.length() > data.largest_data_len) {
        data.largest_data_len = write_data.length();
        data.largest_data_off = off;
        data.largest_data_off_in_data_bl = orig_len + sizeof(__u32);  // we are about to
  ¦ ¦ }                                                                                                                              
  ¦ ¦ data.ops++; //增加op的计数。
  ¦ }