WIP - try representing snapshots_to_send as a watch

This commit is contained in:
Max Brunsfeld 2022-06-30 18:04:31 -07:00
parent 5fdbc38f46
commit 8a105bf12f

View file

@ -134,7 +134,7 @@ enum ScanState {
struct ShareState { struct ShareState {
project_id: u64, project_id: u64,
snapshots_tx: Sender<LocalSnapshot>, snapshots_tx: watch::Sender<LocalSnapshot>,
_maintain_remote_snapshot: Option<Task<Option<()>>>, _maintain_remote_snapshot: Option<Task<Option<()>>>,
} }
@ -334,38 +334,9 @@ impl Worktree {
fn poll_snapshot(&mut self, cx: &mut ModelContext<Self>) { fn poll_snapshot(&mut self, cx: &mut ModelContext<Self>) {
match self { match self {
Self::Local(worktree) => { Self::Local(worktree) => worktree.poll_snapshot(cx),
let is_fake_fs = worktree.fs.is_fake(); Self::Remote(worktree) => worktree.poll_snapshot(cx),
worktree.snapshot = worktree.background_snapshot.lock().clone();
if matches!(worktree.scan_state(), ScanState::Initializing) {
if worktree.poll_task.is_none() {
worktree.poll_task = Some(cx.spawn_weak(|this, mut cx| async move {
if is_fake_fs {
#[cfg(any(test, feature = "test-support"))]
cx.background().simulate_random_delay().await;
} else {
smol::Timer::after(Duration::from_millis(100)).await;
}
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
this.as_local_mut().unwrap().poll_task = None;
this.poll_snapshot(cx);
});
}
}));
}
} else {
worktree.poll_task.take();
cx.emit(Event::UpdatedEntries);
}
}
Self::Remote(worktree) => {
worktree.snapshot = worktree.background_snapshot.lock().clone();
cx.emit(Event::UpdatedEntries);
}
}; };
cx.notify();
} }
} }
@ -441,9 +412,8 @@ impl LocalWorktree {
last_scan_state_tx.blocking_send(scan_state).ok(); last_scan_state_tx.blocking_send(scan_state).ok();
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
this.poll_snapshot(cx); this.poll_snapshot(cx);
this.as_local().unwrap().broadcast_snapshot() this.as_local_mut().unwrap().broadcast_snapshot()
}) });
.await;
} else { } else {
break; break;
} }
@ -527,6 +497,40 @@ impl LocalWorktree {
Ok(updated) Ok(updated)
} }
fn poll_snapshot(&mut self, cx: &mut ModelContext<Worktree>) {
match self.scan_state() {
ScanState::Idle => {
self.snapshot = self.background_snapshot.lock().clone();
self.poll_task.take();
cx.emit(Event::UpdatedEntries);
}
ScanState::Initializing => {
self.snapshot = self.background_snapshot.lock().clone();
if self.poll_task.is_none() {
let is_fake_fs = self.fs.is_fake();
self.poll_task = Some(cx.spawn_weak(|this, mut cx| async move {
if is_fake_fs {
#[cfg(any(test, feature = "test-support"))]
cx.background().simulate_random_delay().await;
} else {
smol::Timer::after(Duration::from_millis(100)).await;
}
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
this.as_local_mut().unwrap().poll_task = None;
this.poll_snapshot(cx);
});
}
}));
}
cx.emit(Event::UpdatedEntries);
}
ScanState::Updating => {}
ScanState::Err(_) => {}
}
cx.notify();
}
pub fn scan_complete(&self) -> impl Future<Output = ()> { pub fn scan_complete(&self) -> impl Future<Output = ()> {
let mut scan_state_rx = self.last_scan_state_rx.clone(); let mut scan_state_rx = self.last_scan_state_rx.clone();
async move { async move {
@ -666,16 +670,15 @@ impl LocalWorktree {
Some(cx.spawn(|this, mut cx| async move { Some(cx.spawn(|this, mut cx| async move {
delete.await?; delete.await?;
this.update(&mut cx, |this, _| { this.update(&mut cx, |this, cx| {
let this = this.as_local_mut().unwrap(); let this = this.as_local_mut().unwrap();
{
let mut snapshot = this.background_snapshot.lock(); let mut snapshot = this.background_snapshot.lock();
snapshot.delete_entry(entry_id); snapshot.delete_entry(entry_id);
}); }
this.update(&mut cx, |this, cx| {
this.poll_snapshot(cx); this.poll_snapshot(cx);
this.as_local().unwrap().broadcast_snapshot() this.broadcast_snapshot();
}) });
.await;
Ok(()) Ok(())
})) }))
} }
@ -712,10 +715,10 @@ impl LocalWorktree {
}) })
.await?; .await?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
let this = this.as_local_mut().unwrap();
this.poll_snapshot(cx); this.poll_snapshot(cx);
this.as_local().unwrap().broadcast_snapshot() this.broadcast_snapshot();
}) });
.await;
Ok(entry) Ok(entry)
})) }))
} }
@ -752,10 +755,10 @@ impl LocalWorktree {
}) })
.await?; .await?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
let this = this.as_local_mut().unwrap();
this.poll_snapshot(cx); this.poll_snapshot(cx);
this.as_local().unwrap().broadcast_snapshot() this.broadcast_snapshot()
}) });
.await;
Ok(entry) Ok(entry)
})) }))
} }
@ -790,10 +793,10 @@ impl LocalWorktree {
}) })
.await?; .await?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
let this = this.as_local_mut().unwrap();
this.poll_snapshot(cx); this.poll_snapshot(cx);
this.as_local().unwrap().broadcast_snapshot() this.broadcast_snapshot();
}) });
.await;
Ok(entry) Ok(entry)
}) })
} }
@ -826,8 +829,10 @@ impl LocalWorktree {
let this = this let this = this
.upgrade(&cx) .upgrade(&cx)
.ok_or_else(|| anyhow!("worktree was dropped"))?; .ok_or_else(|| anyhow!("worktree was dropped"))?;
let (entry, snapshot, snapshots_tx) = this.read_with(&cx, |this, _| { this.update(&mut cx, |this, cx| {
let this = this.as_local().unwrap(); let this = this.as_local_mut().unwrap();
let inserted_entry;
{
let mut snapshot = this.background_snapshot.lock(); let mut snapshot = this.background_snapshot.lock();
entry.is_ignored = snapshot entry.is_ignored = snapshot
.ignore_stack_for_path(&path, entry.is_dir()) .ignore_stack_for_path(&path, entry.is_dir())
@ -835,36 +840,31 @@ impl LocalWorktree {
if let Some(old_path) = old_path { if let Some(old_path) = old_path {
snapshot.remove_path(&old_path); snapshot.remove_path(&old_path);
} }
let entry = snapshot.insert_entry(entry, fs.as_ref()); inserted_entry = snapshot.insert_entry(entry, fs.as_ref());
snapshot.scan_id += 1; snapshot.scan_id += 1;
let snapshots_tx = this.share.as_ref().map(|s| s.snapshots_tx.clone());
(entry, snapshot.clone(), snapshots_tx)
});
this.update(&mut cx, |this, cx| this.poll_snapshot(cx));
if let Some(snapshots_tx) = snapshots_tx {
snapshots_tx.send(snapshot).await.ok();
} }
this.poll_snapshot(cx);
Ok(entry) this.broadcast_snapshot();
Ok(inserted_entry)
})
}) })
} }
pub fn share(&mut self, project_id: u64, cx: &mut ModelContext<Worktree>) -> Task<Result<()>> { pub fn share(&mut self, project_id: u64, cx: &mut ModelContext<Worktree>) -> Task<Result<()>> {
let (share_tx, share_rx) = oneshot::channel(); let (share_tx, share_rx) = oneshot::channel();
let (snapshots_to_send_tx, snapshots_to_send_rx) =
smol::channel::unbounded::<LocalSnapshot>();
if self.share.is_some() { if self.share.is_some() {
let _ = share_tx.send(Ok(())); let _ = share_tx.send(Ok(()));
} else { } else {
let (snapshots_tx, mut snapshots_rx) = watch::channel_with(self.snapshot());
let rpc = self.client.clone(); let rpc = self.client.clone();
let worktree_id = cx.model_id() as u64; let worktree_id = cx.model_id() as u64;
let maintain_remote_snapshot = cx.background().spawn({ let maintain_remote_snapshot = cx.background().spawn({
let rpc = rpc.clone(); let rpc = rpc.clone();
let diagnostic_summaries = self.diagnostic_summaries.clone(); let diagnostic_summaries = self.diagnostic_summaries.clone();
async move { async move {
let mut prev_snapshot = match snapshots_to_send_rx.recv().await { let mut prev_snapshot = match snapshots_rx.recv().await {
Ok(snapshot) => { Some(snapshot) => {
let update = proto::UpdateWorktree { let update = proto::UpdateWorktree {
project_id, project_id,
worktree_id, worktree_id,
@ -886,8 +886,10 @@ impl LocalWorktree {
snapshot snapshot
} }
} }
Err(error) => { None => {
let _ = share_tx.send(Err(error.into())); share_tx
.send(Err(anyhow!("worktree dropped before share completed")))
.ok();
return Err(anyhow!("failed to send initial update worktree")); return Err(anyhow!("failed to send initial update worktree"));
} }
}; };
@ -900,11 +902,7 @@ impl LocalWorktree {
})?; })?;
} }
while let Ok(mut snapshot) = snapshots_to_send_rx.recv().await { while let Some(snapshot) = snapshots_rx.recv().await {
while let Ok(newer_snapshot) = snapshots_to_send_rx.try_recv() {
snapshot = newer_snapshot;
}
send_worktree_update( send_worktree_update(
&rpc, &rpc,
snapshot.build_update(&prev_snapshot, project_id, worktree_id, true), snapshot.build_update(&prev_snapshot, project_id, worktree_id, true),
@ -919,18 +917,12 @@ impl LocalWorktree {
}); });
self.share = Some(ShareState { self.share = Some(ShareState {
project_id, project_id,
snapshots_tx: snapshots_to_send_tx.clone(), snapshots_tx,
_maintain_remote_snapshot: Some(maintain_remote_snapshot), _maintain_remote_snapshot: Some(maintain_remote_snapshot),
}); });
} }
cx.spawn_weak(|this, cx| async move { cx.foreground().spawn(async move {
if let Some(this) = this.upgrade(&cx) {
this.read_with(&cx, |this, _| {
let this = this.as_local().unwrap();
let _ = snapshots_to_send_tx.try_send(this.snapshot());
});
}
share_rx share_rx
.await .await
.unwrap_or_else(|_| Err(anyhow!("share ended"))) .unwrap_or_else(|_| Err(anyhow!("share ended")))
@ -945,19 +937,11 @@ impl LocalWorktree {
self.share.is_some() self.share.is_some()
} }
fn broadcast_snapshot(&self) -> impl Future<Output = ()> { fn broadcast_snapshot(&mut self) {
let mut to_send = None;
if matches!(self.scan_state(), ScanState::Idle) { if matches!(self.scan_state(), ScanState::Idle) {
if let Some(share) = self.share.as_ref() { let snapshot = self.snapshot();
to_send = Some((self.snapshot(), share.snapshots_tx.clone())); if let Some(share) = self.share.as_mut() {
} *share.snapshots_tx.borrow_mut() = snapshot;
}
async move {
if let Some((snapshot, snapshots_to_send_tx)) = to_send {
if let Err(err) = snapshots_to_send_tx.send(snapshot).await {
log::error!("error submitting snapshot to send {}", err);
}
} }
} }
} }
@ -968,6 +952,12 @@ impl RemoteWorktree {
self.snapshot.clone() self.snapshot.clone()
} }
fn poll_snapshot(&mut self, cx: &mut ModelContext<Worktree>) {
self.snapshot = self.background_snapshot.lock().clone();
cx.emit(Event::UpdatedEntries);
cx.notify();
}
pub fn disconnected_from_host(&mut self) { pub fn disconnected_from_host(&mut self) {
self.updates_tx.take(); self.updates_tx.take();
self.snapshot_subscriptions.clear(); self.snapshot_subscriptions.clear();