vdsl_sync/infra/transfer_store.rs
1//! TransferStore — Transfer永続化トレイト。
2//!
3//! 配送記録の永続化を抽象化する。
4//! Transfer CRUD + クエリ + 集計 + pruning。
5
6use async_trait::async_trait;
7use chrono::{DateTime, Utc};
8
9use crate::domain::location::LocationId;
10use crate::domain::transfer::{Transfer, TransferState};
11use crate::infra::error::InfraError;
12
13/// DB集約クエリの1行。dest×state別のファイル数カウント。
14#[derive(Debug, Clone)]
15pub struct TransferStatRow {
16 pub src: LocationId,
17 pub dest: LocationId,
18 pub state: TransferState,
19 pub error_kind: Option<String>,
20 pub attempt: u32,
21 pub file_count: usize,
22}
23
24/// Transfer永続化。
25///
26/// 実装: [`super::sqlite::SqliteSyncStore`] (feature = "sqlite")
27#[async_trait]
28pub trait TransferStore: Send + Sync {
29 /// Transferを保存。
30 async fn insert_transfer(&self, transfer: &Transfer) -> Result<(), InfraError>;
31
32 /// Transfer状態を更新(start/complete/fail後に呼ぶ)。
33 async fn update_transfer(&self, transfer: &Transfer) -> Result<(), InfraError>;
34
35 /// 特定destのQueued Transfer一覧。
36 ///
37 /// 各file_idの最新Transferのみ返す(古いリトライは除外)。
38 async fn queued_transfers(&self, dest: &LocationId) -> Result<Vec<Transfer>, InfraError>;
39
40 /// 特定ファイルの最新Transfer(dest別)。
41 ///
42 /// 各destについて最新のTransferのみ返す。
43 /// FileView構築時にPresenceView導出に使用。
44 async fn latest_transfers_by_file(&self, file_id: &str) -> Result<Vec<Transfer>, InfraError>;
45
46 /// Failed Transfer一覧(最新のみ)。
47 async fn failed_transfers(&self) -> Result<Vec<Transfer>, InfraError>;
48
49 /// 完了済み古いTransferを削除。削除件数を返す。
50 ///
51 /// 履歴肥大化防止用。各file_id×destの最新は保持される。
52 async fn prune_completed(&self, before: DateTime<Utc>) -> Result<usize, InfraError>;
53
54 /// Queued状態のTransfer件数を返す。進捗表示用。
55 async fn count_queued(&self) -> Result<usize, InfraError>;
56
57 /// InFlight状態のTransferをCancelledに遷移。
58 ///
59 /// プロセス再起動時にInFlightのまま残った孤児transferを終端状態にする。
60 /// Cancelledは終端状態 — 再実行されない。必要であれば新しいTransferを作成する。
61 /// 返り値はキャンセルした件数。
62 async fn cancel_orphaned_inflight(&self) -> Result<usize, InfraError>;
63
64 /// 指定Transfer IDに依存するBlocked TransferをQueuedに遷移させる。
65 ///
66 /// Transfer完了時に呼び出し、依存チェーンの次ホップを実行可能にする。
67 /// 返り値はunblockした件数。
68 async fn unblock_dependents(&self, completed_transfer_id: &str) -> Result<usize, InfraError>;
69
70 /// 全destのQueued/Blocked Transfer一覧(最新のみ)。
71 ///
72 /// `status()` のpending_entries構築用。dest指定なしで全pendingを返す。
73 async fn all_pending_transfers(&self) -> Result<Vec<Transfer>, InfraError>;
74
75 /// Transfer状態の集約統計。
76 ///
77 /// 最新Transfer(file_id×dest別)をsrc, dest, state, error_kind, attemptでGROUP BYし、
78 /// ファイル数カウントを返す。`status()`のN+1クエリ問題を解消するための集約メソッド。
79 async fn transfer_stats(&self) -> Result<Vec<TransferStatRow>, InfraError>;
80
81 /// Location別のPresent file数。
82 ///
83 /// 各locationについて、srcとして送出した or completedとして到達したdistinct file数を返す。
84 /// UNIONでsrc/completed-destを統合し、同一location×file_idの重複を排除する。
85 async fn present_counts_by_location(
86 &self,
87 ) -> Result<std::collections::HashMap<LocationId, usize>, InfraError>;
88}