]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: CInode: create scrub_info_t and surrounding infrastructure
authorGreg Farnum <gfarnum@redhat.com>
Mon, 10 Nov 2014 22:34:04 +0000 (14:34 -0800)
committerYan, Zheng <zyan@redhat.com>
Wed, 4 Nov 2015 09:17:24 +0000 (17:17 +0800)
Like the CDir stuff, this has data structures and helpers to track its
own internal scrub state, and -- in the case of directory inodes -- to
select the next dirfrag you need to handle.

Signed-off-by: Greg Farnum <gfarnum@redhat.com>
src/mds/CInode.cc
src/mds/CInode.h

index 2e69d6f4b1d5f5296b984ccb7d0c420cb6cab9cf..a5ceea4442a790d7f876b19362c864d54f603cb4 100644 (file)
@@ -250,6 +250,16 @@ ostream& operator<<(ostream& out, const CInode& in)
   return out;
 }
 
+ostream& operator<<(ostream& out, const CInode::scrub_stamp_info_t& si)
+{
+  out << "{scrub_start_version: " << si.scrub_start_version
+      << ", scrub_start_stamp: " << si.scrub_start_stamp
+      << ", last_scrub_version: " << si.last_scrub_version
+      << ", last_scrub_stamp: " << si.last_scrub_stamp;
+  return out;
+}
+
+
 
 void CInode::print(ostream& out)
 {
@@ -352,12 +362,22 @@ inode_t *CInode::project_inode(map<string,bufferptr> *px)
     if (px)
       *px = *get_projected_xattrs();
   }
+
+  projected_inode_t &pi = *projected_nodes.back();
+
   if (px) {
-    projected_nodes.back()->xattrs = px;
+    pi.xattrs = px;
     ++num_projected_xattrs;
   }
-  dout(15) << "project_inode " << projected_nodes.back()->inode << dendl;
-  return projected_nodes.back()->inode;
+
+  if (scrub_infop && scrub_infop->last_scrub_dirty) {
+    pi.inode->last_scrub_stamp = scrub_infop->last_scrub_stamp;
+    pi.inode->last_scrub_version = scrub_infop->last_scrub_version;
+    scrub_infop->last_scrub_dirty = false;
+    scrub_maybe_delete_info();
+  }
+  dout(15) << "project_inode " << pi.inode << dendl;
+  return pi.inode;
 }
 
 void CInode::pop_and_dirty_projected_inode(LogSegment *ls) 
@@ -3985,3 +4005,138 @@ void CInode::dump(Formatter *f) const
   f->close_section();
 }
 
