]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
ciommon/admin_socket: extract find_matched_hook() out
authorKefu Chai <kchai@redhat.com>
Fri, 11 Sep 2020 08:35:29 +0000 (16:35 +0800)
committerKefu Chai <kchai@redhat.com>
Fri, 11 Sep 2020 08:57:18 +0000 (16:57 +0800)
this function is complicated and isolated enough to be a separated
method.

Signed-off-by: Kefu Chai <kchai@redhat.com>
src/common/admin_socket.cc
src/common/admin_socket.h

index a756e2f0c68f9ad56916597e44b29afc77bf4566..10183fd42f59a89319190b2ad45a0252c6ba2002 100644 (file)
@@ -501,31 +501,20 @@ void AdminSocket::execute_command(
 
   auto f = Formatter::create(format, "json-pretty", "json-pretty");
 
-  std::unique_lock l(lock);
-  decltype(hooks)::iterator p;
-  p = hooks.find(prefix);
-  if (p == hooks.cend()) {
+  auto [retval, hook] = find_matched_hook(prefix, cmdmap);
+  switch (retval) {
+  case ENOENT:
     lderr(m_cct) << "AdminSocket: request '" << cmdvec
                 << "' not defined" << dendl;
     delete f;
     return on_finish(-EINVAL, "unknown command prefix "s + prefix, empty);
+  case EINVAL:
+    delete f;
+    return on_finish(-EINVAL, "invalid command json", empty);
+  default:
+    assert(retval == 0);
   }
 
-  // make sure one of the registered commands with this prefix validates.
-  if (!validate_cmd(m_cct, p->second.desc, cmdmap, errss)) {
-    if (p->first != prefix) {
-      delete f;
-      return on_finish(-EINVAL, "invalid command json", empty);
-    }
-  }
-
-  // Drop lock to avoid cycles in cases where the hook takes
-  // the same lock that was held during calls to register/unregister,
-  // and set in_hook to allow unregister to wait for us before
-  // removing this hook.
-  in_hook = true;
-  auto hook = p->second.hook;
-  l.unlock();
   hook->call_async(
     prefix, cmdmap, f, inbl,
     [f, on_finish](int r, const std::string& err, bufferlist& out) {
@@ -537,11 +526,35 @@ void AdminSocket::execute_command(
       on_finish(r, err, out);
     });
 
-  l.lock();
+  std::unique_lock l(lock);
   in_hook = false;
   in_hook_cond.notify_all();
 }
 
+std::pair<int, AdminSocketHook*>
+AdminSocket::find_matched_hook(std::string& prefix,
+                              const cmdmap_t& cmdmap)
+{
+  std::unique_lock l(lock);
+  // Drop lock after done with the lookup to avoid cycles in cases where the
+  // hook takes the same lock that was held during calls to
+  // register/unregister, and set in_hook to allow unregister to wait for us
+  // before removing this hook.
+  auto p = hooks.find(prefix);
+  if (p == hooks.cend()) {
+    return {ENOENT, nullptr};
+  }
+  // make sure one of the registered commands with this prefix validates.
+  stringstream errss;
+  if (!validate_cmd(m_cct, p->second.desc, cmdmap, errss)) {
+    if (p->first != prefix) {
+      return {EINVAL, nullptr};
+    }
+  }
+  in_hook = true;
+  return {0, p->second.hook};
+}
+
 void AdminSocket::queue_tell_command(cref_t<MCommand> m)
 {
   ldout(m_cct,10) << __func__ << " " << *m << dendl;
index 429b69e00394c605f5a1c85c3ac97bf09573ec94..c5d2b48e563bf0414f19e2e4362f7ad177a75886 100644 (file)
@@ -204,6 +204,11 @@ private:
       : hook(hook), desc(desc), help(help) {}
   };
 
+  /// find the first hook which matches the given prefix and cmdmap
+  std::pair<int, AdminSocketHook*> find_matched_hook(
+    std::string& prefix,
+    const cmdmap_t& cmdmap);
+
   std::multimap<std::string, hook_info, std::less<>> hooks;
 
   friend class AdminSocketTest;