]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: implement 'dump cache' asok command 3750/head
authorJohn Spray <john.spray@redhat.com>
Tue, 17 Mar 2015 18:38:41 +0000 (18:38 +0000)
committerJohn Spray <john.spray@redhat.com>
Thu, 19 Mar 2015 21:27:35 +0000 (21:27 +0000)
Retains old text format output when user specifies
a filename, else returns JSON.  JSON output will
cope less well with large caches, but will be more
useful for automated tests.

Signed-off-by: John Spray <john.spray@redhat.com>
src/mds/MDCache.cc
src/mds/MDCache.h
src/mds/MDS.cc

index 81ea780e64b5e46079d8c573aeb335d0debdb457..915e700fbd0e7d171f0fca9fc5b3e24d2244b127 100644 (file)
@@ -11807,63 +11807,124 @@ void MDCache::show_cache()
   }
 }
 
+void MDCache::dump_cache(std::string const &file_name)
+{
+  dump_cache(file_name.c_str(), NULL);
+}
 
-void MDCache::dump_cache(const char *fn)
+void MDCache::dump_cache(Formatter *f)
 {
-  int r;
-  char deffn[200];
-  if (!fn) {
-    snprintf(deffn, sizeof(deffn), "cachedump.%d.mds%d", (int)mds->mdsmap->get_epoch(), int(mds->get_nodeid()));
-    fn = deffn;
-  }
+  dump_cache(NULL, f);
+}
 
