parallel_processor/memory_fs/file/
reader.rs1use crate::memory_fs::file::internal::{FileChunk, MemoryFileInternal, OpenMode};
2use crate::utils::vec_reader::VecReaderInner;
3use parking_lot::lock_api::ArcRwLockReadGuard;
4use parking_lot::{RawRwLock, RwLock};
5use std::io;
6use std::io::{ErrorKind, Read, Seek, SeekFrom};
7use std::ops::Range;
8use std::path::{Path, PathBuf};
9use std::sync::Arc;
10
11use super::writer::FileWriter;
12
13const MIN_UNBUFFERED_READ: usize = 2048;
14const FILE_READ_BUFFER_SIZE: usize = 4096;
15
16#[derive(Clone)]
17pub struct FileRangeReference {
18 file: Arc<RwLock<MemoryFileInternal>>,
19 start_chunk: usize,
20 start_chunk_offset: usize,
21 bytes_count: usize,
22}
23
24impl FileRangeReference {
25 pub unsafe fn copy_to_unsync(&self, other: &FileWriter) {
26 let file = self.file.read();
27 let mut chunk_index = self.start_chunk;
28 let mut chunk_offset = self.start_chunk_offset;
29 let mut written_bytes = 0;
30
31 while written_bytes < self.bytes_count {
32 let underlying_file = file.get_underlying_file();
33 let chunk = file.get_chunk(chunk_index);
34 let chunk = chunk.read();
35 let to_copy = (chunk.get_length() - chunk_offset).min(self.bytes_count - written_bytes);
36
37 other.write_all_unsync_from_readfn(
38 |buffer| {
39 let amount = chunk
40 .read_at(underlying_file, chunk_offset as u64, buffer)
41 .unwrap();
42 chunk_offset += amount;
43 amount
44 },
45 to_copy,
46 );
47
48 written_bytes += to_copy;
49 chunk_index += 1;
50 chunk_offset = 0;
51 }
52 }
53}
54
55pub struct FileReader {
56 path: PathBuf,
57 file: Arc<RwLock<MemoryFileInternal>>,
58 current_chunk_ref: Option<ArcRwLockReadGuard<RawRwLock, FileChunk>>,
59 current_chunk_index: usize,
60 chunks_count: usize,
61 current_position: usize,
62 current_len: usize,
63 current_file_position: usize,
64 is_on_disk: bool,
65 buffer: Option<VecReaderInner>,
66 buffer_position: usize,
67}
68
69unsafe impl Sync for FileReader {}
70unsafe impl Send for FileReader {}
71
72impl Clone for FileReader {
73 fn clone(&self) -> Self {
74 Self {
75 path: self.path.clone(),
76 file: self.file.clone(),
77 current_chunk_ref: self
78 .current_chunk_ref
79 .as_ref()
80 .map(|c| ArcRwLockReadGuard::rwlock(&c).read_arc()),
81 current_chunk_index: self.current_chunk_index,
82 chunks_count: self.chunks_count,
83 current_position: self.current_position,
84 current_len: self.current_len,
85 current_file_position: self.current_file_position,
86 is_on_disk: self.is_on_disk,
87 buffer: self.buffer.clone(),
88 buffer_position: self.buffer_position,
89 }
90 }
91}
92
93impl FileReader {
94 fn set_chunk_info(&mut self, index: usize) {
95 let file = self.file.read();
96
97 let chunk = file.get_chunk(index);
98 let chunk_guard = chunk.read_arc();
99
100 self.current_position = 0;
101 self.buffer_position = 0;
102 self.current_len = chunk_guard.get_length();
103 self.is_on_disk = chunk_guard.is_on_disk();
104 self.current_chunk_ref = Some(chunk_guard);
105
106 if self.is_on_disk && self.buffer.is_none() {
107 self.buffer = Some(VecReaderInner::new(FILE_READ_BUFFER_SIZE))
108 }
109
110 self.buffer.as_mut().map(|b| b.reset());
111 }
112
113 pub fn open(path: impl AsRef<Path>) -> Option<Self> {
114 let file = match MemoryFileInternal::retrieve_reference(&path) {
115 None => MemoryFileInternal::create_from_fs(&path)?,
116 Some(x) => x,
117 };
118
119 let mut file_lock = file.write();
120
121 file_lock.open(OpenMode::Read).unwrap();
122 let chunks_count = file_lock.get_chunks_count();
123 drop(file_lock);
124
125 let mut reader = Self {
126 path: path.as_ref().into(),
127 file,
128 current_chunk_ref: None,
129 current_chunk_index: 0,
130 chunks_count,
131 current_position: 0,
132 current_len: 0,
133 current_file_position: 0,
134 is_on_disk: false,
135 buffer: None,
136 buffer_position: 0,
137 };
138
139 if reader.chunks_count > 0 {
140 reader.set_chunk_info(0);
141 }
142
143 Some(reader)
144 }
145
146 pub fn get_unique_file_id(&self) -> usize {
147 self.file.data_ptr() as usize
148 }
149
150 pub fn total_file_size(&self) -> usize {
151 self.file.read().len()
152 }
153
154 pub fn get_file_path(&self) -> &Path {
155 &self.path
156 }
157
158 pub fn close_and_remove(self, remove_fs: bool) -> bool {
159 MemoryFileInternal::delete(self.path, remove_fs)
160 }
161
162 pub fn get_range_reference(&self, file_range: Range<u64>) -> FileRangeReference {
163 let file = self.file.read();
164 let mut chunk_index = 0;
165 let mut chunk_offset = 0;
166 let mut start = file_range.start;
167
168 while start > 0 {
169 let chunk = file.get_chunk(chunk_index);
170 let chunk = chunk.read();
171 let len = chunk.get_length() as u64;
172 if start < len {
173 chunk_offset = start as usize;
174 break;
175 }
176 start -= len;
177 chunk_index += 1;
178 }
179
180 FileRangeReference {
181 file: self.file.clone(),
182 start_chunk: chunk_index,
183 start_chunk_offset: chunk_offset,
184 bytes_count: file_range.end as usize - file_range.start as usize,
185 }
186 }
187
188 }
193
194impl Read for FileReader {
195 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
196 let mut bytes_written = 0;
197
198 while bytes_written != buf.len() {
199 if self.current_len == 0 {
200 self.current_chunk_index += 1;
201 if self.current_chunk_index >= self.chunks_count {
202 return Ok(bytes_written);
204 }
205 self.set_chunk_info(self.current_chunk_index);
206 }
207
208 let file = self.file.read();
209 let underlying_file = file.get_underlying_file();
210
211 let copyable_bytes = buf.len() - bytes_written;
212
213 let copyable_bytes = if self.is_on_disk && copyable_bytes < MIN_UNBUFFERED_READ {
214 let buffer = self.buffer.as_mut().unwrap();
215 let copyable_bytes = buffer.read_bytes(&mut buf[bytes_written..], |buffer| {
216 let read_amount = self.current_chunk_ref.as_ref().unwrap().read_at(
217 underlying_file,
218 self.buffer_position as u64,
219 buffer,
220 )?;
221 self.buffer_position += read_amount;
222 Ok(read_amount)
223 });
224 copyable_bytes
225 } else {
226 let copyable_bytes = self.current_chunk_ref.as_ref().unwrap().read_at(
227 underlying_file,
228 self.current_position as u64,
229 &mut buf[bytes_written..],
230 )?;
231 self.buffer
232 .as_mut()
233 .map(|b| self.buffer_position += b.discard(copyable_bytes));
234 copyable_bytes
235 };
236
237 self.current_position += copyable_bytes;
238 self.current_len -= copyable_bytes;
239 self.current_file_position += copyable_bytes;
240 bytes_written += copyable_bytes;
241 }
242
243 Ok(bytes_written)
244 }
245
246 #[inline(always)]
247 fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
248 match self.read(buf) {
249 Ok(count) => {
250 if count == buf.len() {
251 Ok(())
252 } else {
253 Err(io::Error::new(
254 io::ErrorKind::Other,
255 "Unexpected error while reading",
256 ))
257 }
258 }
259 Err(err) => Err(err),
260 }
261 }
262}
263
264impl Seek for FileReader {
265 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
266 match pos {
267 SeekFrom::Start(mut offset) => {
268 let mut chunk_idx = 0;
269
270 let file = self.file.read();
271 while chunk_idx < self.chunks_count {
272 let len = file.get_chunk(chunk_idx).read().get_length();
273 if offset < (len as u64) {
274 break;
275 }
276 chunk_idx += 1;
277 offset -= len as u64;
278 }
279
280 if chunk_idx == self.chunks_count {
281 return Err(std::io::Error::new(
282 ErrorKind::UnexpectedEof,
283 "Unexpected eof",
284 ));
285 }
286
287 self.current_chunk_index = chunk_idx;
288 drop(file);
289 self.set_chunk_info(chunk_idx);
290
291 self.current_position += offset as usize;
292 self.buffer
293 .as_mut()
294 .map(|b| self.buffer_position += b.discard(offset as usize));
295 self.current_len -= offset as usize;
296 self.current_file_position = offset as usize;
297
298 return Ok(offset);
299 }
300 SeekFrom::Current(offset) => {
301 assert!(offset >= 0); let mut offset = offset as usize;
303 loop {
304 let clen_offset = offset.min(self.current_len);
305 offset -= clen_offset;
306 self.current_len -= clen_offset;
307 self.current_position += clen_offset;
308 self.buffer
309 .as_mut()
310 .map(|b| self.buffer_position += b.discard(clen_offset as usize));
311 self.current_file_position += clen_offset;
312
313 if offset == 0 {
314 break Ok(self.current_file_position as u64);
315 }
316
317 if self.current_chunk_index >= self.chunks_count - 1 {
318 break Err(std::io::Error::new(
319 ErrorKind::UnexpectedEof,
320 "Unexpected eof",
321 ));
322 }
323
324 self.current_chunk_index += 1;
325 self.set_chunk_info(self.current_chunk_index);
326 }
327 }
328 _ => {
329 unimplemented!()
330 }
331 }
332 }
333
334 fn stream_position(&mut self) -> io::Result<u64> {
335 let mut position = 0;
336
337 let file_read = self.file.read();
338
339 for i in 0..self.current_chunk_index {
340 position += file_read.get_chunk(i).read().get_length();
341 }
342
343 position += file_read
344 .get_chunk(self.current_chunk_index)
345 .read()
346 .get_length()
347 - self.current_len;
348
349 Ok(position as u64)
350 }
351}