diff options
Diffstat (limited to 'synapse/state.py')
-rw-r--r-- | synapse/state.py | 135 |
1 files changed, 84 insertions, 51 deletions
diff --git a/synapse/state.py b/synapse/state.py index ef1bc470be..78461215ca 100644 --- a/synapse/state.py +++ b/synapse/state.py @@ -93,8 +93,30 @@ class StateHandler(object): if not latest_event_ids: latest_event_ids = yield self.store.get_latest_event_ids_in_room(room_id) - res = yield self.resolve_state_groups(room_id, latest_event_ids) - state = res[1] + _, state = yield self.resolve_state_groups(room_id, latest_event_ids) + + if event_type: + event_id = state.get((event_type, state_key)) + event = None + if event_id: + event = yield self.store.get_event(event_id, allow_none=True) + defer.returnValue(event) + return + + state_map = yield self.store.get_events(state.values(), get_prev_content=False) + state = { + key: state_map[e_id] for key, e_id in state.items() if e_id in state_map + } + + defer.returnValue(state) + + @defer.inlineCallbacks + def get_current_state_ids(self, room_id, event_type=None, state_key="", + latest_event_ids=None): + if not latest_event_ids: + latest_event_ids = yield self.store.get_latest_event_ids_in_room(room_id) + + _, state = yield self.resolve_state_groups(room_id, latest_event_ids) if event_type: defer.returnValue(state.get((event_type, state_key))) @@ -123,27 +145,27 @@ class StateHandler(object): # state. Certainly store.get_current_state won't return any, and # persisting the event won't store the state group. if old_state: - context.current_state = { - (s.type, s.state_key): s for s in old_state + context.current_state_ids = { + (s.type, s.state_key): s.event_id for s in old_state } else: - context.current_state = {} + context.current_state_ids = {} context.prev_state_events = [] context.state_group = None defer.returnValue(context) if old_state: - context.current_state = { - (s.type, s.state_key): s for s in old_state + context.current_state_ids = { + (s.type, s.state_key): s.event_id for s in old_state } context.state_group = None if event.is_state(): key = (event.type, event.state_key) - if key in context.current_state: - replaces = context.current_state[key] - if replaces.event_id != event.event_id: # Paranoia check - event.unsigned["replaces_state"] = replaces.event_id + if key in context.current_state_ids: + replaces = context.current_state_ids[key] + if replaces != event.event_id: # Paranoia check + event.unsigned["replaces_state"] = replaces context.prev_state_events = [] defer.returnValue(context) @@ -159,18 +181,18 @@ class StateHandler(object): event.room_id, [e for e, _ in event.prev_events], ) - group, curr_state, prev_state = ret + group, curr_state = ret - context.current_state = curr_state + context.current_state_ids = curr_state context.state_group = group if not event.is_state() else None if event.is_state(): key = (event.type, event.state_key) - if key in context.current_state: - replaces = context.current_state[key] - event.unsigned["replaces_state"] = replaces.event_id + if key in context.current_state_ids: + replaces = context.current_state_ids[key] + event.unsigned["replaces_state"] = replaces - context.prev_state_events = prev_state + context.prev_state_events = [] defer.returnValue(context) @defer.inlineCallbacks @@ -187,72 +209,83 @@ class StateHandler(object): """ logger.debug("resolve_state_groups event_ids %s", event_ids) - state_groups = yield self.store.get_state_groups( + state_groups_ids = yield self.store.get_state_groups_ids( room_id, event_ids ) logger.debug( "resolve_state_groups state_groups %s", - state_groups.keys() + state_groups_ids.keys() ) - group_names = frozenset(state_groups.keys()) + group_names = frozenset(state_groups_ids.keys()) if len(group_names) == 1: - name, state_list = state_groups.items().pop() - state = { - (e.type, e.state_key): e - for e in state_list - } - prev_state = state.get((event_type, state_key), None) - if prev_state: - prev_state = prev_state.event_id - prev_states = [prev_state] - else: - prev_states = [] + name, state_list = state_groups_ids.items().pop() - defer.returnValue((name, state, prev_states)) + defer.returnValue((name, state_list,)) if self._state_cache is not None: cache = self._state_cache.get(group_names, None) if cache: cache.ts = self.clock.time_msec() - event_dict = yield self.store.get_events(cache.state.values()) - state = {(e.type, e.state_key): e for e in event_dict.values()} - - prev_state = state.get((event_type, state_key), None) - if prev_state: - prev_state = prev_state.event_id - prev_states = [prev_state] - else: - prev_states = [] defer.returnValue( - (cache.state_group, state, prev_states) + (cache.state_group, cache.state,) ) - logger.info("Resolving state for %s with %d groups", room_id, len(state_groups)) - - new_state, prev_states = self._resolve_events( - state_groups.values(), event_type, state_key + logger.info( + "Resolving state for %s with %d groups", room_id, len(state_groups_ids) ) + state = {} + for st in state_groups_ids.values(): + for key, e_id in st.items(): + state.setdefault(key, set()).add(e_id) + + conflicted_state = { + k: list(v) + for k, v in state.items() + if len(v) > 1 + } + + if conflicted_state: + logger.info("Resolving conflicted state for %r", room_id) + state_map = yield self.store.get_events( + [e_id for st in state_groups_ids.values() for e_id in st.values()], + get_prev_content=False + ) + state_sets = [ + [state_map[e_id] for key, e_id in st.items() if e_id in state_map] + for st in state_groups_ids.values() + ] + new_state, _ = self._resolve_events( + state_sets, event_type, state_key + ) + new_state = { + key: e.event_id for key, e in new_state.items() + } + else: + new_state = { + key: e_ids.pop() for key, e_ids in state.items() + } + state_group = None - new_state_event_ids = frozenset(e.event_id for e in new_state.values()) - for sg, events in state_groups.items(): - if new_state_event_ids == frozenset(e.event_id for e in events): + new_state_event_ids = frozenset(new_state.values()) + for sg, events in state_groups_ids.items(): + if new_state_event_ids == frozenset(e_id for e_id in events): state_group = sg break if self._state_cache is not None: cache = _StateCacheEntry( - state={key: event.event_id for key, event in new_state.items()}, + state=new_state, state_group=state_group, ts=self.clock.time_msec() ) self._state_cache[group_names] = cache - defer.returnValue((state_group, new_state, prev_states)) + defer.returnValue((state_group, new_state,)) def resolve_events(self, state_sets, event): logger.info( |