use rocksdb caches for a few of the lru_caches

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-04-08 01:29:52 -07:00 committed by June
parent fc44ba6ab3
commit 345be5ba5e
10 changed files with 133 additions and 192 deletions

View file

@ -148,31 +148,19 @@ impl service::globals::Data for KeyValueDatabase {
fn cork_and_sync(&self) -> Result<Cork> { Ok(Cork::new(&self.db, true, true)) }
fn memory_usage(&self) -> String {
let pdu_cache = self.pdu_cache.lock().unwrap().len();
let shorteventid_cache = self.shorteventid_cache.lock().unwrap().len();
let auth_chain_cache = self.auth_chain_cache.lock().unwrap().len();
let eventidshort_cache = self.eventidshort_cache.lock().unwrap().len();
let statekeyshort_cache = self.statekeyshort_cache.lock().unwrap().len();
let our_real_users_cache = self.our_real_users_cache.read().unwrap().len();
let appservice_in_room_cache = self.appservice_in_room_cache.read().unwrap().len();
let lasttimelinecount_cache = self.lasttimelinecount_cache.lock().unwrap().len();
let max_pdu_cache = self.pdu_cache.lock().unwrap().capacity();
let max_shorteventid_cache = self.shorteventid_cache.lock().unwrap().capacity();
let max_auth_chain_cache = self.auth_chain_cache.lock().unwrap().capacity();
let max_eventidshort_cache = self.eventidshort_cache.lock().unwrap().capacity();
let max_statekeyshort_cache = self.statekeyshort_cache.lock().unwrap().capacity();
let max_our_real_users_cache = self.our_real_users_cache.read().unwrap().capacity();
let max_appservice_in_room_cache = self.appservice_in_room_cache.read().unwrap().capacity();
let max_lasttimelinecount_cache = self.lasttimelinecount_cache.lock().unwrap().capacity();
let mut response = format!(
"\
pdu_cache: {pdu_cache} / {max_pdu_cache}
shorteventid_cache: {shorteventid_cache} / {max_shorteventid_cache}
auth_chain_cache: {auth_chain_cache} / {max_auth_chain_cache}
eventidshort_cache: {eventidshort_cache} / {max_eventidshort_cache}
statekeyshort_cache: {statekeyshort_cache} / {max_statekeyshort_cache}
our_real_users_cache: {our_real_users_cache} / {max_our_real_users_cache}
appservice_in_room_cache: {appservice_in_room_cache} / {max_appservice_in_room_cache}
lasttimelinecount_cache: {lasttimelinecount_cache} / {max_lasttimelinecount_cache}\n\n"
@ -185,35 +173,19 @@ lasttimelinecount_cache: {lasttimelinecount_cache} / {max_lasttimelinecount_cach
}
fn clear_caches(&self, amount: u32) {
if amount > 0 {
let c = &mut *self.pdu_cache.lock().unwrap();
*c = LruCache::new(c.capacity());
}
if amount > 1 {
let c = &mut *self.shorteventid_cache.lock().unwrap();
*c = LruCache::new(c.capacity());
}
if amount > 2 {
let c = &mut *self.auth_chain_cache.lock().unwrap();
*c = LruCache::new(c.capacity());
}
if amount > 3 {
let c = &mut *self.eventidshort_cache.lock().unwrap();
*c = LruCache::new(c.capacity());
}
if amount > 4 {
let c = &mut *self.statekeyshort_cache.lock().unwrap();
*c = LruCache::new(c.capacity());
}
if amount > 5 {
if amount > 2 {
let c = &mut *self.our_real_users_cache.write().unwrap();
*c = HashMap::new();
}
if amount > 6 {
if amount > 3 {
let c = &mut *self.appservice_in_room_cache.write().unwrap();
*c = HashMap::new();
}
if amount > 7 {
if amount > 4 {
let c = &mut *self.lasttimelinecount_cache.lock().unwrap();
*c = HashMap::new();
}

View file

@ -7,10 +7,6 @@ use crate::{database::KeyValueDatabase, service, services, utils, Error, Result}
impl service::rooms::short::Data for KeyValueDatabase {
fn get_or_create_shorteventid(&self, event_id: &EventId) -> Result<u64> {
if let Some(short) = self.eventidshort_cache.lock().unwrap().get_mut(event_id) {
return Ok(*short);
}
let short = if let Some(shorteventid) = self.eventid_shorteventid.get(event_id.as_bytes())? {
utils::u64_from_bytes(&shorteventid).map_err(|_| Error::bad_database("Invalid shorteventid in db."))?
} else {
@ -22,24 +18,10 @@ impl service::rooms::short::Data for KeyValueDatabase {
shorteventid
};
self.eventidshort_cache
.lock()
.unwrap()
.insert(event_id.to_owned(), short);
Ok(short)
}
fn get_shortstatekey(&self, event_type: &StateEventType, state_key: &str) -> Result<Option<u64>> {
if let Some(short) = self
.statekeyshort_cache
.lock()
.unwrap()
.get_mut(&(event_type.clone(), state_key.to_owned()))
{
return Ok(Some(*short));
}
let mut statekey_vec = event_type.to_string().as_bytes().to_vec();
statekey_vec.push(0xFF);
statekey_vec.extend_from_slice(state_key.as_bytes());
@ -52,26 +34,10 @@ impl service::rooms::short::Data for KeyValueDatabase {
})
.transpose()?;
if let Some(s) = short {
self.statekeyshort_cache
.lock()
.unwrap()
.insert((event_type.clone(), state_key.to_owned()), s);
}
Ok(short)
}
fn get_or_create_shortstatekey(&self, event_type: &StateEventType, state_key: &str) -> Result<u64> {
if let Some(short) = self
.statekeyshort_cache
.lock()
.unwrap()
.get_mut(&(event_type.clone(), state_key.to_owned()))
{
return Ok(*short);
}
let mut statekey_vec = event_type.to_string().as_bytes().to_vec();
statekey_vec.push(0xFF);
statekey_vec.extend_from_slice(state_key.as_bytes());
@ -87,24 +53,10 @@ impl service::rooms::short::Data for KeyValueDatabase {
shortstatekey
};
self.statekeyshort_cache
.lock()
.unwrap()
.insert((event_type.clone(), state_key.to_owned()), short);
Ok(short)
}
fn get_eventid_from_short(&self, shorteventid: u64) -> Result<Arc<EventId>> {
if let Some(id) = self
.shorteventid_cache
.lock()
.unwrap()
.get_mut(&shorteventid)
{
return Ok(Arc::clone(id));
}
let bytes = self
.shorteventid_eventid
.get(&shorteventid.to_be_bytes())?
@ -116,24 +68,10 @@ impl service::rooms::short::Data for KeyValueDatabase {
)
.map_err(|_| Error::bad_database("EventId in shorteventid_eventid is invalid."))?;
self.shorteventid_cache
.lock()
.unwrap()
.insert(shorteventid, Arc::clone(&event_id));
Ok(event_id)
}
fn get_statekey_from_short(&self, shortstatekey: u64) -> Result<(StateEventType, String)> {
if let Some(id) = self
.shortstatekey_cache
.lock()
.unwrap()
.get_mut(&shortstatekey)
{
return Ok(id.clone());
}
let bytes = self
.shortstatekey_statekey
.get(&shortstatekey.to_be_bytes())?
@ -155,11 +93,6 @@ impl service::rooms::short::Data for KeyValueDatabase {
let result = (event_type, state_key);
self.shortstatekey_cache
.lock()
.unwrap()
.insert(shortstatekey, result.clone());
Ok(result)
}

View file

@ -89,10 +89,6 @@ impl service::rooms::timeline::Data for KeyValueDatabase {
///
/// Checks the `eventid_outlierpdu` Tree if not found in the timeline.
fn get_pdu(&self, event_id: &EventId) -> Result<Option<Arc<PduEvent>>> {
if let Some(p) = self.pdu_cache.lock().unwrap().get_mut(event_id) {
return Ok(Some(Arc::clone(p)));
}
if let Some(pdu) = self
.get_non_outlier_pdu(event_id)?
.map_or_else(
@ -106,10 +102,6 @@ impl service::rooms::timeline::Data for KeyValueDatabase {
)?
.map(Arc::new)
{
self.pdu_cache
.lock()
.unwrap()
.insert(event_id.to_owned(), Arc::clone(&pdu));
Ok(Some(pdu))
} else {
Ok(None)
@ -166,7 +158,7 @@ impl service::rooms::timeline::Data for KeyValueDatabase {
}
/// Removes a pdu and creates a new one with the same id.
fn replace_pdu(&self, pdu_id: &[u8], pdu_json: &CanonicalJsonObject, pdu: &PduEvent) -> Result<()> {
fn replace_pdu(&self, pdu_id: &[u8], pdu_json: &CanonicalJsonObject, _pdu: &PduEvent) -> Result<()> {
if self.pduid_pdu.get(pdu_id)?.is_some() {
self.pduid_pdu.insert(
pdu_id,
@ -176,11 +168,6 @@ impl service::rooms::timeline::Data for KeyValueDatabase {
return Err(Error::BadRequest(ErrorKind::NotFound, "PDU does not exist."));
}
self.pdu_cache
.lock()
.unwrap()
.remove(&(*pdu.event_id).to_owned());
Ok(())
}

View file

@ -619,7 +619,7 @@ pub(crate) async fn migrations(db: &KeyValueDatabase, config: &Config) -> Result
}
info!(
"Loaded {} database with version {}",
"Loaded {} database with schema version {}",
config.database_backend, latest_database_version
);
} else {

View file

@ -28,10 +28,10 @@ use lru_cache::LruCache;
use ruma::{
events::{
push_rules::PushRulesEventContent, room::message::RoomMessageEventContent, GlobalAccountDataEvent,
GlobalAccountDataEventType, StateEventType,
GlobalAccountDataEventType,
},
push::Ruleset,
CanonicalJsonValue, EventId, OwnedDeviceId, OwnedEventId, OwnedRoomId, OwnedUserId, UserId,
CanonicalJsonValue, OwnedDeviceId, OwnedRoomId, OwnedUserId, UserId,
};
use serde::Deserialize;
#[cfg(unix)]
@ -40,8 +40,8 @@ use tokio::time::{interval, Instant};
use tracing::{debug, error, warn};
use crate::{
database::migrations::migrations, service::rooms::timeline::PduCount, services, Config, Error, PduEvent, Result,
Services, SERVICES,
database::migrations::migrations, service::rooms::timeline::PduCount, services, Config, Error, Result, Services,
SERVICES,
};
pub struct KeyValueDatabase {
@ -181,12 +181,7 @@ pub struct KeyValueDatabase {
//pub pusher: pusher::PushData,
pub(super) senderkey_pusher: Arc<dyn KvTree>,
pub(super) pdu_cache: Mutex<LruCache<OwnedEventId, Arc<PduEvent>>>,
pub(super) shorteventid_cache: Mutex<LruCache<u64, Arc<EventId>>>,
pub(super) auth_chain_cache: Mutex<LruCache<Vec<u64>, Arc<HashSet<u64>>>>,
pub(super) eventidshort_cache: Mutex<LruCache<OwnedEventId, u64>>,
pub(super) statekeyshort_cache: Mutex<LruCache<(StateEventType, String), u64>>,
pub(super) shortstatekey_cache: Mutex<LruCache<u64, (StateEventType, String)>>,
pub(super) our_real_users_cache: RwLock<HashMap<OwnedRoomId, Arc<HashSet<OwnedUserId>>>>,
pub(super) appservice_in_room_cache: RwLock<HashMap<OwnedRoomId, HashMap<String, bool>>>,
pub(super) lasttimelinecount_cache: Mutex<HashMap<OwnedRoomId, PduCount>>,
@ -347,27 +342,9 @@ impl KeyValueDatabase {
global: builder.open_tree("global")?,
server_signingkeys: builder.open_tree("server_signingkeys")?,
pdu_cache: Mutex::new(LruCache::new(
config
.pdu_cache_capacity
.try_into()
.expect("pdu cache capacity fits into usize"),
)),
auth_chain_cache: Mutex::new(LruCache::new(
(f64::from(config.auth_chain_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)),
shorteventid_cache: Mutex::new(LruCache::new(
(f64::from(config.shorteventid_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)),
eventidshort_cache: Mutex::new(LruCache::new(
(f64::from(config.eventidshort_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)),
shortstatekey_cache: Mutex::new(LruCache::new(
(f64::from(config.shortstatekey_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)),
statekeyshort_cache: Mutex::new(LruCache::new(
(f64::from(config.statekeyshort_cache_capacity) * config.conduit_cache_capacity_modifier) as usize,
)),
our_real_users_cache: RwLock::new(HashMap::new()),
appservice_in_room_cache: RwLock::new(HashMap::new()),
lasttimelinecount_cache: Mutex::new(HashMap::new()),

View file

@ -1,9 +1,12 @@
use std::sync::{atomic::AtomicU32, Arc};
use std::{
collections::HashMap,
sync::{atomic::AtomicU32, Arc},
};
use chrono::{DateTime, Utc};
use rust_rocksdb::{
backup::{BackupEngine, BackupEngineOptions},
DBWithThreadMode as Db, MultiThreaded,
Cache, ColumnFamilyDescriptor, DBCommon, DBWithThreadMode as Db, Env, MultiThreaded, Options,
};
use tracing::{debug, error, info, warn};
@ -20,11 +23,11 @@ use super::watchers;
pub(crate) struct Engine {
rocks: Db<MultiThreaded>,
row_cache: rust_rocksdb::Cache,
col_cache: rust_rocksdb::Cache,
row_cache: Cache,
col_cache: HashMap<String, Cache>,
old_cfs: Vec<String>,
opts: rust_rocksdb::Options,
env: rust_rocksdb::Env,
opts: Options,
env: Env,
config: Config,
corks: AtomicU32,
}
@ -32,14 +35,17 @@ pub(crate) struct Engine {
impl KeyValueDatabaseEngine for Arc<Engine> {
fn open(config: &Config) -> Result<Self> {
let cache_capacity_bytes = config.db_cache_capacity_mb * 1024.0 * 1024.0;
let row_cache_capacity_bytes = (cache_capacity_bytes * 0.25) as usize;
let col_cache_capacity_bytes = (cache_capacity_bytes * 0.75) as usize;
let row_cache_capacity_bytes = (cache_capacity_bytes * 0.50) as usize;
let col_cache_capacity_bytes = (cache_capacity_bytes * 0.50) as usize;
let db_env = rust_rocksdb::Env::new()?;
let row_cache = rust_rocksdb::Cache::new_lru_cache(row_cache_capacity_bytes);
let col_cache = rust_rocksdb::Cache::new_lru_cache(col_cache_capacity_bytes);
let db_opts = db_options(config, &db_env, &row_cache, &col_cache);
let mut col_cache = HashMap::new();
col_cache.insert("primary".to_owned(), Cache::new_lru_cache(col_cache_capacity_bytes));
let db_env = Env::new()?;
let row_cache = Cache::new_lru_cache(row_cache_capacity_bytes);
let db_opts = db_options(config, &db_env, &row_cache, col_cache.get("primary").expect("cache"));
let load_time = std::time::Instant::now();
if config.rocksdb_repair {
warn!("Starting database repair. This may take a long time...");
if let Err(e) = Db::<MultiThreaded>::repair(&db_opts, &config.database_path) {
@ -53,7 +59,7 @@ impl KeyValueDatabaseEngine for Arc<Engine> {
debug!("Opening {} column family descriptors in database", cfs.len());
let cfds = cfs
.iter()
.map(|name| rust_rocksdb::ColumnFamilyDescriptor::new(name, cf_options(name, db_opts.clone(), config)))
.map(|name| ColumnFamilyDescriptor::new(name, cf_options(config, name, db_opts.clone(), &mut col_cache)))
.collect::<Vec<_>>();
debug!("Opening database...");
@ -63,7 +69,11 @@ impl KeyValueDatabaseEngine for Arc<Engine> {
Db::<MultiThreaded>::open_cf_descriptors(&db_opts, &config.database_path, cfds)?
};
info!("Opened database at sequence number {}", db.latest_sequence_number());
info!(
"Opened database at sequence number {} in {:?}",
db.latest_sequence_number(),
load_time.elapsed()
);
Ok(Arc::new(Engine {
rocks: db,
row_cache,
@ -91,13 +101,13 @@ impl KeyValueDatabaseEngine for Arc<Engine> {
}
fn flush(&self) -> Result<()> {
rust_rocksdb::DBCommon::flush_wal(&self.rocks, false)?;
DBCommon::flush_wal(&self.rocks, false)?;
Ok(())
}
fn sync(&self) -> Result<()> {
rust_rocksdb::DBCommon::flush_wal(&self.rocks, true)?;
DBCommon::flush_wal(&self.rocks, true)?;
Ok(())
}
@ -119,31 +129,34 @@ impl KeyValueDatabaseEngine for Arc<Engine> {
}
fn memory_usage(&self) -> Result<String> {
let stats = rust_rocksdb::perf::get_memory_usage_stats(
Some(&[&self.rocks]),
Some(&[&self.row_cache, &self.col_cache]),
)?;
Ok(format!(
"Approximate memory usage of all the mem-tables: {:.3} MB\nApproximate memory usage of un-flushed \
mem-tables: {:.3} MB\nApproximate memory usage of all the table readers: {:.3} MB\nApproximate memory \
usage by cache: {:.3} MB\nApproximate memory usage by row cache: {:.3} MB pinned: {:.3} MB\nApproximate \
memory usage by column cache: {:.3} MB pinned: {:.3} MB\n",
let mut res = String::new();
let stats = rust_rocksdb::perf::get_memory_usage_stats(Some(&[&self.rocks]), Some(&[&self.row_cache]))?;
_ = std::fmt::write(
&mut res,
format_args!(
"Memory buffers: {:.2} MiB\nPending write: {:.2} MiB\nTable readers: {:.2} MiB\nRow cache: {:.2} MiB\n",
stats.mem_table_total as f64 / 1024.0 / 1024.0,
stats.mem_table_unflushed as f64 / 1024.0 / 1024.0,
stats.mem_table_readers_total as f64 / 1024.0 / 1024.0,
stats.cache_total as f64 / 1024.0 / 1024.0,
self.row_cache.get_usage() as f64 / 1024.0 / 1024.0,
self.row_cache.get_pinned_usage() as f64 / 1024.0 / 1024.0,
self.col_cache.get_usage() as f64 / 1024.0 / 1024.0,
self.col_cache.get_pinned_usage() as f64 / 1024.0 / 1024.0,
))
),
);
for (name, cache) in &self.col_cache {
_ = std::fmt::write(
&mut res,
format_args!("{} cache: {:.2} MiB\n", name, cache.get_usage() as f64 / 1024.0 / 1024.0,),
);
}
Ok(res)
}
fn cleanup(&self) -> Result<()> {
debug!("Running flush_opt");
let flushoptions = rust_rocksdb::FlushOptions::default();
rust_rocksdb::DBCommon::flush_opt(&self.rocks, &flushoptions)?;
DBCommon::flush_opt(&self.rocks, &flushoptions)?;
Ok(())
}

View file

@ -1,5 +1,7 @@
#![allow(dead_code)]
use std::collections::HashMap;
use rust_rocksdb::{
BlockBasedOptions, Cache, DBCompactionStyle, DBCompressionType, DBRecoveryMode, Env, LogLevel, Options,
UniversalCompactOptions, UniversalCompactionStopStyle,
@ -43,6 +45,7 @@ pub(crate) fn db_options(config: &Config, env: &Env, row_cache: &Cache, col_cach
// Blocks
let mut table_opts = table_options(config);
table_opts.set_block_cache(col_cache);
opts.set_block_based_table_factory(&table_opts);
opts.set_row_cache(row_cache);
// Buffers
@ -75,7 +78,6 @@ pub(crate) fn db_options(config: &Config, env: &Env, row_cache: &Cache, col_cach
4_u8..=u8::MAX => unimplemented!(),
});
opts.set_block_based_table_factory(&table_opts);
opts.set_env(env);
opts
}
@ -83,7 +85,8 @@ pub(crate) fn db_options(config: &Config, env: &Env, row_cache: &Cache, col_cach
/// Adjust options for the specific column by name. Provide the result of
/// db_options() as the argument to this function and use the return value in
/// the arguments to open the specific column.
pub(crate) fn cf_options(name: &str, mut opts: Options, config: &Config) -> Options {
pub(crate) fn cf_options(cfg: &Config, name: &str, mut opts: Options, cache: &mut HashMap<String, Cache>) -> Options {
// Columns with non-default compaction options
match name {
"backupid_algorithm"
| "backupid_etag"
@ -94,7 +97,52 @@ pub(crate) fn cf_options(name: &str, mut opts: Options, config: &Config) -> Opti
| "shortstatekey_statekey"
| "shortstatehash_statediff"
| "userdevicetxnid_response"
| "userfilterid_filter" => set_for_sequential_small_uc(&mut opts, config),
| "userfilterid_filter" => set_for_sequential_small_uc(&mut opts, cfg),
&_ => {},
}
// Columns with non-default table/cache configs
match name {
"shorteventid_eventid" => set_table_with_new_cache(
&mut opts,
cfg,
cache,
name,
cache_size(cfg, cfg.shorteventid_cache_capacity, 64),
),
"eventid_shorteventid" => set_table_with_new_cache(
&mut opts,
cfg,
cache,
name,
cache_size(cfg, cfg.eventidshort_cache_capacity, 64),
),
"shorteventid_authchain" => {
set_table_with_new_cache(&mut opts, cfg, cache, name, cache_size(cfg, cfg.auth_chain_cache_capacity, 192));
},
"shortstatekey_statekey" => set_table_with_new_cache(
&mut opts,
cfg,
cache,
name,
cache_size(cfg, cfg.shortstatekey_cache_capacity, 1024),
),
"statekey_shortstatekey" => set_table_with_new_cache(
&mut opts,
cfg,
cache,
name,
cache_size(cfg, cfg.statekeyshort_cache_capacity, 1024),
),
"pduid_pdu" => set_table_with_new_cache(&mut opts, cfg, cache, name, cfg.pdu_cache_capacity as usize * 1536),
"eventid_outlierpdu" => set_table_with_shared_cache(&mut opts, cfg, cache, name, "pduid_pdu"),
&_ => {},
}
@ -220,6 +268,31 @@ fn uc_options(_config: &Config) -> UniversalCompactOptions {
opts
}
fn set_table_with_new_cache(
opts: &mut Options, config: &Config, cache: &mut HashMap<String, Cache>, name: &str, size: usize,
) {
cache.insert(name.to_owned(), Cache::new_lru_cache(size));
set_table_with_shared_cache(opts, config, cache, name, name);
}
fn set_table_with_shared_cache(
opts: &mut Options, config: &Config, cache: &HashMap<String, Cache>, _name: &str, cache_name: &str,
) {
let mut table = table_options(config);
table.set_block_cache(
cache
.get(cache_name)
.expect("existing cache to share with this column"),
);
opts.set_block_based_table_factory(&table);
}
fn cache_size(config: &Config, base_size: u32, entity_size: usize) -> usize {
let ents = f64::from(base_size) * config.conduit_cache_capacity_modifier;
ents as usize * entity_size
}
fn table_options(_config: &Config) -> BlockBasedOptions {
let mut opts = BlockBasedOptions::default();

View file

@ -268,9 +268,7 @@ async fn stop(_server: &Server) -> io::Result<()> {
/// Async initializations
async fn start(server: &Server) -> Result<(), Error> {
let db_load_time = std::time::Instant::now();
KeyValueDatabase::load_or_create(server.config.clone(), server.tracing_reload_handle.clone()).await?;
info!("Database took {:?} to load", db_load_time.elapsed());
Ok(())
}

View file

@ -72,8 +72,6 @@ impl Services<'_> {
},
auth_chain: rooms::auth_chain::Service {
db,
shorteventid_cache_capacity: (f64::from(config.shorteventid_cache_capacity)
* config.conduit_cache_capacity_modifier) as usize,
},
directory: rooms::directory::Service {
db,

View file

@ -12,7 +12,6 @@ use crate::{services, Error, Result};
pub struct Service {
pub db: &'static dyn Data,
pub(crate) shorteventid_cache_capacity: usize,
}
impl Service {
@ -117,15 +116,6 @@ impl Service {
"Auth chain stats",
);
if full_auth_chain.len() > self.shorteventid_cache_capacity {
warn!(
"Room {room_id} requires cache size of {} but it is set to {}. Increase 'shorteventid_cache_capacity' \
in your config file.",
full_auth_chain.len(),
self.shorteventid_cache_capacity,
);
}
Ok(full_auth_chain
.into_iter()
.filter_map(move |sid| services().rooms.short.get_eventid_from_short(sid).ok()))