vendor: Update vendoring for the exec client and server implementations
Signed-off-by: Jacek J. Łakis <jacek.lakis@intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
d25b88583f
commit
bf51655a7b
2124 changed files with 809703 additions and 5 deletions
789
vendor/cloud.google.com/go/bigtable/cmd/cbt/cbt.go
generated
vendored
Normal file
789
vendor/cloud.google.com/go/bigtable/cmd/cbt/cbt.go
generated
vendored
Normal file
|
@ -0,0 +1,789 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
// Command docs are in cbtdoc.go.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/bigtable"
|
||||
"cloud.google.com/go/bigtable/internal/cbtconfig"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var (
|
||||
oFlag = flag.String("o", "", "if set, redirect stdout to this file")
|
||||
|
||||
config *cbtconfig.Config
|
||||
client *bigtable.Client
|
||||
adminClient *bigtable.AdminClient
|
||||
instanceAdminClient *bigtable.InstanceAdminClient
|
||||
)
|
||||
|
||||
func getCredentialOpts(opts []option.ClientOption) []option.ClientOption {
|
||||
if ts := config.TokenSource; ts != nil {
|
||||
opts = append(opts, option.WithTokenSource(ts))
|
||||
}
|
||||
if tlsCreds := config.TLSCreds; tlsCreds != nil {
|
||||
opts = append(opts, option.WithGRPCDialOption(grpc.WithTransportCredentials(tlsCreds)))
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
func getClient() *bigtable.Client {
|
||||
if client == nil {
|
||||
var opts []option.ClientOption
|
||||
if ep := config.DataEndpoint; ep != "" {
|
||||
opts = append(opts, option.WithEndpoint(ep))
|
||||
}
|
||||
opts = getCredentialOpts(opts)
|
||||
var err error
|
||||
client, err = bigtable.NewClient(context.Background(), config.Project, config.Instance, opts...)
|
||||
if err != nil {
|
||||
log.Fatalf("Making bigtable.Client: %v", err)
|
||||
}
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func getAdminClient() *bigtable.AdminClient {
|
||||
if adminClient == nil {
|
||||
var opts []option.ClientOption
|
||||
if ep := config.AdminEndpoint; ep != "" {
|
||||
opts = append(opts, option.WithEndpoint(ep))
|
||||
}
|
||||
opts = getCredentialOpts(opts)
|
||||
var err error
|
||||
adminClient, err = bigtable.NewAdminClient(context.Background(), config.Project, config.Instance, opts...)
|
||||
if err != nil {
|
||||
log.Fatalf("Making bigtable.AdminClient: %v", err)
|
||||
}
|
||||
}
|
||||
return adminClient
|
||||
}
|
||||
|
||||
func getInstanceAdminClient() *bigtable.InstanceAdminClient {
|
||||
if instanceAdminClient == nil {
|
||||
var opts []option.ClientOption
|
||||
if ep := config.AdminEndpoint; ep != "" {
|
||||
opts = append(opts, option.WithEndpoint(ep))
|
||||
}
|
||||
opts = getCredentialOpts(opts)
|
||||
var err error
|
||||
instanceAdminClient, err = bigtable.NewInstanceAdminClient(context.Background(), config.Project, opts...)
|
||||
if err != nil {
|
||||
log.Fatalf("Making bigtable.InstanceAdminClient: %v", err)
|
||||
}
|
||||
}
|
||||
return instanceAdminClient
|
||||
}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
config, err = cbtconfig.Load()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
config.RegisterFlags()
|
||||
|
||||
flag.Usage = func() { usage(os.Stderr) }
|
||||
flag.Parse()
|
||||
if flag.NArg() == 0 {
|
||||
usage(os.Stderr)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *oFlag != "" {
|
||||
f, err := os.Create(*oFlag)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
os.Stdout = f
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
for _, cmd := range commands {
|
||||
if cmd.Name == flag.Arg(0) {
|
||||
if err := config.CheckFlags(cmd.Required); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cmd.do(ctx, flag.Args()[1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Fatalf("Unknown command %q", flag.Arg(0))
|
||||
}
|
||||
|
||||
func usage(w io.Writer) {
|
||||
fmt.Fprintf(w, "Usage: %s [flags] <command> ...\n", os.Args[0])
|
||||
flag.CommandLine.SetOutput(w)
|
||||
flag.CommandLine.PrintDefaults()
|
||||
fmt.Fprintf(w, "\n%s", cmdSummary)
|
||||
}
|
||||
|
||||
var cmdSummary string // generated in init, below
|
||||
|
||||
func init() {
|
||||
var buf bytes.Buffer
|
||||
tw := tabwriter.NewWriter(&buf, 10, 8, 4, '\t', 0)
|
||||
for _, cmd := range commands {
|
||||
fmt.Fprintf(tw, "cbt %s\t%s\n", cmd.Name, cmd.Desc)
|
||||
}
|
||||
tw.Flush()
|
||||
buf.WriteString(configHelp)
|
||||
cmdSummary = buf.String()
|
||||
}
|
||||
|
||||
var configHelp = `
|
||||
For convenience, values of the -project, -instance, -creds,
|
||||
-admin-endpoint and -data-endpoint flags may be specified in
|
||||
` + cbtconfig.Filename() + ` in this format:
|
||||
project = my-project-123
|
||||
instance = my-instance
|
||||
creds = path-to-account-key.json
|
||||
admin-endpoint = hostname:port
|
||||
data-endpoint = hostname:port
|
||||
All values are optional, and all will be overridden by flags.
|
||||
`
|
||||
|
||||
var commands = []struct {
|
||||
Name, Desc string
|
||||
do func(context.Context, ...string)
|
||||
Usage string
|
||||
Required cbtconfig.RequiredFlags
|
||||
}{
|
||||
{
|
||||
Name: "count",
|
||||
Desc: "Count rows in a table",
|
||||
do: doCount,
|
||||
Usage: "cbt count <table>",
|
||||
Required: cbtconfig.ProjectAndInstanceRequired,
|
||||
},
|
||||
{
|
||||
Name: "createfamily",
|
||||
Desc: "Create a column family",
|
||||
do: doCreateFamily,
|
||||
Usage: "cbt createfamily <table> <family>",
|
||||
Required: cbtconfig.ProjectAndInstanceRequired,
|
||||
},
|
||||
{
|
||||
Name: "createtable",
|
||||
Desc: "Create a table",
|
||||
do: doCreateTable,
|
||||
Usage: "cbt createtable <table> [initial_splits...]\n" +
|
||||
" initial_splits=row A row key to be used to initially split the table " +
|
||||
"into multiple tablets. Can be repeated to create multiple splits.",
|
||||
Required: cbtconfig.ProjectAndInstanceRequired,
|
||||
},
|
||||
{
|
||||
Name: "deletefamily",
|
||||
Desc: "Delete a column family",
|
||||
do: doDeleteFamily,
|
||||
Usage: "cbt deletefamily <table> <family>",
|
||||
Required: cbtconfig.ProjectAndInstanceRequired,
|
||||
},
|
||||
{
|
||||
Name: "deleterow",
|
||||
Desc: "Delete a row",
|
||||
do: doDeleteRow,
|
||||
Usage: "cbt deleterow <table> <row>",
|
||||
Required: cbtconfig.ProjectAndInstanceRequired,
|
||||
},
|
||||
{
|
||||
Name: "deletetable",
|
||||
Desc: "Delete a table",
|
||||
do: doDeleteTable,
|
||||
Usage: "cbt deletetable <table>",
|
||||
Required: cbtconfig.ProjectAndInstanceRequired,
|
||||
},
|
||||
{
|
||||
Name: "doc",
|
||||
Desc: "Print godoc-suitable documentation for cbt",
|
||||
do: doDoc,
|
||||
Usage: "cbt doc",
|
||||
Required: cbtconfig.NoneRequired,
|
||||
},
|
||||
{
|
||||
Name: "help",
|
||||
Desc: "Print help text",
|
||||
do: doHelp,
|
||||
Usage: "cbt help [command]",
|
||||
Required: cbtconfig.NoneRequired,
|
||||
},
|
||||
{
|
||||
Name: "listinstances",
|
||||
Desc: "List instances in a project",
|
||||
do: doListInstances,
|
||||
Usage: "cbt listinstances",
|
||||
Required: cbtconfig.ProjectRequired,
|
||||
},
|
||||
{
|
||||
Name: "lookup",
|
||||
Desc: "Read from a single row",
|
||||
do: doLookup,
|
||||
Usage: "cbt lookup <table> <row>",
|
||||
Required: cbtconfig.ProjectAndInstanceRequired,
|
||||
},
|
||||
{
|
||||
Name: "ls",
|
||||
Desc: "List tables and column families",
|
||||
do: doLS,
|
||||
Usage: "cbt ls List tables\n" +
|
||||
"cbt ls <table> List column families in <table>",
|
||||
Required: cbtconfig.ProjectAndInstanceRequired,
|
||||
},
|
||||
{
|
||||
Name: "mddoc",
|
||||
Desc: "Print documentation for cbt in Markdown format",
|
||||
do: doMDDoc,
|
||||
Usage: "cbt mddoc",
|
||||
Required: cbtconfig.NoneRequired,
|
||||
},
|
||||
{
|
||||
Name: "read",
|
||||
Desc: "Read rows",
|
||||
do: doRead,
|
||||
Usage: "cbt read <table> [start=<row>] [end=<row>] [prefix=<prefix>] [count=<n>]\n" +
|
||||
" start=<row> Start reading at this row\n" +
|
||||
" end=<row> Stop reading before this row\n" +
|
||||
" prefix=<prefix> Read rows with this prefix\n" +
|
||||
" count=<n> Read only this many rows\n",
|
||||
Required: cbtconfig.ProjectAndInstanceRequired,
|
||||
},
|
||||
{
|
||||
Name: "set",
|
||||
Desc: "Set value of a cell",
|
||||
do: doSet,
|
||||
Usage: "cbt set <table> <row> family:column=val[@ts] ...\n" +
|
||||
" family:column=val[@ts] may be repeated to set multiple cells.\n" +
|
||||
"\n" +
|
||||
" ts is an optional integer timestamp.\n" +
|
||||
" If it cannot be parsed, the `@ts` part will be\n" +
|
||||
" interpreted as part of the value.",
|
||||
Required: cbtconfig.ProjectAndInstanceRequired,
|
||||
},
|
||||
{
|
||||
Name: "setgcpolicy",
|
||||
Desc: "Set the GC policy for a column family",
|
||||
do: doSetGCPolicy,
|
||||
Usage: "cbt setgcpolicy <table> <family> ( maxage=<d> | maxversions=<n> )\n" +
|
||||
"\n" +
|
||||
` maxage=<d> Maximum timestamp age to preserve (e.g. "1h", "4d")` + "\n" +
|
||||
" maxversions=<n> Maximum number of versions to preserve",
|
||||
Required: cbtconfig.ProjectAndInstanceRequired,
|
||||
},
|
||||
}
|
||||
|
||||
func doCount(ctx context.Context, args ...string) {
|
||||
if len(args) != 1 {
|
||||
log.Fatal("usage: cbt count <table>")
|
||||
}
|
||||
tbl := getClient().Open(args[0])
|
||||
|
||||
n := 0
|
||||
err := tbl.ReadRows(ctx, bigtable.InfiniteRange(""), func(_ bigtable.Row) bool {
|
||||
n++
|
||||
return true
|
||||
}, bigtable.RowFilter(bigtable.StripValueFilter()))
|
||||
if err != nil {
|
||||
log.Fatalf("Reading rows: %v", err)
|
||||
}
|
||||
fmt.Println(n)
|
||||
}
|
||||
|
||||
func doCreateFamily(ctx context.Context, args ...string) {
|
||||
if len(args) != 2 {
|
||||
log.Fatal("usage: cbt createfamily <table> <family>")
|
||||
}
|
||||
err := getAdminClient().CreateColumnFamily(ctx, args[0], args[1])
|
||||
if err != nil {
|
||||
log.Fatalf("Creating column family: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func doCreateTable(ctx context.Context, args ...string) {
|
||||
if len(args) < 1 {
|
||||
log.Fatal("usage: cbt createtable <table> [initial_splits...]")
|
||||
}
|
||||
var err error
|
||||
if len(args) > 1 {
|
||||
splits := args[1:]
|
||||
err = getAdminClient().CreatePresplitTable(ctx, args[0], splits)
|
||||
} else {
|
||||
err = getAdminClient().CreateTable(ctx, args[0])
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("Creating table: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func doDeleteFamily(ctx context.Context, args ...string) {
|
||||
if len(args) != 2 {
|
||||
log.Fatal("usage: cbt deletefamily <table> <family>")
|
||||
}
|
||||
err := getAdminClient().DeleteColumnFamily(ctx, args[0], args[1])
|
||||
if err != nil {
|
||||
log.Fatalf("Deleting column family: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func doDeleteRow(ctx context.Context, args ...string) {
|
||||
if len(args) != 2 {
|
||||
log.Fatal("usage: cbt deleterow <table> <row>")
|
||||
}
|
||||
tbl := getClient().Open(args[0])
|
||||
mut := bigtable.NewMutation()
|
||||
mut.DeleteRow()
|
||||
if err := tbl.Apply(ctx, args[1], mut); err != nil {
|
||||
log.Fatalf("Deleting row: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func doDeleteTable(ctx context.Context, args ...string) {
|
||||
if len(args) != 1 {
|
||||
log.Fatalf("Can't do `cbt deletetable %s`", args)
|
||||
}
|
||||
err := getAdminClient().DeleteTable(ctx, args[0])
|
||||
if err != nil {
|
||||
log.Fatalf("Deleting table: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// to break circular dependencies
|
||||
var (
|
||||
doDocFn func(ctx context.Context, args ...string)
|
||||
doHelpFn func(ctx context.Context, args ...string)
|
||||
doMDDocFn func(ctx context.Context, args ...string)
|
||||
)
|
||||
|
||||
func init() {
|
||||
doDocFn = doDocReal
|
||||
doHelpFn = doHelpReal
|
||||
doMDDocFn = doMDDocReal
|
||||
}
|
||||
|
||||
func doDoc(ctx context.Context, args ...string) { doDocFn(ctx, args...) }
|
||||
func doHelp(ctx context.Context, args ...string) { doHelpFn(ctx, args...) }
|
||||
func doMDDoc(ctx context.Context, args ...string) { doMDDocFn(ctx, args...) }
|
||||
|
||||
func docFlags() []*flag.Flag {
|
||||
// Only include specific flags, in a specific order.
|
||||
var flags []*flag.Flag
|
||||
for _, name := range []string{"project", "instance", "creds"} {
|
||||
f := flag.Lookup(name)
|
||||
if f == nil {
|
||||
log.Fatalf("Flag not linked: -%s", name)
|
||||
}
|
||||
flags = append(flags, f)
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
func doDocReal(ctx context.Context, args ...string) {
|
||||
data := map[string]interface{}{
|
||||
"Commands": commands,
|
||||
"Flags": docFlags(),
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := docTemplate.Execute(&buf, data); err != nil {
|
||||
log.Fatalf("Bad doc template: %v", err)
|
||||
}
|
||||
out, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
log.Fatalf("Bad doc output: %v", err)
|
||||
}
|
||||
os.Stdout.Write(out)
|
||||
}
|
||||
|
||||
func indentLines(s, ind string) string {
|
||||
ss := strings.Split(s, "\n")
|
||||
for i, p := range ss {
|
||||
ss[i] = ind + p
|
||||
}
|
||||
return strings.Join(ss, "\n")
|
||||
}
|
||||
|
||||
var docTemplate = template.Must(template.New("doc").Funcs(template.FuncMap{
|
||||
"indent": indentLines,
|
||||
}).
|
||||
Parse(`
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// DO NOT EDIT. THIS IS AUTOMATICALLY GENERATED.
|
||||
// Run "go generate" to regenerate.
|
||||
//go:generate go run cbt.go -o cbtdoc.go doc
|
||||
|
||||
/*
|
||||
Cbt is a tool for doing basic interactions with Cloud Bigtable.
|
||||
|
||||
Usage:
|
||||
|
||||
cbt [options] command [arguments]
|
||||
|
||||
The commands are:
|
||||
{{range .Commands}}
|
||||
{{printf "%-25s %s" .Name .Desc}}{{end}}
|
||||
|
||||
Use "cbt help <command>" for more information about a command.
|
||||
|
||||
The options are:
|
||||
{{range .Flags}}
|
||||
-{{.Name}} string
|
||||
{{.Usage}}{{end}}
|
||||
|
||||
{{range .Commands}}
|
||||
{{.Desc}}
|
||||
|
||||
Usage:
|
||||
{{indent .Usage "\t"}}
|
||||
|
||||
|
||||
|
||||
{{end}}
|
||||
*/
|
||||
package main
|
||||
`))
|
||||
|
||||
func doHelpReal(ctx context.Context, args ...string) {
|
||||
if len(args) == 0 {
|
||||
usage(os.Stdout)
|
||||
return
|
||||
}
|
||||
for _, cmd := range commands {
|
||||
if cmd.Name == args[0] {
|
||||
fmt.Println(cmd.Usage)
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Fatalf("Don't know command %q", args[0])
|
||||
}
|
||||
|
||||
func doListInstances(ctx context.Context, args ...string) {
|
||||
if len(args) != 0 {
|
||||
log.Fatalf("usage: cbt listinstances")
|
||||
}
|
||||
is, err := getInstanceAdminClient().Instances(ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Getting list of instances: %v", err)
|
||||
}
|
||||
tw := tabwriter.NewWriter(os.Stdout, 10, 8, 4, '\t', 0)
|
||||
fmt.Fprintf(tw, "Instance Name\tInfo\n")
|
||||
fmt.Fprintf(tw, "-------------\t----\n")
|
||||
for _, i := range is {
|
||||
fmt.Fprintf(tw, "%s\t%s\n", i.Name, i.DisplayName)
|
||||
}
|
||||
tw.Flush()
|
||||
}
|
||||
|
||||
func doLookup(ctx context.Context, args ...string) {
|
||||
if len(args) != 2 {
|
||||
log.Fatalf("usage: cbt lookup <table> <row>")
|
||||
}
|
||||
table, row := args[0], args[1]
|
||||
tbl := getClient().Open(table)
|
||||
r, err := tbl.ReadRow(ctx, row)
|
||||
if err != nil {
|
||||
log.Fatalf("Reading row: %v", err)
|
||||
}
|
||||
printRow(r)
|
||||
}
|
||||
|
||||
func printRow(r bigtable.Row) {
|
||||
fmt.Println(strings.Repeat("-", 40))
|
||||
fmt.Println(r.Key())
|
||||
|
||||
var fams []string
|
||||
for fam := range r {
|
||||
fams = append(fams, fam)
|
||||
}
|
||||
sort.Strings(fams)
|
||||
for _, fam := range fams {
|
||||
ris := r[fam]
|
||||
sort.Sort(byColumn(ris))
|
||||
for _, ri := range ris {
|
||||
ts := time.Unix(0, int64(ri.Timestamp)*1e3)
|
||||
fmt.Printf(" %-40s @ %s\n", ri.Column, ts.Format("2006/01/02-15:04:05.000000"))
|
||||
fmt.Printf(" %q\n", ri.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type byColumn []bigtable.ReadItem
|
||||
|
||||
func (b byColumn) Len() int { return len(b) }
|
||||
func (b byColumn) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
||||
func (b byColumn) Less(i, j int) bool { return b[i].Column < b[j].Column }
|
||||
|
||||
func doLS(ctx context.Context, args ...string) {
|
||||
switch len(args) {
|
||||
default:
|
||||
log.Fatalf("Can't do `cbt ls %s`", args)
|
||||
case 0:
|
||||
tables, err := getAdminClient().Tables(ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Getting list of tables: %v", err)
|
||||
}
|
||||
sort.Strings(tables)
|
||||
for _, table := range tables {
|
||||
fmt.Println(table)
|
||||
}
|
||||
case 1:
|
||||
table := args[0]
|
||||
ti, err := getAdminClient().TableInfo(ctx, table)
|
||||
if err != nil {
|
||||
log.Fatalf("Getting table info: %v", err)
|
||||
}
|
||||
sort.Strings(ti.Families)
|
||||
for _, fam := range ti.Families {
|
||||
fmt.Println(fam)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doMDDocReal(ctx context.Context, args ...string) {
|
||||
data := map[string]interface{}{
|
||||
"Commands": commands,
|
||||
"Flags": docFlags(),
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := mddocTemplate.Execute(&buf, data); err != nil {
|
||||
log.Fatalf("Bad mddoc template: %v", err)
|
||||
}
|
||||
io.Copy(os.Stdout, &buf)
|
||||
}
|
||||
|
||||
var mddocTemplate = template.Must(template.New("mddoc").Funcs(template.FuncMap{
|
||||
"indent": indentLines,
|
||||
}).
|
||||
Parse(`
|
||||
Cbt is a tool for doing basic interactions with Cloud Bigtable.
|
||||
|
||||
Usage:
|
||||
|
||||
cbt [options] command [arguments]
|
||||
|
||||
The commands are:
|
||||
{{range .Commands}}
|
||||
{{printf "%-25s %s" .Name .Desc}}{{end}}
|
||||
|
||||
Use "cbt help <command>" for more information about a command.
|
||||
|
||||
The options are:
|
||||
{{range .Flags}}
|
||||
-{{.Name}} string
|
||||
{{.Usage}}{{end}}
|
||||
|
||||
{{range .Commands}}
|
||||
## {{.Desc}}
|
||||
|
||||
{{indent .Usage "\t"}}
|
||||
|
||||
|
||||
|
||||
{{end}}
|
||||
`))
|
||||
|
||||
func doRead(ctx context.Context, args ...string) {
|
||||
if len(args) < 1 {
|
||||
log.Fatalf("usage: cbt read <table> [args ...]")
|
||||
}
|
||||
tbl := getClient().Open(args[0])
|
||||
|
||||
parsed := make(map[string]string)
|
||||
for _, arg := range args[1:] {
|
||||
i := strings.Index(arg, "=")
|
||||
if i < 0 {
|
||||
log.Fatalf("Bad arg %q", arg)
|
||||
}
|
||||
key, val := arg[:i], arg[i+1:]
|
||||
switch key {
|
||||
default:
|
||||
log.Fatalf("Unknown arg key %q", key)
|
||||
case "limit":
|
||||
// Be nicer; we used to support this, but renamed it to "end".
|
||||
log.Fatalf("Unknown arg key %q; did you mean %q?", key, "end")
|
||||
case "start", "end", "prefix", "count":
|
||||
parsed[key] = val
|
||||
}
|
||||
}
|
||||
if (parsed["start"] != "" || parsed["end"] != "") && parsed["prefix"] != "" {
|
||||
log.Fatal(`"start"/"end" may not be mixed with "prefix"`)
|
||||
}
|
||||
|
||||
var rr bigtable.RowRange
|
||||
if start, end := parsed["start"], parsed["end"]; end != "" {
|
||||
rr = bigtable.NewRange(start, end)
|
||||
} else if start != "" {
|
||||
rr = bigtable.InfiniteRange(start)
|
||||
}
|
||||
if prefix := parsed["prefix"]; prefix != "" {
|
||||
rr = bigtable.PrefixRange(prefix)
|
||||
}
|
||||
|
||||
var opts []bigtable.ReadOption
|
||||
if count := parsed["count"]; count != "" {
|
||||
n, err := strconv.ParseInt(count, 0, 64)
|
||||
if err != nil {
|
||||
log.Fatalf("Bad count %q: %v", count, err)
|
||||
}
|
||||
opts = append(opts, bigtable.LimitRows(n))
|
||||
}
|
||||
|
||||
// TODO(dsymonds): Support filters.
|
||||
err := tbl.ReadRows(ctx, rr, func(r bigtable.Row) bool {
|
||||
printRow(r)
|
||||
return true
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
log.Fatalf("Reading rows: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var setArg = regexp.MustCompile(`([^:]+):([^=]*)=(.*)`)
|
||||
|
||||
func doSet(ctx context.Context, args ...string) {
|
||||
if len(args) < 3 {
|
||||
log.Fatalf("usage: cbt set <table> <row> family:[column]=val[@ts] ...")
|
||||
}
|
||||
tbl := getClient().Open(args[0])
|
||||
row := args[1]
|
||||
mut := bigtable.NewMutation()
|
||||
for _, arg := range args[2:] {
|
||||
m := setArg.FindStringSubmatch(arg)
|
||||
if m == nil {
|
||||
log.Fatalf("Bad set arg %q", arg)
|
||||
}
|
||||
val := m[3]
|
||||
ts := bigtable.Now()
|
||||
if i := strings.LastIndex(val, "@"); i >= 0 {
|
||||
// Try parsing a timestamp.
|
||||
n, err := strconv.ParseInt(val[i+1:], 0, 64)
|
||||
if err == nil {
|
||||
val = val[:i]
|
||||
ts = bigtable.Timestamp(n)
|
||||
}
|
||||
}
|
||||
mut.Set(m[1], m[2], ts, []byte(val))
|
||||
}
|
||||
if err := tbl.Apply(ctx, row, mut); err != nil {
|
||||
log.Fatalf("Applying mutation: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func doSetGCPolicy(ctx context.Context, args ...string) {
|
||||
if len(args) < 3 {
|
||||
log.Fatalf("usage: cbt setgcpolicy <table> <family> ( maxage=<d> | maxversions=<n> )")
|
||||
}
|
||||
table := args[0]
|
||||
fam := args[1]
|
||||
|
||||
var pol bigtable.GCPolicy
|
||||
switch p := args[2]; {
|
||||
case strings.HasPrefix(p, "maxage="):
|
||||
d, err := parseDuration(p[7:])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
pol = bigtable.MaxAgePolicy(d)
|
||||
case strings.HasPrefix(p, "maxversions="):
|
||||
n, err := strconv.ParseUint(p[12:], 10, 16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
pol = bigtable.MaxVersionsPolicy(int(n))
|
||||
default:
|
||||
log.Fatalf("Bad GC policy %q", p)
|
||||
}
|
||||
if err := getAdminClient().SetGCPolicy(ctx, table, fam, pol); err != nil {
|
||||
log.Fatalf("Setting GC policy: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// parseDuration parses a duration string.
|
||||
// It is similar to Go's time.ParseDuration, except with a different set of supported units,
|
||||
// and only simple formats supported.
|
||||
func parseDuration(s string) (time.Duration, error) {
|
||||
// [0-9]+[a-z]+
|
||||
|
||||
// Split [0-9]+ from [a-z]+.
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
}
|
||||
ds, u := s[:i], s[i:]
|
||||
if ds == "" || u == "" {
|
||||
return 0, fmt.Errorf("invalid duration %q", s)
|
||||
}
|
||||
// Parse them.
|
||||
d, err := strconv.ParseUint(ds, 10, 32)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid duration %q: %v", s, err)
|
||||
}
|
||||
unit, ok := unitMap[u]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("unknown unit %q in duration %q", u, s)
|
||||
}
|
||||
if d > uint64((1<<63-1)/unit) {
|
||||
// overflow
|
||||
return 0, fmt.Errorf("invalid duration %q overflows", s)
|
||||
}
|
||||
return time.Duration(d) * unit, nil
|
||||
}
|
||||
|
||||
var unitMap = map[string]time.Duration{
|
||||
"ms": time.Millisecond,
|
||||
"s": time.Second,
|
||||
"m": time.Minute,
|
||||
"h": time.Hour,
|
||||
"d": 24 * time.Hour,
|
||||
}
|
59
vendor/cloud.google.com/go/bigtable/cmd/cbt/cbt_test.go
generated
vendored
Normal file
59
vendor/cloud.google.com/go/bigtable/cmd/cbt/cbt_test.go
generated
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestParseDuration(t *testing.T) {
|
||||
tests := []struct {
|
||||
in string
|
||||
// out or fail are mutually exclusive
|
||||
out time.Duration
|
||||
fail bool
|
||||
}{
|
||||
{in: "10ms", out: 10 * time.Millisecond},
|
||||
{in: "3s", out: 3 * time.Second},
|
||||
{in: "60m", out: 60 * time.Minute},
|
||||
{in: "12h", out: 12 * time.Hour},
|
||||
{in: "7d", out: 168 * time.Hour},
|
||||
|
||||
{in: "", fail: true},
|
||||
{in: "0", fail: true},
|
||||
{in: "7ns", fail: true},
|
||||
{in: "14mo", fail: true},
|
||||
{in: "3.5h", fail: true},
|
||||
{in: "106752d", fail: true}, // overflow
|
||||
}
|
||||
for _, tc := range tests {
|
||||
got, err := parseDuration(tc.in)
|
||||
if !tc.fail && err != nil {
|
||||
t.Errorf("parseDuration(%q) unexpectedly failed: %v", tc.in, err)
|
||||
continue
|
||||
}
|
||||
if tc.fail && err == nil {
|
||||
t.Errorf("parseDuration(%q) did not fail", tc.in)
|
||||
continue
|
||||
}
|
||||
if tc.fail {
|
||||
continue
|
||||
}
|
||||
if got != tc.out {
|
||||
t.Errorf("parseDuration(%q) = %v, want %v", tc.in, got, tc.out)
|
||||
}
|
||||
}
|
||||
}
|
191
vendor/cloud.google.com/go/bigtable/cmd/cbt/cbtdoc.go
generated
vendored
Normal file
191
vendor/cloud.google.com/go/bigtable/cmd/cbt/cbtdoc.go
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// DO NOT EDIT. THIS IS AUTOMATICALLY GENERATED.
|
||||
// Run "go generate" to regenerate.
|
||||
//go:generate go run cbt.go -o cbtdoc.go doc
|
||||
|
||||
/*
|
||||
Cbt is a tool for doing basic interactions with Cloud Bigtable.
|
||||
|
||||
Usage:
|
||||
|
||||
cbt [options] command [arguments]
|
||||
|
||||
The commands are:
|
||||
|
||||
count Count rows in a table
|
||||
createfamily Create a column family
|
||||
createtable Create a table
|
||||
deletefamily Delete a column family
|
||||
deleterow Delete a row
|
||||
deletetable Delete a table
|
||||
doc Print godoc-suitable documentation for cbt
|
||||
help Print help text
|
||||
listinstances List instances in a project
|
||||
lookup Read from a single row
|
||||
ls List tables and column families
|
||||
mddoc Print documentation for cbt in Markdown format
|
||||
read Read rows
|
||||
set Set value of a cell
|
||||
setgcpolicy Set the GC policy for a column family
|
||||
|
||||
Use "cbt help <command>" for more information about a command.
|
||||
|
||||
The options are:
|
||||
|
||||
-project string
|
||||
project ID
|
||||
-instance string
|
||||
Cloud Bigtable instance
|
||||
-creds string
|
||||
if set, use application credentials in this file
|
||||
|
||||
|
||||
Count rows in a table
|
||||
|
||||
Usage:
|
||||
cbt count <table>
|
||||
|
||||
|
||||
|
||||
|
||||
Create a column family
|
||||
|
||||
Usage:
|
||||
cbt createfamily <table> <family>
|
||||
|
||||
|
||||
|
||||
|
||||
Create a table
|
||||
|
||||
Usage:
|
||||
cbt createtable <table>
|
||||
|
||||
|
||||
|
||||
|
||||
Delete a column family
|
||||
|
||||
Usage:
|
||||
cbt deletefamily <table> <family>
|
||||
|
||||
|
||||
|
||||
|
||||
Delete a row
|
||||
|
||||
Usage:
|
||||
cbt deleterow <table> <row>
|
||||
|
||||
|
||||
|
||||
|
||||
Delete a table
|
||||
|
||||
Usage:
|
||||
cbt deletetable <table>
|
||||
|
||||
|
||||
|
||||
|
||||
Print godoc-suitable documentation for cbt
|
||||
|
||||
Usage:
|
||||
cbt doc
|
||||
|
||||
|
||||
|
||||
|
||||
Print help text
|
||||
|
||||
Usage:
|
||||
cbt help [command]
|
||||
|
||||
|
||||
|
||||
|
||||
List instances in a project
|
||||
|
||||
Usage:
|
||||
cbt listinstances
|
||||
|
||||
|
||||
|
||||
|
||||
Read from a single row
|
||||
|
||||
Usage:
|
||||
cbt lookup <table> <row>
|
||||
|
||||
|
||||
|
||||
|
||||
List tables and column families
|
||||
|
||||
Usage:
|
||||
cbt ls List tables
|
||||
cbt ls <table> List column families in <table>
|
||||
|
||||
|
||||
|
||||
|
||||
Print documentation for cbt in Markdown format
|
||||
|
||||
Usage:
|
||||
cbt mddoc
|
||||
|
||||
|
||||
|
||||
|
||||
Read rows
|
||||
|
||||
Usage:
|
||||
cbt read <table> [start=<row>] [end=<row>] [prefix=<prefix>] [count=<n>]
|
||||
start=<row> Start reading at this row
|
||||
end=<row> Stop reading before this row
|
||||
prefix=<prefix> Read rows with this prefix
|
||||
count=<n> Read only this many rows
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Set value of a cell
|
||||
|
||||
Usage:
|
||||
cbt set <table> <row> family:column=val[@ts] ...
|
||||
family:column=val[@ts] may be repeated to set multiple cells.
|
||||
|
||||
ts is an optional integer timestamp.
|
||||
If it cannot be parsed, the `@ts` part will be
|
||||
interpreted as part of the value.
|
||||
|
||||
|
||||
|
||||
|
||||
Set the GC policy for a column family
|
||||
|
||||
Usage:
|
||||
cbt setgcpolicy <table> <family> ( maxage=<d> | maxversions=<n> )
|
||||
|
||||
maxage=<d> Maximum timestamp age to preserve (e.g. "1h", "4d")
|
||||
maxversions=<n> Maximum number of versions to preserve
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
package main
|
44
vendor/cloud.google.com/go/bigtable/cmd/emulator/cbtemulator.go
generated
vendored
Normal file
44
vendor/cloud.google.com/go/bigtable/cmd/emulator/cbtemulator.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*
|
||||
cbtemulator launches the in-memory Cloud Bigtable server on the given address.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"cloud.google.com/go/bigtable/bttest"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var (
|
||||
host = flag.String("host", "localhost", "the address to bind to on the local machine")
|
||||
port = flag.Int("port", 9000, "the port number to bind to on the local machine")
|
||||
)
|
||||
|
||||
func main() {
|
||||
grpc.EnableTracing = false
|
||||
flag.Parse()
|
||||
srv, err := bttest.NewServer(fmt.Sprintf("%s:%d", *host, *port))
|
||||
if err != nil {
|
||||
log.Fatalf("failed to start emulator: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Cloud Bigtable emulator running on %s\n", srv.Addr)
|
||||
select {}
|
||||
}
|
186
vendor/cloud.google.com/go/bigtable/cmd/loadtest/loadtest.go
generated
vendored
Normal file
186
vendor/cloud.google.com/go/bigtable/cmd/loadtest/loadtest.go
generated
vendored
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Loadtest does some load testing through the Go client library for Cloud Bigtable.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/bigtable"
|
||||
"cloud.google.com/go/bigtable/internal/cbtconfig"
|
||||
"cloud.google.com/go/bigtable/internal/stat"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
var (
|
||||
runFor = flag.Duration("run_for", 5*time.Second, "how long to run the load test for")
|
||||
scratchTable = flag.String("scratch_table", "loadtest-scratch", "name of table to use; should not already exist")
|
||||
csvOutput = flag.String("csv_output", "",
|
||||
"output path for statistics in .csv format. If this file already exists it will be overwritten.")
|
||||
poolSize = flag.Int("pool_size", 1, "size of the gRPC connection pool to use for the data client")
|
||||
reqCount = flag.Int("req_count", 100, "number of concurrent requests")
|
||||
|
||||
config *cbtconfig.Config
|
||||
client *bigtable.Client
|
||||
adminClient *bigtable.AdminClient
|
||||
)
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
config, err = cbtconfig.Load()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
config.RegisterFlags()
|
||||
|
||||
flag.Parse()
|
||||
if err := config.CheckFlags(cbtconfig.ProjectAndInstanceRequired); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if config.Creds != "" {
|
||||
os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", config.Creds)
|
||||
}
|
||||
if flag.NArg() != 0 {
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var options []option.ClientOption
|
||||
if *poolSize > 1 {
|
||||
options = append(options, option.WithGRPCConnectionPool(*poolSize))
|
||||
}
|
||||
|
||||
var csvFile *os.File
|
||||
if *csvOutput != "" {
|
||||
csvFile, err = os.Create(*csvOutput)
|
||||
if err != nil {
|
||||
log.Fatalf("creating csv output file: %v", err)
|
||||
}
|
||||
defer csvFile.Close()
|
||||
log.Printf("Writing statistics to %q ...", *csvOutput)
|
||||
}
|
||||
|
||||
log.Printf("Dialing connections...")
|
||||
client, err = bigtable.NewClient(context.Background(), config.Project, config.Instance, options...)
|
||||
if err != nil {
|
||||
log.Fatalf("Making bigtable.Client: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
adminClient, err = bigtable.NewAdminClient(context.Background(), config.Project, config.Instance)
|
||||
if err != nil {
|
||||
log.Fatalf("Making bigtable.AdminClient: %v", err)
|
||||
}
|
||||
defer adminClient.Close()
|
||||
|
||||
// Create a scratch table.
|
||||
log.Printf("Setting up scratch table...")
|
||||
if err := adminClient.CreateTable(context.Background(), *scratchTable); err != nil {
|
||||
log.Fatalf("Making scratch table %q: %v", *scratchTable, err)
|
||||
}
|
||||
if err := adminClient.CreateColumnFamily(context.Background(), *scratchTable, "f"); err != nil {
|
||||
log.Fatalf("Making scratch table column family: %v", err)
|
||||
}
|
||||
// Upon a successful run, delete the table. Don't bother checking for errors.
|
||||
defer adminClient.DeleteTable(context.Background(), *scratchTable)
|
||||
|
||||
log.Printf("Starting load test... (run for %v)", *runFor)
|
||||
tbl := client.Open(*scratchTable)
|
||||
sem := make(chan int, *reqCount) // limit the number of requests happening at once
|
||||
var reads, writes stats
|
||||
stopTime := time.Now().Add(*runFor)
|
||||
var wg sync.WaitGroup
|
||||
for time.Now().Before(stopTime) {
|
||||
sem <- 1
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer func() { <-sem }()
|
||||
|
||||
ok := true
|
||||
opStart := time.Now()
|
||||
var stats *stats
|
||||
defer func() {
|
||||
stats.Record(ok, time.Since(opStart))
|
||||
}()
|
||||
|
||||
row := fmt.Sprintf("row%d", rand.Intn(100)) // operate on 1 of 100 rows
|
||||
|
||||
switch rand.Intn(10) {
|
||||
default:
|
||||
// read
|
||||
stats = &reads
|
||||
_, err := tbl.ReadRow(context.Background(), row, bigtable.RowFilter(bigtable.LatestNFilter(1)))
|
||||
if err != nil {
|
||||
log.Printf("Error doing read: %v", err)
|
||||
ok = false
|
||||
}
|
||||
case 0, 1, 2, 3, 4:
|
||||
// write
|
||||
stats = &writes
|
||||
mut := bigtable.NewMutation()
|
||||
mut.Set("f", "col", bigtable.Now(), bytes.Repeat([]byte("0"), 1<<10)) // 1 KB write
|
||||
if err := tbl.Apply(context.Background(), row, mut); err != nil {
|
||||
log.Printf("Error doing mutation: %v", err)
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
readsAgg := stat.NewAggregate("reads", reads.ds, reads.tries-reads.ok)
|
||||
writesAgg := stat.NewAggregate("writes", writes.ds, writes.tries-writes.ok)
|
||||
log.Printf("Reads (%d ok / %d tries):\n%v", reads.ok, reads.tries, readsAgg)
|
||||
log.Printf("Writes (%d ok / %d tries):\n%v", writes.ok, writes.tries, writesAgg)
|
||||
|
||||
if csvFile != nil {
|
||||
stat.WriteCSV([]*stat.Aggregate{readsAgg, writesAgg}, csvFile)
|
||||
}
|
||||
}
|
||||
|
||||
var allStats int64 // atomic
|
||||
|
||||
type stats struct {
|
||||
mu sync.Mutex
|
||||
tries, ok int
|
||||
ds []time.Duration
|
||||
}
|
||||
|
||||
func (s *stats) Record(ok bool, d time.Duration) {
|
||||
s.mu.Lock()
|
||||
s.tries++
|
||||
if ok {
|
||||
s.ok++
|
||||
}
|
||||
s.ds = append(s.ds, d)
|
||||
s.mu.Unlock()
|
||||
|
||||
if n := atomic.AddInt64(&allStats, 1); n%1000 == 0 {
|
||||
log.Printf("Progress: done %d ops", n)
|
||||
}
|
||||
}
|
155
vendor/cloud.google.com/go/bigtable/cmd/scantest/scantest.go
generated
vendored
Normal file
155
vendor/cloud.google.com/go/bigtable/cmd/scantest/scantest.go
generated
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Scantest does scan-related load testing against Cloud Bigtable. The logic here
|
||||
mimics a similar test written using the Java client.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/bigtable"
|
||||
"cloud.google.com/go/bigtable/internal/cbtconfig"
|
||||
"cloud.google.com/go/bigtable/internal/stat"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
runFor = flag.Duration("run_for", 5*time.Second, "how long to run the load test for")
|
||||
numScans = flag.Int("concurrent_scans", 1, "number of concurrent scans")
|
||||
rowLimit = flag.Int("row_limit", 10000, "max number of records per scan")
|
||||
|
||||
config *cbtconfig.Config
|
||||
client *bigtable.Client
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Usage = func() {
|
||||
fmt.Printf("Usage: scantest [options] <table_name>\n\n")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
var err error
|
||||
config, err = cbtconfig.Load()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
config.RegisterFlags()
|
||||
|
||||
flag.Parse()
|
||||
if err := config.CheckFlags(cbtconfig.ProjectAndInstanceRequired); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if config.Creds != "" {
|
||||
os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", config.Creds)
|
||||
}
|
||||
if flag.NArg() != 1 {
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
table := flag.Arg(0)
|
||||
|
||||
log.Printf("Dialing connections...")
|
||||
client, err = bigtable.NewClient(context.Background(), config.Project, config.Instance)
|
||||
if err != nil {
|
||||
log.Fatalf("Making bigtable.Client: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
log.Printf("Starting scan test... (run for %v)", *runFor)
|
||||
tbl := client.Open(table)
|
||||
sem := make(chan int, *numScans) // limit the number of requests happening at once
|
||||
var scans stats
|
||||
|
||||
stopTime := time.Now().Add(*runFor)
|
||||
var wg sync.WaitGroup
|
||||
for time.Now().Before(stopTime) {
|
||||
sem <- 1
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer func() { <-sem }()
|
||||
|
||||
ok := true
|
||||
opStart := time.Now()
|
||||
defer func() {
|
||||
scans.Record(ok, time.Since(opStart))
|
||||
}()
|
||||
|
||||
// Start at a random row key
|
||||
key := fmt.Sprintf("user%d", rand.Int63())
|
||||
limit := bigtable.LimitRows(int64(*rowLimit))
|
||||
noop := func(bigtable.Row) bool { return true }
|
||||
if err := tbl.ReadRows(context.Background(), bigtable.NewRange(key, ""), noop, limit); err != nil {
|
||||
log.Printf("Error during scan: %v", err)
|
||||
ok = false
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
agg := stat.NewAggregate("scans", scans.ds, scans.tries-scans.ok)
|
||||
log.Printf("Scans (%d ok / %d tries):\nscan times:\n%v\nthroughput (rows/second):\n%v",
|
||||
scans.ok, scans.tries, agg, throughputString(agg))
|
||||
}
|
||||
|
||||
func throughputString(agg *stat.Aggregate) string {
|
||||
var buf bytes.Buffer
|
||||
tw := tabwriter.NewWriter(&buf, 0, 0, 1, ' ', 0) // one-space padding
|
||||
rowLimitF := float64(*rowLimit)
|
||||
fmt.Fprintf(
|
||||
tw,
|
||||
"min:\t%.2f\nmedian:\t%.2f\nmax:\t%.2f\n",
|
||||
rowLimitF/agg.Max.Seconds(),
|
||||
rowLimitF/agg.Median.Seconds(),
|
||||
rowLimitF/agg.Min.Seconds())
|
||||
tw.Flush()
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
var allStats int64 // atomic
|
||||
|
||||
type stats struct {
|
||||
mu sync.Mutex
|
||||
tries, ok int
|
||||
ds []time.Duration
|
||||
}
|
||||
|
||||
func (s *stats) Record(ok bool, d time.Duration) {
|
||||
s.mu.Lock()
|
||||
s.tries++
|
||||
if ok {
|
||||
s.ok++
|
||||
}
|
||||
s.ds = append(s.ds, d)
|
||||
s.mu.Unlock()
|
||||
|
||||
if n := atomic.AddInt64(&allStats, 1); n%1000 == 0 {
|
||||
log.Printf("Progress: done %d ops", n)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue