blob: 1d1851eb7abfc3a060e1f7a9069d78a2ce927db8 [file] [log] [blame]
package gcsloader
import (
"fmt"
"sort"
"cloud.google.com/go/storage"
"go.skia.org/infra/fuzzer/go/common"
"go.skia.org/infra/fuzzer/go/config"
"go.skia.org/infra/fuzzer/go/frontend/fuzzcache"
"go.skia.org/infra/fuzzer/go/frontend/fuzzpool"
fstorage "go.skia.org/infra/fuzzer/go/storage"
"go.skia.org/infra/go/sklog"
)
// LoadFromBoltDB fills the given *fuzzpool.FuzzPool from FuzzReportCache associated with the given
// hash. The data.FuzzReports will all be in the current part of the pool.
// If a cache for the commit does not exist, or there are other problems with the retrieval,
// an error is returned. We do not need to deduplicate on extraction because
// the fuzzes were deduplicated on storage.
func LoadFromBoltDB(pool *fuzzpool.FuzzPool, cache *fuzzcache.FuzzReportCache) error {
sklog.Infof("Looking into cache for revision %s", config.Common.SkiaVersion.Hash)
if err := cache.LoadPool(pool, config.Common.SkiaVersion.Hash); err != nil {
return fmt.Errorf("Could not load from cache: %s", err)
}
sklog.Infof("Loaded a fuzz pool of size %d", len(pool.Reports()))
return nil
}
// GCSLoader is a struct that handles downloading fuzzes from Google Storage.
type GCSLoader struct {
storageClient *storage.Client
Cache *fuzzcache.FuzzReportCache
Pool *fuzzpool.FuzzPool
}
// New creates a GCSLoader and returns it.
func New(s *storage.Client, c *fuzzcache.FuzzReportCache, p *fuzzpool.FuzzPool) *GCSLoader {
return &GCSLoader{
storageClient: s,
Cache: c,
Pool: p,
}
}
// LoadFreshFromGoogleStorage pulls all bad and grey fuzzes out of GCS and loads them into memory.
// The "fresh" in the name refers to the fact that all other loaded fuzzes (if any)
// are written over, including in the cache.
// Upon completion, the full results are cached to a boltDB instance and moved from staging
// to the current copy.
func (g *GCSLoader) LoadFreshFromGoogleStorage() error {
revision := config.Common.SkiaVersion.Hash
g.Pool.ClearStaging()
fuzzNames := make([]string, 0, 100)
for _, arch := range common.ARCHITECTURES {
for _, cat := range common.FUZZ_CATEGORIES {
badPath := fmt.Sprintf("%s/%s/%s/bad", cat, revision, arch)
reports, err := fstorage.GetReportsFromGCS(g.storageClient, badPath, cat, arch, nil, config.FrontEnd.NumDownloadProcesses)
if err != nil {
return err
}
b := 0
for report := range reports {
report.IsGrey = false
fuzzNames = append(fuzzNames, report.FuzzName)
g.Pool.AddFuzzReport(report)
b++
}
sklog.Infof("%d bad fuzzes freshly loaded from gs://%s/%s", b, config.GCS.Bucket, badPath)
greyPath := fmt.Sprintf("%s/%s/%s/grey", cat, revision, arch)
reports, err = fstorage.GetReportsFromGCS(g.storageClient, greyPath, cat, arch, nil, config.FrontEnd.NumDownloadProcesses)
if err != nil {
return err
}
b = 0
for report := range reports {
report.IsGrey = true
fuzzNames = append(fuzzNames, report.FuzzName)
g.Pool.AddFuzzReport(report)
b++
}
sklog.Infof("%d grey fuzzes freshly loaded from gs://%s/%s", b, config.GCS.Bucket, greyPath)
}
}
g.Pool.CurrentFromStaging()
g.Pool.ClearStaging()
if err := g.Cache.StorePool(g.Pool, revision); err != nil {
return fmt.Errorf("Problem storing fuzz pool to boltDB: %s", err)
}
return g.Cache.StoreFuzzNames(fuzzNames, revision)
}
// LoadFuzzesFromGoogleStorage pulls all fuzzes out of GCS that are on the given whitelist
// and loads them into memory (as staging). These fuzzes represent the newly found bad fuzzes
// that have been uploaded by the various generators/aggregators. After loading them, it
// updates the cache and moves them from staging to the current copy.
func (g *GCSLoader) LoadFuzzesFromGoogleStorage(whitelist []string) error {
revision := config.Common.SkiaVersion.Hash
g.Pool.StagingFromCurrent()
sort.Strings(whitelist)
fuzzNames := make([]string, 0, 100)
for _, arch := range common.ARCHITECTURES {
for _, cat := range common.FUZZ_CATEGORIES {
badPath := fmt.Sprintf("%s/%s/%s/bad", cat, revision, arch)
reports, err := fstorage.GetReportsFromGCS(g.storageClient, badPath, cat, arch, whitelist, config.FrontEnd.NumDownloadProcesses)
if err != nil {
return err
}
b := 0
for report := range reports {
report.IsGrey = false
fuzzNames = append(fuzzNames, report.FuzzName)
g.Pool.AddFuzzReport(report)
b++
}
sklog.Infof("%d bad fuzzes incrementally loaded from gs://%s/%s", b, config.GCS.Bucket, badPath)
}
}
// We must wait until after all the fuzzes are in staging, otherwise, we'll only have a partial update
g.Pool.CurrentFromStaging()
g.Pool.ClearStaging()
oldBinaryFuzzNames, err := g.Cache.LoadFuzzNames(revision)
if err != nil {
sklog.Warningf("Could not read old binary fuzz names from cache: %s\n Continuing...", err)
oldBinaryFuzzNames = []string{}
}
if err := g.Cache.StorePool(g.Pool, revision); err != nil {
return fmt.Errorf("Problem storing fuzz pool to boltDB: %s", err)
}
return g.Cache.StoreFuzzNames(append(oldBinaryFuzzNames, whitelist...), revision)
}