Skip to main content

tdm_server_rust/cache/
rss_file_lock.rs

1//! RSS 文件 per-file 互斥锁
2//!
3//! 防止多个定时任务同时写入同一 RSS XML 文件导致内容交错。
4//! 基于 `DashMap` 实现懒创建的文件级互斥锁。
5//!
6//! ## 设计
7//!
8//! 每次 RSS 写入前,通过文件名获取对应的 `tokio::sync::Mutex`。
9//! 若该文件尚无锁,自动创建并插入 `DashMap`。
10//! 锁的生命周期为整个写入过程(读数据库 + 格式化 + 写文件)。
11
12use dashmap::DashMap;
13use std::sync::Arc;
14use tokio::sync::{Mutex, OwnedMutexGuard};
15
16/// RSS 文件级互斥锁管理器
17///
18/// 内部使用 `DashMap<String, Arc<Mutex<()>>>` 维护文件名到互斥锁的映射。
19/// 锁在首次访问时懒创建,进程生命周期内持续存在。
20pub struct RssFileLock {
21    /// 文件名 → 互斥锁的并发哈希表
22    locks: DashMap<String, Arc<Mutex<()>>>,
23}
24
25impl RssFileLock {
26    /// 创建空的锁表
27    pub fn new() -> Self {
28        Self {
29            locks: DashMap::new(),
30        }
31    }
32
33    /// 获取指定文件的独占写锁
34    ///
35    /// 若该文件尚无锁,自动插入新的 `Mutex`。
36    /// 返回 `OwnedMutexGuard`,锁在 guard drop 时释放。
37    ///
38    /// # 参数
39    ///
40    /// - `file_name`: RSS XML 文件名(如 `"rss.xml"`)
41    ///
42    /// # 返回值
43    ///
44    /// 返回持有锁的 `OwnedMutexGuard`,离开作用域时自动释放。
45    pub async fn lock(&self, file_name: &str) -> OwnedMutexGuard<()> {
46        let mutex = self
47            .locks
48            .entry(file_name.to_string())
49            .or_insert_with(|| Arc::new(Mutex::new(())))
50            .clone();
51        mutex.lock_owned().await
52    }
53}
54
55impl Default for RssFileLock {
56    fn default() -> Self {
57        Self::new()
58    }
59}