+/****** Scrub Stuff *****/
+void CInode::scrub_info_create() const
+{
+  dout(25) << __func__ << dendl;
+  assert(!scrub_infop);
+
+  // break out of const-land to set up implicit initial state
+  CInode *me = const_cast<CInode*>(this);
+  inode_t *in = me->get_projected_inode();
+
+  scrub_info_t *si = new scrub_info_t();
+  si->scrub_start_stamp = si->last_scrub_stamp = in->last_scrub_stamp;
+  si->scrub_start_version = si->last_scrub_version = in->last_scrub_version;
+
+  me->scrub_infop = si;
+}
+
+void CInode::scrub_maybe_delete_info()
+{
+  if (scrub_infop &&
+      !scrub_infop->scrub_in_progress &&
+      !scrub_infop->last_scrub_dirty) {
+    delete scrub_infop;
+    scrub_infop = NULL;
+  }
+}
+
+void CInode::scrub_initialize(version_t scrub_version)
+{
+  dout(20) << __func__ << " with scrub_version "
+           << scrub_version << dendl;
+  assert(!scrub_infop || !scrub_infop->scrub_in_progress);
+  scrub_info();
+  if (!scrub_infop)
+    scrub_infop = new scrub_info_t();
+  else
+    assert(!scrub_infop->scrub_in_progress);
+
+  if (get_projected_inode()->is_dir()) {
+    // fill in dirfrag_stamps with initial state
+    std::list<frag_t> frags;
+    dirfragtree.get_leaves(frags);
+    for (std::list<frag_t>::iterator i = frags.begin();
+        i != frags.end();
+        ++i) {
+      scrub_infop->dirfrag_stamps[*i];
+    }
+  }
+  scrub_infop->scrub_in_progress = true;
+  scrub_infop->scrub_start_version = scrub_version;
+  scrub_infop->scrub_start_stamp = ceph_clock_now(g_ceph_context);
+  // right now we don't handle remote inodes
+}
+
+int CInode::scrub_dirfrag_next(frag_t* out_dirfrag)
+{
+  dout(20) << __func__ << dendl;
+  assert(scrub_infop && scrub_infop->scrub_in_progress);
+
+  if (!is_dir()) {
+    return -ENOTDIR;
+  }
+
+  std::map<frag_t, scrub_stamp_info_t>::iterator i =
+      scrub_infop->dirfrag_stamps.begin();
+
+  while (i != scrub_infop->dirfrag_stamps.end()) {
+    if (i->second.scrub_start_version < scrub_infop->scrub_start_version) {
+      i->second.scrub_start_version = get_projected_version();
+      i->second.scrub_start_stamp = ceph_clock_now(g_ceph_context);
+      *out_dirfrag = i->first;
+      dout(20) << " return frag " << *out_dirfrag << dendl;
+      return 0;
+    }
+    ++i;
+  }
+
+  dout(20) << " no frags left, ENOENT " << dendl;
+  return ENOENT;
+}
+
+void CInode::scrub_dirfrags_scrubbing(list<frag_t>* out_dirfrags)
+{
+  assert(out_dirfrags != NULL);
+  assert(scrub_infop != NULL);
+
+  out_dirfrags->clear();
+  std::map<frag_t, scrub_stamp_info_t>::iterator i =
+      scrub_infop->dirfrag_stamps.begin();
+
+  while (i != scrub_infop->dirfrag_stamps.end()) {
+    if (i->second.scrub_start_version >= scrub_infop->scrub_start_version) {
+      if (i->second.last_scrub_version < scrub_infop->scrub_start_version)
+        out_dirfrags->push_back(i->first);
+    } else {
+      return;
+    }
+
+    ++i;
+  }
+}
+
+void CInode::scrub_dirfrag_finished(frag_t dirfrag)
+{
+  dout(20) << __func__ << " on frag " << dirfrag << dendl;
+  assert(scrub_infop && scrub_infop->scrub_in_progress);
+
+  std::map<frag_t, scrub_stamp_info_t>::iterator i =
+      scrub_infop->dirfrag_stamps.find(dirfrag);
+  assert(i != scrub_infop->dirfrag_stamps.end());
+
+  scrub_stamp_info_t &si = i->second;
+  si.last_scrub_stamp = si.scrub_start_stamp;
+  si.last_scrub_version = si.scrub_start_version;
+}
+
+void CInode::scrub_finished(Context **c) {
+  dout(20) << __func__ << dendl;
+  assert(scrub_info()->scrub_in_progress);
+  for (std::map<frag_t, scrub_stamp_info_t>::iterator i =
+      scrub_infop->dirfrag_stamps.begin();
+      i != scrub_infop->dirfrag_stamps.end();
+      ++i) {
+    if(i->second.last_scrub_version != i->second.scrub_start_version) {
+      derr << i->second.last_scrub_version << " != "
+        << i->second.scrub_start_version << dendl;
+    }
+    assert(i->second.last_scrub_version == i->second.scrub_start_version);
+  }
+  scrub_infop->last_scrub_version = scrub_infop->scrub_start_version;
+  scrub_infop->last_scrub_stamp = scrub_infop->scrub_start_stamp;
+  scrub_infop->last_scrub_dirty = true;
+  scrub_infop->scrub_in_progress = false;
+  parent->scrub_finished(c);
+}
index a7abba43c2c9fc2c91395d3c957dc675af9c78b7..c77375544c9ea50070f2a466e5a4da974f0457a1 100644 (file)
@@ -242,6 +242,87 @@ public:
   snapid_t          first, last;
   compact_set<snapid_t> dirty_old_rstats;
 
