[gold] Remove DiffStore dependency from web handlers.
Bug: skia:10582
Change-Id: Ic0eb9c5d6f2d119d103eb4d991bee276796127c6
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/373743
Reviewed-by: Leandro Lovisolo <lovisolo@google.com>
diff --git a/golden/cmd/gold_frontend/gold_frontend.go b/golden/cmd/gold_frontend/gold_frontend.go
index 95d33a3..68e988b 100644
--- a/golden/cmd/gold_frontend/gold_frontend.go
+++ b/golden/cmd/gold_frontend/gold_frontend.go
@@ -253,7 +253,7 @@
mustStartExpectationsCleanupProcess(ctx, fsc, expStore, ixr)
- handlers := mustMakeWebHandlers(diffStore, expStore, gsClient, ignoreStore, ixr, reviewSystems, searchAPI, statusWatcher, tileSource, tjs, vcs)
+ handlers := mustMakeWebHandlers(sqlDB, expStore, gsClient, ignoreStore, ixr, reviewSystems, searchAPI, statusWatcher, tileSource, tjs, vcs)
rootRouter := mustMakeRootRouter(fsc, handlers)
@@ -700,10 +700,10 @@
}
// mustMakeWebHandlers returns a new web.Handlers.
-func mustMakeWebHandlers(diffStore diff.DiffStore, expStore expectations.Store, gsClient storage.GCSClient, ignoreStore ignore.Store, ixr *indexer.Indexer, reviewSystems []clstore.ReviewSystem, searchAPI search.SearchAPI, statusWatcher *status.StatusWatcher, tileSource tilesource.TileSource, tjs tjstore.Store, vcs vcsinfo.VCS) *web.Handlers {
+func mustMakeWebHandlers(db *pgxpool.Pool, expStore expectations.Store, gsClient storage.GCSClient, ignoreStore ignore.Store, ixr *indexer.Indexer, reviewSystems []clstore.ReviewSystem, searchAPI search.SearchAPI, statusWatcher *status.StatusWatcher, tileSource tilesource.TileSource, tjs tjstore.Store, vcs vcsinfo.VCS) *web.Handlers {
handlers, err := web.NewHandlers(web.HandlersConfig{
Baseliner: simple_baseliner.New(expStore),
- DiffStore: diffStore,
+ DB: db,
ExpectationsStore: expStore,
GCSClient: gsClient,
IgnoreStore: ignoreStore,
diff --git a/golden/go/web/web.go b/golden/go/web/web.go
index 84acb92..45793cd 100644
--- a/golden/go/web/web.go
+++ b/golden/go/web/web.go
@@ -18,6 +18,7 @@
"time"
"github.com/gorilla/mux"
+ "github.com/jackc/pgx/v4/pgxpool"
"go.opencensus.io/trace"
"go.skia.org/infra/golden/go/diffstore/common"
search_fe "go.skia.org/infra/golden/go/search/frontend"
@@ -42,6 +43,7 @@
"go.skia.org/infra/golden/go/search"
"go.skia.org/infra/golden/go/search/export"
"go.skia.org/infra/golden/go/search/query"
+ "go.skia.org/infra/golden/go/sql"
"go.skia.org/infra/golden/go/status"
"go.skia.org/infra/golden/go/storage"
"go.skia.org/infra/golden/go/tilesource"
@@ -88,7 +90,7 @@
// HandlersConfig holds the environment needed by the various http handler functions.
type HandlersConfig struct {
Baseliner baseline.BaselineFetcher
- DiffStore diff.DiffStore
+ DB *pgxpool.Pool
ExpectationsStore expectations.Store
GCSClient storage.GCSClient
IgnoreStore ignore.Store
@@ -129,8 +131,8 @@
}
if val == FullFrontEnd {
- if conf.DiffStore == nil {
- return nil, skerr.Fmt("DiffStore cannot be nil")
+ if conf.DB == nil {
+ return nil, skerr.Fmt("DB cannot be nil")
}
if conf.ExpectationsStore == nil {
return nil, skerr.Fmt("ExpectationsStore cannot be nil")
@@ -1113,16 +1115,16 @@
Status: d.Status,
})
remaining := digests[i:]
- diffs, err := wh.DiffStore.Get(r.Context(), d.Digest, remaining)
+ links, err := wh.getLinksBetween(r.Context(), d.Digest, remaining)
if err != nil {
- sklog.Errorf("Failed to calculate differences: %s", err)
- continue
+ httputils.ReportError(w, err, "could not compute diff metrics", http.StatusInternalServerError)
+ return
}
- for otherDigest, dm := range diffs {
+ for otherDigest, distance := range links {
d3.Links = append(d3.Links, Link{
Source: digestIndex[d.Digest],
Target: digestIndex[otherDigest],
- Value: dm.PixelDiffPercent,
+ Value: distance,
})
}
d3.ParamsetByDigest[d.Digest] = idx.GetParamsetSummary(d.Test, d.Digest, types.ExcludeIgnoredTraces)
@@ -1139,6 +1141,47 @@
sendJSONResponse(w, d3)
}
+// getLinksBetween queries the SQL DB for the PercentPixelsDiff between the left digest and
+// the right digests. It returns them in a map.
+func (wh *Handlers) getLinksBetween(ctx context.Context, left types.Digest, right types.DigestSlice) (map[types.Digest]float32, error) {
+ ctx, span := trace.StartSpan(ctx, "getLinksBetween")
+ span.AddAttributes(trace.Int64Attribute("num_right", int64(len(right))))
+ defer span.End()
+ const statement = `
+SELECT encode(right_digest, 'hex'), percent_pixels_diff FROM DiffMetrics
+AS OF SYSTEM TIME '-0.1s'
+WHERE left_digest = $1 AND right_digest IN `
+ arguments := make([]interface{}, 0, len(right)+1)
+ lb, err := sql.DigestToBytes(left)
+ if err != nil {
+ return nil, skerr.Wrap(err)
+ }
+ arguments = append(arguments, lb)
+ for _, r := range right {
+ rb, err := sql.DigestToBytes(r)
+ if err != nil {
+ return nil, skerr.Wrap(err)
+ }
+ arguments = append(arguments, rb)
+ }
+ vp := sql.ValuesPlaceholders(len(arguments), 1)
+ rows, err := wh.DB.Query(ctx, statement+vp, arguments...)
+ if err != nil {
+ return nil, skerr.Wrap(err)
+ }
+ defer rows.Close()
+ rv := map[types.Digest]float32{}
+ for rows.Next() {
+ var rightD types.Digest
+ var linkDistance float32
+ if err := rows.Scan(&rightD, &linkDistance); err != nil {
+ return nil, skerr.Wrap(err)
+ }
+ rv[rightD] = linkDistance
+ }
+ return rv, nil
+}
+
// Node represents a single node in a d3 diagram. Used in ClusterDiffResult.
type Node struct {
Name types.Digest `json:"name"`
diff --git a/golden/go/web/web_test.go b/golden/go/web/web_test.go
index 14149fa..55aaf51 100644
--- a/golden/go/web/web_test.go
+++ b/golden/go/web/web_test.go
@@ -45,6 +45,8 @@
"go.skia.org/infra/golden/go/search"
search_fe "go.skia.org/infra/golden/go/search/frontend"
mock_search "go.skia.org/infra/golden/go/search/mocks"
+ "go.skia.org/infra/golden/go/sql/datakitchensink"
+ "go.skia.org/infra/golden/go/sql/sqltest"
bug_revert "go.skia.org/infra/golden/go/testutils/data_bug_revert"
one_by_five "go.skia.org/infra/golden/go/testutils/data_one_by_five"
data "go.skia.org/infra/golden/go/testutils/data_three_devices"
@@ -2899,6 +2901,51 @@
return buf.Bytes()
}
+func TestGetLinksBetween_SomeDiffMetricsExist_Success(t *testing.T) {
+ unittest.LargeTest(t)
+
+ ctx := context.Background()
+ db := sqltest.NewCockroachDBForTestsWithProductionSchema(ctx, t)
+ require.NoError(t, sqltest.BulkInsertDataTables(ctx, db, datakitchensink.Build()))
+ waitForSystemTime()
+ wh := Handlers{
+ HandlersConfig: HandlersConfig{
+ DB: db,
+ },
+ }
+
+ links, err := wh.getLinksBetween(ctx, datakitchensink.DigestA01Pos, []types.Digest{
+ datakitchensink.DigestA02Pos, datakitchensink.DigestA03Pos, datakitchensink.DigestA05Unt,
+ "0123456789abcdef0123456789abcdef", // not a real digest
+ })
+ require.NoError(t, err)
+ assert.Equal(t, map[types.Digest]float32{
+ datakitchensink.DigestA02Pos: 56.25,
+ datakitchensink.DigestA03Pos: 56.25,
+ datakitchensink.DigestA05Unt: 3.125,
+ }, links)
+}
+
+func TestGetLinksBetween_NoDiffMetricsExist_EmptyMapReturned(t *testing.T) {
+ unittest.LargeTest(t)
+
+ ctx := context.Background()
+ db := sqltest.NewCockroachDBForTestsWithProductionSchema(ctx, t)
+ require.NoError(t, sqltest.BulkInsertDataTables(ctx, db, datakitchensink.Build()))
+ waitForSystemTime()
+ wh := Handlers{
+ HandlersConfig: HandlersConfig{
+ DB: db,
+ },
+ }
+
+ links, err := wh.getLinksBetween(ctx, datakitchensink.DigestA01Pos, []types.Digest{
+ "0123456789abcdef0123456789abcdef", // not a real digest
+ })
+ require.NoError(t, err)
+ assert.Empty(t, links)
+}
+
// Because we are calling our handlers directly, the target URL doesn't matter. The target URL
// would only matter if we were calling into the router, so it knew which handler to call.
const requestURL = "/does/not/matter"
@@ -2988,3 +3035,9 @@
func setID(r *http.Request, id string) *http.Request {
return mux.SetURLVars(r, map[string]string{"id": id})
}
+
+// waitForSystemTime waits for a time greater than the duration mentioned in "AS OF SYSTEM TIME"
+// clauses in queries. This way, the queries will be accurate.
+func waitForSystemTime() {
+ time.Sleep(150 * time.Millisecond)
+}