github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/storage/netstore.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:50</date> 10 //</624342684219215872> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 package storage 29 30 import ( 31 "context" 32 "time" 33 34 "github.com/ethereum/go-ethereum/swarm/log" 35 "github.com/ethereum/go-ethereum/swarm/spancontext" 36 opentracing "github.com/opentracing/opentracing-go" 37 ) 38 39 var ( 40 // 41 // 42 // 43 netStoreRetryTimeout = 30 * time.Second 44 // 45 // 46 // 47 netStoreMinRetryDelay = 3 * time.Second 48 // 49 // 50 // 51 searchTimeout = 10 * time.Second 52 ) 53 54 // 55 // 56 // 57 // 58 type NetStore struct { 59 localStore *LocalStore 60 retrieve func(ctx context.Context, chunk *Chunk) error 61 } 62 63 func NewNetStore(localStore *LocalStore, retrieve func(ctx context.Context, chunk *Chunk) error) *NetStore { 64 return &NetStore{localStore, retrieve} 65 } 66 67 // 68 // 69 // 70 // 71 // 72 // 73 func (ns *NetStore) Get(ctx context.Context, addr Address) (chunk *Chunk, err error) { 74 75 var sp opentracing.Span 76 ctx, sp = spancontext.StartSpan( 77 ctx, 78 "netstore.get.global") 79 defer sp.Finish() 80 81 timer := time.NewTimer(netStoreRetryTimeout) 82 defer timer.Stop() 83 84 // 85 // 86 type result struct { 87 chunk *Chunk 88 err error 89 } 90 resultC := make(chan result) 91 92 // 93 // 94 quitC := make(chan struct{}) 95 defer close(quitC) 96 97 // 98 // 99 go func() { 100 // 101 // 102 // 103 // 104 limiter := time.NewTimer(netStoreMinRetryDelay) 105 defer limiter.Stop() 106 107 for { 108 chunk, err := ns.get(ctx, addr, 0) 109 if err != ErrChunkNotFound { 110 // 111 // 112 select { 113 case <-quitC: 114 // 115 // 116 // 117 case resultC <- result{chunk: chunk, err: err}: 118 // 119 } 120 return 121 122 } 123 select { 124 case <-quitC: 125 // 126 // 127 // 128 return 129 case <-limiter.C: 130 } 131 // 132 limiter.Reset(netStoreMinRetryDelay) 133 log.Debug("NetStore.Get retry chunk", "key", addr) 134 } 135 }() 136 137 select { 138 case r := <-resultC: 139 return r.chunk, r.err 140 case <-timer.C: 141 return nil, ErrChunkNotFound 142 } 143 } 144 145 // 146 func (ns *NetStore) GetWithTimeout(ctx context.Context, addr Address, timeout time.Duration) (chunk *Chunk, err error) { 147 return ns.get(ctx, addr, timeout) 148 } 149 150 func (ns *NetStore) get(ctx context.Context, addr Address, timeout time.Duration) (chunk *Chunk, err error) { 151 if timeout == 0 { 152 timeout = searchTimeout 153 } 154 155 var sp opentracing.Span 156 ctx, sp = spancontext.StartSpan( 157 ctx, 158 "netstore.get") 159 defer sp.Finish() 160 161 if ns.retrieve == nil { 162 chunk, err = ns.localStore.Get(ctx, addr) 163 if err == nil { 164 return chunk, nil 165 } 166 if err != ErrFetching { 167 return nil, err 168 } 169 } else { 170 var created bool 171 chunk, created = ns.localStore.GetOrCreateRequest(ctx, addr) 172 173 if chunk.ReqC == nil { 174 return chunk, nil 175 } 176 177 if created { 178 err := ns.retrieve(ctx, chunk) 179 if err != nil { 180 // 181 chunk.SetErrored(ErrChunkUnavailable) 182 return nil, err 183 } 184 } 185 } 186 187 t := time.NewTicker(timeout) 188 defer t.Stop() 189 190 select { 191 case <-t.C: 192 // 193 chunk.SetErrored(ErrChunkNotFound) 194 return nil, ErrChunkNotFound 195 case <-chunk.ReqC: 196 } 197 chunk.SetErrored(nil) 198 return chunk, nil 199 } 200 201 // 202 func (ns *NetStore) Put(ctx context.Context, chunk *Chunk) { 203 ns.localStore.Put(ctx, chunk) 204 } 205 206 // 207 func (ns *NetStore) Close() { 208 ns.localStore.Close() 209 } 210