filestore的omap中会按照key-value的方式存储对象的属性信息,在ceph中按照key-value存储属性信息有三个版本,分别是levleDB/ROCKSDB/kineticstore/memDB,目前主要用的是rocksDB。这四部分的源码在src/kv中
从其makefile中可以看到
set(kv_srcs
KeyValueDB.cc
MemDB.cc
RocksDBStore.cc)
if (WITH_LEVELDB)
list(APPEND kv_srcs LevelDBStore.cc)
endif (WITH_LEVELDB)
如果要使用levelDB的话,需要打开with_leveldb这个宏
那ceph 到底是如何选择用哪个kv呢?
在src/common/options.cc 中定义了一个filestore_omap_backend。可以看到默认用的是rocksdb
Option("filestore_omap_backend", Option::TYPE_STR, Option::LEVEL_DEV)
.set_default("rocksdb")
.set_description(""),
在filestore.cc 中的FileStore::mkfs() 函数中
会有如下赋值
// superblock
superblock.omap_backend = cct->_conf->filestore_omap_backend;
ret = write_superblock();
if (ret < 0) {
derr << __FUNC__ << ": write_superblock() failed: "
<< cpp_strerror(ret) << dendl;
goto close_fsid_fd;
}
根据superblock.omap_backend 这个值可以在filestore.cc中的int FileStore::mount() 函数中有如下的code。
KeyValueDB * omap_store = KeyValueDB::create(cct,
superblock.omap_backend,
omap_dir);
if (omap_store == NULL)
{
derr << __FUNC__ << ": Error creating " << superblock.omap_backend << dendl;
ret = -1;
goto close_current_fd;
}
在这个create函数中就可以看到用的kv是哪个后端
KeyValueDB *KeyValueDB::create(CephContext *cct, const string& type,
const string& dir,
void *p)
{
#ifdef WITH_LEVELDB
if (type == "leveldb") {
return new LevelDBStore(cct, dir);
}
#endif
#ifdef HAVE_KINETIC
if (type == "kinetic" &&
cct->check_experimental_feature_enabled("kinetic")) {
return new KineticStore(cct);
}
#endif
#ifdef HAVE_LIBROCKSDB
if (type == "rocksdb") {
return new RocksDBStore(cct, dir, p);
}
#endif
if ((type == "memdb") &&
cct->check_experimental_feature_enabled("memdb")) {
return new MemDB(cct, dir, p);
}
return NULL;
}
从这里我们知道当前系统中所有的支持的kv的后端存储和我们当前的选择
我们看看DBObjectmap中如何读取属性值
int DBObjectMap::get_xattrs(const ghobject_t &oid,
const set<string> &to_get,
map<string, bufferlist> *out)
{
#首先加锁,说明属性值可以被多个进程同时读取。
MapHeaderLock hl(this, oid);
#根据oid找到对应的header,如果没有找到,则根据oid新建一个header
Header header = lookup_map_header(hl, oid);
if (!header)
return -ENOENT;
#根据header中的seq得到键值
return db->get(xattr_prefix(header), to_get, out);
}
其中
string DBObjectMap::xattr_prefix(Header header)
{
return USER_PREFIX + header_key(header->seq) + XATTR_PREFIX;
}
其中header_key的定义如下:
string DBObjectMap::header_key(uint64_t seq)
{
char buf[100];
snprintf(buf, sizeof(buf), "%.*" PRId64, (int)(2*sizeof(seq)), seq);
return string(buf);
}
可见主要是对seq格式化成字符串输出
其中USER_PREFIX 和 XATTR_PREFIX 是两个字符串定义如下:
const string DBObjectMap::USER_PREFIX = "_USER_";
const string DBObjectMap::XATTR_PREFIX = "_AXATTR_";
从这里可以知道kv中的key主要是由seq决定的,而这里的seq是一个
我们知道在get_xattrs 中首先会根据oid新建一个header,以header中的seq为key再保存value,所以seq也是在新建header时候赋值的,具体函数如下:
DBObjectMap::Header DBObjectMap::_generate_new_header(const ghobject_t &oid,
Header parent)
{
#新建一个header
Header header = Header(new _Header(), RemoveOnDelete(this));
#从这里可以知道header中的seq是由state赋值的,并且会一直递增
header->seq = state.seq++;
if (parent) {
header->parent = parent->seq;
header->spos = parent->spos;
}
header->num_children = 1;
header->oid = oid;
assert(!in_use.count(header->seq));
in_use.insert(header->seq);
write_state();
return header;
}
ceph 中kv 存储的后端选择
最新推荐文章于 2022-12-11 12:46:17 发布