From 40817d5f2c4fb4dcb4b50e1aa5dd3acdb98b56d1 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Mon, 15 Dec 2014 12:16:31 +1100 Subject: [PATCH] dashboard/app: add handler to wipe a builder's results column Change-Id: Idc3284ff8564a8863d8352890e285babded362cf Reviewed-on: https://go-review.googlesource.com/1539 Reviewed-by: Brad Fitzpatrick --- dashboard/app/app.yaml | 2 +- dashboard/app/build/build.go | 25 +++++++++++++---- dashboard/app/build/handler.go | 50 +++++++++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/dashboard/app/app.yaml b/dashboard/app/app.yaml index fa03da86..a26a1c73 100644 --- a/dashboard/app/app.yaml +++ b/dashboard/app/app.yaml @@ -13,7 +13,7 @@ handlers: static_dir: static - url: /(|gccgo/|hg/)log/.+ script: _go_app -- url: /(|gccgo/|hg/)(|commit|packages|result|perf-result|tag|todo|perf|perfdetail|perfgraph|updatebenchmark) +- url: /(|gccgo/|hg/)(|clear-results|commit|packages|result|perf-result|tag|todo|perf|perfdetail|perfgraph|updatebenchmark) script: _go_app - url: /(|gccgo/|hg/)(init|buildtest|key|perflearn|_ah/queue/go/delay) script: _go_app diff --git a/dashboard/app/build/build.go b/dashboard/app/build/build.go index 9e965edb..11c3262f 100644 --- a/dashboard/app/build/build.go +++ b/dashboard/app/build/build.go @@ -145,7 +145,7 @@ func putCommit(c appengine.Context, com *Commit) error { // build history and the AppEngine datastore limit of 1mb. const maxResults = 1000 -// AddResult adds the denormalized Result data to the Commit's Result field. +// AddResult adds the denormalized Result data to the Commit's ResultData field. // It must be called from inside a datastore transaction. func (com *Commit) AddResult(c appengine.Context, r *Result) error { if err := datastore.Get(c, com.Key(c), com); err != nil { @@ -167,6 +167,21 @@ func (com *Commit) AddResult(c appengine.Context, r *Result) error { return putCommit(c, com) } +// removeResult removes the denormalized Result data from the ResultData field +// for the given builder and go hash. +// It must be called from within the datastore transaction that gets and puts +// the Commit. Note this is slightly different to AddResult, above. +func (com *Commit) RemoveResult(r *Result) { + var rd []string + for _, s := range com.ResultData { + if strings.HasPrefix(s, r.Builder+"|") && strings.HasSuffix(s, "|"+r.GoHash) { + continue + } + rd = append(rd, s) + } + com.ResultData = rd +} + // AddPerfResult remembers that the builder has run the benchmark on the commit. // It must be called from inside a datastore transaction. func (com *Commit) AddPerfResult(c appengine.Context, builder, benchmark string) error { @@ -205,7 +220,7 @@ func (c *Commit) Result(builder, goHash string) *Result { if len(p) != 4 || p[0] != builder || p[3] != goHash { continue } - return partsToHash(c, p) + return partsToResult(c, p) } return nil } @@ -217,7 +232,7 @@ func (c *Commit) Results() (results []*Result) { if len(p) != 4 { continue } - results = append(results, partsToHash(c, p)) + results = append(results, partsToResult(c, p)) } return } @@ -371,8 +386,8 @@ func GetCommits(c appengine.Context, startCommitNum, n int) ([]*Commit, error) { return res, nil } -// partsToHash converts a Commit and ResultData substrings to a Result. -func partsToHash(c *Commit, p []string) *Result { +// partsToResult converts a Commit and ResultData substrings to a Result. +func partsToResult(c *Commit, p []string) *Result { return &Result{ Builder: p[0], Hash: c.Hash, diff --git a/dashboard/app/build/handler.go b/dashboard/app/build/handler.go index 258d5c12..e58b33c9 100644 --- a/dashboard/app/build/handler.go +++ b/dashboard/app/build/handler.go @@ -793,6 +793,53 @@ func logHandler(w http.ResponseWriter, r *http.Request) { w.Write(b) } +// clearResultsHandler purges the last commitsPerPage results for the given builder. +// It optionally takes a comma-separated list of specific hashes to clear. +func clearResultsHandler(r *http.Request) (interface{}, error) { + if r.Method != "POST" { + return nil, errBadMethod(r.Method) + } + builder := r.FormValue("builder") + if builder == "" { + return nil, errors.New("must specify a builder") + } + clearAll := r.FormValue("hash") == "" + hash := strings.Split(r.FormValue("hash"), ",") + + c := contextForRequest(r) + defer cache.Tick(c) + pkg := (&Package{}).Key(c) // TODO(adg): support clearing sub-repos + err := datastore.RunInTransaction(c, func(c appengine.Context) error { + var coms []*Commit + keys, err := datastore.NewQuery("Commit"). + Ancestor(pkg). + Order("-Num"). + Limit(commitsPerPage). + GetAll(c, &coms) + if err != nil { + return err + } + var rKeys []*datastore.Key + for _, com := range coms { + if !(clearAll || contains(hash, com.Hash)) { + continue + } + r := com.Result(builder, "") + if r == nil { + continue + } + com.RemoveResult(r) + rKeys = append(rKeys, r.Key(c)) + } + _, err = datastore.PutMulti(c, keys, coms) + if err != nil { + return err + } + return datastore.DeleteMulti(c, rKeys) + }, nil) + return nil, err +} + type dashHandler func(*http.Request) (interface{}, error) type dashResponse struct { @@ -862,10 +909,11 @@ func init() { handleFunc("/key", keyHandler) // authenticated handlers + handleFunc("/clear-results", AuthHandler(clearResultsHandler)) handleFunc("/commit", AuthHandler(commitHandler)) handleFunc("/packages", AuthHandler(packagesHandler)) - handleFunc("/result", AuthHandler(resultHandler)) handleFunc("/perf-result", AuthHandler(perfResultHandler)) + handleFunc("/result", AuthHandler(resultHandler)) handleFunc("/tag", AuthHandler(tagHandler)) handleFunc("/todo", AuthHandler(todoHandler))