mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 05:25:14 +08:00
fix(cas): exists 返回 Result 以区分不存在与存储故障
CasRepository::exists(core trait)与底层 Storage::exists 原返回裸 bool, FileSystemStorage 用 try_exists(...).unwrap_or(false)、infra 适配层吞掉解析/ 初始化错误返回 false,调用方无法区分“对象不存在”和权限/IO/初始化故障。 将整条链改为 Result<bool>: - storage trait 与 FileSystemStorage:try_exists 的 IO 错误经 ? 传播; - repository FileSystemCasRepository::exists 及 store/add_reference 内部调用; - core CasRepository::exists trait; - infra 适配层:解析失败→InvalidArgument、初始化/引擎错误经 map_error 传播。 Ok(false) 仅表示确实不存在。 新增单测:合法但不存在的对象返回 Ok(false),非法 ObjectId 返回 Err(而非静默 false);同步更新各层 exists 断言。 对应 issue #18 维护清单 2-1。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,7 @@ impl FileSystemCasRepository {
|
||||
/// 存储对象并增加引用计数。
|
||||
pub async fn store(&self, data: &[u8]) -> Result<Hash> {
|
||||
let hash = compute_hash(data);
|
||||
let existed = self.storage.exists(&hash).await;
|
||||
let existed = self.storage.exists(&hash).await?;
|
||||
let stored_hash = self.storage.put(data).await?;
|
||||
|
||||
// 单条 UPSERT 原子建行并 +1:对象行不会在 store 期间以 ref_count=0
|
||||
@@ -75,13 +75,13 @@ impl FileSystemCasRepository {
|
||||
}
|
||||
|
||||
/// 检查对象是否存在。
|
||||
pub async fn exists(&self, hash: &Hash) -> bool {
|
||||
pub async fn exists(&self, hash: &Hash) -> Result<bool> {
|
||||
self.storage.exists(hash).await
|
||||
}
|
||||
|
||||
/// 增加引用计数。
|
||||
pub async fn add_reference(&self, hash: &Hash) -> Result<u64> {
|
||||
if !self.storage.exists(hash).await {
|
||||
if !self.storage.exists(hash).await? {
|
||||
return Err(CasError::ObjectNotFound(hash.to_string()));
|
||||
}
|
||||
|
||||
@@ -169,8 +169,8 @@ mod tests {
|
||||
repo.remove_reference(&delete).await.unwrap();
|
||||
|
||||
assert_eq!(repo.gc().await.unwrap(), 1);
|
||||
assert!(repo.exists(&keep).await);
|
||||
assert!(!repo.exists(&delete).await);
|
||||
assert!(repo.exists(&keep).await.unwrap());
|
||||
assert!(!repo.exists(&delete).await.unwrap());
|
||||
assert!(matches!(
|
||||
repo.get_reference_count(&delete).await,
|
||||
Err(CasError::ObjectNotFound(_))
|
||||
@@ -209,7 +209,7 @@ mod tests {
|
||||
assert_eq!(repo.get_reference_count(&hash).await.unwrap(), 1);
|
||||
assert!(repo.gc_candidates().await.unwrap().is_empty());
|
||||
assert_eq!(repo.gc().await.unwrap(), 0);
|
||||
assert!(repo.exists(&hash).await);
|
||||
assert!(repo.exists(&hash).await.unwrap());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -224,7 +224,7 @@ mod tests {
|
||||
assert_eq!(repo.add_reference(&hash).await.unwrap(), 1);
|
||||
// gc 的原子闸门应跳过它,对象文件保留。
|
||||
assert_eq!(repo.gc().await.unwrap(), 0);
|
||||
assert!(repo.exists(&hash).await);
|
||||
assert!(repo.exists(&hash).await.unwrap());
|
||||
assert_eq!(repo.get_reference_count(&hash).await.unwrap(), 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,10 @@ pub trait Storage: Send + Sync {
|
||||
async fn get(&self, hash: &Hash) -> Result<Vec<u8>>;
|
||||
|
||||
/// 检查对象文件是否存在。
|
||||
async fn exists(&self, hash: &Hash) -> bool;
|
||||
///
|
||||
/// 返回 `Result` 以便区分“确实不存在”(`Ok(false)`)与底层 IO 故障(`Err`),
|
||||
/// 避免把权限或其它 IO 错误静默当成不存在。
|
||||
async fn exists(&self, hash: &Hash) -> Result<bool>;
|
||||
|
||||
/// 删除对象文件。
|
||||
async fn delete(&self, hash: &Hash) -> Result<()>;
|
||||
@@ -115,7 +118,7 @@ impl FileSystemStorage {
|
||||
}
|
||||
|
||||
async fn validate_existing_object(&self, hash: &Hash) -> Result<bool> {
|
||||
if !self.exists(hash).await {
|
||||
if !self.exists(hash).await? {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
@@ -249,10 +252,8 @@ impl Storage for FileSystemStorage {
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
async fn exists(&self, hash: &Hash) -> bool {
|
||||
tokio::fs::try_exists(self.object_path(hash))
|
||||
.await
|
||||
.unwrap_or(false)
|
||||
async fn exists(&self, hash: &Hash) -> Result<bool> {
|
||||
Ok(tokio::fs::try_exists(self.object_path(hash)).await?)
|
||||
}
|
||||
|
||||
async fn delete(&self, hash: &Hash) -> Result<()> {
|
||||
@@ -347,10 +348,10 @@ mod tests {
|
||||
|
||||
let hash = storage.put(b"Test data").await.unwrap();
|
||||
|
||||
assert!(storage.exists(&hash).await);
|
||||
assert!(storage.exists(&hash).await.unwrap());
|
||||
let deleted = storage.delete(&hash).await;
|
||||
deleted.unwrap();
|
||||
assert!(!storage.exists(&hash).await);
|
||||
assert!(!storage.exists(&hash).await.unwrap());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
Reference in New Issue
Block a user