#undef dout_prefix
#define dout_prefix *_dout << "bluestore(" << store->path << ").collection(" << cid << ") "
-BlueStore::Collection::Collection(BlueStore *ns, coll_t c)
+BlueStore::Collection::Collection(BlueStore *ns, Cache *cs, coll_t c)
: store(ns),
+ cache(cs),
cid(c),
lock("BlueStore::Collection::lock", true, false),
exists(true),
bnode_set(MAX(16, g_conf->bluestore_onode_cache_size / 128)),
- onode_map(&ns->cache)
+ onode_map(cs)
{
}
return OnodeRef();
// new
- on = new Onode(&onode_map, oid, key, &cache);
+ on = new Onode(&onode_map, oid, key, cache);
} else {
// loaded
assert(r >=0);
- on = new Onode(&onode_map, oid, key, &cache);
+ on = new Onode(&onode_map, oid, key, cache);
on->exists = true;
bufferlist::iterator p = v.begin();
::decode(on->onode, p);
{
_init_logger();
g_ceph_context->_conf->add_observer(this);
+ set_cache_shards(1);
}
BlueStore::~BlueStore()
assert(db == NULL);
assert(bluefs == NULL);
assert(fsid_fd < 0);
+ for (auto i : cache_shards) {
+ delete i;
+ }
+ cache_shards.clear();
}
const char **BlueStore::get_tracked_conf_keys() const
it->next()) {
coll_t cid;
if (cid.parse(it->key())) {
- CollectionRef c(new Collection(this, cid));
+ CollectionRef c(
+ new Collection(
+ this,
+ cache_shards[cid.hash_to_shard(cache_shards.size())],
+ cid));
bufferlist bl = it->value();
bufferlist::iterator p = bl.begin();
try {
return r;
}
+void BlueStore::set_cache_shards(unsigned num)
+{
+ dout(10) << __func__ << " " << num << dendl;
+ size_t old = cache_shards.size();
+ assert(num >= old);
+ cache_shards.resize(num);
+ for (unsigned i = old; i < num; ++i) {
+ cache_shards[i] = new Cache;
+ }
+}
+
int BlueStore::mount()
{
dout(1) << __func__ << " path " << path << dendl;
{
std::lock_guard<std::mutex> l(osr->qlock);
dout(20) << __func__ << " osr " << osr << dendl;
+ CollectionRef c;
while (!osr->q.empty()) {
TransContext *txc = &osr->q.front();
dout(20) << __func__ << " txc " << txc << " " << txc->get_state_name()
break;
}
+ if (!c && txc->first_collection) {
+ c = txc->first_collection;
+ }
+
osr->q.pop_front();
txc->log_state_latency(logger, l_bluestore_state_done_lat);
delete txc;
if (osr->q.empty())
dout(20) << __func__ << " osr " << osr << " q now empty" << dendl;
}
-
- cache.trim(g_conf->bluestore_onode_cache_size,
- g_conf->bluestore_buffer_cache_size);
+ if (c) {
+ c->cache->trim(
+ g_conf->bluestore_onode_cache_size,
+ g_conf->bluestore_buffer_cache_size);
+ }
}
void BlueStore::_txc_finalize_kv(TransContext *txc, KeyValueDB::Transaction t)
for (vector<coll_t>::iterator p = i.colls.begin(); p != i.colls.end();
++p, ++j) {
cvec[j] = _get_collection(*p);
+
+ // note first collection we reference
+ if (!j && !txc->first_collection)
+ txc->first_collection = cvec[j];
}
vector<OnodeRef> ovec(i.objects.size());
r = -EEXIST;
goto out;
}
- c->reset(new Collection(this, cid));
+ c->reset(
+ new Collection(
+ this,
+ cache_shards[cid.hash_to_shard(cache_shards.size())],
+ cid));
(*c)->cnode.bits = bits;
coll_map[cid] = *c;
}
bool get_next(const ghobject_t& after, pair<ghobject_t,OnodeRef> *next);
};
+ struct Cache;
+
struct Collection : public CollectionImpl {
BlueStore *store;
+ Cache *cache; ///< our cache shard
coll_t cid;
bluestore_cnode_t cnode;
RWLock lock;
// cache onodes on a per-collection basis to avoid lock
// contention.
OnodeSpace onode_map;
- Cache cache;
OnodeRef get_onode(const ghobject_t& oid, bool create);
BnodeRef get_bnode(uint32_t hash);
return false;
}
- Collection(BlueStore *ns, coll_t c);
+ Collection(BlueStore *ns, Cache *ca, coll_t c);
};
typedef boost::intrusive_ptr<Collection> CollectionRef;
IOContext ioc;
+ CollectionRef first_collection; ///< first referenced collection
+
uint64_t seq = 0;
utime_t start;
RWLock coll_lock; ///< rwlock to protect coll_map
ceph::unordered_map<coll_t, CollectionRef> coll_map;
- Cache cache;
+ vector<Cache*> cache_shards;
std::mutex nid_lock;
uint64_t nid_last;
int fsck() override;
+ void set_cache_shards(unsigned num) override;
+
int validate_hobject_key(const hobject_t &obj) const override {
return 0;
}