atagen

matrix-rust-sdk

public
Star0
Watch0
ssh://brewery@pls.lobotomise.me:33/atagen/matrix-rust-sdk.git

Blame: benchmarks/benches/event_cache.rs

7ff8adafe9e4atagen2026-10-22 12:30 UTC1
use std::{pin::Pin, sync::Arc};
7ff8adafe9e4atagen2026-10-22 12:30 UTC2
7ff8adafe9e4atagen2026-10-22 12:30 UTC3
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
7ff8adafe9e4atagen2026-10-22 12:30 UTC4
use matrix_sdk::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC5
    RoomInfo, RoomState, SqliteEventCacheStore, StateStore,
7ff8adafe9e4atagen2026-10-22 12:30 UTC6
    cross_process_lock::CrossProcessLockConfig,
7ff8adafe9e4atagen2026-10-22 12:30 UTC7
    store::StoreConfig,
7ff8adafe9e4atagen2026-10-22 12:30 UTC8
    sync::{JoinedRoomUpdate, RoomUpdates},
7ff8adafe9e4atagen2026-10-22 12:30 UTC9
    test_utils::client::MockClientBuilder,
7ff8adafe9e4atagen2026-10-22 12:30 UTC10
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC11
use matrix_sdk_base::event_cache::store::{DynEventCacheStore, IntoEventCacheStore, MemoryStore};
7ff8adafe9e4atagen2026-10-22 12:30 UTC12
use matrix_sdk_test::{ALICE, base64_sha256_hash, event_factory::EventFactory};
7ff8adafe9e4atagen2026-10-22 12:30 UTC13
use ruma::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC14
    OwnedRoomId, RoomId,
7ff8adafe9e4atagen2026-10-22 12:30 UTC15
    events::{relation::RelationType, room::message::RoomMessageEventContentWithoutRelation},
7ff8adafe9e4atagen2026-10-22 12:30 UTC16
    room_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC17
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC18
use tempfile::tempdir;
7ff8adafe9e4atagen2026-10-22 12:30 UTC19
use tokio::runtime::Builder;
7ff8adafe9e4atagen2026-10-22 12:30 UTC20
7ff8adafe9e4atagen2026-10-22 12:30 UTC21
type StoreBuilder = Box<dyn Fn() -> Pin<Box<dyn Future<Output = Arc<DynEventCacheStore>>>>>;
7ff8adafe9e4atagen2026-10-22 12:30 UTC22
7ff8adafe9e4atagen2026-10-22 12:30 UTC23
fn handle_room_updates(c: &mut Criterion) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC24
    // Create a new asynchronous runtime.
7ff8adafe9e4atagen2026-10-22 12:30 UTC25
    let runtime = Builder::new_multi_thread()
7ff8adafe9e4atagen2026-10-22 12:30 UTC26
        .enable_time()
7ff8adafe9e4atagen2026-10-22 12:30 UTC27
        .enable_io()
7ff8adafe9e4atagen2026-10-22 12:30 UTC28
        .build()
7ff8adafe9e4atagen2026-10-22 12:30 UTC29
        .expect("Failed to create an asynchronous runtime");
7ff8adafe9e4atagen2026-10-22 12:30 UTC30
7ff8adafe9e4atagen2026-10-22 12:30 UTC31
    let mut group = c.benchmark_group("Event cache room updates");
7ff8adafe9e4atagen2026-10-22 12:30 UTC32
    group.sample_size(10);
7ff8adafe9e4atagen2026-10-22 12:30 UTC33
7ff8adafe9e4atagen2026-10-22 12:30 UTC34
    const NUM_EVENTS: usize = 1000;
