目录
一 引言
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寻址
如果需要获取某个对象的属性值,需要进行以下过程:
- 根据对象object id获取HOBJECT_TO_SEQ+ghobject_key(oid),根据此key值获取对应的header;
- 根据对应的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中。
1444

被折叠的 条评论
为什么被折叠?



