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)
{
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)
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);
+}
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
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(); }
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),
/** @} Scrubbing and fsck */
};
+ostream& operator<<(ostream& out, const CInode::scrub_stamp_info_t& si);
+
#endif