7ff8adafe9e4atagen2026-10-22 12:30 UTC35
7ff8adafe9e4atagen2026-10-22 12:30 UTC36
    for num_rooms in [1, 10, 100] {
7ff8adafe9e4atagen2026-10-22 12:30 UTC37
        // Add some joined rooms, each with NUM_EVENTS in it, to the sync response.
7ff8adafe9e4atagen2026-10-22 12:30 UTC38
        let mut room_updates = RoomUpdates::default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC39
7ff8adafe9e4atagen2026-10-22 12:30 UTC40
        let mut changes = matrix_sdk::StateChanges::default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC41
7ff8adafe9e4atagen2026-10-22 12:30 UTC42
        for i in 0..num_rooms {
7ff8adafe9e4atagen2026-10-22 12:30 UTC43
            // Synapse's room IDs for rooms v1 to v11 have an 18 characters localpart.
7ff8adafe9e4atagen2026-10-22 12:30 UTC44
            let raw_room_id = format!("!firstbatchroom{i:04}:example.com");
7ff8adafe9e4atagen2026-10-22 12:30 UTC45
7ff8adafe9e4atagen2026-10-22 12:30 UTC46
            let room_id = if i % 10 == 9 {
7ff8adafe9e4atagen2026-10-22 12:30 UTC47
                // Make 1 in 10 rooms use a room v12 ID, which is a base64 hash similar to an
7ff8adafe9e4atagen2026-10-22 12:30 UTC48
                // event ID.
7ff8adafe9e4atagen2026-10-22 12:30 UTC49
                RoomId::new_v2(&base64_sha256_hash(raw_room_id.as_bytes())).unwrap()
7ff8adafe9e4atagen2026-10-22 12:30 UTC50
            } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC51
                OwnedRoomId::try_from(raw_room_id).unwrap()
7ff8adafe9e4atagen2026-10-22 12:30 UTC52
            };
7ff8adafe9e4atagen2026-10-22 12:30 UTC53
            let event_factory = EventFactory::new().room(&room_id).sender(&ALICE);
7ff8adafe9e4atagen2026-10-22 12:30 UTC54
7ff8adafe9e4atagen2026-10-22 12:30 UTC55
            let mut joined_room_update = JoinedRoomUpdate::default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC56
            for j in 0..NUM_EVENTS {
7ff8adafe9e4atagen2026-10-22 12:30 UTC57
                let event = event_factory.text_msg(format!("Message {j}")).into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC58
                joined_room_update.timeline.events.push(event);
7ff8adafe9e4atagen2026-10-22 12:30 UTC59
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC60
            room_updates.joined.insert(room_id.clone(), joined_room_update);
7ff8adafe9e4atagen2026-10-22 12:30 UTC61
7ff8adafe9e4atagen2026-10-22 12:30 UTC62
            changes.add_room(RoomInfo::new(&room_id, RoomState::Joined));
7ff8adafe9e4atagen2026-10-22 12:30 UTC63
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC64
7ff8adafe9e4atagen2026-10-22 12:30 UTC65
        // Declare new stores for this set of events.
7ff8adafe9e4atagen2026-10-22 12:30 UTC66
        let temp_dir = Arc::new(tempdir().unwrap());
7ff8adafe9e4atagen2026-10-22 12:30 UTC67
7ff8adafe9e4atagen2026-10-22 12:30 UTC68
        let store_builders: Vec<(_, StoreBuilder)> = vec![
7ff8adafe9e4atagen2026-10-22 12:30 UTC69
            (
7ff8adafe9e4atagen2026-10-22 12:30 UTC70
                "memory",
7ff8adafe9e4atagen2026-10-22 12:30 UTC71
                Box::new(|| Box::pin(async { MemoryStore::default().into_event_cache_store() })),
7ff8adafe9e4atagen2026-10-22 12:30 UTC72
            ),
7ff8adafe9e4atagen2026-10-22 12:30 UTC73
            (
7ff8adafe9e4atagen2026-10-22 12:30 UTC74
                "SQLite",
7ff8adafe9e4atagen2026-10-22 12:30 UTC75
                Box::new(move || {
7ff8adafe9e4atagen2026-10-22 12:30 UTC76
                    let temp_dir = temp_dir.clone();
7ff8adafe9e4atagen2026-10-22 12:30 UTC77
                    Box::pin(async move {
7ff8adafe9e4atagen2026-10-22 12:30 UTC78
                        // Remove all the files in the temp_dir, to reset the event cache state.
7ff8adafe9e4atagen2026-10-22 12:30 UTC79
                        for entry in temp_dir.path().read_dir().unwrap() {
7ff8adafe9e4atagen2026-10-22 12:30 UTC80
                            let entry = entry.unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC81
                            let path = entry.path();
7ff8adafe9e4atagen2026-10-22 12:30 UTC82
                            if path.is_dir() {
7ff8adafe9e4atagen2026-10-22 12:30 UTC83
                                // If it's a directory, remove it recursively.
7ff8adafe9e4atagen2026-10-22 12:30 UTC84
                                std::fs::remove_dir_all(path).unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC85
                            } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC86
                                std::fs::remove_file(path).unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC87
                            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC88
                        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC89
7ff8adafe9e4atagen2026-10-22 12:30 UTC90
                        // Recreate a new store.
7ff8adafe9e4atagen2026-10-22 12:30 UTC91
                        SqliteEventCacheStore::open(temp_dir.path().join("bench"), None)
7ff8adafe9e4atagen2026-10-22 12:30 UTC92
                            .await
7ff8adafe9e4atagen2026-10-22 12:30 UTC93
                            .unwrap()
7ff8adafe9e4atagen2026-10-22 12:30 UTC94
                            .into_event_cache_store()
7ff8adafe9e4atagen2026-10-22 12:30 UTC95
                    })
7ff8adafe9e4atagen2026-10-22 12:30 UTC96
                }),
7ff8adafe9e4atagen2026-10-22 12:30 UTC97
            ),
7ff8adafe9e4atagen2026-10-22 12:30 UTC98
        ];
7ff8adafe9e4atagen2026-10-22 12:30 UTC99
7ff8adafe9e4atagen2026-10-22 12:30 UTC100
        let state_store = runtime.block_on(async {
7ff8adafe9e4atagen2026-10-22 12:30 UTC101
            let state_store = matrix_sdk::MemoryStore::new();
7ff8adafe9e4atagen2026-10-22 12:30 UTC102
            state_store.save_changes(&changes).await.unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC103
            Arc::new(state_store)
7ff8adafe9e4atagen2026-10-22 12:30 UTC104
        });
7ff8adafe9e4atagen2026-10-22 12:30 UTC105
7ff8adafe9e4atagen2026-10-22 12:30 UTC106
        for (store_name, store_builder) in &store_builders {
7ff8adafe9e4atagen2026-10-22 12:30 UTC107
            let client = runtime.block_on(async {
7ff8adafe9e4atagen2026-10-22 12:30 UTC108
                let event_cache_store = store_builder().await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC109
7ff8adafe9e4atagen2026-10-22 12:30 UTC110
                let client = MockClientBuilder::new(None)
7ff8adafe9e4atagen2026-10-22 12:30 UTC111
                    .on_builder(|builder| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC112
                        builder.store_config(
7ff8adafe9e4atagen2026-10-22 12:30 UTC113
                            StoreConfig::new(CrossProcessLockConfig::multi_process(
7ff8adafe9e4atagen2026-10-22 12:30 UTC114
                                "cross-process-store-locks-holder-name",
7ff8adafe9e4atagen2026-10-22 12:30 UTC115
                            ))
7ff8adafe9e4atagen2026-10-22 12:30 UTC116
                            .state_store(state_store.clone())
7ff8adafe9e4atagen2026-10-22 12:30 UTC117
                            .event_cache_store(event_cache_store.clone()),
7ff8adafe9e4atagen2026-10-22 12:30 UTC118
                        )
7ff8adafe9e4atagen2026-10-22 12:30 UTC119
                    })
7ff8adafe9e4atagen2026-10-22 12:30 UTC120
                    .build()
7ff8adafe9e4atagen2026-10-22 12:30 UTC121
                    .await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC122
7ff8adafe9e4atagen2026-10-22 12:30 UTC123
                client.event_cache().subscribe().unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC124
7ff8adafe9e4atagen2026-10-22 12:30 UTC125
                client
7ff8adafe9e4atagen2026-10-22 12:30 UTC126
            });
7ff8adafe9e4atagen2026-10-22 12:30 UTC127
7ff8adafe9e4atagen2026-10-22 12:30 UTC128
            // Define a state store with all rooms known in it.
7ff8adafe9e4atagen2026-10-22 12:30 UTC129
            // Define the throughput.
7ff8adafe9e4atagen2026-10-22 12:30 UTC130
            group.throughput(Throughput::Elements(num_rooms));
7ff8adafe9e4atagen2026-10-22 12:30 UTC131
7ff8adafe9e4atagen2026-10-22 12:30 UTC132
            // Bench the handling of room updates.
7ff8adafe9e4atagen2026-10-22 12:30 UTC133
            group.bench_function(
7ff8adafe9e4atagen2026-10-22 12:30 UTC134
                BenchmarkId::new(
7ff8adafe9e4atagen2026-10-22 12:30 UTC135
                    format!("Event cache room updates[{store_name}]"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC136
                    format!("room count: {num_rooms}"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC137
                ),
7ff8adafe9e4atagen2026-10-22 12:30 UTC138
                |bencher| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC139
                    bencher.to_async(&runtime).iter(
7ff8adafe9e4atagen2026-10-22 12:30 UTC140
                        // The routine itself.
7ff8adafe9e4atagen2026-10-22 12:30 UTC141
                        || {
7ff8adafe9e4atagen2026-10-22 12:30 UTC142
                            let room_updates = room_updates.clone();
7ff8adafe9e4atagen2026-10-22 12:30 UTC143
                            let client = client.clone();
7ff8adafe9e4atagen2026-10-22 12:30 UTC144
7ff8adafe9e4atagen2026-10-22 12:30 UTC145
                            async move {
7ff8adafe9e4atagen2026-10-22 12:30 UTC146
                                client.event_cache().clear_all_rooms().await.unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC147
7ff8adafe9e4atagen2026-10-22 12:30 UTC148
                                client
7ff8adafe9e4atagen2026-10-22 12:30 UTC149
                                    .event_cache()
7ff8adafe9e4atagen2026-10-22 12:30 UTC150
                                    .handle_room_updates(room_updates.clone())
7ff8adafe9e4atagen2026-10-22 12:30 UTC151
                                    .await
7ff8adafe9e4atagen2026-10-22 12:30 UTC152
                                    .unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC153
                            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC154
                        },
7ff8adafe9e4atagen2026-10-22 12:30 UTC155
                    )
7ff8adafe9e4atagen2026-10-22 12:30 UTC156
                },
7ff8adafe9e4atagen2026-10-22 12:30 UTC157
            );
7ff8adafe9e4atagen2026-10-22 12:30 UTC158
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC159
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC160
7ff8adafe9e4atagen2026-10-22 12:30 UTC161
    group.finish()
7ff8adafe9e4atagen2026-10-22 12:30 UTC162
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC163
7ff8adafe9e4atagen2026-10-22 12:30 UTC164
fn find_event_relations(c: &mut Criterion) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC165
    // Number of other events to saturate the DB, but that will not be affected by
7ff8adafe9e4atagen2026-10-22 12:30 UTC166
    // the benchmark. A small multiple of this number will be added.
7ff8adafe9e4atagen2026-10-22 12:30 UTC167
    // When running locally, run with more events than in Codespeed CI.
7ff8adafe9e4atagen2026-10-22 12:30 UTC168
    #[cfg(feature = "codspeed")]
7ff8adafe9e4atagen2026-10-22 12:30 UTC169
    const NUM_OTHER_EVENTS: usize = 100;
7ff8adafe9e4atagen2026-10-22 12:30 UTC170
    #[cfg(not(feature = "codspeed"))]
7ff8adafe9e4atagen2026-10-22 12:30 UTC171
    const NUM_OTHER_EVENTS: usize = 1000;
7ff8adafe9e4atagen2026-10-22 12:30 UTC172
7ff8adafe9e4atagen2026-10-22 12:30 UTC173
    // Create a new asynchronous runtime.
7ff8adafe9e4atagen2026-10-22 12:30 UTC174
    let runtime = Builder::new_multi_thread()
7ff8adafe9e4atagen2026-10-22 12:30 UTC175
        .enable_time()
7ff8adafe9e4atagen2026-10-22 12:30 UTC176
        .enable_io()
7ff8adafe9e4atagen2026-10-22 12:30 UTC177
        .build()
7ff8adafe9e4atagen2026-10-22 12:30 UTC178
        .expect("Failed to create an asynchronous runtime");
7ff8adafe9e4atagen2026-10-22 12:30 UTC179
7ff8adafe9e4atagen2026-10-22 12:30 UTC180
    let mut group = c.benchmark_group("Event cache room updates");
7ff8adafe9e4atagen2026-10-22 12:30 UTC181
    group.sample_size(10);
7ff8adafe9e4atagen2026-10-22 12:30 UTC182
7ff8adafe9e4atagen2026-10-22 12:30 UTC183
    // Room v1-v11 ID.
7ff8adafe9e4atagen2026-10-22 12:30 UTC184
    let room_id = room_id!("!initialtestingroom:ben.ch");
7ff8adafe9e4atagen2026-10-22 12:30 UTC185
    // Room v12 ID.
7ff8adafe9e4atagen2026-10-22 12:30 UTC186
    let other_room_id = room_id!("!ICMDdumUm6RRX_eWYY2wMb2w0CY0Z_5OvlY2gBR6ELc");
7ff8adafe9e4atagen2026-10-22 12:30 UTC187
7ff8adafe9e4atagen2026-10-22 12:30 UTC188
    // Make the state store aware of the room, so that `client.get_room()` works
7ff8adafe9e4atagen2026-10-22 12:30 UTC189
    // with it.
7ff8adafe9e4atagen2026-10-22 12:30 UTC190
    let mut changes = matrix_sdk::StateChanges::default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC191
    changes.add_room(RoomInfo::new(room_id, RoomState::Joined));
7ff8adafe9e4atagen2026-10-22 12:30 UTC192
    changes.add_room(RoomInfo::new(other_room_id, RoomState::Joined));
7ff8adafe9e4atagen2026-10-22 12:30 UTC193
    let state_store = runtime.block_on(async {
7ff8adafe9e4atagen2026-10-22 12:30 UTC194
        let state_store = matrix_sdk::MemoryStore::new();
7ff8adafe9e4atagen2026-10-22 12:30 UTC195
        state_store.save_changes(&changes).await.unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC196
        Arc::new(state_store)
7ff8adafe9e4atagen2026-10-22 12:30 UTC197
    });
7ff8adafe9e4atagen2026-10-22 12:30 UTC198
7ff8adafe9e4atagen2026-10-22 12:30 UTC199
    for num_related_events in [10, 100, 1000] {
7ff8adafe9e4atagen2026-10-22 12:30 UTC200
        // Prefill the event cache store with one event and N related events.
7ff8adafe9e4atagen2026-10-22 12:30 UTC201
        let mut room_updates = RoomUpdates::default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC202
7ff8adafe9e4atagen2026-10-22 12:30 UTC203
        let event_factory = EventFactory::new().room(room_id).sender(&ALICE);
7ff8adafe9e4atagen2026-10-22 12:30 UTC204
7ff8adafe9e4atagen2026-10-22 12:30 UTC205
        let mut joined_room_update = JoinedRoomUpdate::default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC206
7ff8adafe9e4atagen2026-10-22 12:30 UTC207
        // Add the target event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC208
        let target_event = event_factory.text_msg("hello world").into_event();
7ff8adafe9e4atagen2026-10-22 12:30 UTC209
        let target_event_id =
7ff8adafe9e4atagen2026-10-22 12:30 UTC210
            { &target_event.event_id().expect("generated event has an event ID") };
7ff8adafe9e4atagen2026-10-22 12:30 UTC211
        joined_room_update.timeline.events.push(target_event);
7ff8adafe9e4atagen2026-10-22 12:30 UTC212
7ff8adafe9e4atagen2026-10-22 12:30 UTC213
        // Add the numerous edits.
7ff8adafe9e4atagen2026-10-22 12:30 UTC214
        for i in 0..num_related_events {
7ff8adafe9e4atagen2026-10-22 12:30 UTC215
            let event = event_factory
7ff8adafe9e4atagen2026-10-22 12:30 UTC216
                .text_msg(format!("* edit {i}"))
7ff8adafe9e4atagen2026-10-22 12:30 UTC217
                .edit(
7ff8adafe9e4atagen2026-10-22 12:30 UTC218
                    target_event_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC219
                    RoomMessageEventContentWithoutRelation::text_plain(format!("edit {i}")),
7ff8adafe9e4atagen2026-10-22 12:30 UTC220
                )
7ff8adafe9e4atagen2026-10-22 12:30 UTC221
                .into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC222
            joined_room_update.timeline.events.push(event);
7ff8adafe9e4atagen2026-10-22 12:30 UTC223
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC224
7ff8adafe9e4atagen2026-10-22 12:30 UTC225
        // Add other events, in the same room, without a relation.
7ff8adafe9e4atagen2026-10-22 12:30 UTC226
        for i in 0..NUM_OTHER_EVENTS {
7ff8adafe9e4atagen2026-10-22 12:30 UTC227
            let event = event_factory.text_msg(format!("unrelated message {i}")).into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC228
            joined_room_update.timeline.events.push(event);
7ff8adafe9e4atagen2026-10-22 12:30 UTC229
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC230
7ff8adafe9e4atagen2026-10-22 12:30 UTC231
        // Add other events, in the same room, related to other events.
7ff8adafe9e4atagen2026-10-22 12:30 UTC232
        let other_target_event = event_factory.text_msg("hello world").into_event();
7ff8adafe9e4atagen2026-10-22 12:30 UTC233
        let other_target_event_id =
7ff8adafe9e4atagen2026-10-22 12:30 UTC234
            other_target_event.event_id().expect("generated event has an event ID");
7ff8adafe9e4atagen2026-10-22 12:30 UTC235
        joined_room_update.timeline.events.push(other_target_event);
7ff8adafe9e4atagen2026-10-22 12:30 UTC236
7ff8adafe9e4atagen2026-10-22 12:30 UTC237
        for _i in 0..NUM_OTHER_EVENTS {
7ff8adafe9e4atagen2026-10-22 12:30 UTC238
            let event = event_factory.reaction(&other_target_event_id, "👍").into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC239
            joined_room_update.timeline.events.push(event);
7ff8adafe9e4atagen2026-10-22 12:30 UTC240
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC241
7ff8adafe9e4atagen2026-10-22 12:30 UTC242
        room_updates.joined.insert(room_id.to_owned(), joined_room_update);
7ff8adafe9e4atagen2026-10-22 12:30 UTC243
7ff8adafe9e4atagen2026-10-22 12:30 UTC244
        // Add other events, in another room.
7ff8adafe9e4atagen2026-10-22 12:30 UTC245
        let mut other_joined_room_update = JoinedRoomUpdate::default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC246
        let event_factory = event_factory.room(other_room_id);
7ff8adafe9e4atagen2026-10-22 12:30 UTC247
        for i in 0..NUM_OTHER_EVENTS {
7ff8adafe9e4atagen2026-10-22 12:30 UTC248
            let event = event_factory.text_msg(format!("hi {i}")).into();
7ff8adafe9e4atagen2026-10-22 12:30 UTC249
            other_joined_room_update.timeline.events.push(event);
7ff8adafe9e4atagen2026-10-22 12:30 UTC250
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC251
        room_updates.joined.insert(other_room_id.to_owned(), other_joined_room_update);
7ff8adafe9e4atagen2026-10-22 12:30 UTC252
7ff8adafe9e4atagen2026-10-22 12:30 UTC253
        changes.add_room(RoomInfo::new(room_id, RoomState::Joined));
7ff8adafe9e4atagen2026-10-22 12:30 UTC254
7ff8adafe9e4atagen2026-10-22 12:30 UTC255
        // Declare new stores for this set of events.
7ff8adafe9e4atagen2026-10-22 12:30 UTC256
        let temp_dir = Arc::new(tempdir().unwrap());
7ff8adafe9e4atagen2026-10-22 12:30 UTC257
7ff8adafe9e4atagen2026-10-22 12:30 UTC258
        let stores = vec![
7ff8adafe9e4atagen2026-10-22 12:30 UTC259
            ("memory", MemoryStore::default().into_event_cache_store()),
7ff8adafe9e4atagen2026-10-22 12:30 UTC260
            (
7ff8adafe9e4atagen2026-10-22 12:30 UTC261
                "SQLite",
7ff8adafe9e4atagen2026-10-22 12:30 UTC262
                runtime.block_on(async {
7ff8adafe9e4atagen2026-10-22 12:30 UTC263
                    SqliteEventCacheStore::open(temp_dir.path().join("bench"), None)
7ff8adafe9e4atagen2026-10-22 12:30 UTC264
                        .await
7ff8adafe9e4atagen2026-10-22 12:30 UTC265
                        .unwrap()
7ff8adafe9e4atagen2026-10-22 12:30 UTC266
                        .into_event_cache_store()
7ff8adafe9e4atagen2026-10-22 12:30 UTC267
                }),
7ff8adafe9e4atagen2026-10-22 12:30 UTC268
            ),
7ff8adafe9e4atagen2026-10-22 12:30 UTC269
        ];
7ff8adafe9e4atagen2026-10-22 12:30 UTC270
7ff8adafe9e4atagen2026-10-22 12:30 UTC271
        for (store_name, event_cache_store) in stores {
7ff8adafe9e4atagen2026-10-22 12:30 UTC272
            let (client, room_event_cache, _drop_handles) = runtime.block_on(async {
7ff8adafe9e4atagen2026-10-22 12:30 UTC273
                let client = MockClientBuilder::new(None)
7ff8adafe9e4atagen2026-10-22 12:30 UTC274
                    .on_builder(|builder| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC275
                        builder.store_config(
7ff8adafe9e4atagen2026-10-22 12:30 UTC276
                            StoreConfig::new(CrossProcessLockConfig::multi_process(
7ff8adafe9e4atagen2026-10-22 12:30 UTC277
                                "cross-process-store-locks-holder-name",
7ff8adafe9e4atagen2026-10-22 12:30 UTC278
                            ))
7ff8adafe9e4atagen2026-10-22 12:30 UTC279
                            .state_store(state_store.clone())
7ff8adafe9e4atagen2026-10-22 12:30 UTC280
                            .event_cache_store(event_cache_store),
7ff8adafe9e4atagen2026-10-22 12:30 UTC281
                        )
7ff8adafe9e4atagen2026-10-22 12:30 UTC282
                    })
7ff8adafe9e4atagen2026-10-22 12:30 UTC283
                    .build()
7ff8adafe9e4atagen2026-10-22 12:30 UTC284
                    .await;
7ff8adafe9e4atagen2026-10-22 12:30 UTC285
7ff8adafe9e4atagen2026-10-22 12:30 UTC286
                client.event_cache().subscribe().unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC287
7ff8adafe9e4atagen2026-10-22 12:30 UTC288
                // Sync the updates before starting the benchmark.
7ff8adafe9e4atagen2026-10-22 12:30 UTC289
                let mut update_recv = client.event_cache().subscribe_to_room_generic_updates();
7ff8adafe9e4atagen2026-10-22 12:30 UTC290
7ff8adafe9e4atagen2026-10-22 12:30 UTC291
                client.event_cache().handle_room_updates(room_updates.clone()).await.unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC292
7ff8adafe9e4atagen2026-10-22 12:30 UTC293
                // Wait for the event cache to notify us of the room updates.
7ff8adafe9e4atagen2026-10-22 12:30 UTC294
                let update = update_recv.recv().await.unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC295
                assert!(update.room_id == room_id || update.room_id == other_room_id);
7ff8adafe9e4atagen2026-10-22 12:30 UTC296
7ff8adafe9e4atagen2026-10-22 12:30 UTC297
                let update = update_recv.recv().await.unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC298
                assert!(update.room_id == room_id || update.room_id == other_room_id);
7ff8adafe9e4atagen2026-10-22 12:30 UTC299
7ff8adafe9e4atagen2026-10-22 12:30 UTC300
                let room = client.get_room(room_id).unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC301
                let room_event_cache = room.event_cache().await.unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC302
7ff8adafe9e4atagen2026-10-22 12:30 UTC303
                (client, room_event_cache.0, room_event_cache.1)
7ff8adafe9e4atagen2026-10-22 12:30 UTC304
            });
7ff8adafe9e4atagen2026-10-22 12:30 UTC305
7ff8adafe9e4atagen2026-10-22 12:30 UTC306
            // Define the throughput.
7ff8adafe9e4atagen2026-10-22 12:30 UTC307
            group.throughput(Throughput::Elements(num_related_events));
7ff8adafe9e4atagen2026-10-22 12:30 UTC308
7ff8adafe9e4atagen2026-10-22 12:30 UTC309
            for filter in [None, Some(vec![RelationType::Replacement])] {
7ff8adafe9e4atagen2026-10-22 12:30 UTC310
                group.bench_function(
7ff8adafe9e4atagen2026-10-22 12:30 UTC311
                    BenchmarkId::new(
7ff8adafe9e4atagen2026-10-22 12:30 UTC312
                        format!("Event cache find_event_relations[{store_name}]"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC313
                        format!(
7ff8adafe9e4atagen2026-10-22 12:30 UTC314
                            "{num_related_events} events, {} filter",
7ff8adafe9e4atagen2026-10-22 12:30 UTC315
                            if filter.is_some() { "edits" } else { "#no" },
7ff8adafe9e4atagen2026-10-22 12:30 UTC316
                        ),
7ff8adafe9e4atagen2026-10-22 12:30 UTC317
                    ),
7ff8adafe9e4atagen2026-10-22 12:30 UTC318
                    |bencher| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC319
                        bencher.to_async(&runtime).iter_batched(
7ff8adafe9e4atagen2026-10-22 12:30 UTC320
                            // The setup.
7ff8adafe9e4atagen2026-10-22 12:30 UTC321
                            || (room_event_cache.clone(), filter.clone()),
7ff8adafe9e4atagen2026-10-22 12:30 UTC322
                            // The routine itself.
7ff8adafe9e4atagen2026-10-22 12:30 UTC323
                            |(room_event_cache, filter)| async move {
7ff8adafe9e4atagen2026-10-22 12:30 UTC324
                                let (target, relations) = room_event_cache
7ff8adafe9e4atagen2026-10-22 12:30 UTC325
                                    .find_event_with_relations(target_event_id, filter)
7ff8adafe9e4atagen2026-10-22 12:30 UTC326
                                    .await
7ff8adafe9e4atagen2026-10-22 12:30 UTC327
                                    .unwrap()
7ff8adafe9e4atagen2026-10-22 12:30 UTC328
                                    .unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC329
                                assert_eq!(target.event_id().unwrap(), *target_event_id);
7ff8adafe9e4atagen2026-10-22 12:30 UTC330
                                assert_eq!(relations.len(), num_related_events as usize);
7ff8adafe9e4atagen2026-10-22 12:30 UTC331
                            },
7ff8adafe9e4atagen2026-10-22 12:30 UTC332
                            criterion::BatchSize::PerIteration,
7ff8adafe9e4atagen2026-10-22 12:30 UTC333
                        )
7ff8adafe9e4atagen2026-10-22 12:30 UTC334
                    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC335
                );
7ff8adafe9e4atagen2026-10-22 12:30 UTC336
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC337
7ff8adafe9e4atagen2026-10-22 12:30 UTC338
            {
7ff8adafe9e4atagen2026-10-22 12:30 UTC339
                let _guard = runtime.enter();
7ff8adafe9e4atagen2026-10-22 12:30 UTC340
                drop(room_event_cache);
7ff8adafe9e4atagen2026-10-22 12:30 UTC341
                drop(client);
7ff8adafe9e4atagen2026-10-22 12:30 UTC342
                drop(_drop_handles);
7ff8adafe9e4atagen2026-10-22 12:30 UTC343
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC344
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC345
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC346
7ff8adafe9e4atagen2026-10-22 12:30 UTC347
    {
7ff8adafe9e4atagen2026-10-22 12:30 UTC348
        let _guard = runtime.enter();
7ff8adafe9e4atagen2026-10-22 12:30 UTC349
        drop(state_store);
7ff8adafe9e4atagen2026-10-22 12:30 UTC350
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC351
7ff8adafe9e4atagen2026-10-22 12:30 UTC352
    group.finish()
7ff8adafe9e4atagen2026-10-22 12:30 UTC353
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC354
7ff8adafe9e4atagen2026-10-22 12:30 UTC355
criterion_group! {
7ff8adafe9e4atagen2026-10-22 12:30 UTC356
    name = event_cache;
7ff8adafe9e4atagen2026-10-22 12:30 UTC357
    config = Criterion::default();
7ff8adafe9e4atagen2026-10-22 12:30 UTC358
    targets = handle_room_updates, find_event_relations,
7ff8adafe9e4atagen2026-10-22 12:30 UTC359
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC360
7ff8adafe9e4atagen2026-10-22 12:30 UTC361
criterion_main!(event_cache);