1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use std::collections::{HashMap, VecDeque};
use std::{cmp, ptr};
use syscall::error::Result;
use disk::Disk;
use BLOCK_SIZE;
fn copy_memory(src: &[u8], dest: &mut [u8]) -> usize {
let len = cmp::min(src.len(), dest.len());
unsafe { ptr::copy(src.as_ptr(), dest.as_mut_ptr(), len) };
len
}
pub struct DiskCache<T> {
inner: T,
cache: HashMap<u64, [u8; BLOCK_SIZE as usize]>,
order: VecDeque<u64>,
size: usize,
}
impl<T: Disk> DiskCache<T> {
pub fn new(inner: T) -> Self {
DiskCache {
inner: inner,
cache: HashMap::new(),
order: VecDeque::new(),
size: 65536,
}
}
fn insert(&mut self, i: u64, data: [u8; BLOCK_SIZE as usize]) {
while self.order.len() >= self.size {
let removed = self.order.pop_front().unwrap();
self.cache.remove(&removed);
}
self.cache.insert(i, data);
self.order.push_back(i);
}
}
impl<T: Disk> Disk for DiskCache<T> {
fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
let mut read = 0;
let mut failed = false;
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1) / (BLOCK_SIZE as usize) {
let block_i = block + i as u64;
let buffer_i = i * BLOCK_SIZE as usize;
let buffer_j = cmp::min(buffer_i + BLOCK_SIZE as usize, buffer.len());
let buffer_slice = &mut buffer[buffer_i..buffer_j];
if let Some(cache_buf) = self.cache.get_mut(&block_i) {
read += copy_memory(cache_buf, buffer_slice);
} else {
failed = true;
break;
}
}
if failed {
self.inner.read_at(block, buffer)?;
read = 0;
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1) / (BLOCK_SIZE as usize) {
let block_i = block + i as u64;
let buffer_i = i * BLOCK_SIZE as usize;
let buffer_j = cmp::min(buffer_i + BLOCK_SIZE as usize, buffer.len());
let buffer_slice = &buffer[buffer_i..buffer_j];
let mut cache_buf = [0; BLOCK_SIZE as usize];
read += copy_memory(buffer_slice, &mut cache_buf);
self.insert(block_i, cache_buf);
}
}
Ok(read)
}
fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
self.inner.write_at(block, buffer)?;
let mut written = 0;
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1) / (BLOCK_SIZE as usize) {
let block_i = block + i as u64;
let buffer_i = i * BLOCK_SIZE as usize;
let buffer_j = cmp::min(buffer_i + BLOCK_SIZE as usize, buffer.len());
let buffer_slice = &buffer[buffer_i..buffer_j];
let mut cache_buf = [0; BLOCK_SIZE as usize];
written += copy_memory(buffer_slice, &mut cache_buf);
self.insert(block_i, cache_buf);
}
Ok(written)
}
fn size(&mut self) -> Result<u64> {
self.inner.size()
}
}