1 2015/07/06 星期一
1.1 任务一
复习关于文件体统的一些基本的知识
1.1.1 遇到问题
1. 文件系统的挂载点被删除了,之前文件系统挂载在/zb下,但是这个路径好像是被删掉了,然后卸载文件系统,初始化,等的各种不好使:
/zb errinfo:No such file or directory
2. 文件系统中superblock、inode、block的理解
3. 对文件系统碎片,扇区,ext3日志式文件系统,挂载点等的理解。
1.1.2 解决问题
1. 在服务器上的我的一些信息,之前一个挂载点被清理,然后导致挂载载该路径下的文件系统不好使,弄清楚原因之后,创建新的挂载点,重新挂载文件系统,然后就好使了。
2. 文件系统中superblock、inode、block
Ø superblock: 记录filesystem的整体信息,包括inode、block的总量、使用量、剩余量,还有文件系统的格式和相关的信息。superblock的大小为1024bytes。
Superblock中记录的信息:block与inode的总量、未使用和已使用inode和block的数量、block与inode的大小(block为1,2,4K,inode为128bytes)、文件系统的挂载时间、最后一次写数据的时间,最近一次检验磁盘的时间等文件系统相关的信息、一个validbit数值,若此文件系统已被挂载,则validbit为0,未被挂载则为1,可见superblock是非常重要的,因为文件系统的基本信息都在这。
Ø inode: 记录文件的属性,一个文件只占用一个inode,同时记录此文件的数据所在的所在的block号码。大小为128bytes。
Inode中包含的东西:文件的存取模式、拥有者与群组、文件的容量、文件简历或者状态改变的时间、最后一次读取的时间、最近一次修改的时间、文件的内容指向。
注:一个文件只有一个inode
Ø block: 实际记录文件的内容,若文件太大,则会有很多个block
3. dumpe2fs命令:
dumpe2fs[-bh] 装置文件名
选项与参数:
-b :列出保留为坏轨的部分(一般用不到吧!?)
-h :仅列出superblock 的数据,不会列出其他的区段内容!
找出我的根目录磁盘文件名,并观察文件系统的相关信息
4. 目录inode:文件系统在建立一个目录时,会分配一个inode和至少一个block。
5. 碎片整理:文件系统使用太久,常常删除/编辑/新增档案时,那么还是可能会造成档案数据太过于离散的问题,此时或许会需要进行重整一下
6. 扇区:磁盘上的每个磁道被等分为若干个弧段,这些弧段便是磁盘的扇区。硬盘的读写以扇区为基本单位。
7. 日志式文件系统
在我们的filesystem当中规划出一个区块,该区块专门在记录写入或修订档案时的步骤:
预备:当系统要写入一个档案时,会先在日志记录区块中纪录某个档案准备要写入的信息;
实际写入:开始写入档案的权限与数据;开始更新metadata的数据;
结束:完成数据与metadata的更新后,在日志记录区块当中完成该档案的纪录。
8. 挂载点:
每个文件系统都有独立的inode/superblock/block等信息,这个文件系统要能够链接到目录树才能被我么使用,将文件系统与目录树的结合叫做挂载。挂载点是目录,是进入文件系统的入口。文件系统必须要挂载到牧歌目录树的目录后面才能使用。
2 2015/07/07 星期二
2.1 任务一
1. 由于时间相隔已久,重新开始看之前看过的代码。
2.1.1 遇到问题
1. b2/Filesystem文件夹下各个文件的作用;
2. b2/FuseInterface文件夹下的各个文件的作用
3. b2/include中各个功能的作用 ,
Include+lib :元数据的存储
4. b2/Management中各种文件的作用
5. b2/Until的作用
6. b2/DataStore
7. Config配置文件解析
8. Fstest整个系统的测试程序
9. Script中的一些功能
10. TypeDef主要就是自己封装的一些结构
11. System中的一些东西
12. Obj
2.1.2 解决思路
1. Filesystem.h:对整个文件系统的各种操作,包括文件系统的卸载、挂载、对文件的加锁解锁,设置,检查等的操作
DedupParam.h:文件系统的相关参数,定义了很多所需要的结构体。
DateOpr.h :数据的相关操作,包括打开文件信息,读取,删除,关闭等
FSClearner.h:文件系统的清理工作,关闭文件时,把要关闭的文件暂时保持起来;打开文件时,要把新打开的文件从延迟关闭中删除;对于时间到期的文件要进行关闭。
INInitor.h:输入输出的初始化(函数中没有实现部分)
RaCalculation.h:预读算法,用LRUCache来处理缓存
SuperBlock.h :超级块,记录filesystem的整体信息,包括inode、block的总量、使用量、剩余量,还有文件系统的格式和相关的信息。文件系统的基本信息都在这
InfoChunk.h:信息库,在指定的位置对SuperBlock中的信息进行读写操作(ReadBackUpDedupPath函数是什么意思?)
ListChunk.h:数据块的链表,在数据链中添加seq(序列信号),删除无用的seq,清空数据块中的全部记录
2. FuseInterface:元数据的接口转换
1) DDFSMetaStore.h:DDFSMetaStore继承MetaStateStore,获取元数据的状态
2) DDFSOpr.h:DDFSOpr继承FuseOpr之后添加对数据的操作
3) AdfsOpr.h:消冗库的初始化、创建、关闭;根据偏移量打开、读、写、删除,关闭文件,计算消冗后数据的大小
4) SDataCache.h:对缓存的操作,map中数据的操作
3. b2/include中各个功能的作用
1) MetaStateStore.h
元数据的存储状态,设置元数据的存储状态
2) MetaCommon.h
包含几个结构体:INodeStat 数据块的信息、MetaParam元数据的参数信息
3) LocalOpr.h
继承FuseOpr之后添加对数据的操作
4) FuseOpr.h
与fuse连接,编写操作函数
5) MetaManage.h
元数据的管理
6) MetaInterface
元数据的操作——读写删
4. Management中主要是MsgServer的功能:
(消息管理,消息机制,热配参数,进程间通信)
1) 初始化消息队列,监听线程,
2) 进程通信信息处理功能的开启,接收消息,处理消息,处理结果的返回,
3) 解析接受的命令,
4) 删除消息队列。
5. Until主要包含一些工具
(1) Until/Iniparser配置文件的解析
(2) Until/log日志文件
(3) Util/MachineState机器的状态
(4) Util/Semaphore信号量
(5) Util/Serializer.h并串行装唤器(未使用)
(6) LRUCache.h缓存处理
6. DataStore数据的存储
7. Script中的一些功能
/script/adfs_script :文件系统的挂载,卸载
adfs_sysconfig : 服务形式
adfs_daemon : 守护进程
adfs_mkfs : 初始化
adfs_mount : 挂载
adfs_umount : 卸载
主要用于创建文件系统;首先解析配置文件,然后创建文件系统并用配置文件对系统进行相应的初始化。挂载文件系统;其中包括设置数据库路径,启动LOG日志,初始化元数据信息等挂载时需要执行的操作。卸载文件系统。
8. System中的一些东西:
System/IoMonitor.h 系统是否繁忙
作用:系统空闲时回答后空间(老版本上的东西,采集5次空间信息,然后断定其是否处于空闲状态)
System/systemState.h 系统的状态
作用:定义的系统的状态信息类SystemState,其中包括设置,重置,获取,保存系统状态等操作
3 2015/07/08 星期三
3.1 任务一
1. 看src里面include和inode的东西
3.1.1 遇到问题
1. src /include文件夹中各个文件的作用
2. src /inode :INodeDir,INodeFile.,INodeSym都是继承INode类,但不知道其具体的作用,没有看懂。
3.1.2 解决思路
1. include/ FuseOpr.h:定义接口FuseOpr
include/MetaCommon.h :定义了Inode的结构体,MetaParam的结构体信息
include/LocalOpr.h :LocalOpr类 继承 FuseOpr
include/MetaInterface.h :初始化根目录结构,提供挂载main函数,获取系统的总大小,获取文件的大小,设置文件大小,获取当前最大的得bidSeq,读/写/删bid,创建目录(私有)
include/MetaStateStore.h:设置元数据的状态
include/ MetaManager.h:对元数据的一些操作
2. inode/INode.h :将INodeBuf中的数据填充到不同INode,INodeDir数据不完整 PersitantStore查找后放置vector中,INodeDir将vector中的IName加入内存,INodeFile数据不完整 PersitantStore查找后放置vector中,INodeFile将vector中的Block加入内存,获取指定name对应的INodeNum等一些有关Inode的接口
inode/INodeDir.h:INodeDir类继承INode
inode/INodeFile.h:INodeFile类继承INode
inode/INodeSym.h:INodeSym类继承Inode
4 2015/07/09 星期四
4.1 任务一
1. 看src里面manager的东西
4.1.1 遇到问题
1. MetaManager类函数都是空的,而实现都在MetaManagerImpl类中,为何不直接写一起?
2. RemoteOpr.h好像是远程连接的,但是里面是函数实现部分是空的,不知道有啥用?
3. JournalMgr.h中implementation()函数是合并日志,不明白是合并哪些日志?都有什么用?
4. FuseDispather.h是FuseOpr.h的实现.
4.1.2 解决思路
1. MetaManagerImpl类是MetaManager类的实现(implementation),有可能是为了以后要有新加的功能,不知道这样想是不是对的。
2. 不知道这部分用在哪里
3. JournalMgr.h中implementation()函数是合并日志,这里的日志是什么日志,是正常操作的日志吗还是元数据的日志。
4. FuseDispather.h是FuseOpr的实现.用了静态函数,表示该实现只能在该内中使用。
5 2015/07/10 星期五
5.1 任务一
1. 看src里面store的东西
5.1.1 遇到问题
1. BitMap有什么作用?
2. Lookup是怎样的过程。
3. 类INameStore的作用不是很明白。
5.1.2 解决问题
1. Bitmap有两,一个是block bitmap ,另一个是 inode bitmap 。新增文件块会用到block,所以得需要个空的block来记录新的块,而从block bitmap中就可以知道哪些个block是空的,故而系统能够很快的找到可以使用的空间里处理。Inode bitmap和block bitmap的功能类似,inode bitmap也是记录使用和未使用的inode号(不知道这样理解是不是对)。
BitMap类中,主要是对新增的文件块,选择新的block,然后先获取bit,然后从找到没用使用中的bit,每次申请int8_t的空间,然后每次使用完后更新,当新增的inode用完后,整理日志,这样就能获取新的可以用的inode号。
2. Lookup的过程:
(1) 获取DirIndex作为查询的依照 并进行初次访问的初始化
(2) Step2:获取当前访问INode的属性,以获得ID和Mode用以写日志
(3) 循环访问每个Block以查询某name或直接遍历全部Block
i. 处理某个Block
ii. 根据当前Block的处理返回值记录日志。
iii. 根据当前Block的处理返回值记录日志。
(4) 单独处理最后一个Block空的情况
6 2015/07/13 星期一
6.1 任务一
1. 看src里面store的东西
2. 看store中LRUDentryStore类
6.1.1 遇到问题
1. int main() {
struct statbuf;
stat("/etc/hosts", &buf);
printf("/etc/hosts file size = %d\n",buf.st_size);
}
其中的蓝色部分怎么理解?
2. C++STL中vector容器 begin()与end()函数、front()与back()的用法
3. 对LRUDentryStore类中成员函数的理解。
6.1.2 解决问题
1. structstat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
unsigned long st_blksize; //块大小(文件系统的I/O 缓冲区大小)
unsigned long st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};
通过提供的函数,返回一个结构体,里面保存着文件信息。
2. C++STL中vector容器 begin()与end()函数、front()与back()的用法:
begin函数:
函数原型:
iteratorbegin();
const_iteratorbegin();
功能:
返回一个当前vector容器中起始元素的迭代器。
end函数:
函数原型:
iteratorend();
const_iteratorend();
功能:
返回一个当前vector容器中末尾元素的迭代器。
front函数:
函数原型:
referencefront();
const_referencefront();
功能:
返回当前vector容器中起始元素的引用。
back函数:
函数原型:
referenceback();
const_referenceback();
3. LRUDentryStore类
(1) DelMegred():删除合并日志
(2) Delete():删除某个号码对应的日志
(3) IsSync():文件号是否同步了
(4) GetINode():从INodeBuf中获取不同的东西,并且之后删除释放buf
(5) DelINode():
(6) Add():添加
(7) Load():插入一个节点,并在日志文件中显示当前的节点数
(8) Unload():删除某个节点
(9) Lookup():num 对应文件目录一定存在, map or lru or disk,要么在Dentry中有对应的INode* (但INode*对象可能不完整 自身负责换出换入),要么被DentryStore换出或者没有载入 去磁盘上查找,TODO 为保证LRUcachedb中无更改过的 则查找首先在map中进行 然后删掉LRU中的 貌似很Ugly,或者是 在Add之前先删
7 2015/07/14 星期二
7.1 任务一
1. 看src里面util的crc东西
7.1.1 遇到问题
1. Until/crc/ICrc16.h中Process()函数的作用?(没有看明白)
2. MetaFactory类
3. CPUSupport.h没有看懂
7.1.2 解决问题
1.
ICrc |
Crc16 |
BasicCrc32 |
QuickCrc32 |
Crc16类,BasicCrc32,类,QuickCrc32类都是公有继承ICrc类。对其中的Process进行不同的实现。
2. MetaFactory类中GetInstance是根据不同的type来返回调用的DEFAULT_CRC32, CUR_CRC,BASIC_CRC32, QUICK_CRC32。DelInstance函数最后销毁crc对象
8 2015/07/15 星期三
8.1 任务一
1. 看src里面store的Journal类
8.1.1 遇到问题
1. 对Journal类中一些函数的理解
8.1.2 解决问题
(1) GetJournalFile():获取日志文件,首先先给该文件加锁,以防止访问的时候,被修改,并且该函数仅在初始化函数中调用。
(2) Init():初始化,初始化过程也就是调用一遍GetJournalFile(),然后初始化完毕
(3) UpdateFileSet():更新FileSet,将其文件名插入到要删除的m_ToDelSet队列最后,然后将m_FileSet的第一个元素删除。等到要删除的m_ToDelSet的大小大于m_DelFileWin时,在删除m_ToFileSet中的第一个元素。
(4) GetJournal():这个函数比较长,梳理下其中的功能实现:加锁,打开m_FileSet.front(),要是打开不了则更新FileSet列表并返回。fstat根据open() 函数调用后的返回值(文件描述符)获取文件的状态信息,如果返回非0则表示获取文件信息失败。获取的文件的st_size(文件字节数)如果小于等于m_HeadSize(10)则说明不满足条件,更新FileSet后返回,要是大于的话,在堆区申请空间data(大小为st_size- m_HeadSize),然后通过lseek函数将偏移量移到m_HeadSize(10)得位置(SEEK_SET 参数的意思是偏移量为前面一个参数),然后开始从偏移量为之开始读,再解析日志是否合法,然后填写日志,最后释放申请的空间data,若此时解析的日志是非法的则将其后续日志删除。在更新FileSet列表,把长度返回出去(atoll函数的功能是把字符串转换成长整型的数)。
9 2015/07/16 星期四
9.1 任务一
1. 接着看src里面store的Journal类
9.1.1 遇到问题
1. 对Journal类中一些函数的理解
9.1.2 解决问题
(1) GetValidJournal():解析日志是否合法
(2) UpdateCursor():更新日志解析
(3) DelInvalidJournal():删除出现的非法日志
处理过程:首先将当前日志文件截断到offset大小,然后删除其他日志即可
(4) GetJournalEntry():给日志里面写内容
(5) MergerInternal():读日志,填充JournalEntry,对于一个INode的操作至于vector中。
具体的操作过程是:对于JournalEntry中内部vector,将OpeEntrySet进行排序(函数OprEntry()决定排序的规则),最后确保LastPos[x] 中位置是JournalOpr中最后几位。
(6) OprEntryCmp():比较OprEntry类中Opr是否相同,若相同,按照时间排序,若是不相同则按照JournalOpr的大小排序
10 2015/07/17 星期五
10.1任务一
1. 接着看src里面store的Journal类
10.1.1 遇到问题
1. 对Journal类中一些write开头的函数的理解
10.1.2 解决问题
(1) WriteXXXJournal():MetaManager的接口
1) WriteCreateJournal():lock的作用,确保添加INode和IName时候能够不间断的写入日志Journal中,并且没有中断,除非是断电的情况或者是程序崩溃的情况。
Ø Write(ATOMIC_BEGIN)
Ø WriteAddINodeEntry 按照新加的INode的stat信息来OprItem<INodeAdd>结构,然后将其写入日志,最后释放
Ø WriteAddINameEntry 根据stat和新添加的文件名name,用户ID参数来写入OprItem<INameAdd>,然后将其写入日志,最后释放,若是最后满足WriteDelPidEntry函数的掉用条件则掉用WriteDelPidEntry 函数。
Ø WriteSetAttrEntry 根据父目录的stat构造OprItem<AttrSet>,并写入日志,释放。
Ø WriteSetAttrEntry 对新添加的文件或目录的索引部分清零,根据新添加的文件的目录stat构建OprItem<AttrSet>,然后释放
Ø Write(ATOMIC_END)
return:FinishWriteJournal() 如果说1最后日志没有写满,则返回已使用的最大的日志标号;2若是写满了,则文件信息同步到存储设备,关闭m_Fd;
然后EXIT();并创建新的日志文件,并返回创建之前的日志编号。
2) WriteRenameJournal():重命名日志文件
3) WriteAddBidJournal():在日志文件中添加bid
4) WriteDelBidJournal():在日志文件中删除bid
5) WriteDelPidJournal():
Ø WriteDelPidEntry():
当curPid小于0时,是需要删除头部。当nextPid小于0时,表示要删除尾部。curPid nextPid 大于0时,操作次持久化文件。若 curPid < nextPid 删除中部。相等删除某一个。
Ø WriteSetAttrEntry():
returnFinishWriteJournal():
6) WriteLinkJournal():链接
7) WriteRmJournal():
8) WriteSymLinkJournal():
(2) CreateJournalFile():创建日志文件
(3) WriteXXXEntry():使用WriteXXXJournal,做实际的文件写入
1) WriteAddINodeEntry():按照新加的INode的stat信息来OprItem<INodeAdd>结构,然后将其写入日志,最后释放
2) WriteAddINameEntry():根据stat和新添加的文件名name,用户ID参数来写入OprItem<INameAdd>,然后将其写入日志,最后释放,若是最后满足WriteDelPidEntry函数的掉用条件则掉用WriteDelPidEntry 函数。
3) WriteAddIdxPidEntry():
4) WriteAddSymLinkEntry():添加符号链接
5) WriteDelINameEntry():
6) WriteDelINodeEntry():
7) WriteDelIdxPidEntry():
8) WriteDelSymlinkEntry():
9) WriteSetInterBIDEntry():
(4) WriteDelBidProcess():
(5) GetJournalCount():获取可以整理的日志个数
(6) Write():写没有CRC的日志
(7) isValid():判断当前的buf中的内容是否有效
(8) FinshWriteJournal:日志未写满,返回最大使用日志序号;日志写满了,文件信息同步到存储设备,关闭fd,Exit(),创建一个新的日志文件,返回未创建新文件之前的最大使用日志序号。
11 2015/07/20 星期一
11.1任务一
MetaInternal类的理解
主要看元数据内部的东西定义的部分
11.1.1 遇到问题
1. CRC校验
2. 记录Store/MetaInternal.h里面的功能
3. 序列化和反序列化的理解
4. 遇到一些掌握有问题(或者不会)的知识的总结
11.1.2 解决思路
1. CRC校验:
是数据通信领域中最常用的一种差错校验码,其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。
2. Store/MetaInternal.h 元数据内部的东西
1) 设置基本属性时,从INodeStat中获取,若是涉及到对此持久化的索引的更改需要通过container_of中获得INodeBuf。
2) 主要定义一些父目录的属性设置宏,子目录的属性设置宏,不区分父子的属性设置宏。
3) 然后定义了结构体:DirIndex目录索引,FileIndex文件索引,SymIndex符号索引,
4) 定义INodeBuf的结构体,里面包含INodeSta的对象,和INodeINdex的对象,和GetBataByMask函数。
5) 定义了结构体:Bid,INameInfo,IName,BidIndex
6) 定义了INameInfo的结构体
7) 定义了IName的结构体
8) 定义了BidIndex的结构体,因为删除Bid是需要得到的索引信息
9) 最后定义了很多的全局变量
3. 序列化和反序列化
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为对象。
把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
4. 遇到不熟的知识点
1) int open( constchar * pathname, int flags);
//pathname:要打开文件的路径
//flag:打开的方式
O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开文件
O_RDWR 以可读写方式打开文件。
返回值:0表示打开成功,-1表示打开失败
int read(int fd,void * buf,size_t count);
//fd:这是一个已经打开的文件句柄(一个文件描述符),表示从这个文件句柄所代表的文件读取数据。文件描述符是需要我们用open系统调用后才能得到的,而文件全路经直接写就可以了。
//buf:缓冲区,读取到得数据放在这个缓冲区中去。
//count:表示一次read操作,应该读取多少字节
返回值:成功:返回实际读取的的字符数量;失败:-1
2) stat函数
int_stat(const char *file_name,struct _stat *buffer);
函数说明:通过文件名filename来获取文件的信息,并保存在buffer所指的结构体中。
//file_name:文件名或者目录名
//buffer:结构体对象地址
返回值:成功:0;失败:-1(错误码在error中)
注:intfstat(int filedes, struct stat *buf);
int stat(const char*path, struct stat *buf);
int lstat(const char*path, struct stat *buf);
fstat区别于另外两个系统调用的地方在于,fstat系统调用接受的是一个“文件描述符”,而另外两个则直接接受“文件全路径”。文件描述符是需要我们用open系统调用后才能得到的,而文件全路经直接写就可以了。
stat和lstat的区别:当文件是一个符号链接时,lstat返回的是该符号链接本身的信息;而stat返回的是该链接指向的文件的信息。(似乎有些晕吧,这样记,lstat比stat多了一个l,因此它是有本事处理符号链接文件的,因此当遇到符号链接文件时,lstat当然不会放过。而 stat系统调用没有这个本事,它只能对符号链接文件睁一只眼闭一只眼,直接去处理链接所指文件喽)
12 2015/07/21 星期二
12.1任务一
BitMap类
12.1.1 遇到问题
1. 对BitMap类中各个函数的理解
2. 遇到一些掌握有问题(或者不会)的知识的总结
12.1.2 解决思路
1. BitMap类中(1):
Expand(int64_t index):判断当前m_BitMap中size的大小,若是m_BitMap.size<index,则拓展map的大小为index
GetMeta(const char* path,int32_t& crc, int64_t& bufsize):获取数据,从path路径下读取东西,然后放在crc中,将其大小放在bufsize中。
GetContent(int32_t crc, int64_tbufsize):将crc里的东西,存到m_BitMap容器中。具体过程是:申请bufsize大小空间,然候将从m_Fd(打开的文件)开始读,读取bufsize大小的内容,然候和crc校验是否相同,若是相同,则将其拷贝到m_BitMap容器中,并释放buf。
RenameFile():重命名文件为日期格式。
具体的过程是:首先time(&timeval)函数(返回一个时间形式的大整数)获取当前系统的时间,然后将m_MapPath.c_str()的字符串格式化写入到timeval中(sprintf函数的功能),在用rename函数,将m_MapPath.c_str()重命名为logFile。
Load(const char* path):加载
具体的过程:首先用GetMeta函数,获取path路径下的数据,如果获取成功并且大小大于0,则将其数据存到m_BitMap容器中(调用GetContent函数),并对存在此容器中文件重命名为当前日期的名字文件。
2. 遇到不熟的知识点
a) lseek函数
off_t lseek(int filedes, off_t offset, intwhence);
函数的功能:为一个打开的文件设置偏移量
//filedes:文件名
//offect:偏移量取决于后面的参数wherece
//wherece:决定偏移量。
SEEK_SET、SEEK_CUR和 SEEK_END是wherece的值。
b) sprintf函数
int sprintf( char *buffer, const char *format,[ argument] … );
函数功能:把格式化的数据写到某个字符串中。
返回值:字符串的长度
//buffer:char型指针,指向写入字符串的缓冲区。
//format:格式化字符串
//[ argument] …:可选参数,可以是任何数据类型
注:sprintf函数是个变参函数,使用时总会出问题,而且都是能导致程序崩溃的内存访问的错误。sprintf_s()是sprintf的安全版本,原型是:
int sprintf_s(char *buffer,size_tsizeOfBuffer,const char *format [,argument] ... );
转换字符
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
%%印出百分比符号,不转换。
%c整数转成对应的ASCII字元。
%d整数转成十进位。
%f倍精确度数字转成浮点数。
%o整数转成八进位。
%s整数转成字符串。
%x整数转成小写十六进位。
%X整数转成大写十六进位。
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
另外,strftime()函数和sprintf()函数类似,专门用于格式化时间字符串
c) rename函数
int rename(char *oldname, char *newname);
函数功能:给一个文件重命名
返回值:成功:0;失败:-1
//(1)linux下,如果oldname为一个文件而不是目录,那么为该文件更名。若是这种情况下,newname已经作为一个目录已经存在,那么他不能重命名一个目录。若是newname已经存在,而且不是一个目录,则将其删除,将oldname更名为newname
//(2)为一个目录,则为该目录更名。若是newname已经存在,则他必须是一个空目录,然后先将其删除,然后更名。
13 2015/07/22 星期三
13.1任务一
继续BitMap的类
13.1.1 遇到问题
1. 将剩下的BitMap类中各个函数的理解
2. 遇到一些掌握有问题(或者不会)的知识的总结
13.1.2 解决思路
1. BitMap类(2):
SetCursor(int32_t pos):设置指针的位置,m_Cursor =pos;
ClearBuf():清空缓冲区buf的内容,然后用SetCursor函数将指针的位置设置到0。
Write(const void* buf,int32_t size):将buf中的内容拷贝到m_Buf+Cursor的位置(memcpy函数),然后m_Cursor变成m_Cursor+size。
Store():存储。具体过程:首先打开m_MapPath.c_str()路径下的文件,打开成功后将调用Write()函数,将其buf中的东西写到里面,若是写入成功,则进行同步(Sync()函数),最后关闭文件。
Read(void* buf, int32_tsize):将m_Buf+Cursor所指的东西拷贝到buf中,然后m_Cursor再往后偏移size。
GetLength():返回m_Cursor的值
GetCapacity():获取m_BufSize的大小
Stat2INodeStat(INodeStat*inodestat, const struct stat* stat):INodeStat获取stat中的信息
INodeStat2Stat(constINodeStat* inodestat, struct stat* stat):Stat获取INodeStat中的信息,但是在获取之前首先初始化stat,不然会引起。
GetBit(uint64_t pos):检查pos是否已经被使用了。
UpdateUsage(uint64_t pos,bool exist):更新已使用的。
具体过程:首先算出有多少个m_ExpandSize,然后获取m_MaxUsed的大小,然后她两相减就是未使用的部分,然后将其标记为未使用;接着是根据exit,处理解决占用之情况,这块没看明白,不知道是啥意思。
SetBit(uint64_t pos, boolbit):设置pos为值的状态是否被使用,由bit决定。
具体过程:这里首先说下m_ExpandSize成员变量,表示BitMap增长的规模,一次增长m_ExpandSize个bit。
GetBit(uint64_tpos):判断pos是否被使用。
算出map中的索引,map中的偏移量,内部的(intra)偏移量和索引,如果m_BitMap[i]用光了,则扔一个m_BitMap[i+1]进去,
FillBuf():当存放可用inode的buf使用完了,然后把所有日志整理,获取新的可用inode号。具体的过程是:合并日志(MergeJournal),然后从头到尾遍历一遍,把每个地方都查看下是否已经被使用了(GetBit),将没使用的释放掉。
GetFreeBit():首先看m_Buf(预取出的空闲num的链表)是不是空的,如果是空的,则调用FillBuff()函数进行整理。然后获取首元素的引用,并删掉首元素,并将其设置为未使用状态。然后将其空闲的bit返回。
2. 遇到不熟的知识点
a) memcpy函数
void*memcpy(void *dest, void *src, unsigned int count);
函数功能: 把资源内存(src所指向的内存区域) 拷贝到目标内存(dest所指向的内存区域),拷贝大小由第三个参数count决定。
返回值:一定要返回一个值(指针)
//dest:拷到dest指的位置
//src:拷src所指向的东西
//count:大小
注:(1)首先要判断指针的值不能为空,desc为空的话肯定不能拷贝内存空间,src为空相当于没有拷贝;所以之间return掉;
(2)" " 空串是指内容为0,NULL是0,不是串;两个不等价;
(3)int dest[2] = {0};这是对int 类型的数组初始化的方法;如果是char类型,就用char a[5] ="1234"; 注意数组下标要 多于实际看到的字符数,因为还有'/0'
(4)如果初始化的时候:
char dest[1024] = "12345666";//{0};
const char src[5] = "3333";
那么拷贝的时候,如果用memcpy1(dest,src,sizeof(src));则printf(dest);出来是3333。如果memcpy1(dest,src,4);则printf(dest);出来是33335666;因为上面的sizeof(src),包含'/0',所以拷贝过去的字符串以'/0'结束,就只有3333,而如果传4个字符,'/0'是第五个字符,那就遇到dest[1024] 的'/0'结束,所以是33335666。
字符串的'/0'问题一定要注意。
b) memset函数
void*memset(void *buffer, int c, int count);
函数功能:把buffer所指内存区域的前count个字节设置成字符c。memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。
返回值:
//buffer:指针或是数组
//c:赋给buff的值
//count:buffer的长度
注:初始化一块内存最好的方法,src和dest所指内存区域不能重叠,函数返回指向dest的指针。
c) strcpy函数(智能拷贝字符串)
char*strcpy(char *dest,char *src);
函数功能:把src所指由NULL结束的字符串复制到dest所指的数组中。
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
d) Vector容器
vector类称作向量类,它实现了动态数组,用于元素数量变化的对象数组。像数组一样,vector类也用从0开始的下标表示元素的位置;但和数组不同的是,当vector对象创建后,数组的元素个数会随着vector对象元素个数的增大和缩小而自动变化。
· vector():创建一个空vector
· vector(int nSize):创建一个vector,元素个数为nSize
· vector(int nSize,constt& t):创建一个vector,元素个数为nSize,且值均为t
· vector(constvector&):复制构造函数
· vector(begin,end):复制[begin,end)区间内另一个数组的元素到vector中
· void push_back(constT& x):向量尾部增加一个元素X
· iterator insert(iteratorit,const T& x):向量中迭代器指向元素前增加一个元素x
· iterator insert(iteratorit,int n,const T& x):向量中迭代器指向元素前增加n个相同的元素x
· iterator insert(iteratorit,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据
· iterator erase(iteratorit):删除向量中迭代器指向元素
· iterator erase(iteratorfirst,iterator last):删除向量中[first,last)中元素
· void pop_back():删除向量中最后一个元素
· void clear():清空向量中所有元素
· reference at(int pos):返回pos位置元素的引用
· reference front():返回首元素的引用
· reference back():返回尾元素的引用
· iterator begin():返回向量头指针,指向第一个元素
· iterator end():返回向量尾指针,指向向量最后一个元素的下一个位置
· reverse_iteratorrbegin():反向迭代器,指向最后一个元素
· reverse_iterator rend():反向迭代器,指向第一个元素之前的位置
· bool empty() const:判断向量是否为空,若为空,则向量中无元素
· int size() const:返回向量中元素的个数
· int capacity() const:返回当前向量张红所能容纳的最大元素值
· int max_size() const:返回最大可允许的vector元素数量值
· void swap(vector&):交换两个同类型向量的数据
· void assign(int n,constT& x):设置向量中第n个元素的值为x
· voidassign(const_iterator first,const_iterator last):向量中[first,last)中元素设置成当前向量元素
·
进一步理解vector,如下图所示
当执行代码vector<int> v(2,5)时,在内存里建立了2个整形元素空间,值是5.当增加一个元素时,原有的空间由2个编程4个整形元素空间,并把元素1放入第3个整形空间,第4个空间作为预留空间。当增加元素2时,直接把值2放入第4个空间。当增加元素3时,由于原有向量中没有预留空间,则内存空间由4个变为8个整形空间,并把值放入第5个内存空间。
总之,扩大新元素时,如果超过当前的容量,则容量会自动扩充2倍,如果2倍容量仍不足,则继续扩大2倍。
14 2015/07/23 星期四
14.1任务一
DentryStore类,JournalEntry类,PersistentStore类
14.1.1 遇到问题
1. DentryStore类的理解
2. JournalEntry类的理解
3. PersistentStore类的理解
14.1.2 解决思路
1. DentryStore类
1) Lookup在map和LRU中
2) Add +Load VS Delete + UnLoad(添加目录到map中,从map和LRU中删除)
3) Protected:map<int64_t,INode*> m_ModifiedDentry;
避免出现大的map和Dentry已经被限制
2. JournalEntry类
首先:JournalOpr== char(记住这个取别名的变量,之前看好多次)
里面主要定义了,
(1)一些结构体:
OprEntry,JournalEntry,INameAdd,INameDel,BidAdd,INodeAdd,INodeDel,IdxPidAdd,AttrSet,SymAdd,PidDel,OprHead,OprItem等
(2)一些模板类函数:
inline voidOprItem<Type>::Delete(OprItem<Type>* oi)
inline int32_t OprItem<Type>::BodySize()
inline int32_t OprItem<Type>::TotalSize()
OPR_END ATOMIC_BEGIN ATOMIC_END INIT_FLAG无CRC仅一个JournalOpr在文件中,其他均包含一个头部信息struct OprHead。OprHead中包含CRC。
3. PersistentStore类
GetFreeINode():获取一个未使用的node从mainbitmap中或者extend bitmap中。
erge(vector<JournalEntry>&entrySet):逐个处理vector中的JournalEntry,将其合并到持久化的文件中。
Load(intloadNum, Journal* j, int64_t& usedCnt, int64_t& totalSize):将全部node的使用情况更新到位图中,并加载指定数量的LoadNum的inode元数据到内存中。(loadNum是1~loadNum范围,无论使用还是没有使用,LoadNum的INode的数目是<=loadNum)
Lookup(int64_tnum, INodeStat* statBuf):将指定的num对应的INodeStat填充到INodeBuf中。
LookUp()——LookUpSym()——LookUpFile():返回值:>0,说明找到正确的inodenum;=0,说明找到;<0,没有找到。
15 2015/07/24 星期五
15.1任务一
FixedLengthStore类
FixdPageFile类(一)
15.1.1 遇到问题
1. 对FixedLengthStore类的理解
2. 对FixdPageFile类的理解
15.1.2 解决思路
1. FixedLengthStore类(继承PersistentStore类)——(声明里面都是纯虚函数,方便继承)
GetInoSize():其实就是m_InoSize。
GetInoCnt():调用INodeStore类中GetInoCnt函数;
在INodeStore类中对其函数进行详细的说明
DelInodeInMem(int64_tnum):调用INodeStore类中DelInodeInMem函数;
在INodeStore类中对其函数进行详细的说明
GetInodeInUse(int64_tnum):调用INodeStore类中GetInodeInUse函数;
在INodeStore类中对其函数进行详细的说明
PreAlloc(INode*inode, const char* name, struct DirIndex& di):调用INameStore中PreAlloc函数。
Store(): 存储,分别调用下面四个类中的store函数。
² INodeStore::Store()
² INameStore::Store()
² SymTgtStore::Store()
² FileBidStore::Store()
GetCntPerFixed(int& pi dPerFixed, int& bidPerFixed):调用FileBidStore类中的函数
//两个lookup对空洞的处理(注释上是这么说的,空洞是啥意思),出现一个FixedLengthStore实例同时调用Lookup
Lookup(int64_t num, INodeStat*statBuf):定长载入载入指定INodeNum的定长记录并填充到INodeBuf中
Lookup(INode* inode, const char*name):变长载入
----------------------------------------------------------------------------------------------------------------
LookupFile(INode* inode, int32_tbidSeq, int interBidCnt, void* bidBuf, short bidSize):调用FileBidStore中LookUpFile函数
GetFreeINode():调用INodeStore类中GetFreeINode函数
2. FixdPageFile类(一)
Load():将m_DirPath中的东西加载到m_BitMap中。
具体过程:先将路径m_DirPath和名字bitmap拼接起来,然后调用BitMap类中load(在BitMap类中有该函数的额说明),然后根据其返回值判断接下来操作,如果返回值==NEED_RECOVERY,则说明bitmap需要恢复;若返回值<0,则说明load加载失败;如果都不是,则说明加载成功,加载状态至于true。
Reclaim(int64_t pid):(reclaim意思是开拓、回收再利用)
具体过程:首先调用Load函数,将m_DirPath中的东西加载到m_BitMap中,若果加载成功则调用WriteMeta函数,将pid对应的文件块写入。
² WriteMeta(int64_tpid, bool exist):将pid对应的文件块写入,然后根据参数exist设置pid的状态(是否被使用)。
Ø Write(int64_t pid, int32_t offset, Converter& er):根据pid算出fd,索引,大小,偏移量,然后根据pwrite函数,将缓冲区的东西写入fd文件,返回值是写入文件的字节数。最后比较返回的字节数和前面文件大小是否相等,若是相等则返回0表示成功。
ü GetFileFd(int64_tpid):根据pid算出文件ID,然后根据ID判断文件是否存在,若是存在则格式化文件名,然后将其存入LRU中,并返回新的newfd。
GetFileID():文件ID从1开始,pid从1开始。算出ID返回出去。
m_FdSet.exists(file):在map中找file文件,能否找到,找到怎说明文件存在,找不到则说明失败。
GetName(int32_tfileID):根据文件的ID获取文件名
OpenFile((string&fileName, int fileID)):打开fileName的文件(不存在则创建),然后将其插入到LRU中(m_FdSet.insert),若是已存在,则替换,然后在判断LRU是否已经存满了,若是则删除最后一个。
ü GetOffsetInFile(int64_t pid):根据pid算出偏移量在File中,也就是File的索引。
ü er.GetLength():长度也就是m_Cursor。
Ø SetBit(int64_tpid, bool exist):调用BitMap类中SetBit,设置pid的是是否被使用。
16 2015/07/27 星期一
16.1任务一
FixdPageFile类(二)
16.1.1 遇到问题
1. 继续对FixdPageFile类中成员的理解
2. 原子操作
3. 由于对Linux下一些快捷键掌握不是很多,对其加以总结,和练习
16.1.2 解决思路
1. FixdPageFile类(二)
GetCountInFile(int64_tsize):获取File文件中有多少文件块
GetMaxPid():获取位图的最大值,最大持久化文件的id号*每个文件存储pid的最大个数
Store():先调用BitMap类中的Store()函数(BitMap类中有说明),是将buf中的东西存下来,然后利用m_FdSet.get_all_keys()函数获取所有有key值的一个链表,最后挨个关闭这些小的文件,达到持久化存储的目的。
Alloc():分配一个空闲的bit。具体过程是调用BitMap类中GetFreeBit()函数。
GetMaxUsedBit():获取Bit的最大使用量。
Read(int64_tpid, int32_t offset, int32_t size, Converter& er):将pid对应的文件数据读到缓存中。
具体过程:根据pid算出fd,索引,大小,偏移量,然后根据pread函数将奋斗文件东西读出来放到缓冲区er.GetBuf中,并返回读取到文件的字节数。注意:执行后文件的偏移指针没有变。
ReadPage(int64_tpid, int32_t offset, int32_t size, Converter& er):先将m_DirPath中的东西加载到m_BitMap中,若加载成功,然后检查pid是否被占用,然后通过 Read 函数,将pid对应的文件数据读到缓存中。
Recovery():恢复文件。具体过程:首先求出文件id,然后让pid从1开始循环读取数据到缓冲区,然后算出exist的状态,然后根据exist状态设置pid的使用状态。
2. 原子操作
所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。
pread函数和pwrite函数:(原子操作)
(1) pread()
形式:#include
ssize_t pread(int filedes, void*buf, size_t nbytes, off_t offset);
成功:返回读到的字节数;出错:返回-1;到文件结尾:返回0
参数:
(1) fd:要读取数据的文件描述符
(3) count:读取数据的字节数
(4) offset:读取的起始地址的偏移量,读取地址=文件开始+offset。注意,执行后,文件偏移指针不变
原因:由于lseek和read 调用之间,内核可能会临时挂起进程,所以对同步问题造成了问题,调用pread相当于顺序调用了lseek 和 read,这两个操作相当于一个捆绑的原子操作。
实现:文件(由filedes所指)-读nbytes字节->内存buf中。
补充:调用pread时,无法中断其定位和读操作,另外不更新文件指针。
(2) pwrite()
形式:#include
ssize_t pwrite(int filedes, const void*buf, size_t nbytes, off_t offset);
成功:返回已写的字节数;出错:返回-1;
参数:
(1) fd:要写入数据的文件描述符
(3) count:写入文件中的数据的字节数
原因:由于lseek和write 调用之间,内核可能会临时挂起进程,所以对同步问题造成了问题,调用pwrite相当于顺序调用了lseek 和 write,这两个操作相当于一个捆绑的原子操作。
实现:文件(由filedes所指)<-写nbytes字节-内存buf中。
补充:调用pwrite时,无法中断其定位和读操作,另外不更新文件指针。
注:补充说明read和write函数
l read函数
ssize_t read (intfd, void *buf, size_t count);
返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0。
参数:
fd:要读取数据的文件描述符
count:请求读取的字节数,读上来的数据保存在缓冲区buf中,同时文件的当前读写位置向后移。
补充:有多种情况可使实际读到的字节数少于要求读的字节数:
当从普通文件读时,在读到要求字节数之前已到达了文件尾端。
当从终端设备读时,通常一次最多读一行。
当从网络读时,网络中缓冲机构可能造成返回值小于所要求读的字节数。
当从管道或FIFO读时,如若管道包含的字节少于所需的数量,那么只返回实际用
的字节数。
当从某些面向记录的设备读时,一次最多返回一个记录。
当某一信号造成中断,而已经读了部分数据量时。
l write函数
ssize_t write (int fd,const void * buf,size_t count);
说明:把指针buf所指的内存写入count个字节到参数fd所指的文件内。注意,文件读写位置也会随之移动。
返回值:如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。
参数:
fd:要写入数据的文件描述符
count:写入文件中的数据的字节数
补充:write出错的一个常见的原因是:磁盘已写满,或者超过了一个给定进程的文件长度限制。对于普通文件,写操作从文件的当前偏移量处开始。如果在打开该文件时,指定了O_APPEND选项,则在每次写操作之前,将文件偏移量设置在文件的当前结尾处。在一次成功写之后,该文件偏移量增加实际写的字节数
fread和read,fwrite和write的区别:
就是是否带缓冲,只单纯的系统调用。系统内核对磁盘的读写都会提供一个块缓冲,当用write函数对其写数据时,直接调用系统调用,将数据写入到块缓冲进行排队,当块缓冲达到一定的量时,才会把数据写入磁盘。
不带缓冲的I/O是指进程不提供缓冲功能。每调用一次write或read函数,直接系统调用。
带缓冲的I/O是指进程对输入输出流进行了改进,提供了一个流缓冲,当用fwrite函数网磁盘写数据时,先把数据写入流缓冲区中,当达到一定条件,比如流缓冲区满了,或刷新流缓冲,这时候才会把数据一次送往内核提供的块缓冲,再经块缓冲写入磁盘
3. 快捷键小结
ctrl和按键组合
Ctrl+c 结束正在运行的程序
Ctrl+d 结束输入或退出shell
Ctrl+s 暂停屏幕输出【锁住终端】
Ctrl+q 恢复屏幕输出【解锁终端】
Ctrl+l 清屏,【是字母L的小写】等同于Clear
Ctrl+a 切换到命令行开始
Ctrl+e 切换到命令行末尾
Ctrl+u 清除剪切光标之前的内容
Ctrl+k 清除剪切光标及光标之后的内容
Ctrl+y 在光标处粘贴剪切的内容
Ctrl+r 查找历史命令【输入关键字,就能调出以前执行过的命令】
Ctrl+t 调换光标所在处与其之前字符位置,并把光标移到下个字符
Ctrl+x+u 撤销操作
Ctrl+z 转入后台运行【用户退出时,停止。请参阅曾写blog:linux ctrl+Z的作用 】
vim 常用命令
1、光标移动
上:k 下:j 左:l 『字母L小写』 右:h
上一行行首:-
下一行行首:+
行首:0 『数字0』
行尾:$
单词词尾或后一个单词词尾:e
后一个单词词首:w
单词词首或前一个单词词首:b
跳转到特定行::行号 ( :5 :跳转到第5行 )
上一屏:ctrl + b 下一屏:ctrl + f
上半屏:ctrl + u 下半屏:ctrl + d
向上滚屏:ctr + y 向下滚屏:ctr + e
跳到文件头:gg 跳到文件尾:G
2、搜索
向后模式搜索:/ + 搜索模式
向前模式搜索:?+ 搜索模式
注意:结合n和N向前向后查找
3、追加或插入
光标右侧追加:a
光标行尾追加:A
光标左侧追加:i
光标行首追加:I 『i 的大写』
光标下方插入行:o 【字母o】
光标上方插入行:O 【字母o的大写】
n到m行行首插入#: :n,m s/^/#/g 『1到5行,行首插入wow :1,3 s/^/wow/g 』
n到m+l行行首插入#: :n,+l s/^/#/g『1到6行,行首插入# :1,+5 s/^/#/g 』
4、删除
删除光标:x
删除光标左侧:X
删除光标所在的单词:dw
删除当前行:dd
删除光标至行尾:d$或D
删除当前行及以下n-1行:ndd
删除n到m行: :n,m d
5、复制粘贴
复制光标所在的单词:yw
复制光标至行尾:y$ 或Y
复制当前行:yy
复制行n次:yyn
复制当前行及以下n-1行:nyy
复制n到m行,粘贴到k+1行: :n,m co k
剪切n到m行,粘贴到k+1行: :n,m m k
粘贴到光标下:p
粘贴到光标上:P
6、撤销回复
撤销:u
恢复:ctrl + r
7、替换
替换光标所在的字符:r
替换一个单词:cw
替换光标所在的前一个字符:cb
替换光标至行尾的所有字符:c$
替换当前行:cc
替换当前行的第一个old为new: :s/old/new
替换当前行的所有的old为new::s/old/new/g
替换当前行到最后行的第一个old为new::.,$s/old/new
替换当前行到最后行的所有old为new::.,$s/old/new/g
替换第n行到第m行的第一个old为new::n,m s/old/new
替换第n行到第m行的所有old为new::n,m s/old/new/g
替换所有行的第一个old为new: :%s/old/new
替换所有行的所有old为new: :%s/old/new/g
17 2015/07/28 星期二
17.1任务一
INameStore类(目录)
INodeStore类(一)
17.1.1 遇到问题
1. 对INameStore类的理解
2. 对INodeStore类的理解(一)
17.1.2 解决思路
1. INameStore类
Load(Journal* j):将m_DirPath中的东西加载到m_BitMap中
HandleCurBlock(DirIndex* di, INode*inode, const char* name):先将某Block读到Converter中,然后将读到的Block解析,并加入到IName数组中,最后返回查询结果。如果读取的结果有效,加载到内存。
² ParseBlock(DirIndex*di, Converter& er, vector<IName>& inSet, const char* name):解析block。
ü GetIName(DirIndex*di, Converter& er, vector<IName>& inSet, const char* name):获取名字
² LoadBlock(INode*inode, vector<IName>& inSet):
ü Load(Journal*j):将m_DirPath中的东西加载到m_BitMap中
Lookup(INode* inode, const char*name):获取DirIndex作为查询的依照并进行初次访问的初始化,获取当前访问INode的属性,以获得ID和Mode用以写日志,循环访问每个Block以查询某name或直接遍历全部Block,单独处理最后一个Block空的情况。
HandleEmptyBlock(DirIndex* di,INodeStat& stat, bool lastEmpty, bool curEmpty):根据当前Block的处理返回值将失效块记录于日志中,然后根据当前Block的处理返回值将块链表的修复补丁记录于日志中。
PreAlloc(INode* inode, const char*name, struct DirIndex& di):
AddIName(JournalEntry& je, intbegin, int end):更新目录的时候。
WriteHead(int32_t curPid, int32_tnextPid):
DelIName(JournalEntry& je, intbegin, int end):
DelBlk(JournalEntry& je, intbegin, int end):
2. INodeStore类(一)
LookupSize(int64_tnum):获取num对应数据的大小。
先将m_DirPath中的东西加载到m_BitMap中,若加载成功,然后检查pid是否被占用,将pid对应的文件数据读到缓存中。然后将缓存里的东西再读到stat中,然后计算其数据的大小。
GetTotalSize():计算已使用INo对应的总大小。
先调用FixedPageFile类中GetMaxUsedBit()函数以获取Bit的最大使用量。然后判断这些使用量中的每一个ino是否存在,若不存在则进入下一次循环,存在则计算其大小,然后一直将求出总大小。
Load(intloadNum, DentryStore* mem, int64_t& usedCnt, int64_t& totalSize):
将m_DirPath中的东西加载到m_BitMap中,然后通过函数GetTotalSize获取系统总数据量,如果其返回值是-1,则需要从持久化文件中获取,非-1,则不做任何操作。
Lookup():先根据statBuf指针和CommonStat成员获取其整个结构体的指针(container_of宏的功能),然后将num对应的数据读到缓存中,在讲缓存中的数据读到&inodeBuf->CommonStat,然后再根据判断文件是目录,还是常规文件,还是是一个链接,根据下面几个函数:
S_ISREG(st_mode):是否是一个常规文件.
S_ISDIR(st_mode):是否是一个目录
S_ISLNK检查文件模式是否文件是一个符号链接。如果是这样,返回True
如果是上面一种,则返回0;如果都不是的话返回-1。
18 2015/07/29 星期三
18.1任务一
INodeStore类(二)
18.1.1 遇到问题
1. 对INodeStore类的理解(二)
2. container_of的使用
4. LL
18.1.2 解决思路
1. INodeStore类(二):
GetFreeINode():获取一个空闲的INode(FixedPageFile类Alloc()函数功能:分配一个空闲的bit)
GetInterBidMaxCnt():获取最大的Bid使用量(不知道理解对不)
Store():调用FixedPageFile类中Store函数,将buf中的东西存储,达到持久化存储(详细请查看FixedPageFile::Store函数的解释)。
AddINode(int64_tnum, OprEntry& opr):添加一个INode。
SetAttr(JournalEntry&je, int begin, int end):
步骤1:获取每个里的最后一个,SA_MKNOD3 SA_MKDIR2,mpSet。
步骤2:翻译内容从mpSet到pmSet的内容。
步骤3:将pmSet中每一个mask合并
² WriteByMask(JournalEntry& je, int32_t pos,int64_t mask):通过文件模式
l GetSegFromMask(int64_t mask,vector<int64_t>& posSet):(这块没看明白,先搁置下,看后面的)
DelINode(int64_t num, OprEntry&opr):不是真的删除这个inode,而是对齐进行回收利用。直接调用FixedPageFile类中Reclaim函数,现将num的东西写入,然后设置num的状态(详见Reclaim函数)
DelInodeInMem(int64_t num):设置num的状态
GetInodeInUse(int64_t num):判断num的bit是否被使用
GetInoCnt():ino使用的总数。
2. container_of的用法:
#define container_of(ptr, type, member) (
{
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type*)( (char *)__mptr - offsetof(type,member) );
} )
解决了如何通过结构体中某个变量的地址获取结构体本身的指针的问题。
container_of实现了根据一个结构体变量中的一个成员变量的指针来获取指向整个结构体变量指针的功能。
S_ISLNK(st_mode):是否是一个连接.
S_ISREG(st_mode):是否是一个常规文件.
S_ISDIR(st_mode):是否是一个目录
S_ISCHR(st_mode):是否是一个字符设备.
S_ISBLK(st_mode):是否是一个块设备
S_ISFIFO(st_mode):是否是一个FIFO文件.
S_ISSOCK(st_mode):是否是一个SOCKET文件
4. LL
LL是long long int的意思,C99标准的新东西。
是一个长度修饰符,表示他前面跟的数字是长长整型,(如果你写的整形数大于了整型的长度,这样就会报错,而加上就不会)
eg. 1LL,长长的整型的1。
19 2015/07/30 星期四
19.1任务一
FileBidStore类(文件)
19.1.1 遇到问题
1. 对FileBidStore类的理解
19.1.2 解决思路
1. FileBidStore类:
Load():重建位图
GetCntBySize(int size):根据大小获取bid的的数量
DelBlk(JournalEntry& je, intbegin, int end):从begin到end回收JournalEntry中curbid。
AddIdxPid(JournalEntry& je, intbegin, int end):将je里的东西通过转换器都写到文件中。
DelBlk(JournalEntry& je, intbegin, int end):把je里从begin到end的block回收,得出每个curpid,将curpid对应的数据写到文件,然后设置curpid的使用状态、
AddBid(JournalEntry& je, intbegin, int end):获取je中的东西,然后将curpid对应的数据挨个写到文件中。
GetIdxType(int seqNum, int&type):获取索引的类型,是以及索引还是耳机索引。
GetBidIndex(INode* inode, int32_tbidSeq, int interBidCnt, struct BidIndex& bi):获取bid的索引。先算出序列号(bidSeq - interBidCnt),然后获取索引的类型,然后根据不同的类型得到不同case,看是一级索引bid号(直接存储pid)而是二级索引(存储一级索引pid号),若是一级的,则直接给bi;若是二级索引,则先用ReadInPidCache函数获取tmpPid,若是大于0,则就是了给bi即可。然后,若果序列号是m_BidPerFixed的整数倍,则PushIdxPid函数,设置偏移量位置pid为-1;如果是序列号和m_BidPerFixed相等,则二级索引为0。
ReadInPidCache(structFileIndex*& fi, int32_t offsetNum):读取pid,通过偏移量offsetNum从pidCache里获取pid。
PushIdxPid(struct FileIndex*&fi, int32_t offsetNum, int32_t pid):在pid缓存中偏移量offsetNum位置修改pid。
20 2015/07/31 星期五
20.1任务一
SymTgtStore类(符号链接)
20.1.1 遇到问题
1. 对SymTgtStore类的理解
2. 符号链接(软链接)和硬链接
20.1.2 解决思路
1. SymTgtStore类:
Load():将m_DirPath中的东西加载到m_BitMap中。
LookupSym(INode* inode):查找inode号对应的符号链接。
PreAllocSym(INode* inode, const char* name,struct SymIndex& si):根据name获取pid的个数,然后通过Alloc函数分配一个空闲的bit。
AddSymlink(JournalEntry& je, int begin, intend):添加软链接
DelSymlinkPid(JournalEntry& je, int begin,int end):删除pid的符号链接
GetPidCntByName(const char* name):通过name获取pid的个数
2. 符号链接(软链接)和硬链接:
软链接(符号链接) |
区别:硬链接原文件&链接文件公用一个inode号,说明他们是同一个文件,而软链接原文件&链接文件拥有不同的inode号,表明他们是两个不同的文件;在文件属性上软链接明确写出了是链接文件,而硬链接没有写出来,因为在本质上硬链接文件和原文件是完全平等关系;链接数目是不一样的,软链接的链接数目不会增加;文件大小是不一样的,硬链接文件显示的大小是跟原文件是一样的,这用强调,因为是等同的嘛,而这里软链接显示的大小与原文件就不同了。一句话,建立软链接就是建立了一个新文件,而硬链接不建立新文件。
21 2015/08/03 星期一
21.1任务一
store中各个类之间的关系
21.1.1 遇到问题
1. Store中类的关系
2. 类和类之间的各种关系
3. 对bid的理解
21.1.2 解决思路
1. 类的关系图(有点小)
2. 类和类之间的依赖、关联、聚合、组合关系
² 继承关系
继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力。在UML类图设计中,继承用一条带空心三角箭头的实线表示,从子类指向父类,或者子接口指向父接口。
² 实现关系
实现指的是一个class类实现interface接口(可以是多个)的功能,实现是类与接口之间最常见的关系。在UML类图设计中,实现用一条带空心三角箭头的虚线表示,从类指向实现的接口。
² 依赖关系
简单的理解,依赖就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是类B的变化会影响到类A。比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖。表现在代码层面,为类B作为参数被类A在某个method方法中使用。在UML类图设计中,依赖关系用由类A指向类B的带箭头虚线表示。
² 关联关系
关联体现的是两个类之间语义级别的一种强依赖关系,联可以是单向、双向的。表现在代码层面,为被关联类B以类的属性形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量。在UML类图设计中,关联关系用由关联类A指向被关联类B的带箭头实线表示,在关联的两端可以标注关联双方的角色和多重性标记。
² 聚合关系
聚合是关联关系的一种特例,它体现的是整体与部分的关系,即has-a的关系。此时整体与部分之间是可分离的,它们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。在UML类图设计中,聚合关系以空心菱形加实线箭头表示。
² 组合关系
组合也是关联关系的一种特例,它体现的是一种contains-a的关系,这种关系比聚合更强,也称为强聚合。它同样体现整体与部分间的关系,但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周期结束。表现在代码层面,和关联关系是一致的,只能从语义级别来区分。在UML类图设计中,组合关系以实心菱形加实线箭头表示。
首先这是他的结构体:
structBID
{
short Size;
char Buf[0];
static BID* Create(short size)
{
int bufSize = sizeof(BID) + size;
BID* tmp = (BID*)new char[bufSize];
memset(tmp, 0, bufSize);
tmp->Size = size;
return tmp;
}
static void Delete(BID* p)
{
delete [] p;
}
};
我认为他是一小块文件,文件系统前一个版本存在的东西,就是存在磁盘上的一个固定大小文件里面的一个小块文件。
(个人理解,如果不对请指教)
22 2015/08/04 星期二
22.1任务一
对系统中,一些结构的理解
22.1.1 遇到问题
文件系统中的一些数据类型
22.1.2 解决思路
1. 文件系统中的一些数据类型
buf:buf是目录保存中的用来提供给boost序列化/反序列化的缓冲区(string类型)
FileMap:将buf反序列化后存入FileMap中,FileMap中存入(string,FileNode)类型键值对
chunk:划分每个小的数据块
chunk的存储结构:
chunk
{
int length;//长度
short Crc;//Crc校验码
char Buffer[];//数据缓冲区
}
chunkpos:chunk的位置,由fileID,offset,length组成
chunkIdex:chunk形成的索引,由chunkhash,offsetInblock,chunkpos组成
Block:多个chunk组成Block,每个Block的长度不定,但是有最大长度的限制,用于记录文件的内容,文件越大,则有多个Block
BlockSid:Block的特征值,用来进行Block相似性检索,目前选取chunkIndex中n(可变)个最小值作为其sid,两个Blocksid中将其相等的chunkhash表示两Block相似度
BlockIdex:Block划分为chunk后形成的索引。
BlockIndexPos:BlockIdex的存贮位置。
inode:一个文件只对应一个inode,用于记录文件的属性,和文件数据所在的block号码
superblock:记录FileSystem,包括inode、block总量、使用量,剩余量,还有其他文件系统信息。
23 2015/08/05 星期三
23.1任务一
文件系统的操作流程
23.1.1 遇到问题
读流程
写流程
更新流程
23.1.2 解决思路
1. 写流程
2. 读流程:
3. 更新流程
24 2015/08/06 星期四
24.1任务一
MetaManagerImpl类
24.1.1 遇到问题
对MetaManagerImpl类的理解
24.1.2 解决思路
1. MetaManagerImpl类:
Init():新建Journal及INodeMap对象,合并日志及初始化位图。
StoreTotalSize(int64_t&total):在系统系在是保存total的值。
LoadTotalSize(int64_t&total):在系统启动时,读取上次保存的total值,如果找不到对应的文件,则上次没有征程卸载,需要恢复。
Unlink(int64_tparent, const char* name):更新内存中文件的大小
a) 获得父目录对象并设置最大版本号以防止被合并线程删除
b) 在父目录对象中查找,获得要删除name的描述信息(文件包括硬链接、目录、符号链接)
c) 根据b步骤中获得的Ino获取name的对象
d) 获取name的属性信息,并设置其为最大版本号
e) 分类型处理删除符号链接,硬链接,目录的特殊情况。如果是符号链接需要填充SymIndex于INodeBuf中以便于SymTgtStore去删除符号链接内容;如果是硬链接则不得删除该INode。并减少引用计数。如果是目录需减少父目录的引用计数。
f) 设置父目录的时间戳及可能更改的引用计数。
g) 写删除日志,并获得当前的日志版本号
h) 更新内存中的元数据对象
InitINodeStat(INodeStat& stat,int64_t ino, int32_t nlink):初始化INode信息
LoadDentry(INode* inode, constchar* name, int64_t num):加载目录到内存中
Statfs(int64_t maxAvailSize,int64_t& maxInoNum, int64_t& usedInoCnt):根据最大使用量计算出inode的最大号码和inode的使用量
Link(int64_t ino, int64_tnewparent, const char* name, INodeStat& statBuf):链接
a) 获取父目录对象并设置最大版本序列号,然后在父目录中找,获得要链接name的描述信息,设置为正在使用的状态然后di将会更新,
Rename(int64_t parent, const char*name, int64_t newparent, const char* newname):重命名
ReadBid(int64_t ino, int32_tbidSeq, void* bidBuf):从vector中查找,若找到了则设置buf,要是找不到则从磁盘上查找,然后将其压到vector中。传入参数:文件ino号,bid序号,bidBuf,传出参数:-1失败, 0成功
WriteBid(int64_t ino, int32_tbidSeq, const void* bidBuf, int64_t fileSize):写bid,传入参数:文件ino号,bid序号,bid,对应的文件大小,传出参数:-1失败, 0成功
DeleteBid(int64_t ino, int32_tbidSeq, int64_t fileSize):删除bid,传入参数:文件ino号,bid序号,对应文件大小,传出参数:-1失败, 0成功
GetMaxSeqNum(int64_t ino):根据ino号,获取最大的序列号
Readlink(int64_t ino):根据ino号读取链接
Symlink(const char* target, int64_tparent, const char* name, INodeStat &statBuf):符号链接
Mkdir(int64_t parent, const char*name, INodeStat& statBuf):创建一个文件目录
Mknod(int64_tparent, const char* name, INodeStat& statBuf):
SetFileSize(int64_t ino, int64_tfileSize, int journalLabel):设置文件的大小
Setattr(int64_t ino, int32_t mask,INodeStat& statBuf):设置文件属性
Getattr(int64_t ino, INodeStat&statBuf):获取文件属性
UpdateState():更新
SetMetaStateStore(MetaStateStore*stateStore):设置元数据存数状态
Lookup(int64_t parent, const char*name):查找,根据文件名在在父目录下查找,找出对应的num,首先在内存中查找,要时没有找到,则在磁盘中查找
25 2015/08/07 星期五
25.1任务一
FuseDispatcher类
25.1.1 遇到问题
1. 对FuseDispatcher类的理解
2. 对其中XXXLL函数,基本都是一个空的东西,然后调用FuseOpr类中的函数,但是FuseOpr函数只有.h没有.cpp,实现部分没有发现,函数调用完后,在进fuse_reply_attr函数,不知道这个函数有啥意思。
3. 一些额外的小知识点
25.1.2 解决思路
1. FuseDispatcher类:
GetMetaBase(MetaParam* mp):获取数据参数的信息
通过文件名来获取文件信息的状态,保存在statbuf中,然后判断是不是目录(不是目录则写入错误信息),创建路径,并补全各个路径
ParseParam(MetaParam* mp):解析参数,检测INode、File、Dir、Sym、JournalDirPath等的路径是否正确,然后再检测他们的大小是否是在正常的范围
InitLowLevelOps(fuse_lowlevel_ops& ops):初始化挂载的实例opr。参数中放入mask,并根据mask进行函数指针赋值。
LowLevelMain(FuseOpr* opr, MetaParam* mp, intargc, char** argv):提供挂载主函数,opr是实例,mp为配置参数
InitRootMeta(MetaParam* mp, char* mountpoint):根据挂载点初始化数据
2. 找完所有代码,都是没有发现实现部分,不清楚是什么功能
3. 小知识点
a) fopen()函数
FILE *fopen(char *filename, *type);
说明:用于文件的打开,返回一个打开文件的指针
Filename:要打开的文件名
Type:打开文件的使用方式(读,写,追加,二进制文件)
介绍函数后,了解下面的先验知识。
o 流(stream)和文件(File)
为编程者和被访问的设备之间提供了一层抽象的东西,称之为"流",而将具体的实际设备叫做文件。流是一个逻辑设备,具有相同的行为。因此,用来进行磁盘文件写的函数也同样可以用来进行打印机的写入。对磁盘来说就是文本文件和二进制文件。C语言2.0没有对此做特别的说明。
o 文件指针FILE
FILE一个包括了文件管理有关信息的数据结构,即在打开文件时必须先定义一个文件指针。
b) open和fopen函数的区别:
前者属于低级IO,后者是高级IO。
前者返回一个文件描述符(用户程序区的),后者返回一个文件指针。
前者无缓冲,后者有缓冲。
前者与 read, write等配合使用,后者与fread, fwrite等配合使用。
后者是在前者的基础上扩充而来的,在大多数情况下,用后者。
c) 函数指针的赋值(给函数赋值)
int fun(int a,intb)
{
return a + b;
}
main()
{
int g_fun(int a,intb);
g_fun = fun;
return 0;
}
函数名,其实就是一个指针,函数名指向该函数在内存中的首地址。
ct.pClassFun=&ct.print; //
外部将类中函数指针赋值为类中函数地址,注意这里print是static即静态函数,否则不能赋值。
26 2015/08/17—2015/08/21周报
26.1任务一
在自己电脑上安装adfs
26.1.1 遇到问题
1. linux拓展磁盘容量(因为adfs的安装需要很大空间,原来的不够)
2. 安装完文件系统后,在挂载点下创建文件,提示:无法打开并写入文件。
3. 挂载adfs时,挂载失败,提示:
fuse: mountpoint is not empty
fuse: if you are sure this is safe, use the 'nonempty' mount option
4. 接着遇到的问题2
26.1.2 解决思路
1. linux拓展磁盘有两种方法:
一是直接添加一个新的linux系统,这样做的缺点是上面的资料,以及安装的插件都没有了,得重新弄,有些自己不会装的就完蛋了;
二是直接拓展,这样是最好的,但是的在VM10.0以上版本(以下也可以,但是特别麻烦,最好是升级到10.0版本),才能直接拓展。(分两大步:VMware中设置+linux中设置)
简单介绍下,操作过程:
1) 首先先删除快照,这样才能拓展。(大胆删,别怕,不会有事)
2) 然后拓展到预期的容量大小
3) 在linux中设置(最重要一步)
fdisk –l //查看
fdisk /dev/sda 进入设置
这里:说下,我操作的时候纠结的地方,因为在设置的时候,要是使用d删除分区时一直怕里面的文件会丢失,在原来有sda3(就想拓展这个),要拓展这个分区,使用d先删除3,然后再添加3,一直默认大小(不用自己设置大小)操作,这样也就是把剩余空间都给sda3,注意:不要怕删除3后里面的文件啥的都没了,不会的(我试过好几次,都在)
设置完毕后,这时fdisk,磁盘信息已经变了,而df时,磁盘还没变,fdisk是分区工具,df系统文件系统信息,重新加载逻辑卷的大小,这样可以不用重启系统(不过我是重启好多次):resize2fs /dev/sda3
2. 首先先查看adfs的版本信息,看其版本激活没,然后发现Activated:n然后将其激活,但是以为激活密码是虚拟机的,输入好几次都提示错误,只能等第二天问宏哥再说。
然后查看日志文件发现:
[INFO] 2015-08-17 06:32:35,162 - no disk prepared,nospace! - @ DataStore/PathMgr.cpp(84)
[ERROR] 2015-08-17 06:32:35,162 - GetPath error: - @ DataStore/BlockStream.cpp(44)
[ERROR].2015-08-17.06:32:35,162-BlkStream.Open.error:-2.inode:2.-.@ FileSystem/DataOpr.cpp(564)
[ERROR] 2015-08-17 06:32:35,162 - GetFileInfo erro: ino:2 - @FileSystem/DataOpr.cpp(102)
[ERROR] 2015-08-17 06:32:35,162 - OpenData error: ret:-1 - @FuseInterface/AdfsOpr.cpp(83)
[ERROR] 2015-08-17 06:32:35,162 - OpenData error: ret:-5 - @FuseInterface/DDFSOpr.cpp(35)
3. 经过检查,发现挂载点路径下面的文件夹里面有东西,不是空的,就发现当挂载点下非空时就会报错,检测到路径下面有东西,就会返回-1
4. 查看日志文件,发现:
no disk prepared, nospace! - @ DataStore/PathMgr.cpp(84)
就发现在PathMgr::GetPath(int64_tinode)函数中,发现是没有路径可以使用,原因是检测到磁盘空间不足。
然后,想是在添加路径与盘符形成的映射那里查看下路径是否有异常,DiskMgr::SetPath(std::string path)
根据输出的日志文件的信息查看得知添加的路径是正常的,然后通过GetFreeSize(path)获取路径对应的磁盘空间,再查看m_DevStat[m_DevStatIdx]->path,m_DevStat[m_DevStatIdx]->size发现获取到的磁盘空间是对的。
接着继续继续顺着流程往下走,MountStat(int idx)函数中也是正常执行,/proc/mounts文件也是正常打开,然后在memcpy函数前后各个变量的值也是属于正常值,因而排除了在setpath函数用于添加路径与盘符形成映射这一功能中出现问题。
然后在DiskMgr::GetPath(intidx):这函数功能是获取可用路径的序号,如果是传入序号,则表示只需要该路径的序号,并且返回可用磁盘序号。如果是返回时NULL则表示当前没有可用的磁盘,返回时-2 则是表示盘符已经发生了变化,需要重新映射。此时输出结果是:GetPathi:0----name:sda3----level:inf----size:-1----io:89.9072 m_DevStat[x]->path :/home/mx//.adfsData//Data 可见这时获取的到的磁盘路径是对的,但是level是inf(无穷大),size是-1。很明显是这里已经出现了异常。因为虚拟机的磁盘空间是拓展后的(拓展到了60G),不是一开始就是这么大的(开始是20 G,导致安装文件系统是出现磁盘空间不足,然后将其拓展),不知道是不是虚拟机的猫病。
然后基本现在问题就在setpath之后到getpath那块,然后之后又调试了很久时间,因为已经浪费了大量的时间(都花了一周),再加上电脑内存总是跑满,卡的不行,浪费好多时间,就打算先搁置下来,后续再找这个问题(你等着!!)。
27 2015/08/24—2015/08/28周报
任务
重新安装一个虚拟机,然后安装adfs、完成后按照日志开始了解文件系统的执行流程
遇到问题+解决思路
1. 重新安装一个新的虚拟机,然后在adfs/b2文件下make,然后出现很多的错误:
(1) 找不到或者不存在log4cpp.h文件或者文件夹:
分析原因,可能是缺少log4cpp库,然后从网上找一个log4cpp库。
但是,问题来了,不知道怎么安装库,再次查找下
安装的过程:(大多数库文件都是这样,先解压,然后安装)
#./configure
#make
#make check(可选)
#make install
(2) 解决上一个问题后,再次编译,出现新的问题:
fuse/fuse_level.h 没有那个文件或者目录,还有很多没有定义的与fuse有关的东西:
我觉得应该是缺fuse,然后找一个fuse安装上
//http:fuse.sourceforge/net./下载
然后安装:
./configure –prefix=/usr
make
make install
/sbin/ldconfig 更新下动态库
注:安装完后从fuse官网将example一下,确定是否安装成功
(3) 解决上一个问题后,再次make
错误:Lzmalib.h没有那个文件或者目录
我觉得应该是缺Lzma库
下载找一个Lzma-4.32.7(当时下的这个版本),然后安装
#./configure
#make
#make check(可选)
#make install
(4) snappy.h 没有那个文件或者目录
安装snapp库,snappy-1.1.2.tar.gz
(5) google/malloc_extendion.h 诶呦那个文件或者目录:
觉得是缺少google-pertools工具(google-pertools-1.8.2.tar.gz)
注意:装google-pertools工具前首先要装libunwind工具,然后再装,就会成功,否则会报错。
libunwind工具:libunwind-1.0.1.tar.gz
(6) 然后在解决上面的问题之后,再次编译,发现:
undefined reference to ‘log4cpp ……’(截取的片段)
more underfined reference to‘log4cpp’:
这个问题有点不好解决,当时以为log4cpp库我没装,然后就在装了一遍,但是装完之后依然是不好使的,还是报这个问题,然后上/usr/local/lib中、/usr/local/include中、/usr/local/中找相应的库都是存在的。
然后向人请教后,调试发现,是因为由于库与库的冲突导致,第三方加载的库想冲突。
解决方法:将其对应的库调整一致即可。
注意:在安装库的时候,要注意要和系统的相匹配。
2. 一个额外的小点:
在linux虚拟机中,调整行号,tab键等的在~/.vimrc 中调整,不是在/etc/vimrc中。
还有F5、F7、n+c、n+o、等都在~/.vimrc中配置,按照自己的习惯自行的调整。
3.
新建的虚拟机,挂载文件系统,初始化adfs时出现段错误:
Volumngroup “vg zb-lv ”not found 中的vg zb-lv是在DataStore/DiskMgr.cpp LVMToSd ( )函数中,其中vgs–noheading –o –pv_name vg_zb-lv-root
发现在MountStat()函数中,调用LVMToSd()函数的时候发生错误,最后一个memcpy的时候,由于要拷贝的文件内存大小不一样而没有正常复制。最后用vgs命令执行vgs–noheading –o –pv_name vg_zb-lv-root时找不到vg_zb-lv,用vgs命令后,发现只是vg_zb,然后发现在LVMToSd()中memcpy(tmp,lv+8,8)(此时是vg_zb-lv)改成memcpy(tmp,lv+12,5)这样就是vg_zb,在次执行就ok了,问题解决。
4. adfs的创建(格式化):adfsformat
FileSystem::Create()来完成这一行为。
具体过程是:
1) 将adfs的整体信息保存超级块
获取压缩的类型,chunkfile的大小,chunk的大小,数据存储下路径的数目。
2) 初始换元数据库的信息
ü 获取根目录的结构------FuseDispatcher::GetMetaBase(mp)
Ø 判断路径的有效性
Ø 通过文件名来获取文件信息的状态,保存在statbuf中
Ø 判断是不是目录(不是目录则写入错误信息)
Ø 创建路径,并补全各个路径
ü 根据获取的元数据的路径(加上"/meta/"),access函数判断是否具有存储文件的权限。
ü 然后判断该路径下是否为空,不空则return结束,说明该路径下不是空路径,不能创建文件系统。
ü 然后分别创建INode、File、Dir、Sym、Journal的DirPath。
ü 最后创建logPath。
3) 初始化数据处理对象,并设置flush线程---FileSystem::InitRes(boolcreate)
开启消冗库:
首先设置adfs消冗库的参数:
然后设置在消冗库中同步刷新和延迟关闭的参数
最后初始化adfs消冗库,创建延迟关闭功能-----AdfsOpr::Init()
ü 先根据配置文件的参数上层和下层的数据操作-----DataOpr::Init(DataParam &dataParam)
ü 配置成功后,看是否需要延迟关闭,要是开启则
FSCleaner::Open(FSCParam &fSCParam):将fSCParam的参数传递出去
FSCleaner::Start():申请一个缓冲装置,将要延迟关闭的文件放里面,然后重启一个线程,对这些要延迟关闭的文件进行后续的操作。
4) 保存系统的状态
将内存中的超级块信息写到磁盘中-----WriteSuperBlock();
WriteBackUpDedupPath():
5) DestroyRes()
释放资源:当文件系统卸载时,销毁掉相应的对象。