From f36a5b8cd71fc2185d55f098b4b62307431db506 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Tue, 13 Jun 2023 12:34:19 +0100 Subject: [PATCH] Deserialise events early so we don't have to do it multiple times We pass the already-deserialised event in to handle_state and process_sliding_sync_room_membership, to avoid deserialising inside both of them. --- crates/matrix-sdk-base/src/client.rs | 43 +++++++++++++------ crates/matrix-sdk-base/src/sliding_sync.rs | 50 ++++++++++++---------- 2 files changed, 58 insertions(+), 35 deletions(-) diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index c08c28e7f..e59e8cbc0 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -17,7 +17,7 @@ use std::ops::Deref; use std::{ collections::{BTreeMap, BTreeSet}, - fmt, + fmt, iter, sync::Arc, }; @@ -478,10 +478,16 @@ impl BaseClient { changes.stripped_state.insert(room_info.room_id().to_owned(), state_events); } + /// Process the events provided during a sync. + /// + /// events must be exactly the same list of events that are in raw_events, + /// but deserialised. We demand them here to avoid deserialising + /// multiple times. #[instrument(skip_all, fields(room_id = ?room_info.room_id))] pub(crate) async fn handle_state( &self, - events: &[Raw], + raw_events: &[Raw], + events: &[AnySyncStateEvent], room_info: &mut RoomInfo, changes: &mut StateChanges, ambiguity_cache: &mut AmbiguityCache, @@ -490,16 +496,8 @@ impl BaseClient { let mut user_ids = BTreeSet::new(); let mut profiles = BTreeMap::new(); - for raw_event in events { - let event = match raw_event.deserialize() { - Ok(ev) => ev, - Err(e) => { - warn!("Couldn't deserialize state event: {e}"); - continue; - } - }; - - room_info.handle_state_event(&event); + for (raw_event, event) in iter::zip(raw_events, events) { + room_info.handle_state_event(event); if let AnySyncStateEvent::RoomMember(member) = &event { ambiguity_cache.handle_event(changes, &room_info.room_id, member).await?; @@ -714,9 +712,12 @@ impl BaseClient { room_info.set_prev_batch(new_info.timeline.prev_batch.as_deref()); room_info.mark_state_fully_synced(); + let deserialized_events = Self::deserialize_events(&new_info.state.events); + let mut user_ids = self .handle_state( &new_info.state.events, + &deserialized_events, &mut room_info, &mut changes, &mut ambiguity_cache, @@ -800,9 +801,12 @@ impl BaseClient { room_info.mark_as_left(); room_info.mark_state_partially_synced(); + let deserialized_events = Self::deserialize_events(&new_info.state.events); + let mut user_ids = self .handle_state( &new_info.state.events, + &deserialized_events, &mut room_info, &mut changes, &mut ambiguity_cache, @@ -1242,6 +1246,21 @@ impl BaseClient { pub fn subscribe_to_ignore_user_list_changes(&self) -> Subscriber<()> { self.ignore_user_list_changes_tx.subscribe() } + + pub(crate) fn deserialize_events( + raw_events: &[Raw], + ) -> Vec { + raw_events + .iter() + .filter_map(|raw_event| match raw_event.deserialize() { + Ok(ev) => Some(ev), + Err(e) => { + warn!("Couldn't deserialize state event: {e}"); + None + } + }) + .collect() + } } impl Default for BaseClient { diff --git a/crates/matrix-sdk-base/src/sliding_sync.rs b/crates/matrix-sdk-base/src/sliding_sync.rs index 5d11b2976..5e6674a1a 100644 --- a/crates/matrix-sdk-base/src/sliding_sync.rs +++ b/crates/matrix-sdk-base/src/sliding_sync.rs @@ -21,10 +21,9 @@ use ruma::{ v4::{self, AccountData}, }, events::AnySyncStateEvent, - serde::Raw, RoomId, }; -use tracing::{debug, info, instrument, warn}; +use tracing::{debug, info, instrument}; use super::BaseClient; #[cfg(feature = "e2e-encryption")] @@ -193,15 +192,30 @@ impl BaseClient { ambiguity_cache: &mut AmbiguityCache, account_data: &AccountData, ) -> Result<(RoomInfo, Option, Option)> { + let required_state = Self::deserialize_events(&room_data.required_state); + // Find or create the room in the store - let (room, mut room_info, invited_room) = - self.process_sliding_sync_room_membership(room_data, store, room_id, changes).await; + let (room, mut room_info, invited_room) = self + .process_sliding_sync_room_membership( + room_data, + &required_state, + store, + room_id, + changes, + ) + .await; room_info.mark_state_partially_synced(); - let mut user_ids = if !room_data.required_state.is_empty() { - self.handle_state(&room_data.required_state, &mut room_info, changes, ambiguity_cache) - .await? + let mut user_ids = if !required_state.is_empty() { + self.handle_state( + &room_data.required_state, + &required_state, + &mut room_info, + changes, + ambiguity_cache, + ) + .await? } else { Default::default() }; @@ -276,6 +290,7 @@ impl BaseClient { async fn process_sliding_sync_room_membership( &self, room_data: &v4::SlidingSyncRoom, + required_state: &[AnySyncStateEvent], store: &Store, room_id: &RoomId, changes: &mut StateChanges, @@ -319,31 +334,20 @@ impl BaseClient { // property. In sliding sync we only have invite_state and // required_state, so we must process required_state looking for // relevant membership events. - self.handle_own_room_membership(&room_data.required_state, &mut room_info).await; + self.handle_own_room_membership(required_state, &mut room_info).await; (room, room_info, None) } } - /// Find any m.room.member events that refer to the current user, and update the state in - /// room_info to reflect the "membership" property. + /// Find any m.room.member events that refer to the current user, and update + /// the state in room_info to reflect the "membership" property. pub(crate) async fn handle_own_room_membership( &self, - required_state: &[Raw], + required_state: &[AnySyncStateEvent], room_info: &mut RoomInfo, ) { - // Note: we deserialise these same events inside handle_state(). We could refactor to do - // this only once. - - for raw_event in required_state { - let event = match raw_event.deserialize() { - Ok(ev) => ev, - Err(e) => { - warn!("Couldn't deserialize state event: {e}"); - continue; - } - }; - + for event in required_state { if let AnySyncStateEvent::RoomMember(member) = &event { // If this event updates the current user's membership, record that in the // room_info.