reflector.go/store/speedwalk/speedwalk.go

88 lines
1.8 KiB
Go
Raw Permalink Normal View History

package speedwalk
import (
"io/ioutil"
"path/filepath"
"runtime"
"sync"
"github.com/lbryio/lbry.go/v2/extras/errors"
"github.com/karrick/godirwalk"
"github.com/sirupsen/logrus"
)
// AllFiles recursively lists every file in every subdirectory of a given directory
2020-11-02 20:48:56 +01:00
// If basename is true, return the basename of each file. Otherwise return the full path starting at startDir.
func AllFiles(startDir string, basename bool) ([]string, error) {
items, err := ioutil.ReadDir(startDir)
if err != nil {
return nil, err
}
pathChan := make(chan string)
paths := make([]string, 0, 1000)
2020-11-02 20:48:56 +01:00
pathWG := &sync.WaitGroup{}
pathWG.Add(1)
go func() {
2020-11-02 20:48:56 +01:00
defer pathWG.Done()
for {
path, ok := <-pathChan
if !ok {
return
}
paths = append(paths, path)
}
}()
maxThreads := runtime.NumCPU() - 1
goroutineLimiter := make(chan struct{}, maxThreads)
for i := 0; i < maxThreads; i++ {
goroutineLimiter <- struct{}{}
}
2020-11-02 20:48:56 +01:00
walkerWG := &sync.WaitGroup{}
for _, item := range items {
if !item.IsDir() {
if basename {
pathChan <- item.Name()
} else {
pathChan <- filepath.Join(startDir, item.Name())
}
continue
}
<-goroutineLimiter
2020-11-02 20:48:56 +01:00
walkerWG.Add(1)
go func(dir string) {
defer func() {
2020-11-02 20:48:56 +01:00
walkerWG.Done()
goroutineLimiter <- struct{}{}
}()
err = godirwalk.Walk(filepath.Join(startDir, dir), &godirwalk.Options{
Unsorted: true, // faster this way
Callback: func(osPathname string, de *godirwalk.Dirent) error {
if de.IsRegular() {
if basename {
pathChan <- de.Name()
} else {
2020-11-02 20:48:56 +01:00
pathChan <- osPathname
}
}
return nil
},
})
if err != nil {
logrus.Errorf(errors.FullTrace(err))
}
}(item.Name())
}
2020-11-02 20:48:56 +01:00
walkerWG.Wait()
close(pathChan)
2020-11-02 20:48:56 +01:00
pathWG.Wait()
return paths, nil
}