improvement: better prev event fetching, perf improvements

next
Timo Kösters 2021-08-17 16:06:09 +02:00
parent 75ba8bb565
commit bf7e019a68
No known key found for this signature in database
GPG Key ID: 24DA7517711A2BA4
4 changed files with 202 additions and 69 deletions

View File

@ -733,7 +733,7 @@ pub async fn deactivate_route(
pub async fn third_party_route( pub async fn third_party_route(
body: Ruma<get_contacts::Request>, body: Ruma<get_contacts::Request>,
) -> ConduitResult<get_contacts::Response> { ) -> ConduitResult<get_contacts::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated"); let _sender_user = body.sender_user.as_ref().expect("user is authenticated");
Ok(get_contacts::Response::new(Vec::new()).into()) Ok(get_contacts::Response::new(Vec::new()).into())
} }

View File

@ -278,6 +278,8 @@ impl Database {
pdu_cache: Mutex::new(LruCache::new(100_000)), pdu_cache: Mutex::new(LruCache::new(100_000)),
auth_chain_cache: Mutex::new(LruCache::new(100_000)), auth_chain_cache: Mutex::new(LruCache::new(100_000)),
shorteventid_cache: Mutex::new(LruCache::new(1_000_000)), shorteventid_cache: Mutex::new(LruCache::new(1_000_000)),
eventidshort_cache: Mutex::new(LruCache::new(1_000_000)),
statekeyshort_cache: Mutex::new(LruCache::new(1_000_000)),
stateinfo_cache: Mutex::new(LruCache::new(1000)), stateinfo_cache: Mutex::new(LruCache::new(1000)),
}, },
account_data: account_data::AccountData { account_data: account_data::AccountData {

View File

@ -92,6 +92,8 @@ pub struct Rooms {
pub(super) pdu_cache: Mutex<LruCache<EventId, Arc<PduEvent>>>, pub(super) pdu_cache: Mutex<LruCache<EventId, Arc<PduEvent>>>,
pub(super) auth_chain_cache: Mutex<LruCache<u64, HashSet<u64>>>, pub(super) auth_chain_cache: Mutex<LruCache<u64, HashSet<u64>>>,
pub(super) shorteventid_cache: Mutex<LruCache<u64, EventId>>, pub(super) shorteventid_cache: Mutex<LruCache<u64, EventId>>,
pub(super) eventidshort_cache: Mutex<LruCache<EventId, u64>>,
pub(super) statekeyshort_cache: Mutex<LruCache<(EventType, String), u64>>,
pub(super) stateinfo_cache: Mutex< pub(super) stateinfo_cache: Mutex<
LruCache< LruCache<
u64, u64,
@ -665,7 +667,11 @@ impl Rooms {
event_id: &EventId, event_id: &EventId,
globals: &super::globals::Globals, globals: &super::globals::Globals,
) -> Result<u64> { ) -> Result<u64> {
Ok(match self.eventid_shorteventid.get(event_id.as_bytes())? { if let Some(short) = self.eventidshort_cache.lock().unwrap().get_mut(&event_id) {
return Ok(*short);
}
let short = match self.eventid_shorteventid.get(event_id.as_bytes())? {
Some(shorteventid) => utils::u64_from_bytes(&shorteventid) Some(shorteventid) => utils::u64_from_bytes(&shorteventid)
.map_err(|_| Error::bad_database("Invalid shorteventid in db."))?, .map_err(|_| Error::bad_database("Invalid shorteventid in db."))?,
None => { None => {
@ -676,7 +682,14 @@ impl Rooms {
.insert(&shorteventid.to_be_bytes(), event_id.as_bytes())?; .insert(&shorteventid.to_be_bytes(), event_id.as_bytes())?;
shorteventid shorteventid
} }
}) };
self.eventidshort_cache
.lock()
.unwrap()
.insert(event_id.clone(), short);
Ok(short)
} }
pub fn get_shortroomid(&self, room_id: &RoomId) -> Result<Option<u64>> { pub fn get_shortroomid(&self, room_id: &RoomId) -> Result<Option<u64>> {
@ -694,17 +707,36 @@ impl Rooms {
event_type: &EventType, event_type: &EventType,
state_key: &str, state_key: &str,
) -> Result<Option<u64>> { ) -> 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 = event_type.as_ref().as_bytes().to_vec(); let mut statekey = event_type.as_ref().as_bytes().to_vec();
statekey.push(0xff); statekey.push(0xff);
statekey.extend_from_slice(&state_key.as_bytes()); statekey.extend_from_slice(&state_key.as_bytes());
self.statekey_shortstatekey let short = self
.statekey_shortstatekey
.get(&statekey)? .get(&statekey)?
.map(|shortstatekey| { .map(|shortstatekey| {
utils::u64_from_bytes(&shortstatekey) utils::u64_from_bytes(&shortstatekey)
.map_err(|_| Error::bad_database("Invalid shortstatekey in db.")) .map_err(|_| Error::bad_database("Invalid shortstatekey in db."))
}) })
.transpose() .transpose()?;
if let Some(s) = short {
self.statekeyshort_cache
.lock()
.unwrap()
.insert((event_type.clone(), state_key.to_owned()), s);
}
Ok(short)
} }
pub fn get_or_create_shortroomid( pub fn get_or_create_shortroomid(
@ -730,11 +762,20 @@ impl Rooms {
state_key: &str, state_key: &str,
globals: &super::globals::Globals, globals: &super::globals::Globals,
) -> Result<u64> { ) -> 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 = event_type.as_ref().as_bytes().to_vec(); let mut statekey = event_type.as_ref().as_bytes().to_vec();
statekey.push(0xff); statekey.push(0xff);
statekey.extend_from_slice(&state_key.as_bytes()); statekey.extend_from_slice(&state_key.as_bytes());
Ok(match self.statekey_shortstatekey.get(&statekey)? { let short = match self.statekey_shortstatekey.get(&statekey)? {
Some(shortstatekey) => utils::u64_from_bytes(&shortstatekey) Some(shortstatekey) => utils::u64_from_bytes(&shortstatekey)
.map_err(|_| Error::bad_database("Invalid shortstatekey in db."))?, .map_err(|_| Error::bad_database("Invalid shortstatekey in db."))?,
None => { None => {
@ -743,7 +784,14 @@ impl Rooms {
.insert(&statekey, &shortstatekey.to_be_bytes())?; .insert(&statekey, &shortstatekey.to_be_bytes())?;
shortstatekey shortstatekey
} }
}) };
self.statekeyshort_cache
.lock()
.unwrap()
.insert((event_type.clone(), state_key.to_owned()), short);
Ok(short)
} }
pub fn get_eventid_from_short(&self, shorteventid: u64) -> Result<EventId> { pub fn get_eventid_from_short(&self, shorteventid: u64) -> Result<EventId> {
@ -2173,8 +2221,10 @@ impl Rooms {
} }
} }
if update_joined_count {
self.roomserverids.insert(&roomserver_id, &[])?; self.roomserverids.insert(&roomserver_id, &[])?;
self.serverroomids.insert(&serverroom_id, &[])?; self.serverroomids.insert(&serverroom_id, &[])?;
}
self.userroomid_joined.insert(&userroom_id, &[])?; self.userroomid_joined.insert(&userroom_id, &[])?;
self.roomuserid_joined.insert(&roomuser_id, &[])?; self.roomuserid_joined.insert(&roomuser_id, &[])?;
self.userroomid_invitestate.remove(&userroom_id)?; self.userroomid_invitestate.remove(&userroom_id)?;
@ -2199,8 +2249,10 @@ impl Rooms {
return Ok(()); return Ok(());
} }
if update_joined_count {
self.roomserverids.insert(&roomserver_id, &[])?; self.roomserverids.insert(&roomserver_id, &[])?;
self.serverroomids.insert(&serverroom_id, &[])?; self.serverroomids.insert(&serverroom_id, &[])?;
}
self.userroomid_invitestate.insert( self.userroomid_invitestate.insert(
&userroom_id, &userroom_id,
&serde_json::to_vec(&last_state.unwrap_or_default()) &serde_json::to_vec(&last_state.unwrap_or_default())
@ -2214,6 +2266,7 @@ impl Rooms {
self.roomuserid_leftcount.remove(&roomuser_id)?; self.roomuserid_leftcount.remove(&roomuser_id)?;
} }
member::MembershipState::Leave | member::MembershipState::Ban => { member::MembershipState::Leave | member::MembershipState::Ban => {
if update_joined_count {
if self if self
.room_members(room_id) .room_members(room_id)
.chain(self.room_members_invited(room_id)) .chain(self.room_members_invited(room_id))
@ -2223,6 +2276,7 @@ impl Rooms {
self.roomserverids.remove(&roomserver_id)?; self.roomserverids.remove(&roomserver_id)?;
self.serverroomids.remove(&serverroom_id)?; self.serverroomids.remove(&serverroom_id)?;
} }
}
self.userroomid_leftstate.insert( self.userroomid_leftstate.insert(
&userroom_id, &userroom_id,
&serde_json::to_vec(&Vec::<Raw<AnySyncStateEvent>>::new()).unwrap(), &serde_json::to_vec(&Vec::<Raw<AnySyncStateEvent>>::new()).unwrap(),
@ -2245,10 +2299,52 @@ impl Rooms {
} }
pub fn update_joined_count(&self, room_id: &RoomId) -> Result<()> { pub fn update_joined_count(&self, room_id: &RoomId) -> Result<()> {
self.roomid_joinedcount.insert( let mut joinedcount = 0_u64;
room_id.as_bytes(), let mut joined_servers = HashSet::new();
&(self.room_members(&room_id).count() as u64).to_be_bytes(),
) for joined in self.room_members(&room_id).filter_map(|r| r.ok()) {
joined_servers.insert(joined.server_name().to_owned());
joinedcount += 1;
}
for invited in self.room_members_invited(&room_id).filter_map(|r| r.ok()) {
joined_servers.insert(invited.server_name().to_owned());
}
self.roomid_joinedcount
.insert(room_id.as_bytes(), &joinedcount.to_be_bytes())?;
for old_joined_server in self.room_servers(room_id).filter_map(|r| r.ok()) {
if !joined_servers.remove(&old_joined_server) {
// Server not in room anymore
let mut roomserver_id = room_id.as_bytes().to_vec();
roomserver_id.push(0xff);
roomserver_id.extend_from_slice(old_joined_server.as_bytes());
let mut serverroom_id = old_joined_server.as_bytes().to_vec();
serverroom_id.push(0xff);
serverroom_id.extend_from_slice(room_id.as_bytes());
self.roomserverids.remove(&roomserver_id)?;
self.serverroomids.remove(&serverroom_id)?;
}
}
// Now only new servers are in joined_servers anymore
for server in joined_servers {
let mut roomserver_id = room_id.as_bytes().to_vec();
roomserver_id.push(0xff);
roomserver_id.extend_from_slice(server.as_bytes());
let mut serverroom_id = server.as_bytes().to_vec();
serverroom_id.push(0xff);
serverroom_id.extend_from_slice(room_id.as_bytes());
self.roomserverids.insert(&roomserver_id, &[])?;
self.serverroomids.insert(&serverroom_id, &[])?;
}
Ok(())
} }
pub async fn leave_room( pub async fn leave_room(

View File

@ -272,14 +272,20 @@ where
if status == 200 { if status == 200 {
let response = T::IncomingResponse::try_from_http_response(http_response); let response = T::IncomingResponse::try_from_http_response(http_response);
response.map_err(|e| { response.map_err(|e| {
warn!("Invalid 200 response from {}: {}", &destination, e); warn!(
"Invalid 200 response from {} on: {} {}",
&destination, url, e
);
Error::BadServerResponse("Server returned bad 200 response.") Error::BadServerResponse("Server returned bad 200 response.")
}) })
} else { } else {
Err(Error::FederationError( Err(Error::FederationError(
destination.to_owned(), destination.to_owned(),
RumaError::try_from_http_response(http_response).map_err(|e| { RumaError::try_from_http_response(http_response).map_err(|e| {
warn!("Server returned bad error response: {}", e); warn!(
"Invalid {} response from {} on: {} {}",
status, &destination, url, e
);
Error::BadServerResponse("Server returned bad error response.") Error::BadServerResponse("Server returned bad error response.")
})?, })?,
)) ))
@ -884,15 +890,10 @@ pub async fn handle_incoming_pdu<'a>(
} }
// 9. Fetch any missing prev events doing all checks listed here starting at 1. These are timeline events // 9. Fetch any missing prev events doing all checks listed here starting at 1. These are timeline events
let mut visited = HashSet::new(); let mut graph = HashMap::new();
let mut eventid_info = HashMap::new();
let mut todo_outlier_stack = incoming_pdu.prev_events.clone(); let mut todo_outlier_stack = incoming_pdu.prev_events.clone();
let mut todo_timeline_stack = Vec::new();
while let Some(prev_event_id) = todo_outlier_stack.pop() { while let Some(prev_event_id) = todo_outlier_stack.pop() {
if visited.contains(&prev_event_id) {
continue;
}
visited.insert(prev_event_id.clone());
if let Some((pdu, json_opt)) = fetch_and_handle_outliers( if let Some((pdu, json_opt)) = fetch_and_handle_outliers(
db, db,
origin, origin,
@ -914,17 +915,50 @@ pub async fn handle_incoming_pdu<'a>(
.expect("Room exists") .expect("Room exists")
.origin_server_ts .origin_server_ts
{ {
todo_outlier_stack.extend(pdu.prev_events.iter().cloned()); for prev_prev in &pdu.prev_events {
todo_timeline_stack.push((pdu, json)); if !graph.contains_key(prev_prev) {
todo_outlier_stack.push(dbg!(prev_prev.clone()));
} }
} }
graph.insert(
prev_event_id.clone(),
pdu.prev_events.iter().cloned().collect(),
);
eventid_info.insert(prev_event_id.clone(), (pdu, json));
} else {
graph.insert(prev_event_id.clone(), HashSet::new());
eventid_info.insert(prev_event_id.clone(), (pdu, json));
}
} else {
graph.insert(prev_event_id.clone(), HashSet::new());
}
} }
} }
while let Some(prev) = todo_timeline_stack.pop() { let sorted =
state_res::StateResolution::lexicographical_topological_sort(dbg!(&graph), |event_id| {
// This return value is the key used for sorting events,
// events are then sorted by power level, time,
// and lexically by event_id.
println!("{}", event_id);
Ok((
0,
MilliSecondsSinceUnixEpoch(
eventid_info
.get(event_id)
.map_or_else(|| uint!(0), |info| info.0.origin_server_ts.clone()),
),
ruma::event_id!("$notimportant"),
))
})
.map_err(|_| "Error sorting prev events".to_owned())?;
for prev_id in dbg!(sorted) {
if let Some((pdu, json)) = eventid_info.remove(&prev_id) {
upgrade_outlier_to_timeline_pdu( upgrade_outlier_to_timeline_pdu(
prev.0, pdu,
prev.1, json,
&create_event, &create_event,
origin, origin,
db, db,
@ -933,6 +967,7 @@ pub async fn handle_incoming_pdu<'a>(
) )
.await?; .await?;
} }
}
upgrade_outlier_to_timeline_pdu( upgrade_outlier_to_timeline_pdu(
incoming_pdu, incoming_pdu,
@ -1872,8 +1907,7 @@ fn get_auth_chain(
full_auth_chain.extend(cached.iter().cloned()); full_auth_chain.extend(cached.iter().cloned());
} else { } else {
drop(cache); drop(cache);
let mut auth_chain = HashSet::new(); let auth_chain = get_auth_chain_inner(&event_id, db)?;
get_auth_chain_recursive(&event_id, &mut auth_chain, db)?;
cache = db.rooms.auth_chain_cache(); cache = db.rooms.auth_chain_cache();
cache.insert(sevent_id, auth_chain.clone()); cache.insert(sevent_id, auth_chain.clone());
full_auth_chain.extend(auth_chain); full_auth_chain.extend(auth_chain);
@ -1887,33 +1921,34 @@ fn get_auth_chain(
.filter_map(move |sid| db.rooms.get_eventid_from_short(sid).ok())) .filter_map(move |sid| db.rooms.get_eventid_from_short(sid).ok()))
} }
fn get_auth_chain_recursive( fn get_auth_chain_inner(event_id: &EventId, db: &Database) -> Result<HashSet<u64>> {
event_id: &EventId, let mut todo = vec![event_id.clone()];
found: &mut HashSet<u64>, let mut found = HashSet::new();
db: &Database,
) -> Result<()> { while let Some(event_id) = todo.pop() {
let r = db.rooms.get_pdu(&event_id); match db.rooms.get_pdu(&event_id) {
match r {
Ok(Some(pdu)) => { Ok(Some(pdu)) => {
for auth_event in &pdu.auth_events { for auth_event in &pdu.auth_events {
let sauthevent = db let sauthevent = db
.rooms .rooms
.get_or_create_shorteventid(auth_event, &db.globals)?; .get_or_create_shorteventid(auth_event, &db.globals)?;
if !found.contains(&sauthevent) { if !found.contains(&sauthevent) {
found.insert(sauthevent); found.insert(sauthevent);
get_auth_chain_recursive(&auth_event, found, db)?; todo.push(auth_event.clone());
} }
} }
} }
Ok(None) => { Ok(None) => {
warn!("Could not find pdu mentioned in auth events."); warn!("Could not find pdu mentioned in auth events: {}", event_id);
} }
Err(e) => { Err(e) => {
warn!("Could not load event in auth chain: {}", e); warn!("Could not load event in auth chain: {} {}", event_id, e);
}
} }
} }
Ok(()) Ok(found)
} }
#[cfg_attr( #[cfg_attr(