github.com/turingchain2020/turingchain@v1.1.21/system/p2p/dht/protocol/download/handler.go (about) 1 package download 2 3 import ( 4 "fmt" 5 "sync" 6 "sync/atomic" 7 "time" 8 9 "github.com/turingchain2020/turingchain/queue" 10 "github.com/turingchain2020/turingchain/system/p2p/dht/protocol" 11 "github.com/turingchain2020/turingchain/types" 12 "github.com/google/uuid" 13 "github.com/libp2p/go-libp2p-core/network" 14 ) 15 16 func (p *Protocol) handleStreamDownloadBlock(stream network.Stream) { 17 var req types.ReqBlocks 18 err := protocol.ReadStream(&req, stream) 19 if err != nil { 20 log.Error("Handle", "err", err) 21 return 22 } 23 //允许下载的最大高度区间为256 24 if req.End-req.Start > 256 || req.End < req.Start { 25 log.Error("handleStreamDownloadBlock", "error", "wrong parameter") 26 return 27 } 28 29 msg := p.QueueClient.NewMessage("blockchain", types.EventGetBlocks, &req) 30 err = p.QueueClient.Send(msg, true) 31 if err != nil { 32 return 33 } 34 reply, err := p.QueueClient.WaitTimeout(msg, time.Second*3) 35 if err != nil { 36 return 37 } 38 blocks := reply.Data.(*types.BlockDetails) 39 if len(blocks.Items) == 0 { 40 return 41 } 42 block := blocks.Items[0].Block 43 err = protocol.WriteStream(block, stream) 44 if err != nil { 45 log.Error("WriteStream", "error", err, "remote pid", stream.Conn().RemotePeer().String()) 46 return 47 } 48 log.Debug("handleStreamDownloadBlock", "block height", block.GetHeight(), "remote peer", stream.Conn().RemotePeer().String()) 49 } 50 51 func (p *Protocol) handleStreamDownloadBlockOld(stream network.Stream) { 52 var data types.MessageGetBlocksReq 53 err := protocol.ReadStream(&data, stream) 54 if err != nil { 55 log.Error("Handle", "err", err) 56 return 57 } 58 req := types.ReqBlocks{ 59 Start: data.Message.StartHeight, 60 End: data.Message.EndHeight, 61 } 62 //允许下载的最大高度区间为256 63 if req.End-req.Start > 256 || req.End < req.Start { 64 log.Error("handleStreamDownloadBlock", "error", "wrong parameter") 65 return 66 } 67 68 msg := p.QueueClient.NewMessage("blockchain", types.EventGetBlocks, &req) 69 err = p.QueueClient.Send(msg, true) 70 if err != nil { 71 return 72 } 73 reply, err := p.QueueClient.WaitTimeout(msg, time.Second*3) 74 if err != nil { 75 return 76 } 77 blocks := reply.Data.(*types.BlockDetails) 78 if len(blocks.Items) == 0 { 79 log.Error("handleStreamDownloadBlockOld", "error", "block not found") 80 return 81 } 82 var resp types.MessageGetBlocksResp 83 var list []*types.InvData 84 for _, blockDetail := range blocks.Items { 85 list = append(list, &types.InvData{ 86 Ty: 2, 87 Value: &types.InvData_Block{ 88 Block: blockDetail.Block, 89 }, 90 }) 91 } 92 resp.Message = &types.InvDatas{ 93 Items: list, 94 } 95 err = protocol.WriteStream(&resp, stream) 96 if err != nil { 97 log.Error("WriteStream", "error", err, "remote pid", stream.Conn().RemotePeer().String()) 98 return 99 } 100 } 101 102 func (p *Protocol) handleEventDownloadBlock(msg *queue.Message) { 103 req := msg.GetData().(*types.ReqBlocks) 104 if req.GetStart() > req.GetEnd() { 105 log.Error("handleEventDownloadBlock", "download start", req.GetStart(), "download end", req.GetEnd()) 106 msg.Reply(p.QueueClient.NewMessage("blockchain", types.EventReply, types.Reply{Msg: []byte("start>end")})) 107 return 108 } 109 pids := req.GetPid() 110 if len(pids) == 0 { //根据指定的pidlist 获取对应的block header 111 log.Debug("GetBlocks:pid is nil") 112 msg.Reply(p.QueueClient.NewMessage("blockchain", types.EventReply, types.Reply{Msg: []byte("no pid")})) 113 return 114 } 115 116 msg.Reply(p.QueueClient.NewMessage("blockchain", types.EventReply, types.Reply{IsOk: true, Msg: []byte("ok")})) 117 var taskID = uuid.New().String() + "+" + fmt.Sprintf("%d-%d", req.GetStart(), req.GetEnd()) 118 119 log.Debug("handleEventDownloadBlock", "taskID", taskID, "download start", req.GetStart(), "download end", req.GetEnd(), "pids", pids) 120 121 //具体的下载逻辑 122 jobS := p.initJob(pids, taskID) 123 log.Debug("handleEventDownloadBlock", "jobs", jobS) 124 var wg sync.WaitGroup 125 var mutex sync.Mutex 126 var maxGoroutine int32 127 var reDownload = make(map[string]interface{}) 128 var startTime = time.Now().UnixNano() 129 130 for height := req.GetStart(); height <= req.GetEnd(); height++ { 131 wg.Add(1) 132 Wait: 133 if atomic.LoadInt32(&maxGoroutine) > 50 { 134 time.Sleep(time.Millisecond * 200) 135 goto Wait 136 } 137 atomic.AddInt32(&maxGoroutine, 1) 138 go func(blockheight int64, tasks tasks) { 139 err := p.downloadBlock(blockheight, tasks) 140 if err != nil { 141 mutex.Lock() 142 defer mutex.Unlock() 143 144 if err == p.Ctx.Err() { 145 log.Error("syncDownloadBlock", "err", err.Error()) 146 return 147 } 148 149 log.Error("syncDownloadBlock", "downloadBlock err", err.Error()) 150 v, ok := reDownload[taskID] 151 if ok { 152 failedJob := v.(map[int64]bool) 153 failedJob[blockheight] = false 154 reDownload[taskID] = failedJob 155 156 } else { 157 var failedJob = make(map[int64]bool) 158 failedJob[blockheight] = false 159 reDownload[taskID] = failedJob 160 161 } 162 } 163 wg.Done() 164 atomic.AddInt32(&maxGoroutine, -1) 165 166 }(height, jobS) 167 168 } 169 170 wg.Wait() 171 p.checkTask(taskID, pids, reDownload) 172 log.Debug("Download Job Complete!", "TaskID++++++++++++++", taskID, 173 "cost time", fmt.Sprintf("cost time:%d ms", (time.Now().UnixNano()-startTime)/1e6), 174 "from", pids) 175 176 }