17
17
use std:: { sync:: Arc , time:: Duration } ;
18
18
19
19
use eyeball:: { SharedObservable , Subscriber } ;
20
- use matrix_sdk_base:: {
21
- deserialized_responses:: TimelineEvent , linked_chunk:: ChunkIdentifier , timeout:: timeout,
22
- } ;
20
+ use matrix_sdk_base:: timeout:: timeout;
23
21
use matrix_sdk_common:: linked_chunk:: ChunkContent ;
24
22
use ruma:: api:: Direction ;
25
- use tokio:: sync:: RwLockWriteGuard ;
26
23
use tracing:: { debug, instrument, trace} ;
27
24
28
25
use super :: {
29
- deduplicator:: DeduplicationOutcome ,
30
26
room:: { events:: Gap , LoadMoreEventsBackwardsOutcome , RoomEventCacheInner } ,
31
- BackPaginationOutcome , EventsOrigin , Result , RoomEventCacheState , RoomEventCacheUpdate ,
27
+ BackPaginationOutcome , EventsOrigin , Result , RoomEventCacheUpdate ,
32
28
} ;
33
29
use crate :: { event_cache:: EventCacheError , room:: MessagesOptions } ;
34
30
@@ -281,7 +277,7 @@ impl RoomPagination {
281
277
282
278
// Make sure the `RoomEvents` isn't updated while we are saving events from
283
279
// backpagination.
284
- let state = self . inner . state . write ( ) . await ;
280
+ let mut state = self . inner . state . write ( ) . await ;
285
281
286
282
// Check that the previous token still exists; otherwise it's a sign that the
287
283
// room's timeline has been cleared.
@@ -305,164 +301,12 @@ impl RoomPagination {
305
301
None
306
302
} ;
307
303
308
- self . handle_network_pagination_result ( state, events, new_gap, prev_gap_chunk_id)
304
+ state
305
+ . handle_backpagination ( events, new_gap, prev_gap_chunk_id, & self . inner . sender )
309
306
. await
310
307
. map ( Some )
311
308
}
312
309
313
- /// Handle the result of a successful network back-pagination.
314
- async fn handle_network_pagination_result (
315
- & self ,
316
- mut state : RwLockWriteGuard < ' _ , RoomEventCacheState > ,
317
- events : Vec < TimelineEvent > ,
318
- new_gap : Option < Gap > ,
319
- prev_gap_id : Option < ChunkIdentifier > ,
320
- ) -> Result < BackPaginationOutcome > {
321
- // If there's no new previous gap, then we've reached the start of the timeline.
322
- let network_reached_start = new_gap. is_none ( ) ;
323
-
324
- let (
325
- DeduplicationOutcome {
326
- all_events : mut events,
327
- in_memory_duplicated_event_ids,
328
- in_store_duplicated_event_ids,
329
- } ,
330
- all_duplicates,
331
- ) = state. collect_valid_and_duplicated_events ( events) . await ?;
332
-
333
- // If not all the events have been back-paginated, we need to remove the
334
- // previous ones, otherwise we can end up with misordered events.
335
- //
336
- // Consider the following scenario:
337
- // - sync returns [D, E, F]
338
- // - then sync returns [] with a previous batch token PB1, so the internal
339
- // linked chunk state is [D, E, F, PB1].
340
- // - back-paginating with PB1 may return [A, B, C, D, E, F].
341
- //
342
- // Only inserting the new events when replacing PB1 would result in a timeline
343
- // ordering of [D, E, F, A, B, C], which is incorrect. So we do have to remove
344
- // all the events, in case this happens (see also #4746).
345
-
346
- let mut event_diffs = if !all_duplicates {
347
- // Let's forget all the previous events.
348
- state
349
- . remove_events ( in_memory_duplicated_event_ids, in_store_duplicated_event_ids)
350
- . await ?
351
- } else {
352
- // All new events are duplicated, they can all be ignored.
353
- events. clear ( ) ;
354
- Default :: default ( )
355
- } ;
356
-
357
- let next_diffs = state
358
- . with_events_mut ( false , |room_events| {
359
- // Reverse the order of the events as `/messages` has been called with `dir=b`
360
- // (backwards). The `RoomEvents` API expects the first event to be the oldest.
361
- // Let's re-order them for this block.
362
- let reversed_events = events. iter ( ) . rev ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
363
-
364
- let first_event_pos = room_events. events ( ) . next ( ) . map ( |( item_pos, _) | item_pos) ;
365
-
366
- // First, insert events.
367
- let insert_new_gap_pos = if let Some ( gap_id) = prev_gap_id {
368
- // There is a prior gap, let's replace it by new events!
369
- if all_duplicates {
370
- assert ! ( reversed_events. is_empty( ) ) ;
371
- }
372
-
373
- trace ! ( "replacing previous gap with the back-paginated events" ) ;
374
-
375
- // Replace the gap with the events we just deduplicated. This might get rid of
376
- // the underlying gap, if the conditions are favorable to
377
- // us.
378
- room_events
379
- . replace_gap_at ( reversed_events. clone ( ) , gap_id)
380
- . expect ( "gap_identifier is a valid chunk id we read previously" )
381
- } else if let Some ( pos) = first_event_pos {
382
- // No prior gap, but we had some events: assume we need to prepend events
383
- // before those.
384
- trace ! ( "inserted events before the first known event" ) ;
385
-
386
- room_events
387
- . insert_events_at ( reversed_events. clone ( ) , pos)
388
- . expect ( "pos is a valid position we just read above" ) ;
389
-
390
- Some ( pos)
391
- } else {
392
- // No prior gap, and no prior events: push the events.
393
- trace ! ( "pushing events received from back-pagination" ) ;
394
-
395
- room_events. push_events ( reversed_events. clone ( ) ) ;
396
-
397
- // A new gap may be inserted before the new events, if there are any.
398
- room_events. events ( ) . next ( ) . map ( |( item_pos, _) | item_pos)
399
- } ;
400
-
401
- // And insert the new gap if needs be.
402
- //
403
- // We only do this when at least one new, non-duplicated event, has been added
404
- // to the chunk. Otherwise it means we've back-paginated all the known events.
405
- if !all_duplicates {
406
- if let Some ( new_gap) = new_gap {
407
- if let Some ( new_pos) = insert_new_gap_pos {
408
- room_events
409
- . insert_gap_at ( new_gap, new_pos)
410
- . expect ( "events_chunk_pos represents a valid chunk position" ) ;
411
- } else {
412
- room_events. push_gap ( new_gap) ;
413
- }
414
- }
415
- } else {
416
- debug ! (
417
- "not storing previous batch token, because we \
418
- deduplicated all new back-paginated events"
419
- ) ;
420
- }
421
-
422
- reversed_events
423
- } )
424
- . await ?;
425
-
426
- event_diffs. extend ( next_diffs) ;
427
-
428
- // There could be an inconsistency between the network (which thinks we hit the
429
- // start of the timeline) and the disk (which has the initial empty
430
- // chunks), so tweak the `reached_start` value so that it reflects the disk
431
- // state in priority instead.
432
- let reached_start = {
433
- // There are no gaps.
434
- let has_gaps = state. events ( ) . chunks ( ) . any ( |chunk| chunk. is_gap ( ) ) ;
435
-
436
- // The first chunk has no predecessors.
437
- let first_chunk_is_definitive_head =
438
- state. events ( ) . chunks ( ) . next ( ) . map ( |chunk| chunk. is_definitive_head ( ) ) ;
439
-
440
- let reached_start =
441
- !has_gaps && first_chunk_is_definitive_head. unwrap_or ( network_reached_start) ;
442
-
443
- trace ! (
444
- ?network_reached_start,
445
- ?has_gaps,
446
- ?first_chunk_is_definitive_head,
447
- ?reached_start,
448
- "finished handling network back-pagination"
449
- ) ;
450
-
451
- reached_start
452
- } ;
453
-
454
- let backpagination_outcome = BackPaginationOutcome { events, reached_start } ;
455
-
456
- if !event_diffs. is_empty ( ) {
457
- let _ = self . inner . sender . send ( RoomEventCacheUpdate :: UpdateTimelineEvents {
458
- diffs : event_diffs,
459
- origin : EventsOrigin :: Pagination ,
460
- } ) ;
461
- }
462
-
463
- Ok ( backpagination_outcome)
464
- }
465
-
466
310
/// Returns a subscriber to the pagination status used for the
467
311
/// back-pagination integrated to the event cache.
468
312
pub fn status ( & self ) -> Subscriber < RoomPaginationStatus > {
0 commit comments