Do not eagerly cancel running tasks

This commit is contained in:
Kirill Bulatov 2023-06-24 23:46:20 +03:00
parent 4d4544f680
commit 11fee4ce42
2 changed files with 115 additions and 46 deletions

View file

@ -2632,7 +2632,7 @@ impl Editor {
}
InlayRefreshReason::NewLinesShown => InvalidationStrategy::None,
InlayRefreshReason::ExcerptEdited => InvalidationStrategy::OnConflict,
InlayRefreshReason::RefreshRequested => InvalidationStrategy::All,
InlayRefreshReason::RefreshRequested => InvalidationStrategy::Forced,
};
let excerpts_to_query = self
@ -2680,7 +2680,6 @@ impl Editor {
.into_iter()
.map(|(position, id, hint)| {
let mut text = hint.text();
// TODO kb styling instead?
if hint.padding_right {
text.push(' ');
}

View file

@ -19,11 +19,17 @@ pub struct InlayHintCache {
pub hints: HashMap<ExcerptId, Arc<RwLock<CachedExcerptHints>>>,
pub allowed_hint_kinds: HashSet<Option<InlayHintKind>>,
pub version: usize,
update_tasks: HashMap<ExcerptId, InlayHintUpdateTask>,
update_tasks: HashMap<ExcerptId, UpdateTask>,
}
struct InlayHintUpdateTask {
struct UpdateTask {
current: (InvalidationStrategy, SpawnedTask),
pending_refresh: Option<SpawnedTask>,
}
struct SpawnedTask {
version: usize,
is_running_rx: smol::channel::Receiver<()>,
_task: Task<()>,
}
@ -51,6 +57,31 @@ struct ExcerptDimensions {
excerpt_visible_range_end: language::Anchor,
}
impl UpdateTask {
fn new(invalidation_strategy: InvalidationStrategy, spawned_task: SpawnedTask) -> Self {
Self {
current: (invalidation_strategy, spawned_task),
pending_refresh: None,
}
}
fn is_running(&self) -> bool {
!self.current.1.is_running_rx.is_closed()
|| self
.pending_refresh
.as_ref()
.map_or(false, |task| !task.is_running_rx.is_closed())
}
fn cache_version(&self) -> usize {
self.current.1.version
}
fn invalidation_strategy(&self) -> InvalidationStrategy {
self.current.0
}
}
impl ExcerptDimensions {
fn contains_position(
&self,
@ -80,7 +111,7 @@ impl ExcerptDimensions {
#[derive(Debug, Clone, Copy)]
pub enum InvalidationStrategy {
All,
Forced,
OnConflict,
None,
}
@ -157,7 +188,7 @@ impl InlayHintCache {
let update_tasks = &mut self.update_tasks;
let invalidate_cache = matches!(
invalidate,
InvalidationStrategy::All | InvalidationStrategy::OnConflict
InvalidationStrategy::Forced | InvalidationStrategy::OnConflict
);
if invalidate_cache {
update_tasks
@ -166,22 +197,7 @@ impl InlayHintCache {
let cache_version = self.version;
excerpts_to_query.retain(|visible_excerpt_id, _| {
match update_tasks.entry(*visible_excerpt_id) {
hash_map::Entry::Occupied(o) => match o.get().version.cmp(&cache_version) {
cmp::Ordering::Less => true,
cmp::Ordering::Equal => invalidate_cache,
cmp::Ordering::Greater => false,
},
hash_map::Entry::Vacant(_) => true,
}
});
if invalidate_cache {
update_tasks
.retain(|task_excerpt_id, _| excerpts_to_query.contains_key(task_excerpt_id));
}
excerpts_to_query.retain(|visible_excerpt_id, _| {
match update_tasks.entry(*visible_excerpt_id) {
hash_map::Entry::Occupied(o) => match o.get().version.cmp(&cache_version) {
hash_map::Entry::Occupied(o) => match o.get().cache_version().cmp(&cache_version) {
cmp::Ordering::Less => true,
cmp::Ordering::Equal => invalidate_cache,
cmp::Ordering::Greater => false,
@ -313,8 +329,8 @@ impl InlayHintCache {
fn spawn_new_update_tasks(
editor: &mut Editor,
excerpts_to_query: HashMap<ExcerptId, (ModelHandle<Buffer>, Range<usize>)>,
invalidate: InvalidationStrategy,
cache_version: usize,
invalidation_strategy: InvalidationStrategy,
update_cache_version: usize,
cx: &mut ViewContext<'_, '_, Editor>,
) {
let visible_hints = Arc::new(visible_inlay_hints(editor, cx).cloned().collect::<Vec<_>>());
@ -323,21 +339,27 @@ fn spawn_new_update_tasks(
let buffer = buffer_handle.read(cx);
let buffer_snapshot = buffer.snapshot();
let cached_excerpt_hints = editor.inlay_hint_cache.hints.get(&excerpt_id).cloned();
if let Some(cached_excerpt_hints) = &cached_excerpt_hints {
let cache_is_empty = match &cached_excerpt_hints {
Some(cached_excerpt_hints) => {
let new_task_buffer_version = buffer_snapshot.version();
let cached_excerpt_hints = cached_excerpt_hints.read();
let cached_buffer_version = &cached_excerpt_hints.buffer_version;
if cached_buffer_version.changed_since(new_task_buffer_version) {
return;
}
// TODO kb on refresh (InvalidationStrategy::All), instead spawn a new task afterwards, that would wait before 1st query finishes
if !new_task_buffer_version.changed_since(&cached_buffer_version)
&& !matches!(invalidate, InvalidationStrategy::All)
if cached_excerpt_hints.version > update_cache_version
|| cached_buffer_version.changed_since(new_task_buffer_version)
{
return;
}
if !new_task_buffer_version.changed_since(&cached_buffer_version)
&& !matches!(invalidation_strategy, InvalidationStrategy::Forced)
{
return;
}
cached_excerpt_hints.hints.is_empty()
}
None => true,
};
let buffer_id = buffer.remote_id();
let excerpt_visible_range_start = buffer.anchor_before(excerpt_visible_range.start);
let excerpt_visible_range_end = buffer.anchor_after(excerpt_visible_range.end);
@ -365,21 +387,62 @@ fn spawn_new_update_tasks(
excerpt_visible_range_start,
excerpt_visible_range_end,
},
cache_version,
invalidate,
cache_version: update_cache_version,
invalidate: invalidation_strategy,
};
editor.inlay_hint_cache.update_tasks.insert(
excerpt_id,
let new_update_task = |previous_task| {
new_update_task(
query,
multi_buffer_snapshot,
buffer_snapshot,
Arc::clone(&visible_hints),
cached_excerpt_hints,
previous_task,
cx,
),
);
)
};
match editor.inlay_hint_cache.update_tasks.entry(excerpt_id) {
hash_map::Entry::Occupied(mut o) => {
let update_task = o.get_mut();
if update_task.is_running() {
match (update_task.invalidation_strategy(), invalidation_strategy) {
(InvalidationStrategy::Forced, InvalidationStrategy::Forced)
| (_, InvalidationStrategy::OnConflict) => {
o.insert(UpdateTask::new(
invalidation_strategy,
new_update_task(None),
));
}
(InvalidationStrategy::Forced, _) => {}
(_, InvalidationStrategy::Forced) => {
if cache_is_empty {
o.insert(UpdateTask::new(
invalidation_strategy,
new_update_task(None),
));
} else if update_task.pending_refresh.is_none() {
update_task.pending_refresh = Some(new_update_task(Some(
update_task.current.1.is_running_rx.clone(),
)));
}
}
_ => {}
}
} else {
o.insert(UpdateTask::new(
invalidation_strategy,
new_update_task(None),
));
}
}
hash_map::Entry::Vacant(v) => {
v.insert(UpdateTask::new(
invalidation_strategy,
new_update_task(None),
));
}
}
}
}
}
@ -391,10 +454,16 @@ fn new_update_task(
buffer_snapshot: BufferSnapshot,
visible_hints: Arc<Vec<Inlay>>,
cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
previous_task: Option<smol::channel::Receiver<()>>,
cx: &mut ViewContext<'_, '_, Editor>,
) -> InlayHintUpdateTask {
) -> SpawnedTask {
let hints_fetch_tasks = hints_fetch_tasks(query, &buffer_snapshot, cx);
let (is_running_tx, is_running_rx) = smol::channel::bounded(1);
let _task = cx.spawn(|editor, cx| async move {
let _is_running_tx = is_running_tx;
if let Some(previous_task) = previous_task {
previous_task.recv().await.ok();
}
let create_update_task = |range, hint_fetch_task| {
fetch_and_update_hints(
editor.clone(),
@ -437,9 +506,10 @@ fn new_update_task(
}
});
InlayHintUpdateTask {
SpawnedTask {
version: query.cache_version,
_task,
is_running_rx,
}
}
@ -597,7 +667,7 @@ fn calculate_hint_updates(
let mut remove_from_cache = HashSet::default();
if matches!(
query.invalidate,
InvalidationStrategy::All | InvalidationStrategy::OnConflict
InvalidationStrategy::Forced | InvalidationStrategy::OnConflict
) {
remove_from_visible.extend(
visible_hints