contents[*pdn] = in->inode;
}
}
-
+
// add .. too?
- if (diri != root && diri->dn && diri->dn->dir) {
- Inode *parent = diri->dn->dir->parent_inode;
- contents[".."] = parent->inode;
- }
+ if (diri != root)
+ contents[".."] = diri->inode;
// FIXME: remove items in cache that weren't in my readdir?
// ***
if (dir.get_dir_auth() != CDIR_AUTH_DEFAULT)
out << " dir_auth=" << dir.get_dir_auth();
+ if (dir.get_cum_auth_pins())
+ out << " ap=" << dir.get_auth_pins() << "+" << dir.get_nested_auth_pins();
+
out << " state=" << dir.get_state();
- if (dir.state_test(CDIR_STATE_PROXY)) out << "|proxy";
- if (dir.state_test(CDIR_STATE_COMPLETE)) out << "|complete";
- if (dir.state_test(CDIR_STATE_FREEZINGTREE)) out << "|freezingtree";
- if (dir.state_test(CDIR_STATE_FROZENTREE)) out << "|frozentree";
- //if (dir.state_test(CDIR_STATE_FROZENTREELEAF)) out << "|frozentreeleaf";
- if (dir.state_test(CDIR_STATE_FROZENDIR)) out << "|frozendir";
- if (dir.state_test(CDIR_STATE_FREEZINGDIR)) out << "|freezingdir";
+ if (dir.state_test(CDir::STATE_PROXY)) out << "|proxy";
+ if (dir.state_test(CDir::STATE_COMPLETE)) out << "|complete";
+ if (dir.state_test(CDir::STATE_FREEZINGTREE)) out << "|freezingtree";
+ if (dir.state_test(CDir::STATE_FROZENTREE)) out << "|frozentree";
+ //if (dir.state_test(CDir::STATE_FROZENTREELEAF)) out << "|frozentreeleaf";
+ if (dir.state_test(CDir::STATE_FROZENDIR)) out << "|frozendir";
+ if (dir.state_test(CDir::STATE_FREEZINGDIR)) out << "|freezingdir";
+ if (dir.state_test(CDir::STATE_EXPORTBOUND)) out << "|exportbound";
+ if (dir.state_test(CDir::STATE_IMPORTBOUND)) out << "|importbound";
out << " sz=" << dir.get_nitems() << "+" << dir.get_nnull();
nitems = 0;
nnull = 0;
- state = CDIR_STATE_INITIAL;
+ state = STATE_INITIAL;
projected_version = version = 0;
committing_version = 0;
// auth
assert(in->is_dir());
if (auth)
- state |= CDIR_STATE_AUTH;
+ state |= STATE_AUTH;
/*
if (in->dir_is_hashed()) {
assert(0); // when does this happen?
- state |= CDIR_STATE_HASHED;
+ state |= STATE_HASHED;
}
*/
nested_auth_pins = 0;
request_pins = 0;
- //dir_rep = CDIR_REP_NONE;
- dir_rep = CDIR_REP_ALL; // hack: to wring out some bugs! FIXME FIXME
+ //dir_rep = REP_NONE;
+ dir_rep = REP_ALL; // hack: to wring out some bugs! FIXME FIXME
}
list<Context*> finished;
take_waiting(mask, finished);
- finish_contexts(finished, result);
+ //finish_contexts(finished, result);
+ cache->mds->queue_finished(finished);
}
void CDir::finish_waiting(int mask, const string& dn, int result)
list<Context*> finished;
take_waiting(mask, dn, finished);
- finish_contexts(finished, result);
+ //finish_contexts(finished, result);
+ cache->mds->queue_finished(finished);
}
void CDir::_mark_dirty()
{
- if (!state_test(CDIR_STATE_DIRTY)) {
- state_set(CDIR_STATE_DIRTY);
+ if (!state_test(STATE_DIRTY)) {
+ state_set(STATE_DIRTY);
dout(10) << "mark_dirty (was clean) " << *this << " version " << version << endl;
get(PIN_DIRTY);
} else {
void CDir::mark_clean()
{
dout(10) << "mark_clean " << *this << " version " << version << endl;
- if (state_test(CDIR_STATE_DIRTY)) {
- state_clear(CDIR_STATE_DIRTY);
+ if (state_test(STATE_DIRTY)) {
+ state_clear(STATE_DIRTY);
put(PIN_DIRTY);
}
}
*/
pair<int,int> CDir::authority()
{
+ if (is_subtree_root())
+ return dir_auth;
+
+ return inode->authority();
+}
+/*
pair<int,int> a = dir_auth;
// look at parent?
else
return pair<int,int>(a.first, dir_auth.second);
}
+*/
/** is_subtree_root()
* true if this is an auth delegation point.
*/
bool CDir::is_subtree_root()
{
- if (dir_auth == CDIR_AUTH_DEFAULT)
+ if (dir_auth == CDIR_AUTH_DEFAULT) {
+ //dout(10) << "is_subtree_root false " << dir_auth << " != " << CDIR_AUTH_DEFAULT
+ //<< " on " << ino() << endl;
return false;
- else
+ } else {
+ //dout(10) << "is_subtree_root true " << dir_auth << " != " << CDIR_AUTH_DEFAULT
+ //<< " on " << ino() << endl;
return true;
+ }
}
/** set_dir_auth
+ *
+ * always list ourselves first.
*
* accept 'iamauth' param so that i can intelligently adjust freeze auth_pins
* even when the auth bit isn't correct.
// new subtree root?
if (!was_subtree && is_subtree_root()) {
- dout(10) << "new subtree root, adjusting auth_pins" << endl;
+ dout(10) << " new subtree root, adjusting auth_pins" << endl;
// adjust nested auth pins
- inode->adjust_nested_auth_pins(get_cum_auth_pins());
+ inode->adjust_nested_auth_pins(-get_cum_auth_pins());
- // pin parent of frozen dir/tree?
- if (iamauth && (is_frozen_tree_root() || is_frozen_dir()))
- inode->auth_pin();
+ // unpin parent of frozen dir/tree?
+ if (inode->is_auth() && (is_frozen_tree_root() || is_frozen_dir()))
+ inode->auth_unpin();
}
if (was_subtree && !is_subtree_root()) {
- dout(10) << "old subtree root, adjusting auth_pins" << endl;
+ dout(10) << " old subtree root, adjusting auth_pins" << endl;
// adjust nested auth pins
inode->adjust_nested_auth_pins(get_cum_auth_pins());
assert(auth_pins >= 0);
// pending freeze?
- if (auth_pins + nested_auth_pins == 0)
+ if (auth_pins + nested_auth_pins == 0)
on_freezeable();
// nest?
// dir
dir->nested_auth_pins += inc;
- dout(10) << "adjust_nested_auth_pins on " << *dir << " count now " << dir->auth_pins << " + " << dir->nested_auth_pins << endl;
+ dout(10) << "adjust_nested_auth_pins " << inc << " on " << *dir << " count now " << dir->auth_pins << " + " << dir->nested_auth_pins << endl;
assert(dir->nested_auth_pins >= 0);
// pending freeze?
dout(10) << "freeze_tree " << *this << endl;
_freeze_tree(c);
} else {
- state_set(CDIR_STATE_FREEZINGTREE);
+ state_set(STATE_FREEZINGTREE);
dout(10) << "freeze_tree + wait " << *this << endl;
// need to wait for auth pins to expire
if (!is_freezeable()) {
// wait again!
dout(10) << "freeze_tree_finish still waiting " << *this << endl;
- state_set(CDIR_STATE_FREEZINGTREE);
+ state_set(STATE_FREEZINGTREE);
add_waiter(CDIR_WAIT_FREEZEABLE, new C_MDS_FreezeTree(this, c));
return;
}
assert(is_freezeable_dir());
// twiddle state
- state_clear(CDIR_STATE_FREEZINGTREE); // actually, this may get set again by next context?
- state_set(CDIR_STATE_FROZENTREE);
+ state_clear(STATE_FREEZINGTREE); // actually, this may get set again by next context?
+ state_set(STATE_FROZENTREE);
// auth_pin inode for duration of freeze, if we are not a subtree root.
if (is_auth() && !is_subtree_root())
{
dout(10) << "unfreeze_tree " << *this << endl;
- if (state_test(CDIR_STATE_FROZENTREE)) {
+ if (state_test(STATE_FROZENTREE)) {
// frozen. unfreeze.
- state_clear(CDIR_STATE_FROZENTREE);
+ state_clear(STATE_FROZENTREE);
// unpin (may => FREEZEABLE) FIXME: is this order good?
if (is_auth() && !is_subtree_root())
finish_waiting(CDIR_WAIT_UNFREEZE);
} else {
// freezing. stop it.
- assert(state_test(CDIR_STATE_FREEZINGTREE));
- state_clear(CDIR_STATE_FREEZINGTREE);
+ assert(state_test(STATE_FREEZINGTREE));
+ state_clear(STATE_FREEZINGTREE);
// cancel freeze waiters
finish_waiting(CDIR_WAIT_FREEZEABLE, -1);
dout(10) << "freeze_dir " << *this << endl;
_freeze_dir(c);
} else {
- state_set(CDIR_STATE_FREEZINGDIR);
+ state_set(STATE_FREEZINGDIR);
dout(10) << "freeze_dir + wait " << *this << endl;
// need to wait for auth pins to expire
{
dout(10) << "_freeze_dir " << *this << endl;
- state_set(CDIR_STATE_FROZENDIR);
+ state_set(STATE_FROZENDIR);
if (is_auth() && !is_subtree_root())
inode->auth_pin(); // auth_pin for duration of freeze
} else {
// wait again!
dout(10) << "freeze_dir_finish still waiting " << *this << endl;
- state_set(CDIR_STATE_FREEZINGDIR);
+ state_set(STATE_FREEZINGDIR);
add_waiter(CDIR_WAIT_FREEZEABLE, new C_MDS_FreezeDir(this, c));
}
}
void CDir::unfreeze_dir()
{
dout(10) << "unfreeze_dir " << *this << endl;
- state_clear(CDIR_STATE_FROZENDIR);
+ state_clear(STATE_FROZENDIR);
// unpin (may => FREEZEABLE) FIXME: is this order good?
if (is_auth() && !is_subtree_root())
iter++;
}
- if (!(state_test(CDIR_STATE_COMPLETE)))
+ if (!(state_test(STATE_COMPLETE)))
dout(10) << ind << "..." << endl;
- if (state_test(CDIR_STATE_DIRTY))
+ if (state_test(STATE_DIRTY))
dout(10) << ind << "[dirty]" << endl;
}
#define CDIR_NONCE_EXPORT 1
-// state bits
-#define CDIR_STATE_AUTH (1<<0) // auth for this dir (hashing doesn't count)
-#define CDIR_STATE_PROXY (1<<1) // proxy auth
-#define CDIR_STATE_COMPLETE (1<<2) // the complete contents are in cache
-#define CDIR_STATE_DIRTY (1<<3) // has been modified since last commit
-#define CDIR_STATE_FROZENTREE (1<<4) // root of tree (bounded by exports)
-#define CDIR_STATE_FREEZINGTREE (1<<5) // in process of freezing
-//#define CDIR_STATE_FROZENTREELEAF (1<<6) // outer bound of frozen region (on import)
-#define CDIR_STATE_FROZENDIR (1<<7)
-#define CDIR_STATE_FREEZINGDIR (1<<8)
-
-#define CDIR_STATE_COMMITTING (1<<9) // mid-commit
-#define CDIR_STATE_FETCHING (1<<10) // currenting fetching
-
-#define CDIR_STATE_DELETED (1<<11)
-
-#define CDIR_STATE_IMPORT (1<<12) // flag set if this is an import.
-#define CDIR_STATE_EXPORT (1<<13)
-#define CDIR_STATE_IMPORTBOUND (1<<14)
-#define CDIR_STATE_EXPORTBOUND (1<<15)
-
-#define CDIR_STATE_HASHED (1<<16) // if hashed
-#define CDIR_STATE_HASHING (1<<17)
-#define CDIR_STATE_UNHASHING (1<<18)
-
-
-
-
-
-// these state bits are preserved by an import/export
-// ...except if the directory is hashed, in which case none of them are!
-#define CDIR_MASK_STATE_EXPORTED (CDIR_STATE_COMPLETE\
- |CDIR_STATE_DIRTY)
-#define CDIR_MASK_STATE_IMPORT_KEPT (CDIR_STATE_IMPORT\
- |CDIR_STATE_EXPORT\
- |CDIR_STATE_IMPORTBOUND\
- |CDIR_STATE_FROZENTREE\
- |CDIR_STATE_PROXY)
-
-#define CDIR_MASK_STATE_EXPORT_KEPT (CDIR_STATE_HASHED\
- |CDIR_STATE_FROZENTREE\
- |CDIR_STATE_FROZENDIR\
- |CDIR_STATE_EXPORT\
- |CDIR_STATE_PROXY)
-
-// common states
-#define CDIR_STATE_CLEAN 0
-#define CDIR_STATE_INITIAL 0
-
-// directory replication
-#define CDIR_REP_ALL 1
-#define CDIR_REP_NONE 0
-#define CDIR_REP_LIST 2
}
}
+ // -- state --
+ static const unsigned STATE_AUTH = (1<< 0); // auth for this dir (hashing doesn't count)
+ static const unsigned STATE_PROXY = (1<< 1); // proxy auth
+ static const unsigned STATE_COMPLETE = (1<< 2); // the complete contents are in cache
+ static const unsigned STATE_DIRTY = (1<< 3); // has been modified since last commit
+ static const unsigned STATE_FROZENTREE = (1<< 4); // root of tree (bounded by exports)
+ static const unsigned STATE_FREEZINGTREE = (1<< 5); // in process of freezing
+ static const unsigned STATE_FROZENDIR = (1<< 6);
+ static const unsigned STATE_FREEZINGDIR = (1<< 7);
+ static const unsigned STATE_COMMITTING = (1<< 8); // mid-commit
+ static const unsigned STATE_FETCHING = (1<< 9); // currenting fetching
+ static const unsigned STATE_DELETED = (1<<10);
+ static const unsigned STATE_IMPORT = (1<<11); // flag set if this is an import.
+ static const unsigned STATE_EXPORT = (1<<12);
+ static const unsigned STATE_IMPORTBOUND = (1<<13);
+ static const unsigned STATE_EXPORTBOUND = (1<<14);
+ static const unsigned STATE_HASHED = (1<<15); // if hashed
+ static const unsigned STATE_HASHING = (1<<16);
+ static const unsigned STATE_UNHASHING = (1<<17);
+
+ // common states
+ static const unsigned STATE_CLEAN = 0;
+ static const unsigned STATE_INITIAL = 0;
+
+ // these state bits are preserved by an import/export
+ // ...except if the directory is hashed, in which case none of them are!
+ static const unsigned MASK_STATE_EXPORTED =
+ STATE_COMPLETE|STATE_DIRTY;
+ static const unsigned MASK_STATE_IMPORT_KEPT =
+ STATE_IMPORT|STATE_EXPORT
+ |STATE_IMPORTBOUND|STATE_EXPORTBOUND
+ |STATE_FROZENTREE|STATE_PROXY;
+ static const unsigned MASK_STATE_EXPORT_KEPT =
+ STATE_HASHED
+ |STATE_IMPORTBOUND|STATE_EXPORTBOUND
+ |STATE_FROZENTREE
+ |STATE_FROZENDIR
+ |STATE_EXPORT
+ |STATE_PROXY;
+
+ // -- rep spec --
+ static const int REP_NONE = 0;
+ static const int REP_ALL = 1;
+ static const int REP_LIST = 2;
+
+
public:
// context
// cache control (defined for authority; hints for replicas)
int dir_rep;
- set<int> dir_rep_by; // if dir_rep == CDIR_REP_LIST
+ set<int> dir_rep_by; // if dir_rep == REP_LIST
// popularity
meta_load_t popularity[MDS_NPOP];
pair<int,int> authority();
pair<int,int> dentry_authority(const string& d);
pair<int,int> get_dir_auth() { return dir_auth; }
- //int get_dir_auth_pending() { return dir_auth->second; }
void set_dir_auth(pair<int,int> a, bool iamauth=false);
- void set_dir_auth(int a, bool iamauth=false) {
- set_dir_auth(pair<int,int>(a, dir_auth.second), iamauth);
+ void set_dir_auth(int a) {
+ set_dir_auth(pair<int,int>(a, CDIR_AUTH_UNKNOWN), false);
}
- void set_dir_auth_pending(int b) {
- set_dir_auth(pair<int,int>(dir_auth.first, b));
+ bool auth_is_ambiguous() {
+ return dir_auth.second != CDIR_AUTH_UNKNOWN;
}
-
+ bool is_fullauth() {
+ return is_auth() && !auth_is_ambiguous();
+ }
+ bool is_fullnonauth() {
+ return !is_auth() && !auth_is_ambiguous();
+ }
+
bool is_subtree_root();
-
// for giving to clients
// -- state --
- bool is_complete() { return state & CDIR_STATE_COMPLETE; }
- bool is_dirty() { return state_test(CDIR_STATE_DIRTY); }
+ bool is_complete() { return state & STATE_COMPLETE; }
+ bool is_dirty() { return state_test(STATE_DIRTY); }
- bool is_auth() { return state & CDIR_STATE_AUTH; }
- bool is_proxy() { return state & CDIR_STATE_PROXY; }
- bool is_import() { return state & CDIR_STATE_IMPORT; }
- bool is_export() { return state & CDIR_STATE_EXPORT; }
+ bool is_auth() { return state & STATE_AUTH; }
+ bool is_proxy() { return state & STATE_PROXY; }
+ bool is_import() { return state & STATE_IMPORT; }
+ bool is_export() { return state & STATE_EXPORT; }
- bool is_hashed() { return state & CDIR_STATE_HASHED; }
- bool is_hashing() { return state & CDIR_STATE_HASHING; }
- bool is_unhashing() { return state & CDIR_STATE_UNHASHING; }
+ bool is_hashed() { return state & STATE_HASHED; }
+ bool is_hashing() { return state & STATE_HASHING; }
+ bool is_unhashing() { return state & STATE_UNHASHING; }
bool is_rep() {
- if (dir_rep == CDIR_REP_NONE) return false;
+ if (dir_rep == REP_NONE) return false;
return true;
}
void _mark_dirty();
void mark_dirty(version_t pv);
void mark_clean();
- void mark_complete() { state_set(CDIR_STATE_COMPLETE); }
- bool is_clean() { return !state_test(CDIR_STATE_DIRTY); }
+ void mark_complete() { state_set(STATE_COMPLETE); }
+ bool is_clean() { return !state_test(STATE_DIRTY); }
bool can_auth_pin() { return !(is_frozen() || is_freezing()); }
int is_auth_pinned() { return auth_pins; }
int get_cum_auth_pins() { return auth_pins + nested_auth_pins; }
+ int get_auth_pins() { return auth_pins; }
+ int get_nested_auth_pins() { return nested_auth_pins; }
void auth_pin();
void auth_unpin();
void adjust_nested_auth_pins(int inc);
bool is_freezing() { return is_freezing_tree() || is_freezing_dir(); }
bool is_freezing_tree();
- bool is_freezing_tree_root() { return state & CDIR_STATE_FREEZINGTREE; }
- bool is_freezing_dir() { return state & CDIR_STATE_FREEZINGDIR; }
+ bool is_freezing_tree_root() { return state & STATE_FREEZINGTREE; }
+ bool is_freezing_dir() { return state & STATE_FREEZINGDIR; }
bool is_frozen() { return is_frozen_dir() || is_frozen_tree(); }
bool is_frozen_tree();
- bool is_frozen_tree_root() { return state & CDIR_STATE_FROZENTREE; }
- bool is_frozen_dir() { return state & CDIR_STATE_FROZENDIR; }
+ bool is_frozen_tree_root() { return state & STATE_FROZENTREE; }
+ bool is_frozen_dir() { return state & STATE_FROZENDIR; }
bool is_freezeable() {
// no nested auth pins.
return false;
// inode must not be frozen.
- if (inode->is_frozen())
+ if (!is_subtree_root() && inode->is_frozen())
return false;
return true;
if (auth_pins > 0)
return false;
- // inode must not be frozen.
- if (inode->is_frozen())
+ // if not subtree root, inode must not be frozen.
+ if (!is_subtree_root() && inode->is_frozen())
return false;
return true;
CDirDiscover(CDir *dir, int nonce) {
ino = dir->ino();
this->nonce = nonce;
- dir_auth = dir->dir_auth.first;
+ //dir_auth = dir->dir_auth.first;
dir_rep = dir->dir_rep;
rep_by = dir->dir_rep_by;
}
assert(!dir->is_auth());
dir->replica_nonce = nonce;
- dir->set_dir_auth( dir_auth );
+ //dir->set_dir_auth( dir_auth );
dir->dir_rep = dir_rep;
dir->dir_rep_by = rep_by;
}
dir->projected_version = dir->version = st.version; // this is bumped, below, if dirty
// twiddle state
- if (dir->state & CDIR_STATE_HASHED)
- dir->state_set( CDIR_STATE_AUTH ); // just inherit auth flag when hashed
+ if (dir->state & CDir::STATE_HASHED)
+ dir->state_set( CDir::STATE_AUTH ); // just inherit auth flag when hashed
else
- dir->state = (dir->state & CDIR_MASK_STATE_IMPORT_KEPT) | // remember import flag, etc.
- (st.state & CDIR_MASK_STATE_EXPORTED);
+ dir->state = (dir->state & CDir::MASK_STATE_IMPORT_KEPT) | // remember import flag, etc.
+ (st.state & CDir::MASK_STATE_EXPORTED);
dir->dir_rep = st.dir_rep;
dir->popularity[MDS_POP_JUSTME] += st.popularity_justme;
case LOCK_AC_REQXLOCK:
// send nak
- if (dir->state_test(CDIR_STATE_DELETED)) {
+ if (dir->state_test(CDir::STATE_DELETED)) {
dout(7) << "handle_lock_dn reqxlock on deleted dir " << *dir << ", nak" << endl;
} else {
dout(7) << "handle_lock_dn reqxlock on " << dname << " in " << *dir << " dne, nak" << endl;
// balance?
if (true &&
mds->get_nodeid() == 0 &&
+ g_conf.mds_bal_interval > 0 &&
(num_bal_times ||
(g_conf.mds_bal_max_until >= 0 &&
elapsed.sec() > g_conf.mds_bal_max_until)) &&
mds_load_t load = get_load();
mds_load[ mds->get_nodeid() ] = load;
- // import_map
+ // import_map -- how much do i import from whom
map<int, float> import_map;
-
- for (set<CDir*>::iterator it = mds->mdcache->imports.begin();
- it != mds->mdcache->imports.end();
+ set<CDir*> authsubs;
+ mds->mdcache->get_auth_subtrees(authsubs);
+ for (set<CDir*>::iterator it = authsubs.begin();
+ it != authsubs.end();
it++) {
CDir *im = *it;
- if (im->inode->is_root()) continue;
int from = im->inode->authority().first;
+ if (from == mds->get_nodeid()) continue;
import_map[from] += im->popularity[MDS_POP_CURDOM].meta_load();
}
mds_import_map[ mds->get_nodeid() ] = import_map;
-
+
dout(5) << "mds" << mds->get_nodeid() << " sending heartbeat " << beat_epoch << " " << load << endl;
for (map<int, float>::iterator it = import_map.begin();
void MDBalancer::export_empties()
{
dout(5) << "export_empties checking for empty imports" << endl;
-
- for (set<CDir*>::iterator it = mds->mdcache->imports.begin();
- it != mds->mdcache->imports.end();
+ dout(0) << "IMPLEMENT ME" << endl;
+ /*
+ for (set<CDir*>::iterator it = mds->mdcache->subtrees.begin();
+ it != mds->mdcache->subtrees.end();
it++) {
CDir *dir = *it;
if (!dir->inode->is_root() && dir->get_size() == 0)
mds->mdcache->migrator->export_empty_import(dir);
}
+ */
}
if (mds_load[whoami].mds_load() > 0) {
load_fac = mds_load[whoami].root.meta_load() / mds_load[whoami].mds_load();
dout(7) << " load_fac is " << load_fac
- << " <- " << mds_load[whoami].root.meta_load() << " / " << mds_load[whoami].mds_load()
+ << " <- " << mds_load[whoami].root.meta_load()
+ << " / " << mds_load[whoami].mds_load()
<< endl;
}
// make a sorted list of my imports
map<double,CDir*> import_pop_map;
multimap<int,CDir*> import_from_map;
- for (set<CDir*>::iterator it = mds->mdcache->imports.begin();
- it != mds->mdcache->imports.end();
+ set<CDir*> fullauthsubs;
+
+ mds->mdcache->get_fullauth_subtrees(fullauthsubs);
+ for (set<CDir*>::iterator it = fullauthsubs.begin();
+ it != fullauthsubs.end();
it++) {
- if ((*it)->is_hashed()) continue;
- double pop = (*it)->popularity[MDS_POP_CURDOM].meta_load();
+ CDir *im = *it;
+
+ double pop = im->popularity[MDS_POP_CURDOM].meta_load();
if (pop < g_conf.mds_bal_idle_threshold &&
- (*it)->inode != mds->mdcache->get_root()) {
- dout(-5) << " exporting idle import " << **it
- << " back to mds" << (*it)->inode->authority()
+ im->inode != mds->mdcache->get_root()) {
+ dout(-5) << " exporting idle import " << *im
+ << " back to mds" << im->inode->authority().first
<< endl;
- mds->mdcache->migrator->export_dir(*it, (*it)->inode->authority().first);
+ mds->mdcache->migrator->export_dir(im, im->inode->authority().first);
continue;
}
- import_pop_map[ pop ] = *it;
- int from = (*it)->inode->authority().first;
- dout(15) << " map: i imported " << **it << " from " << from << endl;
- import_from_map.insert(pair<int,CDir*>(from, *it));
+ import_pop_map[ pop ] = im;
+ int from = im->inode->authority().first;
+ dout(15) << " map: i imported " << *im << " from " << from << endl;
+ import_from_map.insert(pair<int,CDir*>(from, im));
}
}
// okay, search for fragments of my workload
- set<CDir*> candidates = mds->mdcache->imports;
+ set<CDir*> candidates;
+ mds->mdcache->get_fullauth_subtrees(candidates);
list<CDir*> exports;
if (!in->is_dir()) continue;
if (!in->dir) continue; // clearly not popular
- if (in->dir->is_export()) continue;
+ if (!in->dir->is_auth()) continue;
if (in->dir->is_hashed()) continue;
if (already_exporting.count(in->dir)) continue;
dout(1) << "replicating dir " << *dir << " pop " << dir_pop << " .. rdp " << rdp << " adj " << rd_adj << endl;
- dir->dir_rep = CDIR_REP_ALL;
+ dir->dir_rep = CDir::REP_ALL;
mds->mdcache->send_dir_updates(dir, true);
dir->popularity[MDS_POP_JUSTME].pop[META_POP_IRD].adjust(rd_adj);
// unreplicate
dout(1) << "unreplicating dir " << *dir << " pop " << dir_pop << endl;
- dir->dir_rep = CDIR_REP_NONE;
+ dir->dir_rep = CDir::REP_NONE;
mds->mdcache->send_dir_updates(dir);
}
}
in->popularity[MDS_POP_CURDOM].pop[type].hit();
}
- if (dir->is_import())
+ if (dir->is_subtree_root())
curdom = false; // end of auth domain, stop hitting auth counters.
dir = dir->inode->get_parent_dir();
}
{
meta_load_t curdom = dir->popularity[MDS_POP_CURDOM];
- bool in_domain = !dir->is_import();
+ bool in_domain = !dir->is_subtree_root();
while (true) {
CInode *in = dir->inode;
dir = in->get_parent_dir();
if (!dir) break;
- if (dir->is_import()) in_domain = false;
+ if (dir->is_subtree_root()) in_domain = false;
dir->popularity[MDS_POP_ANYDOM] -= curdom;
if (in_domain) dir->popularity[MDS_POP_CURDOM] -= curdom;
{
meta_load_t curdom = dir->popularity[MDS_POP_CURDOM];
- bool in_domain = !dir->is_import();
+ bool in_domain = !dir->is_subtree_root();
while (true) {
CInode *in = dir->inode;
dir = in->get_parent_dir();
if (!dir) break;
- if (dir->is_import()) in_domain = false;
+ if (dir->is_subtree_root()) in_domain = false;
dir->popularity[MDS_POP_ANYDOM] += curdom;
if (in_domain) dir->popularity[MDS_POP_CURDOM] += curdom;
void MDCache::log_import_map(Context *onsync)
{
- dout(10) << "log_import_map " << imports.size() << " imports, "
- << exports.size() << " exports" << endl;
+ dout(10) << "log_import_map " << num_subtrees() << " subtrees"
+ << num_subtrees_fullauth() << " fullauth"
+ << endl;
EImportMap *le = new EImportMap;
-
+
// include import/export inodes,
// and a spanning tree to tie it to the root of the fs
+ /*
for (set<CDir*>::iterator p = imports.begin();
p != imports.end();
p++) {
}
}
}
+ */
mds->mdlog->writing_import_map = true;
mds->mdlog->submit_entry(le);
{
dout(10) << "send_import_map to mds" << who << endl;
+ /*
MMDSImportMap *m = new MMDSImportMap;
// known
- for (set<CDir*>::iterator p = imports.begin();
- p != imports.end();
+ for (map<CDir*,set<CDir*> >::iterator p = subtrees.begin();
+ p != subtrees.end();
p++) {
- CDir *im = *p;
+ CDir *dir = p->first;
- if (migrator->is_importing(im->ino())) {
+ // only our subtrees
+ if (dir->authority().first != mds->get_nodeid())
+ continue;
+
+ if (migrator->is_importing(dir->ino())) {
// ambiguous (mid-import)
- m->add_ambiguous_import(im->ino(),
- migrator->get_import_bound_inos(im->ino()));
+ m->add_ambiguous_import(dir->ino(),
+ migrator->get_import_bound_inos(dir->ino()));
} else {
// not ambiguous.
- m->add_import(im->ino());
+ m->add_import(dir->ino());
- if (nested_exports.count(im)) {
- for (set<CDir*>::iterator q = nested_exports[im].begin();
- q != nested_exports[im].end();
+ // bounds too
+ if (nested_exports.count(dir)) {
+ for (set<CDir*>::iterator q = p->second.begin();
+ q != p->second.end();
++q) {
- CDir *ex = *q;
- m->add_import_export(im->ino(), ex->ino());
+ CDir *bound = *q;
+ m->add_import_export(dir->ino(), bound->ino());
}
}
}
// second
mds->send_message_mds(m, who, MDS_PORT_CACHE);
+
+ */
}
}
// adjust dir_auth, import maps
- import_subtree(dir, bounds);
+ adjust_subtree_auth(dir, mds->get_nodeid());
}
void MDCache::finish_ambiguous_export(inodeno_t dirino, set<inodeno_t>& bounds)
<< " bounds " << bounds
<< endl;
+ /*
// adjust dir_auth
CDir *im = get_auth_container(dir);
if (dir->get_inode()->authority().first == CDIR_AUTH_UNKNOWN) {
assert(imports.count(dir));
imports.erase(dir);
dir->set_dir_auth( CDIR_AUTH_PARENT );
- dir->state_clear(CDIR_STATE_IMPORT);
+ dir->state_clear(CDir::STATE_IMPORT);
dir->put(CDir::PIN_IMPORT);
} else {
// i'm now an export
exports.insert(dir);
nested_exports[im].insert(dir);
dir->set_dir_auth( CDIR_AUTH_UNKNOWN ); // not me
- dir->state_set(CDIR_STATE_EXPORT);
+ dir->state_set(CDir::STATE_EXPORT);
dir->get(CDir::PIN_EXPORT);
}
dout(10) << " root " << *dir << endl;
assert(bd->get_dir_auth().first != CDIR_AUTH_PARENT);
bd->set_dir_auth( CDIR_AUTH_PARENT ); // not me
- bd->state_clear(CDIR_STATE_EXPORT);
+ bd->state_clear(CDir::STATE_EXPORT);
bd->put(CDir::PIN_EXPORT);
dout(10) << " bound " << *bd << endl;
}
-
+ */
show_imports();
}
-/** import_subtree
- * adjust dir_auth.first.
- * adjust import/export/nested_export maps and pins.
+
+/*
+ * adjust the dir_auth of a subtree.
+ * merge with parent and/or child subtrees, if is it appropriate.
+ * merge can ONLY happen if both parent and child have unambiguous auth.
*/
-void MDCache::import_subtree(CDir *root, set<CDir*>& bounds)
+void MDCache::adjust_subtree_auth(CDir *dir, pair<int,int> auth)
{
- dout(7) << "import_subtree_start " << *root << endl;
+ dout(7) << "adjust_subtree_auth " << dir->get_dir_auth() << " -> " << auth
+ << " on " << *dir << endl;
- CDir *im = root; // the new subtree root (an import)
+ show_subtrees();
- // root
- if (root->inode->is_auth()) {
- // parent is already me. was export, adding back to existing import.
- im = get_auth_container(root);
- assert(im);
- nested_exports[im].erase(root);
- exports.erase(root);
- root->set_dir_auth(CDIR_AUTH_PARENT, true);
- root->state_clear(CDIR_STATE_EXPORT);
- root->put(CDir::PIN_EXPORT);
+ CDir *root;
+ if (dir->ino() == 1) {
+ root = dir; // bootstrap hack.
+ subtrees[root].clear();
} else {
- // parent isn't me. new import.
- imports.insert(root);
- root->set_dir_auth(mds->get_nodeid(), true);
- root->state_set(CDIR_STATE_IMPORT);
- root->get(CDir::PIN_IMPORT);
+ root = get_subtree_root(dir); // subtree root
}
+ assert(root);
+ assert(subtrees.count(root));
+ dout(7) << " current root is " << *root << endl;
- dout(10) << " root " << *root << endl;
- if (root != im)
- dout(10) << " under " << *im << endl;
-
- // i should have no pins in this region.
- assert(root->get_cum_auth_pins() == 0);
+ if (root == dir) {
+ // i am already a subtree.
+ dir->set_dir_auth(auth);
+ } else {
+ // i am a new subtree.
+ dout(10) << " new subtree at " << *dir << endl;
+ assert(subtrees.count(dir) == 0);
+ subtrees[dir].clear(); // create empty subtree bounds list for me.
- // bounds
- for (set<CDir*>::iterator it = bounds.begin();
- it != bounds.end();
- it++) {
- CDir *bd = *it;
-
- if (bd->is_import()) {
- // bound is still me. was an import.
- imports.erase(bd);
- bd->set_dir_auth(CDIR_AUTH_PARENT, true);
- bd->state_clear(CDIR_STATE_IMPORT);
- bd->put(CDir::PIN_IMPORT);
- // move nested exports under this bound to my subtree root.
- for (set<CDir*>::iterator q = nested_exports[bd].begin();
- q != nested_exports[bd].end();
- ++q)
- nested_exports[im].insert(*q);
- nested_exports.erase(bd);
- } else {
- // not me anymore. now an export.
- exports.insert(bd);
- nested_exports[im].insert(bd);
- assert(bd->get_dir_auth().first != CDIR_AUTH_PARENT);
- bd->state_set(CDIR_STATE_EXPORT);
- bd->get(CDir::PIN_EXPORT);
+ // set dir_auth
+ dir->set_dir_auth(auth);
+
+ // move items nested beneath me, under me.
+ set<CDir*>::iterator p = subtrees[root].begin();
+ while (p != subtrees[root].end()) {
+ set<CDir*>::iterator next = p;
+ next++;
+ if (get_subtree_root((*p)->get_parent_dir()) == dir) {
+ // move under me
+ dout(10) << " claiming child bound " << **p << endl;
+ subtrees[dir].insert(*p);
+ subtrees[root].erase(p);
+ }
+ p = next;
}
- dout(10) << " bound " << *bd << endl;
+ // i am a bound of the parent subtree.
+ subtrees[root].insert(dir);
+
+ // i am now the subtree root.
+ root = dir;
}
+
+ // adjust export pins
+ adjust_export_state(dir);
+ for (set<CDir*>::iterator p = subtrees[dir].begin();
+ p != subtrees[dir].end();
+ ++p)
+ adjust_export_state(*p);
+
+ show_subtrees();
}
-void MDCache::import_subtree_finish(CDir *root, set<CDir*>& bounds)
+
+/*
+ * any "export" point must be pinned in cache to ensure a proper
+ * chain of delegation. we do this by pinning when a dir is nonauth
+ * but the inode is auth.
+ *
+ * import points don't need to be pinned the same way simply because the
+ * exporter is pinned and thus always open.
+ */
+void MDCache::adjust_export_state(CDir *dir)
{
-
+ if (!dir->is_auth() && dir->inode->is_auth()) {
+ // export.
+ if (!dir->state_test(CDir::STATE_EXPORT)) {
+ dout(10) << "adjust_export_state pinning new export " << *dir << endl;
+ dir->state_set(CDir::STATE_EXPORT);
+ dir->get(CDir::PIN_EXPORT);
+ }
+ }
+ else {
+ // not export.
+ if (dir->state_test(CDir::STATE_EXPORT)) {
+ dout(10) << "adjust_export_state unpinning old export " << *dir << endl;
+ dir->state_clear(CDir::STATE_EXPORT);
+ dir->put(CDir::PIN_EXPORT);
+ }
+ }
}
-void MDCache::export_subtree(CDir *root, set<CDir*>& bounds, int dest)
+void MDCache::try_subtree_merge(CDir *dir)
{
- dout(7) << "export_subtree " << *root << endl;
-
- CDir *im = get_auth_container(root);
+ dout(7) << "try_subtree_merge " << *dir << endl;
- // root
- if (root->is_import()) {
- // was an import, hose it
- assert(im == root);
- assert(imports.count(root));
- imports.erase(root);
- root->set_dir_auth(CDIR_AUTH_PARENT);
- root->state_clear(CDIR_STATE_IMPORT);
- root->put(CDir::PIN_IMPORT);
- } else {
- // i'm now an export
- exports.insert(root);
- nested_exports[im].insert(root);
- root->set_dir_auth( dest ); // not me
- root->state_set(CDIR_STATE_EXPORT);
- root->get(CDir::PIN_EXPORT);
+ // try to merge bounds?
+ set<CDir*>::iterator p = subtrees[dir].begin();
+ while (p != subtrees[dir].end()) {
+ set<CDir*>::iterator next = p;
+ next++;
+ CDir *bound = *p;
+
+ if (bound->dir_auth == dir->dir_auth && // if auth matches,
+ dir->dir_auth.second == CDIR_AUTH_UNKNOWN && // auth is unambiguous,
+ !bound->state_test(CDir::STATE_EXPORTBOUND)) { // and not an exportbound,
+ // merge with child.
+ dout(10) << " merging with child bound " << *bound << endl;
+ bound->set_dir_auth(CDIR_AUTH_DEFAULT);
+
+ // move child's children under dir.
+ for (set<CDir*>::iterator q = subtrees[bound].begin();
+ q != subtrees[bound].end();
+ ++q)
+ subtrees[dir].insert(*q);
+
+ // bound is no longer a separate subtree.
+ subtrees[dir].erase(bound);
+ subtrees.erase(bound);
+ }
+
+ // next!
+ p = next;
}
- // fix dir_auth
- if (root->inode->authority().first == dest)
- root->set_dir_auth( CDIR_AUTH_PARENT );
- else
- root->set_dir_auth( dest );
+ // merge with parent?
+ CDir *parent = dir;
+ if (dir->ino() != 1)
+ parent = get_subtree_root(dir->get_parent_dir());
- dout(10) << " root " << *root << endl;
- if (root != im)
- dout(10) << " under " << *im << endl;
+ if (parent != dir && // we have a parent,
+ parent->dir_auth == dir->dir_auth && // auth matches,
+ dir->dir_auth.second == CDIR_AUTH_UNKNOWN && // auth is unambiguous,
+ !dir->state_test(CDir::STATE_EXPORTBOUND)) { // not an exportbound,
+ // merge with parent.
+ dout(10) << " merge with parent " << *parent << endl;
+ dir->set_dir_auth(CDIR_AUTH_DEFAULT);
- // bounds (there were exports, before)
- for (set<CDir*>::iterator p = bounds.begin();
- p != bounds.end();
- ++p) {
- CDir *bd = *p;
+ // move our bounds under the parent
+ for (set<CDir*>::iterator p = subtrees[dir].begin();
+ p != subtrees[dir].end();
+ ++p)
+ subtrees[parent].insert(*p);
- // hose export
- assert(exports.count(bd));
- exports.erase(bd);
- nested_exports[im].erase(bd);
+ // we are no longer a subtree or bound
+ subtrees.erase(dir);
+ subtrees[parent].erase(dir);
+ }
- bd->state_clear(CDIR_STATE_EXPORT);
- bd->put(CDir::PIN_EXPORT);
-
- // fix dir_auth
- assert(bd->get_dir_auth().first != CDIR_AUTH_PARENT);
- if (bd->get_dir_auth().first == dest)
- bd->set_dir_auth(CDIR_AUTH_PARENT);
- else
- bd->set_dir_auth(dest);
-
- dout(10) << " bound " << *bd << endl;
- }
+ show_subtrees();
}
-/*
- * adjust the dir_auth of a subtree.
- * merge with parent and/or child subtrees, if is it appropriate.
- */
-void MDCache::adjust_subtree_auth(CDir *dir, pair<int,int> auth)
+void MDCache::adjust_bounded_subtree_auth(CDir *dir, set<CDir*>& bounds, pair<int,int> auth)
{
- dout(7) << "adjust_subtree_auth " << dir->get_dir_auth() << " -> " << auth
- << " under " << *dir << endl;
+ dout(7) << "adjust_bounded_subtree_auth " << dir->get_dir_auth() << " -> " << auth
+ << " on " << *dir << endl;
- // note my current bounds.
- set<CDir*> bounds = subtree_bounds[dir];
+ show_subtrees();
- // join with parent?
- CDir *root = dir;
- if (dir->ino() != 1) // i'm the root, screw you
- root = get_subtree_root(dir->get_parent_dir());
-
- if (root != dir && root->get_dir_auth() == auth) {
- // join the subtrees.
- dir->set_dir_auth(CDIR_AUTH_DEFAULT);
- dout(10) << " merge with parent " << *root << endl;
+ CDir *root;
+ if (dir->ino() == 1) {
+ root = dir; // bootstrap hack.
+ subtrees[root].clear();
+ } else {
+ root = get_subtree_root(dir); // subtree root
+ }
+ assert(root);
+ assert(subtrees.count(root));
+ dout(7) << " current root is " << *root << endl;
- // move our bounds under new root
- subtree_bounds.erase(dir);
- for (set<CDir*>::iterator p = bounds.begin();
- p != bounds.end();
- ++p)
- subtree_bounds[root].insert(*p);
+ pair<int,int> oldauth = dir->authority();
- // dir is no longer a subtree
- subtree_bounds.erase(dir);
+ if (root == dir) {
+ // i am already a subtree.
+ dir->set_dir_auth(auth);
} else {
- // don't merge with parent, just update our auth.
+ // i am a new subtree.
+ dout(10) << " new subtree at " << *dir << endl;
+ assert(subtrees.count(dir) == 0);
+ subtrees[dir].clear(); // create empty subtree bounds list for me.
+
+ // set dir_auth
dir->set_dir_auth(auth);
- }
+
+ // move items nested beneath me, under me.
+ set<CDir*>::iterator p = subtrees[root].begin();
+ while (p != subtrees[root].end()) {
+ set<CDir*>::iterator next = p;
+ next++;
+ if (get_subtree_root((*p)->get_parent_dir()) == dir) {
+ // move under me
+ dout(10) << " claiming child bound " << **p << endl;
+ subtrees[dir].insert(*p);
+ subtrees[root].erase(p);
+ }
+ p = next;
+ }
+
+ // i am a bound of the parent subtree.
+ subtrees[root].insert(dir);
- // bounds
+ // i am now the subtree root.
+ root = dir;
+ }
+
+ // verify/adjust bounds.
+ // these may be new, but no deeper than any existing bounds.
for (set<CDir*>::iterator p = bounds.begin();
p != bounds.end();
++p) {
CDir *bound = *p;
-
- if (bound->dir_auth == auth) {
- // merge with child.
- dout(10) << " merging bound " << *bound << endl;
- bound->set_dir_auth(CDIR_AUTH_DEFAULT);
-
- // move child's children under root.
- for (set<CDir*>::iterator q = subtree_bounds[bound].begin();
- q != subtree_bounds[bound].end();
- ++q)
- subtree_bounds[root].insert(*q);
+ if (subtrees[dir].count(bound)) continue; // have it.
+ adjust_subtree_auth(bound, oldauth); // otherwise, adjust at bound.
+ }
- // bound is no longer a subtree.
- subtree_bounds[root].erase(bound);
- } else {
- // don't merge.
- dout(10) << " bound " << *bound << endl;
+ verify_subtree_bounds(dir, bounds);
+
+ show_subtrees();
+}
+
+
+CDir *MDCache::get_subtree_root(CDir *dir)
+{
+ // find the underlying dir that delegates (or is about to delegate) auth
+ while (true) {
+ if (dir->is_subtree_root())
+ return dir;
+ dir = dir->get_parent_dir();
+ if (!dir)
+ return 0; // none
+ }
+}
+
+void MDCache::get_subtree_bounds(CDir *dir, set<CDir*>& bounds)
+{
+ assert(subtrees.count(dir));
+ bounds = subtrees[dir];
+}
+
+void MDCache::get_wouldbe_subtree_bounds(CDir *dir, set<CDir*>& bounds)
+{
+ if (subtrees.count(dir)) {
+ // just copy them, dir is a subtree.
+ get_subtree_bounds(dir, bounds);
+ } else {
+ // find them
+ CDir *root = get_subtree_root(dir);
+ for (set<CDir*>::iterator p = subtrees[root].begin();
+ p != subtrees[root].end();
+ ++p) {
+ CDir *t = *p;
+ while (t != root) {
+ t = t->get_parent_dir();
+ assert(t);
+ if (t == dir) {
+ bounds.insert(*p);
+ continue;
+ }
+ }
}
}
}
+void MDCache::verify_subtree_bounds(CDir *dir, const set<CDir*>& bounds)
+{
+ // for debugging only.
+ assert(subtrees.count(dir));
+ if (bounds != subtrees[dir]) {
+ dout(0) << "verify_subtree_bounds failed" << endl;
+ set<CDir*> b = bounds;
+ for (set<CDir*>::iterator p = subtrees[dir].begin();
+ p != subtrees[dir].end();
+ ++p) {
+ if (bounds.count(*p)) {
+ b.erase(*p);
+ continue;
+ }
+ dout(0) << " missing bound " << **p << endl;
+ }
+ for (set<CDir*>::iterator p = b.begin();
+ p != b.end();
+ ++p)
+ dout(0) << " extra bound " << **p << endl;
+ }
+ assert(bounds == subtrees[dir]);
+}
+
+void MDCache::verify_subtree_bounds(CDir *dir, const list<inodeno_t>& bounds)
+{
+ // for debugging only.
+ assert(subtrees.count(dir));
+
+ // make sure that any bounds i do have are properly noted as such.
+ int failed = 0;
+ for (list<inodeno_t>::const_iterator p = bounds.begin();
+ p != bounds.end();
+ ++p) {
+ CInode *bdi = get_inode(*p);
+ if (!bdi) continue;
+ CDir *bd = bdi->dir;
+ if (!bd) continue;
+ if (subtrees[dir].count(bd) == 0) {
+ dout(0) << "verify_subtree_bounds failed: extra bound " << *bd << endl;
+ failed++;
+ }
+ }
+ assert(failed == 0);
+}
+
+
+void MDCache::get_fullauth_subtrees(set<CDir*>& s)
+{
+ for (map<CDir*,set<CDir*> >::iterator p = subtrees.begin();
+ p != subtrees.end();
+ ++p) {
+ CDir *root = p->first;
+ if (root->is_fullauth())
+ s.insert(root);
+ }
+}
+void MDCache::get_auth_subtrees(set<CDir*>& s)
+{
+ for (map<CDir*,set<CDir*> >::iterator p = subtrees.begin();
+ p != subtrees.end();
+ ++p) {
+ CDir *root = p->first;
+ if (root->is_auth())
+ s.insert(root);
+ }
+}
+
+
+// count.
+
+int MDCache::num_subtrees()
+{
+ return subtrees.size();
+}
+
+int MDCache::num_subtrees_fullauth()
+{
+ int n = 0;
+ for (map<CDir*,set<CDir*> >::iterator p = subtrees.begin();
+ p != subtrees.end();
+ ++p) {
+ CDir *root = p->first;
+ if (root->is_fullauth())
+ n++;
+ }
+ return n;
+}
+
+int MDCache::num_subtrees_fullnonauth()
+{
+ int n = 0;
+ for (map<CDir*,set<CDir*> >::iterator p = subtrees.begin();
+ p != subtrees.end();
+ ++p) {
+ CDir *root = p->first;
+ if (root->is_fullnonauth())
+ n++;
+ }
+ return n;
+}
+
+
+
+
+
+
+
/*
root->state_set(CInode::STATE_ROOT);
}
+/*
void MDCache::add_import(CDir *dir)
{
imports.insert(dir);
- dir->state_set(CDIR_STATE_IMPORT);
+ dir->state_set(CDir::STATE_IMPORT);
dir->get(CDir::PIN_IMPORT);
}
+*/
void MDCache::recalc_auth_bits()
if (in->dir) {
if (in->dir->authority().first == mds->get_nodeid())
- in->dir->state_set(CDIR_STATE_AUTH);
+ in->dir->state_set(CDir::STATE_AUTH);
else {
- in->dir->state_clear(CDIR_STATE_AUTH);
+ in->dir->state_clear(CDir::STATE_AUTH);
if (in->dir->is_dirty())
in->dir->mark_clean();
}
// adjust the dir state
CInode *diri = dir->get_inode();
- diri->dir->state_clear(CDIR_STATE_COMPLETE); // dir incomplete!
+ diri->dir->state_clear(CDir::STATE_COMPLETE); // dir incomplete!
// reexport?
if (diri->dir->is_import() && // import
// was this an auth delegation? (if so, slightly modified container)
inodeno_t dconino = conino;
if (in->dir->is_subtree_root()) {
- dout(12) << " for just this dir, the container is " << *in->dir << endl;
+ dout(12) << " this is a subtree, removing from map, container is " << *in->dir << endl;
dconino = in->ino();
+
+ // remove from subtree map
+ assert(subtrees.count(in->dir));
+ assert(subtrees[in->dir].empty());
+ subtrees.erase(in->dir);
}
for (int a=dirauth.first;
// adjust the dir state
CInode *diri = dir->get_inode();
- diri->dir->state_clear(CDIR_STATE_COMPLETE); // dir incomplete!
+ diri->dir->state_clear(CDir::STATE_COMPLETE); // dir incomplete!
}
}
dout(0) << "log len " << mds->mdlog->get_num_events() << endl;
- if (exports.size())
- dout(0) << "still have " << exports.size() << " exports" << endl;
-
if (mds->filer->is_active())
dout(0) << "filer still active" << endl;
}
}
// unhash dirs?
+ /*
if (!hashdirs.empty()) {
// unhash any of my dirs?
for (set<CDir*>::iterator it = hashdirs.begin();
dout(7) << "waiting for dirs to unhash" << endl;
return false;
}
+ */
// commit dirs?
if (g_conf.mds_commit_on_shutdown) {
// send all imports back to 0.
- if (mds->get_nodeid() != 0 && !did_shutdown_exports) {
+ if (mds->get_nodeid() != 0 &&
+ !migrator->is_exporting() &&
+ !migrator->is_importing()) {
// flush what i can from the cache first..
trim(0);
-
+
// export to root
- for (set<CDir*>::iterator it = imports.begin();
- it != imports.end();
- ) {
- CDir *im = *it;
- it++;
- if (im->inode->is_root()) continue;
- if (im->is_frozen() || im->is_freezing()) continue;
+ for (map<CDir*, set<CDir*> >::iterator it = subtrees.begin();
+ it != subtrees.end();
+ it++) {
+ CDir *dir = it->first;
+ if (dir->inode->is_root()) continue;
+ if (dir->is_frozen() || dir->is_freezing()) continue;
+ if (!dir->is_fullauth()) continue;
- dout(7) << "sending " << *im << " back to mds0" << endl;
- migrator->export_dir(im,0);
+ dout(7) << "sending " << *dir << " back to mds0" << endl;
+ migrator->export_dir(dir, 0);
}
did_shutdown_exports = true;
}
-
-
- // waiting for imports? (e.g. root?)
- if (exports.size()) {
- dout(7) << "still have " << exports.size() << " exports" << endl;
- //show_cache();
- return false;
- }
-
// close root?
if (lru.lru_get_size() == 0 &&
root &&
- root->dir) {
-
- if (root->dir->is_import()) {
- // un-import
- dout(7) << "removing root import" << endl;
- imports.erase(root->dir);
- root->dir->state_clear(CDIR_STATE_IMPORT);
- root->dir->put(CDir::PIN_IMPORT);
-
- if (root->is_pinned_by(CInode::PIN_DIRTY)) {
- dout(7) << "clearing root inode dirty flag" << endl;
- root->put(CInode::PIN_DIRTY);
- }
- }
-
- // ignore root inode/dir on other nodes, since it's empty anyway.
+ root->is_pinned_by(CInode::PIN_DIRTY)) {
+ dout(7) << "clearing root inode dirty flag" << endl;
+ root->put(CInode::PIN_DIRTY);
}
- // imports?
- if (!imports.empty() || migrator->is_exporting()) {
- dout(7) << "still have " << imports.size() << " imports, or still exporting" << endl;
+ // subtrees map not empty yet?
+ if (!subtrees.empty()) {
+ dout(7) << "still have " << num_subtrees() << " subtrees" << endl;
show_cache();
return false;
}
+ assert(subtrees.empty());
+ assert(!migrator->is_exporting());
+ assert(!migrator->is_importing());
// cap log?
if (g_conf.mds_log_flush_on_shutdown) {
- if (imports.empty() && exports.empty()) {
- // (only do this once!)
- if (!mds->mdlog->is_capped()) {
- dout(7) << "capping the log" << endl;
- mds->mdlog->cap();
- // note that this won't flush right away, so we'll make at least one more pass
- }
+ // (only do this once!)
+ if (!mds->mdlog->is_capped()) {
+ dout(7) << "capping the log" << endl;
+ mds->mdlog->cap();
+ // note that this won't flush right away, so we'll make at least one more pass
}
-
+
if (mds->mdlog->get_num_events()) {
dout(7) << "waiting for log to flush (including import_map, now) .. " << mds->mdlog->get_num_events()
<< " (" << mds->mdlog->get_non_importmap_events() << ")" << endl;
return false;
}
-
+
if (!did_shutdown_log_cap) {
// flush journal header
dout(7) << "writing header for (now-empty) journal" << endl;
// root directory too
assert(root->dir == NULL);
- root->set_dir( new CDir(root, this, true) );
- root->dir->set_dir_auth( 0 ); // me!
- root->dir->dir_rep = CDIR_REP_ALL; //NONE;
+ root->set_dir(new CDir(root, this, true));
+ adjust_subtree_auth(root->dir, 0);
+ root->dir->dir_rep = CDir::REP_ALL; //NONE;
- // root is sort of technically an import (from a vacuum)
- imports.insert( root->dir );
- root->dir->state_set(CDIR_STATE_IMPORT);
- root->dir->get(CDir::PIN_IMPORT);
+ show_imports();
if (c) {
c->finish(0);
// add it (_replica_)
cur->set_dir( new CDir(cur, this, false) );
m->get_dir(i).update_dir(cur->dir);
+
+ // is this a dir_auth delegation boundary?
+ if (m->get_source().num() != cur->authority().first)
+ adjust_subtree_auth(cur->dir, m->get_source().num());
+
dout(7) << "added " << *cur->dir << " nonce " << cur->dir->replica_nonce << endl;
// get waiters
if (dn->inode->dir) {
// mark dir clean too, since it now dne!
assert(dn->inode->dir->is_auth());
- dn->inode->dir->state_set(CDIR_STATE_DELETED);
+ dn->inode->dir->state_set(CDir::STATE_DELETED);
dn->inode->dir->remove_null_dentries();
dn->inode->dir->mark_clean();
}
// dir?
if (dn->inode) {
if (dn->inode->dir) {
- dn->inode->dir->state_set(CDIR_STATE_DELETED);
+ dn->inode->dir->state_set(CDir::STATE_DELETED);
dn->inode->dir->remove_null_dentries();
}
}
* and we are nested underneath an inode in that dir (that hashes to us).
* Thus do not assume result->is_auth()! It is_auth() || is_hashed().
*/
+
+/*
CDir *MDCache::get_auth_container(CDir *dir)
{
CDir *imp = dir; // might be *dir
return imp;
}
-CDir *MDCache::get_subtree_root(CDir *dir)
-{
- // find the underlying dir that delegates (or is about to delegate) auth
- while (true) {
- if (dir->is_subtree_root())
- return dir;
- dir = dir->get_parent_dir();
- if (!dir)
- return 0; // none
- }
-}
-
CDir *MDCache::get_export_container(CDir *dir)
{
CDir *ex = dir; // might be *dir
}
-
+*/
// ==============================================================
// debug crap
+void MDCache::show_subtrees()
+{
+ dout(10) << "show_subtrees:" << endl;
+
+ list<pair<CDir*,int> > q;
+ string indent;
+
+ if (root && root->dir)
+ q.push_back(pair<CDir*,int>(root->dir, 0));
+
+ set<CDir*> seen;
+
+ while (!q.empty()) {
+ CDir *dir = q.front().first;
+ int d = q.front().second;
+ q.pop_front();
+
+ // sanity check
+ if (seen.count(dir)) dout(0) << "aah, already seen " << *dir << endl;
+ assert(seen.count(dir) == 0);
+ seen.insert(dir);
+
+ // adjust indenter
+ while ((unsigned)d < indent.size())
+ indent.resize(d);
+
+ // pad
+ string pad = "__________________________________";
+ pad.resize(12-indent.size());
+
+ string auth;
+ if (dir->is_auth())
+ auth = "auth ";
+ else
+ auth = "rep ";
+
+ char s[10];
+ if (dir->get_dir_auth().second == CDIR_AUTH_UNKNOWN)
+ sprintf(s, "%2d ", dir->get_dir_auth().first);
+ else
+ sprintf(s, "%2d,%2d", dir->get_dir_auth().first, dir->get_dir_auth().second);
+
+ // print
+ dout(10) << indent << "|_" << pad << s << " " << auth << *dir << endl;
+
+ // nested items?
+ if (!subtrees[dir].empty()) {
+ // more at my level?
+ if (!q.empty() && q.front().second == d)
+ indent += "| ";
+ else
+ indent += " ";
+
+ for (set<CDir*>::iterator p = subtrees[dir].begin();
+ p != subtrees[dir].end();
+ ++p)
+ q.push_front(pair<CDir*,int>(*p, d+2));
+ }
+ }
+}
+
void MDCache::show_imports()
{
int db = 10;
+ dout(db) << "show_imports:" << endl;
+
+ for (map<CDir*,set<CDir*> >::iterator p = subtrees.begin();
+ p != subtrees.end();
+ ++p) {
+ CDir *root = p->first;
+
+ if (!root->is_auth()) continue;
+
+ dout(db) << " ___ " << *root << endl;
+
+ for (set<CDir*>::iterator q = p->second.begin();
+ q != p->second.end();
+ ++q) {
+ CDir *bound = *q;
+ dout(db) << " |__" << *bound << endl;
+ }
+ }
+
+ show_subtrees();
+ return;
+
+
+
+ /// old
+ /*
if (imports.empty() &&
hashdirs.empty()) {
dout(db) << "show_imports: no imports/exports/hashdirs" << endl;
dout(1) << "***** stray item in exports: " << **it << endl;
assert(ecopy.size() == 0);
}
+ */
}
// root
list<Context*> waiting_for_root;
+ /*
// imports, exports, and hashes.
set<CDir*> imports; // includes root (on mds0)
set<CDir*> exports;
set<CDir*> hashdirs;
map<CDir*,set<CDir*> > nested_exports; // exports nested under imports _or_ hashdirs
- // subtrees
- map<CDir*,set<CDir*> > subtree_bounds; // nested bounds on subtrees.
+ void import_subtree(CDir *root, set<CDir*>& bounds);
+ void export_subtree(CDir *root, set<CDir*>& bounds, int dest);
+ */
+
+ // -- subtrees --
+protected:
+ map<CDir*,set<CDir*> > subtrees; // nested bounds on subtrees.
// adjust subtree auth specification
// dir->dir_auth
// imports/exports/nested_exports
// join/split subtrees as appropriate
- void import_subtree(CDir *root, set<CDir*>& bounds);
- void import_subtree_finish(CDir *root, set<CDir*>& bounds);
- void export_subtree(CDir *root, set<CDir*>& bounds, int dest);
- void export_subtree_finish(CDir *root, set<CDir*>& bounds, int dest);
-
+public:
void adjust_subtree_auth(CDir *root, pair<int,int> auth);
+ void adjust_subtree_auth(CDir *root, int a, int b=CDIR_AUTH_UNKNOWN) {
+ adjust_subtree_auth(root, pair<int,int>(a,b)); }
+ void adjust_bounded_subtree_auth(CDir *dir, set<CDir*>& bounds, pair<int,int> auth);
+ void adjust_export_state(CDir *dir);
+ void try_subtree_merge(CDir *root);
+ CDir *get_subtree_root(CDir *dir);
+ void get_subtree_bounds(CDir *root, set<CDir*>& bounds);
+ void get_wouldbe_subtree_bounds(CDir *root, set<CDir*>& bounds);
+ void verify_subtree_bounds(CDir *root, const set<CDir*>& bounds);
+ void verify_subtree_bounds(CDir *root, const list<inodeno_t>& boundinos);
+
+ void get_auth_subtrees(set<CDir*>& s);
+ void get_fullauth_subtrees(set<CDir*>& s);
+
+ int num_subtrees();
+ int num_subtrees_fullauth();
+ int num_subtrees_fullnonauth();
+
+protected:
// delayed cache expire
map<CDir*, map<int, MCacheExpire*> > delayed_expire; // import|export dir -> expire msg
CInode *get_root() { return root; }
void set_root(CInode *r);
- int get_num_imports() { return imports.size(); }
- void add_import(CDir *dir);
- void remove_import(CDir *dir);
+ //int get_num_imports() { return imports.size(); }
+ //void add_import(CDir *dir);
+ //void remove_import(CDir *dir);
void recalc_auth_bits();
void log_import_map(Context *onsync=0);
public:
CDir *get_auth_container(CDir *in);
- CDir *get_subtree_root(CDir *dir);
CDir *get_export_container(CDir *dir);
void find_nested_exports(CDir *dir, set<CDir*>& s);
void find_nested_exports_under(CDir *import, CDir *dir, set<CDir*>& s);
void show_imports();
void show_cache();
+ void show_subtrees();
};
dout(1) << "MDS dispatch unknown message port" << m->get_dest_port() << endl;
assert(0);
}
+
+ // finish any triggered contexts
+ if (finished_queue.size()) {
+ dout(7) << "mds has " << finished_queue.size() << " queued contexts" << endl;
+ list<Context*> ls;
+ ls.splice(ls.begin(), finished_queue);
+ assert(finished_queue.empty());
+ finish_contexts(ls);
+ }
// HACK FOR NOW
// trim cache
mdcache->trim();
}
-
- // finish any triggered contexts
- if (finished_queue.size()) {
- dout(7) << "mds has " << finished_queue.size() << " queued contexts" << endl;
- list<Context*> ls;
- ls.splice(ls.begin(), finished_queue);
- assert(finished_queue.empty());
- finish_contexts(ls);
- }
// hack: thrash exports
for (int i=0; i<g_conf.mds_thrash_exports; i++) {
set<int> s;
mdsmap->get_mds_set(s, MDSMap::STATE_ACTIVE);
- if (s.size() == 1)
+ if (s.size() == 1 || mdcache->inode_map.size() < 10)
break; // need peers for this to work.
dout(7) << "mds thrashing exports pass " << (i+1) << "/" << g_conf.mds_thrash_exports << endl;
while (n--) p++;
CDir *dir = p->second->dir;
- if (dir && dir->is_auth()) {
- int dest;
- do {
- int k = rand() % s.size();
- set<int>::iterator p = s.begin();
- while (k--) p++;
- dest = *p;
- } while (dest != whoami);
- mdcache->migrator->export_dir(dir,dest);
- }
+ if (!dir) continue; // must be a dir.
+ if (!dir->get_parent_dir()) continue; // must be linked.
+ if (!dir->is_auth()) continue; // must be auth.
+
+ int dest;
+ do {
+ int k = rand() % s.size();
+ set<int>::iterator p = s.begin();
+ while (k--) p++;
+ dest = *p;
+ } while (dest == whoami);
+ mdcache->migrator->export_dir(dir,dest);
}
bool is_rejoin(int m) { return mds_state.count(m) && mds_state[m] == STATE_REJOIN; }
bool is_active(int m) { return mds_state.count(m) && mds_state[m] == STATE_ACTIVE; }
bool is_stopping(int m) { return mds_state.count(m) && mds_state[m] == STATE_STOPPING; }
+ bool is_active_or_stopping(int m) { return is_active(m) || is_stopping(m); }
bool is_stopped(int m) { return mds_state.count(m) && mds_state[m] == STATE_STOPPED; }
bool has_created(int m) { return mds_created.count(m); }
if (c) dir->add_waiter(CDIR_WAIT_COMPLETE, c);
// already fetching?
- if (dir->state_test(CDIR_STATE_FETCHING)) {
+ if (dir->state_test(CDir::STATE_FETCHING)) {
dout(7) << "already fetching " << *dir << "; waiting" << endl;
return;
}
// state
- dir->state_set(CDIR_STATE_FETCHING);
+ dir->state_set(CDir::STATE_FETCHING);
// stats
if (mds->logger) mds->logger->inc("fdir");
assert(dir);
// dir is now complete
- dir->state_set(CDIR_STATE_COMPLETE);
- dir->state_clear(CDIR_STATE_FETCHING);
+ dir->state_set(CDir::STATE_COMPLETE);
+ dir->state_clear(CDir::STATE_FETCHING);
// finish
list<Context*> finished;
dir->is_hashed());
// already committing?
- if (dir->state_test(CDIR_STATE_COMMITTING)) {
+ if (dir->state_test(CDir::STATE_COMMITTING)) {
// already mid-commit!
dout(7) << "commit_dir " << *dir << " mid-commit of " << dir->get_committing_version() << endl;
dout(7) << " current version = " << dir->get_version() << endl;
Context *fin = new C_MDS_CommitDirFinish(this, dir);
// state
- dir->state_set(CDIR_STATE_COMMITTING);
+ dir->state_set(CDir::STATE_COMMITTING);
dir->set_committing_version();
// stats
if (committed_version == dir->get_version())
dir->mark_clean();
- dir->state_clear(CDIR_STATE_COMMITTING);
+ dir->state_clear(CDir::STATE_COMMITTING);
// finish
dir->finish_waiting(CDIR_WAIT_COMMITTED);
export_finish_waiters.erase(dir);
// send pending import_maps? (these need to go out when all exports have finished.)
- mds->mdcache->send_pending_import_maps();
+ cache->send_pending_import_maps();
- mds->mdcache->show_imports();
- mds->mdcache->show_cache();
+ cache->show_imports();
+ cache->show_cache();
} else {
// third party failed. potential peripheral damage?
if (p->second == EXPORT_WARNING) {
case IMPORT_PREPPED:
dout(10) << "state prepping : unpinning base+bounds, unfreezing, " << *dir << endl;
assert(dir);
- dir->set_dir_auth_pending(CDIR_AUTH_UNKNOWN); // not anymore.
// unfreeze
dir->unfreeze_tree();
+ // adjust auth
+ cache->adjust_subtree_auth(dir, mds->get_nodeid());
+ cache->try_subtree_merge(dir);
+
// fall-thru to unpin base+bounds
case IMPORT_PREPPING:
it != import_bounds[dir].end();
it++) {
CDir *bd = *it;
- assert(bd->state_test(CDIR_STATE_IMPORTBOUND));
- bd->state_clear(CDIR_STATE_IMPORTBOUND);
+ assert(bd->state_test(CDir::STATE_IMPORTBOUND));
+ bd->state_clear(CDir::STATE_IMPORTBOUND);
bd->put(CDir::PIN_IMPORTBOUND);
}
break;
import_bound_inos.erase(dirino);
import_bounds.erase(dir);
- mds->mdcache->show_imports();
- mds->mdcache->show_cache();
+ cache->show_imports();
+ cache->show_cache();
}
// next!
int dest)
{
dout(7) << "export_dir " << *dir << " to " << dest << endl;
+ assert(dir->is_auth());
assert(dest != mds->get_nodeid());
assert(!dir->is_hashed());
if (dir->inode->is_root()) {
dout(7) << "i won't export root" << endl;
- assert(0);
+ //assert(0);
return;
}
delete m; // done
}
+/*
class C_MDC_ExportStartLogged : public Context {
Migrator *mig;
CDir *ex; // dir i'm exporting
C_MDC_ExportStartLogged(Migrator *m, CDir *e, int d, MExportDirPrep *p) :
mig(m), ex(e), dest(d), prep(p) {}
virtual void finish(int r) {
- mig->export_dir_frozen_logged(ex, prep, dest);
+ mig->export_dir_start_logged(ex, prep, dest);
}
};
+*/
void Migrator::export_dir_frozen(CDir *dir,
- int dest)
+ int dest)
{
// subtree is now frozen!
dout(7) << "export_dir_frozen on " << *dir << " to " << dest << endl;
export_state[dir] = EXPORT_LOGGINGSTART;
- show_imports();
+ cache->show_imports();
- // -- note/mark subtree bounds --
- // also include traces to all nested exports.
- cache->find_nested_exports(dir, export_bounds[dir]);
+ // note the bounds.
+ // force it into a subtree by listing auth as <me,me>.
+ cache->adjust_subtree_auth(dir, mds->get_nodeid(), mds->get_nodeid());
+ cache->get_subtree_bounds(dir, export_bounds[dir]);
set<CDir*> &bounds = export_bounds[dir];
-
- // note that dest an ambiguous auth for this subtree.
- dir->set_dir_auth_pending(export_peer[dir]);
-
+
// generate prep message, log entry.
EExportStart *le = new EExportStart(dir, dest);
MExportDirPrep *prep = new MExportDirPrep(dir->inode);
for (set<CDir*>::iterator it = bounds.begin();
it != bounds.end();
it++) {
- CDir *exp = *it;
+ CDir *bound = *it;
// pin it.
- exp->get(CDir::PIN_EXPORTBOUND);
+ bound->get(CDir::PIN_EXPORTBOUND);
+ bound->state_set(CDir::STATE_EXPORTBOUND);
- dout(7) << " including nested export " << *exp << " in prep" << endl;
+ dout(7) << " export bound " << *bound << endl;
- prep->add_export( exp->ino() );
- le->get_bounds().insert(exp->ino());
- le->metablob.add_dir_context( exp );
- le->metablob.add_dir( exp, false );
+ prep->add_export( bound->ino() );
+ le->get_bounds().insert(bound->ino());
+ le->metablob.add_dir_context( bound );
+ le->metablob.add_dir( bound, false );
/* first assemble each trace, in trace order, and put in message */
list<CInode*> inode_trace;
// trace to dir
- CDir *cur = exp;
+ CDir *cur = bound;
while (cur != dir) {
// don't repeat ourselves
if (inodes_added.count(cur->ino())) break; // did already!
// log our intentions
dout(7) << " logging EExportStart" << endl;
- mds->mdlog->submit_entry(le, new C_MDC_ExportStartLogged(this, dir, dest, prep));
+ mds->mdlog->submit_entry(le);
+ // don't wait for it to flush, it doesn't matter.
+ // FIXME: just combine Start into Finish, we only need 1 log entry.
+ //, new C_MDC_ExportStartLogged(this, dir, dest, prep));
+
+ /*
+
}
-void Migrator::export_dir_frozen_logged(CDir *dir, MExportDirPrep *prep, int dest)
+void Migrator::export_dir_start_logged(CDir *dir, MExportDirPrep *prep, int dest)
{
- dout(7) << "export_dir_frozen_logged " << *dir << endl;
+ dout(7) << "export_dir_start_logged " << *dir << endl;
if (export_state.count(dir) == 0 ||
export_state[dir] != EXPORT_LOGGINGSTART) {
dir->unfreeze_tree(); // cancel the freeze
return;
}
+ */
export_state[dir] = EXPORT_PREPPING;
mds->send_message_mds(prep, dest, MDS_PORT_MIGRATOR);
CDir *dir = in->dir;
assert(dir);
- dout(7) << "export_dir_prep_ack " << *dir << ", sending notifies" << endl;
+ dout(7) << "export_dir_prep_ack " << *dir << endl;
if (export_state.count(dir) == 0 ||
export_state[dir] != EXPORT_PREPPING) {
p != dir->replicas_end();
++p) {
if (p->first == dest) continue;
- if (!mds->mdsmap->is_active(p->first) ||
- !mds->mdsmap->is_stopping(p->first))
+ if (!mds->mdsmap->is_active_or_stopping(p->first))
continue; // only if active
export_warning_ack_waiting[dir].insert(p->first);
export_notify_ack_waiting[dir].insert(p->first); // we'll eventually get a notifyack, too!
- mds->send_message_mds(new MExportDirWarning(dir->ino(), export_peer[dir]),
- p->first, MDS_PORT_MIGRATOR);
+
+ //mds->send_message_mds(new MExportDirWarning(dir->ino(), export_peer[dir]),
+ //p->first, MDS_PORT_MIGRATOR);
+ MExportDirNotify *notify = new MExportDirNotify(dir->ino(),
+ mds->get_nodeid(), export_peer[dir]);
+ notify->copy_exports(export_bounds[dir]);
+ mds->send_message_mds(notify, p->first, MDS_PORT_MIGRATOR);
+
}
export_state[dir] = EXPORT_WARNING;
int dest = export_peer[dir];
dout(7) << "export_dir_go " << *dir << " to " << dest << endl;
- show_imports();
+ cache->show_imports();
export_warning_ack_waiting.erase(dir);
export_state[dir] = EXPORT_EXPORTING;
assert(dir->get_cum_auth_pins() == 0);
- // update imports/exports
- cache->export_subtree(dir, export_bounds[dir], dest);
-
+ // set ambiguous auth
+ cache->adjust_subtree_auth(dir, dest, mds->get_nodeid());
+ cache->verify_subtree_bounds(dir, export_bounds[dir]);
+
// fill export message with cache data
C_Contexts *fin = new C_Contexts; // collect all the waiters
int num_exported_inodes = encode_export_dir( export_data[dir],
- fin,
- dir, // base
- dir, // recur start point
- dest );
+ fin,
+ dir, // base
+ dir, // recur start point
+ dest );
// send the export data!
MExportDir *req = new MExportDir(dir->ino());
// queue up the finisher
dir->add_waiter( CDIR_WAIT_UNFREEZE, fin );
-
// stats
if (mds->logger) mds->logger->inc("ex");
if (mds->logger) mds->logger->inc("iex", num_exported_inodes);
- show_imports();
+ cache->show_imports();
}
/** encode_export_inode
* update our local state for this inode to export.
* encode relevant state to be sent over the wire.
- * used by: export_dir_walk, file_rename (if foreign)
+ * used by: encode_export_dir, file_rename (if foreign)
*/
void Migrator::encode_export_inode(CInode *in, bufferlist& enc_state, int new_auth)
{
{
int num_exported = 0;
- dout(7) << "export_dir_walk " << *dir << " " << dir->nitems << " items" << endl;
+ dout(7) << "encode_export_dir " << *dir << " " << dir->nitems << " items" << endl;
assert(dir->get_projected_version() == dir->get_version());
// mark
assert(dir->is_auth());
- dir->state_clear(CDIR_STATE_AUTH);
+ dir->state_clear(CDir::STATE_AUTH);
dir->replica_nonce = CDIR_NONCE_EXPORT;
// proxy
- //dir->state_set(CDIR_STATE_PROXY);
+ //dir->state_set(CDir::STATE_PROXY);
//dir->get(CDir::PIN_PROXY);
//export_proxy_dirinos[basedir].push_back(dir->ino());
if (dir->is_hashed()) {
// fix state
- dir->state_clear( CDIR_STATE_AUTH );
+ dir->state_clear( CDir::STATE_AUTH );
} else {
dir->mark_clean();
// discard most dir state
- dir->state &= CDIR_MASK_STATE_EXPORT_KEPT; // i only retain a few things.
+ dir->state &= CDir::MASK_STATE_EXPORT_KEPT; // i only retain a few things.
// suck up all waiters
list<Context*> waiting;
num_exported++;
// -- dentry
- dout(7) << "export_dir_walk exporting " << *dn << endl;
+ dout(7) << "encode_export_dir exporting " << *dn << endl;
// name
_encode(it->first, enc_dir);
encode_export_inode(in, enc_dir, newauth); // encode, and (update state for) export
// directory?
- if (in->is_dir() && in->dir) {
- if (in->dir->is_auth()) {
- // nested subdir
- assert(in->dir->get_dir_auth().first == CDIR_AUTH_PARENT);
- subdirs.push_back(in->dir); // it's ours, recurse (later)
- }
+ if (in->is_dir() &&
+ in->dir &&
+ !in->dir->state_test(CDir::STATE_EXPORTBOUND)) {
+ // include nested subdir
+ assert(in->dir->get_dir_auth().first == CDIR_AUTH_PARENT);
+ subdirs.push_back(in->dir); // it's ours, recurse (later)
}
// add to proxy
export_state[dir] = EXPORT_LOGGINGFINISH;
export_data.erase(dir);
- export_bounds.erase(dir);
// log export completion, then finish (unfreeze, trigger finish context, etc.)
dir->get(CDir::PIN_LOGGINGEXPORTFINISH);
assert(export_bounds.count(dir));
assert(export_data.count(dir));
- // adjust dir_auth, exports
- cache->import_subtree(dir, export_bounds[dir]);
+ // adjust auth, with possible subtree merge.
+ cache->verify_subtree_bounds(dir, export_bounds[dir]);
+ cache->adjust_subtree_auth(dir, mds->get_nodeid());
+ cache->try_subtree_merge(dir);
// unpin bounds
for (set<CDir*>::iterator p = export_bounds[dir].begin();
++p) {
CDir *bd = *p;
bd->put(CDir::PIN_EXPORTBOUND);
+ bd->state_clear(CDir::STATE_EXPORTBOUND);
}
// re-import the metadata
p != export_notify_ack_waiting[dir].end();
++p) {
MExportDirNotify *notify = new MExportDirNotify(dir->ino(),
- mds->get_nodeid(), mds->get_nodeid());
+ mds->get_nodeid(), CDIR_AUTH_UNKNOWN);
notify->copy_exports(export_bounds[dir]);
mds->send_message_mds(notify, *p, MDS_PORT_MIGRATOR);
}
*/
void Migrator::export_dir_logged_finish(CDir *dir)
{
- dout(7) << "export_dir_commit " << *dir << endl;
+ dout(7) << "export_dir_logged_finish " << *dir << endl;
dir->put(CDir::PIN_LOGGINGEXPORTFINISH);
if (export_state.count(dir) == 0||
return;
}
+ cache->verify_subtree_bounds(dir, export_bounds[dir]);
+
// send notifies
int dest = export_peer[dir];
p != export_notify_ack_waiting[dir].end();
++p) {
MExportDirNotify *notify = new MExportDirNotify(dir->ino(),
- mds->get_nodeid(), dest);
+ dest, CDIR_AUTH_UNKNOWN);
notify->copy_exports(export_bounds[dir]);
mds->send_message_mds(notify, *p, MDS_PORT_MIGRATOR);
}
/*
- * i'll get an ack from each bystander.
- * when i get them all, unfreeze and send the finish.
+ * warning:
+ * i'll get an ack from each bystander.
+ * when i get them all, do the export.
+ * notify:
+ * i'll get an ack from each bystander.
+ * when i get them all, unfreeze and send the finish.
*/
void Migrator::handle_export_dir_notify_ack(MExportDirNotifyAck *m)
{
// aborted?
if (!dir ||
export_state.count(dir) == 0 ||
- export_state[dir] != EXPORT_NOTIFYING) {
- dout(7) << "target must have failed, not sending finish message. export succeeded anyway." << endl;
-
+ (export_state[dir] != EXPORT_NOTIFYING &&
+ export_state[dir] != EXPORT_WARNING)) {
+ dout(7) << "target must have failed, ignoring." << endl;
delete m;
return;
}
- // process.
int from = m->get_source().num();
- assert(export_notify_ack_waiting.count(dir));
- export_notify_ack_waiting[dir].erase(from);
-
- if (export_notify_ack_waiting[dir].empty())
- export_dir_finish(dir);
+
+ if (export_state[dir] == EXPORT_WARNING) {
+ // process warning.
+ assert(export_warning_ack_waiting.count(dir));
+ export_warning_ack_waiting[dir].erase(from);
+
+ if (export_warning_ack_waiting[dir].empty())
+ export_dir_go(dir); // start export.
+ } else {
+ // process notify.
+ assert(export_notify_ack_waiting.count(dir));
+ export_notify_ack_waiting[dir].erase(from);
+
+ if (export_notify_ack_waiting[dir].empty())
+ export_dir_finish(dir);
+ }
delete m;
}
{
dout(7) << "export_dir_finish " << *dir << endl;
- export_notify_ack_waiting.erase(dir);
-
- if (export_state.count(dir)) {
- // send finish/commit to new auth
- mds->send_message_mds(new MExportDirFinish(dir->ino()), export_peer[dir], MDS_PORT_MIGRATOR);
-
- // remove from exporting list
- export_state.erase(dir);
- export_peer.erase(dir);
- } else {
+ if (export_state.count(dir) == 0) {
dout(7) << "target must have failed, not sending final commit message. export succeeded anyway." << endl;
+ return;
}
-
+
+ // send finish/commit to new auth
+ mds->send_message_mds(new MExportDirFinish(dir->ino()), export_peer[dir], MDS_PORT_MIGRATOR);
+
// unfreeze
dout(7) << "export_dir_finish unfreezing" << endl;
dir->unfreeze_tree();
++p) {
CDir *bd = *p;
bd->put(CDir::PIN_EXPORTBOUND);
+ bd->state_clear(CDir::STATE_EXPORTBOUND);
}
+ // adjust auth, with possible subtree merge.
+ // (we do this _after_ removing EXPORTBOUND pins, to allow merges)
+ cache->adjust_subtree_auth(dir, export_peer[dir]);
+ cache->try_subtree_merge(dir);
+
// unpin path
dout(7) << "export_dir_finish unpinning path" << endl;
vector<CDentry*> trace;
// discard delayed expires
cache->discard_delayed_expire(dir);
+ // remove from exporting list, clean up state
+ export_state.erase(dir);
+ export_peer.erase(dir);
+ export_bounds.erase(dir);
+ export_notify_ack_waiting.erase(dir);
+
// queue finishers
mds->queue_finished(export_finish_waiters[dir]);
export_finish_waiters.erase(dir);
// stats
- if (mds->logger) mds->logger->set("nex", cache->exports.size());
+ //if (mds->logger) mds->logger->set("nex", cache->exports.size());
- show_imports();
+ cache->show_imports();
// send pending import_maps?
mds->mdcache->send_pending_import_maps();
}
-/*
-void Migrator::clear_export_proxy_pins(CDir *dir)
-{
- dout(10) << "clear_export_proxy_pins " << *dir << endl;
-
- // inodes
- for (list<inodeno_t>::iterator it = export_proxy_inos[dir].begin();
- it != export_proxy_inos[dir].end();
- it++) {
- CInode *in = cache->get_inode(*it);
- dout(15) << " " << *in << endl;
- in->put(CInode::PIN_PROXY);
- assert(in->state_test(CInode::STATE_PROXY));
- in->state_clear(CInode::STATE_PROXY);
- }
- export_proxy_inos.erase(dir);
-
- // dirs
- for (list<inodeno_t>::iterator it = export_proxy_dirinos[dir].begin();
- it != export_proxy_dirinos[dir].end();
- it++) {
- CDir *dir = cache->get_inode(*it)->dir;
- dout(15) << " " << *dir << endl;
- dir->put(CDir::PIN_PROXY);
- assert(dir->state_test(CDIR_STATE_PROXY));
- dir->state_clear(CDIR_STATE_PROXY);
-
- // hose neg dentries, too, since we're no longer auth
- CDir_map_t::iterator it;
- for (it = dir->begin(); it != dir->end(); ) {
- CDentry *dn = it->second;
- it++;
- if (dn->is_null()) {
- assert(dn->is_sync());
- dir->remove_dentry(dn);
- } else {
- //dout(10) << "export_dir_notify_ack leaving xlocked neg " << *dn << endl;
- if (dn->is_dirty())
- dn->mark_clean();
- }
- }
- }
- export_proxy_dirinos.erase(dir);
-}
-*/
import_state[in->ino()] = IMPORT_DISCOVERED;
import_peer[in->ino()] = m->get_source().num();
-
// reply
dout(7) << " sending export_dir_discover_ack on " << *in << endl;
mds->send_message_mds(new MExportDirDiscoverAck(in->ino()),
void Migrator::handle_export_dir_prep(MExportDirPrep *m)
{
- assert(m->get_source().num() != mds->get_nodeid());
-
CInode *diri = cache->get_inode(m->get_ino());
assert(diri);
+ int oldauth = m->get_source().num();
+ assert(oldauth != mds->get_nodeid());
+
list<Context*> finished;
// assimilate root dir.
}
assert(dir->is_auth() == false);
- show_imports();
+ cache->show_imports();
// assimilate contents?
if (!m->did_assim()) {
CInode *in = cache->get_inode(ino);
assert(in);
if (in->dir) {
- if (!in->dir->state_test(CDIR_STATE_IMPORTBOUND)) {
+ if (!in->dir->state_test(CDir::STATE_IMPORTBOUND)) {
dout(7) << " pinning import bound " << *in->dir << endl;
in->dir->get(CDir::PIN_IMPORTBOUND);
- in->dir->state_set(CDIR_STATE_IMPORTBOUND);
+ in->dir->state_set(CDir::STATE_IMPORTBOUND);
import_bounds[dir].insert(in->dir);
} else {
dout(7) << " already pinned import bound " << *in << endl;
if (waiting_for) {
dout(7) << " waiting for " << waiting_for << " nested export dir opens" << endl;
} else {
- // freeze import region
- // (note: this is a manual freeze.. hack hack hack!)
- dout(7) << " all ready, freezing import region" << endl;
-
- // then, note that i am an ambiguous auth for this subtree.
- dir->set_dir_auth_pending(mds->get_nodeid());
+ dout(7) << " all ready, noting auth and freezing import region" << endl;
- // mark import point frozen
+ // note that i am an ambiguous auth for this subtree.
+ // specify bounds, since the exporter explicitly defines the region.
+ cache->adjust_bounded_subtree_auth(dir, import_bounds[dir],
+ pair<int,int>(oldauth, mds->get_nodeid()));
+ cache->verify_subtree_bounds(dir, import_bounds[dir]);
+
+ // freeze.
dir->_freeze_tree();
// ok!
dout(7) << "handle_export_dir importing " << *dir << " from " << oldauth << endl;
assert(dir->is_auth() == false);
- show_imports();
+ cache->show_imports();
// start the journal entry
EImportStart *le = new EImportStart(dir->ino(), m->get_exports());
le->metablob.add_dir_context(dir);
- // update dir_auth, import maps
- cache->import_subtree(dir, import_bounds[dir]);
+ // adjust auth (list us _first_)
+ cache->adjust_subtree_auth(dir, mds->get_nodeid(), oldauth);
+ cache->verify_subtree_bounds(dir, import_bounds[dir]);
// take out my importing pin
dir->put(CDir::PIN_IMPORTING);
// remove bound pin
bd->put(CDir::PIN_IMPORTBOUND);
- bd->state_clear(CDIR_STATE_IMPORTBOUND);
+ bd->state_clear(CDir::STATE_IMPORTBOUND);
// include bounding dirs in EImportStart
// (now that the interior metadata is already in the event)
if (mds->logger) {
mds->logger->inc("im");
mds->logger->inc("iim", num_imported_inodes);
- mds->logger->set("nim", cache->imports.size());
+ //mds->logger->set("nim", cache->imports.size());
}
delete m;
assert(0); // implement me.
- // update dir_auth, import maps
- cache->export_subtree(dir, import_bounds[dir], import_peer[dir->ino()]);
+ // update auth, with possible subtree merge.
+ cache->adjust_subtree_auth(dir, import_peer[dir->ino()]);
+ cache->try_subtree_merge(dir);
// remove bound pins
for (set<CDir*>::iterator it = import_bounds[dir].begin();
it++) {
CDir *bd = *it;
bd->put(CDir::PIN_IMPORTBOUND);
- bd->state_clear(CDIR_STATE_IMPORTBOUND);
+ bd->state_clear(CDir::STATE_IMPORTBOUND);
}
// ...
mds->send_message_mds(new MExportDirAck(dir->inode->ino()),
from, MDS_PORT_MIGRATOR);
- show_imports();
+ cache->show_imports();
}
{
dout(7) << "import_dir_logged_finish " << *dir << endl;
- // unfreeze!
+ // unfreeze
dir->unfreeze_tree();
+
+ // adjust auth, with possible subtree merge.
+ cache->verify_subtree_bounds(dir, import_bounds[dir]);
+ cache->adjust_subtree_auth(dir, mds->get_nodeid());
+ cache->try_subtree_merge(dir);
// clear import state (we're done!)
import_state.erase(dir->ino());
// log it
if (mds->logger) {
- mds->logger->set("nex", cache->exports.size());
- mds->logger->set("nim", cache->imports.size());
+ //mds->logger->set("nex", cache->exports.size());
+ //mds->logger->set("nim", cache->imports.size());
}
- show_imports();
+ cache->show_imports();
// is it empty?
if (dir->get_size() == 0 &&
// mark (may already be marked from get_or_open_dir() above)
if (!dir->is_auth())
- dir->state_set(CDIR_STATE_AUTH);
+ dir->state_set(CDir::STATE_AUTH);
// adjust replica list
//assert(!dir->is_replica(oldauth)); // not true on failed export
CDir *dir = 0;
if (diri) dir = diri->dir;
+ int oldauth = m->get_source().num();
+ int newauth = m->get_new_dir_auth();
if (dir) {
- dout(7) << "handle_export_dir_warning " << m->get_source()
- << " -> mds" << m->get_new_dir_auth()
+ dout(7) << "handle_export_dir_warning mds" << oldauth
+ << " -> mds" << newauth
<< " on " << *dir << endl;
- dir->set_dir_auth_pending(m->get_new_dir_auth());
+ cache->adjust_subtree_auth(dir, oldauth, newauth);
+ // verify?
} else {
dout(7) << "handle_export_dir_warning on dir " << m->get_ino() << ", acking" << endl;
}
-
+
// send the ack
mds->send_message_mds(new MExportDirWarningAck(m->get_ino()),
m->get_source().num(), MDS_PORT_MIGRATOR);
CDir *dir = 0;
if (diri) dir = diri->dir;
+ int from = m->get_source().num();
+ pair<int,int> auth = m->get_auth();
+
if (!dir) {
- dout(7) << "handle_export_dir_notify mds" << m->get_old_auth()
- << " -> mds" << m->get_new_auth()
+ dout(7) << "handle_export_dir_notify " << auth
<< " on missing dir " << m->get_ino() << endl;
- } else if (m->get_old_auth() == m->get_new_auth()) {
- dout(7) << "handle_export_dir_notify mds" << m->get_old_auth()
- << " aborted export on "
- << *dir << endl;
- // clear dir_auth_pending
- dir->set_dir_auth_pending(CDIR_AUTH_UNKNOWN);
-
- // no ack necessary.
- delete m;
- return;
} else {
- dout(7) << "handle_export_dir_notify mds" << m->get_old_auth()
- << " -> mds" << m->get_new_auth()
+ dout(7) << "handle_export_dir_notify " << auth
<< " on " << *dir << endl;
-
- // update bounds first
- for (list<inodeno_t>::iterator it = m->get_exports().begin();
- it != m->get_exports().end();
- it++) {
- CInode *n = cache->get_inode(*it);
- if (!n) continue;
- CDir *ndir = n->dir;
- if (!ndir) continue;
-
- int boundauth = ndir->authority().first;
- dout(7) << "export_dir_notify bound " << *ndir << " was dir_auth " << ndir->get_dir_auth() << " (" << boundauth << ")" << endl;
- if (ndir->get_dir_auth().first == CDIR_AUTH_PARENT) {
- if (boundauth != m->get_new_auth())
- ndir->set_dir_auth( boundauth );
- else
- assert(dir->authority().first == m->get_new_auth()); // apparently we already knew!
- } else {
- if (boundauth == m->get_new_auth())
- ndir->set_dir_auth( CDIR_AUTH_PARENT );
- }
+ // see which bounds we have in our cache
+ set<CDir*> bounds;
+ for (list<inodeno_t>::iterator p = m->get_exports().begin();
+ p != m->get_exports().end();
+ ++p) {
+ CInode *in = cache->get_inode(*p);
+ if (in && in->dir)
+ bounds.insert(in->dir);
}
+
+ // adjust auth
+ cache->adjust_bounded_subtree_auth(dir, bounds, auth);
+ cache->verify_subtree_bounds(dir, bounds);
- // update dir_auth
- if (diri->authority().first == m->get_new_auth()) {
- dout(7) << "handle_export_dir_notify on " << *diri << ": inode auth is the same, setting dir_auth -1" << endl;
- dir->set_dir_auth( CDIR_AUTH_PARENT );
- assert(!diri->is_auth());
- assert(!dir->is_auth());
- } else {
- dir->set_dir_auth( m->get_new_auth() );
- }
- assert(dir->authority().first != mds->get_nodeid());
- assert(!dir->is_auth());
-
- // DEBUG: verify subdirs
- /*
- if (g_conf.mds_verify_export_dirauth) {
-
- dout(7) << "handle_export_dir_notify on " << *dir << " checking " << m->num_subdirs() << " subdirs" << endl;
- for (list<inodeno_t>::iterator it = m->subdirs_begin();
- it != m->subdirs_end();
- it++) {
- CInode *diri = cache->get_inode(*it);
- if (!diri) continue; // don't have it, don't care
- if (!diri->dir) continue;
- dout(10) << "handle_export_dir_notify checking subdir " << *diri->dir << " is auth " << diri->dir->get_dir_auth() << endl;
- assert(diri->dir != dir); // base shouldn't be in subdir list
- if (diri->dir->get_dir_auth() != CDIR_AUTH_PARENT) {
- dout(7) << "*** weird value for dir_auth " << diri->dir->get_dir_auth() << " on " << *diri->dir << ", should have been -1 probably??? ******************" << endl;
- assert(0); // bad news!
- //dir->set_dir_auth( CDIR_AUTH_PARENT );
- }
- assert(diri->dir->authority() == m->get_new_auth());
- }
- }
- */
+ // induce a merge?
+ cache->try_subtree_merge(dir);
}
// send ack
- mds->send_message_mds(new MExportDirNotifyAck(m->get_ino()),
- m->get_old_auth(), MDS_PORT_MIGRATOR);
+ if (auth.first == from &&
+ auth.second == CDIR_AUTH_UNKNOWN) {
+ // aborted. no ack.
+ dout(7) << "handle_export_dir_notify mds" << auth.first
+ << " aborted export, not sending ack for "
+ << *dir << endl;
+ } else {
+ mds->send_message_mds(new MExportDirNotifyAck(m->get_ino()),
+ from, MDS_PORT_MIGRATOR);
+ }
delete m;
}
-
-
-
-
-
-void Migrator::show_imports()
-{
- mds->balancer->show_imports();
-}
// -- misc --
void handle_mds_failure(int who);
- void show_imports();
// -- import/export --
protected:
void handle_export_dir_discover_ack(MExportDirDiscoverAck *m);
void export_dir_frozen(CDir *dir, int dest);
- void export_dir_frozen_logged(CDir *dir, MExportDirPrep *prep, int dest);
+ //void export_dir_start_logged(CDir *dir, MExportDirPrep *prep, int dest);
void handle_export_dir_prep_ack(MExportDirPrepAck *m);
void handle_export_dir_warning_ack(MExportDirWarningAck *m);
void export_dir_go(CDir *dir);
dout(7) << "fix_renamed_dir on " << *in << endl;
dout(7) << "fix_renamed_dir on " << *in->dir << endl;
+
+ assert(0); // rewrite .
+
+ // 1- fix subtree tree.
+ // 2- adjust subtree auth.
+
+ /*
if (in->dir->is_auth()) {
// dir ours
dout(7) << "dir is auth" << endl;
if (in->is_auth()) {
// inode now ours
-
if (authchanged) {
// inode _was_ replica, now ours
- dout(7) << "inode was replica, now ours. removing from import list." << endl;
- assert(in->dir->is_import());
-
- // not import anymore!
- cache->imports.erase(in->dir);
- in->dir->state_clear(CDIR_STATE_IMPORT);
- in->dir->put(CDir::PIN_IMPORT);
-
- in->dir->set_dir_auth( CDIR_AUTH_PARENT );
- dout(7) << " fixing dir_auth to be " << in->dir->get_dir_auth() << endl;
-
- // move my nested imports to in's containing import
- CDir *con = cache->get_auth_container(in->dir);
- assert(con);
- for (set<CDir*>::iterator p = cache->nested_exports[in->dir].begin();
- p != cache->nested_exports[in->dir].end();
- p++) {
- dout(7) << "moving nested export under new container " << *con << endl;
- cache->nested_exports[con].insert(*p);
- }
- cache->nested_exports.erase(in->dir);
-
+ dout(7) << "inode was replica, now ours." << endl;
+ cache->adjust_subtree_auth(dir, mds->get_nodeid());
} else {
// inode was ours, still ours.
dout(7) << "inode was ours, still ours." << endl;
+
assert(!in->dir->is_import());
assert(in->dir->get_dir_auth().first == CDIR_AUTH_PARENT);
// i am now an import
cache->imports.insert(in->dir);
- in->dir->state_set(CDIR_STATE_IMPORT);
+ in->dir->state_set(CDir::STATE_IMPORT);
in->dir->get(CDir::PIN_IMPORT);
in->dir->set_dir_auth( mds->get_nodeid() );
// now export
cache->exports.insert(in->dir);
- in->dir->state_set(CDIR_STATE_EXPORT);
+ in->dir->state_set(CDir::STATE_EXPORT);
in->dir->get(CDir::PIN_EXPORT);
assert(dir_auth >= 0); // better be defined
// remove from export list
cache->exports.erase(in->dir);
- in->dir->state_clear(CDIR_STATE_EXPORT);
+ in->dir->state_clear(CDir::STATE_EXPORT);
in->dir->put(CDir::PIN_EXPORT);
CDir *oldcon = cache->get_auth_container(srcdir);
assert(!in->dir->is_export());
}
}
-
+ */
cache->show_imports();
}
// FIXME: check the slice only
- if (dir->is_proxy()) {
+ if (dir->auth_is_ambiguous()) {
// wait until export is acked (logged on remote) and committed (logged locally)
- CDir *ex = mds->mdcache->get_export_container(dir);
- dout(10) << "EMetaBlob.expire proxy for " << *dir
+ CDir *ex = mds->mdcache->get_subtree_root(dir);
+ dout(10) << "EMetaBlob.expire ambiguous auth for " << *dir
<< ", waiting for export finish on " << *ex << endl;
waitfor_export.push_back(ex);
continue;
void EImportMap::replay(MDS *mds)
{
+ /*
if (!mds->mdcache->imports.empty()) {
dout(10) << "EImportMap.replay -- ignoring, already have import map" << endl;
} else {
mds->mdcache->finish_ambiguous_import(*p);
}
}
-
+ */
mds->mdcache->show_imports();
}
using namespace std;
class MExportDirNotify : public Message {
- int new_auth;
- int old_auth;
inodeno_t ino;
-
+ pair<int,int> auth;
list<inodeno_t> exports; // bounds; these dirs are _not_ included (tho the inodes are)
- list<inodeno_t> subdirs;
+
+ //list<inodeno_t> subdirs;
public:
inodeno_t get_ino() { return ino; }
- int get_new_auth() { return new_auth; }
- int get_old_auth() { return old_auth; }
+ pair<int,int> get_auth() { return auth; }
list<inodeno_t>& get_exports() { return exports; }
- list<inodeno_t>::iterator subdirs_begin() { return subdirs.begin(); }
- list<inodeno_t>::iterator subdirs_end() { return subdirs.end(); }
- int num_subdirs() { return subdirs.size(); }
+ //list<inodeno_t>::iterator subdirs_begin() { return subdirs.begin(); }
+ //list<inodeno_t>::iterator subdirs_end() { return subdirs.end(); }
+ //int num_subdirs() { return subdirs.size(); }
MExportDirNotify() {}
- MExportDirNotify(inodeno_t ino, int old_auth, int new_auth) :
- Message(MSG_MDS_EXPORTDIRNOTIFY) {
- this->ino = ino;
- this->old_auth = old_auth;
- this->new_auth = new_auth;
- }
+ MExportDirNotify(inodeno_t i, int a, int b) :
+ Message(MSG_MDS_EXPORTDIRNOTIFY),
+ ino(i), auth(a,b) { }
+
virtual char *get_type_name() { return "ExNot"; }
+ /*
void copy_subdirs(list<inodeno_t>& s) {
this->subdirs = s;
}
+ */
void copy_exports(list<inodeno_t>& ex) {
this->exports = ex;
}
virtual void decode_payload() {
int off = 0;
- payload.copy(off, sizeof(int), (char*)&new_auth);
- off += sizeof(int);
- payload.copy(off, sizeof(int), (char*)&old_auth);
- off += sizeof(int);
+ payload.copy(off, sizeof(auth), (char*)&auth);
+ off += sizeof(auth);
payload.copy(off, sizeof(ino), (char*)&ino);
off += sizeof(ino);
::_decode(exports, payload, off);
- ::_decode(subdirs, payload, off);
+ //::_decode(subdirs, payload, off);
}
virtual void encode_payload() {
- payload.append((char*)&new_auth, sizeof(int));
- payload.append((char*)&old_auth, sizeof(int));
+ payload.append((char*)&auth, sizeof(auth));
payload.append((char*)&ino, sizeof(ino));
::_encode(exports, payload);
- ::_encode(subdirs, payload);
+ //::_encode(subdirs, payload);
}
};
void print(ostream& out) {
out << "osd_op_reply(" << st.reqid
<< " " << MOSDOp::get_opname(st.op)
- << " " << st.oid << " = " << st.result
- //<< " " << this
- << ")";
+ << " " << st.oid;
+ if (st.commit)
+ out << " commit";
+ else
+ out << " ack";
+ out << " = " << st.result;
+ out << ")";
}
};