| @@ -39,13 +39,13 @@ func (c *Commandline) DispatchCommand(cmd string, args []string) { | |||||
| fmt.Printf("invalid bucket id %s, err: %s", args[1], err.Error()) | fmt.Printf("invalid bucket id %s, err: %s", args[1], err.Error()) | ||||
| os.Exit(1) | os.Exit(1) | ||||
| } | } | ||||
| repNum, _ := strconv.Atoi(args[3]) | |||||
| if repNum <= 0 || repNum > config.Cfg().MaxReplicateNumber { | |||||
| fmt.Printf("replicate number should not be more than %d", config.Cfg().MaxReplicateNumber) | |||||
| repCount, _ := strconv.Atoi(args[3]) | |||||
| if repCount <= 0 || repCount > config.Cfg().MaxRepCount { | |||||
| fmt.Printf("replicate number should not be more than %d", config.Cfg().MaxRepCount) | |||||
| os.Exit(1) | os.Exit(1) | ||||
| } | } | ||||
| if err := c.RepWrite(args[0], bucketID, args[2], repNum); err != nil { | |||||
| if err := c.RepWrite(args[0], bucketID, args[2], repCount); err != nil { | |||||
| fmt.Printf("rep write failed, err: %s", err.Error()) | fmt.Printf("rep write failed, err: %s", err.Error()) | ||||
| os.Exit(1) | os.Exit(1) | ||||
| } | } | ||||
| @@ -21,10 +21,10 @@ func (c *Commandline) ListBucketObjects(bucketID int) error { | |||||
| fmt.Printf("Find %d objects in bucket %d for user %d:\n", len(objects), bucketID, userID) | fmt.Printf("Find %d objects in bucket %d for user %d:\n", len(objects), bucketID, userID) | ||||
| tb := table.NewWriter() | tb := table.NewWriter() | ||||
| tb.AppendHeader(table.Row{"ID", "Name", "Size", "BucketID", "State", "Redundancy", "NumRep", "ECName"}) | |||||
| tb.AppendHeader(table.Row{"ID", "Name", "Size", "BucketID", "State", "Redundancy"}) | |||||
| for _, obj := range objects { | for _, obj := range objects { | ||||
| tb.AppendRow(table.Row{obj.ObjectID, obj.Name, obj.BucketID, obj.State, obj.FileSizeInBytes, obj.Redundancy, obj.NumRep, obj.ECName}) | |||||
| tb.AppendRow(table.Row{obj.ObjectID, obj.Name, obj.BucketID, obj.State, obj.FileSize, obj.Redundancy}) | |||||
| } | } | ||||
| fmt.Print(tb.Render()) | fmt.Print(tb.Render()) | ||||
| @@ -68,7 +68,7 @@ func (c *Commandline) Read(localFilePath string, objectID int) error { | |||||
| return nil | return nil | ||||
| } | } | ||||
| func (c *Commandline) RepWrite(localFilePath string, bucketID int, objectName string, repNum int) error { | |||||
| func (c *Commandline) RepWrite(localFilePath string, bucketID int, objectName string, repCount int) error { | |||||
| file, err := os.Open(localFilePath) | file, err := os.Open(localFilePath) | ||||
| if err != nil { | if err != nil { | ||||
| return fmt.Errorf("open file %s failed, err: %w", localFilePath, err) | return fmt.Errorf("open file %s failed, err: %w", localFilePath, err) | ||||
| @@ -81,7 +81,7 @@ func (c *Commandline) RepWrite(localFilePath string, bucketID int, objectName st | |||||
| } | } | ||||
| fileSize := fileInfo.Size() | fileSize := fileInfo.Size() | ||||
| err = services.ObjectSvc(c.svc).UploadRepObject(0, bucketID, objectName, file, fileSize, repNum) | |||||
| err = services.ObjectSvc(c.svc).UploadRepObject(0, bucketID, objectName, file, fileSize, repCount) | |||||
| if err != nil { | if err != nil { | ||||
| return fmt.Errorf("upload file data failed, err: %w", err) | return fmt.Errorf("upload file data failed, err: %w", err) | ||||
| } | } | ||||
| @@ -8,14 +8,14 @@ import ( | |||||
| ) | ) | ||||
| type Config struct { | type Config struct { | ||||
| GRPCPort int `json:"grpcPort"` | |||||
| GRCPPacketSize int64 `json:"grpcPacketSize"` | |||||
| MaxReplicateNumber int `json:"maxReplicateNumber"` | |||||
| LocalIP string `json:"localIP"` | |||||
| ExternalIP string `json:"externalIP"` | |||||
| Logger logger.Config `json:"logger"` | |||||
| RabbitMQ racfg.Config `json:"rabbitMQ"` | |||||
| IPFS *ipfs.Config `json:"ipfs"` // 此字段非空代表客户端上存在ipfs daemon | |||||
| GRPCPort int `json:"grpcPort"` | |||||
| GRCPPacketSize int64 `json:"grpcPacketSize"` | |||||
| MaxRepCount int `json:"maxRepCount"` | |||||
| LocalIP string `json:"localIP"` | |||||
| ExternalIP string `json:"externalIP"` | |||||
| Logger logger.Config `json:"logger"` | |||||
| RabbitMQ racfg.Config `json:"rabbitMQ"` | |||||
| IPFS *ipfs.Config `json:"ipfs"` // 此字段非空代表客户端上存在ipfs daemon | |||||
| } | } | ||||
| var cfg Config | var cfg Config | ||||
| @@ -26,7 +26,7 @@ func EcWrite(localFilePath string, bucketID int, objectName string, ecName strin | |||||
| if err != nil { | if err != nil { | ||||
| return fmt.Errorf("get file %s state failed, err: %w", localFilePath, err) | return fmt.Errorf("get file %s state failed, err: %w", localFilePath, err) | ||||
| } | } | ||||
| fileSizeInBytes := fileInfo.Size() | |||||
| fileSize := fileInfo.Size() | |||||
| //调用纠删码库,获取编码参数及生成矩阵 | //调用纠删码库,获取编码参数及生成矩阵 | ||||
| ecPolicies := *utils.GetEcPolicy() | ecPolicies := *utils.GetEcPolicy() | ||||
| @@ -45,7 +45,7 @@ func EcWrite(localFilePath string, bucketID int, objectName string, ecName strin | |||||
| var coefs = [][]int64{{1, 1, 1}, {1, 2, 3}} //2应替换为ecK,3应替换为ecN | var coefs = [][]int64{{1, 1, 1}, {1, 2, 3}} //2应替换为ecK,3应替换为ecN | ||||
| //计算每个块的packet数 | //计算每个块的packet数 | ||||
| numPacket := (fileSizeInBytes + int64(ecK)*config.Cfg().GRCPPacketSize - 1) / (int64(ecK) * config.Cfg().GRCPPacketSize) | |||||
| numPacket := (fileSize + int64(ecK)*config.Cfg().GRCPPacketSize - 1) / (int64(ecK) * config.Cfg().GRCPPacketSize) | |||||
| fmt.Println(numPacket) | fmt.Println(numPacket) | ||||
| userId := 0 | userId := 0 | ||||
| @@ -56,7 +56,7 @@ func EcWrite(localFilePath string, bucketID int, objectName string, ecName strin | |||||
| defer coorClient.Close() | defer coorClient.Close() | ||||
| //发送写请求,请求Coor分配写入节点Ip | //发送写请求,请求Coor分配写入节点Ip | ||||
| ecWriteResp, err := coorClient.ECWrite(bucketName, objectName, fileSizeInBytes, ecName, userId) | |||||
| ecWriteResp, err := coorClient.ECWrite(bucketName, objectName, fileSize, ecName, userId) | |||||
| if err != nil { | if err != nil { | ||||
| return fmt.Errorf("request to coordinator failed, err: %w", err) | return fmt.Errorf("request to coordinator failed, err: %w", err) | ||||
| } | } | ||||
| @@ -75,7 +75,7 @@ func EcWrite(localFilePath string, bucketID int, objectName string, ecName strin | |||||
| } | } | ||||
| hashs := make([]string, ecN) | hashs := make([]string, ecN) | ||||
| //正式开始写入 | //正式开始写入 | ||||
| go load(localFilePath, loadBufs[:ecN], ecK, numPacket*int64(ecK), fileSizeInBytes) //从本地文件系统加载数据 | |||||
| go load(localFilePath, loadBufs[:ecN], ecK, numPacket*int64(ecK), fileSize) //从本地文件系统加载数据 | |||||
| go encode(loadBufs[:ecN], encodeBufs[:ecN], ecK, coefs, numPacket) | go encode(loadBufs[:ecN], encodeBufs[:ecN], ecK, coefs, numPacket) | ||||
| var wg sync.WaitGroup | var wg sync.WaitGroup | ||||
| @@ -99,7 +99,7 @@ func EcWrite(localFilePath string, bucketID int, objectName string, ecName strin | |||||
| */ | */ | ||||
| } | } | ||||
| func load(localFilePath string, loadBufs []chan []byte, ecK int, totalNumPacket int64, fileSizeInBytes int64) { | |||||
| func load(localFilePath string, loadBufs []chan []byte, ecK int, totalNumPacket int64, fileSize int64) { | |||||
| fmt.Println("load " + localFilePath) | fmt.Println("load " + localFilePath) | ||||
| file, _ := os.Open(localFilePath) | file, _ := os.Open(localFilePath) | ||||
| @@ -318,7 +318,7 @@ func persist(inBuf []chan []byte, numPacket int64, localFilePath string, wg *syn | |||||
| wg.Done() | wg.Done() | ||||
| } | } | ||||
| func ecRead(fileSizeInBytes int64, nodeIPs []string, blockHashs []string, blockIds []int, ecName string, localFilePath string) { | |||||
| func ecRead(fileSize int64, nodeIPs []string, blockHashs []string, blockIds []int, ecName string, localFilePath string) { | |||||
| //根据ecName获得以下参数 | //根据ecName获得以下参数 | ||||
| wg := sync.WaitGroup{} | wg := sync.WaitGroup{} | ||||
| ecPolicies := *utils.GetEcPolicy() | ecPolicies := *utils.GetEcPolicy() | ||||
| @@ -328,7 +328,7 @@ func ecRead(fileSizeInBytes int64, nodeIPs []string, blockHashs []string, blockI | |||||
| ecN := ecPolicy.GetN() | ecN := ecPolicy.GetN() | ||||
| var coefs = [][]int64{{1, 1, 1}, {1, 2, 3}} //2应替换为ecK,3应替换为ecN | var coefs = [][]int64{{1, 1, 1}, {1, 2, 3}} //2应替换为ecK,3应替换为ecN | ||||
| numPacket := (fileSizeInBytes + int64(ecK)*config.Cfg().GRCPPacketSize - 1) / (int64(ecK) * config.Cfg().GRCPPacketSize) | |||||
| numPacket := (fileSize + int64(ecK)*config.Cfg().GRCPPacketSize - 1) / (int64(ecK) * config.Cfg().GRCPPacketSize) | |||||
| fmt.Println(numPacket) | fmt.Println(numPacket) | ||||
| //创建channel | //创建channel | ||||
| getBufs := make([]chan []byte, ecN) | getBufs := make([]chan []byte, ecN) | ||||
| @@ -9,12 +9,14 @@ import ( | |||||
| "gitlink.org.cn/cloudream/db/model" | "gitlink.org.cn/cloudream/db/model" | ||||
| agentcaller "gitlink.org.cn/cloudream/proto" | agentcaller "gitlink.org.cn/cloudream/proto" | ||||
| agtcli "gitlink.org.cn/cloudream/rabbitmq/client/agent" | agtcli "gitlink.org.cn/cloudream/rabbitmq/client/agent" | ||||
| ramsg "gitlink.org.cn/cloudream/rabbitmq/message" | |||||
| agtmsg "gitlink.org.cn/cloudream/rabbitmq/message/agent" | agtmsg "gitlink.org.cn/cloudream/rabbitmq/message/agent" | ||||
| coormsg "gitlink.org.cn/cloudream/rabbitmq/message/coordinator" | coormsg "gitlink.org.cn/cloudream/rabbitmq/message/coordinator" | ||||
| "gitlink.org.cn/cloudream/utils/consts" | "gitlink.org.cn/cloudream/utils/consts" | ||||
| mygrpc "gitlink.org.cn/cloudream/utils/grpc" | mygrpc "gitlink.org.cn/cloudream/utils/grpc" | ||||
| myio "gitlink.org.cn/cloudream/utils/io" | myio "gitlink.org.cn/cloudream/utils/io" | ||||
| log "gitlink.org.cn/cloudream/utils/logger" | log "gitlink.org.cn/cloudream/utils/logger" | ||||
| serder "gitlink.org.cn/cloudream/utils/serder" | |||||
| mysort "gitlink.org.cn/cloudream/utils/sort" | mysort "gitlink.org.cn/cloudream/utils/sort" | ||||
| "google.golang.org/grpc" | "google.golang.org/grpc" | ||||
| "google.golang.org/grpc/credentials/insecure" | "google.golang.org/grpc/credentials/insecure" | ||||
| @@ -36,7 +38,7 @@ func (svc *ObjectService) GetObject(userID int, objectID int) (model.Object, err | |||||
| } | } | ||||
| func (svc *ObjectService) DownloadObject(userID int, objectID int) (io.ReadCloser, error) { | func (svc *ObjectService) DownloadObject(userID int, objectID int) (io.ReadCloser, error) { | ||||
| preDownloadResp, err := svc.coordinator.PreDownloadObject(coormsg.NewReadCommandBody(objectID, userID, config.Cfg().ExternalIP)) | |||||
| preDownloadResp, err := svc.coordinator.PreDownloadObject(coormsg.NewPreDownloadObjectBody(objectID, userID, config.Cfg().ExternalIP)) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("request to coordinator failed, err: %w", err) | return nil, fmt.Errorf("request to coordinator failed, err: %w", err) | ||||
| } | } | ||||
| @@ -46,22 +48,28 @@ func (svc *ObjectService) DownloadObject(userID int, objectID int) (io.ReadClose | |||||
| switch preDownloadResp.Body.Redundancy { | switch preDownloadResp.Body.Redundancy { | ||||
| case consts.REDUNDANCY_REP: | case consts.REDUNDANCY_REP: | ||||
| if len(preDownloadResp.Body.Entries) == 0 { | |||||
| var repInfo ramsg.RespObjectRepInfo | |||||
| err := serder.MapToObject(preDownloadResp.Body.RedundancyData.(map[string]any), &repInfo) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("redundancy data to rep info failed, err: %w", err) | |||||
| } | |||||
| if len(repInfo.Nodes) == 0 { | |||||
| return nil, fmt.Errorf("no node has this file") | return nil, fmt.Errorf("no node has this file") | ||||
| } | } | ||||
| // 选择下载节点 | // 选择下载节点 | ||||
| entry := svc.chooseDownloadNode(preDownloadResp.Body.Entries) | |||||
| entry := svc.chooseDownloadNode(repInfo.Nodes) | |||||
| // 如果客户端与节点在同一个地域,则使用内网地址连接节点 | // 如果客户端与节点在同一个地域,则使用内网地址连接节点 | ||||
| nodeIP := entry.NodeExternalIP | |||||
| nodeIP := entry.ExternalIP | |||||
| if entry.IsSameLocation { | if entry.IsSameLocation { | ||||
| nodeIP = entry.NodeLocalIP | |||||
| nodeIP = entry.LocalIP | |||||
| log.Infof("client and node %d are at the same location, use local ip\n", entry.NodeID) | |||||
| log.Infof("client and node %d are at the same location, use local ip\n", entry.ID) | |||||
| } | } | ||||
| reader, err := svc.downloadRepObject(nodeIP, entry.FileHash) | |||||
| reader, err := svc.downloadRepObject(nodeIP, repInfo.FileHash) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("rep read failed, err: %w", err) | return nil, fmt.Errorf("rep read failed, err: %w", err) | ||||
| } | } | ||||
| @@ -70,7 +78,7 @@ func (svc *ObjectService) DownloadObject(userID int, objectID int) (io.ReadClose | |||||
| //case consts.REDUNDANCY_EC: | //case consts.REDUNDANCY_EC: | ||||
| // TODO EC部分的代码要考虑重构 | // TODO EC部分的代码要考虑重构 | ||||
| // ecRead(readResp.FileSizeInBytes, readResp.NodeIPs, readResp.Hashes, readResp.BlockIDs, *readResp.ECName) | |||||
| // ecRead(readResp.FileSize, readResp.NodeIPs, readResp.Hashes, readResp.BlockIDs, *readResp.ECName) | |||||
| } | } | ||||
| return nil, fmt.Errorf("unsupported redundancy type: %s", preDownloadResp.Body.Redundancy) | return nil, fmt.Errorf("unsupported redundancy type: %s", preDownloadResp.Body.Redundancy) | ||||
| @@ -79,8 +87,8 @@ func (svc *ObjectService) DownloadObject(userID int, objectID int) (io.ReadClose | |||||
| // chooseDownloadNode 选择一个下载节点 | // chooseDownloadNode 选择一个下载节点 | ||||
| // 1. 从与当前客户端相同地域的节点中随机选一个 | // 1. 从与当前客户端相同地域的节点中随机选一个 | ||||
| // 2. 没有用的话从所有节点中随机选一个 | // 2. 没有用的话从所有节点中随机选一个 | ||||
| func (svc *ObjectService) chooseDownloadNode(entries []coormsg.PreDownloadObjectRespEntry) coormsg.PreDownloadObjectRespEntry { | |||||
| sameLocationEntries := lo.Filter(entries, func(e coormsg.PreDownloadObjectRespEntry, i int) bool { return e.IsSameLocation }) | |||||
| func (svc *ObjectService) chooseDownloadNode(entries []ramsg.RespNode) ramsg.RespNode { | |||||
| sameLocationEntries := lo.Filter(entries, func(e ramsg.RespNode, i int) bool { return e.IsSameLocation }) | |||||
| if len(sameLocationEntries) > 0 { | if len(sameLocationEntries) > 0 { | ||||
| return sameLocationEntries[rand.Intn(len(sameLocationEntries))] | return sameLocationEntries[rand.Intn(len(sameLocationEntries))] | ||||
| } | } | ||||
| @@ -132,7 +140,7 @@ func (svc *ObjectService) downloadFromLocalIPFS(fileHash string) (io.ReadCloser, | |||||
| return reader, nil | return reader, nil | ||||
| } | } | ||||
| func (svc *ObjectService) UploadRepObject(userID int, bucketID int, objectName string, file io.ReadCloser, fileSize int64, repNum int) error { | |||||
| func (svc *ObjectService) UploadRepObject(userID int, bucketID int, objectName string, file io.ReadCloser, fileSize int64, repCount int) error { | |||||
| //发送写请求,请求Coor分配写入节点Ip | //发送写请求,请求Coor分配写入节点Ip | ||||
| repWriteResp, err := svc.coordinator.PreUploadRepObject(coormsg.NewPreUploadRepObjectBody(bucketID, objectName, fileSize, userID, config.Cfg().ExternalIP)) | repWriteResp, err := svc.coordinator.PreUploadRepObject(coormsg.NewPreUploadRepObjectBody(bucketID, objectName, fileSize, userID, config.Cfg().ExternalIP)) | ||||
| @@ -182,7 +190,7 @@ func (svc *ObjectService) UploadRepObject(userID int, bucketID int, objectName s | |||||
| } | } | ||||
| // 记录写入的文件的Hash | // 记录写入的文件的Hash | ||||
| createObjectResp, err := svc.coordinator.CreateRepObject(coormsg.NewCreateRepObjectBody(bucketID, objectName, fileSize, repNum, userID, uploadedNodeIDs, fileHash)) | |||||
| createObjectResp, err := svc.coordinator.CreateRepObject(coormsg.NewCreateRepObjectBody(bucketID, objectName, fileSize, repCount, userID, uploadedNodeIDs, fileHash)) | |||||
| if err != nil { | if err != nil { | ||||
| return fmt.Errorf("request to coordinator failed, err: %w", err) | return fmt.Errorf("request to coordinator failed, err: %w", err) | ||||
| } | } | ||||
| @@ -264,8 +272,8 @@ func (svc *ObjectService) uploadToLocalIPFS(file io.ReadCloser, nodeID int) (str | |||||
| // chooseUploadNode 选择一个上传文件的节点 | // chooseUploadNode 选择一个上传文件的节点 | ||||
| // 1. 从与当前客户端相同地域的节点中随机选一个 | // 1. 从与当前客户端相同地域的节点中随机选一个 | ||||
| // 2. 没有用的话从所有节点中随机选一个 | // 2. 没有用的话从所有节点中随机选一个 | ||||
| func (svc *ObjectService) chooseUploadNode(nodes []coormsg.PreUploadRespNode) coormsg.PreUploadRespNode { | |||||
| sameLocationNodes := lo.Filter(nodes, func(e coormsg.PreUploadRespNode, i int) bool { return e.IsSameLocation }) | |||||
| func (svc *ObjectService) chooseUploadNode(nodes []ramsg.RespNode) ramsg.RespNode { | |||||
| sameLocationNodes := lo.Filter(nodes, func(e ramsg.RespNode, i int) bool { return e.IsSameLocation }) | |||||
| if len(sameLocationNodes) > 0 { | if len(sameLocationNodes) > 0 { | ||||
| return sameLocationNodes[rand.Intn(len(sameLocationNodes))] | return sameLocationNodes[rand.Intn(len(sameLocationNodes))] | ||||
| } | } | ||||
| @@ -7,7 +7,6 @@ import ( | |||||
| agtcli "gitlink.org.cn/cloudream/rabbitmq/client/agent" | agtcli "gitlink.org.cn/cloudream/rabbitmq/client/agent" | ||||
| agtmsg "gitlink.org.cn/cloudream/rabbitmq/message/agent" | agtmsg "gitlink.org.cn/cloudream/rabbitmq/message/agent" | ||||
| coormsg "gitlink.org.cn/cloudream/rabbitmq/message/coordinator" | coormsg "gitlink.org.cn/cloudream/rabbitmq/message/coordinator" | ||||
| "gitlink.org.cn/cloudream/utils/consts" | |||||
| ) | ) | ||||
| type StorageService struct { | type StorageService struct { | ||||
| @@ -35,24 +34,19 @@ func (svc *StorageService) MoveObjectToStorage(userID int, objectID int, storage | |||||
| } | } | ||||
| defer agentClient.Close() | defer agentClient.Close() | ||||
| switch preMoveResp.Body.Redundancy { | |||||
| case consts.REDUNDANCY_REP: | |||||
| agentMoveResp, err := agentClient.RepMove(agtmsg.NewRepMoveCommandBody(preMoveResp.Body.Directory, preMoveResp.Body.Hashes, objectID, userID, preMoveResp.Body.FileSizeInBytes)) | |||||
| if err != nil { | |||||
| return fmt.Errorf("request to agent %d failed, err: %w", preMoveResp.Body.NodeID, err) | |||||
| } | |||||
| if agentMoveResp.IsFailed() { | |||||
| return fmt.Errorf("agent %d operation failed, code: %s, messsage: %s", preMoveResp.Body.NodeID, agentMoveResp.ErrorCode, agentMoveResp.ErrorMessage) | |||||
| } | |||||
| case consts.REDUNDANCY_EC: | |||||
| agentMoveResp, err := agentClient.ECMove(agtmsg.NewECMoveCommandBody(preMoveResp.Body.Directory, preMoveResp.Body.Hashes, preMoveResp.Body.IDs, *preMoveResp.Body.ECName, objectID, userID, preMoveResp.Body.FileSizeInBytes)) | |||||
| if err != nil { | |||||
| return fmt.Errorf("request to agent %d failed, err: %w", preMoveResp.Body.NodeID, err) | |||||
| } | |||||
| if agentMoveResp.IsFailed() { | |||||
| return fmt.Errorf("agent %d operation failed, code: %s, messsage: %s", preMoveResp.Body.NodeID, agentMoveResp.ErrorCode, agentMoveResp.ErrorMessage) | |||||
| } | |||||
| agentMoveResp, err := agentClient.MoveObjectToStorage( | |||||
| agtmsg.NewMoveObjectToStorageBody(preMoveResp.Body.Directory, | |||||
| objectID, | |||||
| userID, | |||||
| preMoveResp.Body.FileSize, | |||||
| preMoveResp.Body.Redundancy, | |||||
| preMoveResp.Body.RedundancyData, | |||||
| )) | |||||
| if err != nil { | |||||
| return fmt.Errorf("request to agent %d failed, err: %w", preMoveResp.Body.NodeID, err) | |||||
| } | |||||
| if agentMoveResp.IsFailed() { | |||||
| return fmt.Errorf("agent %d operation failed, code: %s, messsage: %s", preMoveResp.Body.NodeID, agentMoveResp.ErrorCode, agentMoveResp.ErrorMessage) | |||||
| } | } | ||||
| moveResp, err := svc.coordinator.MoveObjectToStorage(coormsg.NewMoveObjectToStorageBody(objectID, storageID, userID)) | moveResp, err := svc.coordinator.MoveObjectToStorage(coormsg.NewMoveObjectToStorageBody(objectID, storageID, userID)) | ||||