We were being sloppy before with the ESubtreeMap vs import/export events.
Fix that by doing a few things:
- add an ambig flag to the subtree map items, and set it for in-progress
imports. That means an ESubtreeMap followed by EImportFinish will do
the right thing now.
- adjust the dir_auth on EExport journaling (handle_export_dir_ack) so
that our journaled subtree_map state is always in sync with what we
see during replay.
Also document clearly what the dir_auth variations actually mean.
Signed-off-by: Sage Weil <sage@newdream.net>
p != subtrees.end();
++p) {
CDir *dir = p->first;
- if (!dir->is_auth()) continue;
- dout(15) << " subtree " << *dir << dendl;
+ // journal subtree as "ours" if we are
+ // me, -2
+ // me, me
+ // me, !me (may be importing and ambiguous!)
+
+ // so not
+ // !me, *
+ if (dir->get_dir_auth().first != mds->whoami)
+ continue;
+
+ if (dir->is_ambiguous_dir_auth() &&
+ migrator->is_importing(dir->dirfrag())) {
+ dout(15) << " ambig subtree " << *dir << dendl;
+ le->ambiguous_subtrees.insert(dir->dirfrag());
+ } else {
+ dout(15) << " subtree " << *dir << dendl;
+ }
+
le->subtrees[dir->dirfrag()].clear();
le->metablob.add_dir_context(dir, EMetaBlob::TO_ROOT);
le->metablob.add_dir(dir, false);
++p) {
CDir *dir = p->first;
- if (dir->authority().first != who)
+ if (dir->authority().first != who ||
+ dir->authority().second == mds->whoami)
continue;
assert(!dir->is_auth());
#include "messages/MExportCapsAck.h"
-
-
+/*
+ * this is what the dir->dir_auth values look like
+ *
+ * dir_auth authbits
+ * export
+ * me me - before
+ * me, me me - still me, but preparing for export
+ * me, them me - send MExportDir (peer is preparing)
+ * them, me me - journaled EExport
+ * them them - done
+ *
+ * import:
+ * them them - before
+ * me, them me - journaled EImportStart
+ * me me - done
+ *
+ * which implies:
+ * - auth bit is set if i am listed as first _or_ second dir_auth.
+ */
#include "common/config.h"
set<CDir*> bounds;
cache->get_subtree_bounds(dir, bounds);
+ // list us second, them first.
+ // this keeps authority().first in sync with subtree auth state in the journal.
+ int target = export_peer[dir];
+ cache->adjust_subtree_auth(dir, target, mds->get_nodeid());
+
// log completion.
// include export bounds, to ensure they're in the journal.
EExport *le = new EExport(mds->mdlog, dir);
public:
EMetaBlob metablob;
map<dirfrag_t, vector<dirfrag_t> > subtrees;
+ set<dirfrag_t> ambiguous_subtrees;
uint64_t expire_pos;
ESubtreeMap() : LogEvent(EVENT_SUBTREEMAP), expire_pos(0) { }
void print(ostream& out) {
- out << "subtree_map " << subtrees.size() << " subtrees "
+ out << "ESubtreeMap " << subtrees.size() << " subtrees "
+ << ", " << ambiguous_subtrees.size() << " ambiguous "
<< metablob;
}
void encode(bufferlist& bl) const {
- __u8 struct_v = 3;
+ __u8 struct_v = 4;
::encode(struct_v, bl);
::encode(stamp, bl);
::encode(metablob, bl);
::encode(subtrees, bl);
+ ::encode(ambiguous_subtrees, bl);
::encode(expire_pos, bl);
}
void decode(bufferlist::iterator &bl) {
::decode(stamp, bl);
::decode(metablob, bl);
::decode(subtrees, bl);
+ if (struct_v >= 4)
+ ::decode(ambiguous_subtrees, bl);
if (struct_v >= 3)
::decode(expire_pos, bl);
}
p != subtrees.end();
++p) {
CDir *dir = mds->mdcache->get_dirfrag(p->first);
- mds->mdcache->adjust_bounded_subtree_auth(dir, p->second, mds->get_nodeid());
+ if (ambiguous_subtrees.count(p->first)) {
+ // ambiguous!
+ mds->mdcache->add_ambiguous_import(p->first, p->second);
+ mds->mdcache->adjust_bounded_subtree_auth(dir, p->second,
+ pair<int,int>(mds->get_nodeid(), mds->get_nodeid()));
+ } else {
+ // not ambiguous
+ mds->mdcache->adjust_bounded_subtree_auth(dir, p->second, mds->get_nodeid());
+ }
}
mds->mdcache->show_subtrees();
}
} else {
dout(10) << "EImportFinish.replay " << base << " success=" << success
- << ", predates my subtree_map start point, ignoring"
+ << " on subtree not marked as ambiguous"
<< dendl;
- // verify that?
+ assert(0 == "this shouldn't happen unless this is an old journal");
}
}