return -ENOTSUP;
}
+ char buf[1000];
+ do_setxattr(fn, "user.test", &buf, sizeof(buf));
+ do_setxattr(fn, "user.test2", &buf, sizeof(buf));
+ do_setxattr(fn, "user.test3", &buf, sizeof(buf));
+ do_setxattr(fn, "user.test4", &buf, sizeof(buf));
+ ret = do_setxattr(fn, "user.test5", &buf, sizeof(buf));
+ if (ret == -ENOSPC) {
+ if (!g_conf->filestore_xattr_use_omap) {
+ derr << "limited size xattrs -- enable filestore_xattr_use_omap" << dendl;
+ return -ENOTSUP;
+ } else {
+ derr << "limited size xattrs -- filestore_xattr_use_omap enabled" << dendl;
+ }
+ }
+ do_removexattr(fn, "user.test");
+ do_removexattr(fn, "user.test2");
+ do_removexattr(fn, "user.test3");
+ do_removexattr(fn, "user.test4");
+ do_removexattr(fn, "user.test5");
+
int fd = ::open(basedir.c_str(), O_RDONLY);
if (fd < 0)
return -errno;
string name = i.get_attrname();
bufferlist bl;
i.get_bl(bl);
- if (_check_replay_guard(cid, oid, spos))
- r = _setattr(cid, oid, name.c_str(), bl.c_str(), bl.length());
+ if (!_check_replay_guard(cid, oid, spos))
+ break;
+ map<string, bufferptr> to_set;
+ to_set[name] = bufferptr(bl.c_str(), bl.length());
+ r = _setattrs(cid, oid, to_set);
if (r == -ENOSPC)
dout(0) << " ENOSPC on setxattr on " << cid << "/" << oid
<< " name " << name << " size " << bl.length() << dendl;
// objects
-int FileStore::getattr(coll_t cid, const hobject_t& oid, const char *name,
- void *value, size_t size)
-{
- dout(15) << "getattr " << cid << "/" << oid << " '" << name << "' len " << size << dendl;
- char n[ATTR_MAX_NAME_LEN];
- get_attrname(name, n, ATTR_MAX_NAME_LEN);
- int r = lfn_getxattr(cid, oid, n, value, size);
- dout(10) << "getattr " << cid << "/" << oid << " '" << name << "' len " << size << " = " << r << dendl;
- return r;
-}
-
int FileStore::getattr(coll_t cid, const hobject_t& oid, const char *name, bufferptr &bp)
{
dout(15) << "getattr " << cid << "/" << oid << " '" << name << "'" << dendl;
char n[ATTR_MAX_NAME_LEN];
get_attrname(name, n, ATTR_MAX_NAME_LEN);
int r = _getattr(cid, oid, n, bp);
+ if (r == -ENODATA && g_conf->filestore_xattr_use_omap) {
+ map<string, bufferlist> got;
+ set<string> to_get;
+ to_get.insert(string(name));
+ Index index;
+ r = get_index(cid, &index);
+ if (r < 0) {
+ dout(10) << __func__ << " could not get index r = " << r << dendl;
+ return r;
+ }
+ r = object_map->get_xattrs(oid, index, to_get, &got);
+ if (r < 0 && r != -ENOENT) {
+ dout(10) << __func__ << " get_xattrs err r =" << r << dendl;
+ return r;
+ }
+ if (!got.size()) {
+ dout(10) << __func__ << " got.size() is 0" << dendl;
+ return -ENODATA;
+ }
+ bp = bufferptr(got.begin()->second.c_str(),
+ got.begin()->second.length());
+ r = 0;
+ }
dout(10) << "getattr " << cid << "/" << oid << " '" << name << "' = " << r << dendl;
return r;
}
{
dout(15) << "getattrs " << cid << "/" << oid << dendl;
int r = _getattrs(cid, oid, aset, user_only);
+ if (g_conf->filestore_xattr_use_omap) {
+ set<string> omap_attrs;
+ map<string, bufferlist> omap_aset;
+ Index index;
+ int r = get_index(cid, &index);
+ if (r < 0) {
+ dout(10) << __func__ << " could not get index r = " << r << dendl;
+ return r;
+ }
+ r = object_map->get_all_xattrs(oid, index, &omap_attrs);
+ if (r < 0) {
+ dout(10) << __func__ << " could not get omap_attrs r = " << r << dendl;
+ return r;
+ }
+ r = object_map->get_xattrs(oid, index, omap_attrs, &omap_aset);
+ if (r < 0) {
+ dout(10) << __func__ << " could not get omap_attrs r = " << r << dendl;
+ return r;
+ }
+ assert(omap_attrs.size() == omap_aset.size());
+ for (map<string, bufferlist>::iterator i = omap_aset.begin();
+ i != omap_aset.end();
+ ++i) {
+ string key;
+ if (user_only) {
+ if (i->first[0] != '_')
+ continue;
+ if (i->first == "_")
+ continue;
+ key = i->first.substr(1, i->first.size());
+ } else {
+ key = i->first;
+ }
+ aset.insert(make_pair(key,
+ bufferptr(i->second.c_str(), i->second.length())));
+ }
+ }
dout(10) << "getattrs " << cid << "/" << oid << " = " << r << dendl;
return r;
}
-int FileStore::_setattr(coll_t cid, const hobject_t& oid, const char *name,
- const void *value, size_t size)
-{
- dout(15) << "setattr " << cid << "/" << oid << " '" << name << "' len " << size << dendl;
- char n[ATTR_MAX_NAME_LEN];
- get_attrname(name, n, ATTR_MAX_NAME_LEN);
- int r = lfn_setxattr(cid, oid, n, value, size);
- dout(10) << "setattr " << cid << "/" << oid << " '" << name << "' len " << size << " = " << r << dendl;
- return r;
-}
-
int FileStore::_setattrs(coll_t cid, const hobject_t& oid, map<string,bufferptr>& aset)
{
+ map<string, bufferlist> omap_set;
+ set<string> omap_remove;
+ map<string, bufferptr> inline_set;
+ if (g_conf->filestore_xattr_use_omap)
+ _getattrs(cid, oid, inline_set);
dout(15) << "setattrs " << cid << "/" << oid << dendl;
int r = 0;
for (map<string,bufferptr>::iterator p = aset.begin();
++p) {
char n[ATTR_MAX_NAME_LEN];
get_attrname(p->first.c_str(), n, ATTR_MAX_NAME_LEN);
+ if (g_conf->filestore_xattr_use_omap) {
+ if (p->second.length() > g_conf->filestore_max_inline_xattr_size) {
+ if (inline_set.count(p->first)) {
+ inline_set.erase(p->first);
+ r = lfn_removexattr(cid, oid, n);
+ if (r < 0)
+ return r;
+ }
+ omap_set[p->first].push_back(p->second);
+ continue;
+ }
+
+ if (!inline_set.count(p->first) &&
+ inline_set.size() >= g_conf->filestore_max_inline_xattrs) {
+ if (inline_set.count(p->first)) {
+ inline_set.erase(p->first);
+ r = lfn_removexattr(cid, oid, n);
+ if (r < 0)
+ return r;
+ }
+ omap_set[p->first].push_back(p->second);
+ continue;
+ }
+ omap_remove.insert(p->first);
+ inline_set.insert(*p);
+ }
+
const char *val;
if (p->second.length())
val = p->second.c_str();
break;
}
}
+
+ if (g_conf->filestore_xattr_use_omap) {
+ Index index;
+ int r = get_index(cid, &index);
+ if (r < 0) {
+ dout(10) << __func__ << " could not get index r = " << r << dendl;
+ return r;
+ }
+ r = object_map->remove_xattrs(oid, index, omap_remove);
+ if (r < 0 && r != -ENOENT) {
+ dout(10) << __func__ << " could not remove_xattrs r = " << r << dendl;
+ return r;
+ }
+ r = object_map->set_xattrs(oid, index, omap_set);
+ if (r < 0) {
+ dout(10) << __func__ << " could not set_xattrs r = " << r << dendl;
+ return r;
+ }
+ }
dout(10) << "setattrs " << cid << "/" << oid << " = " << r << dendl;
return r;
}
char n[ATTR_MAX_NAME_LEN];
get_attrname(name, n, ATTR_MAX_NAME_LEN);
int r = lfn_removexattr(cid, oid, n);
+ if (r == -ENODATA && g_conf->filestore_xattr_use_omap) {
+ Index index;
+ r = get_index(cid, &index);
+ if (r < 0) {
+ dout(10) << __func__ << " could not get index r = " << r << dendl;
+ return r;
+ }
+ set<string> to_remove;
+ to_remove.insert(string(name));
+ r = object_map->remove_xattrs(oid, index, to_remove);
+ if (r < 0 && r != -ENOENT) {
+ dout(10) << __func__ << " could not remove_xattrs index r = " << r << dendl;
+ return r;
+ }
+ }
dout(10) << "rmattr " << cid << "/" << oid << " '" << name << "' = " << r << dendl;
return r;
}
break;
}
}
+ if (g_conf->filestore_xattr_use_omap) {
+ set<string> omap_attrs;
+ Index index;
+ r = get_index(cid, &index);
+ if (r < 0) {
+ dout(10) << __func__ << " could not get index r = " << r << dendl;
+ return r;
+ }
+ r = object_map->get_all_xattrs(oid, index, &omap_attrs);
+ if (r < 0) {
+ dout(10) << __func__ << " could not get omap_attrs r = " << r << dendl;
+ return r;
+ }
+ r = object_map->remove_xattrs(oid, index, omap_attrs);
+ if (r < 0) {
+ dout(10) << __func__ << " could not remove omap_attrs r = " << r << dendl;
+ return r;
+ }
+ }
dout(10) << "rmattrs " << cid << "/" << oid << " = " << r << dendl;
return r;
}
store->apply_transaction(t);
}
+TEST_F(StoreTest, XattrTest) {
+ coll_t cid("blah");
+ hobject_t hoid("tesomap", "", CEPH_NOSNAP, 0);
+ bufferlist big;
+ for (unsigned i = 0; i < 10000; ++i) {
+ big.append('\0');
+ }
+ bufferlist small;
+ for (unsigned i = 0; i < 10; ++i) {
+ small.append('\0');
+ }
+ int r;
+ {
+ ObjectStore::Transaction t;
+ t.create_collection(cid);
+ t.touch(cid, hoid);
+ r = store->apply_transaction(t);
+ ASSERT_EQ(r, 0);
+ }
+
+ map<string, bufferlist> attrs;
+ {
+ ObjectStore::Transaction t;
+ t.setattr(cid, hoid, "attr1", small);
+ attrs["attr1"] = small;
+ t.setattr(cid, hoid, "attr2", big);
+ attrs["attr2"] = big;
+ t.setattr(cid, hoid, "attr3", small);
+ attrs["attr3"] = small;
+ t.setattr(cid, hoid, "attr1", small);
+ attrs["attr1"] = small;
+ t.setattr(cid, hoid, "attr4", big);
+ attrs["attr4"] = big;
+ t.setattr(cid, hoid, "attr3", big);
+ attrs["attr3"] = big;
+ r = store->apply_transaction(t);
+ ASSERT_EQ(r, 0);
+ }
+
+ map<string, bufferptr> aset;
+ store->getattrs(cid, hoid, aset);
+ ASSERT_EQ(aset.size(), attrs.size());
+ for (map<string, bufferptr>::iterator i = aset.begin();
+ i != aset.end();
+ ++i) {
+ bufferlist bl;
+ bl.push_back(i->second);
+ ASSERT_TRUE(attrs[i->first] == bl);
+ }
+
+ {
+ ObjectStore::Transaction t;
+ t.rmattr(cid, hoid, "attr2");
+ attrs.erase("attr2");
+ r = store->apply_transaction(t);
+ ASSERT_EQ(r, 0);
+ }
+
+ aset.clear();
+ store->getattrs(cid, hoid, aset);
+ ASSERT_EQ(aset.size(), attrs.size());
+ for (map<string, bufferptr>::iterator i = aset.begin();
+ i != aset.end();
+ ++i) {
+ bufferlist bl;
+ bl.push_back(i->second);
+ ASSERT_TRUE(attrs[i->first] == bl);
+ }
+
+ bufferptr bp;
+ r = store->getattr(cid, hoid, "attr2", bp);
+ ASSERT_EQ(r, -ENODATA);
+
+ r = store->getattr(cid, hoid, "attr3", bp);
+ ASSERT_EQ(r, 0);
+ bufferlist bl2;
+ bl2.push_back(bp);
+ ASSERT_TRUE(bl2 == attrs["attr3"]);
+}
+
int main(int argc, char **argv) {
vector<const char*> args;
argv_to_vec(argc, (const char **)argv, args);