虽然对分布式也有一些了解,但是一直没有深入到代码去研究具体的实现。在群里咨询了一下,自己也google了一些资料,最终决定从MooseFS入手来深入研究分布式系统。第一步,就是从网上找文档,自己动手安装部署一番。官方网站上有一个中文的安装手册,非常nice,整个安装配置过程也非常顺利,感觉还不错,就是看它的代码实现。看完之后有些失望,在main函数中的第一个函数strerr_init()中看到了这样的代码:
for (n=0 ; errtab[n].str ; n++) {}
而errtab的定义(部分)如下所示:
static errent errtab[] = {
#ifdef E2BIG
{E2BIG,"E2BIG (Argument list too long)"},
#endif
#ifdef EACCES
{EACCES,"EACCES (Permission denied)"},
#endif
......
{0,NULL}
};
很明显,那个循环仅仅是为了计算errtab中元素的个数,而这样的计算有必要用一个循环么?sizeof不能解决么?我实现看不出来作者这里要写一个循环的好处是什么?
另一个地方让我感觉作者在写代码的时候很不用心,cfg_reload()在解析配置文件时定义了一个缓冲区linebuff[1000]数组来存储每行读取的内容。mfs解析配置文件时是按行读取的,每行的配置内容类似“key=value"这样的形式。这个缓冲区的长度定义为1000,也让我很不解。因为在定义缓冲区或分配内存的时候,一般都会考虑到对齐,都会对齐到word size或者CPU cache line的长度。这里的1000让我很不解!
代码中还有很多无用的、多余的判断。例如下面的代码段:
logappname = cfg_getstr("SYSLOG_IDENT",STR(APPNAME));
if (rundaemon) {
if (logappname[0]) {
openlog(logappname, LOG_PID | LOG_NDELAY , LOG_DAEMON);
} else {
openlog(STR(APPNAME), LOG_PID | LOG_NDELAY , LOG_DAEMON);
}
}
这个APPNAME是在编译的时候通过-DAPPNAME=mfsmaster这样的方式定义的一个宏,所以这个宏是必须定义的,否则前面的代码就没法运行(获取配置文件名称)。而且获取SYSLOG_IDENT配置变量的值是会指定默认值,所以if (logappname[0])这样的判断完全多余。如果是在两个函数中,这样的判断还说的过去,可是获取配置变量值的操作和
判断仅一个空行之隔,没必要到极点了吧。
抛开这些细节性的东西不提,mfs选择的I/O复用机制也让人不敢恭维。现在需要监听套接字的读写事件,毫无疑问首选的eventpoll。如果没有记错的话,moosefs是07年开始的,这个时候内核中的eventpoll机制已经很完善了,实在不懂作者为什么要选用poll()来作为I/O复用的接口。在继续之前,先看一下下面的代码:
i = poll(pdesc,ndesc,50);
......
if (i<0) {
if (errno==EAGAIN) {
syslog(LOG_WARNING,"poll returned EAGAIN");
usleep(100000);
continue;
}
if (errno!=EINTR) {
syslog(LOG_WARNING,"poll error: %s",strerr(errno));
break;
}
} else {
......
}
我不明白在poll()返回-1时,为什么要检查EAGAIN错误。查看了man手册,只有EFAULT、EINTR、EINVAL、ENOMEM错误,看了一下内核代码,也没有返回EAGAIN错误的地方。而且很不明白,为什么在EAGAIN的时候要调用usleep()等待100毫秒,不理解!
最终彻底击穿我的信心的是matoclserv_gotpacket()函数,这个函数通过判断eptr->registered的值来做不同的三种处理,这三个代码块中很多都是可以合并的。要么给每种处理封装成一个函数,要么将这三块代码合并成一块,这样看着不是更简洁么?很多switch-case分支中的处理也不用区分eptr->registered的值,为什么写的这么庞大?难道作者在写的时候为了方便,复制粘贴了一番?反正我是很不理解,这样的代码风格真是让我没办法看下去,我决定放弃了。我知道半途而废很不好,本来自己写代码风格就不好,怕看完之后更偏了,所以果断放弃!
下面是matoclserv_gotpacket()函数的代码,大家欣赏一下:
void matoclserv_gotpacket(matoclserventry *eptr,uint32_t type,const uint8_t *data,uint32_t length) {
if (type==ANTOAN_NOP) {
return;
}
if (eptr->registered==0) { // unregistered clients - beware that in this context sesdata is NULL
switch (type) {
case CLTOMA_FUSE_REGISTER:
matoclserv_fuse_register(eptr,data,length);
break;
case CLTOMA_CSERV_LIST:
matoclserv_cserv_list(eptr,data,length);
break;
case CLTOMA_SESSION_LIST:
matoclserv_session_list(eptr,data,length);
break;
case CLTOAN_CHART:
matoclserv_chart(eptr,data,length);
break;
case CLTOAN_CHART_DATA:
matoclserv_chart_data(eptr,data,length);
break;
case CLTOMA_INFO:
matoclserv_info(eptr,data,length);
break;
case CLTOMA_FSTEST_INFO:
matoclserv_fstest_info(eptr,data,length);
break;
case CLTOMA_CHUNKSTEST_INFO:
matoclserv_chunkstest_info(eptr,data,length);
break;
case CLTOMA_CHUNKS_MATRIX:
matoclserv_chunks_matrix(eptr,data,length);
break;
case CLTOMA_QUOTA_INFO:
matoclserv_quota_info(eptr,data,length);
break;
case CLTOMA_EXPORTS_INFO:
matoclserv_exports_info(eptr,data,length);
break;
case CLTOMA_MLOG_LIST:
matoclserv_mlog_list(eptr,data,length);
break;
default:
syslog(LOG_NOTICE,"main master server module: got unknown message from unregistered (type:%"PRIu32")",type);
eptr->mode=KILL;
}
} else if (eptr->registered<100) { // mounts and new tools
if (eptr->sesdata==NULL) {
syslog(LOG_ERR,"registered connection without sesdata !!!");
eptr->mode=KILL;
return;
}
switch (type) {
case CLTOMA_FUSE_REGISTER:
matoclserv_fuse_register(eptr,data,length);
break;
case CLTOMA_FUSE_RESERVED_INODES:
matoclserv_fuse_reserved_inodes(eptr,data,length);
break;
case CLTOMA_FUSE_STATFS:
matoclserv_fuse_statfs(eptr,data,length);
break;
case CLTOMA_FUSE_ACCESS:
matoclserv_fuse_access(eptr,data,length);
break;
case CLTOMA_FUSE_LOOKUP:
matoclserv_fuse_lookup(eptr,data,length);
break;
case CLTOMA_FUSE_GETATTR:
matoclserv_fuse_getattr(eptr,data,length);
break;
case CLTOMA_FUSE_SETATTR:
matoclserv_fuse_setattr(eptr,data,length);
break;
case CLTOMA_FUSE_READLINK:
matoclserv_fuse_readlink(eptr,data,length);
break;
case CLTOMA_FUSE_SYMLINK:
matoclserv_fuse_symlink(eptr,data,length);
break;
case CLTOMA_FUSE_MKNOD:
matoclserv_fuse_mknod(eptr,data,length);
break;
case CLTOMA_FUSE_MKDIR:
matoclserv_fuse_mkdir(eptr,data,length);
break;
case CLTOMA_FUSE_UNLINK:
matoclserv_fuse_unlink(eptr,data,length);
break;
case CLTOMA_FUSE_RMDIR:
matoclserv_fuse_rmdir(eptr,data,length);
break;
case CLTOMA_FUSE_RENAME:
matoclserv_fuse_rename(eptr,data,length);
break;
case CLTOMA_FUSE_LINK:
matoclserv_fuse_link(eptr,data,length);
break;
case CLTOMA_FUSE_GETDIR:
matoclserv_fuse_getdir(eptr,data,length);
break;
/* CACHENOTIFY
case CLTOMA_FUSE_DIR_REMOVED:
matoclserv_fuse_dir_removed(eptr,data,length);
break;
*/
case CLTOMA_FUSE_OPEN:
matoclserv_fuse_open(eptr,data,length);
break;
case CLTOMA_FUSE_READ_CHUNK:
matoclserv_fuse_read_chunk(eptr,data,length);
break;
case CLTOMA_FUSE_WRITE_CHUNK:
matoclserv_fuse_write_chunk(eptr,data,length);
break;
case CLTOMA_FUSE_WRITE_CHUNK_END:
matoclserv_fuse_write_chunk_end(eptr,data,length);
break;
// fuse - meta
case CLTOMA_FUSE_GETTRASH:
matoclserv_fuse_gettrash(eptr,data,length);
break;
case CLTOMA_FUSE_GETDETACHEDATTR:
matoclserv_fuse_getdetachedattr(eptr,data,length);
break;
case CLTOMA_FUSE_GETTRASHPATH:
matoclserv_fuse_gettrashpath(eptr,data,length);
break;
case CLTOMA_FUSE_SETTRASHPATH:
matoclserv_fuse_settrashpath(eptr,data,length);
break;
case CLTOMA_FUSE_UNDEL:
matoclserv_fuse_undel(eptr,data,length);
break;
case CLTOMA_FUSE_PURGE:
matoclserv_fuse_purge(eptr,data,length);
break;
case CLTOMA_FUSE_GETRESERVED:
matoclserv_fuse_getreserved(eptr,data,length);
break;
case CLTOMA_FUSE_CHECK:
matoclserv_fuse_check(eptr,data,length);
break;
case CLTOMA_FUSE_GETTRASHTIME:
matoclserv_fuse_gettrashtime(eptr,data,length);
break;
case CLTOMA_FUSE_SETTRASHTIME:
matoclserv_fuse_settrashtime(eptr,data,length);
break;
case CLTOMA_FUSE_GETGOAL:
matoclserv_fuse_getgoal(eptr,data,length);
break;
case CLTOMA_FUSE_SETGOAL:
matoclserv_fuse_setgoal(eptr,data,length);
break;
case CLTOMA_FUSE_APPEND:
matoclserv_fuse_append(eptr,data,length);
break;
case CLTOMA_FUSE_GETDIRSTATS:
matoclserv_fuse_getdirstats_old(eptr,data,length);
break;
case CLTOMA_FUSE_TRUNCATE:
matoclserv_fuse_truncate(eptr,data,length);
break;
case CLTOMA_FUSE_REPAIR:
matoclserv_fuse_repair(eptr,data,length);
break;
case CLTOMA_FUSE_SNAPSHOT:
matoclserv_fuse_snapshot(eptr,data,length);
break;
case CLTOMA_FUSE_GETEATTR:
matoclserv_fuse_geteattr(eptr,data,length);
break;
case CLTOMA_FUSE_SETEATTR:
matoclserv_fuse_seteattr(eptr,data,length);
break;
/* do not use in version before 1.7.x */
case CLTOMA_FUSE_QUOTACONTROL:
matoclserv_fuse_quotacontrol(eptr,data,length);
break;
/* for tools - also should be available for registered clients */
case CLTOMA_CSERV_LIST:
matoclserv_cserv_list(eptr,data,length);
break;
case CLTOMA_SESSION_LIST:
matoclserv_session_list(eptr,data,length);
break;
case CLTOAN_CHART:
matoclserv_chart(eptr,data,length);
break;
case CLTOAN_CHART_DATA:
matoclserv_chart_data(eptr,data,length);
break;
case CLTOMA_INFO:
matoclserv_info(eptr,data,length);
break;
case CLTOMA_FSTEST_INFO:
matoclserv_fstest_info(eptr,data,length);
break;
case CLTOMA_CHUNKSTEST_INFO:
matoclserv_chunkstest_info(eptr,data,length);
break;
case CLTOMA_CHUNKS_MATRIX:
matoclserv_chunks_matrix(eptr,data,length);
break;
case CLTOMA_QUOTA_INFO:
matoclserv_quota_info(eptr,data,length);
break;
case CLTOMA_EXPORTS_INFO:
matoclserv_exports_info(eptr,data,length);
break;
case CLTOMA_MLOG_LIST:
matoclserv_mlog_list(eptr,data,length);
break;
default:
syslog(LOG_NOTICE,"main master server module: got unknown message from mfsmount (type:%"PRIu32")",type);
eptr->mode=KILL;
}
} else { // old mfstools
if (eptr->sesdata==NULL) {
syslog(LOG_ERR,"registered connection (tools) without sesdata !!!");
eptr->mode=KILL;
return;
}
switch (type) {
// extra (external tools)
case CLTOMA_FUSE_REGISTER:
matoclserv_fuse_register(eptr,data,length);
break;
case CLTOMA_FUSE_READ_CHUNK: // used in mfsfileinfo
matoclserv_fuse_read_chunk(eptr,data,length);
break;
case CLTOMA_FUSE_CHECK:
matoclserv_fuse_check(eptr,data,length);
break;
case CLTOMA_FUSE_GETTRASHTIME:
matoclserv_fuse_gettrashtime(eptr,data,length);
break;
case CLTOMA_FUSE_SETTRASHTIME:
matoclserv_fuse_settrashtime(eptr,data,length);
break;
case CLTOMA_FUSE_GETGOAL:
matoclserv_fuse_getgoal(eptr,data,length);
break;
case CLTOMA_FUSE_SETGOAL:
matoclserv_fuse_setgoal(eptr,data,length);
break;
case CLTOMA_FUSE_APPEND:
matoclserv_fuse_append(eptr,data,length);
break;
case CLTOMA_FUSE_GETDIRSTATS:
matoclserv_fuse_getdirstats(eptr,data,length);
break;
case CLTOMA_FUSE_TRUNCATE:
matoclserv_fuse_truncate(eptr,data,length);
break;
case CLTOMA_FUSE_REPAIR:
matoclserv_fuse_repair(eptr,data,length);
break;
case CLTOMA_FUSE_SNAPSHOT:
matoclserv_fuse_snapshot(eptr,data,length);
break;
case CLTOMA_FUSE_GETEATTR:
matoclserv_fuse_geteattr(eptr,data,length);
break;
case CLTOMA_FUSE_SETEATTR:
matoclserv_fuse_seteattr(eptr,data,length);
break;
/* do not use in version before 1.7.x */
case CLTOMA_FUSE_QUOTACONTROL:
matoclserv_fuse_quotacontrol(eptr,data,length);
break;
/* ------ */
default:
syslog(LOG_NOTICE,"main master server module: got unknown message from mfstools (type:%"PRIu32")",type);
eptr->mode=KILL;
}
}
}