Introduce LocalSnapshot
This allows us to remove the absolute path and scan-related state from the Snapshot. None of this data is relevant or valid on guests.
This commit is contained in:
parent
d192b6ebc7
commit
506ce8e032
2 changed files with 81 additions and 64 deletions
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
path = "src/project.rs"
|
||||
|
|
|
@ -30,7 +30,7 @@ use std::{
|
|||
ffi::{OsStr, OsString},
|
||||
fmt,
|
||||
future::Future,
|
||||
ops::Deref,
|
||||
ops::{Deref, DerefMut},
|
||||
path::{Path, PathBuf},
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||
|
@ -54,9 +54,9 @@ pub enum Worktree {
|
|||
}
|
||||
|
||||
pub struct LocalWorktree {
|
||||
snapshot: Snapshot,
|
||||
snapshot: LocalSnapshot,
|
||||
config: WorktreeConfig,
|
||||
background_snapshot: Arc<Mutex<Snapshot>>,
|
||||
background_snapshot: Arc<Mutex<LocalSnapshot>>,
|
||||
last_scan_state_rx: watch::Receiver<ScanState>,
|
||||
_background_scanner_task: Option<Task<()>>,
|
||||
poll_task: Option<Task<()>>,
|
||||
|
@ -85,15 +85,34 @@ pub struct RemoteWorktree {
|
|||
#[derive(Clone)]
|
||||
pub struct Snapshot {
|
||||
id: WorktreeId,
|
||||
scan_id: usize,
|
||||
abs_path: Arc<Path>,
|
||||
root_name: String,
|
||||
root_char_bag: CharBag,
|
||||
ignores: HashMap<Arc<Path>, (Arc<Gitignore>, usize)>,
|
||||
entries_by_path: SumTree<Entry>,
|
||||
entries_by_id: SumTree<PathEntry>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LocalSnapshot {
|
||||
abs_path: Arc<Path>,
|
||||
scan_id: usize,
|
||||
ignores: HashMap<Arc<Path>, (Arc<Gitignore>, usize)>,
|
||||
removed_entry_ids: HashMap<u64, usize>,
|
||||
next_entry_id: Arc<AtomicUsize>,
|
||||
snapshot: Snapshot,
|
||||
}
|
||||
|
||||
impl Deref for LocalSnapshot {
|
||||
type Target = Snapshot;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.snapshot
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for LocalSnapshot {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.snapshot
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -112,7 +131,7 @@ enum Registration {
|
|||
|
||||
struct ShareState {
|
||||
project_id: u64,
|
||||
snapshots_tx: Sender<Snapshot>,
|
||||
snapshots_tx: Sender<LocalSnapshot>,
|
||||
_maintain_remote_snapshot: Option<Task<()>>,
|
||||
}
|
||||
|
||||
|
@ -158,7 +177,7 @@ impl Worktree {
|
|||
let (tree, scan_states_tx) = LocalWorktree::new(client, path, weak, fs.clone(), cx).await?;
|
||||
tree.update(cx, |tree, cx| {
|
||||
let tree = tree.as_local_mut().unwrap();
|
||||
let abs_path = tree.snapshot.abs_path.clone();
|
||||
let abs_path = tree.abs_path().clone();
|
||||
let background_snapshot = tree.background_snapshot.clone();
|
||||
let background = cx.background().clone();
|
||||
tree._background_scanner_task = Some(cx.background().spawn(async move {
|
||||
|
@ -233,15 +252,10 @@ impl Worktree {
|
|||
cx.add_model(|cx: &mut ModelContext<Worktree>| {
|
||||
let snapshot = Snapshot {
|
||||
id: WorktreeId(remote_id as usize),
|
||||
scan_id: 0,
|
||||
abs_path: Path::new("").into(),
|
||||
root_name,
|
||||
root_char_bag,
|
||||
ignores: Default::default(),
|
||||
entries_by_path,
|
||||
entries_by_id,
|
||||
removed_entry_ids: Default::default(),
|
||||
next_entry_id: Default::default(),
|
||||
};
|
||||
|
||||
let (updates_tx, mut updates_rx) = postage::mpsc::channel(64);
|
||||
|
@ -328,7 +342,7 @@ impl Worktree {
|
|||
|
||||
pub fn snapshot(&self) -> Snapshot {
|
||||
match self {
|
||||
Worktree::Local(worktree) => worktree.snapshot(),
|
||||
Worktree::Local(worktree) => worktree.snapshot().snapshot,
|
||||
Worktree::Remote(worktree) => worktree.snapshot(),
|
||||
}
|
||||
}
|
||||
|
@ -469,28 +483,28 @@ impl LocalWorktree {
|
|||
let (scan_states_tx, scan_states_rx) = smol::channel::unbounded();
|
||||
let (mut last_scan_state_tx, last_scan_state_rx) = watch::channel_with(ScanState::Scanning);
|
||||
let tree = cx.add_model(move |cx: &mut ModelContext<Worktree>| {
|
||||
let mut snapshot = Snapshot {
|
||||
id: WorktreeId::from_usize(cx.model_id()),
|
||||
scan_id: 0,
|
||||
let mut snapshot = LocalSnapshot {
|
||||
abs_path,
|
||||
root_name: root_name.clone(),
|
||||
root_char_bag,
|
||||
scan_id: 0,
|
||||
ignores: Default::default(),
|
||||
entries_by_path: Default::default(),
|
||||
entries_by_id: Default::default(),
|
||||
removed_entry_ids: Default::default(),
|
||||
next_entry_id: Arc::new(next_entry_id),
|
||||
snapshot: Snapshot {
|
||||
id: WorktreeId::from_usize(cx.model_id()),
|
||||
root_name: root_name.clone(),
|
||||
root_char_bag,
|
||||
entries_by_path: Default::default(),
|
||||
entries_by_id: Default::default(),
|
||||
},
|
||||
};
|
||||
if let Some(metadata) = metadata {
|
||||
snapshot.insert_entry(
|
||||
Entry::new(
|
||||
path.into(),
|
||||
&metadata,
|
||||
&snapshot.next_entry_id,
|
||||
snapshot.root_char_bag,
|
||||
),
|
||||
fs.as_ref(),
|
||||
let entry = Entry::new(
|
||||
path.into(),
|
||||
&metadata,
|
||||
&snapshot.next_entry_id,
|
||||
snapshot.root_char_bag,
|
||||
);
|
||||
snapshot.insert_entry(entry, fs.as_ref());
|
||||
}
|
||||
|
||||
let tree = Self {
|
||||
|
@ -547,6 +561,18 @@ impl LocalWorktree {
|
|||
&self.abs_path
|
||||
}
|
||||
|
||||
pub fn contains_abs_path(&self, path: &Path) -> bool {
|
||||
path.starts_with(&self.abs_path)
|
||||
}
|
||||
|
||||
fn absolutize(&self, path: &Path) -> PathBuf {
|
||||
if path.file_name().is_some() {
|
||||
self.abs_path.join(path)
|
||||
} else {
|
||||
self.abs_path.to_path_buf()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn authorized_logins(&self) -> Vec<String> {
|
||||
self.config.collaborators.clone()
|
||||
}
|
||||
|
@ -628,7 +654,7 @@ impl LocalWorktree {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn snapshot(&self) -> Snapshot {
|
||||
pub fn snapshot(&self) -> LocalSnapshot {
|
||||
self.snapshot.clone()
|
||||
}
|
||||
|
||||
|
@ -754,7 +780,8 @@ impl LocalWorktree {
|
|||
let snapshot = self.snapshot();
|
||||
let rpc = self.client.clone();
|
||||
let worktree_id = cx.model_id() as u64;
|
||||
let (snapshots_to_send_tx, snapshots_to_send_rx) = smol::channel::unbounded::<Snapshot>();
|
||||
let (snapshots_to_send_tx, snapshots_to_send_rx) =
|
||||
smol::channel::unbounded::<LocalSnapshot>();
|
||||
let maintain_remote_snapshot = cx.background().spawn({
|
||||
let rpc = rpc.clone();
|
||||
let snapshot = snapshot.clone();
|
||||
|
@ -974,9 +1001,6 @@ impl Snapshot {
|
|||
}
|
||||
|
||||
pub(crate) fn apply_update(&mut self, update: proto::UpdateWorktree) -> Result<()> {
|
||||
self.scan_id += 1;
|
||||
let scan_id = self.scan_id;
|
||||
|
||||
let mut entries_by_path_edits = Vec::new();
|
||||
let mut entries_by_id_edits = Vec::new();
|
||||
for entry_id in update.removed_entries {
|
||||
|
@ -997,7 +1021,7 @@ impl Snapshot {
|
|||
id: entry.id,
|
||||
path: entry.path.clone(),
|
||||
is_ignored: entry.is_ignored,
|
||||
scan_id,
|
||||
scan_id: 0,
|
||||
}));
|
||||
entries_by_path_edits.push(Edit::Insert(entry));
|
||||
}
|
||||
|
@ -1084,18 +1108,6 @@ impl Snapshot {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn contains_abs_path(&self, path: &Path) -> bool {
|
||||
path.starts_with(&self.abs_path)
|
||||
}
|
||||
|
||||
fn absolutize(&self, path: &Path) -> PathBuf {
|
||||
if path.file_name().is_some() {
|
||||
self.abs_path.join(path)
|
||||
} else {
|
||||
self.abs_path.to_path_buf()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn root_entry(&self) -> Option<&Entry> {
|
||||
self.entry_for_path("")
|
||||
}
|
||||
|
@ -1125,7 +1137,9 @@ impl Snapshot {
|
|||
pub fn inode_for_path(&self, path: impl AsRef<Path>) -> Option<u64> {
|
||||
self.entry_for_path(path.as_ref()).map(|e| e.inode)
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalSnapshot {
|
||||
fn insert_entry(&mut self, mut entry: Entry, fs: &dyn Fs) -> Entry {
|
||||
if !entry.is_dir() && entry.path.file_name() == Some(&GITIGNORE) {
|
||||
let abs_path = self.abs_path.join(&entry.path);
|
||||
|
@ -1147,12 +1161,13 @@ impl Snapshot {
|
|||
|
||||
self.reuse_entry_id(&mut entry);
|
||||
self.entries_by_path.insert_or_replace(entry.clone(), &());
|
||||
let scan_id = self.scan_id;
|
||||
self.entries_by_id.insert_or_replace(
|
||||
PathEntry {
|
||||
id: entry.id,
|
||||
path: entry.path.clone(),
|
||||
is_ignored: entry.is_ignored,
|
||||
scan_id: self.scan_id,
|
||||
scan_id,
|
||||
},
|
||||
&(),
|
||||
);
|
||||
|
@ -1308,7 +1323,7 @@ impl Deref for Worktree {
|
|||
}
|
||||
|
||||
impl Deref for LocalWorktree {
|
||||
type Target = Snapshot;
|
||||
type Target = LocalSnapshot;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.snapshot
|
||||
|
@ -1679,14 +1694,14 @@ impl<'a> sum_tree::Dimension<'a, EntrySummary> for PathKey {
|
|||
|
||||
struct BackgroundScanner {
|
||||
fs: Arc<dyn Fs>,
|
||||
snapshot: Arc<Mutex<Snapshot>>,
|
||||
snapshot: Arc<Mutex<LocalSnapshot>>,
|
||||
notify: Sender<ScanState>,
|
||||
executor: Arc<executor::Background>,
|
||||
}
|
||||
|
||||
impl BackgroundScanner {
|
||||
fn new(
|
||||
snapshot: Arc<Mutex<Snapshot>>,
|
||||
snapshot: Arc<Mutex<LocalSnapshot>>,
|
||||
notify: Sender<ScanState>,
|
||||
fs: Arc<dyn Fs>,
|
||||
executor: Arc<executor::Background>,
|
||||
|
@ -1703,7 +1718,7 @@ impl BackgroundScanner {
|
|||
self.snapshot.lock().abs_path.clone()
|
||||
}
|
||||
|
||||
fn snapshot(&self) -> Snapshot {
|
||||
fn snapshot(&self) -> LocalSnapshot {
|
||||
self.snapshot.lock().clone()
|
||||
}
|
||||
|
||||
|
@ -2046,7 +2061,7 @@ impl BackgroundScanner {
|
|||
.await;
|
||||
}
|
||||
|
||||
async fn update_ignore_status(&self, job: UpdateIgnoreStatusJob, snapshot: &Snapshot) {
|
||||
async fn update_ignore_status(&self, job: UpdateIgnoreStatusJob, snapshot: &LocalSnapshot) {
|
||||
let mut ignore_stack = job.ignore_stack;
|
||||
if let Some((ignore, _)) = snapshot.ignores.get(&job.path) {
|
||||
ignore_stack = ignore_stack.append(job.path.clone(), ignore.clone());
|
||||
|
@ -2090,7 +2105,7 @@ impl BackgroundScanner {
|
|||
|
||||
async fn refresh_entry(
|
||||
fs: &dyn Fs,
|
||||
snapshot: &Mutex<Snapshot>,
|
||||
snapshot: &Mutex<LocalSnapshot>,
|
||||
path: Arc<Path>,
|
||||
abs_path: &Path,
|
||||
) -> Result<Entry> {
|
||||
|
@ -2158,7 +2173,7 @@ impl WorktreeHandle for ModelHandle<Worktree> {
|
|||
use smol::future::FutureExt;
|
||||
|
||||
let filename = "fs-event-sentinel";
|
||||
let root_path = cx.read(|cx| self.read(cx).abs_path.clone());
|
||||
let root_path = cx.read(|cx| self.read(cx).as_local().unwrap().abs_path().clone());
|
||||
let tree = self.clone();
|
||||
async move {
|
||||
std::fs::write(root_path.join(filename), "").unwrap();
|
||||
|
@ -2510,17 +2525,19 @@ mod tests {
|
|||
let (notify_tx, _notify_rx) = smol::channel::unbounded();
|
||||
let fs = Arc::new(RealFs);
|
||||
let next_entry_id = Arc::new(AtomicUsize::new(0));
|
||||
let mut initial_snapshot = Snapshot {
|
||||
id: WorktreeId::from_usize(0),
|
||||
scan_id: 0,
|
||||
let mut initial_snapshot = LocalSnapshot {
|
||||
abs_path: root_dir.path().into(),
|
||||
entries_by_path: Default::default(),
|
||||
entries_by_id: Default::default(),
|
||||
scan_id: 0,
|
||||
removed_entry_ids: Default::default(),
|
||||
ignores: Default::default(),
|
||||
root_name: Default::default(),
|
||||
root_char_bag: Default::default(),
|
||||
next_entry_id: next_entry_id.clone(),
|
||||
snapshot: Snapshot {
|
||||
id: WorktreeId::from_usize(0),
|
||||
entries_by_path: Default::default(),
|
||||
entries_by_id: Default::default(),
|
||||
root_name: Default::default(),
|
||||
root_char_bag: Default::default(),
|
||||
},
|
||||
};
|
||||
initial_snapshot.insert_entry(
|
||||
Entry::new(
|
||||
|
@ -2756,7 +2773,7 @@ mod tests {
|
|||
.collect()
|
||||
}
|
||||
|
||||
impl Snapshot {
|
||||
impl LocalSnapshot {
|
||||
fn check_invariants(&self) {
|
||||
let mut files = self.files(true, 0);
|
||||
let mut visible_files = self.files(false, 0);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue