patch: faster preload with BufReader

1. seek avoided with self maintained offset
2. BufReader to read faster

Signed-off-by: ClSlaid <cailue@bupt.edu.cn>
This commit is contained in:
ClSlaid 2023-10-28 22:33:51 +08:00
parent 7a802726fb
commit 4cd8d8a4a5
No known key found for this signature in database
GPG Key ID: E0A5F564C51C056E
3 changed files with 61 additions and 26 deletions

View File

@ -47,7 +47,7 @@ use super::LDAP_EPOCH_DELTA;
const READ_RETRY: i32 = 3; const READ_RETRY: i32 = 3;
/// block size for fuse, align to our asynchronic request size over FileContentsRequest. /// block size for fuse, align to our asynchronic request size over FileContentsRequest.
const BLOCK_SIZE: u32 = 4 * 1024 * 1024; pub const BLOCK_SIZE: u32 = 4 * 1024 * 1024;
/// read only permission /// read only permission
const PERM_READ: u16 = 0o444; const PERM_READ: u16 = 0o444;

View File

@ -1,9 +1,10 @@
use std::{ use std::{
collections::HashSet, collections::HashSet,
fs::File, fs::File,
io::{Read, Seek}, io::{BufReader, Read, Seek},
os::unix::prelude::PermissionsExt, os::unix::prelude::PermissionsExt,
path::PathBuf, path::PathBuf,
sync::atomic::{AtomicU64, Ordering},
time::SystemTime, time::SystemTime,
}; };
@ -13,7 +14,10 @@ use hbb_common::{
}; };
use utf16string::WString; use utf16string::WString;
use crate::{platform::LDAP_EPOCH_DELTA, CliprdrError}; use crate::{
platform::{fuse::BLOCK_SIZE, LDAP_EPOCH_DELTA},
CliprdrError,
};
/// has valid file attributes /// has valid file attributes
const FLAGS_FD_ATTRIBUTES: u32 = 0x04; const FLAGS_FD_ATTRIBUTES: u32 = 0x04;
@ -30,7 +34,9 @@ const FLAGS_FD_UNIX_MODE: u32 = 0x08;
#[derive(Debug)] #[derive(Debug)]
pub(super) struct LocalFile { pub(super) struct LocalFile {
pub path: PathBuf, pub path: PathBuf,
pub handle: Option<File>,
pub handle: Option<BufReader<File>>,
pub offset: AtomicU64,
pub name: String, pub name: String,
pub size: u64, pub size: u64,
@ -69,11 +75,13 @@ impl LocalFile {
// NOTE: open files lazily // NOTE: open files lazily
let handle = None; let handle = None;
let offset = AtomicU64::new(0);
Ok(Self { Ok(Self {
name, name,
path: path.clone(), path: path.clone(),
handle, handle,
offset,
size, size,
last_write_time, last_write_time,
is_dir, is_dir,
@ -160,33 +168,47 @@ impl LocalFile {
buf.to_vec() buf.to_vec()
} }
pub fn read_exact_at(&mut self, buf: &mut [u8], offset: u64) -> Result<(), CliprdrError> { #[inline]
if self.handle.is_none() { pub fn load_handle(&mut self) -> Result<(), CliprdrError> {
if !self.is_dir && self.handle.is_none() {
let handle = std::fs::File::open(&self.path).map_err(|e| CliprdrError::FileError { let handle = std::fs::File::open(&self.path).map_err(|e| CliprdrError::FileError {
path: self.path.clone(), path: self.path.clone(),
err: e, err: e,
})?; })?;
self.handle = Some(handle); let reader = BufReader::with_capacity(BLOCK_SIZE as usize, handle);
self.handle = Some(reader);
}; };
Ok(())
}
pub fn read_exact_at(&mut self, buf: &mut [u8], offset: u64) -> Result<(), CliprdrError> {
self.load_handle()?;
let handle = self.handle.as_mut().unwrap(); let handle = self.handle.as_mut().unwrap();
handle if offset != self.offset.load(Ordering::Relaxed) {
.seek(std::io::SeekFrom::Start(offset)) handle
.map_err(|e| CliprdrError::FileError { .seek(std::io::SeekFrom::Start(offset))
path: self.path.clone(), .map_err(|e| CliprdrError::FileError {
err: e, path: self.path.clone(),
})?; err: e,
})?;
}
handle handle
.read_exact(buf) .read_exact(buf)
.map_err(|e| CliprdrError::FileError { .map_err(|e| CliprdrError::FileError {
path: self.path.clone(), path: self.path.clone(),
err: e, err: e,
})?; })?;
// gc let new_offset = offset + (buf.len() as u64);
if offset + (buf.len() as u64) >= self.size { self.offset.store(new_offset, Ordering::Relaxed);
// gc file handle
if new_offset >= self.size {
self.offset.store(0, Ordering::Relaxed);
self.handle = None; self.handle = None;
} }
Ok(()) Ok(())
} }
} }

View File

@ -190,7 +190,7 @@ impl ClipboardContext {
) -> Result<(), CliprdrError> { ) -> Result<(), CliprdrError> {
let mut file_list = self.local_files.lock(); let mut file_list = self.local_files.lock();
let file_contents_resp = match request { let (file_idx, file_contents_resp) = match request {
FileContentsRequest::Size { FileContentsRequest::Size {
stream_id, stream_id,
file_idx, file_idx,
@ -220,11 +220,14 @@ impl ClipboardContext {
); );
let size = file.size; let size = file.size;
ClipboardFile::FileContentsResponse { (
msg_flags: 0x1, file_idx,
stream_id, ClipboardFile::FileContentsResponse {
requested_data: size.to_le_bytes().to_vec(), msg_flags: 0x1,
} stream_id,
requested_data: size.to_le_bytes().to_vec(),
},
)
} }
FileContentsRequest::Range { FileContentsRequest::Range {
stream_id, stream_id,
@ -280,16 +283,26 @@ impl ClipboardContext {
file.read_exact_at(&mut buf, offset)?; file.read_exact_at(&mut buf, offset)?;
ClipboardFile::FileContentsResponse { (
msg_flags: 0x1, file_idx,
stream_id, ClipboardFile::FileContentsResponse {
requested_data: buf, msg_flags: 0x1,
} stream_id,
requested_data: buf,
},
)
} }
}; };
send_data(conn_id, file_contents_resp); send_data(conn_id, file_contents_resp);
log::debug!("file contents sent to conn: {}", conn_id); log::debug!("file contents sent to conn: {}", conn_id);
// hot reload next file
for next_file in file_list.iter_mut().skip(file_idx + 1) {
if !next_file.is_dir {
next_file.load_handle()?;
break;
}
}
Ok(()) Ok(())
} }
} }