github.com/daeglee/go-ethereum@v0.0.0-20190504220456-cad3e8d18e9b/cmd/swarm/swarm-smoke/upload_and_sync.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "bytes" 21 "context" 22 "fmt" 23 "io/ioutil" 24 "math/rand" 25 "os" 26 "strings" 27 "sync" 28 "time" 29 30 "github.com/ethereum/go-ethereum/log" 31 "github.com/ethereum/go-ethereum/metrics" 32 "github.com/ethereum/go-ethereum/rpc" 33 "github.com/ethereum/go-ethereum/swarm/api" 34 "github.com/ethereum/go-ethereum/swarm/storage" 35 "github.com/ethereum/go-ethereum/swarm/testutil" 36 "github.com/pborman/uuid" 37 38 cli "gopkg.in/urfave/cli.v1" 39 ) 40 41 func uploadAndSyncCmd(ctx *cli.Context, tuid string) error { 42 // use input seed if it has been set 43 if inputSeed != 0 { 44 seed = inputSeed 45 } 46 47 randomBytes := testutil.RandomBytes(seed, filesize*1000) 48 49 errc := make(chan error) 50 51 go func() { 52 errc <- uploadAndSync(ctx, randomBytes, tuid) 53 }() 54 55 var err error 56 select { 57 case err = <-errc: 58 if err != nil { 59 metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1) 60 } 61 case <-time.After(time.Duration(timeout) * time.Second): 62 metrics.GetOrRegisterCounter(fmt.Sprintf("%s.timeout", commandName), nil).Inc(1) 63 64 err = fmt.Errorf("timeout after %v sec", timeout) 65 } 66 67 // trigger debug functionality on randomBytes 68 e := trackChunks(randomBytes[:]) 69 if e != nil { 70 log.Error(e.Error()) 71 } 72 73 return err 74 } 75 76 func trackChunks(testData []byte) error { 77 addrs, err := getAllRefs(testData) 78 if err != nil { 79 return err 80 } 81 82 for i, ref := range addrs { 83 log.Trace(fmt.Sprintf("ref %d", i), "ref", ref) 84 } 85 86 for _, host := range hosts { 87 httpHost := fmt.Sprintf("ws://%s:%d", host, 8546) 88 89 hostChunks := []string{} 90 91 rpcClient, err := rpc.Dial(httpHost) 92 if err != nil { 93 log.Error("error dialing host", "err", err, "host", httpHost) 94 continue 95 } 96 97 var hasInfo []api.HasInfo 98 err = rpcClient.Call(&hasInfo, "bzz_has", addrs) 99 if err != nil { 100 log.Error("error calling rpc client", "err", err, "host", httpHost) 101 continue 102 } 103 104 count := 0 105 for _, info := range hasInfo { 106 if info.Has { 107 hostChunks = append(hostChunks, "1") 108 } else { 109 hostChunks = append(hostChunks, "0") 110 count++ 111 } 112 } 113 114 if count == 0 { 115 log.Info("host reported to have all chunks", "host", host) 116 } 117 118 log.Trace("chunks", "chunks", strings.Join(hostChunks, ""), "host", host) 119 } 120 return nil 121 } 122 123 func getAllRefs(testData []byte) (storage.AddressCollection, error) { 124 datadir, err := ioutil.TempDir("", "chunk-debug") 125 if err != nil { 126 return nil, fmt.Errorf("unable to create temp dir: %v", err) 127 } 128 defer os.RemoveAll(datadir) 129 fileStore, err := storage.NewLocalFileStore(datadir, make([]byte, 32)) 130 if err != nil { 131 return nil, err 132 } 133 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(trackTimeout)*time.Second) 134 defer cancel() 135 136 reader := bytes.NewReader(testData) 137 return fileStore.GetAllReferences(ctx, reader, false) 138 } 139 140 func uploadAndSync(c *cli.Context, randomBytes []byte, tuid string) error { 141 log.Info("uploading to "+httpEndpoint(hosts[0])+" and syncing", "tuid", tuid, "seed", seed) 142 143 t1 := time.Now() 144 hash, err := upload(randomBytes, httpEndpoint(hosts[0])) 145 if err != nil { 146 log.Error(err.Error()) 147 return err 148 } 149 t2 := time.Since(t1) 150 metrics.GetOrRegisterResettingTimer("upload-and-sync.upload-time", nil).Update(t2) 151 152 fhash, err := digest(bytes.NewReader(randomBytes)) 153 if err != nil { 154 log.Error(err.Error()) 155 return err 156 } 157 158 log.Info("uploaded successfully", "tuid", tuid, "hash", hash, "took", t2, "digest", fmt.Sprintf("%x", fhash)) 159 160 time.Sleep(time.Duration(syncDelay) * time.Second) 161 162 wg := sync.WaitGroup{} 163 if single { 164 randIndex := 1 + rand.Intn(len(hosts)-1) 165 ruid := uuid.New()[:8] 166 wg.Add(1) 167 go func(endpoint string, ruid string) { 168 for { 169 start := time.Now() 170 err := fetch(hash, endpoint, fhash, ruid, tuid) 171 if err != nil { 172 continue 173 } 174 ended := time.Since(start) 175 176 metrics.GetOrRegisterResettingTimer("upload-and-sync.single.fetch-time", nil).Update(ended) 177 log.Info("fetch successful", "tuid", tuid, "ruid", ruid, "took", ended, "endpoint", endpoint) 178 wg.Done() 179 return 180 } 181 }(httpEndpoint(hosts[randIndex]), ruid) 182 } else { 183 for _, endpoint := range hosts[1:] { 184 ruid := uuid.New()[:8] 185 wg.Add(1) 186 go func(endpoint string, ruid string) { 187 for { 188 start := time.Now() 189 err := fetch(hash, endpoint, fhash, ruid, tuid) 190 if err != nil { 191 continue 192 } 193 ended := time.Since(start) 194 195 metrics.GetOrRegisterResettingTimer("upload-and-sync.each.fetch-time", nil).Update(ended) 196 log.Info("fetch successful", "tuid", tuid, "ruid", ruid, "took", ended, "endpoint", endpoint) 197 wg.Done() 198 return 199 } 200 }(httpEndpoint(endpoint), ruid) 201 } 202 } 203 wg.Wait() 204 log.Info("all hosts synced random file successfully") 205 206 return nil 207 }