Add docs and rename _get_event -> get_or_load_event

This commit is contained in:
Devin Ragotzy 2020-08-14 15:49:43 -04:00
parent d22d83522b
commit ccc75313c5

View File

@ -45,6 +45,19 @@ pub struct StateResolution;
impl StateResolution { impl StateResolution {
/// Resolve sets of state events as they come in. Internally `StateResolution` builds a graph /// Resolve sets of state events as they come in. Internally `StateResolution` builds a graph
/// and an auth chain to allow for state conflict resolution. /// and an auth chain to allow for state conflict resolution.
///
/// ## Arguments
///
/// * `state_sets` - The incoming state to resolve. Each `StateMap` represents a possible fork
/// in the state of a room.
///
/// * `event_map` - The `EventMap` acts as a local cache of state, any event that is not found
/// in the `event_map` will be fetched from the `StateStore` and cached in the `event_map`. There
/// is no state kept from separate `resolve` calls, although this could be a potential optimization
/// in the future.
///
/// * `store` - Any type that implements `StateStore` acts as the database. When an event is not
/// found in the `event_map` it will be retrieved from the `store`.
pub fn resolve( pub fn resolve(
&self, &self,
room_id: &RoomId, room_id: &RoomId,
@ -134,7 +147,7 @@ impl StateResolution {
let mut sorted_power_levels = self.reverse_topological_power_sort( let mut sorted_power_levels = self.reverse_topological_power_sort(
room_id, room_id,
&power_events, &power_events,
&mut event_map, // TODO use event_map &mut event_map,
store, store,
&all_conflicted, &all_conflicted,
); );
@ -217,7 +230,6 @@ impl StateResolution {
// add unconflicted state to the resolved state // add unconflicted state to the resolved state
resolved_state.extend(clean); resolved_state.extend(clean);
// TODO return something not a place holder
Ok(ResolutionResult::Resolved(resolved_state)) Ok(ResolutionResult::Resolved(resolved_state))
} }
@ -275,7 +287,7 @@ impl StateResolution {
(unconflicted_state, conflicted_state) (unconflicted_state, conflicted_state)
} }
/// Returns a Vec of deduped EventIds that appear in some chains but no others. /// Returns a Vec of deduped EventIds that appear in some chains but not others.
pub fn get_auth_chain_diff( pub fn get_auth_chain_diff(
&self, &self,
room_id: &RoomId, room_id: &RoomId,
@ -298,6 +310,12 @@ impl StateResolution {
.map_err(Error::TempString) .map_err(Error::TempString)
} }
/// Events are sorted from "earliest" to "latest". They are compared using
/// the negative power level, the origin server timestamp and incase of a
/// tie the `EventId`s are compared lexicographically.
///
/// The power level is negative because a higher power level is equated to an
/// earlier (further back in time) origin server timestamp.
pub fn reverse_topological_power_sort( pub fn reverse_topological_power_sort(
&self, &self,
room_id: &RoomId, room_id: &RoomId,
@ -426,6 +444,7 @@ impl StateResolution {
sorted sorted
} }
/// Find the power level for the sender of `event_id` or return a default value of zero.
fn get_power_level_for_sender( fn get_power_level_for_sender(
&self, &self,
room_id: &RoomId, room_id: &RoomId,
@ -433,14 +452,15 @@ impl StateResolution {
event_map: &mut EventMap<StateEvent>, event_map: &mut EventMap<StateEvent>,
store: &dyn StateStore, store: &dyn StateStore,
) -> i64 { ) -> i64 {
tracing::info!("fetch event senders ({}) power level", event_id.to_string()); tracing::info!("fetch event ({}) senders power level", event_id.to_string());
let event = self._get_event(room_id, event_id, event_map, store);
let event = self.get_or_load_event(room_id, event_id, event_map, store);
let mut pl = None; let mut pl = None;
// TODO store.auth_event_ids returns "self" with the event ids is this ok // TODO store.auth_event_ids returns "self" with the event ids is this ok
// event.auth_event_ids does not include its own event id ? // event.auth_event_ids does not include its own event id ?
for aid in event.as_ref().unwrap().auth_events() { for aid in event.as_ref().unwrap().auth_events() {
if let Some(aev) = self._get_event(room_id, &aid, event_map, store) { if let Some(aev) = self.get_or_load_event(room_id, &aid, event_map, store) {
if aev.is_type_and_key(EventType::RoomPowerLevels, "") { if aev.is_type_and_key(EventType::RoomPowerLevels, "") {
pl = Some(aev); pl = Some(aev);
break; break;
@ -492,7 +512,7 @@ impl StateResolution {
room_version: &RoomVersionId, room_version: &RoomVersionId,
power_events: &[EventId], power_events: &[EventId],
unconflicted_state: &StateMap<EventId>, unconflicted_state: &StateMap<EventId>,
event_map: &mut EventMap<StateEvent>, // TODO use event_map over store ?? event_map: &mut EventMap<StateEvent>,
store: &dyn StateStore, store: &dyn StateStore,
) -> Result<StateMap<EventId>> { ) -> Result<StateMap<EventId>> {
tracing::info!("starting iterative auth check"); tracing::info!("starting iterative auth check");
@ -509,12 +529,12 @@ impl StateResolution {
for (idx, event_id) in power_events.iter().enumerate() { for (idx, event_id) in power_events.iter().enumerate() {
let event = self let event = self
._get_event(room_id, event_id, event_map, store) .get_or_load_event(room_id, event_id, event_map, store)
.unwrap(); .unwrap();
let mut auth_events = BTreeMap::new(); let mut auth_events = BTreeMap::new();
for aid in event.auth_events() { for aid in event.auth_events() {
if let Some(ev) = self._get_event(room_id, &aid, event_map, store) { if let Some(ev) = self.get_or_load_event(room_id, &aid, event_map, store) {
// TODO what to do when no state_key is found ?? // TODO what to do when no state_key is found ??
// TODO synapse check "rejected_reason", I'm guessing this is redacted_because for ruma ?? // TODO synapse check "rejected_reason", I'm guessing this is redacted_because for ruma ??
auth_events.insert((ev.kind(), ev.state_key()), ev); auth_events.insert((ev.kind(), ev.state_key()), ev);
@ -530,7 +550,7 @@ impl StateResolution {
event.content().clone(), event.content().clone(),
) { ) {
if let Some(ev_id) = resolved_state.get(&key) { if let Some(ev_id) = resolved_state.get(&key) {
if let Some(event) = self._get_event(room_id, ev_id, event_map, store) { if let Some(event) = self.get_or_load_event(room_id, ev_id, event_map, store) {
// TODO synapse checks `rejected_reason` is None here // TODO synapse checks `rejected_reason` is None here
auth_events.insert(key.clone(), event); auth_events.insert(key.clone(), event);
} }
@ -588,11 +608,15 @@ impl StateResolution {
while let Some(p) = pl { while let Some(p) = pl {
mainline.push(p.clone()); mainline.push(p.clone());
let event = self._get_event(room_id, &p, event_map, store).unwrap(); let event = self
.get_or_load_event(room_id, &p, event_map, store)
.unwrap();
let auth_events = event.auth_events(); let auth_events = event.auth_events();
pl = None; pl = None;
for aid in auth_events { for aid in auth_events {
let ev = self._get_event(room_id, &aid, event_map, store).unwrap(); let ev = self
.get_or_load_event(room_id, &aid, event_map, store)
.unwrap();
if ev.is_type_and_key(EventType::RoomPowerLevels, "") { if ev.is_type_and_key(EventType::RoomPowerLevels, "") {
pl = Some(aid.clone()); pl = Some(aid.clone());
break; break;
@ -616,7 +640,7 @@ impl StateResolution {
let mut order_map = BTreeMap::new(); let mut order_map = BTreeMap::new();
for (idx, ev_id) in to_sort.iter().enumerate() { for (idx, ev_id) in to_sort.iter().enumerate() {
let event = self._get_event(room_id, ev_id, event_map, store); let event = self.get_or_load_event(room_id, ev_id, event_map, store);
let depth = self.get_mainline_depth(room_id, event, &mainline_map, event_map, store); let depth = self.get_mainline_depth(room_id, event, &mainline_map, event_map, store);
order_map.insert( order_map.insert(
ev_id, ev_id,
@ -663,7 +687,9 @@ impl StateResolution {
let auth_events = sort_ev.auth_events(); let auth_events = sort_ev.auth_events();
event = None; event = None;
for aid in auth_events { for aid in auth_events {
let aev = self._get_event(room_id, &aid, event_map, store).unwrap(); let aev = self
.get_or_load_event(room_id, &aid, event_map, store)
.unwrap();
if aev.is_type_and_key(EventType::RoomPowerLevels, "") { if aev.is_type_and_key(EventType::RoomPowerLevels, "") {
event = Some(aev.clone()); event = Some(aev.clone());
break; break;
@ -691,7 +717,7 @@ impl StateResolution {
// prefer the store to event as the store filters dedups the events // prefer the store to event as the store filters dedups the events
// otherwise it seems we can loop forever // otherwise it seems we can loop forever
for aid in self for aid in self
._get_event(room_id, &eid, event_map, store) .get_or_load_event(room_id, &eid, event_map, store)
.unwrap() .unwrap()
.auth_events() .auth_events()
{ {
@ -707,8 +733,13 @@ impl StateResolution {
} }
} }
/// TODO update self if we go that route just as event_map will be updated // TODO having the event_map as a field of self would allow us to keep
fn _get_event( // cached state from `resolve` to `resolve` calls, good idea or not?
/// Uses the `event_map` to return the full PDU or fetches from the `StateStore` implementation
/// if the event_map does not have the PDU.
///
/// If the PDU is missing from the `event_map` it is added.
fn get_or_load_event(
&self, &self,
room_id: &RoomId, room_id: &RoomId,
ev_id: &EventId, ev_id: &EventId,
@ -729,6 +760,6 @@ impl StateResolution {
pub fn is_power_event(event_id: &EventId, event_map: &EventMap<StateEvent>) -> bool { pub fn is_power_event(event_id: &EventId, event_map: &EventMap<StateEvent>) -> bool {
match event_map.get(event_id) { match event_map.get(event_id) {
Some(state) => state.is_power_event(), Some(state) => state.is_power_event(),
_ => false, // TODO this shouldn't eat errors? _ => false,
} }
} }