-  dout(1) << "dump_cache to " << fn << dendl;
+/**
+ * Dump the metadata cache, either to a Formatter, if
+ * provided, else to a plain text file.
+ */
+void MDCache::dump_cache(const char *fn, Formatter *f)
+{
+  int r = 0;
+  int fd = -1;
 
-  int fd = ::open(fn, O_WRONLY|O_CREAT|O_EXCL, 0600);
-  if (fd < 0) {
-    derr << "failed to open " << fn << ": " << cpp_strerror(errno) << dendl;
-    return;
+  if (f) {
+    f->open_array_section("inodes");
+  } else {
+    char deffn[200];
+    if (!fn) {
+      snprintf(deffn, sizeof(deffn), "cachedump.%d.mds%d", (int)mds->mdsmap->get_epoch(), int(mds->get_nodeid()));
+      fn = deffn;
+    }
+
+    dout(1) << "dump_cache to " << fn << dendl;
+
+    fd = ::open(fn, O_WRONLY|O_CREAT|O_EXCL, 0600);
+    if (fd < 0) {
+      derr << "failed to open " << fn << ": " << cpp_strerror(errno) << dendl;
+      return;
+    }
   }
   
   for (ceph::unordered_map<vinodeno_t,CInode*>::iterator it = inode_map.begin();
        it != inode_map.end();
        ++it) {
     CInode *in = it->second;
-    ostringstream ss;
-    ss << *in << std::endl;
-    std::string s = ss.str();
-    r = safe_write(fd, s.c_str(), s.length());
-    if (r < 0)
-      goto out;
+    if (f) {
+      f->open_object_section("inode");
+      in->dump(f);
+    } else {
+      ostringstream ss;
+      ss << *in << std::endl;
+      std::string s = ss.str();
+      r = safe_write(fd, s.c_str(), s.length());
+      if (r < 0) {
+        goto out;
+      }
+    }
 
     list<CDir*> dfs;
     in->get_dirfrags(dfs);
+    if (f) {
+      f->open_array_section("dirfrags");
+    }
     for (list<CDir*>::iterator p = dfs.begin(); p != dfs.end(); ++p) {
       CDir *dir = *p;
-      ostringstream tt;
-      tt << " " << *dir << std::endl;
-      string t = tt.str();
-      r = safe_write(fd, t.c_str(), t.length());
-      if (r < 0)
-       goto out;
+      if (f) {
+        f->open_object_section("dir");
+        dir->dump(f);
+      } else {
+        ostringstream tt;
+        tt << " " << *dir << std::endl;
+        string t = tt.str();
+        r = safe_write(fd, t.c_str(), t.length());
+        if (r < 0) {
+          goto out;
+        }
+      }
       
+      if (f) {
+        f->open_array_section("dentries");
+      }
       for (CDir::map_t::iterator q = dir->items.begin();
           q != dir->items.end();
           ++q) {
        CDentry *dn = q->second;
-       ostringstream uu;
-       uu << "  " << *dn << std::endl;
-       string u = uu.str();
-       r = safe_write(fd, u.c_str(), u.length());
-       if (r < 0)
-         goto out;
+        if (f) {
+         f->open_object_section("dentry");
+          dn->dump(f);
+          f->close_section();
+        } else {
+          ostringstream uu;
+          uu << "  " << *dn << std::endl;
+          string u = uu.str();
+          r = safe_write(fd, u.c_str(), u.length());
+          if (r < 0) {
+            goto out;
+          }
+        }
+      }
+      if (f) {
+       f->close_section();  //dentries
       }
       dir->check_rstats();
+      if (f) {
+       f->close_section();  //dir
+      }
+    }
+    if (f) {
+      f->close_section();  // dirfrags
+    }
+
+    if (f) {
+      f->close_section();  // inode
     }
   }
 
  out:
-  ::close(fd);
+  if (f) {
+    f->close_section();  // inodes
+  } else {
+    ::close(fd);
+  }
 }
 
 
index dca96b9587575b6ac728ef4e008503e7117540d6..39b1f66f143eb0285badf1ca7d3ec4e0561fbe74 100644 (file)
@@ -1081,10 +1081,16 @@ public:
   void discard_delayed_expire(CDir *dir);
 
 
+protected:
+  void dump_cache(const char *fn, Formatter *f);
+public:
+  void dump_cache() {dump_cache(NULL, NULL);}
+  void dump_cache(const std::string &filename);
+  void dump_cache(Formatter *f);
+
   // == crap fns ==
  public:
   void show_cache();
-  void dump_cache(const char *fn=0);
   void show_subtrees(int dbl=10);
 
   CInode *hack_pick_random_inode() {
index 77727ae9356280cc63dce519648a239357e3d6ce..2b785c607a41a341d43136b24c6402a9d31e2335 100644 (file)
@@ -347,6 +347,13 @@ bool MDS::asok_command(string command, cmdmap_t& cmdmap, string format,
         return true;
       }
       command_export_dir(f, path, (mds_rank_t)rank);
+    } else if (command == "dump cache") {
+      string path;
+      if(!cmd_getval(g_ceph_context, cmdmap, "path", path)) {
+        mdcache->dump_cache(f);
+      } else {
+        mdcache->dump_cache(path);
+      }
     } else if (command == "force_readonly") {
       mds_lock.Lock();
       mdcache->force_readonly();
@@ -602,6 +609,11 @@ void MDS::set_up_admin_socket()
                                      asok_hook,
                                      "migrate a subtree to named MDS");
   assert(r == 0);
+  r = admin_socket->register_command("dump cache",
+                                     "dump cache name=path,type=CephString,req=false",
+                                     asok_hook,
+                                     "dump metadata cache (optionally to a file)");
+  assert(r == 0);
   r = admin_socket->register_command("session evict",
                                     "session evict name=client_id,type=CephString",
                                     asok_hook,
@@ -1225,9 +1237,6 @@ COMMAND("heap " \
        "mds", "*", "cli,rest")
 };
 
-// FIXME: reinstate dumpcache as an admin socket command
-//  -- it makes no sense for it to be a remote command when
-//     the output is a local file
 // FIXME: reinstate issue_caps, try_eval, fragment_dir, merge_dir
 //  *if* it makes sense to do so (or should these be admin socket things?)