@@ -137,7 +137,7 @@ jobs:
github.repository_owner == 'zed-industries' &&
needs.job_spec.outputs.run_tests == 'true'
runs-on:
- - buildjet-8vcpu-ubuntu-2204
+ - github-8vcpu-ubuntu-2204
steps:
- name: Checkout repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
@@ -168,7 +168,7 @@ jobs:
needs: [job_spec]
if: github.repository_owner == 'zed-industries'
runs-on:
- - buildjet-8vcpu-ubuntu-2204
+ - github-8vcpu-ubuntu-2204
steps:
- name: Checkout repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
@@ -221,7 +221,7 @@ jobs:
github.repository_owner == 'zed-industries' &&
(needs.job_spec.outputs.run_tests == 'true' || needs.job_spec.outputs.run_docs == 'true')
runs-on:
- - buildjet-8vcpu-ubuntu-2204
+ - github-8vcpu-ubuntu-2204
steps:
- name: Checkout repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
@@ -328,7 +328,7 @@ jobs:
github.repository_owner == 'zed-industries' &&
needs.job_spec.outputs.run_tests == 'true'
runs-on:
- - buildjet-16vcpu-ubuntu-2204
+ - github-16vcpu-ubuntu-2204
steps:
- name: Add Rust to the PATH
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
@@ -342,7 +342,7 @@ jobs:
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- cache-provider: "buildjet"
+ # cache-provider: "buildjet"
- name: Install Linux dependencies
run: ./script/linux
@@ -380,7 +380,7 @@ jobs:
github.repository_owner == 'zed-industries' &&
needs.job_spec.outputs.run_tests == 'true'
runs-on:
- - buildjet-8vcpu-ubuntu-2204
+ - github-8vcpu-ubuntu-2204
steps:
- name: Add Rust to the PATH
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
@@ -394,7 +394,7 @@ jobs:
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- cache-provider: "buildjet"
+ # cache-provider: "buildjet"
- name: Install Clang & Mold
run: ./script/remote-server && ./script/install-mold 2.34.0
@@ -597,7 +597,8 @@ jobs:
timeout-minutes: 60
name: Linux x86_x64 release bundle
runs-on:
- - buildjet-16vcpu-ubuntu-2004 # ubuntu 20.04 for minimal glibc
+ - github-16vcpu-ubuntu-2204
+ # - buildjet-16vcpu-ubuntu-2004 # ubuntu 20.04 for minimal glibc
if: |
startsWith(github.ref, 'refs/tags/v')
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
@@ -650,7 +651,7 @@ jobs:
timeout-minutes: 60
name: Linux arm64 release bundle
runs-on:
- - buildjet-32vcpu-ubuntu-2204-arm
+ - github-16vcpu-ubuntu-2204-arm
if: |
startsWith(github.ref, 'refs/tags/v')
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
@@ -1,9 +1,6 @@
use notify::EventKind;
use parking_lot::Mutex;
-use std::{
- collections::HashMap,
- sync::{Arc, OnceLock},
-};
+use std::sync::{Arc, OnceLock};
use util::{ResultExt, paths::SanitizedPath};
use crate::{PathEvent, PathEventKind, Watcher};
@@ -11,7 +8,6 @@ use crate::{PathEvent, PathEventKind, Watcher};
pub struct FsWatcher {
tx: smol::channel::Sender<()>,
pending_path_events: Arc<Mutex<Vec<PathEvent>>>,
- registrations: Mutex<HashMap<Arc<std::path::Path>, WatcherRegistrationId>>,
}
impl FsWatcher {
@@ -22,24 +18,10 @@ impl FsWatcher {
Self {
tx,
pending_path_events,
- registrations: Default::default(),
}
}
}
-impl Drop for FsWatcher {
- fn drop(&mut self) {
- let mut registrations = self.registrations.lock();
- let registrations = registrations.drain();
-
- let _ = global(|g| {
- for (_, registration) in registrations {
- g.remove(registration);
- }
- });
- }
-}
-
impl Watcher for FsWatcher {
fn add(&self, path: &std::path::Path) -> anyhow::Result<()> {
let root_path = SanitizedPath::from(path);
@@ -47,136 +29,75 @@ impl Watcher for FsWatcher {
let tx = self.tx.clone();
let pending_paths = self.pending_path_events.clone();
- let path: Arc<std::path::Path> = path.into();
-
- if self.registrations.lock().contains_key(&path) {
- return Ok(());
- }
+ use notify::Watcher;
- let registration_id = global({
- let path = path.clone();
+ global({
|g| {
- g.add(
- path,
- notify::RecursiveMode::NonRecursive,
- move |event: ¬ify::Event| {
- let kind = match event.kind {
- EventKind::Create(_) => Some(PathEventKind::Created),
- EventKind::Modify(_) => Some(PathEventKind::Changed),
- EventKind::Remove(_) => Some(PathEventKind::Removed),
- _ => None,
- };
- let mut path_events = event
- .paths
- .iter()
- .filter_map(|event_path| {
- let event_path = SanitizedPath::from(event_path);
- event_path.starts_with(&root_path).then(|| PathEvent {
- path: event_path.as_path().to_path_buf(),
- kind,
- })
+ g.add(move |event: ¬ify::Event| {
+ let kind = match event.kind {
+ EventKind::Create(_) => Some(PathEventKind::Created),
+ EventKind::Modify(_) => Some(PathEventKind::Changed),
+ EventKind::Remove(_) => Some(PathEventKind::Removed),
+ _ => None,
+ };
+ let mut path_events = event
+ .paths
+ .iter()
+ .filter_map(|event_path| {
+ let event_path = SanitizedPath::from(event_path);
+ event_path.starts_with(&root_path).then(|| PathEvent {
+ path: event_path.as_path().to_path_buf(),
+ kind,
})
- .collect::<Vec<_>>();
-
- if !path_events.is_empty() {
- path_events.sort();
- let mut pending_paths = pending_paths.lock();
- if pending_paths.is_empty() {
- tx.try_send(()).ok();
- }
- util::extend_sorted(
- &mut *pending_paths,
- path_events,
- usize::MAX,
- |a, b| a.path.cmp(&b.path),
- );
+ })
+ .collect::<Vec<_>>();
+
+ if !path_events.is_empty() {
+ path_events.sort();
+ let mut pending_paths = pending_paths.lock();
+ if pending_paths.is_empty() {
+ tx.try_send(()).ok();
}
- },
- )
+ util::extend_sorted(
+ &mut *pending_paths,
+ path_events,
+ usize::MAX,
+ |a, b| a.path.cmp(&b.path),
+ );
+ }
+ })
}
- })??;
+ })?;
- self.registrations.lock().insert(path, registration_id);
+ global(|g| {
+ g.watcher
+ .lock()
+ .watch(path, notify::RecursiveMode::NonRecursive)
+ })??;
Ok(())
}
fn remove(&self, path: &std::path::Path) -> anyhow::Result<()> {
- let Some(registration) = self.registrations.lock().remove(path) else {
- return Ok(());
- };
-
- global(|w| w.remove(registration))
+ use notify::Watcher;
+ Ok(global(|w| w.watcher.lock().unwatch(path))??)
}
}
-#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct WatcherRegistrationId(u32);
-
-struct WatcherRegistrationState {
- callback: Box<dyn Fn(¬ify::Event) + Send + Sync>,
- path: Arc<std::path::Path>,
-}
-
-struct WatcherState {
+pub struct GlobalWatcher {
// two mutexes because calling watcher.add triggers an watcher.event, which needs watchers.
#[cfg(target_os = "linux")]
- watcher: notify::INotifyWatcher,
+ pub(super) watcher: Mutex<notify::INotifyWatcher>,
#[cfg(target_os = "freebsd")]
- watcher: notify::KqueueWatcher,
+ pub(super) watcher: Mutex<notify::KqueueWatcher>,
#[cfg(target_os = "windows")]
- watcher: notify::ReadDirectoryChangesWatcher,
-
- watchers: HashMap<WatcherRegistrationId, WatcherRegistrationState>,
- path_registrations: HashMap<Arc<std::path::Path>, u32>,
- last_registration: WatcherRegistrationId,
-}
-
-pub struct GlobalWatcher {
- state: Mutex<WatcherState>,
+ pub(super) watcher: Mutex<notify::ReadDirectoryChangesWatcher>,
+ pub(super) watchers: Mutex<Vec<Box<dyn Fn(¬ify::Event) + Send + Sync>>>,
}
impl GlobalWatcher {
- #[must_use]
- fn add(
- &self,
- path: Arc<std::path::Path>,
- mode: notify::RecursiveMode,
- cb: impl Fn(¬ify::Event) + Send + Sync + 'static,
- ) -> anyhow::Result<WatcherRegistrationId> {
- use notify::Watcher;
- let mut state = self.state.lock();
-
- state.watcher.watch(&path, mode)?;
-
- let id = state.last_registration;
- state.last_registration = WatcherRegistrationId(id.0 + 1);
-
- let registration_state = WatcherRegistrationState {
- callback: Box::new(cb),
- path: path.clone(),
- };
- state.watchers.insert(id, registration_state);
- *state.path_registrations.entry(path.clone()).or_insert(0) += 1;
-
- Ok(id)
- }
-
- pub fn remove(&self, id: WatcherRegistrationId) {
- use notify::Watcher;
- let mut state = self.state.lock();
- let Some(registration_state) = state.watchers.remove(&id) else {
- return;
- };
-
- let Some(count) = state.path_registrations.get_mut(®istration_state.path) else {
- return;
- };
- *count -= 1;
- if *count == 0 {
- state.watcher.unwatch(®istration_state.path).log_err();
- state.path_registrations.remove(®istration_state.path);
- }
+ pub(super) fn add(&self, cb: impl Fn(¬ify::Event) + Send + Sync + 'static) {
+ self.watchers.lock().push(Box::new(cb))
}
}
@@ -193,10 +114,8 @@ fn handle_event(event: Result<notify::Event, notify::Error>) {
return;
};
global::<()>(move |watcher| {
- let state = watcher.state.lock();
- for registration in state.watchers.values() {
- let callback = ®istration.callback;
- callback(&event);
+ for f in watcher.watchers.lock().iter() {
+ f(&event)
}
})
.log_err();
@@ -205,12 +124,8 @@ fn handle_event(event: Result<notify::Event, notify::Error>) {
pub fn global<T>(f: impl FnOnce(&GlobalWatcher) -> T) -> anyhow::Result<T> {
let result = FS_WATCHER_INSTANCE.get_or_init(|| {
notify::recommended_watcher(handle_event).map(|file_watcher| GlobalWatcher {
- state: Mutex::new(WatcherState {
- watcher: file_watcher,
- watchers: Default::default(),
- path_registrations: Default::default(),
- last_registration: Default::default(),
- }),
+ watcher: Mutex::new(file_watcher),
+ watchers: Default::default(),
})
});
match result {