[LINUX]VFS高速缓存的实现方式

VFS buffercache的实现原理:

  • ①磁盘的存储方式:(这里的磁盘理解为驱动程序的模拟),磁盘类似块存储的方式,一个文件可能分为非常多的块来存储,每个块并不大,可能就4k个字节等,即一个文件最终被存储在多个块上,而上层通过索引节点inode来记录对于块的索引(一个inode对应于一个或者多个同样内容的文件路径),而一个inode对下对应了多个块的信息。inode之上就某个文件系统超级块(包含了该文件系统的详细信息,即inode是相对于文件系统的概念,每个文件系统有一套自己的inode)。
  • ②高速缓存:区别于之前的就是,高速缓存并不对应于某一个文件系统,而是总的概念。时内核中的一段内存,用hash表数组+双向链表的方式存储块的内容,其实和我们之前用的模式基本一样,这里用双向链表增加一个指针的空间,是为了方便增删改。每个块都有唯一的设备号和块号(这里的设备号可以理解为某个文件系统,块号是这个文件系统下对应的块的编号,所以buffer cache是多文件系统公用的,里面可能存储了磁盘文件系统的块信息,也有可能存储了socket文件系统的块信息。
  • ③基本的算法思路:由于内存和磁盘相比,空间毕竟是有限的,所以涉及到内存块的删除,这个也是缓存的基本操作,基本的算法思路其实和我们的也比较的类似,就是最最常用的块尽量保留(命中率高的),即“最近最少使用”的算法:方法是维护一个空闲的循环链表,头尾相接,当然会有一个fake的作为尾节点,里面存储了所有预分配好的空闲的可以存储的块(块大小是固定的,所以可以预分配),一开始所有的表都是在空闲队列中,当有读写请求时,从空闲队列取一块出来,再进行磁盘驱动的读请求。并且根据设备号、块号,将这个“装载”了数据的块,放到hash表中的位置。后续如果有相同的读请求,则不用进行磁盘IO直接从缓存中根据hash表找到相应的块,进行读取。
  • ④释放规则:最近最少使用其实关键在于释放规则,每次从空闲队列头部取空闲块,而每次块释放,并不是真正的释放,只是将其放到空闲队列的尾部,这样有一个好处,只要使用一次,那么这个块就会从空闲队列中移出来,使用完毕后又放到了空闲队列的尾部,这样,越高命中的块,往往永远会存在于hash表中,不会被真的释放。那么什么时候真的释放呢?在空闲队列头部取出一个块,该块如果没有延迟写标记,那么他上面的内容就会被真的释放,块上面的数据会被清零,也会从hash表中移除对应的块和设备号节点。(这也是为什么空闲队列和hash表都要用双向链表实现的原因,因为会进行频繁的插入、删除等操作),新的块号和设备号会被赋予这个块,同时会放入到用于查询的hash表中。这套机制简单理解就是做了保留命中率高的缓存机制(和我们用访问时间来保留缓存类似,只是用访问时间可能还需要排序,这种实现性能更加好一些,算法思路上也更加精致)。
  • ⑤这种机制还顺便带来了很多的好处,比如控制,在单核cpu上面,如果一个进程获得了某个块,在其释放之前,这个块是无法被其他进程所获取的,其他进程只能够阻塞等待通知。一定程度上保证了同一时间对于某个块只有一个进程访问,但同时,文件又是由茫茫多的块组成,所以一定程度上又保证了多个进程同时读同一个文件的性能(因为只是同一个块需要等待,不同的块,无需等待)。
  • ⑥在此基础上,buffer cache还有一些特性,比如异步预读文件块,当读取某一个块后预期可能还要读下一个块,那么会采用异步读取+释放的方式实现,当读取另一个块的时候,由于已经读取过了,直接从缓存中就能够获取到。

你可能感兴趣的:(平台(PLATFORM))