Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of fuse lowlevel, ls cd mkdir rmdir. #849

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/cn/fuse_lowlevel_namespace.md
Original file line number Diff line number Diff line change
@@ -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`函数进行相应的修改。


287 changes: 264 additions & 23 deletions fuse_lowlevel/bfs_ll_mount.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,196 @@

#include <sdk/bfs.h>

// 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<MountFile*>(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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Loading