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  }