{
CDir *dir = it->first;
bool unpin = (it->second.state == EXPORT_CANCELLING);
+ auto parent = std::move(it->second.parent);
total_exporting_size -= it->second.approx_size;
export_state.erase(it);
}
// send pending import_maps? (these need to go out when all exports have finished.)
cache->maybe_send_pending_resolves();
+
+ if (parent)
+ child_export_finish(parent, false);
}
// ==========================================================
* check if directory is too large to be export in whole. If it is,
* choose some subdirs, whose total size is suitable.
*/
-void Migrator::maybe_split_export(CDir* dir, vector<pair<CDir*, size_t> >& results)
+void Migrator::maybe_split_export(CDir* dir, uint64_t max_size, bool null_okay,
+ vector<pair<CDir*, size_t> >& results)
{
static const unsigned frag_size = 800;
static const unsigned inode_size = 1000;
vector<LevelData> stack;
stack.emplace_back(dir);
- uint64_t max_size = max_export_size;
size_t found_size = 0;
size_t skipped_size = 0;
for (auto& p : stack)
results.insert(results.end(), p.subdirs.begin(), p.subdirs.end());
- if (results.empty())
+ if (results.empty() && (!skipped_size || !null_okay))
results.emplace_back(dir, found_size + skipped_size);
}
assert(g_conf->mds_kill_export_at != 1);
+ auto parent = it->second.parent;
+
vector<pair<CDir*, size_t> > results;
- maybe_split_export(dir, results);
+ maybe_split_export(dir, max_export_size, (bool)parent, results);
if (results.size() == 1 && results.front().first == dir) {
num_locking_exports--;
return;
}
- dout(7) << "subtree is too large, splitting it into: " << dendl;
+ if (parent) {
+ parent->pending_children += results.size();
+ } else {
+ parent = std::make_shared<export_base_t>(dir->dirfrag(), dest,
+ results.size(), export_queue_gen);
+ }
+
+ if (results.empty()) {
+ dout(7) << "subtree's children all are under exporting, retry rest parts of parent export "
+ << parent->dirfrag << dendl;
+ parent->restart = true;
+ } else {
+ dout(7) << "subtree is too large, splitting it into: " << dendl;
+ }
+
for (auto& p : results) {
CDir *sub = p.first;
assert(sub != dir);
stat.peer = dest;
stat.tid = _mdr->reqid.tid;
stat.mut = _mdr;
+ stat.parent = parent;
mds->mdcache->dispatch_request(_mdr);
}
export_try_cancel(dir);
}
+void Migrator::child_export_finish(std::shared_ptr<export_base_t>& parent, bool success)
+{
+ if (success)
+ parent->restart = true;
+ if (--parent->pending_children == 0) {
+ if (parent->restart &&
+ parent->export_queue_gen == export_queue_gen) {
+ CDir *origin = mds->mdcache->get_dirfrag(parent->dirfrag);
+ if (origin && origin->is_auth()) {
+ dout(7) << "child_export_finish requeue " << *origin << dendl;
+ export_queue.emplace_front(origin->dirfrag(), parent->dest);
+ }
+ }
+ }
+}
+
/*
* called on receipt of MExportDirDiscoverAck
* the importer now has the directory's _inode_ in memory, and pinned.
if (!finished.empty())
mds->queue_waiters(finished);
- MutationRef mut = it->second.mut;
+ MutationRef mut = std::move(it->second.mut);
+ auto parent = std::move(it->second.parent);
// remove from exporting list, clean up state
total_exporting_size -= it->second.approx_size;
export_state.erase(it);
mds->locker->drop_locks(mut.get());
mut->cleanup();
}
-
+
+ if (parent)
+ child_export_finish(parent, true);
+
maybe_do_queued_export();
}
const MDSMap &mds_map);
protected:
+ struct export_base_t {
+ dirfrag_t dirfrag;
+ mds_rank_t dest;
+ unsigned pending_children;
+ uint64_t export_queue_gen;
+ bool restart = false;
+ export_base_t(dirfrag_t df, mds_rank_t d, unsigned c, uint64_t g) :
+ dirfrag(df), dest(d), pending_children(c), export_queue_gen(g) {}
+ };
+
// export fun
struct export_state_t {
int state = 0;
int last_cum_auth_pins = 0;
int num_remote_waiters = 0; // number of remote authpin waiters
export_state_t() {}
+
+ std::shared_ptr<export_base_t> parent;
};
map<CDir*, export_state_t> export_state;
typedef map<CDir*, export_state_t>::iterator export_state_iterator;
unsigned num_locking_exports = 0; // exports in locking state (approx_size == 0)
list<pair<dirfrag_t,mds_rank_t> > export_queue;
+ uint64_t export_queue_gen = 1;
// import fun
struct import_state_t {
void maybe_do_queued_export();
void clear_export_queue() {
export_queue.clear();
+ export_queue_gen++;
}
- void maybe_split_export(CDir* dir, vector<pair<CDir*, size_t> >& results);
+ void maybe_split_export(CDir* dir, uint64_t max_size, bool null_okay,
+ vector<pair<CDir*, size_t> >& results);
+ void child_export_finish(std::shared_ptr<export_base_t>& parent, bool success);
void get_export_lock_set(CDir *dir, set<SimpleLock*>& locks);
void get_export_client_set(CDir *dir, set<client_t> &client_set);
void get_export_client_set(CInode *in, set<client_t> &client_set);