提交 fd9c1964 编写于 作者: chyyuu1972's avatar chyyuu1972

update ch7/sec2: rust closure intro

上级 40d6fbc2
......@@ -50,7 +50,7 @@
- ``read_block`` 可以将编号为 ``block_id`` 的块从磁盘读入内存中的缓冲区 ``buf`` ;
- ``write_block`` 可以内存中的缓冲区 ``buf`` 中的数据写入磁盘编号为 ``block_id`` 的块。
这是因为块设备仅支持以块为单位进行随机读写,由此才有了这两个抽象方法。在 ``easy-fs`` 中并没有一个实现了 ``BlockDevice`` Trait 的具体类型,实际上这是需要由库的使用者提供并接入到 ``easy-fs`` 库的。这也体现了 ``easy-fs`` 的泛用性:它可以用于管理任何实现了 ``BlockDevice`` Trait 的块设备。
这是因为块设备仅支持以块为单位进行随机读写,由此才有了这两个抽象方法。但这是由具体的块设备驱动要实现的方法,在 ``easy-fs`` 中并没有一个实现了 ``BlockDevice`` Trait 的具体类型。实际上这是需要由库的使用者(比如操作系统内核或直接测试 ``easy-fs`` 文件系统的 ``easy-fs-fuse`` 应用程序)提供并接入到 ``easy-fs`` 库的。 ``easy-fs`` 库的块缓存层会调用这两个方法,进行块缓存的管理。这也体现了 ``easy-fs`` 的泛用性:它可以用于管理任何实现了 ``BlockDevice`` Trait 的块设备。
.. note::
......@@ -63,13 +63,13 @@
本层的代码在 ``block_cache.rs`` 中。
由于 CPU 不能直接读写磁盘块,因此常见的手段是先通过 ``read_block`` 将一个块上的数据从磁盘读到内存中的一个缓冲区中,这个缓冲区中的内容是可以直接读写的。如果对于缓冲区中的内容进行了修改,那么后续需要通过 ``write_block`` 将缓冲区中的内容写回到磁盘块中。
由于操作系统频繁读写磁盘块会极大降低系统性能,因此常见的手段是先通过 ``read_block`` 将一个块上的数据从磁盘读到内存中的一个缓冲区中,这个缓冲区中的内容是可以直接读写的,那么后续对这个数据块的大部分访问就可以在内存中完成了。如果对于缓冲区中的内容进行了修改,那么后续还需要通过 ``write_block`` 将缓冲区中的内容写回到磁盘块中。
事实上,无论站在代码实现鲁棒性还是性能的角度,将这些缓冲区合理的管理起来都是很有必要的。一种完全不进行任何管理的模式可能是:每当要对一个磁盘块进行读写的时候,都通过 ``read_block`` 将块数据读取到一个 *临时* 创建的缓冲区,并在进行一些操作之后(可选地)将缓冲区的内容写回到磁盘块。从性能上考虑,我们需要尽可能降低真正块读写(即 ``read/write_block`` )的次数,因为每一次调用它们都会产生大量开销。要做到这一点,关键就在于对于块读写操作进行 **合并** 。例如,如果一个块已经被读到缓冲区中了,那么我们就没有必要再读一遍,直接用已有的缓冲区就行了;同时,对于同一个块的缓冲区的多次修改没有必要每次都写回磁盘,只需等所有的修改都结束之后统一写回磁盘即可。
事实上,无论站在代码实现鲁棒性还是性能的角度,将这些缓冲区合理的管理起来都是很有必要的。一种完全不进行任何管理的模式可能是:每当要对一个磁盘块进行读写的时候,都通过 ``read_block`` 将块数据读取到一个 *临时* 创建的缓冲区,并在进行一些操作之后(可选地)将缓冲区的内容写回到磁盘块。从性能上考虑,我们需要尽可能降低实际块读写(即 ``read/write_block`` )的次数,因为每一次调用它们都会产生大量开销。要做到这一点,关键就在于对于块读写操作进行 **合并** 。例如,如果一个块已经被读到缓冲区中了,那么我们就没有必要再读一遍,直接用已有的缓冲区就行了;同时,对于同一个块的缓冲区的多次修改没有必要每次都写回磁盘,只需等所有的修改都结束之后统一写回磁盘即可。
但是,当磁盘上的数据结构比较复杂的时候,在编程的时候我们很难手动正确的规划块读取/写入的时机。这不仅可能涉及到复杂的参数传递,稍有不慎还有可能引入同步性问题:即对于一个块缓冲区的修改在对于同一个块进行后续操作的时候不可见。它很致命但又难以调试。
但是,当磁盘上的数据结构比较复杂的时候,在编程的时候我们很难手动正确的规划块读取/写入的时机。这不仅可能涉及到复杂的参数传递,稍有不慎还有可能引入同步性问题(目前可以暂时忽略):即对于一个块缓冲区的修改在对于同一个块进行后续操作的时候不可见。它很致命但又难以调试。
因此,我们的做法是将缓冲区统一管理起来。当我们要读写一个块的时候,首先就是去全局管理器中查看这个块是否已被缓存到内存中的缓冲区中。这样,在一段连续时间内对于一个块进行的所有操作均是在同一个固定的缓冲区中进行的,这解决了同步性问题。此外,通过 ``read/write_block`` 真正进行块读写的时机完全交给全局管理器处理,我们在编程时无需操心。全局管理器仅会在必要的时机分别发起一次真正的块读写,尽可能将更多的块操作合并起来
因此,我们的做法是将缓冲区统一管理起来。当我们要读写一个块的时候,首先就是去全局管理器中查看这个块是否已被缓存到内存中的缓冲区中。这样,在一段连续时间内对于一个块进行的所有操作均是在同一个固定的缓冲区中进行的,这解决了同步性问题。此外,通过 ``read/write_block`` 进行块实际读写的时机完全交给全局管理器处理,我们在编程时无需操心。全局管理器会尽可能将更多的块操作合并起来,并在必要的时机发起真正的块的实际读写
块缓存
+++++++++++++++++++++++++++++++++++++++++
......@@ -149,7 +149,7 @@
}
}
- ``addr_of_offset`` 可以得到一个 ``BlockCache`` 内部的缓冲区一个指定偏移量 ``offset`` 的字节地址;
- ``addr_of_offset`` 可以得到一个 ``BlockCache`` 内部的缓冲区指定偏移量 ``offset`` 的字节地址;
- ``get_ref`` 是一个泛型方法,它可以获取缓冲区中的位于偏移量 ``offset`` 的一个类型为 ``T`` 的磁盘上数据结构的不可变引用。该泛型方法的 Trait Bound 限制类型 ``T`` 必须是一个编译时已知大小的类型,我们通过 ``core::mem::size_of::<T>()`` 在编译时获取类型 ``T`` 的大小并确认该数据结构被整个包含在磁盘块及其缓冲区之内。这里编译器会自动进行生命周期标注,约束返回的引用的生命周期不超过 ``BlockCache`` 自身,在使用的时候我们会保证这一点。
- ``get_mut`` 与 ``get_ref`` 的不同之处在于它会获取磁盘上数据结构的可变引用,由此可以对数据结构进行修改。由于这些数据结构目前位于内存中的缓冲区中,我们需要将 ``BlockCache`` 的 ``modified`` 标记为 true 表示该缓冲区已经被修改,之后需要将数据写回磁盘块才能真正将修改同步到磁盘。
......@@ -192,7 +192,7 @@
}
}
它们的含义是:在 ``BlockCache`` 缓冲区偏移量为 ``offset`` 的位置获取一个类型为 ``T`` 的磁盘上数据结构的不可变/可变引用(分别对应 ``read/modify`` ),并让它进行传入的闭包 ``f`` 中所定义的操作。注意 ``read/modify`` 的返回值是和传入闭包的返回值相同的,因此相当于 ``read/modify`` 构成了传入闭包 ``f`` 的一层执行环境,让它能够真正绑定到一个缓冲区开始执行。
它们的含义是:在 ``BlockCache`` 缓冲区偏移量为 ``offset`` 的位置获取一个类型为 ``T`` 的磁盘上数据结构的不可变/可变引用(分别对应 ``read/modify`` ),并让它进行传入的闭包 ``f`` 中所定义的操作。注意 ``read/modify`` 的返回值是和传入闭包的返回值相同的,因此相当于 ``read/modify`` 构成了传入闭包 ``f`` 的一层执行环境,让它能够绑定到一个缓冲区上执行。
这里我们传入闭包的类型为 ``FnOnce`` ,这是因为闭包里面的变量被捕获的方式涵盖了不可变引用/可变引用/和 move 三种可能性,故而我们需要选取范围最广的 ``FnOnce`` 。参数中的 ``impl`` 关键字体现了一种类似泛型的静态分发功能。
......@@ -463,7 +463,8 @@ easy-fs 超级块
**Rust 语法卡片:闭包**
FIXME
闭包是持有外部环境变量的函数。所谓外部环境, 就是指创建闭包时所在的词法作用域。Rust中定义的闭包,按照对外部环境变量的使用方式(借用、复制、转移所有权),分为三个类型: Fn、FnMut、FnOnce。Fn类型的闭包会在闭包内部以共享借用的方式使用环境变量;FnMut类型的闭包会在闭包内部以独占借用的方式使用环境变量;而FnOnce类型的闭包会在闭包内部以所有者的身份使用环境变量。由此可见,根据闭包内使用环境变量的方式,即可判断创建出来的闭包的类型。
接下来看 ``Bitmap`` 如何回收一个比特:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册