TmStorage: 一种新型的存储系统

在当今快速发展的信息技术领域,数据存储的需求日益增长,这促使寻求更高效、更灵活的存储解决方案。TmStorage就是这样一种创新的存储系统,它不仅能够存储各种类型的信息,而且具有扁平化的结构,使得数据管理更加直观和高效。本文将详细介绍TmStorage的设计原理、实现方式以及其潜在的应用场景。

TmStorage的设计理念

TmStorage最初被设计为一种文件系统,但随着功能的不断扩展,它逐渐演变成了一种通用的存储系统。与传统的文件系统不同,TmStorage采用了扁平化的结构,这意味着所有的数据流都存储在一个文件中,而不是分散在多个文件夹和子文件夹中。这种设计使得TmStorage能够轻松地扩展,以适应不断增长的数据量。

TmStorage的核心功能

TmStorage的核心功能包括:

  • 在单个文件中存储大量的数据流(可达数百万条)。
  • 自动分配和回收空间,以适应数据流长度的变化。
  • 支持完整的事务处理,确保数据的一致性和完整性。
  • 使用GUID引用数据流,而不是名称,以确保唯一性和灵活性。
  • 内部使用64位整数,大大提高了存储容量。

TmStorage的使用示例

TmStorage提供了创建、打开和删除数据流的方法。以下是一个示例,展示了如何在TmStorage中保存一张图片:

Image image = Image.FromFile("c:\\image.png"); Storage storage = new Storage("c:\\images.storage", "c:\\images.storagelog"); Guid streamId = Guid.NewGuid(); storage.StartTransaction(); try { Stream stream = storage.CreateStream(streamId); image.Save(stream, ImageFormat.Png); stream.Close(); storage.CommitTransaction(); } catch { storage.RollbackTransaction(); }

开源项目

TmStorage是一个开源项目,采用MIT许可证,这意味着任何人都可以自由地使用它,无论是商业用途还是非商业用途。项目源代码可以在SourceForge和GitHub上找到:

  • SourceForge:
  • GitHub:

TmStorage的工作原理

TmStorage使用一个主文件来存储所有的数据流。主文件被划分为可变长度的段,每个段只能被一个数据流拥有。每个数据流可以由零个或多个段组成,这些段被链式连接在一起。标记空闲空间的段也被链式连接在一起,形成一个称为空闲空间流的流。

每个段的开始处都写有段元数据,包含以下信息:

  • 段的大小(Int64)
  • 下一个段的位置(如果是最后一个段则为null)(Int64)
  • 元数据校验和(Int)

为了减少碎片化,段的大小总是块大小的倍数,块大小固定为512字节。

空间分配与回收

当创建一个新的空存储时,会创建一个空闲空间流,它由一个段组成,占据了主文件中所有可用的虚拟空间(2^64字节)。主文件的实际大小永远不会像空闲空间流那么大,因为空闲空间流不包含任何数据,它的大小只是虚拟的。

在为数据流分配或回收空间时,只能对段执行两种操作:分割或合并。当数据流扩大时,会从空闲空间流中取出整个段或分割段,并添加到数据流的段链中。

当数据流缩小时,过程相同,只是数据流和空闲空间流的位置互换。当段被添加到段链中时,所有相邻的段会被合并成更大的段,以防止过度分割。

数据流表

所有数据流的元数据都存储在数据流表中。数据流表本身存储在一个数据流中,该数据流具有硬编码的数据流ID和硬编码的第一个段位置,因此在打开存储时,即使数据流表尚未加载,也可以找到它。

数据流元数据包含以下信息:

  • 数据流ID(GUID)
  • 数据流长度(Int64)
  • 初始化的数据流长度(Int64)
  • 链中第一个段的位置(如果为空则为null)(Int64)
  • 标签(Int)

数据流ID的类型是GUID,原因之一是,无论何时何地创建新的数据流ID(例如,使用Guid.CreateNew()),都可以独立于TmStorage创建。因此,即使在实际使用之前很久就创建了数据流ID,也可以确保其唯一性。如果数据流ID是整数,那么就需要一个带有存储的MaxId值的数据流ID生成器。

初始化长度是包含有效数据的数据流长度。这用于优化。当数据流大小扩大时,新分配的空间包含随机(或残留)数据,因为字节不会被初始化为0。如果初始化为0,那么写入数据流的操作就会执行两次,从而降低性能。初始化长度总是小于或等于数据流长度,并且在扩大数据流时不会改变,但当写入数据流时会增长。所有在初始化长度以上(直到数据流长度)读取的字节都会自动设置为0,而不需要实际从数据流中读取。

标签是用于存储一些自定义信息的地方,例如数据流中的数据类型。

事务处理

TmStorage支持完整的事务处理。它们是在主文件级别实现的。在事务期间,每次写入主文件时,TmStorage都会将即将被覆盖的数据复制到事务日志文件中。TmStorage还会记录哪些部分已经被备份,以避免重复备份。事务日志文件是一个单独的文件,位于主文件旁边,当事务提交时会被清除。

如果在抛出异常时,可以回滚事务。如果计算机在事务期间崩溃,下次打开存储时,存储会识别出事务没有完成并进行回滚。

TmStorage目前并不是用于高性能多用户数据库的,而更多地用作各种应用程序的数据存储,其中性能并不是关键因素。

即使在填充了一百万条数据流之后,TmStorage的性能仍然非常好。即使在填充了三百万条数据流之后,它仍然运行良好。数据流表完全加载在内存中,因此访问速度非常快。

缺少的一个特性是缓存层。想法是在内存中缓存主文件的块以加快读取速度。如果存储不太大,所有数据都可以被缓存。

还想要实现快照功能。想法是能够对当前存储进行快照,以便所有对它的更改只写入快照。最后,可以选择将更改与主文件合并,或者丢弃它们。这在测试写入存储的软件时非常有用,因为每次开始测试时,不必每次都对存储主文件进行完整备份。

可能的使用示例

  • 分层文件系统:一个文件夹中的项目表存储在一个数据流中,每个文件夹项指向一个包含子文件夹表的数据流,每个文件项指向一个存储文件数据的数据流。只有包含根项目的数据流ID是硬编码的,而其他数据流ID是生成的。表中的每个项目还会存储文件/文件夹名称、创建日期等。
  • 文档管理数据库:处理扫描文档的应用程序,对于每个扫描文档,首先存储文档元数据,然后将文档的不同信息存储在从元数据引用的各种数据流中。元数据会存储扫描图像的日期等,并引用这些数据流:
  • 数据库还可以包含一个或多个包含索引数据以快速检索的数据流。
  • 数据库可以使用两个TmStorage,一个用于当前数据,一个用于存档数据,位于另一个驱动器或计算机上。
  • 消息队列:每条消息都存储在一个数据流中,元数据指定下一个消息存储的数据流ID(如果是最后一个则为null)。因此,消息会构建一个链表。
  • 文件包:如果需要为应用程序部署创建一个包含文件的包,TmStorage可以像zip文件一样使用。如果应用程序使用大量文件(图像、声音、游戏纹理...),并且不想在安装文件夹中有很多文件,所有文件都可以直接从TmStorage访问,而不需要首先将文件提取到临时文件夹。
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485