diff --git a/config.go b/config.go index 12fc124..dee054e 100644 --- a/config.go +++ b/config.go @@ -3,6 +3,7 @@ package main import ( "log" "os" + "sync" "time" "github.com/gorhill/cronexpr" @@ -19,12 +20,13 @@ const ( ) type Repo struct { - URL string `yaml:"url"` - URLs []string `yaml:"urls"` - Mirrorlist string `yaml:"mirrorlist"` - HttpProxy string `yaml:"http_proxy"` - LastMirrorlistCheck time.Time `yaml:"-"` - LastModificationTime time.Time `yaml:"-"` + URL string `yaml:"url"` + URLs []string `yaml:"urls"` + Mirrorlist string `yaml:"mirrorlist"` + HttpProxy string `yaml:"http_proxy"` + LastMirrorlistCheck time.Time `yaml:"-"` + MirrorlistMutex sync.Mutex `yaml:"-"` + LastModificationTime time.Time `yaml:"-"` } type RefreshPeriod struct { diff --git a/downloader.go b/downloader.go index b22b1d0..a5ee38a 100644 --- a/downloader.go +++ b/downloader.go @@ -59,7 +59,8 @@ func (d *Downloader) decrementUsage() { } func (d *Downloader) download() error { - if len(d.repo.getUrls()) == 0 { + urls := d.repo.getUrls() + if len(urls) == 0 { return fmt.Errorf("repo %v has no urls", d.repoName) } @@ -70,7 +71,7 @@ func (d *Downloader) download() error { proxyURL = nil } - for _, u := range d.repo.getUrls() { + for _, u := range urls { err := d.downloadFromUpstream(u, proxyURL) if err != nil { log.Printf("unable to download file %v: %v", d.key, err) diff --git a/urls.go b/urls.go index 1ebaab8..39c531f 100644 --- a/urls.go +++ b/urls.go @@ -44,11 +44,23 @@ func parseMirrorlistURLs(file *os.File) ([]string, error) { } func (r *Repo) getMirrorlistURLs() ([]string, error) { - if time.Since(r.LastMirrorlistCheck) < 5*time.Second { + const MirrorlistCheckInterval = 5*time.Second + + if time.Since(r.LastMirrorlistCheck) < MirrorlistCheckInterval { + return r.URLs, nil + } + + r.MirrorlistMutex.Lock() + defer r.MirrorlistMutex.Unlock() + + // Test time again in case another routine already checked in the meantime + if time.Since(r.LastMirrorlistCheck) < MirrorlistCheckInterval { return r.URLs, nil } - r.LastMirrorlistCheck = time.Now() + defer func() { + r.LastMirrorlistCheck = time.Now() + }() fileInfo, err := os.Stat(r.Mirrorlist) if err != nil {