parallel_processor/memory_fs/file/
writer.rs1use crate::memory_fs::allocator::{AllocatedChunk, CHUNKS_ALLOCATOR};
2use crate::memory_fs::file::internal::{
3 FileChunk, MemoryFileInternal, MemoryFileMode, OpenMode, UnderlyingFile,
4};
5use crate::memory_fs::stats;
6use bincode::enc::write::Writer;
7use parking_lot::{RwLock, RwLockWriteGuard};
8use std::io::{Seek, SeekFrom, Write};
9use std::ops::{Deref, DerefMut};
10use std::path::{Path, PathBuf};
11use std::slice::from_raw_parts_mut;
12use std::sync::atomic::{AtomicU64, Ordering};
13use std::sync::Arc;
14
15pub struct FileWriter {
16 path: PathBuf,
17 current_buffer: RwLock<AllocatedChunk>,
18 file_length: AtomicU64,
19 file: Arc<RwLock<MemoryFileInternal>>,
20}
21
22impl FileWriter {
23 pub fn create(path: impl AsRef<Path>, mode: MemoryFileMode) -> Self {
25 Self {
26 path: PathBuf::from(path.as_ref()),
27 current_buffer: RwLock::new(
28 CHUNKS_ALLOCATOR.request_chunk(chunk_usage!(TemporarySpace)),
29 ),
30 file_length: AtomicU64::new(0),
31 file: {
32 let file = MemoryFileInternal::create_new(path, mode);
33 file.write().open(OpenMode::Write).unwrap();
34 file
35 },
36 }
37 }
38
39 pub fn len(&self) -> u64 {
41 self.file_length.load(Ordering::Relaxed) + self.current_buffer.read().len() as u64
42 }
43
44 pub fn write_at_start(&mut self, data: &[u8]) -> Result<(), ()> {
46 if data.len() > 128 {
47 return Err(());
48 }
49
50 unsafe {
51 let current_buffer_lock = self.current_buffer.read();
52
53 let file_read = self.file.read();
54
55 if file_read.get_chunks_count() > 0 {
56 drop(current_buffer_lock);
57 match file_read.get_chunk(0).read().deref() {
58 FileChunk::OnDisk { .. } => {
59 if let UnderlyingFile::WriteMode { file, .. } =
60 file_read.get_underlying_file()
61 {
62 let mut disk_file_lock = file.lock();
63 let mut disk_file = disk_file_lock.get_file();
64 let position = disk_file.stream_position().unwrap();
65 disk_file.seek(SeekFrom::Start(0)).unwrap();
66 disk_file.write_all(data).unwrap();
67 disk_file.seek(SeekFrom::Start(position)).unwrap();
68 Ok(())
69 } else {
70 Err(())
71 }
72 }
73 FileChunk::OnMemory { chunk } => {
74 std::ptr::copy_nonoverlapping(
75 data.as_ptr(),
76 chunk.get_mut_ptr(),
77 data.len(),
78 );
79 Ok(())
80 }
81 }
82 } else {
83 std::ptr::copy_nonoverlapping(
84 data.as_ptr(),
85 current_buffer_lock.get_mut_ptr(),
86 data.len(),
87 );
88 Ok(())
89 }
90 }
91 }
92
93 pub fn write_all_unsync_from_readfn(
94 &self,
95 mut read_fn: impl FnMut(&mut [u8]) -> usize,
96 length: usize,
97 ) -> u64 {
98 stats::add_files_usage(length as u64);
100
101 let buffer = self.current_buffer.read();
102
103 unsafe {
104 let remaining_slice = from_raw_parts_mut(
105 buffer.get_mut_ptr().add(buffer.len()),
106 buffer.max_len() - buffer.len(),
107 );
108 if remaining_slice.len() >= length {
109 let amount_read = read_fn(&mut remaining_slice[..length]);
110 buffer.set_len(self.len() as usize + amount_read);
111 self.file_length.load(Ordering::Relaxed) + buffer.len() as u64
112 } else {
113 drop(buffer);
114 let mut buffer = self.current_buffer.write();
115 let mut temp_vec = Vec::new();
116
117 let position = self
118 .file_length
119 .fetch_add(buffer.len() as u64, Ordering::SeqCst)
120 + (buffer.len() as u64);
121
122 replace_with::replace_with_or_abort(buffer.deref_mut(), |buffer| {
123 let new_buffer = MemoryFileInternal::reserve_space(
124 &self.file,
125 buffer,
126 &mut temp_vec,
127 length,
128 length,
129 );
130 new_buffer
131 });
132
133 self.file_length
135 .fetch_add((length - buffer.len()) as u64, Ordering::SeqCst);
136
137 let _buffer_read = RwLockWriteGuard::downgrade(buffer);
138
139 for (_lock, part) in temp_vec.drain(..) {
140 read_fn(part);
141 }
142
143 if self.file.read().is_on_disk() {
144 self.file.write().flush_chunks(usize::MAX);
145 }
146 position
147 }
148 }
150 }
151
152 pub fn write_all_parallel(&self, data: &[u8], el_size: usize) -> u64 {
154 stats::add_files_usage(data.len() as u64);
156
157 let buffer = self.current_buffer.read();
158 if let Some(chunk_position) = buffer.write_bytes_noextend(data) {
159 self.file_length.load(Ordering::Relaxed) + chunk_position
160 } else {
161 drop(buffer);
162 let mut buffer = self.current_buffer.write();
163
164 if let Some(chunk_position) = buffer.write_bytes_noextend(data) {
166 return self.file_length.load(Ordering::Relaxed) + chunk_position;
167 }
168
169 let mut temp_vec = Vec::new();
170
171 let position = self
172 .file_length
173 .fetch_add(buffer.len() as u64, Ordering::SeqCst)
174 + (buffer.len() as u64);
175
176 replace_with::replace_with_or_abort(buffer.deref_mut(), |buffer| {
177 let new_buffer = MemoryFileInternal::reserve_space(
178 &self.file,
179 buffer,
180 &mut temp_vec,
181 data.len(),
182 el_size,
183 );
184 new_buffer
185 });
186
187 self.file_length
189 .fetch_add((data.len() - buffer.len()) as u64, Ordering::SeqCst);
190
191 let _buffer_read = RwLockWriteGuard::downgrade(buffer);
192
193 let mut offset = 0;
194 for (_lock, part) in temp_vec.drain(..) {
195 part.copy_from_slice(&data[offset..(offset + part.len())]);
196 offset += part.len();
197 }
198
199 if self.file.read().is_on_disk() {
200 self.file.write().flush_chunks(usize::MAX);
201 }
202 position
203 }
204 }
205
206 pub fn get_path(&self) -> PathBuf {
207 self.path.clone()
208 }
209
210 pub fn flush_async(&self) {}
211}
212
213impl Writer for FileWriter {
214 fn write(&mut self, bytes: &[u8]) -> Result<(), bincode::error::EncodeError> {
215 self.write_all_parallel(bytes, 1);
216 Ok(())
217 }
218}
219
220impl Write for FileWriter {
221 #[inline(always)]
222 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
223 self.write_all_parallel(buf, 1);
224 Ok(buf.len())
225 }
226
227 #[inline(always)]
228 fn flush(&mut self) -> std::io::Result<()> {
229 Ok(())
230 }
231}
232
233impl Drop for FileWriter {
234 fn drop(&mut self) {
235 let mut current_buffer = self.current_buffer.write();
236 if current_buffer.len() > 0 {
237 MemoryFileInternal::add_chunk(
238 &self.file,
239 std::mem::replace(current_buffer.deref_mut(), AllocatedChunk::INVALID),
240 );
241 if self.file.read().is_on_disk() {
242 self.file.write().flush_chunks(usize::MAX);
243 }
244 }
245 self.file.write().close();
246 }
247}