allow selecting a subset of rooms

This can make debugging a specific room much easier/faster.
This commit is contained in:
Charles Hall 2024-11-03 11:34:15 -08:00
parent b1e14fad5c
commit aa49b111ed
No known key found for this signature in database
GPG key ID: 7B8E0645816E07CF
4 changed files with 32 additions and 13 deletions

View file

@ -6,6 +6,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use ruma::OwnedRoomId;
use crate::{ use crate::{
config::{default_tracing_filter, EnvFilterClone, LogFormat}, config::{default_tracing_filter, EnvFilterClone, LogFormat},
@ -107,6 +108,12 @@ pub(crate) struct GetRoomStatesArgs {
#[clap(long, short)] #[clap(long, short)]
pub(crate) recompute: bool, pub(crate) recompute: bool,
/// Limit the output to a subset of rooms by their IDs
///
/// This option can be specified multiple times.
#[clap(long, short)]
pub(crate) select: Vec<OwnedRoomId>,
#[clap(flatten)] #[clap(flatten)]
observability: ObservabilityArgs, observability: ObservabilityArgs,
} }

View file

@ -65,9 +65,9 @@ pub(crate) async fn run(
db.apply_migrations().await.map_err(Error::Database)?; db.apply_migrations().await.map_err(Error::Database)?;
let room_states = if args.recompute { let room_states = if args.recompute {
recompute::get_room_states(db) recompute::get_room_states(db, &args.select)
} else { } else {
cache::get_room_states().await cache::get_room_states(&args.select).await
}; };
serde_json::to_writer(std::io::stdout(), &room_states)?; serde_json::to_writer(std::io::stdout(), &room_states)?;

View file

@ -8,12 +8,16 @@ use tracing as t;
use super::StateEvent; use super::StateEvent;
use crate::{services, PduEvent}; use crate::{services, PduEvent};
/// Get the state of all rooms /// Get the state of all rooms, or the selected subset
#[t::instrument] #[t::instrument(skip(select))]
pub(crate) async fn get_room_states() -> Vec<StateEvent> { pub(crate) async fn get_room_states(select: &[OwnedRoomId]) -> Vec<StateEvent> {
let mut serializable_state = Vec::new(); let mut serializable_state = Vec::new();
for room_id in services().rooms.metadata.iter_ids().filter_map(Result::ok) { for room_id in services().rooms.metadata.iter_ids().filter_map(Result::ok) {
if !select.is_empty() && !select.contains(&room_id) {
continue;
}
let Some(state) = get_room_state(room_id).await else { let Some(state) = get_room_state(room_id).await else {
continue; continue;
}; };

View file

@ -18,7 +18,7 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator};
use ruma::{ use ruma::{
events::{StateEventType, TimelineEventType}, events::{StateEventType, TimelineEventType},
state_res::StateMap, state_res::StateMap,
EventId, RoomId, RoomVersionId, UserId, EventId, OwnedRoomId, RoomId, RoomVersionId, UserId,
}; };
use serde::Deserialize; use serde::Deserialize;
use tracing as t; use tracing as t;
@ -64,9 +64,12 @@ struct StateResolutionEdges {
auth_events: Vec<Arc<EventId>>, auth_events: Vec<Arc<EventId>>,
} }
/// Get the state of all rooms /// Get the state of all rooms, or the selected subset
pub(crate) fn get_room_states(db: &KeyValueDatabase) -> Vec<StateEvent> { pub(crate) fn get_room_states(
let state_resolution_edges = get_state_resolution_edges(db); db: &KeyValueDatabase,
select: &[OwnedRoomId],
) -> Vec<StateEvent> {
let state_resolution_edges = get_state_resolution_edges(db, select);
let graphs = get_state_event_graphs(db, state_resolution_edges); let graphs = get_state_event_graphs(db, state_resolution_edges);
let states = resolve_room_states(db, graphs); let states = resolve_room_states(db, graphs);
@ -376,10 +379,11 @@ fn get_either_pdu_by_event_id(
} }
/// Get the edges in the graph of state events for state resolution /// Get the edges in the graph of state events for state resolution
#[t::instrument(skip(db))] #[t::instrument(skip(db, select))]
fn get_state_resolution_edges( fn get_state_resolution_edges<'a>(
db: &KeyValueDatabase, db: &'a KeyValueDatabase,
) -> impl Iterator<Item = StateResolutionEdges> + '_ { select: &'a [OwnedRoomId],
) -> impl Iterator<Item = StateResolutionEdges> + 'a {
let filter_map = |key: Vec<u8>, value: Vec<u8>, map: &str| { let filter_map = |key: Vec<u8>, value: Vec<u8>, map: &str| {
let Ok(pdu) = serde_json::from_slice::<PduEvent>(&value) else { let Ok(pdu) = serde_json::from_slice::<PduEvent>(&value) else {
t::error!( t::error!(
@ -390,6 +394,10 @@ fn get_state_resolution_edges(
return None; return None;
}; };
if !select.is_empty() && !select.contains(&pdu.room_id) {
return None;
}
let Some(state_key) = pdu.state_key else { let Some(state_key) = pdu.state_key else {
// Filter out non-state events // Filter out non-state events
return None; return None;