github.com/Ethersocial/go-esn@v0.3.7/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/ethersocial/go-esn/metrics"
    27  	"github.com/ethersocial/go-esn/p2p/protocols"
    28  	"github.com/ethersocial/go-esn/swarm/log"
    29  	pq "github.com/ethersocial/go-esn/swarm/network/priorityqueue"
    30  	"github.com/ethersocial/go-esn/swarm/network/stream/intervals"
    31  	"github.com/ethersocial/go-esn/swarm/spancontext"
    32  	"github.com/ethersocial/go-esn/swarm/state"
    33  	"github.com/ethersocial/go-esn/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 &notFoundError{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  func (p *Peer) Deliver(ctx context.Context, chunk storage.Chunk, priority uint8) error {
   132  	var sp opentracing.Span
   133  	ctx, sp = spancontext.StartSpan(
   134  		ctx,
   135  		"send.chunk.delivery")
   136  	defer sp.Finish()
   137  
   138  	msg := &ChunkDeliveryMsg{
   139  		Addr:  chunk.Address(),
   140  		SData: chunk.Data(),
   141  	}
   142  	return p.SendPriority(ctx, msg, priority)
   143  }
   144  
   145  // SendPriority sends message to the peer using the outgoing priority queue
   146  func (p *Peer) SendPriority(ctx context.Context, msg interface{}, priority uint8) error {
   147  	defer metrics.GetOrRegisterResettingTimer(fmt.Sprintf("peer.sendpriority_t.%d", priority), nil).UpdateSince(time.Now())
   148  	metrics.GetOrRegisterCounter(fmt.Sprintf("peer.sendpriority.%d", priority), nil).Inc(1)
   149  	wmsg := WrappedPriorityMsg{
   150  		Context: ctx,
   151  		Msg:     msg,
   152  	}
   153  	err := p.pq.Push(wmsg, int(priority))
   154  	if err == pq.ErrContention {
   155  		log.Warn("dropping peer on priority queue contention", "peer", p.ID())
   156  		p.Drop(err)
   157  	}
   158  	return err
   159  }
   160  
   161  // SendOfferedHashes sends OfferedHashesMsg protocol msg
   162  func (p *Peer) SendOfferedHashes(s *server, f, t uint64) error {
   163  	var sp opentracing.Span
   164  	ctx, sp := spancontext.StartSpan(
   165  		context.TODO(),
   166  		"send.offered.hashes")
   167  	defer sp.Finish()
   168  
   169  	hashes, from, to, proof, err := s.SetNextBatch(f, t)
   170  	if err != nil {
   171  		return err
   172  	}
   173  	// true only when quitting
   174  	if len(hashes) == 0 {
   175  		return nil
   176  	}
   177  	if proof == nil {
   178  		proof = &HandoverProof{
   179  			Handover: &Handover{},
   180  		}
   181  	}
   182  	s.currentBatch = hashes
   183  	msg := &OfferedHashesMsg{
   184  		HandoverProof: proof,
   185  		Hashes:        hashes,
   186  		From:          from,
   187  		To:            to,
   188  		Stream:        s.stream,
   189  	}
   190  	log.Trace("Swarm syncer offer batch", "peer", p.ID(), "stream", s.stream, "len", len(hashes), "from", from, "to", to)
   191  	return p.SendPriority(ctx, msg, s.priority)
   192  }
   193  
   194  func (p *Peer) getServer(s Stream) (*server, error) {
   195  	p.serverMu.RLock()
   196  	defer p.serverMu.RUnlock()
   197  
   198  	server := p.servers[s]
   199  	if server == nil {
   200  		return nil, newNotFoundError("server", s)
   201  	}
   202  	return server, nil
   203  }
   204  
   205  func (p *Peer) setServer(s Stream, o Server, priority uint8) (*server, error) {
   206  	p.serverMu.Lock()
   207  	defer p.serverMu.Unlock()
   208  
   209  	if p.servers[s] != nil {
   210  		return nil, fmt.Errorf("server %s already registered", s)
   211  	}
   212  
   213  	if p.streamer.maxPeerServers > 0 && len(p.servers) >= p.streamer.maxPeerServers {
   214  		return nil, ErrMaxPeerServers
   215  	}
   216  
   217  	os := &server{
   218  		Server:   o,
   219  		stream:   s,
   220  		priority: priority,
   221  	}
   222  	p.servers[s] = os
   223  	return os, nil
   224  }
   225  
   226  func (p *Peer) removeServer(s Stream) error {
   227  	p.serverMu.Lock()
   228  	defer p.serverMu.Unlock()
   229  
   230  	server, ok := p.servers[s]
   231  	if !ok {
   232  		return newNotFoundError("server", s)
   233  	}
   234  	server.Close()
   235  	delete(p.servers, s)
   236  	return nil
   237  }
   238  
   239  func (p *Peer) getClient(ctx context.Context, s Stream) (c *client, err error) {
   240  	var params *clientParams
   241  	func() {
   242  		p.clientMu.RLock()
   243  		defer p.clientMu.RUnlock()
   244  
   245  		c = p.clients[s]
   246  		if c != nil {
   247  			return
   248  		}
   249  		params = p.clientParams[s]
   250  	}()
   251  	if c != nil {
   252  		return c, nil
   253  	}
   254  
   255  	if params != nil {
   256  		//debug.PrintStack()
   257  		if err := params.waitClient(ctx); err != nil {
   258  			return nil, err
   259  		}
   260  	}
   261  
   262  	p.clientMu.RLock()
   263  	defer p.clientMu.RUnlock()
   264  
   265  	c = p.clients[s]
   266  	if c != nil {
   267  		return c, nil
   268  	}
   269  	return nil, newNotFoundError("client", s)
   270  }
   271  
   272  func (p *Peer) getOrSetClient(s Stream, from, to uint64) (c *client, created bool, err error) {
   273  	p.clientMu.Lock()
   274  	defer p.clientMu.Unlock()
   275  
   276  	c = p.clients[s]
   277  	if c != nil {
   278  		return c, false, nil
   279  	}
   280  
   281  	f, err := p.streamer.GetClientFunc(s.Name)
   282  	if err != nil {
   283  		return nil, false, err
   284  	}
   285  
   286  	is, err := f(p, s.Key, s.Live)
   287  	if err != nil {
   288  		return nil, false, err
   289  	}
   290  
   291  	cp, err := p.getClientParams(s)
   292  	if err != nil {
   293  		return nil, false, err
   294  	}
   295  	defer func() {
   296  		if err == nil {
   297  			if err := p.removeClientParams(s); err != nil {
   298  				log.Error("stream set client: remove client params", "stream", s, "peer", p, "err", err)
   299  			}
   300  		}
   301  	}()
   302  
   303  	intervalsKey := peerStreamIntervalsKey(p, s)
   304  	if s.Live {
   305  		// try to find previous history and live intervals and merge live into history
   306  		historyKey := peerStreamIntervalsKey(p, NewStream(s.Name, s.Key, false))
   307  		historyIntervals := &intervals.Intervals{}
   308  		err := p.streamer.intervalsStore.Get(historyKey, historyIntervals)
   309  		switch err {
   310  		case nil:
   311  			liveIntervals := &intervals.Intervals{}
   312  			err := p.streamer.intervalsStore.Get(intervalsKey, liveIntervals)
   313  			switch err {
   314  			case nil:
   315  				historyIntervals.Merge(liveIntervals)
   316  				if err := p.streamer.intervalsStore.Put(historyKey, historyIntervals); err != nil {
   317  					log.Error("stream set client: put history intervals", "stream", s, "peer", p, "err", err)
   318  				}
   319  			case state.ErrNotFound:
   320  			default:
   321  				log.Error("stream set client: get live intervals", "stream", s, "peer", p, "err", err)
   322  			}
   323  		case state.ErrNotFound:
   324  		default:
   325  			log.Error("stream set client: get history intervals", "stream", s, "peer", p, "err", err)
   326  		}
   327  	}
   328  
   329  	if err := p.streamer.intervalsStore.Put(intervalsKey, intervals.NewIntervals(from)); err != nil {
   330  		return nil, false, err
   331  	}
   332  
   333  	next := make(chan error, 1)
   334  	c = &client{
   335  		Client:         is,
   336  		stream:         s,
   337  		priority:       cp.priority,
   338  		to:             cp.to,
   339  		next:           next,
   340  		quit:           make(chan struct{}),
   341  		intervalsStore: p.streamer.intervalsStore,
   342  		intervalsKey:   intervalsKey,
   343  	}
   344  	p.clients[s] = c
   345  	cp.clientCreated() // unblock all possible getClient calls that are waiting
   346  	next <- nil        // this is to allow wantedKeysMsg before first batch arrives
   347  	return c, true, nil
   348  }
   349  
   350  func (p *Peer) removeClient(s Stream) error {
   351  	p.clientMu.Lock()
   352  	defer p.clientMu.Unlock()
   353  
   354  	client, ok := p.clients[s]
   355  	if !ok {
   356  		return newNotFoundError("client", s)
   357  	}
   358  	client.close()
   359  	delete(p.clients, s)
   360  	return nil
   361  }
   362  
   363  func (p *Peer) setClientParams(s Stream, params *clientParams) error {
   364  	p.clientMu.Lock()
   365  	defer p.clientMu.Unlock()
   366  
   367  	if p.clients[s] != nil {
   368  		return fmt.Errorf("client %s already exists", s)
   369  	}
   370  	if p.clientParams[s] != nil {
   371  		return fmt.Errorf("client params %s already set", s)
   372  	}
   373  	p.clientParams[s] = params
   374  	return nil
   375  }
   376  
   377  func (p *Peer) getClientParams(s Stream) (*clientParams, error) {
   378  	params := p.clientParams[s]
   379  	if params == nil {
   380  		return nil, fmt.Errorf("client params '%v' not provided to peer %v", s, p.ID())
   381  	}
   382  	return params, nil
   383  }
   384  
   385  func (p *Peer) removeClientParams(s Stream) error {
   386  	_, ok := p.clientParams[s]
   387  	if !ok {
   388  		return newNotFoundError("client params", s)
   389  	}
   390  	delete(p.clientParams, s)
   391  	return nil
   392  }
   393  
   394  func (p *Peer) close() {
   395  	for _, s := range p.servers {
   396  		s.Close()
   397  	}
   398  }