feat: implement draft management system for concurrent editing and committing of data

This commit is contained in:
Tunglies
2025-10-15 08:32:30 +08:00
parent 6113be3b6c
commit e6b7d512fb
9 changed files with 127 additions and 68 deletions

1
src-tauri/Cargo.lock generated
View File

@@ -1470,6 +1470,7 @@ dependencies = [
"serde",
"serde_json",
"tinytemplate",
"tokio",
"walkdir",
]

View File

@@ -128,6 +128,11 @@ tauri-dev = []
tokio-trace = ["console-subscriber"]
clippy = ["tauri/test"]
[[bench]]
name = "draft_benchmark"
path = "benches/draft_benchmark.rs"
harness = false
[profile.release]
panic = "abort"
codegen-units = 16
@@ -162,7 +167,7 @@ name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[dev-dependencies]
criterion = "0.7.0"
criterion = { version = "0.7.0", features = ["async_tokio"] }
[lints.clippy]
# Core categories - most important for code safety and correctness

View File

@@ -1,91 +1,138 @@
use criterion::{Criterion, criterion_group, criterion_main};
use std::hint::black_box;
use tokio::runtime::Runtime;
// 业务模型 & Draft
use app_lib::config::Draft as DraftNew;
// 引入业务模型 & Draft 实现
use app_lib::config::IVerge;
use app_lib::utils::Draft as DraftNew;
// fn bench_apply_old(c: &mut Criterion) {
// c.bench_function("apply_draft_old", |b| {
// b.iter(|| {
// let verge = Box::new(IVerge {
// enable_auto_launch: Some(true),
// enable_tun_mode: Some(false),
// ..Default::default()
// });
/// 创建测试数据
fn make_draft() -> DraftNew<Box<IVerge>> {
let verge = Box::new(IVerge {
enable_auto_launch: Some(true),
enable_tun_mode: Some(false),
..Default::default()
});
DraftNew::from(verge)
}
// let draft = DraftOld::from(black_box(verge));
// {
// let mut d = draft.draft_mut();
// d.enable_auto_launch = Some(false);
// }
// let _ = draft.apply();
// });
// });
// }
// fn bench_discard_old(c: &mut Criterion) {
// c.bench_function("discard_draft_old", |b| {
// b.iter(|| {
// let verge = Box::new(IVerge::default());
// let draft = DraftOld::from(black_box(verge));
// {
// let mut d = draft.draft_mut();
// d.enable_auto_launch = Some(false);
// }
// let _ = draft.discard();
// });
// });
// }
/// 基准:修改草稿并 apply()
fn bench_apply_new(c: &mut Criterion) {
c.bench_function("apply_draft_new", |b| {
/// 基准:只读 data_ref正式数据
fn bench_data_ref(c: &mut Criterion) {
c.bench_function("draft_data_ref", |b| {
b.iter(|| {
let verge = Box::new(IVerge {
enable_auto_launch: Some(true),
enable_tun_mode: Some(false),
..Default::default()
});
let draft = make_draft();
let data = draft.data_ref();
black_box(data.enable_auto_launch);
});
});
}
let draft = DraftNew::from(black_box(verge));
/// 基准:可写 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_new(c: &mut Criterion) {
c.bench_function("discard_draft_new", |b| {
/// 基准discard(丢弃草稿)
fn bench_discard(c: &mut Criterion) {
c.bench_function("draft_discard", |b| {
b.iter(|| {
let verge = Box::new(IVerge::default());
let draft = DraftNew::from(black_box(verge));
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();
c.bench_function("draft_with_data_modify", |b| {
b.to_async(&rt).iter(|| async {
let draft = make_draft();
let _res: Result<(), anyhow::Error> = draft
.with_data_modify(|mut box_data| async move {
box_data.enable_auto_launch =
Some(!box_data.enable_auto_launch.unwrap_or(false));
Ok((box_data, ()))
})
.await;
});
});
}
criterion_group!(
benches,
// bench_apply_old,
// bench_discard_old,
bench_apply_new,
bench_discard_new
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);

View File

@@ -1,9 +1,9 @@
use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge};
use super::{IClashTemp, IProfiles, IRuntime, IVerge};
use crate::{
config::{PrfItem, profiles_append_item_safe},
core::{CoreManager, handle},
enhance, logging,
utils::{dirs, help, logging::Type},
utils::{Draft, dirs, help, logging::Type},
};
use anyhow::{Result, anyhow};
use backoff::{Error as BackoffError, ExponentialBackoff};

View File

@@ -1,16 +1,13 @@
mod clash;
#[allow(clippy::module_inception)]
mod config;
mod draft;
mod encrypt;
mod prfitem;
pub mod profiles;
mod runtime;
mod verge;
pub use self::{
clash::*, config::*, draft::*, encrypt::*, prfitem::*, profiles::*, runtime::*, verge::*,
};
pub use self::{clash::*, config::*, encrypt::*, prfitem::*, profiles::*, runtime::*, verge::*};
pub const DEFAULT_PAC: &str = r#"function FindProxyForURL(url, host) {
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;";

View File

@@ -8,7 +8,7 @@ mod enhance;
mod feat;
mod module;
mod process;
mod utils;
pub mod utils;
#[cfg(target_os = "macos")]
use crate::utils::window_manager::WindowManager;
use crate::{

View File

@@ -109,7 +109,7 @@ impl<T: Clone + ToOwned> Draft<Box<T>> {
#[test]
fn test_draft_box() {
use super::IVerge;
use crate::config::IVerge;
// 1. 创建 Draft<Box<IVerge>>
let verge = Box::new(IVerge {

View File

@@ -1,5 +1,6 @@
pub mod autostart;
pub mod dirs;
pub mod draft;
pub mod format;
pub mod help;
pub mod i18n;
@@ -12,3 +13,5 @@ pub mod server;
pub mod singleton;
pub mod tmpl;
pub mod window_manager;
pub use draft::Draft;

View File

@@ -61,6 +61,12 @@ pub struct NetworkManager {
connection_error_count: Mutex<usize>,
}
impl Default for NetworkManager {
fn default() -> Self {
Self::new()
}
}
impl NetworkManager {
pub fn new() -> Self {
Self {