storage/cmd/reindex: command-line tool to trigger reindexing
Change-Id: Ica64b354cbf8f9bd43344459fac860a2c816d209
Reviewed-on: https://go-review.googlesource.com/35263
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/cmd/benchsave/benchsave.go b/cmd/benchsave/benchsave.go
index 05cfa69..3649c53 100644
--- a/cmd/benchsave/benchsave.go
+++ b/cmd/benchsave/benchsave.go
@@ -67,9 +67,9 @@
}
func usage() {
- fmt.Fprintf(os.Stderr, `Usage of %s:
-%s [flags] file...
-`, os.Args[0], os.Args[0])
+ fmt.Fprintf(os.Stderr, `Usage of benchsave:
+ benchsave [flags] file...
+`)
flag.PrintDefaults()
os.Exit(2)
}
diff --git a/storage/cmd/reindex/reindex.go b/storage/cmd/reindex/reindex.go
new file mode 100644
index 0000000..25d5037
--- /dev/null
+++ b/storage/cmd/reindex/reindex.go
@@ -0,0 +1,147 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Reindex repopulates the perfdata SQL database from the original data files in Google Cloud Storage.
+//
+// Usage:
+//
+// reindex [-v] [-db foo.bar/baz] [-bucket name] prefix...
+//
+// Reindex reindexes all the uploads with IDs starting with the given prefixes.
+
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "strings"
+
+ "cloud.google.com/go/storage"
+ _ "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/mysql"
+ "golang.org/x/perf/storage/benchfmt"
+ "golang.org/x/perf/storage/db"
+ "google.golang.org/api/iterator"
+)
+
+var (
+ dbName = flag.String("db", "root:@cloudsql(golang-org:us-central1:golang-org)/perfdata", "connect to MySQL `database`")
+ bucket = flag.String("bucket", "golang-perfdata", "read from Google Cloud Storage `bucket`")
+ verbose = flag.Bool("v", false, "verbose")
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, `Usage of reindex:
+ reindex [flags] prefix...
+`)
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+func main() {
+ log.SetPrefix("reindex: ")
+ log.SetFlags(0)
+ flag.Usage = usage
+ flag.Parse()
+ if *verbose {
+ log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
+ }
+
+ ctx := context.Background()
+
+ prefixes := flag.Args()
+ if len(prefixes) == 0 {
+ log.Fatal("no prefixes to reindex")
+ }
+
+ d, err := db.OpenSQL("mysql", *dbName)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer d.Close()
+
+ client, err := storage.NewClient(ctx)
+ if err != nil {
+ log.Fatal(err)
+ }
+ bucket := client.Bucket(*bucket)
+
+ for _, prefix := range prefixes {
+ if strings.Index(prefix, "/") >= 0 {
+ log.Fatalf("prefix %q cannot contain /", prefix)
+ }
+ it := bucket.Objects(ctx, &storage.Query{Prefix: "uploads/" + prefix})
+ var lastUploadId string
+ var files []string
+ for {
+ objAttrs, err := it.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+ name := strings.TrimPrefix(objAttrs.Name, "uploads/")
+ slash := strings.Index(name, "/")
+ if slash < 0 {
+ log.Printf("ignoring file %q", objAttrs.Name)
+ }
+ uploadID := name[:slash]
+ if lastUploadId != "" && uploadID != lastUploadId {
+ if err := reindex(ctx, d, bucket, lastUploadId, files); err != nil {
+ log.Fatal(err)
+ }
+ files = nil
+ }
+ files = append(files, objAttrs.Name)
+ lastUploadId = uploadID
+ }
+ if len(files) > 0 {
+ if err := reindex(ctx, d, bucket, lastUploadId, files); err != nil {
+ log.Fatal(err)
+ }
+ }
+ }
+}
+
+func reindex(ctx context.Context, db *db.DB, bucket *storage.BucketHandle, uploadID string, files []string) error {
+ if *verbose {
+ log.Printf("reindexing %q", uploadID)
+ }
+ u, err := db.ReplaceUpload(uploadID)
+ if err != nil {
+ return err
+ }
+ for _, name := range files {
+ if err := reindexOne(ctx, u, bucket, name); err != nil {
+ return err
+ }
+ }
+ return u.Commit()
+}
+
+func reindexOne(ctx context.Context, u *db.Upload, bucket *storage.BucketHandle, name string) error {
+ r, err := bucket.Object(name).NewReader(ctx)
+ if err != nil {
+ return err
+ }
+ defer r.Close()
+ br := benchfmt.NewReader(r)
+ for {
+ res, err := br.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return err
+ }
+ if err := u.InsertRecord(res); err != nil {
+ return err
+ }
+ }
+ return nil
+}