|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- package ops2
-
- import (
- "fmt"
- "time"
-
- "gitlink.org.cn/cloudream/common/pkgs/ioswitch/dag"
- "gitlink.org.cn/cloudream/common/pkgs/ioswitch/exec"
- log "gitlink.org.cn/cloudream/common/pkgs/logger"
- clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types"
- "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/pool"
- "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/types"
- )
-
- func init() {
- exec.UseOp[*MultipartInitiator]()
- exec.UseOp[*MultipartUpload]()
- exec.UseVarValue[*MultipartUploadArgsValue]()
- exec.UseVarValue[*UploadedPartInfoValue]()
- }
-
- type MultipartUploadArgsValue struct {
- InitState types.MultipartInitState
- }
-
- func (v *MultipartUploadArgsValue) Clone() exec.VarValue {
- return &MultipartUploadArgsValue{
- InitState: v.InitState,
- }
- }
-
- type UploadedPartInfoValue struct {
- types.UploadedPartInfo
- }
-
- func (v *UploadedPartInfoValue) Clone() exec.VarValue {
- return &UploadedPartInfoValue{
- UploadedPartInfo: v.UploadedPartInfo,
- }
- }
-
- type MultipartInitiator struct {
- UserSpace clitypes.UserSpaceDetail
- UploadArgs exec.VarID
- UploadedParts []exec.VarID
- BypassFileOutput exec.VarID // 分片上传之后的临时文件的路径
- BypassCallback exec.VarID // 临时文件使用结果,用于告知Initiator如何处理临时文件
- }
-
- func (o *MultipartInitiator) Execute(ctx *exec.ExecContext, e *exec.Executor) error {
- stgPool, err := exec.GetValueByType[*pool.Pool](ctx)
- if err != nil {
- return fmt.Errorf("getting storage pool: %w", err)
- }
-
- multi, err := stgPool.GetMultiparter(&o.UserSpace)
- if err != nil {
- return err
- }
-
- // 启动一个新的上传任务W
- multiTask, err := multi.Initiate(ctx.Context)
- if err != nil {
- return err
- }
- defer multiTask.Abort()
-
- // 分发上传参数
- e.PutVar(o.UploadArgs, &MultipartUploadArgsValue{
- InitState: multiTask.InitState(),
- })
-
- // 收集分片上传结果
- partInfoValues, err := exec.BindArray[*UploadedPartInfoValue](e, ctx.Context, o.UploadedParts)
- if err != nil {
- return fmt.Errorf("getting uploaded parts: %v", err)
- }
-
- partInfos := make([]types.UploadedPartInfo, len(partInfoValues))
- for i, v := range partInfoValues {
- partInfos[i] = v.UploadedPartInfo
- }
-
- // 合并分片
- fileInfo, err := multiTask.JoinParts(ctx.Context, partInfos)
- if err != nil {
- return fmt.Errorf("completing multipart upload: %v", err)
- }
-
- // 告知后续Op临时文件的路径
- e.PutVar(o.BypassFileOutput, &BypassUploadedFileValue{
- BypassUploadedFile: fileInfo,
- })
-
- // 等待后续Op处理临时文件
- cb, err := exec.BindVar[*BypassHandleResultValue](e, ctx.Context, o.BypassCallback)
- if err != nil {
- return fmt.Errorf("getting temp file callback: %v", err)
- }
-
- if cb.Commited {
- multiTask.Complete()
- }
-
- return nil
- }
-
- func (o *MultipartInitiator) String() string {
- return fmt.Sprintf("MultipartInitiator Args: %v, Parts: %v, BypassFileOutput: %v, BypassCallback: %v", o.UploadArgs, o.UploadedParts, o.BypassFileOutput, o.BypassCallback)
- }
-
- type MultipartUpload struct {
- UserSpace clitypes.UserSpaceDetail
- UploadArgs exec.VarID
- UploadResult exec.VarID
- PartStream exec.VarID
- PartNumber int
- PartSize int64
- }
-
- func (o *MultipartUpload) Execute(ctx *exec.ExecContext, e *exec.Executor) error {
- stgPool, err := exec.GetValueByType[*pool.Pool](ctx)
- if err != nil {
- return fmt.Errorf("getting storage pool: %w", err)
- }
-
- uploadArgs, err := exec.BindVar[*MultipartUploadArgsValue](e, ctx.Context, o.UploadArgs)
- if err != nil {
- return err
- }
-
- partStr, err := exec.BindVar[*exec.StreamValue](e, ctx.Context, o.PartStream)
- if err != nil {
- return err
- }
- defer partStr.Stream.Close()
-
- multi, err := stgPool.GetMultiparter(&o.UserSpace)
- if err != nil {
- return err
- }
-
- startTime := time.Now()
- uploadedInfo, err := multi.UploadPart(ctx.Context, uploadArgs.InitState, o.PartSize, o.PartNumber, partStr.Stream)
- if err != nil {
- return err
- }
- log.Debugf("upload finished in %v", time.Since(startTime))
-
- e.PutVar(o.UploadResult, &UploadedPartInfoValue{
- uploadedInfo,
- })
-
- return nil
- }
-
- func (o *MultipartUpload) String() string {
- return fmt.Sprintf("MultipartUpload[PartNumber=%v,PartSize=%v] Args: %v, Result: %v, Stream: %v", o.PartNumber, o.PartSize, o.UploadArgs, o.UploadResult, o.PartStream)
- }
-
- type MultipartInitiatorNode struct {
- dag.NodeBase
- UserSpace clitypes.UserSpaceDetail
- }
-
- func (b *GraphNodeBuilder) NewMultipartInitiator(userSpace clitypes.UserSpaceDetail) *MultipartInitiatorNode {
- node := &MultipartInitiatorNode{
- UserSpace: userSpace,
- }
- b.AddNode(node)
-
- node.OutputValues().Init(node, 2)
- node.InputValues().Init(1)
- return node
- }
-
- func (n *MultipartInitiatorNode) UploadArgsVar() dag.ValueOutputSlot {
- return dag.ValueOutputSlot{
- Node: n,
- Index: 0,
- }
- }
-
- func (n *MultipartInitiatorNode) BypassFileInfoVar() dag.ValueOutputSlot {
- return dag.ValueOutputSlot{
- Node: n,
- Index: 1,
- }
- }
-
- func (n *MultipartInitiatorNode) BypassCallbackSlot() dag.ValueInputSlot {
- return dag.ValueInputSlot{
- Node: n,
- Index: 0,
- }
- }
-
- func (n *MultipartInitiatorNode) AppendPartInfoSlot() dag.ValueInputSlot {
- return dag.ValueInputSlot{
- Node: n,
- Index: n.InputValues().EnlargeOne(),
- }
- }
-
- func (n *MultipartInitiatorNode) GenerateOp() (exec.Op, error) {
- return &MultipartInitiator{
- UserSpace: n.UserSpace,
- UploadArgs: n.UploadArgsVar().Var().VarID,
- UploadedParts: n.InputValues().GetVarIDsStart(1),
- BypassFileOutput: n.BypassFileInfoVar().Var().VarID,
- BypassCallback: n.BypassCallbackSlot().Var().VarID,
- }, nil
- }
-
- type MultipartUploadNode struct {
- dag.NodeBase
- UserSpace clitypes.UserSpaceDetail
- PartNumber int
- PartSize int64
- }
-
- func (b *GraphNodeBuilder) NewMultipartUpload(userSpace clitypes.UserSpaceDetail, partNumber int, partSize int64) *MultipartUploadNode {
- node := &MultipartUploadNode{
- UserSpace: userSpace,
- PartNumber: partNumber,
- PartSize: partSize,
- }
- b.AddNode(node)
-
- node.InputValues().Init(1)
- node.OutputValues().Init(node, 1)
- node.InputStreams().Init(1)
- return node
- }
-
- func (n *MultipartUploadNode) UploadArgsSlot() dag.ValueInputSlot {
- return dag.ValueInputSlot{
- Node: n,
- Index: 0,
- }
- }
-
- func (n *MultipartUploadNode) UploadResultVar() dag.ValueOutputSlot {
- return dag.ValueOutputSlot{
- Node: n,
- Index: 0,
- }
- }
-
- func (n *MultipartUploadNode) PartStreamSlot() dag.StreamInputSlot {
- return dag.StreamInputSlot{
- Node: n,
- Index: 0,
- }
- }
-
- func (n *MultipartUploadNode) GenerateOp() (exec.Op, error) {
- return &MultipartUpload{
- UserSpace: n.UserSpace,
- UploadArgs: n.UploadArgsSlot().Var().VarID,
- UploadResult: n.UploadResultVar().Var().VarID,
- PartStream: n.PartStreamSlot().Var().VarID,
- PartNumber: n.PartNumber,
- PartSize: n.PartSize,
- }, nil
- }
|