使用符号链接存储数据

Using symlinks to store data

我正在处理的一个应用程序需要使计数器的值在多次调用中保持不变,以便每次再次启动该应用程序时,计数器的值都会被读回并从那里继续计数。该值应该以人类可读的形式存储,以便在需要时可以很容易地检查它,并且应该自动更新它,这样一个故障就不会弄乱以前的持久值。

使用普通的旧文本文件似乎太无聊了,所以经过一些创造性的思考后我想到了我可以通过将计数器存储为符号 link 目标来实现相同的目标。

基本上,使用 sh 作为原型语言,而不是做

echo $counter > file.tmp && mv file.tmp file || rm -f file.tmp

我愿意

ln -s $counter file.tmp && mv file.tmp file || rm -f file.tmp

后一种方法的优点是我只需要一个系统调用来写入文件,而不是至少 3 在前一种情况下。

作为额外的好处,从 shell 执行 ls -l 会自动显示 文件的 内容:

$ ls -l the.counter.is
lrwxrwxrwx 1 fabio fabio 4 mar  7 01:08 the.counter.is -> 1234

至于性能,在我的 PC 上执行比较两种方法 (see it here) 的测试程序,我得到符合预期的结果,使用 symlink 方法大约 7 次比标准方法更快(注意测试不关心原子性):

$ uname -a && ./linkfile 10000 4095 /tmp/test
Linux Fabio-Asus 4.8.0-40-generic #43-Ubuntu SMP Thu Feb 23 16:01:19 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
Starting test... [10000, 4095]
writeToFile: 155.537ms
writeToLink: 23.4132ms

然而,on coliru 我得到了不同的结果,略微支持标准方法:

uname -a && g++ -O3 -o test main.cpp && sync && ./test 10000 4095 x
Linux stacked-crooked 4.4.0-57-generic #78-Ubuntu SMP Fri Dec 9 23:50:32 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
Starting test... [10000, 4095]
writeToFile: 21.8001us
writeToLink: 33.9217us

测试包括每种方法的 10000 次迭代,每次迭代写入 4095 字节并平均执行时间。

4095 字节的原因是,超过这些字节会导致 symlink 系统调用失败并显示 ENAMETOOLONG

所以,问题是:

  1. 有没有人,除了疯狂的我,以前用过这种方法来存储数据?
  2. 如果是,用于什么用例?
  3. 考虑到我的电脑运行 i7-6500U CPU @ 2.50GHz,你知道为什么在 coliru 上 标准方法 比我的电脑快得多吗,与 symlink 方法 和绝对时间有关?如果是因为某些缓存,为什么它们不会对我的 PC 产生影响,为什么它们不会对 symlink 方法产生积极影响?

我的回答:

  1. 是的,我看到符号链接被用于存储数据。正如您已经解释过的那样,将小块数据存储在符号链接而不是文件中可以获得巨大的性能提升。我相信符号链接值直接存储在 inode 上,这使得它的存储效率更高。另一个巨大的优势是原子性——符号链接创建是一个原子过程,有助于处理并发问题。
  2. 存储在符号链接中的值主要是特定于应用程序的元数据。例如,如果我必须构建一个增量解析大量动态日志文件的解析器,我可能希望将读取的最后一个字节位置存储在符号链接中。符号链接也可用于实现锁。我见过 flock 在 NFS 上不可靠,而是使用符号链接的情况。
  3. 我不确定 - 可能存在实施差异?