// unix-ey fs stuff
#include <sys/types.h>
+#include <time.h>
#include <utime.h>
messenger->shutdown();
}
+// insert inode info into metadata cache
+
+Inode* Client::insert_inode_info(Dir *dir, c_inode_info *in_info)
+{
+ string dname = in_info->ref_dn;
+ Dentry *dn = NULL;
+ if (dir->dentries.count(dname))
+ dn = dir->dentries[dname];
+ dout(12) << "insert_inode_info " << dname << " ino " << in_info->inode.ino << endl;
+
+ if (dn) {
+ if (dn->inode->inode.ino == in_info->inode.ino) {
+ touch_dn(next);
+ dout(12) << " had dentry " << dname << " with correct ino " << dn->inode->inode.ino << endl;
+ } else {
+ dout(12) << " had dentry " << dname << " with WRONG ino " << dn->inode->inode.ino << endl;
+ unlink(dn);
+ dn = NULL;
+ }
+ }
+
+ if (!dn) {
+ if (inode_map.count(in_info->inode.ino)) {
+ Inode *in = inode_map[in_info->inode.ino];
+ if (in) {
+ dout(12) << " had ino " << dn->inode->inode.ino << " at wrong position, moving" << endl;
+ if (in->dn) unlink(in->dn);
+ dn = link(dir, dname, in);
+ }
+ }
+ }
+
+ if (!dn) {
+ dn = link(dir, dname, new Inode());
+ dn->inode->inode = in_info->inode;
+ inode_map[dn->inode->inode.ino] = dn->inode;
+ dout(12) << " new dentry+node with ino " << dn->inode->inode.ino << endl;
+ }
+
+ // take note of latest distribution on mds's
+ dn->inode->mds_contacts = in_info->dist;
+
+ return dn->inode;
+}
+
// insert trace of reply into metadata cache
void Client::insert_trace(vector<c_inode_info*> trace)
{
Inode *cur = root;
+ time_t now = time(NULL);
+ if (!trace) return;
+
for (int i=0; i<trace.size(); i++) {
- if (i == 0) {
- if (!root) {
- cur = root = new Inode();
- root->inode = trace[i]->inode;
- inode_map[root->inode.ino] = root;
- }
- dout(12) << "insert_trace trace " << i << " root" << endl;
- } else {
- Dir *dir = open_dir( cur );
- string dname = trace[i]->ref_dn;
- Dentry *next = NULL;
- if (dir->dentries.count(dname))
- next = dir->dentries[dname];
- dout(12) << "insert_trace trace " << i << " dname " << dname << " ino " << trace[i]->inode.ino << endl;
-
- if (next) {
- if (next->inode->inode.ino == trace[i]->inode.ino) {
- touch_dn(next);
- dout(12) << " had dentry " << dname << " with correct ino " << next->inode->inode.ino << endl;
- } else {
- dout(12) << " had dentry " << dname << " with WRONG ino " << next->inode->inode.ino << endl;
- unlink(next);
- next = NULL;
- }
- }
-
- if (!next) {
- if (inode_map.count(trace[i]->inode.ino)) {
- Inode *in = inode_map[trace[i]->inode.ino];
- if (in) {
- dout(12) << " had ino " << next->inode->inode.ino << " at wrong position, moving" << endl;
- if (in->dn) unlink(in->dn);
- next = link(dir, dname, in);
- }
- }
- }
-
- if (!next) {
- next = link(dir, dname, new Inode());
- next->inode->inode = trace[i]->inode;
- inode_map[next->inode->inode.ino] = next->inode;
- dout(12) << " new dentry+node with ino " << next->inode->inode.ino << endl;
- }
-
- cur = next->inode;
- }
-
- // take note of latest distribution on mds's
- cur->mds_contacts = trace[i]->dist;
+ if (i == 0) {
+ if (!root) {
+ cur = root = new Inode();
+ root->inode = trace[i]->inode;
+ inode_map[root->inode.ino] = root;
+ }
+ root->mds_contacts = trace[i]->dist;
+ root->last_updated = now;
+ dout(12) << "insert_trace trace " << i << " root" << endl;
+ } else {
+ dout(12) << "insert_trace trace " << i;
+ Dir *dir = open_dir( cur );
+ cur = this->insert_inode_info(dir, trace[i]);
+ cur->last_updated = now;
+ }
}
}
MClientReply *reply = (MClientReply*)messenger->sendrecv(req, MSG_ADDR_MDS(0), MDS_PORT_SERVER);
int res = reply->get_result();
+ if (res == 0) {
+ unlink(lookup(req->get_filepath()));
+ }
+ this->insert_trace(reply->get_trace);
delete reply;
dout(10) << "unlink result is " << res << endl;
return res;
MClientReply *reply = (MClientReply*)messenger->sendrecv(req, MSG_ADDR_MDS(0), MDS_PORT_SERVER);
int res = reply->get_result();
+ this->insert_trace(reply->get_trace);
delete reply;
dout(10) << "rename result is " << res << endl;
return res;
MClientReply *reply = (MClientReply*)messenger->sendrecv(req, MSG_ADDR_MDS(0), MDS_PORT_SERVER);
int res = reply->get_result();
+ this->insert_trace(reply->get_trace);
delete reply;
dout(10) << "mkdir result is " << res << endl;
return res;
MClientReply *reply = (MClientReply*)messenger->sendrecv(req, MSG_ADDR_MDS(0), MDS_PORT_SERVER);
int res = reply->get_result();
+ if (res == 0) {
+ unlink(lookup(req->get_filepath()));
+ }
+ this->insert_trace(reply->get_trace);
delete reply;
dout(10) << "rmdir result is " << res << endl;
return res;
MClientReply *reply = (MClientReply*)messenger->sendrecv(req, MSG_ADDR_MDS(0), MDS_PORT_SERVER);
int res = reply->get_result();
+ this->insert_trace(reply->get_trace); //FIXME assuming trace of link, not of target
delete reply;
dout(10) << "symlink result is " << res << endl;
return res;
int Client::readlink(const char *path, char *buf, size_t size)
{
dout(3) << "readlink " << path << endl;
- // stat first (OR, FIXME, use cached value?) ****
+ // stat first (FIXME, PERF access cache directly) ****
struct stat stbuf;
int r = this->lstat(path, &stbuf);
if (r != 0) return r;
// inode stuff
int Client::lstat(const char *path, struct stat *stbuf)
-// FIXME make sure this implements lstat and not stat
{
dout(3) << "lstat " << path << endl;
+ // FIXME, PERF request allocation convenient but not necessary for cache hit
MClientRequest *req = new MClientRequest(MDS_OP_STAT, whoami);
req->set_path(path);
- // FIXME where does FUSE maintain user information
- req->set_caller_uid(getuid());
- req->set_caller_gid(getgid());
-
- MClientReply *reply = (MClientReply*)messenger->sendrecv(req, MSG_ADDR_MDS(0), MDS_PORT_SERVER);
- int res = reply->get_result();
- dout(10) << "lstat res is " << res << endl;
- if (res != 0) return res;
-
- //Transfer information from reply to stbuf
- vector<c_inode_info*> trace = reply->get_trace();
- inode_t inode = trace[trace.size()-1]->inode;
-
+ // check whether cache content is fresh enough
+ Dentry *dn = lookup(req->get_filepath());
+ inode_t inode;
+ if (dn && ((time(NULL) - dn->inode.last_updated) <= g_conf.client_cache_stat_ttl)) {
+ inode = dn->inode->inode;
+ dout(10) << "lstat cache hit" << endl;
+ } else {
+ // FIXME where does FUSE maintain user information
+ req->set_caller_uid(getuid());
+ req->set_caller_gid(getgid());
+
+ MClientReply *reply = (MClientReply*)messenger->sendrecv(req, MSG_ADDR_MDS(0), MDS_PORT_SERVER);
+ int res = reply->get_result();
+ dout(10) << "lstat res is " << res << endl;
+ if (res != 0) return res;
+
+ //Transfer information from reply to stbuf
+ vector<c_inode_info*> trace = reply->get_trace();
+ inode = trace[trace.size()-1]->inode;
+
+ //Update metadata cache
+ this->insert_trace(trace);
+ }
+
memset(stbuf, 0, sizeof(struct stat));
//stbuf->st_dev =
stbuf->st_ino = inode.ino;
// gross HACK for now.. put an Inode in cache!
// for now i just need to put the symlink content somewhere (so that readlink() will work)
- Inode *in = new Inode;
- inode_map[inode.ino] = in; // put in map so subsequent readlink will find it
- in->inode = inode;
+ //Inode *in = new Inode;
+ //inode_map[inode.ino] = in; // put in map so subsequent readlink will find it
+ //in->inode = inode;
// symlink?
+ Inode *in = inode_map[inode.ino];
if (in->inode.mode & INODE_MODE_SYMLINK) {
if (!in->symlink) in->symlink = new string;
*(in->symlink) = trace[trace.size()-1]->symlink;
dout(1) << "stat sez uid = " << inode.uid << " ino = " << stbuf->st_ino << endl;
- // FIXME need to update cache with trace's inode_info
delete reply;
return 0;
}
MClientReply *reply = (MClientReply*)messenger->sendrecv(req, MSG_ADDR_MDS(0), MDS_PORT_SERVER);
int res = reply->get_result();
+ this->insert_trace(reply->get_trace);
delete reply;
dout(10) << "chmod result is " << res << endl;
return res;
MClientReply *reply = (MClientReply*)messenger->sendrecv(req, MSG_ADDR_MDS(0), MDS_PORT_SERVER);
int res = reply->get_result();
+ this->insert_trace(reply->get_trace);
delete reply;
dout(10) << "chown result is " << res << endl;
return res;
MClientReply *reply = (MClientReply*)messenger->sendrecv(req, MSG_ADDR_MDS(0), MDS_PORT_SERVER);
int res = reply->get_result();
+ this->insert_trace(reply->get_trace);
delete reply;
dout(10) << "utime result is " << res << endl;
return res;
MClientReply *reply = (MClientReply*)messenger->sendrecv(req, MSG_ADDR_MDS(0), MDS_PORT_SERVER);
int res = reply->get_result();
+ vector<c_inode_info*> trace = reply->get_trace();
+ this->insert_trace(trace);
+
+ if (res) return res;
- // dir contents to caller!
+ // dir contents to cache!
+ Dir *dir = open_dir(inode_map[trace[trace.size()-1]->inode.ino]);
+ time_t now = time(NULL);
vector<c_inode_info*>::iterator it;
for (it = reply->get_dir_contents().begin();
it != reply->get_dir_contents().end();
it++) {
// put in cache
-
- contents[(*it)->ref_dn] = &(*it)->inode; // FIXME don't use one from reply!
+ Inode *in = this->insert_inode_info(dir, *it);
+ in->last_updated = now;
+ }
+
+ // dir contents to caller -- some of them might not have been in reply!
+ hash_map<string, *Dentry>::iterator it;
+ for (it = dir->dentries.begin();
+ it != dir->dentries.end();
+ it++) {
+ contents[it->first] = it->second->inode->inode;
}
- //delete reply; fix thing above first
+ delete reply; fix thing above first
return res;
}