内存映射文件中的数据是否保证按顺序刷新?

5
我正在尝试实现一种文件存储机制,它可以在单个文件中容纳多个大小可变的记录,并保证即使系统在硬件层面发生故障,记录集也始终可以恢复到一致的状态。
目前,我想到的每种方案都依赖于顺序写入数据。每个数据块末尾都会附加确认数据以确认写入成功。但如果在刷新时数据不是按顺序写入磁盘,则可能先写入确认数据再写入内容数据。
有两种明显的解决方法,但都不理想:
1. 刷新内容,然后写入确认并刷新。增加额外的刷新可能会降低性能。 2. 在确认中包含校验和(需要读取内容来验证其有效性)。
我使用的是C#在Windows上(32位和64位)和.Net 4.0的内存映射文件实现。

第二个想法(验证数据、时间戳、序列号和校验和)似乎是合理的。然而,一般来说,您应该考虑使用高可用性集群,在网络上使用独立的机器。所有记录或日志写入都需要在网络上复制到两台或更多机器。您无法从单个机器中获得任何保证。 - rwong
2个回答

1

这个问题对于C#来说太底层且与操作系统相关了。建议使用C语言的Windows API,并仔细阅读API规范。


0

你尝试过在底层文件流上使用FileOptions.WriteThrough吗?这可能有所帮助,因为它禁用了缓冲。其他想法是保留一个单独的文件,其中包含确认作为最后写入的偏移量,如果它与您的文件大小不匹配(例如由于停电),则可以将其截断到该大小。


1
这些在故障恢复方面是好主意。但很遗憾,它们不适用于内存映射文件。MM文件总是禁用写穿功能,因为它们使用操作系统的底层页面管理器来处理缓冲。保持确认日志也是一个好主意,但它也有其他问题。然后,每个文件操作都需要两次flush(一次针对MM文件,一次针对日志)。更加棘手的是,在MM文件中,您不知道何时完成flush。最多,您可以指示操作系统开始刷新,但是在完成时不会得到确认。这使得确定性日志成为不可能。 - Kennet Belenky
@Kennet Belenky: 关于清空缓存的事情很奇怪,与Java相比(http://docs.oracle.com/javase/1.4.2/docs/api/java/nio/MappedByteBuffer.html)。也许您可以使用普通的FileOutputStream来记录日志(日志很短,因此速度差异不大)?如果未经确认的记录丢失并不太糟糕,因此您可以更少地刷新日志。 - maaartinus
@maaartinus,Java的API肯定更容易理解,但它也不是完美的。它提供了在返回时刷新完成的保证,这很好。然而,如果它能够提供异步通知,让您可以继续处理其他事情,那就更好了。旋转磁盘刷新的10毫秒寻道时间是一个长时间的空闲期。 - Kennet Belenky
@Kennet Belenky:我想不起来Java中有什么适合这种异步通知的东西。使用CallableExecutorService是冗长的(就像Java中的许多其他东西一样),但对于任何你不想让自己闲置的东西来说都是微不足道的。 - maaartinus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接