mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-19 00:38:54 +00:00
Don't use dashmap when you need async updates [deadlocks xd]
This commit is contained in:
parent
0f91c3a22a
commit
01c743f866
1 changed files with 35 additions and 20 deletions
|
@ -1,19 +1,22 @@
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use dashmap::DashMap;
|
|
||||||
use serenity::model::{
|
use serenity::model::{
|
||||||
guild::Member,
|
guild::Member,
|
||||||
id::{GuildId, UserId},
|
id::{GuildId, UserId},
|
||||||
};
|
};
|
||||||
use serenity::{http::CacheHttp, prelude::*};
|
use serenity::{http::CacheHttp, prelude::*};
|
||||||
|
use std::collections::{hash_map::Entry, HashMap};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
const VALID_CACHE_SECONDS: i64 = 15 * 60; // 15 minutes
|
const VALID_CACHE_SECONDS: i64 = 15 * 60; // 15 minutes
|
||||||
|
|
||||||
|
type Map<K, V> = Mutex<HashMap<K, V>>;
|
||||||
|
|
||||||
/// MemberCache resolves `does User belong to Guild` requests, and store them in a cache.
|
/// MemberCache resolves `does User belong to Guild` requests, and store them in a cache.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct MemberCache {
|
pub struct MemberCache {
|
||||||
per_user: DashMap<(UserId, GuildId), Expiring<Option<Member>>>,
|
per_user: Map<(UserId, GuildId), Expiring<Option<Member>>>,
|
||||||
per_guild: DashMap<GuildId, Expiring<Arc<[Member]>>>,
|
per_guild: Map<GuildId, Expiring<Arc<[Member]>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -49,21 +52,31 @@ impl MemberCache {
|
||||||
) -> Option<Member> {
|
) -> Option<Member> {
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
// Check cache
|
// Check cache
|
||||||
if let Some(r) = self.per_user.get(&(user_id, guild_id)) {
|
if let Some(r) = self.per_user.lock().await.get(&(user_id, guild_id)) {
|
||||||
if r.timeout > now {
|
if r.timeout > now {
|
||||||
return r.clone();
|
return r.value.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Check members cache first if possible
|
||||||
|
if let Ok(mems) = self.query_members(&cache_http, guild_id).await {
|
||||||
|
return mems.iter().find(|m| m.user.id == user_id).cloned();
|
||||||
|
}
|
||||||
// Query
|
// Query
|
||||||
|
let mut map = self.per_user.lock().await;
|
||||||
|
let entry = map.entry((user_id, guild_id));
|
||||||
|
if let Entry::Occupied(oe) = &entry {
|
||||||
|
if oe.get().timeout > now {
|
||||||
|
return oe.get().value.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
let t = guild_id.member(&cache_http, user_id).await.ok();
|
let t = guild_id.member(&cache_http, user_id).await.ok();
|
||||||
self.per_user.insert(
|
entry
|
||||||
(user_id, guild_id),
|
.or_insert(Expiring::new(
|
||||||
Expiring::new(
|
|
||||||
t.clone(),
|
t.clone(),
|
||||||
now + chrono::Duration::seconds(VALID_CACHE_SECONDS),
|
now + chrono::Duration::seconds(VALID_CACHE_SECONDS),
|
||||||
),
|
))
|
||||||
);
|
.value
|
||||||
t
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn query_members(
|
pub async fn query_members(
|
||||||
|
@ -72,24 +85,26 @@ impl MemberCache {
|
||||||
guild_id: GuildId,
|
guild_id: GuildId,
|
||||||
) -> crate::Result<Arc<[Member]>> {
|
) -> crate::Result<Arc<[Member]>> {
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
|
let mut map = self.per_guild.lock().await;
|
||||||
|
let entry = map.entry(guild_id);
|
||||||
// Check cache
|
// Check cache
|
||||||
if let Some(r) = self.per_guild.get(&guild_id) {
|
if let Entry::Occupied(oe) = &entry {
|
||||||
if r.timeout > now {
|
if oe.get().timeout > now {
|
||||||
return Ok(r.value.clone());
|
return Ok(oe.get().value.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// query
|
// query
|
||||||
|
eprintln!("querying members of {}", guild_id);
|
||||||
let members: Arc<[Member]> = guild_id
|
let members: Arc<[Member]> = guild_id
|
||||||
.members(cache_http.http(), None, None)
|
.members(cache_http.http(), None, None)
|
||||||
.await?
|
.await?
|
||||||
.into();
|
.into();
|
||||||
self.per_guild.insert(
|
Ok(entry
|
||||||
guild_id,
|
.or_insert(Expiring::new(
|
||||||
Expiring::new(
|
|
||||||
members.clone(),
|
members.clone(),
|
||||||
now + chrono::Duration::seconds(VALID_CACHE_SECONDS),
|
now + chrono::Duration::seconds(VALID_CACHE_SECONDS),
|
||||||
),
|
))
|
||||||
);
|
.value
|
||||||
Ok(members)
|
.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue