标签:读速度
TpsFs(True Power Safe File System)是一款掉电安全的文件系统,该文件系统是SylixOS内建文件系统(专利技术)。TpsFs是基于事务的B+树文件系统:对元数据的修改使用事务提交的机制,保证了文件系统的一致性;使用B+树管理磁盘空间和文件空间,使得存储文件数据与定位速度更快、空间管理效率更高。TpsFs的源码可以在SylixOS Base工程下的"libsylixos/SylixOS/fs/TpsFs/"目录下查看。
每一种文件系统都有自己特定的数据结构和管理数据的方式,不同的文件系统其数据结构也有所不同,但所有文件系统也有一定的共性。下面介绍TpsFs中用来管理数据的一些结构。
当文件系统在磁盘分区上创建后,就可以进行数据的读取和存储了。数据在写入磁盘或从磁盘读取时每次操作的数据量称为数据单元,它的大小在建立文件系统时确定。数据单元在不同的文件系统中有不同的称呼方式,例如FAT中的"簇",EXT中的"块"。一个数据单元由若干个连续物理扇区组成,大小总是2的整数次幂个扇区。存储数据时,系统以数据单元为最小单位为其分配存储空间。在TpsFs中,数据单元以"块"为单位,并且最小不能小于4096字节,块大小可以在格式化TpsFs文件系统时通过tpsFsFormat函数的参数指定,通常情况下将其设置为4096字节。tpsFsFormat函数原型如程序清单2- 1所示。
程序清单2- 1 tpsFs格式化函数
errno_t tpsFsFormat (PTPS_DEV pdev, UINT uiBlkSize)
函数tpsFsFormat原型分析如下:
函数成功返回ERROR_NONE,失败返回错误号;
参数pdev是设备对象;
参数uiBlkSize是块大小。
块号的定义如程序清单2- 2所示。
程序清单2- 2 块号定义
typedef UINT64 TPS_INUM;
超级块用来描述一个文件系统的基本信息,例如文件系统块大小、总块数、文件系统在磁盘分区内的整体布局(数据区、日志区等位置和大小)、已打开文件链表等等。TpsFs将超级块保存在磁盘分区的第0块内,每一个磁盘分区内只有一个超级块结构体。超级块结构体的定义如程序清单2- 3所示。
程序清单2- 3 超级块结构体定义
typedef struct tps_super_block { UINT SB_uiMagic; /* magic数值 */ UINT SB_uiVersion; /* 版本 */ UINT SB_uiSectorSize; /* 块设备的扇区大小 */ UINT SB_uiSectorShift; UINT SB_uiSectorMask; UINT SB_uiSecPerBlk; /* 每块扇区数 */ UINT SB_uiBlkSize; /* 块大小 */ UINT SB_uiBlkShift; UINT SB_uiBlkMask; UINT SB_uiFlags; /* 挂载标识 */ UINT64 SB_ui64Generation; /* 标识一次格式化用于系统修复 */ UINT64 SB_ui64TotalBlkCnt; /* 总块数 */ UINT64 SB_ui64DataStartBlk; /* 数据块起始 */ UINT64 SB_ui64DataBlkCnt; /* 数据块数量 */ UINT64 SB_ui64LogStartBlk; /* 日志块起始 */ UINT64 SB_ui64LogBlkCnt; /* 日志块数量 */ UINT64 SB_ui64BPStartBlk; /* btree块缓冲表起始块 */ UINT64 SB_ui64BPBlkCnt; /* btree块缓冲表块数量 */ TPS_INUM SB_inumSpaceMng; /* 空间管理inode号 */ TPS_INUM SB_inumRoot; /* 文件系统根inode号 */ TPS_INUM SB_inumDeleted; /* 已删除文件列表 */ PTPS_DEV SB_dev; /* 设备对象指针 */ struct tps_inode *SB_pinodeSpaceMng; /* 空间管理inode */ struct tps_inode *SB_pinodeRoot; /* 文件系统根inode */ struct tps_inode *SB_pinodeDeleted; /* 已经删除的文件 */ struct tps_inode *SB_pinodeOpenList; /* 以打开文件链表 */ UINT SB_uiInodeOpenCnt; /* 当前打开文件数 */ PUCHAR SB_pucSectorBuf; /* 磁盘页面缓冲区 */ struct tps_blk_pool *SB_pbp; /* btree块缓冲链表 */ struct tps_trans_sb *SB_ptranssb; /* 事务系统超级块 */ } TPS_SUPER_BLOCK;
inode节点也被称作元数据,用于表示一个文件,这里的文件不只是普通文件,也包括目录等其他类型的文件,与Linux相似,SylixOS也遵循一切皆文件的原则,文件的类型定义符合UNIX标准,文件类型保存在inode结构体中的IND_iMode成员里,其类型有以下几种。
表2- 1 文件类型
IND_iMode | 文件类型 |
S_IFIFO | FIFO文件 |
S_IFCHR | 字符设备 |
S_IFDIR | 目录 |
S_IFBLK | 块设备 |
S_IFREG | 普通文件 |
S_IFLNK | 符号链接 |
S_IFSOCK | Socket文件 |
inode还记录了文件的大小、创建时间、访问权限等内容。
如果一个文件的类型为目录,那么这个文件的数据区保存的数据就是目录项结构,该目录下的每一个子文件都对应一个目录项。目录项记录了这个子文件的名字、名字长度和该子文件对应的inode节点所在位置,查找文件实际上就是从根节点开始遍历目录项的过程。
B+树可以减少磁盘的访问次数,提高文件的查找效率,文件系统一般都会采用B/B+树来对文件数据进行管理。TpsFs内有两种B+树,一种是用于管理空闲块的B+树,它由空间管理inode进行管理,可以看做是一个大文件,其文件的inode是空间管理inode;另一种是用于管理普通文件空间的B+树,它用于管理这个文件内的数据块,即每一个普通文件都会对应一个B+树来进行数据管理。通过该普通文件对应的inode可以查找到B+树的根节点,进而可以实现整个B+树的遍历。
TpsFs采用事务提交机制,即每次进行写操作(写数据+写元数据)时,会把各个步骤看做是一个个小事务,整体算一个大事务,TpsFs会把各个小事务先写进日志块区域,日志全部写进成功之后,再把它写进数据块区域。
由上一节可知,TpsFs的整体布局由超级块结构体描述,在TpsFs中,超级块的一些常量定义如程序清单3- 1所示。
程序清单3- 1 超级块常量
/************************************************************************** super block常量定义 **************************************************************************/ #define TPS_MIN_LOG_SIZE (512 * 1024) /* 最小日志大小 */ #define TPS_SUPER_BLOCK_SECTOR 0 /* 超级快扇区号 */ #define TPS_SUPER_BLOCK_NUM 0 /* 超级块号 */ #define TPS_SPACE_MNG_INUM 1 /* 空间管理inode号 */ #define TPS_ROOT_INUM 2 /* 根inode号 */ #define TPS_BPSTART_BLK 3 /* 块缓冲起始 */ #define TPS_BPSTART_CNT 7 /* 块缓冲块数目 */ #define TPS_DATASTART_BLK 10 /* 数据块起始 */ #define TPS_MIN_BLK_SIZE 4096 /* 最小块大小限制 */
文件系统布局是在磁盘分区格式化时建立的,格式化函数tpsFsFormat建立文件系统布局的流程如程序清单2- 3所示。
程序清单3- 2 tpsFsFormat函数建立文件系统布局
errno_t tpsFsFormat (PTPS_DEV pdev, UINT uiBlkSize) { ... /* * 磁盘最小为 4MB */ uiSctPerBlk = uiBlkSize / uiSectorSize; uiTotalBlkCnt = pdev->DEV_SectorCnt(pdev) / uiSctPerBlk; if (uiTotalBlkCnt < 1024) { return (ENOSPC); } /* * logsize为磁盘的 1/16 */ uiLogBlkCnt = uiTotalBlkCnt >> 4; uiLogSize = uiLogBlkCnt * uiBlkSize; if (uiLogSize < TPS_MIN_LOG_SIZE) { uiLogSize = TPS_MIN_LOG_SIZE; } /* * 结构体赋值 */ psb = (PTPS_SUPER_BLOCK)TPS_ALLOC(sizeof(TPS_SUPER_BLOCK)); if (LW_NULL == psb) { return (ENOMEM); } psb->SB_uiMagic = TPS_MAGIC_SUPER_BLOCK2; psb->SB_uiVersion = TPS_CUR_VERSION; psb->SB_ui64Generation = TPS_UTC_TIME(); psb->SB_uiSectorSize = uiSectorSize; psb->SB_uiSectorShift = (UINT)archFindMsb((UINT32)uiSectorSize) - 1; psb->SB_uiSectorMask = ((1 << psb->SB_uiSectorShift) - 1); psb->SB_uiSecPerBlk = uiSctPerBlk; psb->SB_uiBlkSize = uiBlkSize; psb->SB_uiBlkShift = (UINT)archFindMsb((UINT32)psb->SB_uiBlkSize) - 1; psb->SB_uiBlkMask = ((1 << psb->SB_uiBlkShift) - 1); psb->SB_uiFlags = TPS_MOUNT_FLAG_READ | TPS_MOUNT_FLAG_WRITE; psb->SB_ui64TotalBlkCnt = uiTotalBlkCnt; psb->SB_ui64DataStartBlk = TPS_DATASTART_BLK; psb->SB_ui64DataBlkCnt = uiTotalBlkCnt - TPS_DATASTART_BLK - uiLogBlkCnt; psb->SB_ui64LogStartBlk = uiTotalBlkCnt - uiLogBlkCnt; psb->SB_ui64LogBlkCnt = uiLogBlkCnt; psb->SB_ui64BPStartBlk = TPS_BPSTART_BLK; psb->SB_ui64BPBlkCnt = TPS_BPSTART_CNT; psb->SB_inumSpaceMng = TPS_SPACE_MNG_INUM; psb->SB_inumRoot = TPS_ROOT_INUM; psb->SB_inumDeleted = 0; psb->SB_pinodeOpenList = LW_NULL; psb->SB_dev = pdev; psb->SB_uiInodeOpenCnt = 0; psb->SB_pinodeDeleted = LW_NULL; psb->SB_pbp = LW_NULL; ... }
由程序清单3- 2可以看出,tpsFsFormat函数根据磁盘分区的扇区数量,块大小以及超级块常量来构建文件系统,格式化完成后,文件系统在磁盘分区内的布局如图3- 1所示。
图3- 1 文件系统布局
本文主要介绍了TpsFs的整体框架,TpsFs的读写流程,事务提交,B+树管理机制等将在后续文档介绍。
《SylixOS应用程序开发手册》
SylixOS内核源码
标签:读速度
原文地址:http://11624185.blog.51cto.com/11614185/1966055