天空 Blond - #文件系统
type: channel
link: https://skyblond.info/tag/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/
items: 【代码札记】使用Java实现一个只读FUSE文件系统

【代码札记】使用Java实现一个只读FUSE文件系统
type: item
date: 2022-10-21T18:05:58+08:00
description: 本文记述了我为我的开源项目hurui200320/Ariteg实现只读FUSE的过程。一点背景在开始之前，我想先交代一些背景。看起来我在做毕设期间完全没有在我的网站上提我做了个啥，做完之后也完全没说。我的毕设代码放在了Github上，分为前端和后端两个仓库，毕业论文放在了后端仓库的这里，然后还有设计草稿。关于具体的细节请看我的毕业论文，简单地说，这个毕业设计实现了如下功能：将不需要随时访问的文件归档存储归档存储时对文件分块，采用Mekle树/有向无环图的方式存储使用上述存储方式时，顺便获得了块级去重的能力，使得存储重复数据不占空间，且允许无感知地增量备份服务端采用先进的证书系统对数据访问鉴权，对于用户和系统的管理则采用网页端服务端和数据库全部支持集群部署，并且横向扩展的性能惩罚较小当然了，最开始我只想做前两条，因为这个是我的实际需求。我需要找到一种方法，既能够安全可靠的存储我下载的各种动漫、电影，同时还能够获得一定量的空间节省。压缩固然最直观，可是每次压缩和解压所用的时间我实在是难以承受。正好那时候又看到了IPFS，感觉它的存储方式非常精妙，于是就受到了启发，借鉴了一下。但是只是做存储的话，好像内容有些简单，于是在毕设导师的指示下，又加了好多花哨但其实没什么用的功能（但我都很用心的设计并实现了）。做完毕设之后，我当然不想为了存储数据而单独跑一个服务，更何况这个服务还是Java写的，还得要数据库。无论是日常运行还是备份，都未免太麻烦了。但是经过毕业设计验证，我这套自己实现的分块算法和存储结构还是很可取的。经过一些删减（当然了，手法还是比老黄1的差远了），我实现了一个纯命令行工具：Ariteg。至于为什么叫这个名字，大家可以不用特别纠结，作为资深起名难患者，我一直用uniq.site生成随机名字，只要念着顺口，没啥尴尬的意思就可以了。这个命令行工具执行完必要的操作后就退出，完全不会驻留后台，而所有数据全部都存在硬盘上。后来随着日常使用，也不断支持了新的需求，例如一个简单的脚本系统，目前使用JavaScript来允许用户编写脚本并操作数据。不过目前为止，所有的读写都是顺序发生的：存放文件时作为数据流将文件分块、打包成树；读取的时候通过先序遍历，不断将数据块写回文件。抛开硬盘空间，这种做法理论上能够容纳无限大的单个数据块（也就是文件）。但是目前的实现方式来看，所有的分块丢在一个文件夹里，这个限制可能会影响整个系统的能力上限。例如NTFS和EXT4最大允许一个文件夹有不到43亿个文件。假设一个文件存储512KB的数据（分块算法允许产生的最小值，不算结尾的残片），那么你只能存储不到2PB的数据。同样的限制到了旧的FAT32上，就变成了但文件夹最大6万多文件，那这个系统只能存储不到32GB的数据。不过这些问题可以通过将文件系统更新为更先进的XFS、BtrFS等来解决，姑且不是问题。（假设这种顺序存放不会带来性能惩罚，如果同一目录下的文件变多会导致访问文件变慢，那么届时我会考虑引入二级或三级文件夹）。最近我在想，有没有一种可能，让我直接把这里面的数据直接挂载为一个硬盘或者网络位置之类的东西，我可以像Google硬盘那样读取存在这个系统里面的数据。这样使用之前就不必还原数据了。可行性分析有了明确需求之后，自然是想这个想法能不能实现。如果不能实现的话，那肯定就歇菜了。由于我这个存储结构整个学的IPFS，而人家IPFS已经能够实现将给定的ipfs链接挂载成Linux下面的文件系统了，就说明这个存储结构做只读的肯定是没问题。但是我这个程序和IPFS有个本质的不同：人家用Go写的，我这个是Java。要知道，文件系统是相当底层的东西，无论是Windows还是Linux，大概率都不会接受在内核线程中运行一个JVM。通过一些搜索，我了解到IPFS是使用FUSE来实现这个功能的。简单地说，FUSE就是一套接口，定义了内核与用户空间应用程序的交互规范。当内核收到一个文件操作请求，发现它是FUSE的话，就直接通过这个接口把文件操作的请求转发给用户空间的程序，程序处理完了再把数据返回给内核，内核返回给操作者。这样就实现了无需修改内核，便可以开发自己的文件系统了。但，我用的是Windows啊。我又看了看之前用的MountainDuck，这个软件能够将网络位置挂载到Windows的盘符上。我不在乎它是本地硬盘还是网络位置，只要能在资源管理器中浏览就好了。由于这个是闭源软件，我只能在它的关于页面找到一些蛛丝马迹。我发现这个软件应该是用Java做与存储后端的交互，我看到诸如S3等后端的Java SDK，同时还有.NET库，然后还有JNA（Java用于访问原生库的库）。但是具体来说，我不清楚这个挂载发生在Java还是发生在.NET侧，但我推断应该是Java以某种方式调用了由.…