Batch persistent history reads during reverse search (#33905)

## Why

Reverse search fetched persistent history one entry at a time, making a deep or unsuccessful search require a lookup for every older entry.

## What changed

- Keep the newest-entry probe lightweight, then scan older persistent history in bounded batches.
- Cache batch results by absolute offset and preserve continuation cursors across repeated searches.
- Ignore stale responses, retry failed batch reads a bounded number of times, and restore the draft without reporting a false “no match” state when history is unavailable.

## Testing

- Cover batch continuation, caching after query changes or cancellation, stale metadata, retry exhaustion, and thread routing.
- Verify that scanning 1,024 entries uses one single-entry lookup and eight batch lookups.

GitOrigin-RevId: efc791fcbd5290050af703dd31c5c21b33240e23
This commit is contained in:
Charlie Marsh authored and copyberry committed 2026-07-17 21:16:07 +00:00
1 parent 025db22058
commit 7ed19a9758
13 files changed
+965 -107

No files matched your search

+23 -10
View File
@@ -19,6 +19,7 @@ use std::path::PathBuf;
use crate::app::app_server_requests::ResolvedAppServerRequest;
use crate::app_event::AppEvent;
use crate::app_event::ConnectorsSnapshot;
use crate::app_event::HistoryLookupResponse;
use crate::app_event_sender::AppEventSender;
use crate::bottom_pane::pending_input_preview::PendingInputPreview;
use crate::bottom_pane::pending_thread_approvals::PendingThreadApprovals;
@@ -1621,16 +1622,28 @@ impl BottomPane {
|| self.composer.is_in_paste_burst()
}
pub(crate) fn on_history_entry_response(
&mut self,
log_id: u64,
offset: usize,
entry: Option<String>,
) {
let updated = self
.composer
.on_history_entry_response(log_id, offset, entry);
pub(crate) fn on_history_lookup_response(&mut self, response: HistoryLookupResponse) {
let updated = match response {
HistoryLookupResponse::Entry {
offset,
log_id,
entry,
} => self
.composer
.on_history_entry_response(log_id, offset, entry),
HistoryLookupResponse::Batch {
cursor,
log_id,
entries,
next_older_cursor,
} => {
self.composer
.on_history_batch_response(log_id, cursor, entries, next_older_cursor)
}
HistoryLookupResponse::BatchError { cursor, log_id } => {
self.composer.on_history_batch_error(log_id, cursor)
}
};
if updated {
self.composer.sync_popups();
self.request_redraw();