void Client::put_cap_ref(Inode *in, int cap)
{
if (in->put_cap_ref(cap) && in->snapid == CEPH_NOSNAP) {
- check_caps(in);
+ check_caps(in, false);
signal_cond_list(in->waitfor_commit);
}
}
-void Client::check_caps(Inode *in, bool flush_snap)
+void Client::cap_delay_requeue(Inode *in)
+{
+ dout(10) << "cap_delay_requeue on " << *in << dendl;
+ in->hold_caps_until = g_clock.now();
+ in->hold_caps_until += 5.0;
+
+ delayed_caps.push_back(&in->cap_delay_item);
+}
+
+void Client::check_caps(Inode *in, bool is_delayed, bool flush_snap)
{
int wanted = in->caps_wanted();
int used = in->caps_used();
dout(10) << "check_caps on " << *in
<< " wanted " << cap_string(wanted)
<< " used " << cap_string(used)
+ << " is_delayed=" << is_delayed
+ << " flush_snap=" << flush_snap
<< dendl;
assert(in->snapid == CEPH_NOSNAP);
if (in->caps.empty())
return; // guard if at end of func
- map<int,InodeCap*>::iterator next;
- for (map<int,InodeCap*>::iterator it = in->caps.begin();
- it != in->caps.end();
- it = next) {
- next = it;
- next++;
+ if (!is_delayed)
+ cap_delay_requeue(in);
+#if 0
+ else {
+ // delayed. induce flush?
+ if ((in->caps_file_wanted() & (CEPH_CAP_WR|CEPH_CAP_WRBUFFER)) == 0 &&
+ (in->caps_used() & (CEPH_CAP_WR|CEPH_CAP_WRBUFFER)))
+ _flush(in, true);
+ }
+#endif
+
+ utime_t now = g_clock.now();
+ map<int,InodeCap*>::iterator it = in->caps.begin();
+ while (it != in->caps.end()) {
+ int mds = it->first;
InodeCap *cap = it->second;
+ it++;
+
int revoking = cap->implemented & ~cap->issued;
if (in->wanted_max_size > in->inode.max_size &&
if ((cap->issued & ~wanted) == 0)
continue; /* nothing extra, all good */
- /*
- if (time_before(jiffies, ci->i_hold_caps_until)) {
- // delaying cap release for a bit
- dout(30, "delaying cap release\n");
- continue;
+ if (now < in->hold_caps_until) {
+ dout(10) << "delaying cap release" << dendl;
+ continue;
}
- */
ack:
int op = CEPH_CAP_OP_ACK;
op = CEPH_CAP_OP_FLUSHSNAP;
else if (wanted == 0)
op = CEPH_CAP_OP_RELEASE;
- dout(10) << " op = " << op << dendl;
MClientFileCaps *m = new MClientFileCaps(op,
in->inode,
0,
m->set_max_size(in->wanted_max_size);
in->requested_max_size = in->wanted_max_size;
m->set_snap_follows(in->snaprealm->get_snap_context().seq);
- messenger->send_message(m, mdsmap->get_inst(it->first));
- if (wanted == 0 && !flush_snap)
- mds_sessions[it->first].num_caps--;
- }
-
- if (wanted == 0 && !flush_snap) {
- remove_all_caps(in);
+ messenger->send_message(m, mdsmap->get_inst(mds));
+ if (wanted == 0 && !flush_snap) {
+ mds_sessions[mds].num_caps--;
+ remove_cap(in, mds);
+ }
}
}
while (!p.end()) {
Inode *in = *p;
++p;
- check_caps(in, true); // force writeback of write caps
+ check_caps(in, false, true); // force writeback of write caps
if (g_conf.client_oc)
_flush(in);
}
// first, writeback in _old_ realm context
// ???
- check_caps(in, true);
+ check_caps(in, false, true);
if (g_conf.client_oc)
_flush(in);
utime_t el = now - last_cap_renew;
if (mdsmap && el > mdsmap->get_session_timeout() / 3.0)
renew_caps();
+
+ // delayed caps
+ xlist<Inode*>::iterator p = delayed_caps.begin();
+ while (!p.end()) {
+ Inode *in = *p;
+ ++p;
+ if (in->hold_caps_until > now)
+ break;
+ delayed_caps.pop_front();
+ check_caps(in, true);
+ }
}
void Client::renew_caps()
Inode *in = f->inode;
if (in->snapid == CEPH_NOSNAP) {
- if (in->put_open_ref(f->mode))
- check_caps(in);
+ if (in->put_open_ref(f->mode)) {
+ if (in->caps_used() & (CEPH_CAP_WRBUFFER|CEPH_CAP_WR))
+ _flush(in, true);
+ check_caps(in, false);
+ }
} else {
assert(in->snap_cap_refs > 0);
in->snap_cap_refs--;
endoff > in->wanted_max_size) {
dout(10) << "wanted_max_size " << in->wanted_max_size << " -> " << endoff << dendl;
in->wanted_max_size = endoff;
- check_caps(in);
+ check_caps(in, false);
}
// wait for caps, max_size
if ((in->inode.size << 1) >= in->inode.max_size &&
(in->reported_size << 1) < in->inode.max_size)
- check_caps(in);
+ check_caps(in, false);
dout(7) << "wrote to " << totalwritten+offset << ", extending file size" << dendl;
} else {
unsigned exporting_issued;
int exporting_mds;
capseq_t exporting_mseq;
+ utime_t hold_caps_until;
+ xlist<Inode*>::item cap_delay_item;
SnapRealm *snaprealm;
xlist<Inode*>::item snaprealm_item;
dir_auth(-1), dir_hashed(false), dir_replicated(false),
snap_caps(0), snap_cap_refs(0),
exporting_issued(0), exporting_mds(-1), exporting_mseq(0),
+ cap_delay_item(this),
snaprealm(0), snaprealm_item(this), snapdir_parent(0),
reported_size(0), wanted_max_size(0), requested_max_size(0),
ref(0), ll_ref(0),
Inode* root;
LRU lru; // lru list of Dentry's in our local metadata cache.
+ xlist<Inode*> delayed_caps;
hash_map<inodeno_t,SnapRealm*> snap_realms;
SnapRealm *get_snap_realm(inodeno_t r) {
void handle_snap(class MClientSnap *m);
void handle_file_caps(class MClientFileCaps *m);
- void check_caps(Inode *in, bool force_dirty=false);
+ void cap_delay_requeue(Inode *in);
+ void check_caps(Inode *in, bool is_delayed, bool flush_snap=false);
void put_cap_ref(Inode *in, int cap);
void _release(Inode *in, bool checkafter=true);