Documentation
¶
Overview ¶
Package watch follows a directory tree for changes, so a backup of it can take the directories nothing changed in whole from its previous commit. A Source reports what changed through one backend: fanotify or inotify on Linux, the NTFS change journal on Windows. A Tracker follows a Source for any number of sets, and a Schedule decides, per set, what a run reads and when a change starts one.
Index ¶
- Constants
- Variables
- type Changes
- type FileStore
- type MemoryStore
- type Options
- type Position
- type Record
- type Run
- type Schedule
- func (s *Schedule) Begin(set string, latest []byte, at *Position) Run
- func (s *Schedule) Check()
- func (s *Schedule) End(r Run, commit []byte, err error) error
- func (s *Schedule) Run(ctx context.Context, interval time.Duration)
- func (s *Schedule) Started(set string, at time.Time)
- func (s *Schedule) State(set string) State
- func (s *Schedule) Unwatch(set string)
- func (s *Schedule) Watch(set string, t *Tracker, o Options)
- type Source
- type State
- type Store
- type Tracker
- func (t *Tracker) After(p Position) (unchanged func(rel string) bool, ok bool)
- func (t *Tracker) Changed(p Position) bool
- func (t *Tracker) Close() error
- func (t *Tracker) Following() bool
- func (t *Tracker) Now() (Position, error)
- func (t *Tracker) Poll(from Position) error
- func (t *Tracker) Prune(floor Position)
- func (t *Tracker) State() TrackerState
- type TrackerState
- type Trigger
Constants ¶
const ( // FullNotFollowing: no tracker follows the root, or it can't tell its // present, so the run has no position to record either. FullNotFollowing = "not-following" // FullFirst: the set has no record of a run yet. FullFirst = "first" // FullSettings: the run reads the tree with other settings than the // last, such as other filters. FullSettings = "settings-changed" // FullDue: the set's last full read is FullReadEvery ago. FullDue = "full-read-due" // FullOtherCommit: the set's latest commit isn't the one its last run // made. FullOtherCommit = "other-commit" // FullInDoubt: the tracker can't tell what changed since the last run, // as after a restart, a queue overflow or the root moving. FullInDoubt = "in-doubt" )
The reasons a run reads the whole tree.
const MaxDirs = 50_000
MaxDirs bounds how many changed paths a Tracker keeps before it counts reading the tree in full as cheaper.
Variables ¶
var ErrInDoubt = errors.New("the change tracking can't tell what changed")
ErrInDoubt is a Source's error when it can't tell what changed since a position: its queue overflowed, the position is from another stream or too old, or the root was moved or unmounted.
var ErrStarting = errors.New("the change tracking is still starting")
ErrStarting is a Source's error while it is still setting up; it has no position yet.
ErrUnavailable is Open's error when no backend can follow the root.
Functions ¶
This section is empty.
Types ¶
type Changes ¶
type Changes struct {
// Dirs are the directories whose entries changed, each with its
// ancestors.
Dirs map[string]int64 `json:"dirs,omitempty"`
// Trees are the directories everything under which changed, as one
// created or moved in.
Trees map[string]int64 `json:"trees,omitempty"`
// Unwatched are the subtrees the source can't follow, with why; they
// count as changed until the source starts again.
Unwatched map[string]string `json:"unwatched,omitempty"`
}
Changes is what changed under a root, as slash-separated paths below it ("" is the root), each with the Seq of its latest change.
func (*Changes) Mark ¶
Mark records that the directory rel changed at seq, and so did each of its ancestors.
type FileStore ¶
type FileStore struct {
// contains filtered or unexported fields
}
FileStore is a Store in one JSON file.
func OpenFileStore ¶
OpenFileStore opens the FileStore at path, empty when there is no file there; one that doesn't parse is empty too, so every set is read in full once.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore is a Store that keeps Records in memory.
type Options ¶
type Options struct {
// MinGap is the least time from a run's start to a run on change.
MinGap time.Duration
// FullReadEvery is how often a run reads everything whatever the
// tracker says; zero never.
FullReadEvery time.Duration
// Settings fingerprints what besides the tree decides what a run
// reads, such as its filters; a run with other settings reads
// everything.
Settings string
}
Options are how a Schedule watches one set.
type Position ¶
Position marks a point in a Source's changes: Stream names an unbroken run of them, and Seq orders the changes in it. Positions of different streams don't compare.
type Record ¶
type Record struct {
Position Position `json:"position"`
Commit []byte `json:"commit"`
Settings string `json:"settings"`
FullAt time.Time `json:"full_at"`
}
Record is what a set's last watched run left: the position taken before it read the tree, the commit it made or kept, the settings it read the tree with and when the set was last read in full.
type Run ¶
type Run struct {
Set string
// At is the position to record once the run succeeds; zero when there
// is none.
At Position
// Unchanged reports the directories the run takes from the set's
// latest commit, for job.PathSettings.Unchanged; nil reads everything.
Unchanged func(rel string) bool
// Full is why the run reads everything, one of the Full reasons; empty
// when Unchanged is set.
Full string
// Detail says more about Full, such as why the tracker isn't following.
Detail string
// contains filtered or unexported fields
}
Run is what one run of a set reads.
type Schedule ¶
type Schedule struct {
Store Store
Trigger Trigger
// Now is the clock; nil is time.Now.
Now func() time.Time
Logger *slog.Logger
// contains filtered or unexported fields
}
Schedule decides for watched sets what each run reads, from the set's Record and its root's Tracker, and starts a run through Trigger once something changed and MinGap has passed since the set's last run started. A set without a Record, or whose tracker can't tell what changed, runs on change too.
func (*Schedule) Begin ¶
Begin starts a run of set, whose latest commit is latest, and says what it reads. at is the position to record, taken before a snapshot the run reads; nil takes it now. End must follow.
func (*Schedule) Check ¶
func (s *Schedule) Check()
Check reads every tracker's changes and starts the run of each watched set that changed since its last run, once its gap has passed. A set whose tracker isn't following runs on its plan alone.
func (*Schedule) End ¶
End ends r. When err is nil it records r's position with commit, the commit the run made or kept, for the set's next run.
func (*Schedule) Started ¶
Started tells the schedule a run of set started at, when it began before the schedule saw it, as the scan start of the set's newest commit.
type Source ¶
type Source interface {
// Backend names how the source follows the root, as inotify.
Backend() string
// Now is the position of the present: a change after it has a Seq at or
// past its Seq.
Now() (Position, error)
// Read is what changed from from on, or ErrInDoubt, and the position it
// read to, which the next Read starts from.
Read(from Position) (*Changes, Position, error)
Close() error
}
Source reports the changes under one root through one backend.
type State ¶
type State struct {
TrackerState
Watched bool `json:"watched"`
}
State is how a set is watched.
type Store ¶
Store keeps each set's Record; a Schedule loads one as a run of the set starts and saves one once it succeeded.
type Tracker ¶
type Tracker struct {
// contains filtered or unexported fields
}
Tracker follows the changes of one root for every set backing it up, each of which asks what changed after its own position. It reads them from a Source when polled, opening a new one when the last one stopped following the root.
func NewTracker ¶
NewTracker returns a Tracker reading the Sources open opens. It opens the first one on the first Poll.
func (*Tracker) After ¶
After reports, for a set whose last run took position p before it read the tree, whether nothing at or under a slash-separated directory below the root changed since; ok is false when the tracker can't tell. unchanged is safe for concurrent use and doesn't change as the tracker reads on.
func (*Tracker) Changed ¶
Changed reports whether something under the root changed after p, or the tracker can't tell; subtrees it can't follow don't count.
func (*Tracker) Following ¶
Following reports whether the tracker follows the root without a gap since it last started.
func (*Tracker) Now ¶
Now is the source's present, the position a run takes before it reads the tree.
func (*Tracker) Poll ¶
Poll reads what changed since the last Poll. A tracker that isn't following yet starts at from, the oldest position a set still asks about, or at the present when from is zero or the source can't read from it. When the source loses track, every set whose position is from before counts as in doubt, and the error says why.
func (*Tracker) State ¶
func (t *Tracker) State() TrackerState
State reports how the tracker follows the root.
type TrackerState ¶
type TrackerState struct {
// Backend names the source's backend; empty before one opened.
Backend string `json:"backend,omitempty"`
Following bool `json:"following"`
// Reason is why the tracker isn't following, or last lost track.
Reason string `json:"reason,omitempty"`
// Unwatched are the subtrees it can't follow, with why.
Unwatched map[string]string `json:"unwatched,omitempty"`
}
TrackerState is what a Tracker reports about itself.