github.com/divan/go-ethereum@v1.8.14-0.20180820134928-1de9ada4016d/swarm/network/stream/peer.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser 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 // The go-ethereum library 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 Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package stream 18 19 import ( 20 "context" 21 "fmt" 22 "sync" 23 "time" 24 25 "github.com/ethereum/go-ethereum/metrics" 26 "github.com/ethereum/go-ethereum/p2p/protocols" 27 "github.com/ethereum/go-ethereum/swarm/log" 28 pq "github.com/ethereum/go-ethereum/swarm/network/priorityqueue" 29 "github.com/ethereum/go-ethereum/swarm/network/stream/intervals" 30 "github.com/ethereum/go-ethereum/swarm/spancontext" 31 "github.com/ethereum/go-ethereum/swarm/state" 32 "github.com/ethereum/go-ethereum/swarm/storage" 33 opentracing "github.com/opentracing/opentracing-go" 34 ) 35 36 var sendTimeout = 30 * time.Second 37 38 type notFoundError struct { 39 t string 40 s Stream 41 } 42 43 func newNotFoundError(t string, s Stream) *notFoundError { 44 return ¬FoundError{t: t, s: s} 45 } 46 47 func (e *notFoundError) Error() string { 48 return fmt.Sprintf("%s not found for stream %q", e.t, e.s) 49 } 50 51 // Peer is the Peer extension for the streaming protocol 52 type Peer struct { 53 *protocols.Peer 54 streamer *Registry 55 pq *pq.PriorityQueue 56 serverMu sync.RWMutex 57 clientMu sync.RWMutex // protects both clients and clientParams 58 servers map[Stream]*server 59 clients map[Stream]*client 60 // clientParams map keeps required client arguments 61 // that are set on Registry.Subscribe and used 62 // on creating a new client in offered hashes handler. 63 clientParams map[Stream]*clientParams 64 quit chan struct{} 65 } 66 67 type WrappedPriorityMsg struct { 68 Context context.Context 69 Msg interface{} 70 } 71 72 // NewPeer is the constructor for Peer 73 func NewPeer(peer *protocols.Peer, streamer *Registry) *Peer { 74 p := &Peer{ 75 Peer: peer, 76 pq: pq.New(int(PriorityQueue), PriorityQueueCap), 77 streamer: streamer, 78 servers: make(map[Stream]*server), 79 clients: make(map[Stream]*client), 80 clientParams: make(map[Stream]*clientParams), 81 quit: make(chan struct{}), 82 } 83 ctx, cancel := context.WithCancel(context.Background()) 84 go p.pq.Run(ctx, func(i interface{}) { 85 wmsg := i.(WrappedPriorityMsg) 86 p.Send(wmsg.Context, wmsg.Msg) 87 }) 88 go func() { 89 <-p.quit 90 cancel() 91 }() 92 return p 93 } 94 95 // Deliver sends a storeRequestMsg protocol message to the peer 96 func (p *Peer) Deliver(ctx context.Context, chunk *storage.Chunk, priority uint8) error { 97 var sp opentracing.Span 98 ctx, sp = spancontext.StartSpan( 99 ctx, 100 "send.chunk.delivery") 101 defer sp.Finish() 102 103 msg := &ChunkDeliveryMsg{ 104 Addr: chunk.Addr, 105 SData: chunk.SData, 106 } 107 return p.SendPriority(ctx, msg, priority) 108 } 109 110 // SendPriority sends message to the peer using the outgoing priority queue 111 func (p *Peer) SendPriority(ctx context.Context, msg interface{}, priority uint8) error { 112 defer metrics.GetOrRegisterResettingTimer(fmt.Sprintf("peer.sendpriority_t.%d", priority), nil).UpdateSince(time.Now()) 113 metrics.GetOrRegisterCounter(fmt.Sprintf("peer.sendpriority.%d", priority), nil).Inc(1) 114 cctx, cancel := context.WithTimeout(context.Background(), sendTimeout) 115 defer cancel() 116 wmsg := WrappedPriorityMsg{ 117 Context: ctx, 118 Msg: msg, 119 } 120 return p.pq.Push(cctx, wmsg, int(priority)) 121 } 122 123 // SendOfferedHashes sends OfferedHashesMsg protocol msg 124 func (p *Peer) SendOfferedHashes(s *server, f, t uint64) error { 125 var sp opentracing.Span 126 ctx, sp := spancontext.StartSpan( 127 context.TODO(), 128 "send.offered.hashes") 129 defer sp.Finish() 130 131 hashes, from, to, proof, err := s.SetNextBatch(f, t) 132 if err != nil { 133 return err 134 } 135 // true only when quiting 136 if len(hashes) == 0 { 137 return nil 138 } 139 if proof == nil { 140 proof = &HandoverProof{ 141 Handover: &Handover{}, 142 } 143 } 144 s.currentBatch = hashes 145 msg := &OfferedHashesMsg{ 146 HandoverProof: proof, 147 Hashes: hashes, 148 From: from, 149 To: to, 150 Stream: s.stream, 151 } 152 log.Trace("Swarm syncer offer batch", "peer", p.ID(), "stream", s.stream, "len", len(hashes), "from", from, "to", to) 153 return p.SendPriority(ctx, msg, s.priority) 154 } 155 156 func (p *Peer) getServer(s Stream) (*server, error) { 157 p.serverMu.RLock() 158 defer p.serverMu.RUnlock() 159 160 server := p.servers[s] 161 if server == nil { 162 return nil, newNotFoundError("server", s) 163 } 164 return server, nil 165 } 166 167 func (p *Peer) setServer(s Stream, o Server, priority uint8) (*server, error) { 168 p.serverMu.Lock() 169 defer p.serverMu.Unlock() 170 171 if p.servers[s] != nil { 172 return nil, fmt.Errorf("server %s already registered", s) 173 } 174 os := &server{ 175 Server: o, 176 stream: s, 177 priority: priority, 178 } 179 p.servers[s] = os 180 return os, nil 181 } 182 183 func (p *Peer) removeServer(s Stream) error { 184 p.serverMu.Lock() 185 defer p.serverMu.Unlock() 186 187 server, ok := p.servers[s] 188 if !ok { 189 return newNotFoundError("server", s) 190 } 191 server.Close() 192 delete(p.servers, s) 193 return nil 194 } 195 196 func (p *Peer) getClient(ctx context.Context, s Stream) (c *client, err error) { 197 var params *clientParams 198 func() { 199 p.clientMu.RLock() 200 defer p.clientMu.RUnlock() 201 202 c = p.clients[s] 203 if c != nil { 204 return 205 } 206 params = p.clientParams[s] 207 }() 208 if c != nil { 209 return c, nil 210 } 211 212 if params != nil { 213 //debug.PrintStack() 214 if err := params.waitClient(ctx); err != nil { 215 return nil, err 216 } 217 } 218 219 p.clientMu.RLock() 220 defer p.clientMu.RUnlock() 221 222 c = p.clients[s] 223 if c != nil { 224 return c, nil 225 } 226 return nil, newNotFoundError("client", s) 227 } 228 229 func (p *Peer) getOrSetClient(s Stream, from, to uint64) (c *client, created bool, err error) { 230 p.clientMu.Lock() 231 defer p.clientMu.Unlock() 232 233 c = p.clients[s] 234 if c != nil { 235 return c, false, nil 236 } 237 238 f, err := p.streamer.GetClientFunc(s.Name) 239 if err != nil { 240 return nil, false, err 241 } 242 243 is, err := f(p, s.Key, s.Live) 244 if err != nil { 245 return nil, false, err 246 } 247 248 cp, err := p.getClientParams(s) 249 if err != nil { 250 return nil, false, err 251 } 252 defer func() { 253 if err == nil { 254 if err := p.removeClientParams(s); err != nil { 255 log.Error("stream set client: remove client params", "stream", s, "peer", p, "err", err) 256 } 257 } 258 }() 259 260 intervalsKey := peerStreamIntervalsKey(p, s) 261 if s.Live { 262 // try to find previous history and live intervals and merge live into history 263 historyKey := peerStreamIntervalsKey(p, NewStream(s.Name, s.Key, false)) 264 historyIntervals := &intervals.Intervals{} 265 err := p.streamer.intervalsStore.Get(historyKey, historyIntervals) 266 switch err { 267 case nil: 268 liveIntervals := &intervals.Intervals{} 269 err := p.streamer.intervalsStore.Get(intervalsKey, liveIntervals) 270 switch err { 271 case nil: 272 historyIntervals.Merge(liveIntervals) 273 if err := p.streamer.intervalsStore.Put(historyKey, historyIntervals); err != nil { 274 log.Error("stream set client: put history intervals", "stream", s, "peer", p, "err", err) 275 } 276 case state.ErrNotFound: 277 default: 278 log.Error("stream set client: get live intervals", "stream", s, "peer", p, "err", err) 279 } 280 case state.ErrNotFound: 281 default: 282 log.Error("stream set client: get history intervals", "stream", s, "peer", p, "err", err) 283 } 284 } 285 286 if err := p.streamer.intervalsStore.Put(intervalsKey, intervals.NewIntervals(from)); err != nil { 287 return nil, false, err 288 } 289 290 next := make(chan error, 1) 291 c = &client{ 292 Client: is, 293 stream: s, 294 priority: cp.priority, 295 to: cp.to, 296 next: next, 297 quit: make(chan struct{}), 298 intervalsStore: p.streamer.intervalsStore, 299 intervalsKey: intervalsKey, 300 } 301 p.clients[s] = c 302 cp.clientCreated() // unblock all possible getClient calls that are waiting 303 next <- nil // this is to allow wantedKeysMsg before first batch arrives 304 return c, true, nil 305 } 306 307 func (p *Peer) removeClient(s Stream) error { 308 p.clientMu.Lock() 309 defer p.clientMu.Unlock() 310 311 client, ok := p.clients[s] 312 if !ok { 313 return newNotFoundError("client", s) 314 } 315 client.close() 316 return nil 317 } 318 319 func (p *Peer) setClientParams(s Stream, params *clientParams) error { 320 p.clientMu.Lock() 321 defer p.clientMu.Unlock() 322 323 if p.clients[s] != nil { 324 return fmt.Errorf("client %s already exists", s) 325 } 326 if p.clientParams[s] != nil { 327 return fmt.Errorf("client params %s already set", s) 328 } 329 p.clientParams[s] = params 330 return nil 331 } 332 333 func (p *Peer) getClientParams(s Stream) (*clientParams, error) { 334 params := p.clientParams[s] 335 if params == nil { 336 return nil, fmt.Errorf("client params '%v' not provided to peer %v", s, p.ID()) 337 } 338 return params, nil 339 } 340 341 func (p *Peer) removeClientParams(s Stream) error { 342 _, ok := p.clientParams[s] 343 if !ok { 344 return newNotFoundError("client params", s) 345 } 346 delete(p.clientParams, s) 347 return nil 348 } 349 350 func (p *Peer) close() { 351 for _, s := range p.servers { 352 s.Close() 353 } 354 }