SplitFS发表在SOSP‘19上。
拦截POSIX调用
作者通过设置环境变量LD_PRELOAD
,拦截POSIX调用:
1 | export LD_PRELOAD=xxx |
日志操作
SplitFS着重优化了追加操作。追加操作的日志项append_log_entry定义在头文件splitfs/log.h中。
1 | struct append_log_entry { |
$$
追加操作的日志项大小 = 4 \times 3 + 8 \times 2 + 8 + 28 = 64B
$$
校验和(checksum)
P499: First, to distinguish between valid and invalid or torn log entries, we incorporate a 4B transactional checksum within the 64B log entry.
校验和(占用4个字节)使用了循环冗余校验(Cyclic Redundancy Check, CRC)。
在CRC中,有几个重要的概念:
第一,模2运算。加法不进位,减法不借位,等价于异或运算(eXclusive OR,XOR)。
第二,生成多项式(Generator Polynomial)。
第三,余数初始值(Initial Remainder)。
第四,结果异或值(XOR)
$$
CRC =(D \ll 2^r) \oplus G
$$
其中,G的长度为r + 1。
校验和的实现代码如下所示:
1 | // 计算r的校验码 |
其中,0xEDB88320
是CRC-32的生成多项式:
$$
\mathrm{poly} = 0xEDB88320 = 0b1110\ 1101\ 1011\ 1000\ 1000\ 0011\ 0010\ 0000 \\
$$
1 | // 计算r的校验码 |
将三目运算符改写为条件判断语句:
1 | uint32_t crc32_for_byte(uint32_t r) { |
CAS操作
P499: Second, we maintain a tail for the log in DRAM and concurrent threads use the tail as a synchronization variable. They use compare-and-swap to atomically advance the tail and write to their respective log entries concurrently.
比较并交换(Compare And Swap,简称CAS)操作:
1 | type __sync_fetch_and_add(type *ptr, type value, ...); |
1 | void persist_append_entry(uint32_t file_ino, |
其中,日志文件的最大容量app_log_lim
:
1 | // log.h |
P499: We employ a 128MB operation log file and if it becomes full, we checkpoint the state of the application by calling relink() on all the open files that have data in staging files. We then zero out the log and reuse it.
对应代码中的条件判断:
1 | fetch_and_add: |
fsync()
1 |
|
内存屏障
内存屏障(Memory Barrier),内存栅栏(Memory Fence)sfence
1 |
|
Relink()
ext4中的函数ext4_ioctl()中的EXT4_IOC_MOVE_EXT命令。
https://github.com/torvalds/linux/blob/v4.13/fs/ext4/ioctl.c#L717
1 | case EXT4_IOC_MOVE_EXT: { |
参考资料
1.论文:https://www.cs.utexas.edu/~vijay/papers/sosp19-splitfs.pdf
2.代码:https://github.com/utsaslab/SplitFS
3.libcrc:https://github.com/lammertb/libcrc