This commit is contained in:
2026-07-25 17:19:36 +02:00
parent 6fb8ab19aa
commit 068e100ca1
6 changed files with 371 additions and 29 deletions
+81
View File
@@ -0,0 +1,81 @@
use std::collections::HashMap;
use std::hash::Hash;
use std::sync::{Arc, Weak};
use tokio::sync::{Mutex, OwnedMutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
/// Structure gérant les garde-fous pour un verrou scopé.
pub struct ScopedGuard<'a, K: Eq + Hash + Clone> {
_global_read_guard: RwLockReadGuard<'a, ()>,
_local_guard: OwnedMutexGuard<()>,
key: K,
manager: &'a ScopedLockManager<K>,
}
impl<'a, K: Eq + Hash + Clone> Drop for ScopedGuard<'a, K> {
fn drop(&mut self) {
// Optionnel : Nettoyage des Mutex orphelins dans la HashMap scopée
let mut map = self.manager.scopes.blocking_lock();
if let Some(weak) = map.get(&self.key) {
if weak.strong_count() == 0 {
map.remove(&self.key);
}
}
}
}
#[derive(Clone, Default)]
pub struct ScopedLockManager<K: Eq + Hash + Clone> {
global_lock: Arc<RwLock<()>>,
scopes: Arc<Mutex<HashMap<K, Weak<Mutex<()>>>>>,
}
impl<K: Eq + Hash + Clone> ScopedLockManager<K> {
pub fn new() -> Self {
Self {
global_lock: Arc::new(RwLock::new(())),
scopes: Arc::new(Mutex::new(HashMap::new())),
}
}
/// Acquiert le verrou global (Exclusif / Write Lock).
/// Bloque tous les autres verrous globaux et tous les verrous scopés.
pub async fn lock_global(&self) -> RwLockWriteGuard<'_, ()> {
self.global_lock.write().await
}
/// Acquiert un verrou ciblé sur une clé `key` (ex: server_id ou user_id).
/// Permet des exécutions parallèles sur des `key` différentes,
/// mais garantit la sérialisation pour la même `key`.
pub async fn lock_scope(&self, key: K) -> ScopedGuard<'_, K> {
// 1. Prendre une garde de lecture (Read) sur le verrou global
let global_read = self.global_lock.read().await;
// 2. Récupérer ou créer le Mutex dédié à la clé `key`
let local_mutex = {
let mut map = self.scopes.lock().await;
if let Some(weak) = map.get(&key) {
if let Some(arc) = weak.upgrade() {
arc
} else {
let arc = Arc::new(Mutex::new(()));
map.insert(key.clone(), Arc::downgrade(&arc));
arc
}
} else {
let arc = Arc::new(Mutex::new(()));
map.insert(key.clone(), Arc::downgrade(&arc));
arc
}
};
// 3. Verrouiller le Mutex local
let local_guard = local_mutex.lock_owned().await;
ScopedGuard {
_global_read_guard: global_read,
_local_guard: local_guard,
key,
manager: self,
}
}
}