From: Greg Farnum Date: Mon, 10 Nov 2014 22:34:04 +0000 (-0800) Subject: mds: CInode: create scrub_info_t and surrounding infrastructure X-Git-Tag: v10.0.1~51^2~16 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=4a6e799ccd8933af62300292bc57e6077658546b;p=ceph.git mds: CInode: create scrub_info_t and surrounding infrastructure 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 --- diff --git a/src/mds/CInode.cc b/src/mds/CInode.cc index 2e69d6f4b1d5..a5ceea4442a7 100644 --- a/src/mds/CInode.cc +++ b/src/mds/CInode.cc @@ -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 *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(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 frags; + dirfragtree.get_leaves(frags); + for (std::list::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::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* out_dirfrags) +{ + assert(out_dirfrags != NULL); + assert(scrub_infop != NULL); + + out_dirfrags->clear(); + std::map::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::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::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); +} diff --git a/src/mds/CInode.h b/src/mds/CInode.h index a7abba43c2c9..c77375544c9e 100644 --- a/src/mds/CInode.h +++ b/src/mds/CInode.h @@ -242,6 +242,87 @@ public: snapid_t first, last; compact_set 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 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 *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 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