]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: batch up writes in SessionMap::save_if_dirty
authorJohn Spray <john.spray@redhat.com>
Wed, 1 Apr 2015 11:21:05 +0000 (12:21 +0100)
committerJohn Spray <john.spray@redhat.com>
Wed, 1 Apr 2015 11:21:05 +0000 (12:21 +0100)
...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 <john.spray@redhat.com>
src/mds/SessionMap.cc
src/mds/SessionMap.h
src/mds/journal.cc

index b37e443b82e3e15c7ecf79486b1d26c827b433f4..cd45b35f18881bbd2b723ef772720d4a06ed2359 100644 (file)
@@ -747,61 +747,85 @@ public:
 };
 
 
-void SessionMap::save_if_dirty(entity_name_t session_id,
+void SessionMap::save_if_dirty(const std::set<entity_name_t> &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<entity_name_t> 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<entity_name_t>::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<string, bufferlist> 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<string, bufferlist> 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));
+    }
+  }
 }
 
 
index f6c851e81ab1cce149373abb2dfc589a99168862..b64871c6d960eac02715fd5ff52024a4f0bb49db 100644 (file)
@@ -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<entity_name_t> &tgt_sessions,
+                     MDSGatherBuilder *gather_bld);
 };
 
 
index 4079a6046a27c49240092dc3f0265b6e2247798b..f92202922a7bcee260c618c6694c5e6126043e35 100644 (file)
@@ -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<entity_name_t>::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