perf: lazy compile and cache lua plugins as binary bytecode (#2490)

This commit is contained in:
三咲雅 · Misaki Masa 2025-03-17 16:12:43 +08:00 committed by GitHub
parent 8b3ce1838a
commit c5808a0db4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 54 additions and 48 deletions

View file

@ -4,7 +4,7 @@ const RE_DEPENDENCIES = /Dependencies\s+[/a-z]+\s*:\s/gm
const RE_CHECKLIST = /#{3}\s+Checklist\s+(?:^-\s+\[x]\s+.+?(?:\n|\r\n|$)){2}/gm
function bugReportBody(creator, content, hash) {
if (RE_CHECKLIST.test(content) && new RegExp(` \\(${hash}[a-z]? `).test(content)) {
if (RE_DEPENDENCIES.test(content) && RE_CHECKLIST.test(content) && new RegExp(` \\(${hash}[a-z]? `).test(content)) {
return null
}

View file

@ -14,7 +14,7 @@ pub(super) struct Logs;
impl Logs {
pub(super) fn start() -> anyhow::Result<()> {
let level = LOG_LEVEL.get();
if LOG_LEVEL.get().is_none() {
if level.is_none() {
return Ok(());
}

View file

@ -1,4 +1,4 @@
use mlua::{ExternalError, ExternalResult, ObjectLike, Table};
use mlua::{ExternalResult, ObjectLike};
use tokio::runtime::Handle;
use yazi_dds::Sendable;
use yazi_proxy::options::PluginOpt;
@ -11,14 +11,9 @@ pub async fn entry(opt: PluginOpt) -> mlua::Result<()> {
tokio::task::spawn_blocking(move || {
let lua = slim_lua(&opt.id)?;
let plugin: Table = if let Some(c) = LOADER.read().get(opt.id.as_ref()) {
lua.load(c.as_bytes()).set_name(opt.id.as_ref()).call(())?
} else {
return Err("unloaded plugin".into_lua_err());
};
let plugin = LOADER.load_once(&lua, &opt.id)?;
let job = lua.create_table_from([("args", Sendable::args_to_table(&lua, opt.args)?)])?;
Handle::current().block_on(plugin.call_async_method("entry", job))
})
.await

View file

@ -1,4 +1,4 @@
use mlua::{ExternalError, ExternalResult, FromLua, IntoLua, Lua, ObjectLike, Table, Value};
use mlua::{ExternalResult, FromLua, IntoLua, Lua, ObjectLike, Value};
use tokio::runtime::Handle;
use yazi_dds::Sendable;
use yazi_shared::event::CmdCow;
@ -17,11 +17,7 @@ pub async fn fetch(
tokio::task::spawn_blocking(move || {
let lua = slim_lua(&cmd.name)?;
let plugin: Table = if let Some(c) = LOADER.read().get(&cmd.name) {
lua.load(c.as_bytes()).set_name(&cmd.name).call(())?
} else {
return Err("unloaded plugin".into_lua_err());
};
let plugin = LOADER.load_once(&lua, &cmd.name)?;
Handle::current().block_on(plugin.call_async_method(
"fetch",

View file

@ -1,6 +1,6 @@
use std::borrow::Cow;
use mlua::{ExternalError, HookTriggers, IntoLua, ObjectLike, Table, VmState};
use mlua::{ExternalError, HookTriggers, IntoLua, ObjectLike, VmState};
use tokio::{runtime::Handle, select};
use tokio_util::sync::CancellationToken;
use tracing::error;
@ -84,12 +84,7 @@ fn peek_async(
},
);
let plugin: Table = if let Some(c) = LOADER.read().get(&cmd.name) {
lua.load(c.as_bytes()).set_name(&cmd.name).call(())?
} else {
return Err("unloaded plugin".into_lua_err());
};
let plugin = LOADER.load_once(&lua, &cmd.name)?;
let job = lua.create_table_from([
("area", Rect::from(LAYOUT.get().preview).into_lua(&lua)?),
("args", Sendable::args_to_table_ref(&lua, &cmd.args)?.into_lua(&lua)?),

View file

@ -1,4 +1,4 @@
use mlua::{ExternalError, ExternalResult, IntoLua, ObjectLike, Table};
use mlua::{ExternalResult, IntoLua, ObjectLike};
use tokio::runtime::Handle;
use yazi_config::LAYOUT;
use yazi_dds::Sendable;
@ -15,11 +15,7 @@ pub async fn preload(
tokio::task::spawn_blocking(move || {
let lua = slim_lua(&cmd.name)?;
let plugin: Table = if let Some(b) = LOADER.read().get(&cmd.name) {
lua.load(b.as_bytes()).set_name(&cmd.name).call(())?
} else {
return Err("unloaded plugin".into_lua_err());
};
let plugin = LOADER.load_once(&lua, &cmd.name)?;
let job = lua.create_table_from([
("area", Rect::from(LAYOUT.get().preview).into_lua(&lua)?),

View file

@ -1,6 +1,6 @@
use std::borrow::Cow;
use mlua::{ExternalError, ExternalResult, HookTriggers, IntoLua, ObjectLike, Table, VmState};
use mlua::{ExternalError, ExternalResult, HookTriggers, IntoLua, ObjectLike, VmState};
use tokio::{runtime::Handle, select};
use tokio_util::sync::CancellationToken;
use tracing::error;
@ -35,18 +35,14 @@ pub fn spot(
},
);
let plugin: Table = if let Some(b) = LOADER.read().get(&cmd.name) {
lua.load(b.as_bytes()).set_name(&cmd.name).call(())?
} else {
return Err("unloaded plugin".into_lua_err());
};
let plugin = LOADER.load_once(&lua, &cmd.name)?;
let job = lua.create_table_from([
("args", Sendable::args_to_table_ref(&lua, &cmd.args)?.into_lua(&lua)?),
("file", File(file).into_lua(&lua)?),
("mime", mime.into_lua(&lua)?),
("skip", skip.into_lua(&lua)?),
])?;
if ct2.is_cancelled() { Ok(()) } else { plugin.call_async_method("spot", job).await }
};

View file

@ -1,8 +1,10 @@
use std::borrow::Cow;
use mlua::{AsChunk, ChunkMode};
use yazi_shared::natsort;
pub struct Chunk {
pub mode: ChunkMode,
pub bytes: Cow<'static, [u8]>,
pub since: String,
pub sync_peek: bool,
@ -10,9 +12,6 @@ pub struct Chunk {
}
impl Chunk {
#[inline]
pub fn as_bytes(&self) -> &[u8] { &self.bytes }
#[inline]
pub fn compatible(&self) -> bool {
let s = yazi_boot::actions::Actions::version();
@ -46,8 +45,13 @@ impl Chunk {
impl From<Cow<'static, [u8]>> for Chunk {
fn from(b: Cow<'static, [u8]>) -> Self {
let mut chunk =
Self { bytes: b, since: String::new(), sync_entry: false, sync_peek: false };
let mut chunk = Self {
mode: ChunkMode::Text,
bytes: b,
since: String::new(),
sync_entry: false,
sync_peek: false,
};
chunk.analyze();
chunk
}
@ -60,3 +64,9 @@ impl From<&'static [u8]> for Chunk {
impl From<Vec<u8>> for Chunk {
fn from(b: Vec<u8>) -> Self { Self::from(Cow::Owned(b)) }
}
impl<'a> AsChunk<'a> for &'a Chunk {
fn source(self) -> std::io::Result<Cow<'a, [u8]>> { Ok(Cow::Borrowed(&self.bytes)) }
fn mode(&self) -> Option<ChunkMode> { Some(self.mode) }
}

View file

@ -1,7 +1,7 @@
use std::{collections::HashMap, ops::Deref};
use std::{borrow::Cow, collections::HashMap, ops::Deref};
use anyhow::{Context, Result, bail};
use mlua::{ExternalError, Lua, Table};
use mlua::{ChunkMode, ExternalError, Lua, Table};
use parking_lot::RwLock;
use tokio::fs;
use yazi_boot::BOOT;
@ -75,16 +75,34 @@ impl Loader {
return Ok(t);
}
let t: Table = match self.read().get(id) {
Some(c) => lua.load(c.as_bytes()).set_name(id).call(())?,
None => Err(format!("plugin `{id}` not found").into_lua_err())?,
};
let t = self.load_once(lua, id)?;
t.raw_set("_id", lua.create_string(id)?)?;
loaded.raw_set(id, t.clone())?;
Ok(t)
}
pub fn load_once(&self, lua: &Lua, id: &str) -> mlua::Result<Table> {
let mut mode = ChunkMode::Text;
let f = match self.read().get(id) {
Some(c) => {
mode = c.mode;
lua.load(c).set_name(id).into_function()
}
None => Err(format!("plugin `{id}` not found").into_lua_err()),
}?;
if mode != ChunkMode::Binary {
let b = f.dump(true);
if let Some(c) = self.write().get_mut(id) {
c.mode = ChunkMode::Binary;
c.bytes = Cow::Owned(b);
}
}
f.call(())
}
pub fn try_load(&self, lua: &Lua, id: &str) -> mlua::Result<Table> {
lua.globals().raw_get::<Table>("package")?.raw_get::<Table>("loaded")?.raw_get(id)
}
@ -95,7 +113,7 @@ impl Loader {
return Ok(t);
}
let t: Table = lua.load(chunk.as_bytes()).set_name(id).call(())?;
let t: Table = lua.load(chunk).set_name(id).call(())?;
t.raw_set("_id", lua.create_string(id)?)?;
loaded.raw_set(id, t.clone())?;