Project5:
Design a File System
一、实验环境
Ubuntu 12.04系统
Eclipse开发平台
二、实验过程:
1、新建java project,添加网上所给代码
新建工程后,把网上下载的第11章的文件夹中的.java文件,拖拽到src目录下即可。
2、在JavaFileSystem.java文件中添加代码,以完成实验目标
2.1、在JavaFileSystem类中,添加Disk、FileTable型变量,用以存储相应数据。
public Disk myDisk;
public FileTable myFileTable;
2.2、部分功能机制的说明
FreeList:
以Group的形式,存储所有空的块号,构成FreeList,像栈一样工作,具体:
1、SuperBlock中存放第一个索引块号;
2、之后每个所以块号中poniter[0]存放下一个索引块号,其余部分存放的是空闲块的块号;
3、最后一个索引块的poniter[0]=0,表示结束;
4、加入新FreeBlock时,把它的块号添加到最后一个索引块的从pointer[1]开始第一个为零的空间中;
5、当最后一个索引块全部存满,加入新FreeBlock时,会并设置poniter[0]为新的FreeBlock块号,并 把新的FreeBlock作为下一块索引块;
6、释放FreeBlock时(即要新开劈Block用以存储数据),它会把最后一个索引块的从pointer[1]开始最后一个不为零的空间中的块号释放;
7、释放FreeBlock时,最后一个索引块全部释放了(即pointer[]全为0),则会释放最后的索引块用以存放数据,并把之前一个索引块的poniter[0]置零;
FileTable:
最大可以打开21个文件,通过fdArray保存打开文件的属性,用bitmap表示对应fdArray是否对应于一个打开的文件,具体:
1、可以通过allocate方法找到第一个未被使用的fdArray;
2、可以通过add方法,向对应位添加文件信息,表示文件打开
3、通过free方法释放对应fdArray,置bitmap对应位为0,表示关闭文件
Disk:
新建一个可随机读取的文件以模仿磁盘,具体:
1、通过read/write读/写对应块的内容,各分SuperBlock、InodeBlock、IndirectBlock和数据块四种;
2、stop方法,删除建立的一个可随机读取的文件
2.3、添加私有方法,已简便操作
添加了5个私有成员函数,内容、功能大致如下:
private void FreeListAdd(int blocknum);
根据FreeList的机制,添加blocknum到FreeList中
private int FreeListDecrease();
根据FreeList的机制,从FreeList中释放一个Block,并返回它的Blocknum;
private Inode getInode(int inum);
根据inum,返回对应InodeBlock中的相应的Inode;
private void Addblock(int inum);
给inum对应的文件添加一个新数据块,它会调用FreeListDecrease()来获得数据块,并根据Inode的使用情况(0~9,10,11,12共4种情况),把块号存到Inode的相应位置;
private int getBlock(int inum, int seekPoint);
根据inum和seekPoint查找其所对应的数据块,返回块号。查找时读取对应Inode后,根据主要用于读写函数;
2.4、完成功能函数
public int formatDisk(int size, int iSize);
根据size,iSize初始化文件系统,初始化myDisk和myFileTable,通过多次调用FreeListAdd方法初始化FreeList
public int shutdown() ;
把myFileTable的所有bitmap置零,表示文件关闭;调用myDisk的stop方法删除文件系统;
public int create();
创建一个新文件并打开:先找到一个未被使用的Inode(通过在InodeBlock逐个测试实现);通过FreeListDecrease方法分配空间;通过myFileTable的add方法打开该文件,将其bitmap置为1;
public int inumber(int fd);
通过myFileTable的getInumber方法直接返回对应inum;
public int open(int iNumber);
通过myFileTable的add方法打开对应文件;
public int read(int fd, byte[] buffer) ;
根据seekpoint,调用getBlock方法找到对应的数据块,读取其中数据,把seekpoint对应字节读到buffer中对应位中,seekpoint通过seek方法+1,如此循环。当seekpoint=fileSize时,或读完buffer长度的字节后,读操作结束,返回所读得字节长度;
public int write(int fd, byte[] buffer);
与读操作基本类似: 调用getBlock方法找到对应的数据块,修改seekpoint对应字节为buffer中的字节后写回,seekpoint通过seek方法+1,如此循环。如果在seek方法中新增了数据块,则对相应的Inode进行修改;
public int seek(int fd, int offset, int whence) ;
有三种方式:1)SEEK_SET,相对于起点设置seekpoint;2)SEEK_CUR,根据seekpoint得当前值,设置seekpoint的值;3)SEEK_END;根据文件大小设置seekpoint的值。如果新的seekpoint超过了filesize,并且需要新增数据块,则调用AddBlock方法;
public int close(int fd);
把FileTable中的Inode状态写回到Disk中,调用Disk的free方法关闭文件
public int delete(int iNumber);
置对应Inode的flags为0,表示Inode未被使用;并把原Inode中存储的数据块号调用FreeListAdd加入到FreeList中;
3、运行并测试
此程序可实现较简单的FileSystem功能:初始化、新建文件、开关文件、读、写、删等功能。
调试有两种方式:
1、直接运行TestFS.java,可以输入相关命令执行相关操作。
命令为:java TestFS
2、用所给的.data文件作为运行参数,执行文件一些列的命令来进行测试。
命令为:java TestFS ./tests/test1.data
经测试,该系统运行正常,能完成相应操作。
以下部分文件的结果:
File:test1.data
--> formatDisk 10 2
Result is 0
// Create a file and write a string to it
--> file1 = create
file1 = 0
--> inum1 = inumber file1
inum1 = 0
--> write file1 Hello,world! 12
Result is 12
--> close file1
Result is 0
--> file2 = open inum1
file2 = 0
--> read file2 100
Result is 0
--> close file2
Result is 0
--> vars
inum1 = 0
file2 = 0
file1 = 0
4、在实验中遇到的一些问题
在实验过程中,该系统的read、write和delete方法较难实现,要考虑数据块增/减、通过seekpoint查找对应数据、Freelist增/减等操作。为简化过程,我写了对应的私有成员函数,来辅助执行。这在很大程度上减少了程序编写的难度、代码的长度等。
在处理Inode的相关造作中,由于Inode的情况有多种,所以要进行多次判断,故代码较繁,较长,编写时需要格外细心。
在调试程序中,遇到了不小的麻烦,都是由一些小错误引起的。由于文件众多,代码较长,有些错总是发生的莫名其妙,在寻找错误发生的地方、产生原因上花了不少时间。最后通过设置断点、运用Eclipse的Debug模式,逐步完成了系统的debug过程。
在read,write操作中,为了编程简单,我是逐个字节进行读写的,而非一块一块进行读取的,会造成Disk读写次数过多,读写速度缓慢,这是还需要改进的地方。
三、实验总结
在这个实验中,通过编写简单的FileSystem,我对文件系统的理解进一步加深,尤其是对Group行的FreeList、Inode等问题有了明确的理解。
在这次实验之前,从来没写过这么多代码的程序,这次也算是一个挑战了。通过读代码、编写函数、调试等过程,锻炼了我大工程编写的能力。
最后,感谢老师这一学期的认真备课、细心讲解,助教的热心帮助、支持,谢谢。
附:源码( http://jcube.sjtu.edu.cn/f/36IN2fjV89dt1Bmx )有众多BUG,没空调了!!!谁比较闲,调好了记得通知我啊~~