43
43
LoggingDatabaseConnection ,
44
44
LoggingTransaction ,
45
45
make_in_list_sql_clause ,
46
+ make_tuple_in_list_sql_clause ,
46
47
)
47
48
from synapse .storage .databases .main .cache import CacheInvalidationWorkerStore
48
49
from synapse .storage .engines import PostgresEngine
@@ -278,7 +279,7 @@ async def get_e2e_device_keys_and_signatures(
278
279
def _get_e2e_device_keys_txn (
279
280
self ,
280
281
txn : LoggingTransaction ,
281
- query_list : Collection [Tuple [str , str ]],
282
+ query_list : Collection [Tuple [str , Optional [ str ] ]],
282
283
include_all_devices : bool = False ,
283
284
include_deleted_devices : bool = False ,
284
285
) -> Dict [str , Dict [str , Optional [DeviceKeyLookupResult ]]]:
@@ -288,49 +289,73 @@ def _get_e2e_device_keys_txn(
288
289
cross-signing signatures which have been added subsequently (for which, see
289
290
get_e2e_device_keys_and_signatures)
290
291
"""
291
- query_clauses = []
292
- query_params = []
292
+ query_clauses : List [ str ] = []
293
+ query_params_list : List [ List [ object ]] = []
293
294
294
295
if include_all_devices is False :
295
296
include_deleted_devices = False
296
297
297
298
if include_deleted_devices :
298
299
deleted_devices = set (query_list )
299
300
301
+ # Split the query list into queries for users and queries for particular
302
+ # devices.
303
+ user_list = []
304
+ user_device_list = []
300
305
for (user_id , device_id ) in query_list :
301
- query_clause = "user_id = ?"
302
- query_params .append (user_id )
303
-
304
- if device_id is not None :
305
- query_clause += " AND device_id = ?"
306
- query_params .append (device_id )
307
-
308
- query_clauses .append (query_clause )
309
-
310
- sql = (
311
- "SELECT user_id, device_id, "
312
- " d.display_name, "
313
- " k.key_json"
314
- " FROM devices d"
315
- " %s JOIN e2e_device_keys_json k USING (user_id, device_id)"
316
- " WHERE %s AND NOT d.hidden"
317
- ) % (
318
- "LEFT" if include_all_devices else "INNER" ,
319
- " OR " .join ("(" + q + ")" for q in query_clauses ),
320
- )
306
+ if device_id is None :
307
+ user_list .append (user_id )
308
+ else :
309
+ user_device_list .append ((user_id , device_id ))
321
310
322
- txn .execute (sql , query_params )
311
+ if user_list :
312
+ user_id_in_list_clause , user_args = make_in_list_sql_clause (
313
+ txn .database_engine , "user_id" , user_list
314
+ )
315
+ query_clauses .append (user_id_in_list_clause )
316
+ query_params_list .append (user_args )
317
+
318
+ if user_device_list :
319
+ # Divide the device queries into batches, to avoid excessively large
320
+ # queries.
321
+ for user_device_batch in batch_iter (user_device_list , 1024 ):
322
+ (
323
+ user_device_id_in_list_clause ,
324
+ user_device_args ,
325
+ ) = make_tuple_in_list_sql_clause (
326
+ txn .database_engine , ("user_id" , "device_id" ), user_device_batch
327
+ )
328
+ query_clauses .append (user_device_id_in_list_clause )
329
+ query_params_list .append (user_device_args )
323
330
324
331
result : Dict [str , Dict [str , Optional [DeviceKeyLookupResult ]]] = {}
325
- for (user_id , device_id , display_name , key_json ) in txn :
326
- if include_deleted_devices :
327
- deleted_devices .remove ((user_id , device_id ))
328
- result .setdefault (user_id , {})[device_id ] = DeviceKeyLookupResult (
329
- display_name , db_to_json (key_json ) if key_json else None
332
+ for query_clause , query_params in zip (query_clauses , query_params_list ):
333
+ sql = (
334
+ "SELECT user_id, device_id, "
335
+ " d.display_name, "
336
+ " k.key_json"
337
+ " FROM devices d"
338
+ " %s JOIN e2e_device_keys_json k USING (user_id, device_id)"
339
+ " WHERE %s AND NOT d.hidden"
340
+ ) % (
341
+ "LEFT" if include_all_devices else "INNER" ,
342
+ query_clause ,
330
343
)
331
344
345
+ txn .execute (sql , query_params )
346
+
347
+ for (user_id , device_id , display_name , key_json ) in txn :
348
+ assert device_id is not None
349
+ if include_deleted_devices :
350
+ deleted_devices .remove ((user_id , device_id ))
351
+ result .setdefault (user_id , {})[device_id ] = DeviceKeyLookupResult (
352
+ display_name , db_to_json (key_json ) if key_json else None
353
+ )
354
+
332
355
if include_deleted_devices :
333
356
for user_id , device_id in deleted_devices :
357
+ if device_id is None :
358
+ continue
334
359
result .setdefault (user_id , {})[device_id ] = None
335
360
336
361
return result
0 commit comments