github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/network/stream/delivery.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:48</date>
    10  //</624342675159519232>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  package stream
    29  
    30  import (
    31  	"context"
    32  	"errors"
    33  	"time"
    34  
    35  	"github.com/ethereum/go-ethereum/common"
    36  	"github.com/ethereum/go-ethereum/metrics"
    37  	"github.com/ethereum/go-ethereum/p2p/discover"
    38  	cp "github.com/ethereum/go-ethereum/swarm/chunk"
    39  	"github.com/ethereum/go-ethereum/swarm/log"
    40  	"github.com/ethereum/go-ethereum/swarm/network"
    41  	"github.com/ethereum/go-ethereum/swarm/spancontext"
    42  	"github.com/ethereum/go-ethereum/swarm/storage"
    43  	opentracing "github.com/opentracing/opentracing-go"
    44  )
    45  
    46  const (
    47  	swarmChunkServerStreamName = "RETRIEVE_REQUEST"
    48  	deliveryCap                = 32
    49  )
    50  
    51  var (
    52  	processReceivedChunksCount    = metrics.NewRegisteredCounter("network.stream.received_chunks.count", nil)
    53  	handleRetrieveRequestMsgCount = metrics.NewRegisteredCounter("network.stream.handle_retrieve_request_msg.count", nil)
    54  
    55  	requestFromPeersCount     = metrics.NewRegisteredCounter("network.stream.request_from_peers.count", nil)
    56  	requestFromPeersEachCount = metrics.NewRegisteredCounter("network.stream.request_from_peers_each.count", nil)
    57  )
    58  
    59  type Delivery struct {
    60  	db       *storage.DBAPI
    61  	overlay  network.Overlay
    62  	receiveC chan *ChunkDeliveryMsg
    63  	getPeer  func(discover.NodeID) *Peer
    64  }
    65  
    66  func NewDelivery(overlay network.Overlay, db *storage.DBAPI) *Delivery {
    67  	d := &Delivery{
    68  		db:       db,
    69  		overlay:  overlay,
    70  		receiveC: make(chan *ChunkDeliveryMsg, deliveryCap),
    71  	}
    72  
    73  	go d.processReceivedChunks()
    74  	return d
    75  }
    76  
    77  //
    78  type SwarmChunkServer struct {
    79  	deliveryC  chan []byte
    80  	batchC     chan []byte
    81  	db         *storage.DBAPI
    82  	currentLen uint64
    83  	quit       chan struct{}
    84  }
    85  
    86  //
    87  func NewSwarmChunkServer(db *storage.DBAPI) *SwarmChunkServer {
    88  	s := &SwarmChunkServer{
    89  		deliveryC: make(chan []byte, deliveryCap),
    90  		batchC:    make(chan []byte),
    91  		db:        db,
    92  		quit:      make(chan struct{}),
    93  	}
    94  	go s.processDeliveries()
    95  	return s
    96  }
    97  
    98  //
    99  func (s *SwarmChunkServer) processDeliveries() {
   100  	var hashes []byte
   101  	var batchC chan []byte
   102  	for {
   103  		select {
   104  		case <-s.quit:
   105  			return
   106  		case hash := <-s.deliveryC:
   107  			hashes = append(hashes, hash...)
   108  			batchC = s.batchC
   109  		case batchC <- hashes:
   110  			hashes = nil
   111  			batchC = nil
   112  		}
   113  	}
   114  }
   115  
   116  //
   117  func (s *SwarmChunkServer) SetNextBatch(_, _ uint64) (hashes []byte, from uint64, to uint64, proof *HandoverProof, err error) {
   118  	select {
   119  	case hashes = <-s.batchC:
   120  	case <-s.quit:
   121  		return
   122  	}
   123  
   124  	from = s.currentLen
   125  	s.currentLen += uint64(len(hashes))
   126  	to = s.currentLen
   127  	return
   128  }
   129  
   130  //
   131  func (s *SwarmChunkServer) Close() {
   132  	close(s.quit)
   133  }
   134  
   135  //
   136  func (s *SwarmChunkServer) GetData(ctx context.Context, key []byte) ([]byte, error) {
   137  	chunk, err := s.db.Get(ctx, storage.Address(key))
   138  	if err == storage.ErrFetching {
   139  		<-chunk.ReqC
   140  	} else if err != nil {
   141  		return nil, err
   142  	}
   143  	return chunk.SData, nil
   144  }
   145  
   146  //
   147  type RetrieveRequestMsg struct {
   148  	Addr      storage.Address
   149  	SkipCheck bool
   150  }
   151  
   152  func (d *Delivery) handleRetrieveRequestMsg(ctx context.Context, sp *Peer, req *RetrieveRequestMsg) error {
   153  	log.Trace("received request", "peer", sp.ID(), "hash", req.Addr)
   154  	handleRetrieveRequestMsgCount.Inc(1)
   155  
   156  	var osp opentracing.Span
   157  	ctx, osp = spancontext.StartSpan(
   158  		ctx,
   159  		"retrieve.request")
   160  	defer osp.Finish()
   161  
   162  	s, err := sp.getServer(NewStream(swarmChunkServerStreamName, "", false))
   163  	if err != nil {
   164  		return err
   165  	}
   166  	streamer := s.Server.(*SwarmChunkServer)
   167  	chunk, created := d.db.GetOrCreateRequest(ctx, req.Addr)
   168  	if chunk.ReqC != nil {
   169  		if created {
   170  			if err := d.RequestFromPeers(ctx, chunk.Addr[:], true, sp.ID()); err != nil {
   171  				log.Warn("unable to forward chunk request", "peer", sp.ID(), "key", chunk.Addr, "err", err)
   172  				chunk.SetErrored(storage.ErrChunkForward)
   173  				return nil
   174  			}
   175  		}
   176  		go func() {
   177  			var osp opentracing.Span
   178  			ctx, osp = spancontext.StartSpan(
   179  				ctx,
   180  				"waiting.delivery")
   181  			defer osp.Finish()
   182  
   183  			t := time.NewTimer(10 * time.Minute)
   184  			defer t.Stop()
   185  
   186  			log.Debug("waiting delivery", "peer", sp.ID(), "hash", req.Addr, "node", common.Bytes2Hex(d.overlay.BaseAddr()), "created", created)
   187  			start := time.Now()
   188  			select {
   189  			case <-chunk.ReqC:
   190  				log.Debug("retrieve request ReqC closed", "peer", sp.ID(), "hash", req.Addr, "time", time.Since(start))
   191  			case <-t.C:
   192  				log.Debug("retrieve request timeout", "peer", sp.ID(), "hash", req.Addr)
   193  				chunk.SetErrored(storage.ErrChunkTimeout)
   194  				return
   195  			}
   196  			chunk.SetErrored(nil)
   197  
   198  			if req.SkipCheck {
   199  				err := sp.Deliver(ctx, chunk, s.priority)
   200  				if err != nil {
   201  					log.Warn("ERROR in handleRetrieveRequestMsg, DROPPING peer!", "err", err)
   202  					sp.Drop(err)
   203  				}
   204  			}
   205  			streamer.deliveryC <- chunk.Addr[:]
   206  		}()
   207  		return nil
   208  	}
   209  //
   210  	if req.SkipCheck {
   211  		log.Trace("deliver", "peer", sp.ID(), "hash", chunk.Addr)
   212  		if length := len(chunk.SData); length < 9 {
   213  			log.Error("Chunk.SData to deliver is too short", "len(chunk.SData)", length, "address", chunk.Addr)
   214  		}
   215  		return sp.Deliver(ctx, chunk, s.priority)
   216  	}
   217  	streamer.deliveryC <- chunk.Addr[:]
   218  	return nil
   219  }
   220  
   221  type ChunkDeliveryMsg struct {
   222  	Addr  storage.Address
   223  SData []byte //
   224  peer  *Peer  //
   225  }
   226  
   227  func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req *ChunkDeliveryMsg) error {
   228  	var osp opentracing.Span
   229  	ctx, osp = spancontext.StartSpan(
   230  		ctx,
   231  		"chunk.delivery")
   232  	defer osp.Finish()
   233  
   234  	req.peer = sp
   235  	d.receiveC <- req
   236  	return nil
   237  }
   238  
   239  func (d *Delivery) processReceivedChunks() {
   240  R:
   241  	for req := range d.receiveC {
   242  		processReceivedChunksCount.Inc(1)
   243  
   244  		if len(req.SData) > cp.DefaultSize+8 {
   245  			log.Warn("received chunk is bigger than expected", "len", len(req.SData))
   246  			continue R
   247  		}
   248  
   249  //
   250  		chunk, err := d.db.Get(context.TODO(), req.Addr)
   251  		if err == nil {
   252  			continue R
   253  		}
   254  		if err != storage.ErrFetching {
   255  			log.Error("processReceivedChunks db error", "addr", req.Addr, "err", err, "chunk", chunk)
   256  			continue R
   257  		}
   258  		select {
   259  		case <-chunk.ReqC:
   260  			log.Error("someone else delivered?", "hash", chunk.Addr.Hex())
   261  			continue R
   262  		default:
   263  		}
   264  
   265  		chunk.SData = req.SData
   266  		d.db.Put(context.TODO(), chunk)
   267  
   268  		go func(req *ChunkDeliveryMsg) {
   269  			err := chunk.WaitToStore()
   270  			if err == storage.ErrChunkInvalid {
   271  				req.peer.Drop(err)
   272  			}
   273  		}(req)
   274  	}
   275  }
   276  
   277  //
   278  func (d *Delivery) RequestFromPeers(ctx context.Context, hash []byte, skipCheck bool, peersToSkip ...discover.NodeID) error {
   279  	var success bool
   280  	var err error
   281  	requestFromPeersCount.Inc(1)
   282  
   283  	d.overlay.EachConn(hash, 255, func(p network.OverlayConn, po int, nn bool) bool {
   284  		spId := p.(network.Peer).ID()
   285  		for _, p := range peersToSkip {
   286  			if p == spId {
   287  				log.Trace("Delivery.RequestFromPeers: skip peer", "peer", spId)
   288  				return true
   289  			}
   290  		}
   291  		sp := d.getPeer(spId)
   292  		if sp == nil {
   293  			log.Warn("Delivery.RequestFromPeers: peer not found", "id", spId)
   294  			return true
   295  		}
   296  		err = sp.SendPriority(ctx, &RetrieveRequestMsg{
   297  			Addr:      hash,
   298  			SkipCheck: skipCheck,
   299  		}, Top)
   300  		if err != nil {
   301  			return true
   302  		}
   303  		requestFromPeersEachCount.Inc(1)
   304  		success = true
   305  		return false
   306  	})
   307  	if success {
   308  		return nil
   309  	}
   310  	return errors.New("no peer found")
   311  }
   312