-
-
Notifications
You must be signed in to change notification settings - Fork 168
feat: readahead #1391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: readahead #1391
Changes from all commits
62bfb06
2ea3104
bd64e3f
2290c8b
1a26831
45a0656
df996e0
0e30c8d
7ee086a
d65805c
0463f1a
db1f01b
527a7db
26ab3f6
8036fd5
cc3ce28
ea45355
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,16 +62,13 @@ impl InnerPageCache { | |
| self.pages.remove(&offset) | ||
| } | ||
|
|
||
| fn create_pages(&mut self, start_page_index: usize, buf: &[u8]) -> Result<(), SystemError> { | ||
| assert!(buf.len().is_multiple_of(MMArch::PAGE_SIZE)); | ||
|
|
||
| let page_num = buf.len() / MMArch::PAGE_SIZE; | ||
|
|
||
| let len = buf.len(); | ||
| if len == 0 { | ||
| pub fn create_pages(&mut self, start_page_index: usize, buf: &[u8]) -> Result<(), SystemError> { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 为什么不再需要
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 文件大小不一定是页面大小的整数倍, |
||
| if buf.is_empty() { | ||
| return Ok(()); | ||
| } | ||
|
Comment on lines
+65
to
68
|
||
|
|
||
| let page_num = ((buf.len() - 1) >> MMArch::PAGE_SHIFT) + 1; | ||
|
|
||
| let mut page_manager_guard = page_manager_lock_irqsave(); | ||
|
|
||
| for i in 0..page_num { | ||
|
|
@@ -90,12 +87,15 @@ impl InnerPageCache { | |
| &mut LockedFrameAllocator, | ||
| )?; | ||
|
|
||
| let page_len = core::cmp::min(MMArch::PAGE_SIZE, buf.len() - buf_offset); | ||
|
|
||
| let mut page_guard = page.write_irqsave(); | ||
| unsafe { | ||
| page_guard.copy_from_slice(&buf[buf_offset..buf_offset + MMArch::PAGE_SIZE]); | ||
| let dst = page_guard.as_slice_mut(); | ||
| dst[..page_len].copy_from_slice(&buf[buf_offset..buf_offset + page_len]); | ||
| } | ||
|
|
||
| self.add_page(page_index, &page); | ||
| self.add_page(start_page_index + i, &page); | ||
| } | ||
|
|
||
| Ok(()) | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,7 @@ use system_error::SystemError; | |||||
| use super::{FileType, IndexNode, InodeId, Metadata, SpecialNodeData}; | ||||||
| use crate::process::pid::PidPrivateData; | ||||||
| use crate::{ | ||||||
| arch::MMArch, | ||||||
| driver::{ | ||||||
| base::{block::SeekFrom, device::DevicePrivateData}, | ||||||
| tty::tty_device::TtyFilePrivateData, | ||||||
|
|
@@ -18,6 +19,11 @@ use crate::{ | |||||
| }, | ||||||
| ipc::{kill::kill_process, pipe::PipeFsPrivateData}, | ||||||
| libs::{rwlock::RwLock, spinlock::SpinLock}, | ||||||
| mm::{ | ||||||
| page::PageFlags, | ||||||
| readahead::{page_cache_async_readahead, page_cache_sync_readahead, FileReadaheadState}, | ||||||
| MemoryManagementArch, | ||||||
| }, | ||||||
| process::{cred::Cred, resource::RLimitID, ProcessControlBlock, ProcessManager, RawPid}, | ||||||
| }; | ||||||
|
|
||||||
|
|
@@ -151,6 +157,8 @@ pub struct File { | |||||
| close_on_exec: AtomicBool, | ||||||
| /// owner | ||||||
| pid: SpinLock<Option<Arc<ProcessControlBlock>>>, | ||||||
| /// 预读状态 | ||||||
| ra_state: SpinLock<FileReadaheadState>, | ||||||
| } | ||||||
|
|
||||||
| impl File { | ||||||
|
|
@@ -182,6 +190,7 @@ impl File { | |||||
| cred: ProcessManager::current_pcb().cred(), | ||||||
| close_on_exec: AtomicBool::new(close_on_exec), | ||||||
| pid: SpinLock::new(None), | ||||||
| ra_state: SpinLock::new(FileReadaheadState::new()), | ||||||
| }; | ||||||
|
|
||||||
| return Ok(f); | ||||||
|
|
@@ -251,6 +260,58 @@ impl File { | |||||
| self.do_write(offset, len, buf, false) | ||||||
| } | ||||||
|
|
||||||
| fn file_readahead(&self, offset: usize, len: usize) -> Result<(), SystemError> { | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 如果该inode的page cache已经存在(比如当前文件已经预读过,或者当前inode对应的其他file已经预读过),那还会预读,创建新的Page cache吗?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. page_cache是inode的,预读前先检查页面是否已经存在。逻辑上都是从第一个缺页的地方开始实际的读 |
||||||
| let page_cache = match self.inode.page_cache() { | ||||||
| Some(page_cahce) => page_cahce, | ||||||
|
||||||
| Some(page_cahce) => page_cahce, | |
| Some(page_cache) => page_cache, |
xboHodx marked this conversation as resolved.
Show resolved
Hide resolved
xboHodx marked this conversation as resolved.
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,3 +31,4 @@ pub mod name; | |
| pub mod decompress; | ||
|
|
||
| pub mod pod; | ||
| pub mod ranges; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| use crate::alloc::vec::Vec; | ||
|
|
||
| /// 合并连续的整数为范围 | ||
| /// | ||
| /// ## 参数 | ||
| /// - `set`: 整数集合,必须已排序 | ||
| /// | ||
| /// ## 返回值 | ||
| /// - `Vec<(start, count)>`: 范围列表 | ||
| /// | ||
| /// ## 示例 | ||
| /// ``` | ||
| /// merge_ranges(&[1, 2, 3, 5, 6, 8]) | ||
| /// // 返回 [(1, 3), (5, 2), (8, 1)] | ||
| /// ``` | ||
| pub fn merge_ranges(set: &[usize]) -> Vec<(usize, usize)> { | ||
| if set.is_empty() { | ||
| return Vec::new(); | ||
| } | ||
|
|
||
| let mut ranges = Vec::new(); | ||
| let mut start = set[0]; | ||
| let mut count = 1; | ||
|
|
||
| for &page_index in &set[1..] { | ||
| if page_index == start + count { | ||
| count += 1; // 连续,扩展范围 | ||
| } else { | ||
| ranges.push((start, count)); // 保存当前范围 | ||
| start = page_index; | ||
| count = 1; | ||
| } | ||
| } | ||
|
|
||
| ranges.push((start, count)); // 最后一个范围 | ||
| ranges | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_empty_input() { | ||
| // 边界情况:空输入 | ||
| let result = merge_ranges(&[]); | ||
| assert_eq!(result, vec![]); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_single_page() { | ||
| // 边界情况:单个页面 | ||
| let result = merge_ranges(&[5]); | ||
| assert_eq!(result, vec![(5, 1)]); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_fully_consecutive() { | ||
| // 完全连续的页面 | ||
| let result = merge_ranges(&[1, 2, 3, 4, 5]); | ||
| assert_eq!(result, vec![(1, 5)]); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_no_consecutive() { | ||
| // 完全不连续的页面 | ||
| let result = merge_ranges(&[1, 3, 5, 7, 9]); | ||
| assert_eq!(result, vec![(1, 1), (3, 1), (5, 1), (7, 1), (9, 1)]); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_mixed_ranges() { | ||
| // 文档示例:混合连续和不连续 | ||
| let result = merge_ranges(&[1, 2, 3, 5, 6, 8]); | ||
| assert_eq!(result, vec![(1, 3), (5, 2), (8, 1)]); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_two_consecutive_pairs() { | ||
| // 两对连续的范围 | ||
| let result = merge_ranges(&[0, 1, 10, 11]); | ||
| assert_eq!(result, vec![(0, 2), (10, 2)]); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_start_from_zero() { | ||
| // 从 0 开始的连续范围 | ||
| let result = merge_ranges(&[0, 1, 2]); | ||
| assert_eq!(result, vec![(0, 3)]); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_large_gap() { | ||
| // 大间隔的不连续页面 | ||
| let result = merge_ranges(&[0, 100, 200]); | ||
| assert_eq!(result, vec![(0, 1), (100, 1), (200, 1)]); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_long_consecutive_sequence() { | ||
| // 长连续序列(模拟大文件预读) | ||
| let input: Vec<usize> = (0..128).collect(); | ||
| let result = merge_ranges(&input); | ||
| assert_eq!(result, vec![(0, 128)]); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_alternating_pattern() { | ||
| // 交替的连续和间断模式 | ||
| let result = merge_ranges(&[1, 2, 4, 5, 7, 8, 10]); | ||
| assert_eq!(result, vec![(1, 2), (4, 2), (7, 2), (10, 1)]); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_real_world_sparse() { | ||
| // 真实场景:稀疏的页面缓存(部分页面已存在) | ||
| let result = merge_ranges(&[0, 5, 6, 7, 12, 20, 21]); | ||
| assert_eq!(result, vec![(0, 1), (5, 3), (12, 1), (20, 2)]); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.