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  }