Documentation
¶
Overview ¶
Package fswatch provides shared helpers for Pando's recursive filesystem watchers. On macOS fsnotify uses kqueue, which costs one file descriptor per watched directory and per file inside it, so every watcher must skip heavy, generated and ignored directories BEFORE calling fsnotify's Add.
Index ¶
- Constants
- func CodeWatchLockPath(workdir string) string
- func DefaultExcludedDirs() []string
- func EstimateCost(goos string, dirs, files int) int
- func TryLock(path string) (release func(), ok bool, err error)
- func TryLockDir(workdir string) (release func(), ok bool, err error)
- type Excluder
- type Hub
- type Subscription
- type WatchBudget
Constants ¶
const WarnThreshold = 10000
WarnThreshold is the estimated file-descriptor cost above which a watcher logs a one-time warning.
Variables ¶
This section is empty.
Functions ¶
func CodeWatchLockPath ¶
CodeWatchLockPath returns the per-project lock file that guards the startup code index and recursive filesystem watcher: <workdir>/.pando/code-watch.lock.
func DefaultExcludedDirs ¶
func DefaultExcludedDirs() []string
DefaultExcludedDirs returns the sorted built-in directory names and suffix globs (for example "*.dSYM") that are excluded from watching.
func EstimateCost ¶
EstimateCost returns the estimated number of file descriptors (or kernel watches) needed to watch dirs directories holding files regular files. kqueue platforms (macOS, BSD) spend one descriptor per directory AND per file; inotify (Linux) and others only count directories.
func TryLock ¶
TryLock takes a non-blocking exclusive flock on path. ok is false when another open file description (in this or another process) holds it. The lock is released automatically if the process dies. release is idempotent.
func TryLockDir ¶
TryLockDir creates <workdir>/.pando if needed and tries to take the non-blocking exclusive code-watch lock for workdir. See TryLock.
Types ¶
type Excluder ¶
type Excluder struct {
// contains filtered or unexported fields
}
Excluder decides which directories a watcher must not register. It is safe for concurrent use.
func NewExcluder ¶
NewExcluder builds an Excluder for the watch root. extra holds user patterns (the WatchExclude config): plain directory names or doublestar globs relative to root, e.g. "mobile-app/www/svg" or "**/generated".
func (*Excluder) ShouldSkipDir ¶
ShouldSkipDir reports whether the directory at absPath must not be watched. The root itself is never skipped. When a directory is kept, its own .gitignore/.pandoignore are loaded so they apply to its children.
type Hub ¶
type Hub struct {
// contains filtered or unexported fields
}
Hub owns ONE recursive fsnotify watcher for a workspace and fans every event out to any number of subscribers.
On macOS (kqueue) fsnotify spends one file descriptor per watched directory and per file inside it, so each extra full-tree watcher multiplies the FD cost. Sharing one watcher keeps that cost constant regardless of how many consumers (LSP clients, the bootstrap watcher, ...) exist.
Lifecycle: the underlying watcher is started lazily by the first Subscribe and keeps running until Close (app shutdown), even if every subscriber leaves. LSP restarts unsubscribe and resubscribe in quick succession, and tearing the tree down and re-walking it each time would be wasteful.
func NewHub ¶
NewHub creates a hub for root. excluder decides which directories are never watched; when nil one is built from the defaults.
func (*Hub) Close ¶
func (h *Hub) Close()
Close stops the shared watcher and closes every subscription. It blocks until the watcher goroutine has released its file descriptors.
func (*Hub) PathCount ¶
PathCount returns how many directories are currently registered with the underlying fsnotify watcher (kept in sync on removals).
func (*Hub) Subscribe ¶
func (h *Hub) Subscribe() *Subscription
Subscribe registers a new subscriber, starting the shared watcher on first use. It returns nil when the hub is closed.
func (*Hub) SubscriberCount ¶
SubscriberCount returns the number of active subscriptions.
type Subscription ¶
type Subscription struct {
// Events delivers every filesystem event the hub observes. It is closed
// when the subscription is closed or the hub is shut down.
Events <-chan fsnotify.Event
// contains filtered or unexported fields
}
Subscription receives the events of a Hub until Close is called.
func (*Subscription) Close ¶
func (s *Subscription) Close()
Close unsubscribes; no further events are delivered and Events is closed.
func (*Subscription) Dropped ¶
func (s *Subscription) Dropped() int64
Dropped returns how many events were discarded because the subscriber was too slow.
type WatchBudget ¶
type WatchBudget struct {
// contains filtered or unexported fields
}
WatchBudget tracks the watch cost of one watcher instance and warns once when it exceeds the threshold. It is safe for concurrent use.
func NewWatchBudget ¶
func NewWatchBudget(name, root string) *WatchBudget
NewWatchBudget creates a budget for the named watcher ("lsp-workspace", "code-index", ...) rooted at root.
func (*WatchBudget) AddDir ¶
func (b *WatchBudget) AddDir()
AddDir records one watched directory. Nil-safe.
func (*WatchBudget) AddFile ¶
func (b *WatchBudget) AddFile()
AddFile records one file living directly inside a watched directory. Nil-safe.
func (*WatchBudget) Check ¶
func (b *WatchBudget) Check() bool
Check logs a single warning (per budget) when the estimate exceeds the threshold. It returns true when the warning was emitted by this call.
func (*WatchBudget) Cost ¶
func (b *WatchBudget) Cost() int
Cost returns the current estimated FD cost.