diff --git a/Cargo.lock b/Cargo.lock index 82533b1..7c36bb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -488,7 +488,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown", + "hashbrown 0.14.3", "lock_api", "once_cell", "parking_lot_core", @@ -503,9 +503,9 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" dependencies = [ "powerfmt", "serde", @@ -945,6 +945,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "halfbrown" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5681137554ddff44396e5f149892c769d45301dd9aa19c51602a89ee214cb0ec" +dependencies = [ + "arrayvec", + "hashbrown 0.13.2", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -961,7 +980,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown", + "hashbrown 0.14.3", ] [[package]] @@ -1130,7 +1149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.3", ] [[package]] @@ -3142,12 +3161,13 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "typesize" version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46638a7bcd4104adbb21b558651f24bdc6a26366a0476099076d0771b864561b" +source = "git+https://github.com/GnomedDev/typesize#eb3cc6d5020a117c1377a159e2d6f03f010db34a" dependencies = [ + "arrayvec", "chrono", "dashmap", - "hashbrown", + "halfbrown", + "hashbrown 0.14.3", "mini-moka", "parking_lot", "secrecy", @@ -3160,8 +3180,7 @@ dependencies = [ [[package]] name = "typesize-derive" version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b122284365ba8497be951b9a21491f70c9688eb6fddc582931a0703f6a00ece" +source = "git+https://github.com/GnomedDev/typesize#eb3cc6d5020a117c1377a159e2d6f03f010db34a" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 9c8f5f1..040e105 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ strum_macros = "0.25" arrayvec = "0.7.4" bitflags = "2.4.1" paste = "1.0.14" -typesize = "0.1.2" +typesize = { version = "0.1.2", features = ["arrayvec"] } futures-util = { version = "0.3.29", default-features = false } [dependencies.symphonia] @@ -70,3 +70,6 @@ branch = "current" [dependencies.songbird] version = "0.4" features = ["builtin-queue"] + +[patch.crates-io] +typesize = { git = "https://github.com/GnomedDev/typesize" } diff --git a/src/commands/owner.rs b/src/commands/owner.rs index a4e1574..4fd1375 100644 --- a/src/commands/owner.rs +++ b/src/commands/owner.rs @@ -17,6 +17,7 @@ use std::{ borrow::Cow, collections::{HashMap, HashSet}, + hash::Hash, sync::atomic::Ordering::SeqCst, }; @@ -27,6 +28,8 @@ use rand::{rngs::ThreadRng, Rng}; use typesize::TypeSize; use crate::{ + database, + database_models::Compact, funcs::dm_generic, opt_ext::OptionTryUnwrap, structs::{Command, CommandResult, Context, PrefixContext, TTSModeChoice}, @@ -314,7 +317,7 @@ fn choose_random<'a, T>(rng: &mut ThreadRng, container: &'a [T]) -> &'a T { &container[index] } -fn choose_random_map<'a, K: std::hash::Hash + Eq, V>( +fn choose_random_map<'a, K: Hash + Eq, V>( rng: &mut ThreadRng, map: &'a HashMap, ) -> Option<&'a V> { @@ -328,6 +331,22 @@ fn random_guild<'a>( cache.guild(choose_random(rng, &cache.guilds())) } +fn get_db_info( + name: &'static str, + handler: &database::Handler, +) -> typesize::Field +where + CacheKey: Eq + Hash + TypeSize, + RowT::Compacted: TypeSize, + RowT: Compact, +{ + typesize::Field { + name, + size: handler.get_size(), + collection_items: handler.get_collection_item_count(), + } +} + #[poise::command(prefix_command, owners_only)] pub async fn cache_info(ctx: Context<'_>, kind: Option) -> CommandResult { struct Field { @@ -339,27 +358,47 @@ pub async fn cache_info(ctx: Context<'_>, kind: Option) -> CommandResult let serenity_cache = ctx.cache(); let cache_stats = { + let data = ctx.data(); let mut rng = rand::thread_rng(); match kind.as_deref() { - Some("guild") => random_guild(&mut rng, serenity_cache) - .try_unwrap()? - .get_size_details(), + Some("db") => Some(vec![ + get_db_info("guild db", &data.guilds_db), + get_db_info("userinfo db", &data.userinfo_db), + get_db_info("nickname db", &data.nickname_db), + get_db_info("user voice db", &data.user_voice_db), + get_db_info("guild voice db", &data.guild_voice_db), + ]), + Some("guild") => Some( + random_guild(&mut rng, serenity_cache) + .try_unwrap()? + .get_size_details(), + ), Some("channel") => { let guild = random_guild(&mut rng, serenity_cache).try_unwrap()?; - choose_random_map(&mut rng, &guild.channels) - .try_unwrap()? - .get_size_details() + Some( + choose_random_map(&mut rng, &guild.channels) + .try_unwrap()? + .get_size_details(), + ) } Some("role") => { let guild = random_guild(&mut rng, serenity_cache).try_unwrap()?; - choose_random_map(&mut rng, &guild.roles) - .try_unwrap()? - .get_size_details() + Some( + choose_random_map(&mut rng, &guild.roles) + .try_unwrap()? + .get_size_details(), + ) } - _ => serenity_cache.get_size_details(), + Some(_) => None, + None => Some(serenity_cache.get_size_details()), } }; + let Some(cache_stats) = cache_stats else { + ctx.say("Unknown cache!").await?; + return Ok(()); + }; + let mut fields = Vec::new(); for field in cache_stats { let name = format!("`{}`", field.name); diff --git a/src/database.rs b/src/database.rs index 06fd987..0a48138 100644 --- a/src/database.rs +++ b/src/database.rs @@ -14,9 +14,10 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::sync::Arc; +use std::{hash::Hash, sync::Arc}; use dashmap::DashMap; +use typesize::TypeSize; pub use crate::database_models::*; use crate::structs::{Result, TTSMode}; @@ -25,7 +26,7 @@ type PgArguments<'a> = >::Arg type QueryAs<'a, R> = sqlx::query::QueryAs<'a, sqlx::Postgres, R, PgArguments<'a>>; type Query<'a> = sqlx::query::Query<'a, sqlx::Postgres, PgArguments<'a>>; -pub trait CacheKeyTrait: std::cmp::Eq + std::hash::Hash { +pub trait CacheKeyTrait: std::cmp::Eq + Hash { fn bind_query(self, query: Query<'_>) -> Query<'_>; fn bind_query_as(self, query: QueryAs<'_, R>) -> QueryAs<'_, R>; } @@ -57,12 +58,11 @@ impl CacheKeyTrait for (i64, TTSMode) { } } -pub struct Handler< - CacheKey: CacheKeyTrait, - RowT: for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow> + Compact, -> { +type OwnedArc = typesize::ptr::SizableArc; + +pub struct Handler { pool: sqlx::PgPool, - cache: DashMap>, + cache: DashMap>, default_row: Arc, single_insert: &'static str, @@ -74,7 +74,7 @@ pub struct Handler< impl Handler where CacheKey: CacheKeyTrait + Sync + Send + Copy + Default, - RowT: for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow> + Compact + Sync + Send + Unpin, + RowT: for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow> + Compact + Send + Unpin, { pub async fn new( pool: sqlx::PgPool, @@ -115,7 +115,7 @@ where .await? .unwrap_or_else(|| self.default_row.clone()); - self.cache.insert(identifier, row.clone()); + self.cache.insert(identifier, row.clone().into()); Ok(row) } @@ -166,6 +166,23 @@ where } } +impl TypeSize for Handler +where + RowT::Compacted: TypeSize, +{ + fn extra_size(&self) -> usize { + self.cache.extra_size() + } + + fn get_collection_item_count(&self) -> Option { + self.cache.get_collection_item_count() + } + + fn get_size_details(&self) -> Vec { + self.cache.get_size_details() + } +} + #[macro_export] macro_rules! create_db_handler { ($pool:expr, $table_name:literal, $id_name:literal) => {{ diff --git a/src/database_models.rs b/src/database_models.rs index d86a816..d2a55ca 100644 --- a/src/database_models.rs +++ b/src/database_models.rs @@ -1,4 +1,5 @@ use arrayvec::ArrayString; +use typesize::derive::TypeSize; use poise::serenity_prelude::{ChannelId, GuildId, RoleId, UserId}; @@ -30,9 +31,11 @@ macro_rules! named_bitflags { (pub struct $name:ident: $flag_size:ident { $(const $flag_name:ident = $flag_value:expr;)* }) => { + #[derive(TypeSize)] + pub struct $name($flag_size); + bitflags::bitflags! { - #[derive(Debug)] - pub struct $name: $flag_size { + impl $name: $flag_size { $(const $flag_name = $flag_value;)* } } @@ -46,6 +49,15 @@ macro_rules! named_bitflags { )* } } + + impl std::fmt::Debug for $name { + fn fmt(&self, mut f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, concat!(stringify!($name), "("))?; + bitflags::parser::to_writer(self, &mut f)?; + write!(f, ")")?; + Ok(()) + } + } }; } @@ -85,7 +97,7 @@ named_bitflags! { } } -#[derive(Debug)] +#[derive(Debug, TypeSize)] pub struct GuildRow { pub flags: GuildRowFlags, pub channel: Option, @@ -144,7 +156,7 @@ named_bitflags! { } } -#[derive(Debug)] +#[derive(Debug, TypeSize)] pub struct UserRow { pub flags: UserRowFlags, pub voice_mode: Option, @@ -173,7 +185,7 @@ pub struct GuildVoiceRowRaw { pub voice: String, } -#[derive(Debug)] +#[derive(Debug, TypeSize)] pub struct GuildVoiceRow { pub guild_id: Option, @@ -200,7 +212,7 @@ pub struct UserVoiceRowRaw { pub speaking_rate: Option, } -#[derive(Debug)] +#[derive(Debug, TypeSize)] pub struct UserVoiceRow { pub user_id: Option, pub mode: TTSMode, @@ -222,7 +234,7 @@ impl Compact for UserVoiceRowRaw { } } -#[derive(Debug, sqlx::FromRow)] +#[derive(Debug, TypeSize, sqlx::FromRow)] pub struct NicknameRow { pub name: Option, } diff --git a/src/structs.rs b/src/structs.rs index ea8a471..186e766 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -4,17 +4,17 @@ use std::{ sync::Arc, }; +pub use anyhow::{Error, Result}; use parking_lot::RwLock; use serde::Deserialize as _; use strum_macros::IntoStaticStr; +use tracing::warn; +use typesize::derive::TypeSize; use poise::serenity_prelude::{self as serenity, json}; -use tracing::warn; use crate::{analytics, database, into_static_display}; -pub use anyhow::{Error, Result}; - #[derive(serde::Deserialize)] pub struct Config { #[serde(rename = "Main")] @@ -320,7 +320,7 @@ impl SpeakingRateInfo { } } -#[derive(IntoStaticStr, sqlx::Type, Debug, Default, Hash, PartialEq, Eq, Copy, Clone)] +#[derive(IntoStaticStr, sqlx::Type, TypeSize, Debug, Default, Hash, PartialEq, Eq, Copy, Clone)] #[allow(non_camel_case_types)] #[sqlx(rename_all = "lowercase")] #[sqlx(type_name = "ttsmode")]