github.com/mre-fog/trillianxx@v1.1.2-0.20180615153820-ae375a99d36a/testonly/hammer/maphammer/main.go (about)

     1  // Copyright 2017 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // maphammer is a stress/load test for a Trillian Map.
    16  package main
    17  
    18  import (
    19  	"bytes"
    20  	"compress/gzip"
    21  	"encoding/base64"
    22  	"flag"
    23  	"fmt"
    24  	"io"
    25  	"math/rand"
    26  	"net/http"
    27  	"os"
    28  	"strconv"
    29  	"strings"
    30  	"sync"
    31  	"time"
    32  
    33  	"github.com/golang/glog"
    34  	"github.com/google/trillian"
    35  	"github.com/google/trillian/monitoring"
    36  	"github.com/google/trillian/monitoring/prometheus"
    37  	"github.com/google/trillian/testonly/hammer"
    38  	"github.com/prometheus/client_golang/prometheus/promhttp"
    39  	"google.golang.org/grpc"
    40  
    41  	_ "github.com/google/trillian/merkle/coniks"    // register CONIKS_SHA512_256
    42  	_ "github.com/google/trillian/merkle/maphasher" // register TEST_MAP_HASHER
    43  )
    44  
    45  var (
    46  	mapIDs          = flag.String("map_ids", "", "Comma-separated list of map IDs to test")
    47  	rpcServer       = flag.String("rpc_server", "", "Server address:port")
    48  	adminServer     = flag.String("admin_server", "", "Address of the gRPC Trillian Admin Server (host:port)")
    49  	metricsEndpoint = flag.String("metrics_endpoint", "", "Endpoint for serving metrics; if left empty, metrics will not be exposed")
    50  	outLog          = flag.String("log_to", "", "File to record operations in")
    51  	seed            = flag.Int64("seed", -1, "Seed for random number generation")
    52  	operations      = flag.Uint64("operations", ^uint64(0), "Number of operations to perform")
    53  	minLeaves       = flag.Int("min_leaves", 0, "Minimum count of leaves to affect per-operation")
    54  	maxLeaves       = flag.Int("max_leaves", 10, "Maximum count of leaves to affect per-operation")
    55  	leafSize        = flag.Uint("leaf_size", 100, "Size of leaf values")
    56  	extraSize       = flag.Uint("extra_size", 100, "Size of leaf extra data")
    57  	checkers        = flag.Int("checkers", 0, "Number of checker goroutines to run")
    58  )
    59  var (
    60  	getLeavesBias    = flag.Int("get_leaves", 20, "Bias for get-leaves operations")
    61  	getLeavesRevBias = flag.Int("get_leaves_rev", 2, "Bias for get-leaves-revision operations")
    62  	setLeavesBias    = flag.Int("set_leaves", 20, "Bias for set-leaves operations")
    63  	getSMRBias       = flag.Int("get_smr", 10, "Bias for get-smr operations")
    64  	getSMRRevBias    = flag.Int("get_smr_rev", 2, "Bias for get-smr-revision operations")
    65  	invalidChance    = flag.Int("invalid_chance", 10, "Chance of generating an invalid operation, as the N in 1-in-N (0 for never)")
    66  )
    67  
    68  func main() {
    69  	flag.Parse()
    70  	defer glog.Flush()
    71  
    72  	if *mapIDs == "" {
    73  		glog.Exit("Test aborted as no map IDs provided (via --map_ids)")
    74  	}
    75  	if *seed == -1 {
    76  		*seed = time.Now().UTC().UnixNano() & 0xFFFFFFFF
    77  	}
    78  	fmt.Printf("Today's test has been brought to you by the letters M, A, and P and the number %#x\n", *seed)
    79  
    80  	bias := hammer.MapBias{
    81  		Bias: map[hammer.MapEntrypointName]int{
    82  			hammer.GetLeavesName:    *getLeavesBias,
    83  			hammer.GetLeavesRevName: *getLeavesRevBias,
    84  			hammer.SetLeavesName:    *setLeavesBias,
    85  			hammer.GetSMRName:       *getSMRBias,
    86  			hammer.GetSMRRevName:    *getSMRRevBias,
    87  		},
    88  		InvalidChance: map[hammer.MapEntrypointName]int{
    89  			hammer.GetLeavesName:    *invalidChance,
    90  			hammer.GetLeavesRevName: *invalidChance,
    91  			hammer.SetLeavesName:    *invalidChance,
    92  			hammer.GetSMRName:       0,
    93  			hammer.GetSMRRevName:    *getSMRRevBias,
    94  		},
    95  	}
    96  
    97  	var mf monitoring.MetricFactory
    98  	if *metricsEndpoint != "" {
    99  		mf = prometheus.MetricFactory{}
   100  		http.Handle("/metrics", promhttp.Handler())
   101  		server := http.Server{Addr: *metricsEndpoint, Handler: nil}
   102  		glog.Infof("Serving metrics at %v", *metricsEndpoint)
   103  		go func() {
   104  			err := server.ListenAndServe()
   105  			glog.Warningf("Metrics server exited: %v", err)
   106  		}()
   107  	} else {
   108  		mf = monitoring.InertMetricFactory{}
   109  	}
   110  
   111  	fmt.Print("\n\nIf they'd let me have my way I could have flayed him into shape.\n")
   112  	for i := 0; i < 8; i++ {
   113  		time.Sleep(100 * time.Millisecond)
   114  		fmt.Print(".")
   115  	}
   116  	fmt.Print("\n\n")
   117  	mc := "H4sIAAAAAAAA/5yXMa70KgyF+1kFBR3WaTNCQmloKAK9F8PanzAkgQxJ7vute6UJCR8H24D5qBdD+QfQPT7aO3CCeKL+C7DovWX+E1CNbngCzuTMgXfIEUgg+3cjol/m7ZR/Bm9dv+cbYDKD/wkEHKcjhajN/E/A4Je1WOqAyJsCUhyAF+IUCGeMMcyaWdseqLZt27JJSeMEFtfjCgRAh0VjTKRb26gM9z06lK4/wFMGfJEXRs8Pn+StAI07X8CeGgXYvYJf5WuDW2Cy8oU7iSAcxM/YCUiQ8cFhDkT0CS4C3rj9XQHuxAI8/W45WRTHa+/1ihnQM0df4oNk4g60MusdaLHbl2HXKD8jMzN+rTRT/bkEp1orAdbWoT9K5T2RAIba2rDQzOzRx0vByzD7M5tOuW2B+Sjk3odbPugxnb1rAjAPLWy68cjVSX9g7N0mKiK/ZzRG3AWIE0jTLRg7QzfFBfcdhh7WHJwRYgFOfH+Yrhishbc+fZnXXIHrOOhVaRGZCnaXOtuISuK5kEtYPvQCbKFgjlBPQOQlWwEGegHWaET1AnSLhOVDywvw62PkFKM3j1OG0VmA0PbJ1TbGGL38Ra/uviIJW1UIdrdpo1QFZYjOGD1uHU6L3oFhemyXxI4C8fXZC7JfbeidZbWrQcGqabpSQFXUsZ5jvIjsgDLjClRgNwXKbDtJqC3e65lC0uxqYiuwnqyVUIPhR9/7XeSPGXZ1MX9kG/p5X+X57dLcph3jNResbjMu+yEC5yFwzf8xlhFHdyC1V3potWEXKEAkbY9dUyE37/vpEbD7ts8gFF4VKGcKKC3HtoomIW6d5oHY9J/hR06HwAoEpUDS9fC7P3fu9t/VSz52wVHIOjmX6ThTRFfSuVQBdp/ufeEgtUX7TB7W1PFa5QDY3Y/eRx+/9+VctZqRJQ+xsj4c2Nc2lnXdTkCy1p6BZWCUxLZLcj3vqG0AYg6SJ62GfgHWBHTMI+9QWDRa5pXuN73fFqdZm85/aqi+ALIuccj2JhKXdmt0qtMdNpe+nAORdczBXje94bisf2S0zLak30MFC7LZpYE5u1aQW5jXoi5bei7aIciQWIdMs6UHWLMwJ5cb7vUWUArcnF2Wkzi4TMfeRtatSzmhQ6k2i+8m15RZ0S59bc7OGc0XC9m5OtWJuDtgzTESaO0/mMBE9qzrw8WnXgysYHc77mP319HH2+juvPMCgVtlfwLe2H8BAAD///XdWNEGEAAA"
   118  	mcData, _ := base64.StdEncoding.DecodeString(mc)
   119  	b := bytes.NewReader(mcData)
   120  	r, _ := gzip.NewReader(b)
   121  	io.Copy(os.Stdout, r)
   122  	r.Close()
   123  	fmt.Print("\n\nLet me hammer him today?\n\n")
   124  
   125  	dialOpts := []grpc.DialOption{grpc.WithInsecure()}
   126  	if *outLog != "" {
   127  		cl, err := hammer.NewRecordingInterceptor(*outLog)
   128  		if err != nil {
   129  			glog.Exitf("failed to build recording interceptor: %v", err)
   130  		}
   131  		dialOpts = append(dialOpts, grpc.WithUnaryInterceptor(cl))
   132  	}
   133  
   134  	mIDs := strings.Split(*mapIDs, ",")
   135  	type result struct {
   136  		mapID int64
   137  		err   error
   138  	}
   139  	results := make(chan result, len(mIDs))
   140  	var wg sync.WaitGroup
   141  	for _, m := range mIDs {
   142  		randSrc := rand.NewSource(*seed)
   143  		mapid, err := strconv.ParseInt(m, 10, 64)
   144  		if err != nil || mapid <= 0 {
   145  			glog.Exitf("Invalid map ID %q", m)
   146  		}
   147  		wg.Add(1)
   148  		c, err := grpc.Dial(*rpcServer, dialOpts...)
   149  		if err != nil {
   150  			glog.Exitf("Failed to create map client conn: %v", err)
   151  		}
   152  		ac, err := grpc.Dial(*adminServer, dialOpts...)
   153  		if err != nil {
   154  			glog.Exitf("Failed to create admin client conn: %v", err)
   155  		}
   156  		cfg := hammer.MapConfig{
   157  			MapID:         mapid,
   158  			Client:        trillian.NewTrillianMapClient(c),
   159  			Admin:         trillian.NewTrillianAdminClient(ac),
   160  			MetricFactory: mf,
   161  			RandSource:    randSrc,
   162  			EPBias:        bias,
   163  			LeafSize:      *leafSize,
   164  			ExtraSize:     *extraSize,
   165  			MinLeaves:     *minLeaves,
   166  			MaxLeaves:     *maxLeaves,
   167  			Operations:    *operations,
   168  			NumCheckers:   *checkers,
   169  		}
   170  		fmt.Printf("%v\n\n", cfg)
   171  		go func(cfg hammer.MapConfig) {
   172  			defer wg.Done()
   173  			err := hammer.HitMap(cfg)
   174  			results <- result{mapID: cfg.MapID, err: err}
   175  		}(cfg)
   176  	}
   177  	wg.Wait()
   178  
   179  	glog.Infof("completed tests on all %d maps:", len(mIDs))
   180  	close(results)
   181  	errCount := 0
   182  	for e := range results {
   183  		if e.err != nil {
   184  			errCount++
   185  			glog.Errorf("  %d: failed with %v", e.mapID, e.err)
   186  		}
   187  	}
   188  	if errCount > 0 {
   189  		glog.Exitf("non-zero error count (%d), exiting", errCount)
   190  	}
   191  	glog.Info("  no errors; done")
   192  }