in shards/watcher.go [79:151]
func (s *DirectoryWatcher) scan() error {
fs, err := filepath.Glob(filepath.Join(s.dir, "*.zoekt"))
if err != nil {
return err
}
if len(s.timestamps) == 0 && len(fs) == 0 {
return fmt.Errorf("directory %s is empty", s.dir)
}
ts := map[string]time.Time{}
for _, fn := range fs {
fi, err := os.Lstat(fn)
if err != nil {
continue
}
ts[fn] = fi.ModTime()
}
var toLoad []string
for k, mtime := range ts {
if t, ok := s.timestamps[k]; !ok || t != mtime {
toLoad = append(toLoad, k)
s.timestamps[k] = mtime
}
}
var toDrop []string
// Unload deleted shards.
for k := range s.timestamps {
if _, ok := ts[k]; !ok {
toDrop = append(toDrop, k)
delete(s.timestamps, k)
}
}
if len(toDrop) > 0 {
log.Printf("unloading %d shard(s)", len(toDrop))
}
for _, t := range toDrop {
log.Printf("unloading: %s", filepath.Base(t))
s.loader.drop(t)
}
if len(toLoad) == 0 {
return nil
}
log.Printf("loading %d shard(s): %s", len(toLoad), humanTruncateList(toLoad, 5))
// Limit amount of concurrent shard loads.
throttle := make(chan struct{}, runtime.GOMAXPROCS(0))
lastProgress := time.Now()
for i, t := range toLoad {
// If taking a while to start-up occasionally give a progress message
if time.Since(lastProgress) > 10*time.Second {
log.Printf("still need to load %d shards...", len(toLoad)-i)
lastProgress = time.Now()
}
throttle <- struct{}{}
go func(k string) {
s.loader.load(k)
<-throttle
}(t)
}
for i := 0; i < cap(throttle); i++ {
throttle <- struct{}{}
}
return nil
}