From: John Spray Date: Wed, 1 Apr 2015 11:21:05 +0000 (+0100) Subject: mds: batch up writes in SessionMap::save_if_dirty X-Git-Tag: v9.0.1~118^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=aa7f0b3669882683597d8b122a78cea78703e569;p=ceph.git mds: batch up writes in SessionMap::save_if_dirty ...in order to avoid issuing lots of separate RADOS ops if expiring a segment that contained requests for many clients. Signed-off-by: John Spray --- diff --git a/src/mds/SessionMap.cc b/src/mds/SessionMap.cc index b37e443b82e3..cd45b35f1888 100644 --- a/src/mds/SessionMap.cc +++ b/src/mds/SessionMap.cc @@ -747,61 +747,85 @@ public: }; -void SessionMap::save_if_dirty(entity_name_t session_id, +void SessionMap::save_if_dirty(const std::set &tgt_sessions, MDSGatherBuilder *gather_bld) { assert(gather_bld != NULL); - if (session_map.count(session_id) == 0) { - // Session isn't around any more, never mind. - return; - } - - Session *session = session_map[session_id]; - if (!session->has_dirty_completed_requests()) { - // Session hasn't had completed_requests - // modified since last write, no need to - // write it now. - return; - } - - if (dirty_sessions.count(session_id) > 0) { - // Session is already dirtied, will be written, no - // need to pre-empt that. - return; - } + std::vector write_sessions; - // Okay, passed all our checks, now we write - // this session out. The version we write - // into the OMAP may now be higher-versioned - // than the version in the header, but that's - // okay because it's never a problem to have - // an overly-fresh copy of a session. - session->clear_dirty_completed_requests(); + // Decide which sessions require a write + for (std::set::iterator i = tgt_sessions.begin(); + i != tgt_sessions.end(); ++i) { + const entity_name_t &session_id = *i; - MDSInternalContextBase *on_safe = gather_bld->new_sub(); + if (session_map.count(session_id) == 0) { + // Session isn't around any more, never mind. + continue; + } - map to_set; + Session *session = session_map[session_id]; + if (!session->has_dirty_completed_requests()) { + // Session hasn't had completed_requests + // modified since last write, no need to + // write it now. + continue; + } - // Serialize K - std::ostringstream k; - k << session_id; + if (dirty_sessions.count(session_id) > 0) { + // Session is already dirtied, will be written, no + // need to pre-empt that. + continue; + } + // Okay, passed all our checks, now we write + // this session out. The version we write + // into the OMAP may now be higher-versioned + // than the version in the header, but that's + // okay because it's never a problem to have + // an overly-fresh copy of a session. + write_sessions.push_back(*i); + } - // Serialize V - bufferlist bl; - session->info.encode(bl); + dout(4) << __func__ << ": writing " << write_sessions.size() << dendl; - // Add to RADOS op - to_set[k.str()] = bl; + // Batch writes into mds_sessionmap_keys_per_op + const uint32_t kpo = g_conf->mds_sessionmap_keys_per_op; + map to_set; + for (uint32_t i = 0; i < write_sessions.size(); ++i) { + // Start a new write transaction? + if (i % g_conf->mds_sessionmap_keys_per_op == 0) { + to_set.clear(); + } - ObjectOperation op; - op.omap_set(to_set); + const entity_name_t &session_id = write_sessions[i]; + Session *session = session_map[session_id]; + session->clear_dirty_completed_requests(); - SnapContext snapc; - object_t oid = get_object_name(); - object_locator_t oloc(mds->mdsmap->get_metadata_pool()); - mds->objecter->mutate(oid, oloc, op, snapc, ceph_clock_now(g_ceph_context), - 0, NULL, new C_OnFinisher(new C_IO_SM_Save_One(this, on_safe), &mds->finisher)); + // Serialize K + std::ostringstream k; + k << session_id; + + // Serialize V + bufferlist bl; + session->info.encode(bl); + + // Add to RADOS op + to_set[k.str()] = bl; + + // Complete this write transaction? + if (i == write_sessions.size() - 1 + || i % kpo == kpo - 1) { + ObjectOperation op; + op.omap_set(to_set); + + SnapContext snapc; + object_t oid = get_object_name(); + object_locator_t oloc(mds->mdsmap->get_metadata_pool()); + MDSInternalContextBase *on_safe = gather_bld->new_sub(); + mds->objecter->mutate(oid, oloc, op, snapc, ceph_clock_now(g_ceph_context), + 0, NULL, new C_OnFinisher(new C_IO_SM_Save_One(this, on_safe), &mds->finisher)); + } + } } diff --git a/src/mds/SessionMap.h b/src/mds/SessionMap.h index f6c851e81ab1..b64871c6d960 100644 --- a/src/mds/SessionMap.h +++ b/src/mds/SessionMap.h @@ -560,12 +560,13 @@ public: void replay_advance_version(); /** - * If a session exists with this ID, and it has + * For these session IDs, if a session exists with this ID, and it has * dirty completed_requests, then persist it immediately * (ahead of usual project/dirty versioned writes * of the map). */ - void save_if_dirty(entity_name_t, MDSGatherBuilder *gather_bld); + void save_if_dirty(const std::set &tgt_sessions, + MDSGatherBuilder *gather_bld); }; diff --git a/src/mds/journal.cc b/src/mds/journal.cc index 4079a6046a27..f92202922a7b 100644 --- a/src/mds/journal.cc +++ b/src/mds/journal.cc @@ -238,10 +238,7 @@ void LogSegment::try_to_expire(MDS *mds, MDSGatherBuilder &gather_bld, int op_pr } // updates to sessions for completed_requests - for (std::set::iterator i = touched_sessions.begin(); - i != touched_sessions.end(); ++i) { - mds->sessionmap.save_if_dirty(*i, &gather_bld); - } + mds->sessionmap.save_if_dirty(touched_sessions, &gather_bld); touched_sessions.clear(); // pending commit atids