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