From 4cd8d8a4a56a7c08eaadfd3ee0bac4fa2cac6817 Mon Sep 17 00:00:00 2001 From: ClSlaid Date: Sat, 28 Oct 2023 22:33:51 +0800 Subject: [PATCH] patch: faster preload with BufReader 1. seek avoided with self maintained offset 2. BufReader to read faster Signed-off-by: ClSlaid --- libs/clipboard/src/platform/fuse.rs | 2 +- .../src/platform/linux/local_file.rs | 50 +++++++++++++------ libs/clipboard/src/platform/linux/mod.rs | 35 +++++++++---- 3 files changed, 61 insertions(+), 26 deletions(-) diff --git a/libs/clipboard/src/platform/fuse.rs b/libs/clipboard/src/platform/fuse.rs index 5ce4accd3..9294ac1db 100644 --- a/libs/clipboard/src/platform/fuse.rs +++ b/libs/clipboard/src/platform/fuse.rs @@ -47,7 +47,7 @@ use super::LDAP_EPOCH_DELTA; const READ_RETRY: i32 = 3; /// 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 const PERM_READ: u16 = 0o444; diff --git a/libs/clipboard/src/platform/linux/local_file.rs b/libs/clipboard/src/platform/linux/local_file.rs index c585758df..2ebe694fa 100644 --- a/libs/clipboard/src/platform/linux/local_file.rs +++ b/libs/clipboard/src/platform/linux/local_file.rs @@ -1,9 +1,10 @@ use std::{ collections::HashSet, fs::File, - io::{Read, Seek}, + io::{BufReader, Read, Seek}, os::unix::prelude::PermissionsExt, path::PathBuf, + sync::atomic::{AtomicU64, Ordering}, time::SystemTime, }; @@ -13,7 +14,10 @@ use hbb_common::{ }; use utf16string::WString; -use crate::{platform::LDAP_EPOCH_DELTA, CliprdrError}; +use crate::{ + platform::{fuse::BLOCK_SIZE, LDAP_EPOCH_DELTA}, + CliprdrError, +}; /// has valid file attributes const FLAGS_FD_ATTRIBUTES: u32 = 0x04; @@ -30,7 +34,9 @@ const FLAGS_FD_UNIX_MODE: u32 = 0x08; #[derive(Debug)] pub(super) struct LocalFile { pub path: PathBuf, - pub handle: Option, + + pub handle: Option>, + pub offset: AtomicU64, pub name: String, pub size: u64, @@ -69,11 +75,13 @@ impl LocalFile { // NOTE: open files lazily let handle = None; + let offset = AtomicU64::new(0); Ok(Self { name, path: path.clone(), handle, + offset, size, last_write_time, is_dir, @@ -160,33 +168,47 @@ impl LocalFile { buf.to_vec() } - pub fn read_exact_at(&mut self, buf: &mut [u8], offset: u64) -> Result<(), CliprdrError> { - if self.handle.is_none() { + #[inline] + 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 { path: self.path.clone(), 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(); - handle - .seek(std::io::SeekFrom::Start(offset)) - .map_err(|e| CliprdrError::FileError { - path: self.path.clone(), - err: e, - })?; + if offset != self.offset.load(Ordering::Relaxed) { + handle + .seek(std::io::SeekFrom::Start(offset)) + .map_err(|e| CliprdrError::FileError { + path: self.path.clone(), + err: e, + })?; + } handle .read_exact(buf) .map_err(|e| CliprdrError::FileError { path: self.path.clone(), err: e, })?; - // gc - if offset + (buf.len() as u64) >= self.size { + let new_offset = offset + (buf.len() as u64); + self.offset.store(new_offset, Ordering::Relaxed); + + // gc file handle + if new_offset >= self.size { + self.offset.store(0, Ordering::Relaxed); self.handle = None; } + Ok(()) } } diff --git a/libs/clipboard/src/platform/linux/mod.rs b/libs/clipboard/src/platform/linux/mod.rs index f1f429946..38e85475b 100644 --- a/libs/clipboard/src/platform/linux/mod.rs +++ b/libs/clipboard/src/platform/linux/mod.rs @@ -190,7 +190,7 @@ impl ClipboardContext { ) -> Result<(), CliprdrError> { let mut file_list = self.local_files.lock(); - let file_contents_resp = match request { + let (file_idx, file_contents_resp) = match request { FileContentsRequest::Size { stream_id, file_idx, @@ -220,11 +220,14 @@ impl ClipboardContext { ); let size = file.size; - ClipboardFile::FileContentsResponse { - msg_flags: 0x1, - stream_id, - requested_data: size.to_le_bytes().to_vec(), - } + ( + file_idx, + ClipboardFile::FileContentsResponse { + msg_flags: 0x1, + stream_id, + requested_data: size.to_le_bytes().to_vec(), + }, + ) } FileContentsRequest::Range { stream_id, @@ -280,16 +283,26 @@ impl ClipboardContext { file.read_exact_at(&mut buf, offset)?; - ClipboardFile::FileContentsResponse { - msg_flags: 0x1, - stream_id, - requested_data: buf, - } + ( + file_idx, + ClipboardFile::FileContentsResponse { + msg_flags: 0x1, + stream_id, + requested_data: buf, + }, + ) } }; send_data(conn_id, file_contents_resp); 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(()) } }