- verify once-per-segment jouranl context is working...
+- open file rejournaling vs capped log...
+ - open files vs shutdown in general! need to export any caps on replicated metadata
+
mds cleanup
- fix freeze_* interface to pull waiters _outside_
- get rid of replicate objects for replicate_to .. encode to bufferlists directly
- fix path_traverse
- fix reconnect/rejoin open file weirdness
+- export caps to auth on unlinked inodes
+
- stray reintegration
- stray purge on shutdown
- need to export stray crap to another mds..
out << " v" << in.get_version();
- if (in.state_test(CInode::STATE_AMBIGUOUSAUTH))
- out << " AMBIGAUTH";
+ if (in.state_test(CInode::STATE_AMBIGUOUSAUTH)) out << " AMBIGAUTH";
if (in.is_freezing_inode()) out << " FREEZING";
if (in.is_frozen_inode()) out << " FROZEN";
void CInode::add_waiter(int tag, Context *c)
{
+ dout(10) << "add_waiter tag " << tag
+ << " !ambig " << !state_test(STATE_AMBIGUOUSAUTH)
+ << " !frozen " << !is_frozen_inode()
+ << " !freezing " << !is_freezing_inode()
+ << dendl;
// wait on the directory?
// make sure its not the inode that is explicitly ambiguous|freezing|frozen
- if ((tag & WAIT_SINGLEAUTH) && !state_test(STATE_AMBIGUOUSAUTH) ||
- (tag & WAIT_UNFREEZE) && !state_test(STATE_FROZEN|STATE_FREEZING)) {
+ if (((tag & WAIT_SINGLEAUTH) && !state_test(STATE_AMBIGUOUSAUTH)) ||
+ ((tag & WAIT_UNFREEZE) && !is_frozen_inode() && !is_freezing_inode())) {
parent->dir->add_waiter(tag, c);
return;
}
static const int WAIT_UNANCHORED = (1<<3);
static const int WAIT_CAPS = (1<<4);
static const int WAIT_FROZEN = (1<<5);
- static const int WAIT_UNFREEZE = (1<<6);
static const int WAIT_AUTHLOCK_OFFSET = 5;
static const int WAIT_LINKLOCK_OFFSET = 5 + SimpleLock::WAIT_BITS;
// LogSegment xlists i (may) belong to
xlist<CInode*>::item xlist_dirty;
public:
- xlist<CInode*>::item xlist_opened_files;
+ xlist<CInode*>::item xlist_open_file;
xlist<CInode*>::item xlist_dirty_inode_mtime;
xlist<CInode*>::item xlist_purging_inode;
stickydir_ref(0),
parent(0), force_auth(CDIR_AUTH_DEFAULT),
replica_caps_wanted(0),
- xlist_dirty(this), xlist_opened_files(this),
+ xlist_dirty(this), xlist_open_file(this),
xlist_dirty_inode_mtime(this), xlist_purging_inode(this),
auth_pins(0), nested_auth_pins(0),
versionlock(this, LOCK_OTYPE_IVERSION, WAIT_VERSIONLOCK_OFFSET),
bool is_root() { return inode.ino == MDS_INO_ROOT; }
bool is_stray() { return MDS_INO_IS_STRAY(inode.ino); }
+ bool is_base() { return inode.ino < MDS_INO_BASE; }
// note: this overloads MDSCacheObject
bool is_ambiguous_auth() {
if (cap->is_null()) {
dout(7) << " cap for client" << client << " is now null, removing from " << *in << dendl;
in->remove_client_cap(client);
+ if (!in->is_any_caps())
+ in->xlist_open_file.remove_myself(); // unpin logsegment
if (!in->is_auth())
request_inode_file_caps(in);
assert(lock->get_parent()->is_auth());
assert(lock->is_stable());
- if (((CInode*)lock->get_parent())->has_subtree_root_dirfrag()) {
+ CInode *in = (CInode*)lock->get_parent();
+ if (in->has_subtree_root_dirfrag() && !in->is_base()) {
// i _should_ be scattered.
if (!lock->is_rdlocked() &&
!lock->is_xlocked()) {
xlist<CInode*> dirty_inodes;
xlist<CDentry*> dirty_dentries;
- xlist<CInode*> opened_files;
+ xlist<CInode*> open_files;
xlist<CInode*> dirty_inode_mtimes;
//xlist<CInode*> purging_inodes;
p = n;
}
}
+ if (max == 0) {
+ for (set<CInode*>::iterator p = base_inodes.begin();
+ p != base_inodes.end();
+ ++p) {
+ CInode *in = *p;
+ list<CDir*> ls;
+ in->get_dirfrags(ls);
+ for (list<CDir*>::iterator p = ls.begin(); p != ls.end(); ++p) {
+ CDir *dir = *p;
+ if (dir->get_num_ref() == 0)
+ trim_dirfrag(dir, 0, expiremap);
+ }
+ if (in->get_num_ref() == 0)
+ trim_inode(0, in, 0, expiremap);
+ }
+ }
// send!
send_expire_messages(expiremap);
return; // i won't print anything.
if (subtrees.empty()) {
- dout(dbl) << "no subtrees" << dendl;
+ dout(dbl) << "show_subtrees - no subtrees" << dendl;
return;
}
p != base_inodes.end();
++p)
(*p)->get_dirfrags(basefrags);
- dout(15) << "show_subtrees, base dirfrags " << basefrags << dendl;
+ //dout(15) << "show_subtrees, base dirfrags " << basefrags << dendl;
+ dout(15) << "show_subtrees" << dendl;
// queue stuff
list<pair<CDir*,int> > q;
out << " x=" << get_xlocked_by();
if (is_wrlocked())
out << " wr=" << get_num_wrlocks();
+ if (updated)
+ out << " updated";
out << ")";
}
EOpen *le = 0;
// check queued inodes
+ LogSegment *ls = mdlog->get_current_segment();
for (set<CInode*>::iterator p = journal_open_queue.begin();
p != journal_open_queue.end();
++p) {
- (*p)->put(CInode::PIN_BATCHOPENJOURNAL);
- if ((*p)->is_any_caps()) {
+ CInode *in = *p;
+ in->put(CInode::PIN_BATCHOPENJOURNAL);
+ if (in->is_any_caps()) {
if (!le) le = new EOpen(mdlog);
- le->add_inode(*p);
- (*p)->last_open_journaled = mds->mdlog->get_write_pos();
+ le->add_inode(in);
+ in->last_open_journaled = mds->mdlog->get_write_pos();
+ ls->open_files.push_back(&in->xlist_open_file);
}
}
journal_open_queue.clear();
if (reqmds >= 0) out << " by mds" << reqmds;
}
- bool has_expired(MDS *mds);
- void expire(MDS *mds, Context *c);
void update_segment();
void replay(MDS *mds);
};
if (atid) out << " atid " << atid;
}
- bool has_expired(MDS *mds);
- void expire(MDS *mds, Context *c);
void replay(MDS *mds);
};
metablob._decode(bl, off);
}
- bool has_expired(MDS *mds);
- void expire(MDS *mds, Context *c);
void update_segment();
void replay(MDS *mds);
};
metablob._decode(bl, off);
}
- bool has_expired(MDS *mds);
- void expire(MDS *mds, Context *c);
void update_segment();
void replay(MDS *mds);
};
++p) {
CDir *dir = *p;
if (dir->can_auth_pin()) {
- dout(10) << " committing " << *dir << dendl;
+ dout(10) << "try_to_expire committing " << *dir << dendl;
dir->commit(0, gather->new_sub());
} else {
- dout(10) << " waiting for unfreeze on " << *dir << dendl;
+ dout(10) << "try_to_expire waiting for unfreeze on " << *dir << dendl;
dir->add_waiter(CDir::WAIT_UNFREEZE, gather->new_sub());
}
}
// dirty non-auth mtimes
for (xlist<CInode*>::iterator p = dirty_inode_mtimes.begin(); !p.end(); ++p) {
- dout(10) << " waiting for dirlock mtime flush on " << *p << dendl;
+ dout(10) << "try_to_expire waiting for dirlock mtime flush on " << *p << dendl;
if (!gather) gather = new C_Gather;
(*p)->dirlock.add_waiter(SimpleLock::WAIT_STABLE, gather->new_sub());
}
+
+ // open files
+ if (!open_files.empty()) {
+ assert(!mds->mdlog->is_capped()); // hmm FIXME
+ for (xlist<CInode*>::iterator p = open_files.begin(); !p.end(); ++p) {
+ dout(20) << "try_to_expire requeueing open file " << **p << dendl;
+ mds->server->queue_journal_open(*p);
+ }
+ if (!gather) gather = new C_Gather;
+ mds->server->add_journal_open_waiter(gather->new_sub());
+ mds->server->maybe_journal_opens();
+ dout(10) << "try_to_expire waiting for open files to rejournal" << dendl;
+ }
// idalloc
if (allocv > mds->idalloc->get_committed_version()) {
- dout(10) << " saving idalloc table, need " << allocv << dendl;
+ dout(10) << "try_to_expire saving idalloc table, need " << allocv << dendl;
if (!gather) gather = new C_Gather;
mds->idalloc->save(gather->new_sub(), allocv);
}
// clientmap
if (clientmapv > mds->clientmap.get_committed()) {
- dout(10) << " saving clientmap, need " << clientmapv << dendl;
+ dout(10) << "try_to_expire saving clientmap, need " << clientmapv << dendl;
if (!gather) gather = new C_Gather;
mds->clientmap.save(gather->new_sub(), clientmapv);
}
++p) {
if (!gather) gather = new C_Gather;
assert(!mds->anchorclient->has_committed(*p));
- dout(10) << " anchor transaction " << *p
+ dout(10) << "try_to_expire anchor transaction " << *p
<< " pending commit (not yet acked), waiting" << dendl;
mds->anchorclient->wait_for_ack(*p, gather->new_sub());
}
// anchortable
if (anchortablev > mds->anchortable->get_committed_version()) {
- dout(10) << " saving anchor table, need " << anchortablev << dendl;
+ dout(10) << "try_to_expire waiting for anchor table to save, need " << anchortablev << dendl;
if (!gather) gather = new C_Gather;
mds->anchortable->save(gather->new_sub());
}
// FIXME client requests...?
// audit handling of anchor transactions?
- // open files?
return gather;
}
// ------------------------
// EOpen
-bool EOpen::has_expired(MDS *mds)
-{
- for (list<inodeno_t>::iterator p = inos.begin(); p != inos.end(); ++p) {
- CInode *in = mds->mdcache->get_inode(*p);
- if (in &&
- in->is_any_caps() &&
- !(in->last_open_journaled > get_start_off() ||
- in->last_open_journaled == 0)) {
- dout(10) << "EOpen.has_expired still refer to caps on " << *in << dendl;
- return false;
- }
- }
- return true;
-}
-
-void EOpen::expire(MDS *mds, Context *c)
-{
- dout(10) << "EOpen.expire " << dendl;
-
- if (mds->mdlog->is_capped()) {
- dout(0) << "uh oh, log is capped, but i have unexpired opens." << dendl;
- assert(0);
- }
-
- for (list<inodeno_t>::iterator p = inos.begin(); p != inos.end(); ++p) {
- CInode *in = mds->mdcache->get_inode(*p);
- if (!in) continue;
- if (!in->is_any_caps()) continue;
-
- dout(10) << "EOpen.expire " << in->ino()
- << " last_open_journaled " << in->last_open_journaled << dendl;
-
- mds->server->queue_journal_open(in);
- }
- mds->server->add_journal_open_waiter(c);
- mds->server->maybe_journal_opens();
-}
-
void EOpen::update_segment()
{
// ??
unsigned state; // state bits
public:
- unsigned get_state() { return state; }
+ unsigned get_state() const { return state; }
+ unsigned state_test(unsigned mask) const { return (state & mask); }
void state_clear(unsigned mask) { state &= ~mask; }
void state_set(unsigned mask) { state |= mask; }
- unsigned state_test(unsigned mask) { return state & mask; }
void state_reset(unsigned s) { state = s; }
- bool is_auth() { return state_test(STATE_AUTH); }
- bool is_dirty() { return state_test(STATE_DIRTY); }
- bool is_clean() { return !is_dirty(); }
- bool is_rejoining() { return state_test(STATE_REJOINING); }
+ bool is_auth() const { return state_test(STATE_AUTH); }
+ bool is_dirty() const { return state_test(STATE_DIRTY); }
+ bool is_clean() const { return !is_dirty(); }
+ bool is_rejoining() const { return state_test(STATE_REJOINING); }
// --------------------------------------------
// authority