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 }