summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Bridle <ben@derelict.engineering>2025-07-08 12:00:02 +1200
committerBen Bridle <ben@derelict.engineering>2025-07-08 12:00:23 +1200
commitf2bcc24eec84c4632c88b5a35821f7e642d41dc5 (patch)
treee45e5e69a52d49f617e23920b37bd769bb067878
parent82a10fb3ae8c935e6c325a1b458e7fe6c0b90df6 (diff)
downloadbedrock-pc-f2bcc24eec84c4632c88b5a35821f7e642d41dc5.zip
Invalidate the cached directory in the file device after a duration
The most recent directory accessed by the file device is cached to improve performance when rapidly ascending and descending between sibling entries. This causes an issue where, in a sandboxed root directory that contains only files, a program will be unable to invalidate the cache and any changes to the directory outside the program will not be seen by the program. To fix this, the directory cache now only lasts for one second.
-rw-r--r--src/devices/file_device.rs54
1 files changed, 27 insertions, 27 deletions
diff --git a/src/devices/file_device.rs b/src/devices/file_device.rs
index 43bb239..73f05cc 100644
--- a/src/devices/file_device.rs
+++ b/src/devices/file_device.rs
@@ -9,8 +9,8 @@ pub struct FileDevice {
pub action_buffer: BedrockPathBuffer,
pub path_buffer: BedrockPathBuffer,
- pub entry: Option<(Entry, BedrockFilePath)>,
- pub cached_dir: Option<(Entry, BedrockFilePath)>,
+ pub entry: Option<(Entry, BedrockFilePath, Instant)>,
+ pub cached_dir: Option<(Entry, BedrockFilePath, Instant)>,
pub success: bool,
pub pointer_write: u32,
@@ -141,10 +141,10 @@ impl FileDevice {
self.path_buffer.clear();
self.flush();
- if let Some((Entry::Directory(mut dir), path)) = std::mem::take(&mut self.entry) {
+ if let Some((Entry::Directory(mut dir), path, time)) = std::mem::take(&mut self.entry) {
// Prevent the selected child from persisting when loading from cache.
dir.deselect_child();
- self.cached_dir = Some((Entry::Directory(dir), path));
+ self.cached_dir = Some((Entry::Directory(dir), path, time));
}
}
@@ -160,17 +160,17 @@ impl FileDevice {
if let Ok(file) = open_result {
self.close();
self.path_buffer.populate(path.as_buffer());
- self.entry = Some((Entry::File(BufferedFile::new(file)), path));
+ self.entry = Some((Entry::File(BufferedFile::new(file)), path, Instant::now()));
return Ok(());
};
}
Some(EntryType::Directory) => {
- // Attempt to use the cached directory.
- if let Some((dir, cached_path)) = std::mem::take(&mut self.cached_dir) {
- if cached_path == path {
+ // Attempt to use the cached directory if not too old.
+ if let Some((dir, cached_path, time)) = std::mem::take(&mut self.cached_dir) {
+ if cached_path == path && time.elapsed() < Duration::from_secs(1) {
self.close();
self.path_buffer.populate(cached_path.as_buffer());
- self.entry = Some((dir, cached_path));
+ self.entry = Some((dir, cached_path, time));
return Ok(());
}
}
@@ -178,7 +178,7 @@ impl FileDevice {
if let Some(listing) = DirectoryListing::from_path(&path) {
self.close();
self.path_buffer.populate(path.as_buffer());
- self.entry = Some((Entry::Directory(listing), path));
+ self.entry = Some((Entry::Directory(listing), path, Instant::now()));
return Ok(());
};
}
@@ -206,7 +206,7 @@ impl FileDevice {
let destination = BedrockFilePath::from_buffer(buffer, &self.base_path);
self.success = false;
- if let Some((_, source)) = &self.entry {
+ if let Some((_, source, _)) = &self.entry {
if destination_blank {
if self.enable_delete {
self.success = delete_entry(&source.as_path());
@@ -227,7 +227,7 @@ impl FileDevice {
/// Attempt to open the parent directory of the current entry.
pub fn ascend_to_parent(&mut self) {
- if let Some((_, path)) = &self.entry {
+ if let Some((_, path, _)) = &self.entry {
match path.parent() {
Some(parent) => self.success = self.open(parent).is_ok(),
None => self.success = false,
@@ -242,7 +242,7 @@ impl FileDevice {
/// Attempt to open the selected child of the current directory.
pub fn descend_to_child(&mut self) {
- if let Some((Entry::Directory(dir), _)) = &self.entry {
+ if let Some((Entry::Directory(dir), _, _)) = &self.entry {
match dir.child_path() {
Some(child) => self.success = self.open(child).is_ok(),
None => self.success = false,
@@ -255,7 +255,7 @@ impl FileDevice {
/// Return true if the current entry is a directory.
pub fn entry_type(&self) -> bool {
match self.entry {
- Some((Entry::Directory(_), _)) => true,
+ Some((Entry::Directory(_), _, _)) => true,
_ => false,
}
}
@@ -263,13 +263,13 @@ impl FileDevice {
/// Read a byte from the path buffer of the selected child.
pub fn read_child_path(&mut self) -> u8 {
match &mut self.entry {
- Some((Entry::Directory(dir), _)) => dir.child_path_buffer().read(),
+ Some((Entry::Directory(dir), _, _)) => dir.child_path_buffer().read(),
_ => 0,
}
}
pub fn set_child_path(&mut self, byte: u8) {
- if let Some((Entry::Directory(dir), _)) = &mut self.entry {
+ if let Some((Entry::Directory(dir), _, _)) = &mut self.entry {
dir.child_path_buffer().set_pointer(byte);
}
}
@@ -277,7 +277,7 @@ impl FileDevice {
/// Return true if the selected child is a directory.
pub fn child_type(&self) -> bool {
match &self.entry {
- Some((Entry::Directory(dir), _)) => match dir.child_type() {
+ Some((Entry::Directory(dir), _, _)) => match dir.child_type() {
Some(EntryType::Directory) => true,
_ => false,
}
@@ -288,7 +288,7 @@ impl FileDevice {
/// Read a byte from the current file.
pub fn read_byte(&mut self) -> u8 {
match &mut self.entry {
- Some((Entry::File(file), _)) => file.read(),
+ Some((Entry::File(file), _, _)) => file.read(),
_ => 0,
}
}
@@ -296,44 +296,44 @@ impl FileDevice {
/// Writes a byte to the currently-open file.
pub fn write_byte(&mut self, byte: u8) {
match &mut self.entry {
- Some((Entry::File(file), _)) => file.write(byte),
+ Some((Entry::File(file), _, _)) => file.write(byte),
_ => (),
}
}
pub fn pointer(&mut self) -> u32 {
match &mut self.entry {
- Some((Entry::File(file), _)) => file.pointer(),
- Some((Entry::Directory(dir), _)) => dir.selected(),
+ Some((Entry::File(file), _, _)) => file.pointer(),
+ Some((Entry::Directory(dir), _, _)) => dir.selected(),
_ => 0,
}
}
pub fn commit_pointer(&mut self) {
match &mut self.entry {
- Some((Entry::File(file), _)) => file.set_pointer(self.pointer_write),
- Some((Entry::Directory(dir), _)) => dir.set_selected(self.pointer_write),
+ Some((Entry::File(file), _, _)) => file.set_pointer(self.pointer_write),
+ Some((Entry::Directory(dir), _, _)) => dir.set_selected(self.pointer_write),
_ => (),
}
}
pub fn length(&mut self) -> u32 {
match &mut self.entry {
- Some((Entry::File(file), _)) => file.length(),
- Some((Entry::Directory(dir), _)) => dir.length(),
+ Some((Entry::File(file), _, _)) => file.length(),
+ Some((Entry::Directory(dir), _, _)) => dir.length(),
_ => 0,
}
}
pub fn commit_length(&mut self) {
match &mut self.entry {
- Some((Entry::File(file), _)) => file.set_length(self.length_write),
+ Some((Entry::File(file), _, _)) => file.set_length(self.length_write),
_ => (),
}
}
pub fn flush(&mut self) {
- if let Some((Entry::File(buffered_file), _)) = &mut self.entry {
+ if let Some((Entry::File(buffered_file), _, _)) = &mut self.entry {
let _ = buffered_file;
}
}