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