Skip to content

Commit 425a310

Browse files
committed
Benchmark file-backed chat-list readiness
Measure release-mode readiness and row fetches on encrypted files with 10,000 and 100,000 retained messages. Alternate the receipt index off and on, exclude setup, and verify identical chat rows.
1 parent 796f765 commit 425a310

1 file changed

Lines changed: 78 additions & 0 deletions

File tree

  • crates/storage-sqlite/src/chat_list

crates/storage-sqlite/src/chat_list/tests.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,84 @@ fn setup_store() -> SqliteAccountStorage {
158158
setup_store_with_group(group())
159159
}
160160

161+
// Compare the existing readiness API with migration 0066’s index on synthetic history.
162+
// Setup, index construction, and the connection/KDF are outside the timed region.
163+
// Run: cargo test -p storage-sqlite --release --lib chat_startup_benchmark -- --ignored --nocapture
164+
#[test]
165+
#[ignore = "file-backed chat startup performance investigation"]
166+
fn chat_startup_benchmark() {
167+
let dir = tempfile::tempdir().unwrap();
168+
let key = SqlCipherKey::new("synthetic chat benchmark").unwrap();
169+
let store =
170+
SqliteAccountStorage::open_encrypted(dir.path().join("account.sqlite3"), &key).unwrap();
171+
store
172+
.save_account_projection_state(
173+
&StoredAccountState {
174+
label: "benchmark".to_owned(),
175+
groups: vec![group()],
176+
..StoredAccountState::default()
177+
},
178+
256,
179+
MAX_FUTURE_SKEW_SECS,
180+
)
181+
.unwrap();
182+
store
183+
.lock()
184+
.unwrap()
185+
.execute_batch("DROP INDEX idx_message_timeline_group_received")
186+
.unwrap();
187+
let mut seeded = 0;
188+
let body = "x".repeat(512);
189+
for count in [10_000, 100_000] {
190+
cgka_traits::StorageProvider::with_transaction(&store, |store| {
191+
for index in seeded..count {
192+
let mut event = chat(&format!("{index:064x}"), REMOTE, index, &body);
193+
event.source_epoch = Some(1);
194+
store.record_app_event(&event)?;
195+
}
196+
Ok::<_, cgka_traits::StorageError>(())
197+
})
198+
.unwrap();
199+
seeded = count;
200+
let id = format!("{:064x}", count - 1);
201+
store
202+
.mark_timeline_message_read(LOCAL, GROUP, &id, &no_mentions)
203+
.unwrap();
204+
store.ensure_chat_list_rows(LOCAL, &no_mentions).unwrap();
205+
let expected = store.chat_list_rows(ChatListQuery::default()).unwrap();
206+
assert_eq!(expected.len(), 1);
207+
assert_eq!(
208+
expected[0].last_message.as_ref().unwrap().message_id_hex,
209+
id
210+
);
211+
assert_eq!(expected[0].unread_count, 0);
212+
// Repeat A/B after dropping the index to expose cache/order effects.
213+
for mode in ["baseline", "indexed", "baseline", "indexed"] {
214+
if mode == "indexed" {
215+
store.lock().unwrap().execute_batch("CREATE INDEX idx_message_timeline_group_received ON message_timeline(group_id_hex, received_at)").unwrap();
216+
}
217+
store.ensure_chat_list_rows(LOCAL, &no_mentions).unwrap();
218+
let mut samples = Vec::new();
219+
for _ in 0..7 {
220+
let start = std::time::Instant::now();
221+
store.ensure_chat_list_rows(LOCAL, &no_mentions).unwrap();
222+
let rows = store.chat_list_rows(ChatListQuery::default()).unwrap();
223+
samples.push(start.elapsed().as_micros());
224+
assert_eq!(rows, expected);
225+
}
226+
samples.sort_unstable();
227+
eprintln!("count={count} mode={mode} median_us={}", samples[3]);
228+
if mode == "indexed" {
229+
store
230+
.lock()
231+
.unwrap()
232+
.execute_batch("DROP INDEX idx_message_timeline_group_received")
233+
.unwrap();
234+
}
235+
}
236+
}
237+
}
238+
161239
/// Preview work stays bounded for accepted history and displaced pending sends.
162240
#[test]
163241
fn preview_query_work() {

0 commit comments

Comments
 (0)