github.com/fzfile/BaiduPCS-Go@v0.0.0-20200606205115-4408961cf336/requester/uploader/multiworker.go (about) 1 package uploader 2 3 import ( 4 "context" 5 "github.com/fzfile/BaiduPCS-Go/pcsutil/waitgroup" 6 "github.com/oleiade/lane" 7 "os" 8 ) 9 10 type ( 11 worker struct { 12 id int 13 partOffset int64 14 splitUnit SplitUnit 15 checksum string 16 } 17 18 workerList []*worker 19 ) 20 21 // CheckSumList 返回所以worker的checksum 22 // TODO: 实现sort 23 func (werl *workerList) CheckSumList() []string { 24 checksumList := make([]string, 0, len(*werl)) 25 for _, wer := range *werl { 26 checksumList = append(checksumList, wer.checksum) 27 } 28 return checksumList 29 } 30 31 func (werl *workerList) Readed() int64 { 32 var readed int64 33 for _, wer := range *werl { 34 readed += wer.splitUnit.Readed() 35 } 36 return readed 37 } 38 39 func (muer *MultiUploader) upload() (uperr error) { 40 err := muer.multiUpload.Precreate() 41 if err != nil { 42 return err 43 } 44 45 var ( 46 uploadDeque = lane.NewDeque() 47 ) 48 49 // 加入队列 50 for _, wer := range muer.workers { 51 if wer.checksum == "" { 52 uploadDeque.Append(wer) 53 } 54 } 55 56 for { 57 wg := waitgroup.NewWaitGroup(muer.config.Parallel) 58 for { 59 e := uploadDeque.Shift() 60 if e == nil { // 任务为空 61 break 62 } 63 64 wer := e.(*worker) 65 wg.AddDelta() 66 go func() { 67 defer wg.Done() 68 69 var ( 70 ctx, cancel = context.WithCancel(context.Background()) 71 doneChan = make(chan struct{}) 72 checksum string 73 terr error 74 ) 75 go func() { 76 checksum, terr = muer.multiUpload.TmpFile(ctx, int(wer.id), wer.partOffset, wer.splitUnit) 77 close(doneChan) 78 }() 79 select { 80 case <-muer.canceled: 81 cancel() 82 return 83 case <-doneChan: 84 // continue 85 } 86 cancel() 87 if terr != nil { 88 if me, ok := terr.(*MultiError); ok { 89 if me.Terminated { // 终止 90 muer.closeCanceledOnce.Do(func() { // 只关闭一次 91 close(muer.canceled) 92 }) 93 uperr = me.Err 94 return 95 } 96 } 97 98 uploaderVerbose.Warnf("upload err: %s, id: %d\n", terr, wer.id) 99 wer.splitUnit.Seek(0, os.SEEK_SET) 100 uploadDeque.Append(wer) 101 return 102 } 103 wer.checksum = checksum 104 105 // 通知更新 106 if muer.updateInstanceStateChan != nil && len(muer.updateInstanceStateChan) < cap(muer.updateInstanceStateChan) { 107 muer.updateInstanceStateChan <- struct{}{} 108 } 109 }() 110 } 111 wg.Wait() 112 113 // 没有任务了 114 if uploadDeque.Size() == 0 { 115 break 116 } 117 } 118 119 select { 120 case <-muer.canceled: 121 if uperr != nil { 122 return uperr 123 } 124 return context.Canceled 125 default: 126 } 127 128 cerr := muer.multiUpload.CreateSuperFile(muer.workers.CheckSumList()...) 129 if cerr != nil { 130 return cerr 131 } 132 133 return 134 }