Sessions refresh when a watch reports a change
A session answers many queries. A refresh before each one would check every file’s metadata each time, which on a large project costs far more than the query itself, and on Windows means opening every file.
Decision
An updating session (-l without -d, or with --auto-refresh) keeps a watch on
what its index was made from: inotify on Linux and ReadDirectoryChangesW on Windows.
Before each query it asks the watch whether anything a refresh reads has changed, and
refreshes only then. The refresh itself is the ordinary one of
ADR 0007.
- Covered before it is read. Once a refresh holds the write lock, and before it looks at any file, it gives the watch the selection rule and the revision it starts from. The watch then covers the directories that hold the indexed files, every include candidate it looked up, found or missing, the file list, the directories discovery walks and the targets of links. Anything the new revision needs beyond that is covered afterwards, and the next query refreshes again.
- Every change made before the query. On Linux inotify queues an event before the system call that made the change returns, so the watch empties its queue. On Windows events reach a watcher thread later, so the watch creates a marker file in the root and waits for that file’s event.
- Only changes a refresh would see. Events for the index and its SQLite files, editor swap and backup files, build output and any other name a refresh would not read are ignored.
- When unsure, refresh. Lost events, a watched directory that moved or was removed, or a revision another process published make the next query refresh. Where no watch can be made at all, every query refreshes, with a note.
- Checks where no watch reaches. Some directories have no watch: on Windows an include directory outside the root or one reached through a junction, and on Linux one outside the root on a network file system. Before each query the names a refresh read or asked about there are checked by their metadata. A directory where many of them are missing is checked by its times instead, which move when a name in it is made, removed or renamed.
Consequences
- A query on an unchanged project answers at once from the published revision. A
query after a change costs what an explicit
rcosts. - Text searches also refresh first after a change, so they search the files selected now.
- One-shot queries refresh when they start, since no process outlives them to keep a watch. The editor integrations use sessions for this reason (ADR 0014).
- inotify reports only changes made through this machine, so sources on a network file
system refresh before every query. So does a tree with more directories than
fs.inotify.max_user_watchesallows. - A tool that sets a directory’s times back after writing into it, such as bsdtar or
7-Zip, hides the names it made there from a directory checked by its times until the
next explicit
r. - Windows needs the
notifycrate’s 9.0 line, which reports a buffer overflow so the watch can rescan. Earlier versions drop it silently. Linux uses inotify throughrustix. - On Windows a build that writes a few hundred files or more into the tree at once can overflow that buffer, and the marker’s event may be lost with the rest. The overflow ends the wait, so the next query refreshes and starts a new watch at once rather than after the marker’s 500 ms deadline.