Fix incredubly slow back pagination query

If a client didn't specify a from token when paginating backwards
synapse would attempt to query the (global) maximum topological token.
This a) doesn't make much sense since they're room specific and b) there
are no indices that lets postgres do this efficiently.
This commit is contained in:
Erik Johnston 2016-10-24 13:35:51 +01:00
parent a842fed418
commit d04e2ff3a4
4 changed files with 48 additions and 12 deletions

View File

@ -82,8 +82,8 @@ class MessageHandler(BaseHandler):
room_token = pagin_config.from_token.room_key room_token = pagin_config.from_token.room_key
else: else:
pagin_config.from_token = ( pagin_config.from_token = (
yield self.hs.get_event_sources().get_current_token( yield self.hs.get_event_sources().get_current_token_for_room(
direction='b' room_id=room_id
) )
) )
room_token = pagin_config.from_token.room_key room_token = pagin_config.from_token.room_key

View File

@ -475,8 +475,11 @@ class RoomEventSource(object):
defer.returnValue((events, end_key)) defer.returnValue((events, end_key))
def get_current_key(self, direction='f'): def get_current_key(self):
return self.store.get_room_events_max_id(direction) return self.store.get_room_events_max_id()
def get_current_key_for_room(self, room_id):
return self.store.get_room_events_max_id(room_id)
@defer.inlineCallbacks @defer.inlineCallbacks
def get_pagination_rows(self, user, config, key): def get_pagination_rows(self, user, config, key):

View File

@ -521,13 +521,20 @@ class StreamStore(SQLBaseStore):
) )
@defer.inlineCallbacks @defer.inlineCallbacks
def get_room_events_max_id(self, direction='f'): def get_room_events_max_id(self, room_id=None):
"""Returns the current token for rooms stream.
By default, it returns the current global stream token. Specifying a
`room_id` causes it to return the current room specific topological
token.
"""
token = yield self._stream_id_gen.get_current_token() token = yield self._stream_id_gen.get_current_token()
if direction != 'b': if room_id is None:
defer.returnValue("s%d" % (token,)) defer.returnValue("s%d" % (token,))
else: else:
topo = yield self.runInteraction( topo = yield self.runInteraction(
"_get_max_topological_txn", self._get_max_topological_txn "_get_max_topological_txn", self._get_max_topological_txn,
room_id,
) )
defer.returnValue("t%d-%d" % (topo, token)) defer.returnValue("t%d-%d" % (topo, token))
@ -579,11 +586,11 @@ class StreamStore(SQLBaseStore):
lambda r: r[0][0] if r else 0 lambda r: r[0][0] if r else 0
) )
def _get_max_topological_txn(self, txn): def _get_max_topological_txn(self, txn, room_id):
txn.execute( txn.execute(
"SELECT MAX(topological_ordering) FROM events" "SELECT MAX(topological_ordering) FROM events"
" WHERE outlier = ?", " WHERE room_id = ?",
(False,) (room_id,)
) )
rows = txn.fetchall() rows = txn.fetchall()

View File

@ -41,13 +41,39 @@ class EventSources(object):
self.store = hs.get_datastore() self.store = hs.get_datastore()
@defer.inlineCallbacks @defer.inlineCallbacks
def get_current_token(self, direction='f'): def get_current_token(self):
push_rules_key, _ = self.store.get_push_rules_stream_token() push_rules_key, _ = self.store.get_push_rules_stream_token()
to_device_key = self.store.get_to_device_stream_token() to_device_key = self.store.get_to_device_stream_token()
token = StreamToken( token = StreamToken(
room_key=( room_key=(
yield self.sources["room"].get_current_key(direction) yield self.sources["room"].get_current_key()
),
presence_key=(
yield self.sources["presence"].get_current_key()
),
typing_key=(
yield self.sources["typing"].get_current_key()
),
receipt_key=(
yield self.sources["receipt"].get_current_key()
),
account_data_key=(
yield self.sources["account_data"].get_current_key()
),
push_rules_key=push_rules_key,
to_device_key=to_device_key,
)
defer.returnValue(token)
@defer.inlineCallbacks
def get_current_token_for_room(self, room_id):
push_rules_key, _ = self.store.get_push_rules_stream_token()
to_device_key = self.store.get_to_device_stream_token()
token = StreamToken(
room_key=(
yield self.sources["room"].get_current_key()
), ),
presence_key=( presence_key=(
yield self.sources["presence"].get_current_key() yield self.sources["presence"].get_current_key()