1.masterserver的启动过程
▲首先读取命令行参数和配置文件。如果当前用户是root,切换到默认用户。检查masterserver主进程是否已经启动。
▲初始化日志。
▲启动对chunkserver的监听。
▲启动对客户端的监听。
▲初始化文件系统,初始化存储文件节点的数组fsnodehash和存储块的数组chunkhash,全部初始化为空。
文件节点对应的是一个树状的数据结构,具体如下:
fsnode
- typedef struct _fsnode {
- uint32_t id;
- uint32_t ctime,mtime,atime;
- uint8_t type;
- uint8_t goal;
- uint16_t mode;
- uint32_t uid;
- uint32_t gid;
- uint32_t trashtime;
- union _data {
- struct _ddata {
- fsedge *children;
- uint32_t nlink;
- uint32_t elements;
- } ddata;
- struct _sdata {
- uint32_t pleng;
- uint8_t *path;
- } sdata;
- uint32_t rdev;
- struct _fdata {
- uint64_t length;
- uint64_t *chunktab;
- uint32_t chunks;
- cuidrec *cuids;
- } fdata;
- } data;
- fsedge *parents;
- struct _fsnode *next;
- } fsnode;
chunk对应的结构是一个链表的结构:
chunk
- typedef struct chunk {
- uint64_t chunkid;
- uint32_t version;
- uint8_t goal;
- uint32_t lockedto;
- flist *flisthead;
- struct chunk *next;
- } chunk;
▲从元数据存储文件(metadata.mfs)中读取所有的文件节点(fsnode)数据和存储块(chunk)的信息。在读取完数据后会把metadata.mfs重命名为metadata.mfs.back。至于fsnode和chunk在元数据中到底存储些什么内容,后面专门来描述。
▲进行用于数据统计的相关初始化工作。
▲进入到主循环(mainloop)。
2.主循环(loop)的工作
在主循环中,会重复执行由几个register函数注册的函数链。
7个register 函数
- void main_destructregister (void (*fun)(void));
- void main_canexitregister (int (*fun)(void));
- void main_wantexitregister (void (*fun)(void));
- void main_reloadregister (void (*fun)(void));
- void main_selectregister (int (*desc)(fd_set *,fd_set *),void (*serve)(fd_set *,fd_set *));
- void main_eachloopregister (void (*fun)(void));
- void main_timeregister (int mode,int seconds,int offset,void (*fun)(void));
拿其中的main_timeregister的实现看一下:
main_timeregister
- void main_timeregister (int mode,int seconds,int offset,void (*fun)(void)) {
- timeentry *aux;
- if (seconds<1) return;
- if (offset>=seconds || offset<0) return;
- aux = (timeentry*)malloc(sizeof(timeentry));
- aux->nextevent = ((now / seconds) * seconds) + offset + seconds;
- aux->seconds = seconds;
- aux->mode = mode;
- aux->fun = fun;
- aux->next = timehead;
- timehead = aux;
- }
他的作用就是把一些要执行的函数放到一个链表里面,后面方便由一个统一的入口timehead去执行。其它的几个register函数实现是类似的。
每个函数的作用说明一下:
▲main_reloadregister、main_wantexitregister、main_canexitregister这个三个注册的是在masterserver需要退出或者重新载入的时候要运行的函数。main_desturctregister注册的函数会在masterserver退出时执行。
▲main_selectregister所注册的函数中,包括了masterserver对chunkserver和客户端通讯的处理。在前面讲到mfsmount模块的时候说到客户端和masterserver的通信,masterserver就是在这里去处理所有与客户端和chunkserver的网络通信的:
main_selectregister
- main_selectregister(matocuserv_desc,matocuserv_serve);
- main_selectregister(matocsserv_desc,matocsserv_serve);
上面的代码中,matocuserv_serve和matocsserv_serve就是响应客户端和chunkserver的相应入口。
▲main_eachloopregister注册的函数在每次循环时都会被执行到,但是这种register在所有的代码中都没有被用到。
▲main_timerregister,大部分任务都是用这个register注册的:
main_timeregisters
- main_timeregister(TIMEMODE_SKIP,60,0,matocsserv_status);
- main_timeregister(TIMEMODE_RUNONCE,10,0,matocu_customer_check);
- main_timeregister(TIMEMODE_RUNONCE,3600,0,matocu_customer_statsmove);
- main_timeregister(TIMEMODE_RUNONCE,1,0,chunk_jobs_main)
- main_timeregister(TIMEMODE_RUNONCE,1,0,fs_test_files);
- main_timeregister(TIMEMODE_RUNONCE,3600,0,fs_dostoreall);
- main_timeregister(TIMEMODE_RUNONCE,300,0,fs_emptytrash);
- main_timeregister(TIMEMODE_RUNONCE,60,0,fs_emptyreserved);
- main_timeregister(TIMEMODE_SKIP,60,0,fs_show_counts);
- main_timeregister(TIMEMODE_RUNONCE,60,0,fsnodes_freeinodes);
注意main_timerregister中的第二个参数,这个是以秒为单位的,所以下面每个任务执行的频率是不一样的。
◆matocsserv_status用于定时统计chunkserver的存储情况。
◆matocu_customer_check用于检查客户端是否还有连接,如果长时间不连接,则释放关联的资源。
◆matocu_customer_statsmove更新客户端的状态。
◆chunk_jobs_main做的工作比较复杂,首先它会在存储chunk信息的数组chunkhash中删除已经没有被使用的chunk。然后针对剩下的chunkhash数组中的每个chunkItem做如下的操作:
①计算这个chunkItem指向的chunk有效和无效的备份数量。删除已经无效的备份。
②如果当前chunkItem指向的chunk正在做某个操作,例如正在复制数据,则返回。
③如果当前chunkItem已经不指向任何chunk,从数组中删除。
④如果当前chunkItem指向的chunk的备份数量太多,删除其中某些状态的chunk。
⑤如果当前chunkItem指向的chunk的备份数量小于配置的值,则让chunk进行复制。
⑥检查所有的chunkserver的信息,如果这些chunkserver上的存储空间的状态差别太大,那么把一些chunk从存储空间比较紧张的chunkserver上转移到存储空间比较宽裕的chunkserver上。
◆fs_test_files用于检查文件的结构是否完好,例如,检查文件所在的chunk是否完好等。
◆fs_storeall用于将当前的文件结构更新到元数据中。
◆fs_emptytrash和fs_emptyreserved顾名思义。
◆fs_show_counts在日志中记录当前一些计数器的值。
◆fsnodes_freeinodes释放资源。
3.存储结构
metadata.mfs是最重要的一个文件,其中保存了所有的元数据,里面的具体内容如下:

最前面的是元数据的格式,说明按照什么格式去读取,每个fsnode中的数据可以看前面他的定义,目录、文件并没有分开存放,都作为一个节点,文件节点信息这部分更具maxnodeid可以知道读到什么地方结束。freenode和chunk的结构比较简单,注意chunk结构里面虽然有goal(每个文件需要多少个备份)的值,但是这个值是从chunk所属的fsnode中取得的。