storj.io/uplink@v1.13.0/private/storage/streams/pieceupload/upload.go (about)

     1  // Copyright (C) 2023 Storj Labs, Inc.
     2  // See LICENSE for copying information.
     3  
     4  package pieceupload
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"io"
    10  
    11  	"github.com/spacemonkeygo/monkit/v3"
    12  
    13  	"storj.io/common/pb"
    14  	"storj.io/common/storj"
    15  	"storj.io/uplink/private/testuplink"
    16  )
    17  
    18  var mon = monkit.Package()
    19  
    20  // PiecePutter puts pieces.
    21  type PiecePutter interface {
    22  	// PutPiece puts a piece using the given limit and private key. The
    23  	// operation can be cancelled using the longTailCtx or uploadCtx is
    24  	// cancelled.
    25  	PutPiece(longTailCtx, uploadCtx context.Context, limit *pb.AddressedOrderLimit, privateKey storj.PiecePrivateKey, data io.ReadCloser) (hash *pb.PieceHash, deprecated *struct{}, err error)
    26  }
    27  
    28  // UploadOne uploads one piece from the manager using the given private key. If
    29  // it fails, it will attempt to upload another until either the upload context,
    30  // or the long tail context is cancelled.
    31  func UploadOne(longTailCtx, uploadCtx context.Context, manager *Manager, putter PiecePutter, privateKey storj.PiecePrivateKey) (_ bool, err error) {
    32  	defer mon.Task()(&longTailCtx)(&err)
    33  
    34  	// If the long tail context is cancelled, then return a nil error.
    35  	defer func() {
    36  		if longTailCtx.Err() != nil {
    37  			err = nil
    38  		}
    39  	}()
    40  
    41  	for {
    42  		piece, limit, done, err := manager.NextPiece(longTailCtx)
    43  		if err != nil {
    44  			return false, err
    45  		}
    46  
    47  		var pieceID string
    48  		if limit.Limit != nil {
    49  			pieceID = limit.Limit.PieceId.String()
    50  		}
    51  
    52  		var address, noise string
    53  		if limit.StorageNodeAddress != nil {
    54  			address = fmt.Sprintf("%-21s", limit.StorageNodeAddress.Address)
    55  			noise = fmt.Sprintf("%-5t", limit.StorageNodeAddress.NoiseInfo != nil)
    56  		}
    57  
    58  		logCtx := testuplink.WithLogWriterContext(uploadCtx,
    59  			"piece_id", pieceID,
    60  			"address", address,
    61  			"noise", noise,
    62  		)
    63  
    64  		testuplink.Log(logCtx, "Uploading piece...")
    65  		hash, _, err := putter.PutPiece(longTailCtx, uploadCtx, limit, privateKey, io.NopCloser(piece))
    66  		testuplink.Log(logCtx, "Done uploading piece. err:", err)
    67  		done(hash, err == nil)
    68  		if err == nil {
    69  			return true, nil
    70  		}
    71  
    72  		if err := uploadCtx.Err(); err != nil {
    73  			return false, err
    74  		}
    75  
    76  		if longTailCtx.Err() != nil {
    77  			// If this context is done but the uploadCtx context isn't, then the
    78  			// download was cancelled for long tail optimization purposes. This
    79  			// is expected. Return that there was no error but that the upload
    80  			// did not complete.
    81  			return false, nil
    82  		}
    83  	}
    84  }