Initial Dever 0.0.1

This commit is contained in:
Codex committed 2026-11-03 03:32:07 +00:00
commit 81233d098c
1479 files changed
+163782

No files matched your search

+277
View File
@@ -0,0 +1,277 @@
// 两侧共享 SQLite、连接池、截止时间与 worker,单独测量 Dever 生成层的额外成本。
// 不把此比较当成未经资源约束的同步 rusqlite、HTTP 吞吐或整个 core 的验收。
use dever_runtime::{
database::{Context, Id as ModelId, Parameter, Registry},
task::{Limits, Runtime, Scope},
time::calendar::DateTime,
value::uuid::Uuid,
};
use std::{hint::black_box, path::PathBuf, sync::Arc, time::Instant};
struct Directory(PathBuf);
impl Drop for Directory {
fn drop(&mut self) {
std::fs::remove_dir_all(&self.0).unwrap();
}
}
async fn rust_count(context: &mut Context, scope: &Scope<'_>) -> i64 {
context
.on(0, scope)
.await
.unwrap()
.query(
scope,
"SELECT COUNT(*) FROM \"demo_account_model\"",
vec![],
1,
|row| Ok(row.get::<_, i64>(0)?),
)
.await
.unwrap()
.pop()
.unwrap()
}
struct RustAccount {
id: ModelId<0>,
created_at: DateTime,
name: String,
note: Option<String>,
uid: Uuid,
rank: i64,
}
async fn rust_row(
context: &mut Context,
scope: &Scope<'_>,
update: bool,
) -> Result<RustAccount, dever_runtime::database::Error> {
let (sql, parameters) = if update {
(
"UPDATE \"demo_account_model\" SET \"name\" = ?2 WHERE id = ?1 RETURNING \"id\",\"created_at\",\"name\",\"note\",\"uid\",\"rank\"",
vec![
Parameter::Integer(1),
Parameter::Text("benchmark 中文".into()),
],
)
} else {
(
"SELECT \"id\",\"created_at\",\"name\",\"note\",\"uid\",\"rank\" FROM \"demo_account_model\" WHERE id = ?1",
vec![Parameter::Integer(1)],
)
};
let sql = dever_runtime::database::Sql {
sqlite: sql,
postgres: if update {
"UPDATE \"demo_account_model\" SET \"name\" = $2 WHERE id = $1 RETURNING \"id\",\"created_at\",\"name\",\"note\",\"uid\",\"rank\""
} else {
"SELECT \"id\",\"created_at\",\"name\",\"note\",\"uid\",\"rank\" FROM \"demo_account_model\" WHERE id = $1"
},
};
context
.on(0, scope)
.await?
.query(scope, sql, parameters, 1, |row| {
Ok(RustAccount {
id: ModelId(row.get::<_, i64>(0)?),
created_at: DateTime::from_millis(row.get::<_, i64>(1)?).map_err(|_| {
dever_runtime::database::Error::new(
dever_runtime::database::Kind::InvalidData,
"invalid stored DateTime",
)
})?,
name: row.get::<_, String>(2)?,
note: row.get::<_, Option<String>>(3)?,
uid: dever_runtime::database::scalar::uuid(row, 4)?,
rank: row.get::<_, i64>(5)?,
})
})
.await?
.pop()
.ok_or_else(|| {
dever_runtime::database::Error::new(
dever_runtime::database::Kind::NotFound,
"account was not found",
)
})
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Case {
Count,
Read,
Update,
}
fn measure(
runtime: &Runtime,
registry: &Arc<Registry>,
generated: bool,
case: Case,
count: usize,
) -> (u128, i64) {
let mut context = Context::new(registry.clone());
runtime
.run(async |scope| {
let mut checksum = 0i64;
let start = Instant::now();
for _ in 0..count {
let value = if case != Case::Count {
let owner = (case == Case::Update).then(|| context.enter());
let row = if generated {
let value = if case == Case::Update {
GENERATED_UPDATE(
dever_runtime::database::Id(1),
"benchmark 中文",
scope,
&mut context,
)
.await
.unwrap()
} else {
GENERATED_READ(dever_runtime::database::Id(1), scope, &mut context)
.await
.unwrap()
};
RustAccount {
id: value.field0,
created_at: value.field1,
name: value.field2,
note: value.field3,
uid: value.field4,
rank: value.field5,
}
} else {
rust_row(&mut context, scope, case == Case::Update)
.await
.unwrap()
};
if let Some(owner) = owner {
context.finish(scope, owner, true).await.unwrap();
}
// 两侧都把完整记录交给调用者,不在 worker 内提前丢字段。
let row = black_box(&row);
assert_eq!(row.name, "benchmark 中文");
assert!(row.note.is_none());
row.id.0 + row.name.len() as i64
} else if generated {
GENERATED_COUNT(scope, &mut context).await.unwrap()
} else {
rust_count(&mut context, scope).await
};
checksum += black_box(value);
}
(start.elapsed().as_nanos(), checksum)
})
.unwrap()
}
fn main() {
let unique = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
let relative = format!("database-benchmark-{}-{unique}", std::process::id());
let directory = Directory(
std::env::current_exe()
.unwrap()
.parent()
.unwrap()
.join(&relative),
);
std::fs::create_dir(&directory.0).unwrap();
let settings = directory.0.join("setting.json");
let runtime = Runtime::new(Limits {
threads: 1,
workers: 1,
tasks: 16,
})
.unwrap();
let schema = database_settings(&runtime, &directory.0, &settings, &relative);
let registry = runtime
.run(async |scope| database_registry(&settings, scope).await)
.unwrap()
.unwrap();
runtime
.run(async |scope| {
let mut context = Context::new(registry.clone());
let created = GENERATED_CREATE("benchmark 中文", scope, &mut context)
.await
.unwrap();
assert_eq!(created.field0.0, 1);
assert_eq!(
GENERATED_COUNT(scope, &mut context).await.unwrap(),
rust_count(&mut context, scope).await
);
let expected = (
created.field0,
created.field1,
created.field2,
created.field3,
created.field4,
created.field5,
);
let read = GENERATED_READ(ModelId(1), scope, &mut context)
.await
.unwrap();
assert_eq!(
(
read.field0,
read.field1,
read.field2,
read.field3,
read.field4,
read.field5
),
expected
);
let read = rust_row(&mut context, scope, false).await.unwrap();
assert_eq!(
(
read.id,
read.created_at,
read.name,
read.note,
read.uid,
read.rank
),
expected
);
})
.unwrap();
println!("case,sample,implementation,nanoseconds,checksum");
for (name, case) in [
("database_count", Case::Count),
("database_get", Case::Read),
("database_update_commit", Case::Update),
] {
if let Ok(selected) = std::env::var("DEVER_BENCH_CASES")
&& !selected.split(',').any(|item| item == name)
{
continue;
}
for generated in [true, false] {
black_box(measure(&runtime, &registry, generated, case, 200));
}
for sample in 0..15 {
let mut order = [("dever", true), ("rust", false), ("control", true)];
order.rotate_left(sample % 3);
let mut expected = None;
for (implementation, generated) in order {
let (elapsed, checksum) = measure(&runtime, &registry, generated, case, 2000);
if let Some(expected) = expected {
assert_eq!(checksum, expected);
}
expected = Some(checksum);
println!("{name},{sample},{implementation},{elapsed},{checksum}");
}
}
}
drop(registry);
if let Some(schema) = schema {
schema.close(&runtime);
}
drop(runtime);
drop(directory);
}