github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/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 "errors" 22 "fmt" 23 "sync" 24 "time" 25 26 "github.com/ShyftNetwork/go-empyrean/metrics" 27 "github.com/ShyftNetwork/go-empyrean/p2p/protocols" 28 "github.com/ShyftNetwork/go-empyrean/swarm/log" 29 pq "github.com/ShyftNetwork/go-empyrean/swarm/network/priorityqueue" 30 "github.com/ShyftNetwork/go-empyrean/swarm/network/stream/intervals" 31 "github.com/ShyftNetwork/go-empyrean/swarm/spancontext" 32 "github.com/ShyftNetwork/go-empyrean/swarm/state" 33 "github.com/ShyftNetwork/go-empyrean/swarm/storage" 34 opentracing "github.com/opentracing/opentracing-go" 35 ) 36 37 type notFoundError struct { 38 t string 39 s Stream 40 } 41 42 func newNotFoundError(t string, s Stream) *notFoundError { 43 return ¬FoundError{t: t, s: s} 44 } 45 46 func (e *notFoundError) Error() string { 47 return fmt.Sprintf("%s not found for stream %q", e.t, e.s) 48 } 49 50 // ErrMaxPeerServers will be returned if peer server limit is reached. 51 // It will be sent in the SubscribeErrorMsg. 52 var ErrMaxPeerServers = errors.New("max peer servers") 53 54 // Peer is the Peer extension for the streaming protocol 55 type Peer struct { 56 *protocols.Peer 57 streamer *Registry 58 pq *pq.PriorityQueue 59 serverMu sync.RWMutex 60 clientMu sync.RWMutex // protects both clients and clientParams 61 servers map[Stream]*server 62 clients map[Stream]*client 63 // clientParams map keeps required client arguments 64 // that are set on Registry.Subscribe and used 65 // on creating a new client in offered hashes handler. 66 clientParams map[Stream]*clientParams 67 quit chan struct{} 68 } 69 70 type WrappedPriorityMsg struct { 71 Context context.Context 72 Msg interface{} 73 } 74 75 // NewPeer is the constructor for Peer 76 func NewPeer(peer *protocols.Peer, streamer *Registry) *Peer { 77 p := &Peer{ 78 Peer: peer, 79 pq: pq.New(int(PriorityQueue), PriorityQueueCap), 80 streamer: streamer, 81 servers: make(map[Stream]*server), 82 clients: make(map[Stream]*client), 83 clientParams: make(map[Stream]*clientParams), 84 quit: make(chan struct{}), 85 } 86 ctx, cancel := context.WithCancel(context.Background()) 87 go p.pq.Run(ctx, func(i interface{}) { 88 wmsg := i.(WrappedPriorityMsg) 89 err := p.Send(wmsg.Context, wmsg.Msg) 90 if err != nil { 91 log.Error("Message send error, dropping peer", "peer", p.ID(), "err", err) 92 p.Drop(err) 93 } 94 }) 95 96 // basic monitoring for pq contention 97 go func(pq *pq.PriorityQueue) { 98 ticker := time.NewTicker(5 * time.Second) 99 defer ticker.Stop() 100 for { 101 select { 102 case <-ticker.C: 103 var len_maxi int 104 var cap_maxi int 105 for k := range pq.Queues { 106 if len_maxi < len(pq.Queues[k]) { 107 len_maxi = len(pq.Queues[k]) 108 } 109 110 if cap_maxi < cap(pq.Queues[k]) { 111 cap_maxi = cap(pq.Queues[k]) 112 } 113 } 114 115 metrics.GetOrRegisterGauge(fmt.Sprintf("pq_len_%s", p.ID().TerminalString()), nil).Update(int64(len_maxi)) 116 metrics.GetOrRegisterGauge(fmt.Sprintf("pq_cap_%s", p.ID().TerminalString()), nil).Update(int64(cap_maxi)) 117 case <-p.quit: 118 return 119 } 120 } 121 }(p.pq) 122 123 go func() { 124 <-p.quit 125 cancel() 126 }() 127 return p 128 } 129 130 // Deliver sends a storeRequestMsg protocol message to the peer 131 // Depending on the `syncing` parameter we send different message types 132 func (p *Peer) Deliver(ctx context.Context, chunk storage.Chunk, priority uint8, syncing bool) error { 133 var sp opentracing.Span 134 var msg interface{} 135 136 spanName := "send.chunk.delivery" 137 138 //we send different types of messages if delivery is for syncing or retrievals, 139 //even if handling and content of the message are the same, 140 //because swap accounting decides which messages need accounting based on the message type 141 if syncing { 142 msg = &ChunkDeliveryMsgSyncing{ 143 Addr: chunk.Address(), 144 SData: chunk.Data(), 145 } 146 spanName += ".syncing" 147 } else { 148 msg = &ChunkDeliveryMsgRetrieval{ 149 Addr: chunk.Address(), 150 SData: chunk.Data(), 151 } 152 spanName += ".retrieval" 153 } 154 ctx, sp = spancontext.StartSpan( 155 ctx, 156 spanName) 157 defer sp.Finish() 158 159 return p.SendPriority(ctx, msg, priority) 160 } 161 162 // SendPriority sends message to the peer using the outgoing priority queue 163 func (p *Peer) SendPriority(ctx context.Context, msg interface{}, priority uint8) error { 164 defer metrics.GetOrRegisterResettingTimer(fmt.Sprintf("peer.sendpriority_t.%d", priority), nil).UpdateSince(time.Now()) 165 metrics.GetOrRegisterCounter(fmt.Sprintf("peer.sendpriority.%d", priority), nil).Inc(1) 166 wmsg := WrappedPriorityMsg{ 167 Context: ctx, 168 Msg: msg, 169 } 170 err := p.pq.Push(wmsg, int(priority)) 171 if err == pq.ErrContention { 172 log.Warn("dropping peer on priority queue contention", "peer", p.ID()) 173 p.Drop(err) 174 } 175 return err 176 } 177 178 // SendOfferedHashes sends OfferedHashesMsg protocol msg 179 func (p *Peer) SendOfferedHashes(s *server, f, t uint64) error { 180 var sp opentracing.Span 181 ctx, sp := spancontext.StartSpan( 182 context.TODO(), 183 "send.offered.hashes") 184 defer sp.Finish() 185 186 hashes, from, to, proof, err := s.setNextBatch(f, t) 187 if err != nil { 188 return err 189 } 190 // true only when quitting 191 if len(hashes) == 0 { 192 return nil 193 } 194 if proof == nil { 195 proof = &HandoverProof{ 196 Handover: &Handover{}, 197 } 198 } 199 s.currentBatch = hashes 200 msg := &OfferedHashesMsg{ 201 HandoverProof: proof, 202 Hashes: hashes, 203 From: from, 204 To: to, 205 Stream: s.stream, 206 } 207 log.Trace("Swarm syncer offer batch", "peer", p.ID(), "stream", s.stream, "len", len(hashes), "from", from, "to", to) 208 return p.SendPriority(ctx, msg, s.priority) 209 } 210 211 func (p *Peer) getServer(s Stream) (*server, error) { 212 p.serverMu.RLock() 213 defer p.serverMu.RUnlock() 214 215 server := p.servers[s] 216 if server == nil { 217 return nil, newNotFoundError("server", s) 218 } 219 return server, nil 220 } 221 222 func (p *Peer) setServer(s Stream, o Server, priority uint8) (*server, error) { 223 p.serverMu.Lock() 224 defer p.serverMu.Unlock() 225 226 if p.servers[s] != nil { 227 return nil, fmt.Errorf("server %s already registered", s) 228 } 229 230 if p.streamer.maxPeerServers > 0 && len(p.servers) >= p.streamer.maxPeerServers { 231 return nil, ErrMaxPeerServers 232 } 233 234 sessionIndex, err := o.SessionIndex() 235 if err != nil { 236 return nil, err 237 } 238 os := &server{ 239 Server: o, 240 stream: s, 241 priority: priority, 242 sessionIndex: sessionIndex, 243 } 244 p.servers[s] = os 245 return os, nil 246 } 247 248 func (p *Peer) removeServer(s Stream) error { 249 p.serverMu.Lock() 250 defer p.serverMu.Unlock() 251 252 server, ok := p.servers[s] 253 if !ok { 254 return newNotFoundError("server", s) 255 } 256 server.Close() 257 delete(p.servers, s) 258 return nil 259 } 260 261 func (p *Peer) getClient(ctx context.Context, s Stream) (c *client, err error) { 262 var params *clientParams 263 func() { 264 p.clientMu.RLock() 265 defer p.clientMu.RUnlock() 266 267 c = p.clients[s] 268 if c != nil { 269 return 270 } 271 params = p.clientParams[s] 272 }() 273 if c != nil { 274 return c, nil 275 } 276 277 if params != nil { 278 //debug.PrintStack() 279 if err := params.waitClient(ctx); err != nil { 280 return nil, err 281 } 282 } 283 284 p.clientMu.RLock() 285 defer p.clientMu.RUnlock() 286 287 c = p.clients[s] 288 if c != nil { 289 return c, nil 290 } 291 return nil, newNotFoundError("client", s) 292 } 293 294 func (p *Peer) getOrSetClient(s Stream, from, to uint64) (c *client, created bool, err error) { 295 p.clientMu.Lock() 296 defer p.clientMu.Unlock() 297 298 c = p.clients[s] 299 if c != nil { 300 return c, false, nil 301 } 302 303 f, err := p.streamer.GetClientFunc(s.Name) 304 if err != nil { 305 return nil, false, err 306 } 307 308 is, err := f(p, s.Key, s.Live) 309 if err != nil { 310 return nil, false, err 311 } 312 313 cp, err := p.getClientParams(s) 314 if err != nil { 315 return nil, false, err 316 } 317 defer func() { 318 if err == nil { 319 if err := p.removeClientParams(s); err != nil { 320 log.Error("stream set client: remove client params", "stream", s, "peer", p, "err", err) 321 } 322 } 323 }() 324 325 intervalsKey := peerStreamIntervalsKey(p, s) 326 if s.Live { 327 // try to find previous history and live intervals and merge live into history 328 historyKey := peerStreamIntervalsKey(p, NewStream(s.Name, s.Key, false)) 329 historyIntervals := &intervals.Intervals{} 330 err := p.streamer.intervalsStore.Get(historyKey, historyIntervals) 331 switch err { 332 case nil: 333 liveIntervals := &intervals.Intervals{} 334 err := p.streamer.intervalsStore.Get(intervalsKey, liveIntervals) 335 switch err { 336 case nil: 337 historyIntervals.Merge(liveIntervals) 338 if err := p.streamer.intervalsStore.Put(historyKey, historyIntervals); err != nil { 339 log.Error("stream set client: put history intervals", "stream", s, "peer", p, "err", err) 340 } 341 case state.ErrNotFound: 342 default: 343 log.Error("stream set client: get live intervals", "stream", s, "peer", p, "err", err) 344 } 345 case state.ErrNotFound: 346 default: 347 log.Error("stream set client: get history intervals", "stream", s, "peer", p, "err", err) 348 } 349 } 350 351 if err := p.streamer.intervalsStore.Put(intervalsKey, intervals.NewIntervals(from)); err != nil { 352 return nil, false, err 353 } 354 355 next := make(chan error, 1) 356 c = &client{ 357 Client: is, 358 stream: s, 359 priority: cp.priority, 360 to: cp.to, 361 next: next, 362 quit: make(chan struct{}), 363 intervalsStore: p.streamer.intervalsStore, 364 intervalsKey: intervalsKey, 365 } 366 p.clients[s] = c 367 cp.clientCreated() // unblock all possible getClient calls that are waiting 368 next <- nil // this is to allow wantedKeysMsg before first batch arrives 369 return c, true, nil 370 } 371 372 func (p *Peer) removeClient(s Stream) error { 373 p.clientMu.Lock() 374 defer p.clientMu.Unlock() 375 376 client, ok := p.clients[s] 377 if !ok { 378 return newNotFoundError("client", s) 379 } 380 client.close() 381 delete(p.clients, s) 382 return nil 383 } 384 385 func (p *Peer) setClientParams(s Stream, params *clientParams) error { 386 p.clientMu.Lock() 387 defer p.clientMu.Unlock() 388 389 if p.clients[s] != nil { 390 return fmt.Errorf("client %s already exists", s) 391 } 392 if p.clientParams[s] != nil { 393 return fmt.Errorf("client params %s already set", s) 394 } 395 p.clientParams[s] = params 396 return nil 397 } 398 399 func (p *Peer) getClientParams(s Stream) (*clientParams, error) { 400 params := p.clientParams[s] 401 if params == nil { 402 return nil, fmt.Errorf("client params '%v' not provided to peer %v", s, p.ID()) 403 } 404 return params, nil 405 } 406 407 func (p *Peer) removeClientParams(s Stream) error { 408 _, ok := p.clientParams[s] 409 if !ok { 410 return newNotFoundError("client params", s) 411 } 412 delete(p.clientParams, s) 413 return nil 414 } 415 416 func (p *Peer) close() { 417 for _, s := range p.servers { 418 s.Close() 419 } 420 }