diff --git a/markbase-core/src/webdav.rs b/markbase-core/src/webdav.rs index d5ea4ce..5971b04 100644 --- a/markbase-core/src/webdav.rs +++ b/markbase-core/src/webdav.rs @@ -333,6 +333,8 @@ pub struct VfsDavFile { is_write: bool, versioning: Option>, flushed: bool, + read_cache: Vec, + read_cache_offset: u64, } impl std::fmt::Debug for VfsDavFile { @@ -359,6 +361,8 @@ impl VfsDavFile { is_write: false, versioning: None, flushed: true, + read_cache: Vec::new(), + read_cache_offset: 0, } } @@ -386,6 +390,8 @@ impl VfsDavFile { is_write: true, versioning, flushed: false, + read_cache: Vec::new(), + read_cache_offset: 0, } } } @@ -455,21 +461,59 @@ impl DavFile for VfsDavFile { } fn read_bytes(&'_ mut self, count: usize) -> FsFuture<'_, Bytes> { + const CHUNK_SIZE: usize = 64 * 1024; // 64KB read-ahead + if let Some(vfs_file_mutex) = &self.vfs_file { + // Check if requested data is in cache + let cache_start = self.read_cache_offset as usize; + let cache_end = cache_start + self.read_cache.len(); + let req_start = self.position as usize; + let req_end = req_start + count; + + if req_start >= cache_start && req_end <= cache_end { + // Data in cache - return directly + let offset_in_cache = req_start - cache_start; + let bytes = Bytes::copy_from_slice( + &self.read_cache[offset_in_cache..offset_in_cache + count.min(self.read_cache.len() - offset_in_cache)] + ); + self.position += bytes.len() as u64; + return Box::pin(std::future::ready(Ok(bytes))); + } + + // Need to read new chunk if let Ok(mut vfs_file) = vfs_file_mutex.lock() { - let mut buf = vec![0u8; count]; - match vfs_file.read(&mut buf) { - Ok(0) => return Box::pin(std::future::ready(Ok(Bytes::new()))), + // Seek to current position if needed + let current_pos = vfs_file.seek(std::io::SeekFrom::Current(0)).unwrap_or(self.position); + if current_pos != self.position { + if vfs_file.seek(std::io::SeekFrom::Start(self.position)).is_err() { + return Box::pin(std::future::ready(Err(FsError::GeneralFailure))); + } + } + + // Read larger chunk + let read_size = std::cmp::max(count, CHUNK_SIZE); + self.read_cache.resize(read_size, 0); + self.read_cache_offset = self.position; + + match vfs_file.read(&mut self.read_cache) { + Ok(0) => { + self.read_cache.clear(); + return Box::pin(std::future::ready(Ok(Bytes::new()))); + } Ok(n) => { - buf.truncate(n); - self.position += n as u64; - return Box::pin(std::future::ready(Ok(Bytes::from(buf)))); + self.read_cache.truncate(n); + // Return requested portion + let result_len = count.min(n); + let bytes = Bytes::copy_from_slice(&self.read_cache[..result_len]); + self.position += result_len as u64; + return Box::pin(std::future::ready(Ok(bytes))); } Err(_) => {} } } Box::pin(std::future::ready(Err(FsError::NotImplemented))) } else { + // Write mode - read from self.data buffer let start = self.position as usize; let end = std::cmp::min(start + count, self.data.len()); @@ -489,6 +533,8 @@ impl DavFile for VfsDavFile { match vfs_file.seek(pos) { Ok(new_pos) => { self.position = new_pos; + self.read_cache.clear(); // Invalidate cache on seek + self.read_cache_offset = 0; return Box::pin(std::future::ready(Ok(new_pos))); } Err(_) => {}