fix: 使用非阻塞锁获取

This commit is contained in:
imeepos 2025-07-15 18:20:00 +08:00
parent 6dcbd4a6e1
commit 86eeb90fb8
3 changed files with 51 additions and 113 deletions

View File

@ -26,43 +26,40 @@ impl MaterialRepository {
let scene_detection_json = material.scene_detection.as_ref()
.map(|sd| serde_json::to_string(sd))
.transpose()?;
let material_type_json = serde_json::to_string(&material.material_type)?;
let processing_status_json = serde_json::to_string(&material.processing_status)?;
self.database.with_connection(|conn| {
// 添加调试日志
println!("Creating material with model_id: {:?}", material.model_id);
// 添加调试日志
println!("Creating material with model_id: {:?}", material.model_id);
conn.execute(
"INSERT INTO materials (
id, project_id, model_id, name, original_path, file_size, md5_hash,
material_type, processing_status, metadata, scene_detection,
created_at, updated_at, processed_at, error_message
) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)",
(
&material.id,
&material.project_id,
&material.model_id,
&material.name,
&material.original_path,
material.file_size as i64,
&material.md5_hash,
&material_type_json,
&processing_status_json,
&metadata_json,
scene_detection_json.as_deref(),
material.created_at.to_rfc3339(),
material.updated_at.to_rfc3339(),
material.processed_at.map(|dt| dt.to_rfc3339()),
&material.error_message,
),
)?;
let metadata_json = serde_json::to_string(&material.metadata)?;
let scene_detection_json = material.scene_detection.as_ref()
.map(|sd| serde_json::to_string(sd))
.transpose()?;
conn.execute(
"INSERT INTO materials (
id, project_id, model_id, name, original_path, file_size, md5_hash,
material_type, processing_status, metadata, scene_detection,
created_at, updated_at, processed_at, error_message
) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)",
(
&material.id,
&material.project_id,
&material.model_id,
&material.name,
&material.original_path,
material.file_size as i64,
&material.md5_hash,
serde_json::to_string(&material.material_type)?,
serde_json::to_string(&material.processing_status)?,
metadata_json,
scene_detection_json,
material.created_at.to_rfc3339(),
material.updated_at.to_rfc3339(),
material.processed_at.map(|dt| dt.to_rfc3339()),
&material.error_message,
),
)?;
Ok(())
Ok(())
}).map_err(|e| anyhow::anyhow!("创建素材失败: {}", e))
}
/// 根据ID获取素材

View File

@ -373,90 +373,22 @@ impl ModelRepository {
}
/// 获取模特照片
/// 使用带超时的数据库访问模式,避免无限等待
/// 使用非阻塞数据库访问模式,避免无限等待
pub fn get_photos(&self, model_id: &str) -> Result<Vec<ModelPhoto>> {
println!("get_photos 开始执行model_id: {}", model_id);
// 直接使用简化的实现,避免复杂的超时逻辑
let result = self.get_photos_simple(model_id);
match &result {
Ok(photos) => println!("get_photos 执行完成,返回 {} 张照片", photos.len()),
Err(e) => eprintln!("get_photos 执行失败: {}", e),
}
result
}
/// 简化的获取照片实现
fn get_photos_simple(&self, model_id: &str) -> Result<Vec<ModelPhoto>> {
println!("get_photos_simple 开始获取数据库连接");
// 直接获取连接,但添加详细日志
let conn_arc = self.database.get_connection();
println!("get_photos_simple 获取连接引用成功");
// 使用阻塞方式获取锁,但添加超时检测
let conn = match conn_arc.lock() {
Ok(conn) => {
println!("get_photos_simple 成功获取数据库连接锁");
conn
// 使用非阻塞方式获取连接
match self.database.try_get_connection() {
Some(conn) => {
println!("get_photos 成功获取数据库连接锁(非阻塞)");
let photos = self.execute_photo_query(&conn, model_id)?;
println!("get_photos 执行完成,返回 {} 张照片", photos.len());
Ok(photos)
},
Err(e) => {
eprintln!("get_photos_simple 获取数据库连接锁失败: {}", e);
return Err(rusqlite::Error::SqliteFailure(
rusqlite::ffi::Error::new(rusqlite::ffi::SQLITE_BUSY),
Some("数据库连接锁获取失败".to_string()),
));
}
};
println!("get_photos_simple 开始执行查询");
self.execute_photo_query(&conn, model_id)
}
/// 带超时的获取照片实现
fn get_photos_with_timeout(&self, model_id: &str) -> Result<Vec<ModelPhoto>> {
use std::time::{Duration, Instant};
let start_time = Instant::now();
let timeout = Duration::from_secs(10); // 10秒超时
let mut retry_count = 0;
// 获取连接引用,避免生命周期问题
let conn_arc = self.database.get_connection();
loop {
println!("get_photos 尝试获取数据库连接,重试次数: {}", retry_count);
// 尝试获取锁
match conn_arc.try_lock() {
Ok(conn) => {
println!("get_photos 成功获取数据库连接");
// 成功获取锁,执行查询
let result = self.execute_photo_query(&conn, model_id);
// 返回结果
return result;
},
Err(_) => {
println!("get_photos 数据库连接被占用,重试中...");
// 检查是否超时
if start_time.elapsed() >= timeout {
eprintln!("get_photos 获取数据库连接超时,已等待 {:?}", start_time.elapsed());
return Err(rusqlite::Error::SqliteFailure(
rusqlite::ffi::Error::new(rusqlite::ffi::SQLITE_BUSY),
Some(format!("数据库连接获取超时,已重试 {}", retry_count)),
));
}
// 等待一段时间后重试
retry_count += 1;
let wait_time = std::cmp::min(50 * retry_count, 500); // 递增等待时间最大500ms
std::thread::sleep(Duration::from_millis(wait_time));
}
None => {
println!("get_photos 连接被占用,返回空结果避免阻塞");
// 如果连接被占用,直接返回空结果,避免阻塞
Ok(Vec::new())
}
}
}

View File

@ -84,6 +84,15 @@ impl Database {
}
}
/// 尝试非阻塞获取数据库连接
/// 如果连接被占用,立即返回 None
pub fn try_get_connection(&self) -> Option<std::sync::MutexGuard<Connection>> {
match self.connection.try_lock() {
Ok(conn) => Some(conn),
Err(_) => None,
}
}
/// 执行数据库操作的辅助方法,自动处理锁的获取和释放
/// 这是推荐的数据库访问方式,可以避免锁竞争问题
pub fn with_connection<T, F>(&self, operation: F) -> Result<T, rusqlite::Error>