/** * Update <key, oldval> with <key, val> */ int zht_update(const char *key, const char *val) { log_msg("cshou debug === zht_update: key = %s, value = %s\n", key, val); return zht_insert(key, val); char res[ZHT_MAX_BUFF] = {0}; int stat = zht_lookup(key, res); if (ZHT_LOOKUP_FAIL == stat) { int insert_res = zht_insert(key, val); if (insert_res) { log_msg("DFZ debug: zht_update() _insert() failed code %d. \n\n", insert_res); return -1; } return 0; } int remove_res = zht_remove(key); log_msg("DFZ debug: zht_update() - remove_res = %d. \n\n", remove_res); int insert_res = zht_insert(key, val); log_msg("DFZ debug: zht_update() - insert_res = %d. \n\n", insert_res); char newval[ZHT_MAX_BUFF] = {0}; int status = zht_lookup(key, newval); log_msg("DFZ debug: zht_update() - status = %d. \n\n", status); if (ZHT_LOOKUP_FAIL == status) log_msg("DFZ debug: zht_update() - key %s not found. \n\n", key); else log_msg("DFZ debug: zht_update() - key = %s, newval = %s. \n\n", key, newval); return 0; }
/** * FUSE document: * * Create and open a file * * If the file does not exist, first create it with the specified * mode, and then open it. * * If this method is not implemented or under Linux kernel * versions earlier than 2.6.15, the mknod() and open() methods * will be called instead. * * Introduced in version 2.5 * * ***************************************************************** * DFZ: * In fusionFS, a file creation always happens in the local node */ int fusion_create(const char *path, mode_t mode, struct fuse_file_info *fi) { int retstat = 0; char fpath[PATH_MAX] = {0}; int fd; log_msg("\nfusion_create(path=\"%s\", mode=0%03o, fi=0x%08x)\n", path, mode, fi); fusion_fullpath(fpath, path); /*if <path> exists in ZHT, we should return at this point*/ char res[ZHT_MAX_BUFF] = {0}; int stat = zht_lookup(path, res); if (ZHT_LOOKUP_FAIL == stat) { log_msg("\n================DFZ ERROR: file already exists. \n"); return -1; } /*create the local file*/ fd = creat(fpath, mode); if (fd < 0) retstat = fusion_error("fusion_create creat"); fi->fh = fd; log_fi(fi); /*add the filename to its parent path in the ZHT entry*/ char dirname[PATH_MAX] = {0}; char *pch = strrchr(path, '/'); strncpy(dirname, path, pch - path + 1); log_msg("\n================DFZ debug: dirname = %s \n", dirname); char oldval[ZHT_MAX_BUFF] = {0}; stat = zht_lookup(dirname, oldval); if (ZHT_LOOKUP_FAIL == stat) { log_msg("\n================DFZ ERROR: no parent path exists. \n"); return -1; } log_msg("\n================DFZ debug: oldval = %s. \n", oldval); zht_append(dirname, pch + 1); // log_msg("cshou debug ==== dirname=%s, filename=%s\n", dirname, pch + 1); /*insert <path, ip_addr> into ZHT */ char addr[PATH_MAX] = {0}; net_getmyip(addr); log_msg("\n================DFZ debug _create(): addr = %s. \n", addr); if (zht_insert(path, addr)) log_msg("\n================ERROR _create(): failed to insert <%s, %s> to ZHT. \n", path, addr); char myaddr[PATH_MAX] = {0}; net_getmyip(myaddr); spade_create(myaddr, fpath, fuse_get_context()->pid); return retstat; }
/** * Update <key, oldval> with <key, val> */ int zht_update(const char *key, const char *val) { // /*DFZ debug*/ // char oldval[PATH_MAX] = {0}; // int status = zht_lookup(key, oldval); // log_msg("DFZ debug: zht_update() - status = %d. \n\n", status); // if (ZHT_LOOKUP_FAIL == status) // log_msg("DFZ debug: zht_update() - key %s not found. \n\n", key); // else // log_msg("DFZ debug: zht_update() - key = %s, oldval = %s. \n\n", key, oldval); /*ZHT supports update semantics now: */ return zht_insert(key, val); char res[ZHT_MAX_BUFF] = {0}; int stat = zht_lookup(key, res); if (ZHT_LOOKUP_FAIL == stat) { int insert_res = zht_insert(key, val); if (insert_res) { log_msg("DFZ debug: zht_update() _insert() failed code %d. \n\n", insert_res); return -1; } return 0; } int remove_res = zht_remove(key); log_msg("DFZ debug: zht_update() - remove_res = %d. \n\n", remove_res); // /*DFZ debug*/ // status = zht_lookup(key, oldval); // if (ZHT_LOOKUP_FAIL == status) // log_msg("DFZ debug: zht_update() - key %s not found. \n\n", key); // else // log_msg("DFZ debug: zht_update() - key = %s, oldval = %s. \n\n", key, oldval); // // log_msg("DFZ debug: zht_update() - key = %s, val = %s. \n\n", key, val); int insert_res = zht_insert(key, val); log_msg("DFZ debug: zht_update() - insert_res = %d. \n\n", insert_res); char newval[ZHT_MAX_BUFF] = {0}; int status = zht_lookup(key, newval); log_msg("DFZ debug: zht_update() - status = %d. \n\n", status); if (ZHT_LOOKUP_FAIL == status) log_msg("DFZ debug: zht_update() - key %s not found. \n\n", key); else log_msg("DFZ debug: zht_update() - key = %s, newval = %s. \n\n", key, newval); return 0; }
/** * Remove a file * * DFZ: two ways to unlink remote files: * 1) [Accepted] add a "unlink request" service type in the ffsnetd daemon process * 2) don't touch the remote file when updating the meta data, but do a batch job in each node to * self-check dangling files */ int fusion_unlink(const char *path) { int retstat = 0; char fpath[PATH_MAX] = {0}; log_msg("fusion_unlink(path=\"%s\")\n", path); fusion_fullpath(fpath, path); /*remove the file from its parent dir in ZHT*/ char dirname[PATH_MAX] = {0}, fname[PATH_MAX] = {0}; char *pch = strrchr(path, '/'); strncpy(dirname, path, pch - path + 1); strcpy(fname, pch + 1); zht_delete(dirname, fname); /*remove the file entry from ZHT*/ char oldaddr[PATH_MAX] = {0}; zht_lookup(path, oldaddr); zht_remove(path); /*DFZ: Uncomment the following for only metadata benchmark, i.e. don't really remove anything*/ return 0; /*if this file doesn't exist*/ char val[ZHT_MAX_BUFF] = {0}; int stat = zht_lookup(path, val); if (ZHT_LOOKUP_FAIL == stat) { fusion_error("_unlink() trying to remove a nonexistent file"); return -1; } /* * The following is to really remove the file */ /*if it's a local operation, we are done here*/ char myip[PATH_MAX] = {0}; net_getmyip(myip); if (!strcmp(myip, oldaddr)) { log_msg("\n DFZ debug: _unlink() local unlink.\n\n"); retstat = unlink(fpath); if (retstat < 0) retstat = fusion_error("fusion_unlink unlink"); return retstat; } log_msg("\n DFZ debug: _unlink() remote rmfile.\n\n"); /*or we need to remove the remote file*/ ffs_rmfile_c("udt", oldaddr, "9000", fpath); return retstat; }
/** * <key, oldval> -> <key, (oldval - val)> */ int zht_delete(const char *key, const char *val) { char newval[ZHT_MAX_BUFF] = {0}; char search[PATH_MAX] = {0}; char oldval[ZHT_MAX_BUFF] = {0}; zht_lookup(key, oldval); strcpy(search, " "); strcat(search, val); strcat(search, " "); char *pch = strstr(oldval, search); /*if for some reason val doesn't exist, we are doen here*/ if (!pch) return 0; strncpy(newval, oldval, pch - oldval); strcat(newval, " "); strcat(newval, pch + strlen(search)); zht_update(key, newval); return 0; }
/** Open directory * * This method should check if the open operation is permitted for * this directory * * Introduced in version 2.3 */ int fusion_opendir(const char *path, struct fuse_file_info *fi) { DIR *dp; int retstat = 0; char fpath[PATH_MAX] = {0}; log_msg("\nfusion_opendir(path=\"%s\", fi=0x%08x)\n", path, fi); fusion_fullpath(fpath, path); /*if path exists in ZHT, create it locally*/ char res[ZHT_MAX_BUFF] = {0}; int stat = zht_lookup(path, res); if (ZHT_LOOKUP_FAIL != stat) { mkdir(fpath, 0775); } else { /*TODO*/ fusion_error("_opendir() failed: <fpath> not found in ZHT"); } dp = opendir(fpath); if (dp == NULL) retstat = fusion_error("fusion_opendir opendir"); fi->fh = (intptr_t) dp; log_fi(fi); return retstat; }
int Worker::update_nodehistory(uint32_t currnode, string alltasks) { int num_vector_count, per_vector_count; vector<vector<string> > tokenize_string = tokenize(alltasks, '\"', '\'', num_vector_count, per_vector_count); uint32_t num_nodes = svrclient.memberList.size(); //cout << "Worker = " << selfIndex << " num_vector_count = " << num_vector_count << " per_vector_count = " << per_vector_count << endl; for (int i = 0; i < num_vector_count; i++) { for (int j = 0; j < per_vector_count; j++) { try { string &taskid = tokenize_string.at(i).at(j); string value = zht_lookup(taskid); Package recv_pkg; recv_pkg.ParseFromString(value); int index = myhash(taskid.c_str(), num_nodes); if (index != selfIndex) { cout << "something wrong..doing remote update_nodehistory index = " << index << " selfIndex = " << selfIndex << endl; } // update number of moves (increment) uint32_t old_nummoves = recv_pkg.nummoves(); recv_pkg.set_nummoves(old_nummoves + 1); // update current location of task recv_pkg.set_currnode(currnode); // update task migration history stringstream nodehistory_ss; nodehistory_ss << currnode << "\'"; string new_nodehistory(nodehistory_ss.str()); new_nodehistory.append(recv_pkg.nodehistory()); //cout << "update_nodehistory: task " << recv_pkg.virtualpath() << " node history = " << recv_pkg.nodehistory(); recv_pkg.set_nodehistory(new_nodehistory); //cout << " node history = " << recv_pkg.nodehistory() << endl; // insert updated task into ZHT int ret = zht_insert(recv_pkg.SerializeAsString()); if (ret != 0) { cout << "update_nodehistory: zht_insert error ret = " << ret << endl; exit(1); } } catch (exception& e) { cout << "update_nodehistory: (tokenize_string.at(i).at(0)) " << " " << e.what() << endl; exit(1); } } } return 0; }
int Worker::update_numwait(string alltasks) { int num_vector_count, per_vector_count; vector<vector<string> > tokenize_string = tokenize(alltasks, '\"', '\'', num_vector_count, per_vector_count); uint32_t num_nodes = svrclient.memberList.size(); for (int i = 0; i < num_vector_count; i++) { for (int j = 0; j < per_vector_count; j++) { try { string &taskid = tokenize_string.at(i).at(j); string value = zht_lookup(taskid); Package recv_pkg; recv_pkg.ParseFromString(value); int index = myhash(taskid.c_str(), num_nodes); if (index != selfIndex) { cout << "something wrong..doing remote update_numwait: index = " << index << " selfIndex = " << selfIndex << endl; } // update number of tasks to wait (decrement) uint32_t old_numwait = recv_pkg.numwait(); recv_pkg.set_numwait(old_numwait - 1); notr++; if (LOGGING) { if (old_numwait - 1 == 0) { log_fp << "task = " << taskid << " is ready" << endl; } } // insert updated task into ZHT int ret = zht_insert(recv_pkg.SerializeAsString()); if (ret != 0) { cout << "update_numwait: old_numwait = " << old_numwait << endl; cout << "update_numwait: zht_insert error ret = " << ret << " key = " << taskid << " index = " << index << " selfindex = " << selfIndex << endl; exit(1); } } catch (exception& e) { cout << "update_numwait: (tokenize_string.at(i).at(0)) " << " " << e.what() << endl; exit(1); } } } log_fp << "notr = " << notr << endl; return 0; }
/** * <key, oldval> -> <key, (oldval + val)> */ int zht_append(const char *key, const char *val) { char newval[ZHT_MAX_BUFF] = {0}; char oldval[ZHT_MAX_BUFF] = {0}; zht_lookup(key, oldval); strcpy(newval, oldval); strcat(newval, val); strcat(newval, " "); zht_update(key, newval); return 0; }
/** * Remove a directory * * DFZ: updated for ZHT * * TODO: deleting a non-empty directory will cause some problems */ int fusion_rmdir(const char *path) { int retstat = 0; char fpath[PATH_MAX] = {0}; log_msg("fusion_rmdir(path=\"%s\")\n", path); fusion_fullpath(fpath, path); /*check ZHT if <path/> is empty */ char dirname[PATH_MAX] = {0}; strcpy(dirname, path); strcat(dirname, "/"); char val[ZHT_MAX_BUFF] = {0}; int stat = zht_lookup(dirname, val); if (ZHT_LOOKUP_FAIL != stat && !strcmp(" ", val)) { char rmcmd[PATH_MAX] = {0}; strcpy(rmcmd, "rm -r "); strcat(rmcmd, fpath); system(rmcmd); } else { fusion_error("fusion_rmdir() directory not empty or not a directory"); return -1; } // retstat = rmdir(fpath); // if (retstat < 0) // retstat = fusion_error("fusion_rmdir rmdir"); /* update ZHT */ char parentpath[PATH_MAX] = {0}; char curpath[PATH_MAX] = {0}; char fullpath[PATH_MAX] = {0}; char *pch = strrchr(path, '/'); strncpy(parentpath, path, pch - path + 1); strcpy(curpath, pch + 1); strcat(curpath, "/"); strcpy(fullpath, path); strcat(fullpath, "/"); log_msg("\n==========DFZ debug: fusion_rmdir() parentpath = %s, curpath = %s \n\n", parentpath, curpath); zht_delete(parentpath, curpath); zht_remove(fullpath); return retstat; }
int Worker::check_if_task_is_ready(string key) { int index = myhash(key.c_str(), svrclient.memberList.size()); if (index != selfIndex) { Package check_package; check_package.set_virtualpath(key); check_package.set_operation(23); string check_str = check_package.SerializeAsString(); pthread_mutex_lock(&msg_lock); int ret = svrclient.svrtosvr(check_str, check_str.size(), index); pthread_mutex_unlock(&msg_lock); return ret; } else { string value = zht_lookup(key); Package check_package; check_package.ParseFromString(value); return check_package.numwait(); } }
/** Release an open file * * Release is called when there are no more references to an open * file: all file descriptors are closed and all memory mappings * are unmapped. * * For every open() call there will be exactly one release() call * with the same flags and file descriptor. It is possible to * have a file opened more than once, in which case only the last * release will mean, that no more reads/writes will happen on the * file. The return value of release is ignored. * * Changed in version 2.2 * * ***************************************************************** * DFZ: this is equivalent to fclose(). Nothing is surprising unless * it modifies the file. In this case we need to make the node * who modifies the file as the new location of this file, as * to update the value in ZHT. We also need to remove the old * copy in its previous node from where it's copied from. */ int fusion_release(const char *path, struct fuse_file_info *fi) { pid_t pid = fuse_get_context()->pid; log_msg("=====cshou debug fusion_release: can we get pid here ? %d\n", pid); int retstat = 0; char fpath[PATH_MAX] = {0}; fusion_fullpath(fpath, path); log_msg("\nfusion_release(path=\"%s\", fi=0x%08x)\n", path, fi); log_fi(fi); /*is this file written?*/ int iswritten = 0; int flags = fcntl(fi->fh, F_GETFL); if (-1 == flags) { /*I don't know what to do... failed to get the old flags */ fusion_error("_release(): fd lost. "); } /* O_ACCMODE<0003>????д?ļ?????ʱ??????ȡ??flag?ĵ?2λ O_RDONLY<00>??ֻ?????? O_WRONLY<01>??ֻд???? O_RDWR<02>????д???? */ else if (O_ACCMODE & flags) { iswritten = 1; } /*if this is just a local IO, we are all set*/ char myip[PATH_MAX] = {0}; net_getmyip(myip); // if (iswritten) { // spade_write(myip, fpath, pid, 0, 0); // } // else { // spade_read(myip, fpath, pid, 0, 0); // } // We need to close the file. Had we allocated any resources // (buffers etc) we'd need to free them here as well. retstat = close(fi->fh); /*dealing with the remote copy*/ if (iswritten) { /*so it's a write mode*/ char oldip[PATH_MAX] = {0}; int stat = zht_lookup(path, oldip); /*if path doesn't exist in ZHT, try to remove it locally */ if (ZHT_LOOKUP_FAIL == stat) { unlink(fpath); return 0; } /*DFZ: test GPU erasure */ /*update m to be the number of (redundant) parities*/ int ida_on = 1, m = 3, n = 8 - m; /*assuming we use all 8 available Cosmos nodes*/ if (ida_on) { log_msg("start testing GPU erasure.\n"); gib_context gc; long bs = 1024 * 1024; /* block size */ /*read the file into buffer*/ FILE *f = fopen(fpath, "r"); fseek(f, 0, SEEK_END); long fsize = ftell(f); fseek(f, 0, SEEK_SET); char *string = malloc(fsize + 1); fread(string, fsize, 1, f); fclose(f); string[fsize] = 0; log_msg("before git_init(). \n"); if (n >= 2 && (n + m) <= 8) /*Gibraltar lib requires both n and m larger than 2; Cosmos has 8 GPU nodes available*/ { int rc = gib_init(m, n, &gc); log_msg("after git_init(). \n"); if (rc) { log_msg("error in gib_init().\n"); } void *data; gib_alloc(&data, bs, &bs, gc); memcpy(data, string, fsize); gib_generate(data, bs, gc); /*send data chunks to n+m-1 nodes*/ int i = 0; for (i = 0; i < n + m; i++) { char suffix[16] = {0}; sprintf(suffix, "%d", i); char new_filename[256] = {0}; strcpy(new_filename, fpath); strcat(new_filename, suffix); FILE *fh = fopen(new_filename, "w"); fwrite(i * bs + data, 1, bs, fh); fclose(fh); /*send out all new_filename to n+m-1 nodes*/ if (!i) continue; /* don't worry about the first chunk */ char member[16] = {0}; member[0] = 'p'; char idx[2] = {0}; sprintf(idx, "%d", i + 3); /*Cosmos node starts from p3*/ strcat(member, idx); ffs_sendfile_c("udt", member, "9000", new_filename, new_filename); } /*DFZ: test only. To recover the failed parity char buff_id[256] = {'1'}; gib_recover(data, bs, buff_id, m, gc); */ gib_free(data, gc); gib_destroy(gc); log_msg("GPU erasure successful. \n"); } } /*traditinal data replication*/ else { int i = 0; for (i = 0; i < m; i++) { char member[16] = {0}; member[0] = 'p'; char idx[2] = {0}; sprintf(idx, "%d", i + 4); /*primary copy on p3, replicas on p4-p10*/ strcat(member, idx); ffs_sendfile_c("udt", member, "9000", fpath, fpath); } } /*DFZ: end of GPU erasure test*/ char nodeaddr[PATH_MAX] = {0}; zht_lookup(path, nodeaddr); if (!strcmp(myip, nodeaddr)) { return retstat; } /*update this file's node value in ZHT*/ char myip[PATH_MAX] = {0}; net_getmyip(myip); zht_update(path, myip); /*TODO: potentially, need to update the parent directory in ZHT * because the physical directory is also created in the new node*/ /*remove the file from its old node*/ /****************************************************************************** * DFZ: I want a more conservative way to clean dirty copies, so the following * remote removal is deferred for now. * * In other words just like the redundant directories, dirty files will be * removed when its parent directory is removed from ZHT * *******************************************************************************/ // ffs_rmfile_c("udt", oldip, "9000", fpath); // invoke spade // spade_write(myip, fpath, fuse_get_context()->pid, 0, 0); } else { /*read-only file*/ /* we don't want o keep a redundant copy in local node to * prevent from the issue on removing multiple files * across different nodes. So, we remove the local file */ unlink(fpath); log_msg("\n=========DFZ debug _release(): %s unlinked from local node. \n\n", fpath); // invoke spade // spade_read(myip, fpath, fuse_get_context()->pid, 0, 0); } return retstat; }
/** Get file attributes. * * Similar to stat(). The 'st_dev' and 'st_blksize' fields are * ignored. The 'st_ino' field is ignored except if the 'use_ino' * mount option is given. * * DFZ: This is the first function to be called whenever the user tries to * get access to any file, even if only to its meta data. Two cases: * 1) if the file exists, i.e. it's stored in ZHT, then this file is * transfered to the local node first and 'lstat' the local copy * 2) if the file doesn't exist, FUSE will pass the control to * _create() */ int fusion_getattr(const char *path, struct stat *statbuf) { int retstat = 0; char fpath[PATH_MAX] = {0}; log_msg("\nfusion_getattr(path=\"%s\", statbuf=0x%08x)\n", path, statbuf); fusion_fullpath(fpath, path); char res[ZHT_MAX_BUFF] = {0}; int status = zht_lookup(path, res); char myaddr[PATH_MAX] = {0}; net_getmyip(myaddr); bool is_transfer = false; log_msg("\n ===========CSHOU debug: _getattr() the local IP got: %s \n\n", myaddr); if (ZHT_LOOKUP_FAIL == status) { /* if not found in ZHT */ log_msg("\n ===========DFZ debug: _getattr() %s does not exist \n\n", path); /*if path is an existing directory*/ char dirname[PATH_MAX] = {0}; strcpy(dirname, path); strcat(dirname, "/"); log_msg("\n ===========DFZ debug: _getattr() dirname = %s. \n\n", dirname); char res[ZHT_MAX_BUFF] = {0}; int stat = zht_lookup(dirname, res); if (ZHT_LOOKUP_FAIL != stat) { log_msg("\n ===========DFZ debug: _getattr() res = %s. \n\n", res); mkdir(fpath, 0755); char cmd_mkdir[PATH_MAX] = {0}; strcpy(cmd_mkdir, "mkdir -p "); strcat(cmd_mkdir, fpath); system(cmd_mkdir); log_msg("\n ===========DFZ debug: _getattr() new directory %s/ created \n\n", fpath); } } else { /* if file exists in ZHT */ log_msg("\n ===========DFZ debug: _getattr() zht_lookup() = %s. \n\n", res); if (access(fpath, F_OK)) { /*if it isn't on this node, copy it over*/ ffs_recvfile_c("udt", res, "9000", fpath, fpath); // ADDED BY CSHOU //if (strcmp(res, myaddr) != 0 && strcmp(res, "") != 0) //if (strcmp(res, myaddr) != 0 && res && strlen(res) != 0) //is_transfer = true; //spade_receivefile(fpath, res, fpath, statbuf->st_size, statbuf->st_mtime); log_msg("\n ===========DFZ debug: _getattr() %s transferred from %s. \n\n", fpath, res); } else if (strcmp("/", path) /*even it's in local node, it could be outdated.*/ && strcmp(res, myaddr)) { ffs_recvfile_c("udt", res, "9000", fpath, fpath); // ADDED BY CSHOU //if (strcmp(res, myaddr) != 0 && res && strlen(res) != 0) //is_transfer = true; //spade_receivefile(fpath, res, fpath, statbuf->st_size, statbuf->st_mtime); log_msg("\n ===========DFZ debug: _getattr() %s transferred from %s because local copy might be outdated. \n\n", fpath, res); } else { /* let it be */ log_msg("\n ===========DFZ debug: _getattr() %s exists in local. \n\n", fpath); } } retstat = lstat(fpath, statbuf); if (retstat != 0) retstat = fusion_error("fusion_getattr lstat"); log_stat(statbuf); /* if (is_transfer) { char s_size[20]; sprintf(s_size, "%zd", statbuf->st_size); spade_receivefile(fpath, res, fpath, s_size, ctime(&statbuf->st_mtime)); }*/ return retstat; }
/** Read directory * * This supersedes the old getdir() interface. New applications * should use this. * * The filesystem may choose between two modes of operation: * * 1) The readdir implementation ignores the offset parameter, and * passes zero to the filler function's offset. The filler * function will not return '1' (unless an error happens), so the * whole directory is read in a single readdir operation. This * works just like the old getdir() method. * * 2) The readdir implementation keeps track of the offsets of the * directory entries. It uses the offset parameter and always * passes non-zero offset to the filler function. When the buffer * is full (or an error happens) the filler function will return * '1'. * * Introduced in version 2.3 */ int fusion_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { log_msg( "\nfusion_readdir(path=\"%s\", buf=0x%08x, filler=0x%08x, offset=%lld, fi=0x%08x)\n", path, buf, filler, offset, fi); int retstat = 0; char fpath[PATH_MAX] = {0}; fusion_fullpath(fpath, path); /* append a '/' if it's not the root directory */ char dirname[PATH_MAX] = {0}; strcpy(dirname, path); if (strcmp("/", dirname)) { strcat(dirname, "/"); } char filelist[ZHT_MAX_BUFF] = {0}; int stat = zht_lookup(dirname, filelist); if (ZHT_LOOKUP_FAIL == stat) log_msg("\n ===========DFZ debug: fusion_readdir() filelist not found in ZHT \n\n"); else log_msg("\n ===========DFZ debug: fusion_readdir() filelist = %s. \n\n", filelist); /*If <path/> has no files, clean up the local physical path*/ if (!strcmp(" ", filelist)) { char rmallcmd[PATH_MAX] = {0}; strcpy(rmallcmd, "rm -r "); strcat(rmallcmd, fpath); strcat(rmallcmd, "*"); system(rmallcmd); } char *pch = strtok((char*)filelist, " "); while (pch) { log_msg("calling filler with name %s\n", pch); if (filler(buf, pch, NULL, 0) != 0) { log_msg(" ERROR fusion_readdir filler: buffer full"); return -ENOMEM; } /*create some dummy dirs for listing*/ if ('/' == *(pch + strlen(pch) - 1)) { char newdir[PATH_MAX] = {0}; strcpy(newdir, fpath); strcat(newdir, "/"); strcat(newdir, pch); mkdir(newdir, 0775); } pch = strtok(NULL, " "); } // // DIR *dp; // struct dirent *de; // // // // once again, no need for fullpath -- but note that I need to cast fi->fh // dp = (DIR *) (uintptr_t) fi->fh; // // // Every directory contains at least two entries: . and .. If my // // first call to the system readdir() returns NULL I've got an // // error; near as I can tell, that's the only condition under // // which I can get an error from readdir() // de = readdir(dp); // if (de == 0) { // retstat = fusion_error("fusion_readdir readdir"); // return retstat; // } // // // This will copy the entire directory into the buffer. The loop exits // // when either the system readdir() returns NULL, or filler() // // returns something non-zero. The first case just means I've // // read the whole directory; the second means the buffer is full. // do { // log_msg("calling filler with name %s\n", de->d_name); // if (filler(buf, de->d_name, NULL, 0) != 0) { // log_msg(" ERROR fusion_readdir filler: buffer full"); // return -ENOMEM; // } // } while ((de = readdir(dp)) != NULL); // //// filler(buf, ep->data, NULL, 0); log_fi(fi); return retstat; }
/** Release an open file * * Release is called when there are no more references to an open * file: all file descriptors are closed and all memory mappings * are unmapped. * * For every open() call there will be exactly one release() call * with the same flags and file descriptor. It is possible to * have a file opened more than once, in which case only the last * release will mean, that no more reads/writes will happen on the * file. The return value of release is ignored. * * Changed in version 2.2 * * ***************************************************************** * DFZ: this is equivalent to fclose(). Nothing is surprising unless * it modifies the file. In this case we need to make the node * who modifies the file as the new location of this file, as * to update the value in ZHT. We also need to remove the old * copy in its previous node from where it's copied from. */ int fusion_release(const char *path, struct fuse_file_info *fi) { int retstat = 0; char fpath[PATH_MAX] = {0}; fusion_fullpath(fpath, path); log_msg("\nfusion_release(path=\"%s\", fi=0x%08x)\n", path, fi); log_fi(fi); /*is this file written?*/ int iswritten = 0; int flags = fcntl(fi->fh, F_GETFL); if (-1 == flags) { /*I don't know what to do... failed to get the old flags */ fusion_error("_release(): fd lost. "); } /* O_ACCMODE<0003>:读写文件操作时,用于取出flag的低2位 O_RDONLY<00>:只读打开 O_WRONLY<01>:只写打开 O_RDWR<02>:读写打开 */ else if (O_ACCMODE & flags) { iswritten = 1; } // We need to close the file. Had we allocated any resources // (buffers etc) we'd need to free them here as well. retstat = close(fi->fh); /*DFZ: uncomment this for metadata benchmark*/ return 0; /*if this is just a local IO, we are all set*/ char myip[PATH_MAX] = {0}; net_getmyip(myip); char nodeaddr[PATH_MAX] = {0}; zht_lookup(path, nodeaddr); if (!strcmp(myip, nodeaddr)) { return retstat; } /*dealing with the remote copy*/ if (iswritten) { /*so it's a write mode*/ char oldip[PATH_MAX] = {0}; int stat = zht_lookup(path, oldip); /*if path doesn't exist in ZHT, try to remove it locally */ if (ZHT_LOOKUP_FAIL == stat) { unlink(fpath); return 0; } /*update this file's node value in ZHT*/ char myip[PATH_MAX] = {0}; net_getmyip(myip); zht_update(path, myip); /*TODO: potentially, need to update the parent directory in ZHT * because the physical directory is also created in the new node*/ /*remove the file from its old node*/ /****************************************************************************** * DFZ: I want a more conservative way to clean dirty copies, so the following * remote removal is deferred for now. * * In other words just like the redundant directories, dirty files will be * removed when its parent directory is removed from ZHT * *******************************************************************************/ // ffs_rmfile_c("udt", oldip, "9000", fpath); } else { /*read-only file*/ /* we don't want o keep a redundant copy in local node to * prevent from the issue on removing multiple files * across different nodes. So, we remove the local file */ unlink(fpath); log_msg("\n=========DFZ debug _release(): %s unlinked from local node. \n\n", fpath); } return retstat; }
/** Get file attributes. * * Similar to stat(). The 'st_dev' and 'st_blksize' fields are * ignored. The 'st_ino' field is ignored except if the 'use_ino' * mount option is given. * * DFZ: This is the first function to be called whenever the user tries to * get access to any file, even if only to its meta data. Two cases: * 1) if the file exists, i.e. it's stored in ZHT, then this file is * transfered to the local node first and 'lstat' the local copy * 2) if the file doesn't exist, FUSE will pass the control to * _create() */ int fusion_getattr(const char *path, struct stat *statbuf) { int retstat = 0; char fpath[PATH_MAX] = {0}; log_msg("\nfusion_getattr(path=\"%s\", statbuf=0x%08x)\n", path, statbuf); fusion_fullpath(fpath, path); char res[ZHT_MAX_BUFF] = {0}; log_msg("\n =====DFZ debug: file %s line %d \n\n", __FILE__, __LINE__); int status = zht_lookup(path, res); log_msg("\n =====DFZ debug: file %s line %d \n\n", __FILE__, __LINE__); char myaddr[PATH_MAX] = {0}; net_getmyip(myaddr); log_msg("\n =====DFZ debug: file %s line %d \n\n", __FILE__, __LINE__); if (ZHT_LOOKUP_FAIL == status) { /* if not found in ZHT */ log_msg("\n ===========DFZ debug: _getattr() %s does not exist \n\n", path); /*DFZ: uncomment this for metadata benchmark*/ return -1; /*if path is an existing directory*/ char dirname[PATH_MAX] = {0}; strcpy(dirname, path); strcat(dirname, "/"); log_msg("\n ===========DFZ debug: _getattr() dirname = %s. \n\n", dirname); char res[ZHT_MAX_BUFF] = {0}; int stat = zht_lookup(dirname, res); if (ZHT_LOOKUP_FAIL != stat) { log_msg("\n ===========DFZ debug: _getattr() res = %s. \n\n", res); mkdir(fpath, 0755); char cmd_mkdir[PATH_MAX] = {0}; strcpy(cmd_mkdir, "mkdir -p "); strcat(cmd_mkdir, fpath); system(cmd_mkdir); log_msg("\n ===========DFZ debug: _getattr() new directory %s/ created \n\n", fpath); } } else { /* if file exists in ZHT */ log_msg("\n ===========DFZ debug: _getattr() zht_lookup() = %s. \n\n", res); /*DFZ: uncomment this for metadata benchmark*/ return 0; if (access(fpath, F_OK)) { /*if it isn't on this node, copy it over*/ ffs_recvfile_c("udt", res, "9000", fpath, fpath); log_msg("\n ===========DFZ debug: _getattr() %s transferred from %s. \n\n", fpath, res); } else if (strcmp("/", path) /*even it's in local node, it could be outdated.*/ && strcmp(res, myaddr)) { ffs_recvfile_c("udt", res, "9000", fpath, fpath); log_msg("\n ===========DFZ debug: _getattr() %s transferred from %s because local copy might be outdated. \n\n", fpath, res); } else { /* let it be */ log_msg("\n ===========DFZ debug: _getattr() %s exists in local. \n\n", fpath); } } retstat = lstat(fpath, statbuf); if (retstat != 0) retstat = fusion_error("fusion_getattr lstat"); log_stat(statbuf); return retstat; }