}
-void Client::update_inode(Inode *in, InodeStat *st, ceph_mds_reply_lease *l, utime_t ttl)
+void Client::update_inode(Inode *in, InodeStat *st, LeaseStat *lease, utime_t from)
{
- dout(12) << "update_inode stat mask is " << st->mask << dendl;
- if (st->mask & CEPH_STAT_MASK_INODE) {
+ utime_t ttl = from;
+ ttl += (float)lease->duration_ms * 1000.0;
+
+ dout(12) << "update_inode mask " << lease->mask << " ttl " << ttl << dendl;
+ if (lease->mask & CEPH_STAT_MASK_INODE) {
in->inode = st->inode;
in->dirfragtree = st->dirfragtree; // FIXME look at the mask!
}
- in->mask = st->mask;
+
+ in->mask = lease->mask;
if (ttl > in->ttl)
in->ttl = ttl;
}
+
/*
* insert_dentry_inode - insert + link a single dentry + inode into the metadata cache.
*/
-Inode* Client::insert_dentry_inode(Dir *dir, const string& dname, int dmask, InodeStat *st, utime_t ttl)
+Inode* Client::insert_dentry_inode(Dir *dir, const string& dname, LeaseStat *dlease,
+ InodeStat *ist, LeaseStat *ilease,
+ utime_t from)
{
+ int dmask = dlease->mask;
+ utime_t dttl = from;
+ dttl += (float)dlease->duration_ms * 1000.0;
+
Dentry *dn = NULL;
if (dir->dentries.count(dname))
dn = dir->dentries[dname];
- dout(12) << "insert_dentry_inode " << dname << " ino " << st->inode.ino
- << " size " << st->inode.size
- << " mtime " << st->inode.mtime
- << " mask " << st->mask
+ dout(12) << "insert_dentry_inode " << dname << " ino " << ist->inode.ino
+ << " size " << ist->inode.size
+ << " mtime " << ist->inode.mtime
+ << " dmask " << dmask
<< " in dir " << dir->parent_inode->inode.ino
<< dendl;
if (dn) {
- if (dn->inode->inode.ino == st->inode.ino) {
+ if (dn->inode->inode.ino == ist->inode.ino) {
touch_dn(dn);
dout(12) << " had dentry " << dname
<< " with correct ino " << dn->inode->inode.ino
if (!dn) {
// have inode linked elsewhere? -> unlink and relink!
- if (inode_map.count(st->inode.ino)) {
- Inode *in = inode_map[st->inode.ino];
+ if (inode_map.count(ist->inode.ino)) {
+ Inode *in = inode_map[ist->inode.ino];
assert(in);
if (in->dn) {
}
if (!dn) {
- Inode *in = new Inode(st->inode, objectcacher);
- inode_map[st->inode.ino] = in;
+ Inode *in = new Inode(ist->inode, objectcacher);
+ inode_map[ist->inode.ino] = in;
dn = link(dir, dname, in);
- dout(12) << " new dentry+node with ino " << st->inode.ino << dendl;
+ dout(12) << " new dentry+node with ino " << ist->inode.ino << dendl;
}
assert(dn && dn->inode);
- update_inode(dn->inode, st, ttl);
+ update_inode(dn->inode, ist, ilease, from);
return dn->inode;
}
*
* insert a trace from a MDS reply into the cache.
*/
-Inode* Client::insert_trace(MClientReply *reply, utime_t ttl)
+Inode* Client::insert_trace(MClientReply *reply, utime_t from)
{
- utime_t now = g_clock.real_now();
- dout(10) << "insert_trace got " << reply->get_trace_in().size() << " inodes" << dendl;
- if (reply->get_trace_in().empty())
+ bufferlist::iterator p = reply->get_trace_bl().begin();
+ if (p.end()) {
+ dout(10) << "insert_trace -- no trace" << dendl;
return NULL;
+ }
+
+ __u32 numi, numd;
+ ::_decode_simple(numi, p);
+ ::_decode_simple(numd, p);
+ dout(10) << "insert_trace got " << numi << " inodes, " << numd << " dentries" << dendl;
- list<string>::const_iterator pdn = reply->get_trace_dn().begin();
- list<char>::const_iterator pdnmask = reply->get_trace_dn_mask().begin();
- list<DirStat*>::const_iterator pdir = reply->get_trace_dir().begin();
- list<InodeStat*>::const_iterator pin = reply->get_trace_in().begin();
+ // decode
+ LeaseStat ilease[numi];
+ InodeStat ist[numi];
+ DirStat dst[numd];
+ string dname[numd];
+ LeaseStat dlease[numd];
+ if (numi == 0)
+ return NULL;
+
+ int ileft = numi;
+ int dleft = numd;
+ if (numi == numd)
+ goto dentry;
+
+ inode:
+ if (!ileft) goto done;
+ ileft--;
+ ist[ileft]._decode(p);
+ ::_decode_simple(ilease[ileft], p);
+
+ dentry:
+ if (!dleft) goto done;
+ dleft--;
+ ::_decode_simple(dname[dleft], p);
+ ::_decode_simple(dlease[dleft], p);
+ dst[dleft]._decode(p);
+ goto inode;
+
+ done:
+
+ // insert into cache --
+ // first inode
Inode *curi = 0;
- inodeno_t ino = (*pin)->inode.ino;
+ inodeno_t ino = ist[0].inode.ino;
if (!root && ino == 1) {
- curi = root = new Inode((*pin)->inode, objectcacher);
+ curi = root = new Inode(ist[0].inode, objectcacher);
dout(10) << "insert_trace new root is " << root << dendl;
inode_map[ino] = root;
root->dir_auth = 0;
assert(inode_map.count(ino));
curi = inode_map[ino];
}
- update_inode(curi, *pin, ttl);
- pin++;
+ update_inode(curi, &ist[0], &ilease[0], from);
- while (pdir != reply->get_trace_dir().end()) {
+ for (unsigned i=0; i<numd; i++) {
Dir *dir = curi->open_dir();
- assert(pdn != reply->get_trace_dn().end());
- if (pin == reply->get_trace_in().end()) {
- dout(10) << "insert_trace " << *pdn << " mask " << *pdnmask
+
+ // in?
+ if (i+1 == numi) {
+ dout(10) << "insert_trace " << dname[i] << " mask " << dlease[i].mask
<< " -- NULL dentry caching not supported yet, IMPLEMENT ME" << dendl;
//insert_null_dentry(dir, *pdn, *pdnmask, ttl); // fixme
break;
}
- curi = insert_dentry_inode(dir, *pdn, *pdnmask, *pin, ttl);
- update_dir_dist(curi, *pdir); // dir stat info is attached to inode...
- pdn++;
- pdnmask++;
- pin++;
- pdir++;
+
+ curi = insert_dentry_inode(dir, dname[i], &dlease[i], &ist[i+1], &ilease[i+1], from);
+ update_dir_dist(curi, &dst[i]); // dir stat info is attached to inode...
}
+ assert(p.end());
return curi;
}
-MClientReply *Client::make_request(MClientRequest *req, Inode **ppin, int use_mds)
+MClientReply *Client::make_request(MClientRequest *req, Inode **ppin, utime_t *pfrom, int use_mds)
{
// time the call
utime_t start = g_clock.real_now();
// insert trace
- if (reply->get_result() >= 0) {
- utime_t ttl = request.sent_stamp;
- float dur = (float)reply->get_lease_duration_ms() / 1000.0;
- ttl += dur;
- dout(20) << "make_request got ttl of " << ttl
- << " (sent_stamp " << request.sent_stamp
- << " + " << dur << "s"
- << ")" << dendl;
- Inode *in = insert_trace(reply, ttl);
- if (ppin)
- *ppin = in;
- }
+ utime_t from = request.sent_stamp;
+ if (pfrom)
+ *pfrom = from;
+ Inode *in = insert_trace(reply, from);
+ if (ppin)
+ *ppin = in;
// -- log times --
if (client_logger) {
req->set_caller_uid(getuid());
req->set_caller_gid(getgid());
- MClientReply *reply = make_request(req);
+ Inode *diri;
+ utime_t from;
+ MClientReply *reply = make_request(req, &diri, &from);
int res = reply->get_result();
- inodeno_t ino = reply->get_ino();
// did i get directory inode?
- Inode *diri = 0;
- if ((res == -EAGAIN || res == 0) &&
- inode_map.count(ino)) {
- diri = inode_map[ino];
+ if ((res == -EAGAIN || res == 0) && diri) {
dout(10) << "_readdir_get_frag got diri " << diri << " " << diri->inode.ino << dendl;
- assert(diri);
assert(diri->inode.is_dir());
}
if (!dirp->inode && diri) {
dout(10) << "_readdir_get_frag attaching inode" << dendl;
- dirp->inode = inode_map[ino];
+ dirp->inode = diri;
diri->get();
}
}
// the rest?
- if (!reply->get_dir_dn().empty()) {
+ bufferlist::iterator p = reply->get_dir_bl().begin();
+ if (!p.end()) {
// only open dir if we're actually adding stuff to it!
Dir *dir = diri->open_dir();
assert(dir);
- utime_t ttl = g_clock.real_now();
- ttl += 60.0;
-
- list<InodeStat*>::const_iterator pin = reply->get_dir_in().begin();
- for (list<string>::const_iterator pdn = reply->get_dir_dn().begin();
- pdn != reply->get_dir_dn().end();
- ++pdn, ++pin) {
- // count entries
- res++;
-
- // put in cache
- Inode *in = this->insert_dentry_inode(dir, *pdn, 0, *pin, ttl);
-
- // contents to caller too!
- dout(15) << "_readdir_get_frag got " << *pdn << " to " << in->inode.ino << dendl;
- _readdir_add_dirent(dirp, *pdn, in);
- }
+ // dirstat
+ DirStat dst(p);
+ __u32 numdn;
+ ::_decode_simple(numdn, p);
+
+ string dname;
+ LeaseStat dlease, ilease;
+ while (numdn) {
+ ::_decode_simple(dname, p);
+ ::_decode_simple(dlease, p);
+ InodeStat ist(p);
+ ::_decode_simple(ilease, p);
+
+ // cache
+ Inode *in = this->insert_dentry_inode(dir, dname, &dlease, &ist, &ilease, from);
+
+ // caller
+ dout(15) << "_readdir_get_frag got " << dname << " to " << in->inode.ino << dendl;
+ _readdir_add_dirent(dirp, dname, in);
+
+ numdn--;
+ }
+
if (dir->is_empty())
close_dir(dir);
}
in->add_open(cmode); // make note of pending open, since it effects _wanted_ caps.
}
- MClientReply *reply = make_request(req);
+ in = 0;
+ MClientReply *reply = make_request(req, &in);
assert(reply);
int result = reply->get_result();
f->mode = cmode;
// inode
- f->inode = inode_map[reply->get_ino()];
- assert(f->inode);
+ assert(in);
+ f->inode = in;
f->inode->get();
if (!in) {
*
*/
+
+struct LeaseStat {
+ // this matches ceph_mds_reply_lease
+ __u16 mask;
+ __u32 duration_ms;
+};
+
struct DirStat {
// mds distribution hints
frag_t frag;
class MClientReply : public Message {
// reply data
struct ceph_mds_reply_head st;
-
- /*
- list<InodeStat*> trace_in;
- list<DirStat*> trace_dir;
- list<string> trace_dn;
- list<char> trace_dn_mask;
- */
bufferlist trace_bl;
-
- DirStat *dir_dir;
- list<InodeStat*> dir_in;
- list<string> dir_dn;
bufferlist dir_bl;
public:
int get_result() { return st.result; }
- inodeno_t get_ino() { return trace_in.back()->inode.ino; }
- const inode_t& get_inode() { return trace_in.back()->inode; }
-
unsigned char get_file_caps() { return st.file_caps; }
long get_file_caps_seq() { return st.file_caps_seq; }
//uint64_t get_file_data_version() { return st.file_data_version; }
void set_file_caps_seq(long s) { st.file_caps_seq = s; }
//void set_file_data_version(uint64_t v) { st.file_data_version = v; }
- MClientReply() : dir_dir(0) {}
+ MClientReply() {}
MClientReply(MClientRequest *req, int result = 0) :
- Message(CEPH_MSG_CLIENT_REPLY), dir_dir(0) {
+ Message(CEPH_MSG_CLIENT_REPLY) {
memset(&st, 0, sizeof(st));
this->st.tid = cpu_to_le64(req->get_tid());
this->st.op = req->get_op();
this->st.result = result;
}
- virtual ~MClientReply() {
- list<InodeStat*>::iterator it;
-
- for (it = trace_in.begin(); it != trace_in.end(); ++it)
- delete *it;
- for (it = dir_in.begin(); it != dir_in.end(); ++it)
- delete *it;
- }
const char *get_type_name() { return "creply"; }
void print(ostream& o) {
o << "creply(" << env.dst.name << "." << le64_to_cpu(st.tid);
// dir contents
- void take_dir_items(bufferlist& bl) {
+ void set_dir_bl(bufferlist& bl) {
dir_bl.claim(bl);
}
- void _decode_dir() {
- bufferlist::iterator p = dir_bl.begin();
- dir_dir = new DirStat(p);
- __u32 num;
- ::_decode_simple(num, p);
- while (num--) {
- string dn;
- ::_decode_simple(dn, p);
- dir_dn.push_back(dn);
- dir_in.push_back(new InodeStat(p));
- }
- assert(p.end());
- }
-
- const list<InodeStat*>& get_dir_in() {
- if (dir_in.empty() && dir_bl.length()) _decode_dir();
- return dir_in;
+ bufferlist &get_dir_bl() {
+ return dir_bl;
}
- const list<string>& get_dir_dn() {
- if (dir_dn.empty() && dir_bl.length()) _decode_dir();
- return dir_dn;
- }
- const DirStat* get_dir_dir() {
- return dir_dir;
- }
-
// trace
- void set_trace(__u16 numi, __u16 numdn, bufferlist& bl) {
- ::_encode_simple(numi, trace_bl);
- ::_encode_simple(numdn, trace_bl);
- trace_bl.claim_append(bl);
+ void set_trace(bufferlist& bl) {
+ trace_bl.claim(bl);
}
bufferlist& get_trace_bl() {
return trace_bl;
}
- /*
- void _decode_trace() {
- bufferlist::iterator p = trace_bl.begin();
- __u16 numi, numdn;
- string ref_dn;
- char dn_mask;
-
- ::_decode_simple(numi, p);
- ::_decode_simple(numdn, p);
- if (numi == numdn)
- goto dentry;
-
- inode:
- // inode
- trace_in.push_front(new InodeStat(p));
- if (--numi == 0) goto done;
-
- dentry:
- // dentry, dir
- ::_decode_simple(ref_dn, p);
- ::_decode_simple(dn_mask, p);
- trace_dn.push_front(ref_dn);
- trace_dn_mask.push_front(dn_mask);
- trace_dir.push_front(new DirStat(p));
- numdn--;
- goto inode;
-
- done:
- assert(p.end());
- }
-
- bool have_trailing_inode() {
- return trace_in.size() > trace_dn.size();
- }
-
- const list<InodeStat*>& get_trace_in() {
- if (trace_in.empty() && trace_bl.length()) _decode_trace();
- return trace_in;
- }
- const list<DirStat*>& get_trace_dir() {
- if (trace_in.empty() && trace_bl.length()) _decode_trace();
- return trace_dir;
- }
- const list<string>& get_trace_dn() {
- if (trace_in.empty() && trace_bl.length()) _decode_trace();
- return trace_dn;
- }
- const list<char>& get_trace_dn_mask() {
- if (trace_in.empty() && trace_bl.length()) _decode_trace();
- return trace_dn_mask;
- }
- */
-
};
#endif