@@ -111,6 +111,23 @@ def __init__(self, hs: "HomeServer"):
111
111
reset_expiry_on_get = False ,
112
112
)
113
113
114
+ # A cache for fetching the room hierarchy over federation.
115
+ #
116
+ # Some stale data over federation is OK, but must be refreshed
117
+ # periodically since the local server is in the room.
118
+ #
119
+ # It is a map of (room ID, suggested-only) -> the response of
120
+ # get_room_hierarchy.
121
+ self ._get_room_hierarchy_cache : ExpiringCache [
122
+ Tuple [str , bool ], Tuple [JsonDict , Sequence [JsonDict ], Sequence [str ]]
123
+ ] = ExpiringCache (
124
+ cache_name = "get_room_hierarchy_cache" ,
125
+ clock = self ._clock ,
126
+ max_len = 1000 ,
127
+ expiry_ms = 5 * 60 * 1000 ,
128
+ reset_expiry_on_get = False ,
129
+ )
130
+
114
131
def _clear_tried_cache (self ):
115
132
"""Clear pdu_destination_tried cache"""
116
133
now = self ._clock .time_msec ()
@@ -1324,6 +1341,10 @@ async def get_room_hierarchy(
1324
1341
remote servers
1325
1342
"""
1326
1343
1344
+ cached_result = self ._get_room_hierarchy_cache .get ((room_id , suggested_only ))
1345
+ if cached_result :
1346
+ return cached_result
1347
+
1327
1348
async def send_request (
1328
1349
destination : str ,
1329
1350
) -> Tuple [JsonDict , Sequence [JsonDict ], Sequence [str ]]:
@@ -1370,58 +1391,63 @@ async def send_request(
1370
1391
return room , children , inaccessible_children
1371
1392
1372
1393
try :
1373
- return await self ._try_destination_list (
1394
+ result = await self ._try_destination_list (
1374
1395
"fetch room hierarchy" ,
1375
1396
destinations ,
1376
1397
send_request ,
1377
1398
failover_on_unknown_endpoint = True ,
1378
1399
)
1379
1400
except SynapseError as e :
1401
+ # If an unexpected error occurred, re-raise it.
1402
+ if e .code != 502 :
1403
+ raise
1404
+
1380
1405
# Fallback to the old federation API and translate the results if
1381
1406
# no servers implement the new API.
1382
1407
#
1383
1408
# The algorithm below is a bit inefficient as it only attempts to
1384
- # get information for the requested room, but the legacy API may
1409
+ # parse information for the requested room, but the legacy API may
1385
1410
# return additional layers.
1386
- if e .code == 502 :
1387
- legacy_result = await self .get_space_summary (
1388
- destinations ,
1389
- room_id ,
1390
- suggested_only ,
1391
- max_rooms_per_space = None ,
1392
- exclude_rooms = [],
1393
- )
1411
+ legacy_result = await self .get_space_summary (
1412
+ destinations ,
1413
+ room_id ,
1414
+ suggested_only ,
1415
+ max_rooms_per_space = None ,
1416
+ exclude_rooms = [],
1417
+ )
1394
1418
1395
- # Find the requested room in the response (and remove it).
1396
- for _i , room in enumerate (legacy_result .rooms ):
1397
- if room .get ("room_id" ) == room_id :
1398
- break
1399
- else :
1400
- # The requested room was not returned, nothing we can do.
1401
- raise
1402
- requested_room = legacy_result .rooms .pop (_i )
1403
-
1404
- # Find any children events of the requested room.
1405
- children_events = []
1406
- children_room_ids = set ()
1407
- for event in legacy_result .events :
1408
- if event .room_id == room_id :
1409
- children_events .append (event .data )
1410
- children_room_ids .add (event .state_key )
1411
- # And add them under the requested room.
1412
- requested_room ["children_state" ] = children_events
1413
-
1414
- # Find the children rooms.
1415
- children = []
1416
- for room in legacy_result .rooms :
1417
- if room .get ("room_id" ) in children_room_ids :
1418
- children .append (room )
1419
-
1420
- # It isn't clear from the response whether some of the rooms are
1421
- # not accessible.
1422
- return requested_room , children , ()
1423
-
1424
- raise
1419
+ # Find the requested room in the response (and remove it).
1420
+ for _i , room in enumerate (legacy_result .rooms ):
1421
+ if room .get ("room_id" ) == room_id :
1422
+ break
1423
+ else :
1424
+ # The requested room was not returned, nothing we can do.
1425
+ raise
1426
+ requested_room = legacy_result .rooms .pop (_i )
1427
+
1428
+ # Find any children events of the requested room.
1429
+ children_events = []
1430
+ children_room_ids = set ()
1431
+ for event in legacy_result .events :
1432
+ if event .room_id == room_id :
1433
+ children_events .append (event .data )
1434
+ children_room_ids .add (event .state_key )
1435
+ # And add them under the requested room.
1436
+ requested_room ["children_state" ] = children_events
1437
+
1438
+ # Find the children rooms.
1439
+ children = []
1440
+ for room in legacy_result .rooms :
1441
+ if room .get ("room_id" ) in children_room_ids :
1442
+ children .append (room )
1443
+
1444
+ # It isn't clear from the response whether some of the rooms are
1445
+ # not accessible.
1446
+ result = (requested_room , children , ())
1447
+
1448
+ # Cache the result to avoid fetching data over federation every time.
1449
+ self ._get_room_hierarchy_cache [(room_id , suggested_only )] = result
1450
+ return result
1425
1451
1426
1452
1427
1453
@attr .s (frozen = True , slots = True , auto_attribs = True )
0 commit comments