FileStore omap的实现

目录

一 引言

二 omap实现

三 omap寻址

四 omap属性设置

五 header ->seq的由来


一 引言

ceph分布式存储中在本地存储方面采用插件模式,支持filestore、bluestore、memstore等存储引擎。FileStore承载着数据的存储,除了要将数据写入本地文件系统外,还需要存储部分数据的属性信息,少量的元数据信息存储在文件系统的xattr中,还有一些属性信息需要存储在kv db中,我们称这些信息为object map,简称omap

二 omap实现

 

上图是omap的静态类图,类ObjectMap定义omap的抽象接口。KeyValueDB主要有三类,由于时间原因各版本采用的kv db并不完全一致,hammer版本采用level db,l版采用rocksdb来存储kv。

omap以key-value的形式存在,如何定义这里的key值?

最简单的设计是采用object id+xattr 作为key值,由于object id的唯一性,采用这种方式存储key值,可形成简单形象的key值。这种方式的主要弊端是当一个对象有多个KV值时, Object的name多次作为key存储, 由于Object的name一般比较长, 这样存储方式浪费空间比较大。FileStore将key值的生成分为两步,第一步根据object id生成seq,然后利用seq+xattr作为对象属性的key值,生成一个header值;第二步,根据header里的seq以及具体对应规则,生成omap值

1)

key:HOBJECT_TO_SEQ+ghobject_key(oid)
value:header

HOBJECT_TO_SEQ是一个固定的前缀标识字符串,函数ghobject_key根据oid获取对象的key字符串。

  struct _Header {
    uint64_t seq; //header在leveldb中的seq序号
    uint64_t parent;//父对象的序号
    uint64_t num_children;//子对象数量

    ghobject_t oid;//对象标识

    SequencerPosition spos;

}

2)对象的属性保存为key-value pair:

key: USER_PREFIX + header_key(header->seq) + XATTR_PREFIX +key

value: omap值

三 omap寻址

如果需要获取某个对象的属性值,需要进行以下过程:

  1. 根据对象object id获取HOBJECT_TO_SEQ+ghobject_key(oid),根据此key值获取对应的header;
  2. 根据对应的header中的seq值,获取leveldb中USER_PREFIX + header_key(header->seq) + XATTR_PREFIX +key对应value值

DBobjectmap.cc:
int DBObjectMap::get_xattrs(const ghobject_t &oid,
                const set<string> &to_get,
                map<string, bufferlist> *out)
{
  MapHeaderLock hl(this, oid);//为对应的iod header加锁
  Header header = lookup_map_header(hl, oid);//查找oid对应的header
  if (!header)
    return -ENOENT;
  return db->get(xattr_prefix(header), to_get, out);//根据查找出的header值生成前缀,然后根据规则取出对应的omap值
}
 

四 omap属性设置

DBObjectMap.cc:

const string DBObjectMap::USER_PREFIX = "_USER_";
const string DBObjectMap::XATTR_PREFIX = "_AXATTR_";
const string DBObjectMap::SYS_PREFIX = "_SYS_";
const string DBObjectMap::COMPLETE_PREFIX = "_COMPLETE_";
const string DBObjectMap::HEADER_KEY = "HEADER";
const string DBObjectMap::USER_HEADER_KEY = "USER_HEADER";
const string DBObjectMap::GLOBAL_STATE_KEY = "HEADER";
const string DBObjectMap::HOBJECT_TO_SEQ = "_HOBJTOSEQ_";

string DBObjectMap::header_key(uint64_t seq)
{
  char buf[100];
  snprintf(buf, sizeof(buf), "%.*" PRId64, (int)(2*sizeof(seq)), seq);
  return string(buf);
}


string DBObjectMap::xattr_prefix(Header header)
{
  return USER_PREFIX + header_key(header->seq) + XATTR_PREFIX;
}

int DBObjectMap::set_xattrs(const ghobject_t &oid,
                const map<string, bufferlist> &to_set,
                const SequencerPosition *spos)
{
  KeyValueDB::Transaction t = db->get_transaction();
  MapHeaderLock hl(this, oid);
  Header header = lookup_create_map_header(hl, oid, t);//有则改之,无则创建
  if (!header)
    return -EINVAL;
  if (check_spos(oid, header, spos))
    return 0;
  t->set(xattr_prefix(header), to_set);//根据header中seq值,设置属性
  return db->submit_transaction(t);
}

五 header ->seq的由来

leveldb中无论是get_xattrs还是set_xattrs,起到核心作用的均是seq这个值。seq如何生成?

查找代码发现,leveldb中另外还存放一个global的key-value pair:

key: SYS_PREFIX + GLOBAL_STATE_KEY 

value:state


  /// persistent state for store @see generate_header
  struct State {
    static const __u8 CUR_VERSION = 3;
    __u8 v;
    uint64_t seq;
    // legacy is false when complete regions never used
    bool legacy;
    State() : v(0), seq(1), legacy(false) {}
    explicit State(uint64_t seq) : v(0), seq(seq), legacy(false) {}

该结构体负责管理seq,当有新的header生成,seq保持单调递增,写入leveldb中。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值