Skip to content

Commit

Permalink
mount init and store added with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
wasm-forge committed Aug 5, 2024
1 parent 3a48857 commit 5d8be0b
Show file tree
Hide file tree
Showing 10 changed files with 493 additions and 182 deletions.
106 changes: 105 additions & 1 deletion src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ impl FileSystem {
}
}

// mounte memory file on the top of the given file name, if the file does not exist, it will be created.
// The method fails if the file system couldn't create the file.
pub fn mount_memory_file(
&mut self,
filename: &str,
Expand All @@ -122,6 +124,24 @@ impl FileSystem {
Ok(())
}

// initialize mounted memory with the data stored in the host file
pub fn init_memory_file(&mut self, filename: &str) -> Result<(), Error> {
// create a file for the mount
let fd = self.open_or_create(
self.root_fd,
filename,
FdStat::default(),
OpenFlags::empty(),
0,
)?;

let node = self.get_node(fd)?;
self.close(fd)?;

self.storage.init_mounted_memory(node)
}

// helper method to set the size of the mounted memory
pub fn set_memory_file_size(
&mut self,
filename: &str,
Expand All @@ -144,6 +164,42 @@ impl FileSystem {
Ok(())
}

// store content of the currently active memory file to the file system
pub fn store_memory_file(&mut self, filename: &str) -> Result<(), Error> {
// create a file for the mount
let fd = self.open_or_create(
self.root_fd,
filename,
FdStat::default(),
OpenFlags::empty(),
0,
)?;

let node = self.get_node(fd)?;
self.close(fd)?;

self.storage.store_mounted_memory(node)
}

// Unmount memory file, the system will continue to work with its own memory
pub fn unmount_memory_file(&mut self, filename: &str) -> Result<Box<dyn Memory>, Error> {
// create a file for the mount
let fd = self.open_or_create(
self.root_fd,
filename,
FdStat::default(),
OpenFlags::empty(),
0,
)?;

let node = self.get_node(fd)?;
self.close(fd)?;

let memory = self.storage.unmount_node(node)?;

Ok(memory)
}

// Get dir entry for a given directory and the directory index.
pub fn get_direntry(&self, fd: Fd, index: DirEntryIndex) -> Result<DirEntry, Error> {
self.get_dir(fd)?.get_entry(index, self.storage.as_ref())
Expand Down Expand Up @@ -514,7 +570,7 @@ mod tests {
structure_helpers::find_node,
types::{FdStat, OpenFlags},
},
storage::types::FileType,
storage::types::{FileSize, FileType},
test_utils::{
new_vector_memory, read_text_file, test_fs, test_fs_setups, test_fs_transient,
write_text_fd, write_text_file,
Expand Down Expand Up @@ -1277,6 +1333,54 @@ mod tests {
println!("{:?}", buf);
}

#[test]
fn mounted_memory_store_and_init_roundtrip() {
for mut fs in test_fs_setups("") {
let memory1: VectorMemory = new_vector_memory();
let memory2: VectorMemory = new_vector_memory();

let file_name = "test.txt";

fs.mount_memory_file(file_name, Box::new(memory1.clone()))
.unwrap();

let content = "ABCDEFG123";
let len = content.len();
let count = 1000;

memory1.grow(5);

// fill up memory with some data
for i in 0..count {
memory1.write(i as u64 * len as u64, content.as_bytes());
}

fs.set_memory_file_size(file_name, len as FileSize * count as FileSize)
.unwrap();

// store memory into a file
fs.store_memory_file(file_name).unwrap();

fs.unmount_memory_file(file_name).unwrap();

fs.mount_memory_file(file_name, Box::new(memory2.clone()))
.unwrap();

// init new memory into a file
fs.init_memory_file(file_name).unwrap();

let mut buf1 = [0u8; 10];
let mut buf2 = [0u8; 10];

for i in 0..count {
memory1.read(i as u64 * len as u64, &mut buf1);
memory2.read(i as u64 * len as u64, &mut buf2);

assert_eq!(buf1, buf2);
}
}
}

#[test]
fn writing_from_different_file_descriptors() {
for mut fs in test_fs_setups("f1/f2/text.txt") {
Expand Down
2 changes: 1 addition & 1 deletion src/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub mod dir;
pub mod fd;
pub mod file;
pub mod structure_helpers;
pub(crate) mod structure_helpers;
pub mod types;
109 changes: 4 additions & 105 deletions src/runtime/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
error::Error,
runtime::types::{FdFlags, FdStat, Whence},
storage::{
types::{FileChunkIndex, FileSize, FileType, Node, FILE_CHUNK_SIZE},
types::{FileSize, FileType, Node},
Storage,
},
};
Expand Down Expand Up @@ -126,6 +126,8 @@ impl File {
buf: &mut [u8],
storage: &mut dyn Storage,
) -> Result<FileSize, Error> {
use super::structure_helpers::get_chunk_infos;

if buf.is_empty() {
return Ok(0 as FileSize);
}
Expand Down Expand Up @@ -155,26 +157,7 @@ impl File {
buf: &[u8],
storage: &mut dyn Storage,
) -> Result<FileSize, Error> {
let mut metadata = storage.get_metadata(self.node)?;
let end = offset + buf.len() as FileSize;
let chunk_infos = get_chunk_infos(offset, end);
let mut written_size = 0;
for chunk in chunk_infos.into_iter() {
storage.write_filechunk(
self.node,
chunk.index,
chunk.offset,
&buf[written_size..written_size + chunk.len as usize],
);
written_size += chunk.len as usize;
}

if end > metadata.size {
metadata.size = end;
storage.put_metadata(self.node, metadata)
}

Ok(written_size as FileSize)
storage.write_with_offset(self.node, offset, buf)
}

// Truncate file to 0 size.
Expand All @@ -186,41 +169,6 @@ impl File {
}
}

#[derive(Debug, PartialEq, Eq)]
struct ChunkHandle {
index: FileChunkIndex,
offset: FileSize,
len: FileSize,
}

fn offset_to_file_chunk_index(offset: FileSize) -> FileChunkIndex {
(offset / FILE_CHUNK_SIZE as FileSize) as FileChunkIndex
}

fn file_chunk_index_to_offset(index: FileChunkIndex) -> FileSize {
index as FileSize * FILE_CHUNK_SIZE as FileSize
}

fn get_chunk_infos(start: FileSize, end: FileSize) -> Vec<ChunkHandle> {
let mut result = vec![];
let start_index = offset_to_file_chunk_index(start);
let end_index = offset_to_file_chunk_index(end);
for index in start_index..=end_index {
let start_of_chunk = file_chunk_index_to_offset(index);
assert!(start_of_chunk <= end);
let start_in_chunk = start_of_chunk.max(start) - start_of_chunk;
let end_in_chunk = (start_of_chunk + FILE_CHUNK_SIZE as FileSize).min(end) - start_of_chunk;
if start_in_chunk < end_in_chunk {
result.push(ChunkHandle {
index,
offset: start_in_chunk,
len: end_in_chunk - start_in_chunk,
});
}
}
result
}

#[cfg(test)]
mod tests {
use crate::{
Expand All @@ -230,55 +178,6 @@ mod tests {

use super::*;

#[test]
fn get_chunk_infos_parital() {
let chunks = get_chunk_infos(
FILE_CHUNK_SIZE as FileSize - 1,
2 * FILE_CHUNK_SIZE as FileSize + 1,
);
assert_eq!(
chunks[0],
ChunkHandle {
index: 0,
offset: FILE_CHUNK_SIZE as FileSize - 1,
len: 1
}
);
assert_eq!(
chunks[1],
ChunkHandle {
index: 1,
offset: 0,
len: FILE_CHUNK_SIZE as FileSize,
}
);

assert_eq!(
chunks[2],
ChunkHandle {
index: 2,
offset: 0,
len: 1,
}
);
}

#[test]
fn get_chunk_infos_full() {
let chunks = get_chunk_infos(0, 10 * FILE_CHUNK_SIZE as FileSize);
#[allow(clippy::needless_range_loop)]
for i in 0..10 {
assert_eq!(
chunks[i],
ChunkHandle {
index: i as FileChunkIndex,
offset: 0,
len: FILE_CHUNK_SIZE as FileSize,
}
);
}
}

#[test]
fn seek_and_tell() {
let mut fs = test_fs();
Expand Down
Loading

0 comments on commit 5d8be0b

Please sign in to comment.