mds: clean up loner set/drop logic

Track what loner we _want_ separately from what loner we have, so
that locks can move toward the right state.

Centralize loner set/drop call points.

Move out of EXCL in simple_eval if our target loner is -1(none).
This commit is contained in:
Sage Weil 2009-08-20 14:48:10 -07:00
parent 0266f877ad
commit c55f2e9812
4 changed files with 68 additions and 48 deletions

View File

@ -117,6 +117,7 @@ uclient
- hadoop: clean up assert usage
mds
- pass issued, wanted into eval(lock) when eval() already has it? (and otherwise optimize eval paths..)
- add an up:shadow mode?
- tail the mds log as it is written
- periodically check head so that we trim, too

View File

@ -151,8 +151,12 @@ ostream& operator<<(ostream& out, CInode& in)
<< "@" << it->second->get_last_sent();
}
out << "}";
if (in.get_loner() >= 0)
if (in.get_loner() >= 0 || in.get_wanted_loner() >= 0) {
out << ",l=" << in.get_loner();
if (in.get_loner() != in.get_wanted_loner())
out << "(" << in.get_wanted_loner() << ")";
}
}
if (in.get_num_ref()) {
@ -1593,8 +1597,12 @@ bool CInode::encode_inodestat(bufferlist& bl, Session *session,
if (!no_caps && valid && !cap) {
// add a new cap
cap = add_client_cap(client, session, find_snaprealm());
if (is_auth())
try_choose_loner();
if (is_auth()) {
if (choose_ideal_loner() >= 0)
try_set_loner();
else if (get_wanted_loner() < 0)
try_drop_loner();
}
}
if (cap && valid) {

View File

@ -334,7 +334,7 @@ private:
xattrlock(this, CEPH_LOCK_IXATTR, WAIT_XATTRLOCK_OFFSET),
snaplock(this, CEPH_LOCK_ISNAP, WAIT_SNAPLOCK_OFFSET),
nestlock(this, CEPH_LOCK_INEST, WAIT_NESTLOCK_OFFSET),
loner_cap(-1)
loner_cap(-1), want_loner_cap(-1)
{
g_num_ino++;
g_num_inoa++;
@ -534,14 +534,22 @@ public:
// -- caps -- (new)
// client caps
int loner_cap;
int loner_cap, want_loner_cap;
bool try_choose_loner() {
if (loner_cap >= 0)
return true;
int get_loner() { return loner_cap; }
int get_wanted_loner() { return want_loner_cap; }
// this is the loner state our locks should aim for
int get_target_loner() {
if (loner_cap == want_loner_cap)
return loner_cap;
else
return -1;
}
int calc_ideal_loner() {
if (!mds_caps_wanted.empty())
return false;
return -1;
int n = 0;
int loner = -1;
@ -549,24 +557,30 @@ public:
it != client_caps.end();
it++)
if (!it->second->is_stale() &&
((it->second->wanted() & (CEPH_CAP_ANY_WR|CEPH_CAP_FILE_WR|CEPH_CAP_FILE_RD))
|| inode.is_dir())) {
((it->second->wanted() & (CEPH_CAP_ANY_WR|CEPH_CAP_FILE_WR|CEPH_CAP_FILE_RD)) ||
(inode.is_dir() && !has_subtree_root_dirfrag()))) {
if (n)
return false;
return -1;
n++;
loner = it->first;
}
if (n == 1) {
loner_cap = loner;
authlock.excl_client = loner;
filelock.excl_client = loner;
linklock.excl_client = loner;
xattrlock.excl_client = loner;
return true;
}
return false;
return loner;
}
int choose_ideal_loner() {
want_loner_cap = calc_ideal_loner();
return want_loner_cap;
}
bool try_set_loner() {
assert(want_loner_cap >= 0);
if (loner_cap >= 0 && loner_cap != want_loner_cap)
return false;
loner_cap = want_loner_cap;
authlock.excl_client = loner_cap;
filelock.excl_client = loner_cap;
linklock.excl_client = loner_cap;
xattrlock.excl_client = loner_cap;
return true;
}
bool try_drop_loner() {
if (loner_cap < 0)
return true;
@ -605,8 +619,9 @@ public:
}
void choose_lock_states() {
int issued = get_caps_issued();
if (is_auth() && (issued & CEPH_CAP_ANY_EXCL))
try_choose_loner();
if (is_auth() && (issued & (CEPH_CAP_ANY_EXCL|CEPH_CAP_ANY_WR)) &&
choose_ideal_loner() >= 0)
try_set_loner();
choose_lock_state(&filelock, issued);
choose_lock_state(&authlock, issued);
choose_lock_state(&xattrlock, issued);
@ -634,9 +649,6 @@ public:
}
return false;
}
int get_loner() {
return loner_cap;
}
bool is_any_caps() { return !client_caps.empty(); }
bool is_any_nonstale_caps() { return count_nonstale_caps(); }

View File

@ -525,8 +525,7 @@ void Locker::eval_gather(SimpleLock *lock, bool first, bool *need_issue)
// drop loner before doing waiters
if (caps &&
in->is_auth() && in->get_loner() >= 0 &&
in->multiple_nonstale_caps()) {
in->is_auth() && in->get_loner() >= 0 && in->get_wanted_loner() < 0) {
dout(10) << " trying to drop loner" << dendl;
if (in->try_drop_loner()) {
dout(10) << " dropped loner" << dendl;
@ -557,18 +556,18 @@ bool Locker::eval(CInode *in, int mask)
dout(10) << "eval " << mask << " " << *in << dendl;
// choose loner?
if (in->is_auth() && in->get_loner() < 0) {
int wanted = in->get_caps_wanted();
if (((wanted & (CEPH_CAP_GWR|CEPH_CAP_GBUFFER|CEPH_CAP_GEXCL)) ||
(in->inode.is_dir() && !in->has_subtree_root_dirfrag() &&
!in->multiple_nonstale_caps())) &&
in->try_choose_loner()) {
dout(10) << " chose loner client" << in->get_loner() << dendl;
need_issue = true;
mask = -1;
}
if (in->is_auth()) {
if (in->choose_ideal_loner() >= 0) {
if (in->try_set_loner()) {
dout(10) << "eval set loner to client" << in->get_loner() << dendl;
need_issue = true;
mask = -1;
} else
dout(10) << "eval want loner client" << in->get_wanted_loner() << " but failed to set it" << dendl;
} else
dout(10) << "eval doesn't want loner" << dendl;
}
if (mask & CEPH_LOCK_IFILE)
eval_any(&in->filelock, &need_issue);
if (mask & CEPH_LOCK_IAUTH)
@ -581,8 +580,7 @@ bool Locker::eval(CInode *in, int mask)
eval_any(&in->nestlock, &need_issue);
// drop loner?
if (in->is_auth() && in->get_loner() >= 0 &&
in->multiple_nonstale_caps()) {
if (in->is_auth() && in->get_loner() >= 0 && in->get_wanted_loner() < 0) {
dout(10) << " trying to drop loner" << dendl;
if (in->try_drop_loner()) {
dout(10) << " dropped loner" << dendl;
@ -1463,7 +1461,7 @@ bool Locker::check_inode_max_size(CInode *in, bool force_wrlock,
if (!force_wrlock && !in->filelock.can_wrlock(in->get_loner())) {
// lock?
if (in->filelock.is_stable()) {
if (in->get_loner() >= 0)
if (in->get_target_loner() >= 0)
file_excl(&in->filelock);
else
simple_lock(&in->filelock);
@ -1880,7 +1878,7 @@ bool Locker::_do_cap_update(CInode *in, Capability *cap,
if (in->filelock.is_stable()) {
bool need_issue = false;
cap->inc_suppress();
if (in->get_loner() >= 0 || in->try_choose_loner()) {
if (in->get_loner() >= 0 || (in->get_wanted_loner() >= 0 && in->try_set_loner())) {
if (in->filelock.get_state() != LOCK_EXCL)
file_excl(&in->filelock, &need_issue);
need_issue = false; // loner!
@ -2469,7 +2467,7 @@ void Locker::simple_eval(SimpleLock *lock, bool *need_issue)
// -> excl?
if (lock->get_state() != LOCK_EXCL &&
in && in->get_loner() >= 0 &&
in && in->get_target_loner() >= 0 &&
(wanted & CEPH_CAP_GEXCL)) {
dout(7) << "simple_eval stable, going to excl " << *lock
<< " on " << *lock->get_parent() << dendl;
@ -2480,8 +2478,9 @@ void Locker::simple_eval(SimpleLock *lock, bool *need_issue)
else if (lock->get_state() != LOCK_SYNC &&
!lock->is_xlocked() &&
!lock->is_wrlocked() &&
!(issued & CEPH_CAP_GEXCL) &&
!lock->is_waiter_for(SimpleLock::WAIT_WR)) {
((!(issued & CEPH_CAP_GEXCL) &&
!lock->is_waiter_for(SimpleLock::WAIT_WR)) ||
(lock->get_state() == LOCK_EXCL && in && in->get_target_loner() < 0))) {
dout(7) << "simple_eval stable, syncing " << *lock
<< " on " << *lock->get_parent() << dendl;
simple_sync(lock, need_issue);
@ -3138,7 +3137,7 @@ void Locker::file_eval(ScatterLock *lock, bool *need_issue)
//!lock->is_waiter_for(SimpleLock::WAIT_WR) &&
((wanted & (CEPH_CAP_GWR|CEPH_CAP_GBUFFER)) ||
(in->inode.is_dir() && !in->has_subtree_root_dirfrag())) &&
in->try_choose_loner()) {
in->get_target_loner() >= 0) {
dout(7) << "file_eval stable, bump to loner " << *lock
<< " on " << *lock->get_parent() << dendl;
file_excl(lock, need_issue);