diff --git a/docs/cn/fuse_lowlevel_namespace.md b/docs/cn/fuse_lowlevel_namespace.md new file mode 100644 index 00000000..27b02dc1 --- /dev/null +++ b/docs/cn/fuse_lowlevel_namespace.md @@ -0,0 +1,30 @@ +# Namespace For FUSE Lowlevel +## 需求 +根据fuse lowlevel的需求,需要两种获得文件的fileinfo的方式: + + * iget:entry_id->fileinfo(目前版本的BFS未实现) + * lookup:parent_id+name->fileinfo(目前版本的BFS在namespace中已实现) + +## 方案 +根据以上需求,有以下两种方案: + +`方案一:再添加一个db来存entry_id->fileinfo的信息。优点:实现简单,对现有的namespace结构改动较小;缺点:有两个db的一致性的问题,存储的信息有冗余,空间利用率低。` + +`方案二:将现有的用来存parent_id+name->fileinfo的db_用来存entry_id->fileinfo。然后再用iget来实现lookup。优点:没有两个db的一致性问题;缺点:对现有namespace的结构改动较大,且这种方式的lookup比目前版本的lookup要慢。` + +## 改动 +为了快速实现fuse lowlevel的接口,所以选择对现有namespace改动较小的方案一,对目前的namespace暂时改动如下: + +1.增加一个表`db_i`来维护`entry_id->fileinfo`,`db_i`中的`fileinfo`只用`name`字段,且该`name`字段存的是文件的`path`。 + +2.添加新的接口`bool NameSpace::IGet(int64_t entry_id, FileInfo * info)`。 + +3.修改其他接口的实现,如`DeleteFileInfo`,`BuildPath`,`CreateFile`等。 + +## 举例 +如fuse lowlevel的`getattr`操作流程:由`entry_id`在db_i里获得`path`,获得文件的`path`以后再调用namespace现有的接口获得文件的`fileinfo`(entry_id->path->fileinfo)。 + +## 说明 +该namespace临时方案对fuse lowlevel只支持单NS,无法支持NS之间的接替。因为对db_i操作的`logentry`没有写到log里,也没有针对`db_i`的情况对`NameSpace::TailLog`函数进行相应的修改。 + + diff --git a/fuse_lowlevel/bfs_ll_mount.cc b/fuse_lowlevel/bfs_ll_mount.cc index 117b7ae7..8367f7ea 100644 --- a/fuse_lowlevel/bfs_ll_mount.cc +++ b/fuse_lowlevel/bfs_ll_mount.cc @@ -14,25 +14,196 @@ #include -// not used -// baidu::bfs::FS* g_fs; +baidu::bfs::FS* g_fs; std::string g_bfs_path; std::string g_bfs_cluster; #define BFS "\e[0;32m[BFS]\e[0m " +#define min(x, y) ((x) < (y) ? (x) : (y)) +struct MountFile { + baidu::bfs::File* bfs_file; + bool read_only; + char* buf; + int32_t buf_len; + int64_t file_size; + std::string file_path; + MountFile(baidu::bfs::File* bfile, const std::string& path) + : bfs_file(bfile), read_only(false), + buf(NULL), buf_len(0), + file_size(0), file_path(path) {} +}; + +baidu::bfs::File* get_bfs_file(const struct fuse_file_info* finfo, + MountFile** mount_file = NULL) { + MountFile* mfile = reinterpret_cast(finfo->fh); + if (mount_file) *mount_file = mfile; + return mfile->bfs_file; +} + +static int bfsfileinfo_to_stat(baidu::bfs::BfsFileInfo *bfile, struct stat *st) { + + if (bfile->mode & (01000)) { + st->st_mode = (bfile->mode & 0777) | S_IFDIR; + st->st_size = 4096; + } else { + st->st_mode = (bfile->mode & 0777) | S_IFREG; + st->st_size = bfile->size; + } + st->st_ino = bfile->ino; + st->st_atime = bfile->ctime; + st->st_ctime = bfile->ctime; + st->st_mtime = bfile->ctime; + /*The correct value of st_nlink for directories is NSUB + 2. Where NSUB + is the number of subdirectories. NOTE: regular-file/symlink/etc + entries do not count into NSUB, only directories. + + If calculating NSUB is hard, the filesystem can set st_nlink of + directories to 1, and find will still work. This is not documented + behavior of find, and it's not clear whether this is intended or just + by accident. But for example the NTFS filesysem relies on this, so + it's unlikely that this "feature" will go away. + */ + st->st_nlink = 1; + return 0; +} + +static int bfs_getattr(fuse_ino_t ino, struct stat *st) { + fprintf(stderr, BFS"%s\n", __func__); + baidu::bfs::BfsFileInfo bfile; + int32_t ret = g_fs->IGet(ino, &bfile); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s IGet ino:%lu fail!\n", __func__, ino); + return -1; + } + std::string file_path(bfile.name); + ret = g_fs->Stat(file_path.c_str(), &bfile); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s Stat file_path:%s fail!\n", __func__, file_path.c_str()); + return -1; + } + ret = bfsfileinfo_to_stat(&bfile, st); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s bfsfileinfo_to_stat fail!\n", __func__); + return -1; + } + return 0; +} + +static int bfs_lookup(fuse_ino_t parent, const char *name, baidu::bfs::BfsFileInfo *bfile) { + fprintf(stderr, BFS"%s\n", __func__); + baidu::bfs::BfsFileInfo fileinfo; + int32_t ret = g_fs->IGet(parent, &fileinfo); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s IGet ino:%lu fail!\n", __func__, parent); + return -1; + } + std::string file_path(fileinfo.name); + file_path.append("/"); + file_path.append(name); + ret = g_fs->Stat(file_path.c_str(), bfile); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s Stat file_path:%s fail!\n", __func__, file_path.c_str()); + return -1; + } + return 0; +} static void bfs_ll_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { fprintf(stderr, BFS"%s\n", __func__); + struct stat st; + memset(&st, 0, sizeof(struct stat)); + if (bfs_getattr(ino, &st) == -1) { + fuse_reply_err(req, ENOENT); + } else { + fuse_reply_attr(req, &st, 1.0); + } } static void bfs_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { - fprintf(stderr, BFS"%s(%s)\n", __func__, name); + fprintf(stderr, BFS"%s parent_ino:%lu name:%s\n", __func__, parent, name); + struct fuse_entry_param e; + baidu::bfs::BfsFileInfo bfile; + + int32_t ret = bfs_lookup(parent, name, &bfile); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s bfs_lookup ino:%lu name:%s fail!\n", __func__, parent, name); + fuse_reply_err(req, ENOENT); + } else { + e.ino = bfile.ino; + e.attr_timeout = 1.0; + e.entry_timeout = 1.0; + ret = bfsfileinfo_to_stat(&bfile, &e.attr); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s bfsfileinfo_to_stat fail!\n", __func__); + fuse_reply_err(req, ENOENT); + } + fuse_reply_entry(req, &e); + } +} + +struct dirbuf { + char *p; + uint32_t size_used; +}; + +static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name, + fuse_ino_t ino) { + struct stat st; + size_t oldsize = b->size_used; + b->size_used += fuse_add_direntry(req, NULL, 0, name, NULL, 0); + b->p = (char *) realloc(b->p, b->size_used); + memset(&st, 0, sizeof(st)); + st.st_ino = ino; + fuse_add_direntry(req, b->p + oldsize, b->size_used - oldsize, name, &st, + b->size_used); +} + +static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize, + off_t off, size_t maxsize) { + if (bufsize - off > 0) { + return fuse_reply_buf(req, buf + off, min(bufsize - off, maxsize)); + } else { + return fuse_reply_buf(req, NULL, 0); + } } static void bfs_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { fprintf(stderr, BFS"%s\n", __func__); + struct stat st; + struct dirbuf b; + int32_t dir_num = 0; + baidu::bfs::BfsFileInfo bfile; + baidu::bfs::BfsFileInfo* bfiles = NULL; + + int32_t ret = g_fs->IGet(ino, &bfile); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s IGet ino:%lu fail!\n", __func__, ino); + fuse_reply_err(req, ENOTDIR); + return ; + } + std::string file_path(bfile.name); + ret = g_fs->ListDirectory(file_path.c_str(), &bfiles, &dir_num); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s ListDirectory file_path:%s fail!\n", __func__, file_path.c_str()); + fuse_reply_err(req, ENOTDIR); + return ; + } + memset(&st, 0, sizeof(st)); + memset(&b, 0, sizeof(b)); + for (int i = 0; i < dir_num; i++) { + ret = bfsfileinfo_to_stat(&bfiles[i], &st); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s bfsfileinfo_to_stat fail!\n", __func__); + fuse_reply_err(req, ENOTDIR); + return ; + } + dirbuf_add(req, &b, bfiles[i].name, bfiles[i].ino); + } + reply_buf_limited(req, b.p, b.size_used, off, size); + delete[] bfiles; + free(b.p); } static void bfs_ll_open(fuse_req_t req, fuse_ino_t ino, @@ -43,6 +214,7 @@ static void bfs_ll_open(fuse_req_t req, fuse_ino_t ino, static void bfs_ll_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { fprintf(stderr, BFS"%s\n", __func__); + fuse_reply_open(req, fi); } static void bfs_ll_read(fuse_req_t req, fuse_ino_t ino, @@ -63,6 +235,39 @@ static void bfs_ll_mknod(fuse_req_t req, fuse_ino_t parent, static void bfs_ll_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) { fprintf(stderr, BFS"%s(%s)\n", __func__, name); + struct fuse_entry_param e; + baidu::bfs::BfsFileInfo bfile; + + int32_t ret = g_fs->IGet(parent, &bfile); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s IGet ino:%lu fail!\n", __func__, parent); + fuse_reply_err(req, ENOENT); + return ; + } + std::string file_path(bfile.name); + file_path.append("/"); + file_path.append(name); + ret = g_fs->CreateDirectory(file_path.c_str()); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s CreateDirectory file_path:%s fail!\n", __func__, file_path.c_str()); + fuse_reply_err(req, ENOENT); + return ; + } + ret = g_fs->Stat(file_path.c_str(), &bfile); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s Stat file_path:%s fail!\n", __func__, file_path.c_str()); + fuse_reply_err(req, ENOENT); + } else { + e.ino = bfile.ino; + e.attr_timeout = 1.0; + e.entry_timeout = 1.0; + ret = bfsfileinfo_to_stat(&bfile, &e.attr); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s bfsfileinfo_to_stat fail!\n", __func__); + fuse_reply_err(req, ENOENT); + } + fuse_reply_entry(req, &e); + } } static void bfs_ll_create(fuse_req_t req, fuse_ino_t parent, @@ -91,6 +296,24 @@ static void bfs_ll_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) { static void bfs_ll_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) { fprintf(stderr, BFS"%s(%s)\n", __func__, name); + baidu::bfs::BfsFileInfo bfile; + + int32_t ret = g_fs->IGet(parent, &bfile); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s IGet ino:%lu fail!\n", __func__, parent); + fuse_reply_err(req, ENOENT); + return ; + } + std::string file_path(bfile.name); + file_path.append("/"); + file_path.append(name); + ret = g_fs->DeleteDirectory(file_path.c_str(), true); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"%s DeleteDirectory file_path:%s fail!\n", __func__, file_path.c_str()); + fuse_reply_err(req, ENOENT); + return ; + } + fuse_reply_err(req, 0); } static void bfs_ll_fsync(fuse_req_t req, fuse_ino_t ino, @@ -105,8 +328,26 @@ static void bfs_ll_fsyncdir(fuse_req_t req, fuse_ino_t ino, static void bfs_ll_access(fuse_req_t req, fuse_ino_t ino, int mask) { fprintf(stderr, BFS"%s\n", __func__); + fuse_reply_err(req, 0); } +static void bfs_ll_init(void *userdata, struct fuse_conn_info *conn) { + fprintf(stderr, BFS"init()\n"); + if (g_bfs_cluster.empty()) { + g_bfs_cluster = "localhost:8828"; + } + if (!baidu::bfs::FS::OpenFileSystem(g_bfs_cluster.c_str(), &g_fs, baidu::bfs::FSOptions())) { + fprintf(stderr, BFS"Open file sytem: %s fail\n", g_bfs_cluster.c_str()); + abort(); + } + int32_t ret = g_fs->Access(g_bfs_path.c_str(), R_OK | W_OK); + if (ret != baidu::bfs::OK) { + fprintf(stderr, BFS"Access %s fail, error code %s\n", + g_bfs_path.c_str(), baidu::bfs::StrError(ret)); + abort(); + } + return ; +} int parse_bfs_args(int* argc, char* argv[]) { if (*argc < 2) { @@ -145,26 +386,26 @@ int parse_bfs_args(int* argc, char* argv[]) { int main(int argc, char *argv[]) { - static struct fuse_lowlevel_ops ll_oper = { - .lookup = bfs_ll_lookup; - .getattr = bfs_ll_getattr; - .readdir = bfs_ll_readdir; - .open = bfs_ll_open; - .opendir = bfs_ll_opendir; - .read = bfs_ll_read; - .write = bfs_ll_write; - .mknod = bfs_ll_mknod; - .mkdir = bfs_ll_mkdir; - .create = bfs_ll_create; - .statfs = bfs_ll_statfs; - .rename = bfs_ll_rename; - .link = bfs_ll_link; - .unlink = bfs_ll_unlink; - .rmdir = bfs_ll_rmdir; - .fsync = bfs_ll_fsync; - .fsyncdir = bfs_ll_fsyncdir; - .access = bfs_ll_access; - }; + static struct fuse_lowlevel_ops ll_oper; + ll_oper.lookup = bfs_ll_lookup; + ll_oper.getattr = bfs_ll_getattr; + ll_oper.readdir = bfs_ll_readdir; + ll_oper.open = bfs_ll_open; + ll_oper.opendir = bfs_ll_opendir; + ll_oper.read = bfs_ll_read; + ll_oper.write = bfs_ll_write; + ll_oper.mknod = bfs_ll_mknod; + ll_oper.mkdir = bfs_ll_mkdir; + ll_oper.create = bfs_ll_create; + ll_oper.statfs = bfs_ll_statfs; + ll_oper.rename = bfs_ll_rename; + ll_oper.link = bfs_ll_link; + ll_oper.unlink = bfs_ll_unlink; + ll_oper.rmdir = bfs_ll_rmdir; + ll_oper.fsync = bfs_ll_fsync; + ll_oper.fsyncdir = bfs_ll_fsyncdir; + ll_oper.access = bfs_ll_access; + ll_oper.init = bfs_ll_init; if (parse_bfs_args(&argc, argv) != 0) { return -1; diff --git a/src/flags.cc b/src/flags.cc index 2a051296..44b3b362 100644 --- a/src/flags.cc +++ b/src/flags.cc @@ -17,6 +17,7 @@ DEFINE_int32(block_report_timeout, 600, "BlockReport rpc timeout, in seconds"); // nameserver DEFINE_string(namedb_path, "./db", "Namespace database"); +DEFINE_string(namedb_i_path, "./db_i", "Namespace database_i"); DEFINE_int64(namedb_cache_size, 1024L, "Namespace datebase memery cache size"); DEFINE_int32(expect_chunkserver_num, 3, "Read only threshtrold"); DEFINE_int32(keepalive_timeout, 10, "Chunkserver keepalive timeout"); diff --git a/src/nameserver/nameserver_impl.cc b/src/nameserver/nameserver_impl.cc index ade00ec9..4ff78a86 100644 --- a/src/nameserver/nameserver_impl.cc +++ b/src/nameserver/nameserver_impl.cc @@ -740,6 +740,36 @@ void NameServerImpl::Stat(::google::protobuf::RpcController* controller, done->Run(); } +void NameServerImpl::IGet(::google::protobuf::RpcController* controller, + const IGetRequest* request, + IGetResponse* response, + ::google::protobuf::Closure* done) { + if (!is_leader_) { + response->set_status(kIsFollower); + done->Run(); + return; + } + response->set_sequence_id(request->sequence_id()); + int64_t entry_id = request->entry_id(); + LOG(INFO, "IGet: E%ld\n", entry_id); + + FileInfo info; + if (namespace_->IGet(entry_id, &info)) { + FileInfo* out_info = response->mutable_file_info(); + out_info->CopyFrom(info); + //maybe haven't been written info meta + if ((out_info->type() & (1 << 9)) == 0) { + SetActualFileSize(out_info); + } + response->set_status(kOK); + LOG(INFO, "IGet: E%ld return: %ld", info.entry_id(), out_info->size()); + } else { + LOG(INFO, "IGet: E%ld return: not found", entry_id); + response->set_status(kNsNotFound); + } + done->Run(); +} + void NameServerImpl::Rename(::google::protobuf::RpcController* controller, const RenameRequest* request, RenameResponse* response, @@ -1515,7 +1545,8 @@ void NameServerImpl::CallMethod(const ::google::protobuf::MethodDescriptor* meth std::make_pair("PushBlockReport", work_thread_pool_), std::make_pair("SysStat", read_thread_pool_), std::make_pair("Chmod", work_thread_pool_), - std::make_pair("Symlink", work_thread_pool_) + std::make_pair("Symlink", work_thread_pool_), + std::make_pair("IGet", read_thread_pool_) }; static int method_num = sizeof(ThreadPoolOfMethod) / diff --git a/src/nameserver/nameserver_impl.h b/src/nameserver/nameserver_impl.h index 181ebd70..a9dce6c6 100644 --- a/src/nameserver/nameserver_impl.h +++ b/src/nameserver/nameserver_impl.h @@ -132,6 +132,10 @@ class NameServerImpl : public NameServer { const ChmodRequest* request, ChmodResponse* response, ::google::protobuf::Closure* done); + void IGet(::google::protobuf::RpcController* controller, + const IGetRequest* request, + IGetResponse* response, + ::google::protobuf::Closure* done); bool WebService(const sofa::pbrpc::HTTPRequest&, sofa::pbrpc::HTTPResponse&); private: diff --git a/src/nameserver/namespace.cc b/src/nameserver/namespace.cc index 33819585..63b7779a 100644 --- a/src/nameserver/namespace.cc +++ b/src/nameserver/namespace.cc @@ -20,6 +20,7 @@ #include "nameserver/sync.h" DECLARE_string(namedb_path); +DECLARE_string(namedb_i_path); DECLARE_int64(namedb_cache_size); DECLARE_int32(default_replica_num); DECLARE_int32(block_id_allocation_size); @@ -44,6 +45,12 @@ NameSpace::NameSpace(bool standalone): version_(0), last_entry_id_(1), LOG(ERROR, "Open leveldb fail: %s", s.ToString().c_str()); exit(EXIT_FAILURE); } + s = leveldb::DB::Open(options, FLAGS_namedb_i_path, &db_i); + if (!s.ok()) { + db_i = NULL; + LOG(ERROR, "Open leveldb db_i fail: %s", s.ToString().c_str()); + exit(EXIT_FAILURE); + } if (standalone) { Activate(NULL, NULL); } @@ -76,9 +83,12 @@ void NameSpace::Activate(std::function callback, NameSer RebuildBlockMap(callback); InitBlockIdUpbound(log); } + NameSpace::~NameSpace() { delete db_; + delete db_i; db_ = NULL; + db_i = NULL; } int64_t NameSpace::Version() const { @@ -147,9 +157,23 @@ bool NameSpace::GetFromStore(const std::string& key, FileInfo* info) { return true; } +bool NameSpace::GetFromStore_i(const std::string& key, FileInfo* info) { + std::string value; + leveldb::Status s = db_i->Get(leveldb::ReadOptions(), key, &value); + if (!s.ok()) { + LOG(DEBUG, "GetFromStore_i get fail "); + return false; + } + if (!info->ParseFromString(value)) { + LOG(WARNING, "GetFromStore_i parse fail %s", key.c_str()); + return false; + } + return true; +} + void NameSpace::SetupRoot() { root_path_.set_entry_id(kRootEntryid); - root_path_.set_name(""); + root_path_.set_name("/"); root_path_.set_parent_entry_id(kRootEntryid); root_path_.set_type(01755); root_path_.set_ctime(static_cast(version_ / 1000000)); @@ -202,14 +226,46 @@ bool NameSpace::LookUp(int64_t parent_id, const std::string& name, FileInfo* inf return true; } +bool NameSpace::IGet(int64_t entry_id, FileInfo * info) { + if (entry_id == 1) { + info->CopyFrom(root_path_); + return true; + } + std::string key_str; + EncodingStoreKey(entry_id, "", &key_str); + if (!GetFromStore_i(key_str, info)) { + LOG(INFO, "IGet E%ld return false", entry_id); + return false; + } + LOG(DEBUG, "IGet E%ld path:%s return true", entry_id, info->name().c_str()); + return true; +} + +//unfinshed, consistency not guranteed, to be continue bool NameSpace::DeleteFileInfo(const std::string file_key, NameServerLog* log) { + std::string file_key_i; + FileInfo info; + if (!GetFromStore(file_key, &info)) { + LOG(INFO, "DeleteFileInfo GetFromStore for entry_id return false"); + return false; + } + int64_t entry_id = info.entry_id(); + LOG(DEBUG, "DeleteFileInfo get entry_id from db_ E%ld return true", entry_id); leveldb::Status s = db_->Delete(leveldb::WriteOptions(), file_key); if (!s.ok()) { + LOG(INFO, "DeleteFileInfo db_ delete return false"); + return false; + } + EncodingStoreKey(entry_id, "", &file_key_i); + s = db_i->Delete(leveldb::WriteOptions(), file_key_i); + if (!s.ok()) { + LOG(INFO, "DeleteFileInfo db_i delete return false"); return false; } EncodeLog(log, kSyncDelete, file_key, ""); return true; } + bool NameSpace::UpdateFileInfo(const FileInfo& file_info, NameServerLog* log) { { MutexLock lock(&mu_); @@ -224,7 +280,7 @@ bool NameSpace::UpdateFileInfo(const FileInfo& file_info, NameServerLog* log) { file_info_for_ldb.CopyFrom(file_info); file_info_for_ldb.clear_cs_addrs(); - std::string file_key; + std::string file_key, file_key_i; EncodingStoreKey(file_info_for_ldb.parent_entry_id(), file_info_for_ldb.name(), &file_key); std::string infobuf_for_ldb; file_info_for_ldb.SerializeToString(&infobuf_for_ldb); @@ -267,15 +323,33 @@ StatusCode NameSpace::BuildPath(const std::string& path, FileInfo* file_info, st std::string info_value; for (int i = 0; i < depth - 1; ++i) { if (!LookUp(parent_id, paths[i], file_info)) { + file_info->set_name(paths[i]); + file_info->set_parent_entry_id(parent_id); file_info->set_type((1 << 9) | 01755); file_info->set_ctime(time(NULL)); file_info->set_entry_id(common::atomic_add64(&last_entry_id_, 1) + 1); file_info->SerializeToString(&info_value); - std::string key_str; - EncodingStoreKey(parent_id, paths[i], &key_str); - leveldb::Status s = db_->Put(leveldb::WriteOptions(), key_str, info_value); - assert(s.ok()); - EncodeLog(log, kSyncWrite, key_str, info_value); + std::string file_key, file_key_i; + EncodingStoreKey(parent_id, paths[i], &file_key); + EncodingStoreKey(file_info->entry_id(), "", &file_key_i); + leveldb::Status s = db_->Put(leveldb::WriteOptions(), file_key, info_value); + if (!s.ok()) { + LOG(WARNING, "BuildPath write to db fail: %s", s.ToString().c_str()); + return kUpdateError; + } + std::string path_i; + for (int j = 0; j <= i; ++j) { + path_i.append("/"); + path_i.append(paths[j]); + } + file_info->set_name(path_i); + file_info->SerializeToString(&info_value); + s = db_i->Put(leveldb::WriteOptions(), file_key_i, info_value); + if (!s.ok()) { + LOG(WARNING, "BuildPath write to db_i fail: %s", s.ToString().c_str()); + return kUpdateError; + } + EncodeLog(log, kSyncWrite, file_key, info_value); LOG(INFO, "Create path recursively: %s E%ld ", paths[i].c_str(), file_info->entry_id()); } else { if (GetFileType(file_info->type()) != kDir) { @@ -318,23 +392,34 @@ StatusCode NameSpace::CreateFile(const std::string& file_name, int flags, int mo } } + file_info.set_name(fname); + file_info.set_parent_entry_id(parent_id); file_info.set_type(((1 << 11) - 1) & mode); file_info.set_entry_id(common::atomic_add64(&last_entry_id_, 1) + 1); file_info.set_ctime(time(NULL)); file_info.set_replicas(replica_num <= 0 ? FLAGS_default_replica_num : replica_num); file_info.SerializeToString(&info_value); - std::string file_key; + std::string file_key, file_key_i; EncodingStoreKey(parent_id, fname, &file_key); + EncodingStoreKey(file_info.entry_id(), "", &file_key_i); leveldb::Status s = db_->Put(leveldb::WriteOptions(), file_key, info_value); - if (s.ok()) { - LOG(INFO, "CreateFile %s E%ld ", file_name.c_str(), file_info.entry_id()); - EncodeLog(log, kSyncWrite, file_key, info_value); - return kOK; - } else { - LOG(WARNING, "CreateFile %s fail: db put fail %s", file_name.c_str(), s.ToString().c_str()); + if (!s.ok()) { + LOG(WARNING, "CreateFile %s E%ld write to db fail: %s", file_name.c_str(), file_info.entry_id(), + s.ToString().c_str()); + return kUpdateError; + } + file_info.set_name(file_name); + file_info.SerializeToString(&info_value); + s = db_i->Put(leveldb::WriteOptions(), file_key_i, info_value); + if (!s.ok()) { + LOG(WARNING, "CreateFile %s E%ld write to db_i fail: %s", file_name.c_str(), file_info.entry_id(), + s.ToString().c_str()); return kUpdateError; } + LOG(INFO, "CreateFile %s E%ld ", file_name.c_str(), file_info.entry_id()); + EncodeLog(log, kSyncWrite, file_key, info_value); + return kOK; } StatusCode NameSpace::ListDirectory(const std::string& path, @@ -444,6 +529,8 @@ StatusCode NameSpace::Rename(const std::string& old_path, EncodingStoreKey(old_file.parent_entry_id(), old_file.name(), &old_key); std::string new_key; EncodingStoreKey(parent_id, dst_name, &new_key); + std::string old_key_i; + EncodingStoreKey(old_file.entry_id(), "", &old_key_i); std::string value; old_file.set_parent_entry_id(parent_id); old_file.set_name(dst_name); @@ -454,19 +541,23 @@ StatusCode NameSpace::Rename(const std::string& old_path, batch.Put(new_key, value); batch.Delete(old_key); - EncodeLog(log, kSyncWrite, new_key, value); - EncodeLog(log, kSyncDelete, old_key, ""); - leveldb::Status s = db_->Write(leveldb::WriteOptions(), &batch); - if (s.ok()) { - LOG(INFO, "Rename %s to %s[%s], replace: %d", - old_path.c_str(), new_path.c_str(), - common::DebugString(new_key).c_str(), *need_unlink); - return kOK; - } else { - LOG(WARNING, "Rename write leveldb fail: %s %s", old_path.c_str(), s.ToString().c_str()); + if (!s.ok()) { + LOG(WARNING, "Rename write db_ fail: %s %s", old_path.c_str(), s.ToString().c_str()); return kUpdateError; } + old_file.set_name(new_path); + old_file.SerializeToString(&value); + s = db_i->Put(leveldb::WriteOptions(), old_key_i, value); + if (!s.ok()) { + LOG(WARNING, "Rename write db_i fail: %s %s", old_path.c_str(), s.ToString().c_str()); + return kUpdateError; + } + LOG(INFO, "Rename %s to %s[%s], replace: %d", old_path.c_str(), new_path.c_str(), + common::DebugString(new_key).c_str(), *need_unlink); + EncodeLog(log, kSyncDelete, old_key, ""); + EncodeLog(log, kSyncWrite, new_key, value); + return kOK; } StatusCode NameSpace::Symlink(const std::string& src, const std::string& dst, NameServerLog* log) { @@ -497,23 +588,32 @@ StatusCode NameSpace::Symlink(const std::string& src, const std::string& dst, Na LOG(INFO, "CreateSymlink %s->%s fail: dst already exist!", dst.c_str(), src.c_str()); return kFileExists; } + file_info.set_name(fname); + file_info.set_parent_entry_id(parent_id); file_info.set_type(((1 << 11) - 1) & 02777); file_info.set_entry_id(common::atomic_add64(&last_entry_id_, 1) + 1); file_info.set_ctime(time(NULL)); file_info.set_sym_link(src); file_info.SerializeToString(&info_value); - std::string file_key; + std::string file_key, file_key_i; EncodingStoreKey(parent_id, fname, &file_key); + EncodingStoreKey(file_info.entry_id(), "", &file_key_i); leveldb::Status s = db_->Put(leveldb::WriteOptions(), file_key, info_value); - if (s.ok()) { - LOG(INFO, "CreateSymlink %s E%ld ", dst.c_str(), file_info.entry_id()); - EncodeLog(log, kSyncWrite, file_key, info_value); - return kOK; - } else { - LOG(WARNING, "CreateSymlink %s fail: db put fail %s", dst.c_str(), s.ToString().c_str()); + if (!s.ok()) { + LOG(WARNING, "CreateSymlink %s fail: db_ put fail %s", dst.c_str(), s.ToString().c_str()); + return kUpdateError; + } + file_info.set_name(dst); + file_info.SerializeToString(&info_value); + s = db_i->Put(leveldb::WriteOptions(), file_key_i, info_value); + if (!s.ok()) { + LOG(WARNING, "CreateSymlink %s fail: db_i put fail %s", dst.c_str(), s.ToString().c_str()); return kUpdateError; } + LOG(INFO, "CreateSymlink %s E%ld ", dst.c_str(), file_info.entry_id()); + EncodeLog(log, kSyncWrite, file_key, info_value); + return kOK; } StatusCode NameSpace::RemoveFile(const std::string& path, FileInfo* file_removed, NameServerLog* log) { @@ -625,7 +725,7 @@ StatusCode NameSpace::InternalDeleteDirectory(const FileInfo& dir_info, } StatusCode ret_status = kOK; - leveldb::WriteBatch batch; + leveldb::WriteBatch batch, batch_i; for (; it->Valid(); it->Next()) { leveldb::Slice key = it->key(); if (key.compare(key_end) >= 0) { @@ -644,8 +744,11 @@ StatusCode NameSpace::InternalDeleteDirectory(const FileInfo& dir_info, break; } } else { + std::string key_i; EncodeLog(log, kSyncDelete, std::string(key.data(), key.size()), ""); batch.Delete(key); + EncodingStoreKey(child_info.entry_id(), "", &key_i); + batch_i.Delete(key_i); child_info.set_parent_entry_id(entry_id); child_info.set_name(entry_name); LOG(DEBUG, "DeleteDirectory Remove push %s", entry_name.c_str()); @@ -655,20 +758,25 @@ StatusCode NameSpace::InternalDeleteDirectory(const FileInfo& dir_info, } delete it; - std::string store_key; + std::string store_key, store_key_i; EncodingStoreKey(dir_info.parent_entry_id(), dir_info.name(), &store_key); + EncodingStoreKey(dir_info.entry_id(), "", &store_key_i); batch.Delete(store_key); + batch_i.Delete(store_key_i); EncodeLog(log, kSyncDelete, store_key, ""); leveldb::Status s = db_->Write(leveldb::WriteOptions(), &batch); - if (s.ok()) { - LOG(INFO, "Delete directory done: %s[%s]", - dir_info.name().c_str(), common::DebugString(store_key).c_str()); - } else { - LOG(INFO, "Unlink dentry fail: %s\n", dir_info.name().c_str()); - LOG(FATAL, "Namespace write to storage fail!"); - ret_status = kUpdateError; + if (!s.ok()) { + LOG(FATAL, "Unlink dentry write to db_ fail: %s\n", dir_info.name().c_str()); + return kUpdateError; + } + s = db_i->Write(leveldb::WriteOptions(), &batch); + if (!s.ok()) { + LOG(FATAL, "Unlink dentry write to db_i fail: %s\n", dir_info.name().c_str()); + return kUpdateError; } + LOG(INFO, "Delete directory done: %s[%s]", + dir_info.name().c_str(), common::DebugString(store_key).c_str()); return ret_status; } diff --git a/src/nameserver/namespace.h b/src/nameserver/namespace.h index da0765fd..60098948 100644 --- a/src/nameserver/namespace.h +++ b/src/nameserver/namespace.h @@ -57,6 +57,8 @@ class NameSpace { bool UpdateFileInfo(const FileInfo& file_info, NameServerLog* log = NULL); /// Delete file bool DeleteFileInfo(const std::string file_key, NameServerLog* log = NULL); + /// Get file by entry_id + bool IGet(int64_t entry_id, FileInfo* info); /// Namespace version int64_t Version() const; /// Rebuild blockmap @@ -85,6 +87,7 @@ class NameSpace { int64_t* entry_id, std::string* path); bool GetFromStore(const std::string& key, FileInfo* info); + bool GetFromStore_i(const std::string& key, FileInfo* info); void SetupRoot(); bool LookUp(const std::string& path, FileInfo* info); bool LookUp(int64_t pid, const std::string& name, FileInfo* info); @@ -100,6 +103,7 @@ class NameSpace { private: leveldb::DB* db_; /// NameSpace storage leveldb::Cache* db_cache_; // block cache for leveldb + leveldb::DB* db_i; /// NameSpace storage entry_id->fileinfo int64_t version_; /// Namespace version. volatile int64_t last_entry_id_; FileInfo root_path_; diff --git a/src/proto/nameserver.proto b/src/proto/nameserver.proto index 996cc499..23df8770 100644 --- a/src/proto/nameserver.proto +++ b/src/proto/nameserver.proto @@ -90,6 +90,16 @@ message StatResponse { optional FileInfo file_info = 3; } +message IGetRequest { + optional int64 sequence_id = 1; + optional int64 entry_id = 2; +} +message IGetResponse { + optional int64 sequence_id = 1; + optional StatusCode status = 2; + optional FileInfo file_info = 3; +} + message RenameRequest { optional int64 sequence_id = 1; optional string oldpath = 2; @@ -363,5 +373,7 @@ service NameServer { rpc SysStat(SysStatRequest) returns(SysStatResponse); rpc Chmod(ChmodRequest) returns(ChmodResponse); rpc Symlink(SymlinkRequest) returns(SymlinkResponse); + + rpc IGet(IGetRequest) returns(IGetResponse); } diff --git a/src/sdk/bfs.h b/src/sdk/bfs.h index bfd9c72f..e1f9fed6 100644 --- a/src/sdk/bfs.h +++ b/src/sdk/bfs.h @@ -78,6 +78,7 @@ class File { }; struct BfsFileInfo { + int64_t ino; int64_t size; uint32_t ctime; uint32_t mode; @@ -104,6 +105,8 @@ class FS { virtual int32_t Access(const char* path, int32_t mode) = 0; /// Stat virtual int32_t Stat(const char* path, BfsFileInfo* fileinfo) = 0; + /// Get fileinfo by ino + virtual int32_t IGet(int64_t ino, BfsFileInfo* fileinfo) = 0; /// GetFileSize: get real file size virtual int32_t GetFileSize(const char* path, int64_t* file_size) = 0; /// Open file for read or write, flags: O_WRONLY or O_RDONLY diff --git a/src/sdk/fs_impl.cc b/src/sdk/fs_impl.cc index 4f1a0e23..88b9ebd5 100644 --- a/src/sdk/fs_impl.cc +++ b/src/sdk/fs_impl.cc @@ -132,13 +132,14 @@ int32_t FSImpl::ListDirectory(const char* path, BfsFileInfo** filelist, int *num *num = response.files_size(); *filelist = new BfsFileInfo[*num]; for (int i = 0; i < *num; i++) { - BfsFileInfo& binfo =(*filelist)[i]; + BfsFileInfo& bfile =(*filelist)[i]; const FileInfo& info = response.files(i); - binfo.ctime = info.ctime(); - binfo.mode = info.type(); - binfo.size = info.size(); - snprintf(binfo.name, sizeof(binfo.name), "%s", info.name().c_str()); - snprintf(binfo.link, sizeof(binfo.link), "%s", info.sym_link().c_str()); + bfile.ino = info.entry_id(); + bfile.ctime = info.ctime(); + bfile.mode = info.type(); + bfile.size = info.size(); + snprintf(bfile.name, sizeof(bfile.name), "%s", info.name().c_str()); + snprintf(bfile.link, sizeof(bfile.link), "%s", info.sym_link().c_str()); } } return OK; @@ -188,7 +189,7 @@ int32_t FSImpl::Access(const char* path, int32_t mode) { } return response.status() == kOK ? 0 : GetErrorCode(response.status()); } -int32_t FSImpl::Stat(const char* path, BfsFileInfo* fileinfo) { +int32_t FSImpl::Stat(const char* path, BfsFileInfo* bfile) { StatRequest request; StatResponse response; request.set_path(path); @@ -201,10 +202,11 @@ int32_t FSImpl::Stat(const char* path, BfsFileInfo* fileinfo) { } if (response.status() == kOK) { const FileInfo& info = response.file_info(); - fileinfo->ctime = info.ctime(); - fileinfo->mode = info.type(); - fileinfo->size = info.size(); - snprintf(fileinfo->name, sizeof(fileinfo->name), "%s", info.name().c_str()); + bfile->ino = info.entry_id(); + bfile->ctime = info.ctime(); + bfile->mode = info.type(); + bfile->size = info.size(); + snprintf(bfile->name, sizeof(bfile->name), "%s", info.name().c_str()); return OK; } return GetErrorCode(response.status()); @@ -316,6 +318,30 @@ int32_t FSImpl::Chmod(int32_t mode, const char* path) { } return OK; } +int32_t FSImpl::IGet(int64_t ino, BfsFileInfo* bfile) { + IGetRequest request; + IGetResponse response; + request.set_entry_id(ino); + request.set_sequence_id(0); + bool ret = nameserver_client_->SendRequest(&NameServer_Stub::IGet, + &request, &response, 15, 1); + if (!ret) { + LOG(WARNING, "IGet rpc fail: E%ld", ino); + return TIMEOUT; + } + if (response.status() != kOK) { + LOG(WARNING, "IGet E%ld return: %s\n", + ino, StatusCode_Name(response.status()).c_str()); + return GetErrorCode(response.status()); + } + const FileInfo& info = response.file_info(); + bfile->ino = info.entry_id(); + bfile->ctime = info.ctime(); + bfile->mode = info.type(); + bfile->size = info.size(); + snprintf(bfile->name, sizeof(bfile->name), "%s", info.name().c_str()); + return OK; +} int32_t FSImpl::OpenFile(const char* path, int32_t flags, File** file, const WriteOptions& options) { return OpenFile(path, flags, 0, file, options); } @@ -550,6 +576,8 @@ int32_t FSImpl::ShutdownChunkServerStat() { } } + + bool FS::OpenFileSystem(const char* nameserver, FS** fs, const FSOptions&) { FSImpl* impl = new FSImpl; if (!impl->ConnectNameServer(nameserver)) { diff --git a/src/sdk/fs_impl.h b/src/sdk/fs_impl.h index 00b91a4f..ebf0e6a5 100644 --- a/src/sdk/fs_impl.h +++ b/src/sdk/fs_impl.h @@ -34,7 +34,8 @@ class FSImpl : public FS { int32_t DeleteDirectory(const char* path, bool recursive); int32_t DiskUsage(const char* path, int64_t* du_size); int32_t Access(const char* path, int32_t mode); - int32_t Stat(const char* path, BfsFileInfo* fileinfo); + int32_t Stat(const char* path, BfsFileInfo* bfile); + int32_t IGet(int64_t ino, BfsFileInfo* bfile); int32_t Chmod(int32_t mode, const char* path); int32_t GetFileSize(const char* path, int64_t* file_size); int32_t GetFileLocation(const std::string& path,