Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 表示/分配文件中可用空间的数据结构和算法_Algorithm_Data Structures_Filesystems - Fatal编程技术网

Algorithm 表示/分配文件中可用空间的数据结构和算法

Algorithm 表示/分配文件中可用空间的数据结构和算法,algorithm,data-structures,filesystems,Algorithm,Data Structures,Filesystems,我有一个文件,里面有“洞”,我想用数据填充它们;我还需要能够释放“使用”的空间,并使自由空间 我正在考虑使用一个映射偏移和长度的双映射。但是,如果文件中确实存在很小的间隙,我不确定这是否是最好的方法。位图可以工作,但我不知道如何在空间的某些区域轻松地动态切换到位图。也许某种根树是一种方法 值得一提的是,我在现代文件系统设计(ZFS、HFS+、NTFS、XFS、ext…)方面已经掌握了最新进展,我发现他们的解决方案严重不足 我的目标是有相当好的空间节省(因此对小碎片的关注)。如果我不在乎的话,我会

我有一个文件,里面有“洞”,我想用数据填充它们;我还需要能够释放“使用”的空间,并使自由空间

我正在考虑使用一个映射偏移和长度的双映射。但是,如果文件中确实存在很小的间隙,我不确定这是否是最好的方法。位图可以工作,但我不知道如何在空间的某些区域轻松地动态切换到位图。也许某种根树是一种方法

值得一提的是,我在现代文件系统设计(ZFS、HFS+、NTFS、XFS、ext…)方面已经掌握了最新进展,我发现他们的解决方案严重不足


我的目标是有相当好的空间节省(因此对小碎片的关注)。如果我不在乎的话,我会选择两棵八字树。。。一个按偏移量排序,另一个按长度排序,领带按偏移量断开。请注意,这将为所有操作提供摊销日志(n),工作设置时间为log(m)。。。非常好。。。但是,如前所述,它不能处理与高碎片相关的问题。

最简单的解决方案是:保留可用块的链接列表,重用可用空间来存储列表中下一个块的地址

我已经发布了商业软件,可以做到这一点。在最近的一次迭代中,我们将文件的块分为“type”和“index”,这样您就可以读取或写入“foo类型的第三个块”。文件的结构如下:

1) 文件头。主类型列表中的点。 2) 数据。每个块都有一个带有类型、索引、逻辑大小和填充大小的头。 3) 每个给定类型的(偏移量、大小)元组数组。 4) 跟踪类型的(类型、偏移量、计数)数组

我们定义它,使每个块都是一个原子单位。您开始编写一个新块,并在开始任何其他操作之前完成了该块的编写。您还可以“设置”块的内容。启动一个新块总是附加在文件的末尾,这样您就可以在不分割块的情况下附加任意多的块。“设置”块可以重复使用空块

当您打开文件时,我们将所有索引加载到RAM中。当您刷新或关闭文件时,我们会在文件末尾重新写入每个更改的索引,然后在文件末尾重新写入索引,然后更新前面的头。这意味着对文件的更改都是原子性的——要么提交到更新头的位置,要么不提交。(有些系统使用两个相隔8KB的头文件副本来保存头文件,即使磁盘扇区坏了;我们没有走那么远)

块的“类型”之一是“空闲块”。当重新写入更改的索引时,以及当替换块的内容时,磁盘上的旧空间被合并到空闲块数组中保留的空闲列表中。相邻的自由块合并成一个较大的块。当您“设置内容”或更新类型块索引时,会重新使用空闲块,但索引索引不会使用空闲块,索引索引总是最后写入的

因为索引总是保存在内存中,所以处理打开的文件速度非常快——通常只需一次读取即可获得单个块的数据(或获取块的句柄以进行流处理)。开盘和收盘稍微复杂一些,因为需要加载和刷新指数。如果出现问题,我们可以按需加载二级指数,而不是提前摊销成本,但这对我们来说从来都不是问题

持久(磁盘上)存储的最高优先级:健壮性!在处理文件时,即使计算机断电,也不要丢失数据!
磁盘存储的第二个优先事项:不要执行超过必要的I/O操作!价格昂贵。在闪存驱动器上,每个I/O都很昂贵,而且写操作的成本加倍。尝试对齐和批处理I/O。对于磁盘存储,使用类似malloc()的方法通常不是很好,因为它会执行太多的搜索。这也是我不太喜欢内存映射文件的一个原因——人们倾向于将它们视为RAM,然后I/O模式变得非常昂贵。

对于内存管理,我喜欢BiBOP*方法,这种方法通常在管理碎片方面非常有效

这个想法是根据数据的大小来分离数据。这样,在一个“袋子”中,你只有大小相同的小块“页面”:

  • 无需明确存储大小,它取决于您所在的包
  • 袋内无“真实”碎片
包里有一个简单的可用页面的免费列表。每一页都有一个可用存储单元的免费列表,覆盖在这些单元上

您需要一个索引来将大小映射到相应的包

您还需要对“异常”请求(即请求分配大于页面大小的请求)进行特殊处理


这种存储非常节省空间,特别是对于小对象,因为开销不是每个对象的,但是有一个缺点:最终可能会出现“几乎为空”的页面,其中仍然包含一个或两个已占用的存储单元

如果您能够“移动”现有对象,则可以缓解此问题。它有效地允许合并页面


(*)BiBOP:Big-Bag-Of-Pages

我建议根据需要定制文件系统(当然可能包含一个文件)。你可以基于以下几点:我建议你选择不相关但最简单的项目,以便轻松学习

选择什么样的算法和数据结构,它可以根据您的需要进行高度深化。它可以是:通过动态压缩/解压缩将映射、列表或文件分割成块

你提出的数据结构是好主意。正如您清楚地看到的,有一个折衷:碎片化与压缩

一方面,最好的压实度,最高的破碎度,以及许多其他种类的树木

另一方面,破碎度最低,压实度最差