refactor: update draft handling and improve benchmark structure
This commit is contained in:
@@ -3,7 +3,6 @@ use std::hint::black_box;
|
|||||||
use std::process;
|
use std::process;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
// 引入业务模型 & Draft 实现
|
|
||||||
use app_lib::config::IVerge;
|
use app_lib::config::IVerge;
|
||||||
use app_lib::utils::Draft as DraftNew;
|
use app_lib::utils::Draft as DraftNew;
|
||||||
|
|
||||||
@@ -17,108 +16,86 @@ fn make_draft() -> DraftNew<Box<IVerge>> {
|
|||||||
DraftNew::from(verge)
|
DraftNew::from(verge)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 基准:只读 data_ref(正式数据)
|
pub fn bench_draft(c: &mut Criterion) {
|
||||||
fn bench_data_ref(c: &mut Criterion) {
|
let rt = Runtime::new().unwrap_or_else(|e| {
|
||||||
c.bench_function("draft_data_ref", |b| {
|
eprintln!("Tokio runtime init failed: {e}");
|
||||||
b.iter(|| {
|
|
||||||
let draft = make_draft();
|
|
||||||
let data = draft.data_ref();
|
|
||||||
black_box(data.enable_auto_launch);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 基准:可写 data_mut(正式数据)
|
|
||||||
fn bench_data_mut(c: &mut Criterion) {
|
|
||||||
c.bench_function("draft_data_mut", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = make_draft();
|
|
||||||
let mut data = draft.data_mut();
|
|
||||||
data.enable_tun_mode = Some(true);
|
|
||||||
black_box(data.enable_tun_mode);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 基准:首次创建草稿(会触发 clone)
|
|
||||||
fn bench_draft_mut_first(c: &mut Criterion) {
|
|
||||||
c.bench_function("draft_draft_mut_first", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = make_draft();
|
|
||||||
let mut d = draft.draft_mut();
|
|
||||||
d.enable_auto_launch = Some(false);
|
|
||||||
black_box(d.enable_auto_launch);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 基准:重复 draft_mut(已存在草稿,不再 clone)
|
|
||||||
fn bench_draft_mut_existing(c: &mut Criterion) {
|
|
||||||
c.bench_function("draft_draft_mut_existing", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = make_draft();
|
|
||||||
{
|
|
||||||
let mut first = draft.draft_mut();
|
|
||||||
first.enable_tun_mode = Some(true);
|
|
||||||
}
|
|
||||||
let mut second = draft.draft_mut();
|
|
||||||
second.enable_tun_mode = Some(false);
|
|
||||||
black_box(second.enable_tun_mode);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 基准:零拷贝读取最新视图(latest_ref)
|
|
||||||
fn bench_latest_ref(c: &mut Criterion) {
|
|
||||||
c.bench_function("draft_latest_ref", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = make_draft();
|
|
||||||
let latest = draft.latest_ref();
|
|
||||||
black_box(latest.enable_auto_launch);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 基准:apply(提交草稿)
|
|
||||||
fn bench_apply(c: &mut Criterion) {
|
|
||||||
c.bench_function("draft_apply", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = make_draft();
|
|
||||||
{
|
|
||||||
let mut d = draft.draft_mut();
|
|
||||||
d.enable_auto_launch = Some(false);
|
|
||||||
}
|
|
||||||
let _ = draft.apply();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 基准:discard(丢弃草稿)
|
|
||||||
fn bench_discard(c: &mut Criterion) {
|
|
||||||
c.bench_function("draft_discard", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = make_draft();
|
|
||||||
{
|
|
||||||
let mut d = draft.draft_mut();
|
|
||||||
d.enable_auto_launch = Some(false);
|
|
||||||
}
|
|
||||||
let _ = draft.discard();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 基准:异步 with_data_modify
|
|
||||||
fn bench_with_data_modify(c: &mut Criterion) {
|
|
||||||
let rt = Runtime::new().unwrap_or_else(|error| {
|
|
||||||
eprintln!("draft benchmarks require a Tokio runtime: {error}");
|
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
c.bench_function("draft_with_data_modify", |b| {
|
let mut group = c.benchmark_group("draft");
|
||||||
|
group.sample_size(100);
|
||||||
|
group.warm_up_time(std::time::Duration::from_millis(300));
|
||||||
|
group.measurement_time(std::time::Duration::from_secs(1));
|
||||||
|
|
||||||
|
group.bench_function("data_mut", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let draft = black_box(make_draft());
|
||||||
|
let mut data = draft.data_mut();
|
||||||
|
data.enable_tun_mode = Some(true);
|
||||||
|
black_box(&data.enable_tun_mode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_function("draft_mut_first", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let draft = black_box(make_draft());
|
||||||
|
let mut d = draft.draft_mut();
|
||||||
|
d.enable_auto_launch = Some(false);
|
||||||
|
black_box(&d.enable_auto_launch);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_function("draft_mut_existing", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let draft = black_box(make_draft());
|
||||||
|
{
|
||||||
|
let mut first = draft.draft_mut();
|
||||||
|
first.enable_tun_mode = Some(true);
|
||||||
|
black_box(&first.enable_tun_mode);
|
||||||
|
}
|
||||||
|
let mut second = draft.draft_mut();
|
||||||
|
second.enable_tun_mode = Some(false);
|
||||||
|
black_box(&second.enable_tun_mode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_function("latest_ref", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let draft = black_box(make_draft());
|
||||||
|
let latest = draft.latest_ref();
|
||||||
|
black_box(&latest.enable_auto_launch);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_function("apply", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let draft = black_box(make_draft());
|
||||||
|
{
|
||||||
|
let mut d = draft.draft_mut();
|
||||||
|
d.enable_auto_launch = Some(false);
|
||||||
|
}
|
||||||
|
draft.apply();
|
||||||
|
black_box(&draft);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_function("discard", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let draft = black_box(make_draft());
|
||||||
|
{
|
||||||
|
let mut d = draft.draft_mut();
|
||||||
|
d.enable_auto_launch = Some(false);
|
||||||
|
}
|
||||||
|
draft.discard();
|
||||||
|
black_box(&draft);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_function("with_data_modify_async", |b| {
|
||||||
b.to_async(&rt).iter(|| async {
|
b.to_async(&rt).iter(|| async {
|
||||||
let draft = make_draft();
|
let draft = black_box(make_draft());
|
||||||
let _res: Result<(), anyhow::Error> = draft
|
let _: Result<(), anyhow::Error> = draft
|
||||||
.with_data_modify(|mut box_data| async move {
|
.with_data_modify::<_, _, _, anyhow::Error>(|mut box_data| async move {
|
||||||
box_data.enable_auto_launch =
|
box_data.enable_auto_launch =
|
||||||
Some(!box_data.enable_auto_launch.unwrap_or(false));
|
Some(!box_data.enable_auto_launch.unwrap_or(false));
|
||||||
Ok((box_data, ()))
|
Ok((box_data, ()))
|
||||||
@@ -126,17 +103,9 @@ fn bench_with_data_modify(c: &mut Criterion) {
|
|||||||
.await;
|
.await;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_group!(
|
criterion_group!(benches, bench_draft);
|
||||||
benches,
|
|
||||||
bench_data_ref,
|
|
||||||
bench_data_mut,
|
|
||||||
bench_draft_mut_first,
|
|
||||||
bench_draft_mut_existing,
|
|
||||||
bench_latest_ref,
|
|
||||||
bench_apply,
|
|
||||||
bench_discard,
|
|
||||||
bench_with_data_modify
|
|
||||||
);
|
|
||||||
criterion_main!(benches);
|
criterion_main!(benches);
|
||||||
|
|||||||
@@ -168,11 +168,11 @@ impl Config {
|
|||||||
pub async fn generate() -> Result<()> {
|
pub async fn generate() -> Result<()> {
|
||||||
let (config, exists_keys, logs) = enhance::enhance().await;
|
let (config, exists_keys, logs) = enhance::enhance().await;
|
||||||
|
|
||||||
*Config::runtime().await.draft_mut() = Box::new(IRuntime {
|
**Config::runtime().await.draft_mut() = IRuntime {
|
||||||
config: Some(config),
|
config: Some(config),
|
||||||
exists_keys,
|
exists_keys,
|
||||||
chain_logs: logs,
|
chain_logs: logs,
|
||||||
});
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::config::Config;
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{DEFAULT_PAC, deserialize_encrypted, serialize_encrypted},
|
config::{DEFAULT_PAC, deserialize_encrypted, serialize_encrypted},
|
||||||
logging,
|
logging,
|
||||||
@@ -304,19 +305,17 @@ impl IVerge {
|
|||||||
|
|
||||||
/// 配置修正后重新加载配置
|
/// 配置修正后重新加载配置
|
||||||
async fn reload_config_after_fix(updated_config: IVerge) -> Result<()> {
|
async fn reload_config_after_fix(updated_config: IVerge) -> Result<()> {
|
||||||
use crate::config::Config;
|
|
||||||
|
|
||||||
let config_draft = Config::verge().await;
|
|
||||||
*config_draft.draft_mut() = Box::new(updated_config.clone());
|
|
||||||
config_draft.apply();
|
|
||||||
|
|
||||||
logging!(
|
logging!(
|
||||||
info,
|
info,
|
||||||
Type::Config,
|
Type::Config,
|
||||||
"内存配置已强制更新,新的clash_core: {:?}",
|
"内存配置已强制更新,新的clash_core: {:?}",
|
||||||
updated_config.clash_core
|
&updated_config.clash_core
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let config_draft = Config::verge().await;
|
||||||
|
**config_draft.draft_mut() = updated_config;
|
||||||
|
config_draft.apply();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ impl CoreManager {
|
|||||||
let runtime_path = dirs::app_home_dir()?.join(RUNTIME_CONFIG);
|
let runtime_path = dirs::app_home_dir()?.join(RUNTIME_CONFIG);
|
||||||
let clash_config = Config::clash().await.latest_ref().0.clone();
|
let clash_config = Config::clash().await.latest_ref().0.clone();
|
||||||
|
|
||||||
*Config::runtime().await.draft_mut() = Box::new(IRuntime {
|
**Config::runtime().await.draft_mut() = IRuntime {
|
||||||
config: Some(clash_config.clone()),
|
config: Some(clash_config.clone()),
|
||||||
exists_keys: vec![],
|
exists_keys: vec![],
|
||||||
chain_logs: Default::default(),
|
chain_logs: Default::default(),
|
||||||
});
|
};
|
||||||
|
|
||||||
help::save_yaml(&runtime_path, &clash_config, Some("# Clash Verge Runtime")).await?;
|
help::save_yaml(&runtime_path, &clash_config, Some("# Clash Verge Runtime")).await?;
|
||||||
handle::Handle::notice_message(error_key, error_msg);
|
handle::Handle::notice_message(error_key, error_msg);
|
||||||
|
|||||||
@@ -419,13 +419,15 @@ impl Timer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get the profile updated timestamp - now safe to await
|
// Get the profile updated timestamp - now safe to await
|
||||||
let config_profiles = Config::profiles().await;
|
let items = {
|
||||||
let profiles = config_profiles.data_ref().clone();
|
let profiles = Config::profiles().await;
|
||||||
let items = match profiles.get_items() {
|
let profiles_guard = profiles.latest_ref();
|
||||||
Some(i) => i,
|
match profiles_guard.get_items() {
|
||||||
None => {
|
Some(i) => i.clone(),
|
||||||
logging!(warn, Type::Timer, "获取配置列表失败");
|
None => {
|
||||||
return None;
|
logging!(warn, Type::Timer, "获取配置列表失败");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ async fn perform_profile_update(
|
|||||||
let profile_name = item.name.clone().unwrap_or_else(|| uid.clone());
|
let profile_name = item.name.clone().unwrap_or_else(|| uid.clone());
|
||||||
handle::Handle::notice_message("update_with_clash_proxy", profile_name);
|
handle::Handle::notice_message("update_with_clash_proxy", profile_name);
|
||||||
|
|
||||||
let is_current = Some(uid.clone()) == profiles.data_ref().get_current();
|
let is_current = Some(uid.clone()) == profiles.latest_ref().get_current();
|
||||||
log::info!(target: "app", "[订阅更新] 是否为当前使用的订阅: {is_current}");
|
log::info!(target: "app", "[订阅更新] 是否为当前使用的订阅: {is_current}");
|
||||||
Ok(is_current)
|
Ok(is_current)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ pub async fn clean_async() -> bool {
|
|||||||
let tun_task = async {
|
let tun_task = async {
|
||||||
let tun_enabled = Config::verge()
|
let tun_enabled = Config::verge()
|
||||||
.await
|
.await
|
||||||
.data_ref()
|
.latest_ref()
|
||||||
.enable_tun_mode
|
.enable_tun_mode
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ impl<T: Clone + ToOwned> From<T> for Draft<T> {
|
|||||||
///
|
///
|
||||||
/// # Methods
|
/// # Methods
|
||||||
/// - `data_mut`: Returns a mutable reference to the committed data.
|
/// - `data_mut`: Returns a mutable reference to the committed data.
|
||||||
/// - `data_ref`: Returns an immutable reference to the committed data.
|
|
||||||
/// - `draft_mut`: Creates or retrieves a mutable reference to the draft data, cloning the committed data if no draft exists.
|
/// - `draft_mut`: Creates or retrieves a mutable reference to the draft data, cloning the committed data if no draft exists.
|
||||||
/// - `latest_ref`: Returns an immutable reference to the draft data if it exists, otherwise to the committed data.
|
/// - `latest_ref`: Returns an immutable reference to the draft data if it exists, otherwise to the committed data.
|
||||||
/// - `apply`: Commits the draft data, replacing the committed data and returning the old committed value if a draft existed.
|
/// - `apply`: Commits the draft data, replacing the committed data and returning the old committed value if a draft existed.
|
||||||
@@ -35,11 +34,6 @@ impl<T: Clone + ToOwned> Draft<Box<T>> {
|
|||||||
RwLockWriteGuard::map(self.inner.write(), |inner| &mut inner.0)
|
RwLockWriteGuard::map(self.inner.write(), |inner| &mut inner.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 返回正式数据的只读视图(不包含草稿)
|
|
||||||
pub fn data_ref(&self) -> MappedRwLockReadGuard<'_, Box<T>> {
|
|
||||||
RwLockReadGuard::map(self.inner.read(), |inner| &inner.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 创建或获取草稿并返回可写引用
|
/// 创建或获取草稿并返回可写引用
|
||||||
pub fn draft_mut(&self) -> MappedRwLockWriteGuard<'_, Box<T>> {
|
pub fn draft_mut(&self) -> MappedRwLockWriteGuard<'_, Box<T>> {
|
||||||
let guard = self.inner.upgradable_read();
|
let guard = self.inner.upgradable_read();
|
||||||
@@ -69,17 +63,21 @@ impl<T: Clone + ToOwned> Draft<Box<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 提交草稿,返回旧正式数据
|
/// 提交草稿,返回旧正式数据
|
||||||
pub fn apply(&self) -> Option<Box<T>> {
|
pub fn apply(&self) {
|
||||||
let mut inner = self.inner.write();
|
let guard = self.inner.upgradable_read();
|
||||||
inner
|
if guard.1.is_none() {
|
||||||
.1
|
return;
|
||||||
.take()
|
}
|
||||||
.map(|draft| std::mem::replace(&mut inner.0, draft))
|
|
||||||
|
let mut guard = RwLockUpgradableReadGuard::upgrade(guard);
|
||||||
|
if let Some(draft) = guard.1.take() {
|
||||||
|
guard.0 = draft;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 丢弃草稿,返回被丢弃的草稿
|
/// 丢弃草稿,返回被丢弃的草稿
|
||||||
pub fn discard(&self) -> Option<Box<T>> {
|
pub fn discard(&self) {
|
||||||
self.inner.write().1.take()
|
self.inner.write().1.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 异步修改正式数据,闭包直接获得 Box<T> 所有权
|
/// 异步修改正式数据,闭包直接获得 Box<T> 所有权
|
||||||
@@ -152,8 +150,7 @@ fn test_draft_box() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5. 提交草稿
|
// 5. 提交草稿
|
||||||
assert!(draft.apply().is_some()); // 第一次提交应有返回
|
draft.apply();
|
||||||
assert!(draft.apply().is_none()); // 第二次提交返回 None
|
|
||||||
|
|
||||||
// 正式数据已更新
|
// 正式数据已更新
|
||||||
{
|
{
|
||||||
@@ -170,8 +167,7 @@ fn test_draft_box() {
|
|||||||
assert_eq!(draft.draft_mut().enable_auto_launch, Some(true));
|
assert_eq!(draft.draft_mut().enable_auto_launch, Some(true));
|
||||||
|
|
||||||
// 7. 丢弃草稿
|
// 7. 丢弃草稿
|
||||||
assert!(draft.discard().is_some()); // 第一次丢弃返回 Some
|
draft.discard();
|
||||||
assert!(draft.discard().is_none()); // 再次丢弃返回 None
|
|
||||||
|
|
||||||
// 8. 草稿已被丢弃,新的 draft_mut() 会重新 clone
|
// 8. 草稿已被丢弃,新的 draft_mut() 会重新 clone
|
||||||
assert_eq!(draft.draft_mut().enable_auto_launch, Some(false));
|
assert_eq!(draft.draft_mut().enable_auto_launch, Some(false));
|
||||||
|
|||||||
Reference in New Issue
Block a user