+  class scrub_stamp_info_t {
+  public:
+    /// version we started our latest scrub (whether in-progress or finished)
+    version_t scrub_start_version;
+    /// time we started our latest scrub (whether in-progress or finished)
+    utime_t scrub_start_stamp;
+    /// version we started our most recent finished scrub
+    version_t last_scrub_version;
+    /// time we started our most recent finished scrub
+    utime_t last_scrub_stamp;
+    scrub_stamp_info_t() : scrub_start_version(0), last_scrub_version(0) {}
+  };
+
+  class scrub_info_t : public scrub_stamp_info_t {
+  public:
+    bool last_scrub_dirty; /// are our stamps dirty with respect to disk state?
+    bool scrub_in_progress; /// are we currently scrubbing?
+    /// my own (temporary) stamps and versions for each dirfrag we have
+    std::map<frag_t, scrub_stamp_info_t> dirfrag_stamps;
+
+    scrub_info_t() : scrub_stamp_info_t(), last_scrub_dirty(false),
+        scrub_in_progress(false) {}
+  };
+
+  const scrub_info_t *scrub_info() const{
+    if (!scrub_infop)
+      scrub_info_create();
+    return scrub_infop;
+  }
+  /**
+   * Start scrubbing on this inode. That could be very short if it's
+   * a file, or take a long time if we're recursively scrubbing a directory.
+   * @pre It is not currently scrubbing
+   * @post it has set up internal scrubbing state
+   * @param scrub_version What version are we scrubbing at (usually, parent
+   * directory's get_projected_version())
+   */
+  void scrub_initialize(version_t scrub_version);
+  /**
+   * Get the next dirfrag to scrub. Gives you a frag_t in output param which
+   * you must convert to a CDir (and possibly load off disk).
+   * @param dir A pointer to frag_t, will be filled in with the next dirfrag to
+   * scrub if there is one.
+   * @returns 0 on success, you should scrub the passed-out frag_t right now;
+   * ENOENT: There are no remaining dirfrags to scrub
+   * <0 There was some other error (It will return -ENOTDIR if not a directory)
+   */
+  int scrub_dirfrag_next(frag_t* out_dirfrag);
+  /**
+   * Get the currently scrubbing dirfrags. When returned, the
+   * passed-in list will be filled in with all frag_ts which have
+   * been returned from scrub_dirfrag_next but not sent back
+   * via scrub_dirfrag_finished.
+   */
+  void scrub_dirfrags_scrubbing(list<frag_t> *out_dirfrags);
+  /**
+   * Report to the CInode that a dirfrag it owns has been scrubbed. Call
+   * this for every frag_t returned from scrub_dirfrag_next().
+   * @param dirfrag The frag_t that was scrubbed
+   */
+  void scrub_dirfrag_finished(frag_t dirfrag);
+  /**
+   * Call this once the scrub has been completed, whether it's a full
+   * recursive scrub on a directory or simply the data on a file (or
+   * anything in between).
+   * @param c An out param which is filled in with a Context* that must
+   * be complete()ed.
+   */
+  void scrub_finished(Context **c);
+
+private:
+  /**
+   * Create a scrub_info_t struct for the scrub_infop poitner.
+   */
+  void scrub_info_create() const;
+  /**
+   * Delete the scrub_info_t struct if it's not got any useful data
+   */
+  void scrub_maybe_delete_info();
+public:
+
   bool is_multiversion() const {
     return snaprealm ||  // other snaprealms will link to me
       inode.is_dir() ||  // links to me in other snaps
@@ -401,6 +482,7 @@ public:
 private:
   compact_map<frag_t,CDir*> dirfrags; // cached dir fragments under this Inode
   int stickydir_ref;
+  scrub_info_t *scrub_infop;
 
 public:
   bool has_dirfrags() { return !dirfrags.empty(); }
@@ -539,6 +621,7 @@ public:
     num_projected_xattrs(0),
     num_projected_srnodes(0),
     stickydir_ref(0),
+    scrub_infop(NULL),
     parent(0),
     inode_auth(CDIR_AUTH_DEFAULT),
     replica_caps_wanted(0),
@@ -1025,4 +1108,6 @@ private:
   /** @} Scrubbing and fsck */
 };
 
+ostream& operator<<(ostream& out, const CInode::scrub_stamp_info_t& si);
+
 #endif