From 5199f928c31ccad69a847df1bde5563c7d67833e Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sat, 26 Jul 2008 08:36:49 -0700 Subject: [PATCH] mds: purge stale snap data during readdir. also, dirty dir if anything gets purged --- src/TODO | 2 +- src/mds/CDir.cc | 66 ++++++++++++++++++++++++++++++++++------------- src/mds/CDir.h | 5 ++++ src/mds/Server.cc | 31 +++++++++++++++++++--- 4 files changed, 82 insertions(+), 22 deletions(-) diff --git a/src/TODO b/src/TODO index 12ab9208fe77b..b24c7e7bed0e1 100644 --- a/src/TODO +++ b/src/TODO @@ -27,7 +27,7 @@ snapshots mds - migrator import/export of versioned dentries, inodes... drop them on export... -/- pin/unpin open_past_parents. +- purge snap during readdir /- call open_parents() where needed. - what about during recovery? e.g. client reconnected caps... - resolve/rejoin vs snapshots! diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index 3f66ba03d4be5..2c91b1455b34f 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -19,9 +19,10 @@ #include "CDentry.h" #include "CInode.h" +#include "MDSMap.h" #include "MDS.h" #include "MDCache.h" -#include "MDSMap.h" +#include "MDLog.h" #include "LogSegment.h" #include "include/Context.h" @@ -954,6 +955,23 @@ void CDir::mark_clean() } +struct C_Dir_Dirty : public Context { + CDir *dir; + version_t pv; + LogSegment *ls; + C_Dir_Dirty(CDir *d, version_t p, LogSegment *l) : dir(d), pv(p), ls(l) {} + void finish(int r) { + dir->mark_dirty(pv, ls); + } +}; + +void CDir::log_mark_dirty() +{ + MDLog *mdlog = inode->mdcache->mds->mdlog; + version_t pv = pre_dirty(); + mdlog->wait_for_sync(new C_Dir_Dirty(this, pv, mdlog->get_current_segment())); +} + void CDir::first_get() @@ -1047,8 +1065,11 @@ void CDir::_fetched(bufferlist &bl) int32_t n; ::decode(n, p); - snapid_t got_last_destroyed; - ::decode(got_last_destroyed, p); + snapid_t got_snap_purged_thru; + ::decode(got_snap_purged_thru, p); + + if (got_snap_purged_thru > snap_purged_thru) + snap_purged_thru = got_snap_purged_thru; // purge stale snaps? // * only if we have past_parents open! @@ -1056,11 +1077,15 @@ void CDir::_fetched(bufferlist &bl) SnapRealm *realm = inode->find_snaprealm(); if (!realm->have_past_parents_open()) { dout(10) << " no snap purge, one or more past parents NOT open" << dendl; - } else if (got_last_destroyed < realm->get_last_destroyed()) { + } else if (snap_purged_thru < realm->get_last_destroyed()) { snaps = &realm->get_snaps(); - dout(10) << " got last_destroyed " << got_last_destroyed << " < " << realm->get_last_destroyed() + dout(10) << " snap_purged_thru " << got_snap_purged_thru + << " < " << realm->get_last_destroyed() << ", snap purge based on " << *snaps << dendl; + snap_purged_thru = realm->get_last_destroyed(); } + bool purged_any = false; + //int num_new_inodes_loaded = 0; @@ -1087,6 +1112,7 @@ void CDir::_fetched(bufferlist &bl) if (p == snaps->end() || *p > last) { dout(10) << " skipping stale dentry on [" << first << "," << last << "]" << dendl; stale = true; + purged_any = true; } } @@ -1245,6 +1271,9 @@ void CDir::_fetched(bufferlist &bl) //cache->mds->logger->inc("newin", num_new_inodes_loaded); //hack_num_accessed = 0; + if (purged_any) + log_mark_dirty(); + // mark complete, !fetching state_set(STATE_COMPLETE); state_clear(STATE_FETCHING); @@ -1354,25 +1383,26 @@ void CDir::_commit(version_t want) if (cache->mds->logger) cache->mds->logger->inc("dir_c"); + // snap purge? + SnapRealm *realm = inode->find_snaprealm(); + const set *snaps = 0; + if (!realm->have_past_parents_open()) { + dout(10) << " no snap purge, one or more past parents NOT open" << dendl; + } else if (snap_purged_thru < realm->get_last_destroyed()) { + snaps = &realm->get_snaps(); + dout(10) << " snap_purged_thru " << snap_purged_thru + << " < " << realm->get_last_destroyed() + << ", snap purge based on " << *snaps << dendl; + snap_purged_thru = realm->get_last_destroyed(); + } + // encode bufferlist bl; ::encode(fnode, bl); int32_t n = num_head_items + num_snap_items; ::encode(n, bl); - - SnapRealm *realm = inode->find_snaprealm(); - snapid_t last_destroyed = realm->get_last_destroyed(); - ::encode(last_destroyed, bl); - - // snap purge? - const set *snaps = 0; - if (realm->have_past_parents_open()) { - snaps = &realm->get_snaps(); - dout(10) << " snap purge based on " << *snaps << dendl; - } else { - dout(10) << " no snap purge, one or more past parents NOT open" << dendl; - } + ::encode(snap_purged_thru, bl); map_t::iterator p = items.begin(); while (p != items.end()) { diff --git a/src/mds/CDir.h b/src/mds/CDir.h index bfc963b180a42..2512ad8f652ea 100644 --- a/src/mds/CDir.h +++ b/src/mds/CDir.h @@ -194,6 +194,7 @@ public: } } void mark_dirty(version_t pv, LogSegment *ls); + void log_mark_dirty(); void mark_clean(); public: @@ -211,6 +212,10 @@ protected: int num_dirty; +public: + snapid_t snap_purged_thru; // the max_last_destroy snapid we've been purged thru +protected: + // state version_t committing_version; version_t committed_version; diff --git a/src/mds/Server.cc b/src/mds/Server.cc index 639095f50e44d..a203dc6391bfb 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -1948,16 +1948,38 @@ void Server::handle_client_readdir(MDRequest *mdr) snapid_t snapid = mdr->ref_snapid; dout(10) << "snapid " << snapid << dendl; + + // purge stale snap data? + const set *snaps = 0; + SnapRealm *realm = diri->find_snaprealm(); + if (realm->get_last_destroyed() > dir->snap_purged_thru) { + snaps = &realm->get_snaps(); + dout(10) << " last_destroyed " << realm->get_last_destroyed() << " > " << dir->snap_purged_thru + << ", doing snap purge with " << *snaps << dendl; + dir->snap_purged_thru = realm->get_last_destroyed(); + assert(snaps->count(snapid)); // just checkin'! + } + bool purged_any = false; + // build dir contents bufferlist dirbl, dnbl; dir->encode_dirstat(dirbl, mds->get_nodeid()); __u32 numfiles = 0; - for (CDir::map_t::iterator it = dir->begin(); - it != dir->end(); - it++) { + CDir::map_t::iterator it = dir->begin(); + while (it != dir->end()) { CDentry *dn = it->second; + it++; + if (dn->is_null()) continue; + if (snaps && dn->last != CEPH_NOSNAP) { + set::const_iterator p = snaps->lower_bound(dn->first); + if (p == snaps->end() || *p > dn->last) { + dir->remove_dentry(dn); + purged_any = true; + continue; + } + } if (dn->last < snapid || dn->first > snapid) continue; @@ -2002,6 +2024,9 @@ void Server::handle_client_readdir(MDRequest *mdr) ::encode(numfiles, dirbl); dirbl.claim_append(dnbl); + if (purged_any) + dir->log_mark_dirty(); + // yay, reply MClientReply *reply = new MClientReply(req); reply->set_dir_bl(dirbl); -- 2.39.5