perf: precache small images to avoid cache misses; use symlink_metadata instead of metadata (#367)

This commit is contained in:
三咲雅 · Misaki Masa 2023-11-15 08:47:55 +08:00 committed by GitHub
parent 5968b82b0e
commit ff30b244b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 16 additions and 30 deletions

View file

@ -170,7 +170,7 @@ impl Adaptor {
pub async fn image_show(self, mut path: &Path, rect: Rect) -> Result<()> {
let cache = PREVIEW.cache(path, 0);
if fs::metadata(&cache).await.is_ok() {
if fs::symlink_metadata(&cache).await.is_ok() {
path = cache.as_path();
}

View file

@ -9,7 +9,7 @@ use yazi_shared::Term;
pub struct Image;
impl Image {
pub(super) async fn crop(path: &Path, size: (u16, u16)) -> Result<DynamicImage> {
pub(super) async fn downscale(path: &Path, size: (u16, u16)) -> Result<DynamicImage> {
let (w, h) = Term::ratio()
.map(|(w, h)| {
let (w, h) = ((size.0 as f64 * w) as u32, (size.1 as f64 * h) as u32);
@ -30,33 +30,19 @@ impl Image {
img.await?
}
pub async fn precache(img: Arc<Vec<u8>>, cache: impl AsRef<Path>) -> Result<bool> {
pub async fn precache(img: Arc<Vec<u8>>, cache: impl AsRef<Path>) -> Result<()> {
let cache = cache.as_ref().to_owned();
let result = tokio::task::spawn_blocking(move || {
let img = image::load_from_memory(&img)?;
let (w, h) = (PREVIEW.max_width, PREVIEW.max_height);
if img.width() <= w && img.height() <= h {
return Ok(false);
}
match img.resize(w, h, FilterType::Triangle) {
Ok(match img.resize(w, h, FilterType::Triangle) {
DynamicImage::ImageRgb8(buf) => buf.save_with_format(cache, ImageFormat::Jpeg),
DynamicImage::ImageRgba8(buf) => buf.save_with_format(cache, ImageFormat::Jpeg),
buf => buf.to_rgb8().save_with_format(cache, ImageFormat::Jpeg),
}?;
Ok(true)
}?)
});
result.await?
}
#[inline]
pub async fn precache_anyway(img: Arc<Vec<u8>>, cache: impl AsRef<Path>) -> Result<()> {
Ok(match Self::precache(img.clone(), &cache).await {
Ok(true) => (),
_ => fs::write(cache, &*img).await?,
})
}
}

View file

@ -13,7 +13,7 @@ pub(super) struct Iterm2;
impl Iterm2 {
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> {
let img = Image::crop(path, (rect.width, rect.height)).await?;
let img = Image::downscale(path, (rect.width, rect.height)).await?;
let b = Self::encode(img).await?;
Self::image_hide(rect)?;

View file

@ -313,7 +313,7 @@ pub(super) struct Kitty;
impl Kitty {
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> {
let img = Image::crop(path, (rect.width, rect.height)).await?;
let img = Image::downscale(path, (rect.width, rect.height)).await?;
let b = Self::encode(img).await?;
Self::image_hide(rect)?;

View file

@ -13,7 +13,7 @@ pub(super) struct KittyOld;
impl KittyOld {
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> {
let img = Image::crop(path, (rect.width, rect.height)).await?;
let img = Image::downscale(path, (rect.width, rect.height)).await?;
let b = Self::encode(img).await?;
Self::image_hide()?;

View file

@ -12,7 +12,7 @@ pub(super) struct Sixel;
impl Sixel {
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> {
let img = Image::crop(path, (rect.width, rect.height)).await?;
let img = Image::downscale(path, (rect.width, rect.height)).await?;
let b = Self::encode(img).await?;
Self::image_hide(rect)?;

View file

@ -25,5 +25,5 @@ pub async fn pdftoppm(src: &Path, dest: impl AsRef<Path>, skip: usize) -> Result
return if pages > 0 { Err(PeekError::Exceed(pages - 1)) } else { Err(s.to_string().into()) };
}
Ok(Image::precache_anyway(Arc::new(output.stdout), dest).await?)
Ok(Image::precache(Arc::new(output.stdout), dest).await?)
}

View file

@ -144,7 +144,7 @@ impl Manager {
let mut failed = Vec::new();
for (o, n) in todo {
if fs::metadata(&n).await.is_ok() {
if fs::symlink_metadata(&n).await.is_ok() {
failed.push((o, n, anyhow!("Destination already exists")));
continue;
}

View file

@ -48,7 +48,7 @@ impl Provider {
pub(super) async fn video(path: &Path, skip: usize) -> Result<PreviewData, PeekError> {
let cache = PREVIEW.cache(path, skip);
if fs::metadata(&cache).await.is_err() {
if fs::symlink_metadata(&cache).await.is_err() {
external::ffmpegthumbnailer(path, &cache, skip).await?;
}
@ -57,7 +57,7 @@ impl Provider {
pub(super) async fn pdf(path: &Path, skip: usize) -> Result<PreviewData, PeekError> {
let cache = PREVIEW.cache(path, skip);
if fs::metadata(&cache).await.is_err() {
if fs::symlink_metadata(&cache).await.is_err() {
external::pdftoppm(path, &cache, skip).await?;
}

View file

@ -75,7 +75,7 @@ impl Precache {
match task {
PrecacheOp::Image(task) => {
let cache = PREVIEW.cache(&task.target, 0);
if fs::metadata(&cache).await.is_ok() {
if fs::symlink_metadata(&cache).await.is_ok() {
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
}
if let Ok(img) = fs::read(&task.target).await {
@ -85,7 +85,7 @@ impl Precache {
}
PrecacheOp::Video(task) => {
let cache = PREVIEW.cache(&task.target, 0);
if fs::metadata(&cache).await.is_ok() {
if fs::symlink_metadata(&cache).await.is_ok() {
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
}
@ -94,7 +94,7 @@ impl Precache {
}
PrecacheOp::Pdf(task) => {
let cache = PREVIEW.cache(&task.target, 0);
if fs::metadata(&cache).await.is_ok() {
if fs::symlink_metadata(&cache).await.is_ok() {
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
}