这帮外国弟兄设计的Pattern比较有意思,写入是以Record为单位的,一条record由Header和data组成,Header里有以下Field:
Field |
Reason |
Checksum |
用于检查bit corruption和shorn writes |
Timestamp |
用于检查unserializable writes |
Block Number |
用于检查 flying writes |
Raw Block Number |
用于检查容量和workload code |
Worker Id |
用于检查unserializable writes和重新生成workload |
Operation Count |
|
Seed |
用于重新生成workload |
Marker |
Header Boundary |
Checksum容易理解,如果有bit错误,可以通过比较checksum发现;
通过Timestamp可以知道每一笔数据被写入的时间,在检查是否存在unserializable writes时会用到;
Marker方便把不同的Header 区分开来;
Block Number:这个是数据应该写入的Block,与数据实际的Block进行比较,可以检查flying writes的问题
Raw Block Number这个field似乎是因为解决测试程序bug而设计的,我没看明白,有兴趣的朋友可以去看原文;
Worker_id, Operation Count和Seed这三个field有两个用途:
- 检查unserializable writes
- 通过哈希算法根据这三个field得到各个操作的顺序
而data部分则用Header填充而成想要的长度。一个Header的长度可能就几个Byte,而Record的长度设定为4K,用Header拼成data部分也有不同的方法:
最简单的方法,是所有Record里的data部分都用一个完全相同的header去填充,这样的话所有的block里写入的内容一致性会非常高(除了Header部分其他都一样),这样的后果是即使发生shorn writes的情况,也没法发现。
另一个方法,是用随机数填充data部分,这样每个record内容都不一样,可以发现shorn writes的问题,但是因为是随机数据,没法知道细节,不知道写了一部分的数据是从哪里来的。
所以比较好的方式是用当前这个record自己的header部分去填充自己data部分,这样哪里错,错从哪里来都比较直观。
上面的方法虽好,但是扛不住有些SSD自带压缩功能,直接把data部分里重复的header给压缩掉再写入NAND,解决方法是在写入的时候把数据跟一个随机掩码进行XOR,读出来的时候再用相同的随机掩码恢复数据。
下篇讨论Unserializability write的问题。