SubZero

论文链接:SubZero: Zero-copy IO for Persistent Main Memory File Systems

Motivation

​ POSIX标准的 read() 和 write() 长期以来一直是访问文件中数据的标准接口。但是,当文件存储在 PMEM 中时,这些方法会带来冗余的数据拷贝开销。为了避免这种数据复制,PMEM 感知型文件系统(如NOVA、PMFS等)使用 DAX 技术通过总线直接访问 PM,但这样做需要程序员管理对文件的写入原子性和并发访问。

​ 所以 SubZero 希望结合 POSIX IO 和 DAX IO 两者的优势,提供类似 DAX 的速度和一个简单的、类似 POSIX 的接口。

Design

​ SubZero IO实现了以下的系统调用:

SubZero系统调用

peek()

​ peek () 系统调用将 PM 文件映射到内存中,并返回一个指向内存区域的指针,该内存区域包含特定文件偏移处的文件内容。映射的内存区域就是执行 peek () 时文件内容的快照,该快照对于文件修改(例如 write () 或 patch () )是原子的。映射使用 O_RDONLY 标志位,使得快照是只读的、不可变的,因此尝试更改其内容会导致Segmentation Fault。

​ peek() 与 mmap() 相比,peek() 的文件偏移或返回的指针没有对齐限制,而 mmap() 需要页对齐。


​ **peek() example1:basic **

1
2
3
4
5
// peek the first 4KB of a PMEM file
int fd = open("foo", O_RDONLY); // Open the target file
char *buf = peek(fd, 0, 4096); // Peek its contents
printf(“%s\n”, buf); // Print the contents
unpeek(buf); // Unpeek the contents

peek() example2:immutability

1
2
3
4
5
6
// peek the first 4KB of a PMEM file
int fd = open("foo", O_RDONLY); // Open the target file
char *buf = peek(fd, 0, 4096); // Peek its contents
printf(“%s\n”, buf); // Print the contents
*buf = ‘a’; // Segmentation fault!
unpeek(buf); // Unpeek the contents

​ **peek() example3:isolation **

1
2
3
4
5
6
7
8
9
// Thread 1: peek the first 4KB of a PMEM file
int fd = open("foo", O_RDONLY);
char *buf = peek(fd, 0, 4096);
...
...
printf(“%s\n”, buf); // print original contents!
...
unpeek(buf);
close(fd);
1
2
3
4
5
6
7
8
9
// Thread 2: update the peek()’ed region
// of the same file
int fd = open("foo", O_WRONLY);
char *buf = malloc(4096);
memset(buf, 0xab, 4096);
write(fd, buf, 4096); // copy-on-write to
... // a new 4KB
free(buf)
close(fd);

patch()

​ patch() 系统调用通过将缓冲区的内容合并到给定偏移量的文件中来修改文件。本质上,缓冲区成为文件的一部分,而不是被复制到文件中。在 patch() 之后,缓冲区变得不可变。

patch操作

​ 这个 buffer 需要 access-aligned 。直观地说,就是缓冲区的页边界必须与文件中的页边界对齐。比如:对于在页大小为 S 的文件系统上使用缓冲区 B 和文件偏移 off 关闭的 patch() 操作,如果 B % S == off % S,则 patch() 是访问对齐的。

Conclusion

​ 为了展示它的潜力,在 PMEM 文件系统 XFS-DAX 和 NOVA 中实现了 SubZero。通过简单的基准测试表明,SubZero 可以比基于复制的 read() 和 write() 性能高出 2 倍和 2.8 倍。在应用层面,peek() 将 Apache Web Server 的 GET 性能提升了 3.6 倍,patch() 将 Kyoto Cabinet 的 SET 性能提升 1.3 倍。