| @@ -7,6 +7,7 @@ import ( | |||||
| c "gitlink.org.cn/cloudream/common/utils/config" | c "gitlink.org.cn/cloudream/common/utils/config" | ||||
| stgmodels "gitlink.org.cn/cloudream/storage/common/models" | stgmodels "gitlink.org.cn/cloudream/storage/common/models" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/connectivity" | "gitlink.org.cn/cloudream/storage/common/pkgs/connectivity" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/downloader" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/grpc" | "gitlink.org.cn/cloudream/storage/common/pkgs/grpc" | ||||
| stgmq "gitlink.org.cn/cloudream/storage/common/pkgs/mq" | stgmq "gitlink.org.cn/cloudream/storage/common/pkgs/mq" | ||||
| ) | ) | ||||
| @@ -21,6 +22,7 @@ type Config struct { | |||||
| IPFS ipfs.Config `json:"ipfs"` | IPFS ipfs.Config `json:"ipfs"` | ||||
| DistLock distlock.Config `json:"distlock"` | DistLock distlock.Config `json:"distlock"` | ||||
| Connectivity connectivity.Config `json:"connectivity"` | Connectivity connectivity.Config `json:"connectivity"` | ||||
| Downloader downloader.Config `json:"downloader"` | |||||
| } | } | ||||
| var cfg Config | var cfg Config | ||||
| @@ -5,7 +5,7 @@ import ( | |||||
| "io" | "io" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| agentserver "gitlink.org.cn/cloudream/storage/common/pkgs/grpc/agent" | agentserver "gitlink.org.cn/cloudream/storage/common/pkgs/grpc/agent" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| ) | ) | ||||
| @@ -48,8 +48,7 @@ func (s *Service) SendStream(server agentserver.Agent_SendStreamServer) error { | |||||
| return fmt.Errorf("recv message failed, err: %w", err) | return fmt.Errorf("recv message failed, err: %w", err) | ||||
| } | } | ||||
| // 将接收到的数据写入管道 | |||||
| err = myio.WriteAll(pw, msg.Data) | |||||
| err = io2.WriteAll(pw, msg.Data) | |||||
| if err != nil { | if err != nil { | ||||
| pw.CloseWithError(io.ErrClosedPipe) | pw.CloseWithError(io.ErrClosedPipe) | ||||
| logger.Warnf("write data to file failed, err: %s", err.Error()) | logger.Warnf("write data to file failed, err: %s", err.Error()) | ||||
| @@ -5,7 +5,7 @@ import ( | |||||
| "io" | "io" | ||||
| log "gitlink.org.cn/cloudream/common/pkgs/logger" | log "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | stgglb "gitlink.org.cn/cloudream/storage/common/globals" | ||||
| agentserver "gitlink.org.cn/cloudream/storage/common/pkgs/grpc/agent" | agentserver "gitlink.org.cn/cloudream/storage/common/pkgs/grpc/agent" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| @@ -52,7 +52,7 @@ func (s *Service) SendIPFSFile(server agentserver.Agent_SendIPFSFileServer) erro | |||||
| return fmt.Errorf("recv message failed, err: %w", err) | return fmt.Errorf("recv message failed, err: %w", err) | ||||
| } | } | ||||
| err = myio.WriteAll(writer, msg.Data) // 将数据写入IPFS文件流 | |||||
| err = io2.WriteAll(writer, msg.Data) | |||||
| if err != nil { | if err != nil { | ||||
| writer.Abort(io.ErrClosedPipe) // 写入出错时关闭文件写入 | writer.Abort(io.ErrClosedPipe) // 写入出错时关闭文件写入 | ||||
| log.Warnf("write data to file failed, err: %s", err.Error()) | log.Warnf("write data to file failed, err: %s", err.Error()) | ||||
| @@ -60,23 +60,14 @@ func (t *CacheMovePackage) do(ctx TaskContext) error { | |||||
| } | } | ||||
| defer stgglb.CoordinatorMQPool.Release(coorCli) | defer stgglb.CoordinatorMQPool.Release(coorCli) | ||||
| // 获取包内对象详情 | |||||
| getResp, err := coorCli.GetPackageObjectDetails(coormq.NewGetPackageObjectDetails(t.packageID)) | |||||
| if err != nil { | |||||
| return fmt.Errorf("getting package object details: %w", err) | |||||
| } | |||||
| // 获取IPFS客户端 | |||||
| ipfsCli, err := stgglb.IPFSPool.Acquire() | ipfsCli, err := stgglb.IPFSPool.Acquire() | ||||
| if err != nil { | if err != nil { | ||||
| return fmt.Errorf("new ipfs client: %w", err) | return fmt.Errorf("new ipfs client: %w", err) | ||||
| } | } | ||||
| defer ipfsCli.Close() | defer ipfsCli.Close() | ||||
| // 遍历并下载对象 | |||||
| objIter := iterator.NewDownloadObjectIterator(getResp.Objects, &iterator.DownloadContext{ | |||||
| Distlock: ctx.distlock, | |||||
| }) | |||||
| // TODO 可以考虑优化,比如rep类型的直接pin就可以 | |||||
| objIter := ctx.downloader.DownloadPackage(t.packageID) | |||||
| defer objIter.Close() | defer objIter.Close() | ||||
| for { | for { | ||||
| @@ -13,7 +13,7 @@ import ( | |||||
| "gitlink.org.cn/cloudream/common/pkgs/ipfs" | "gitlink.org.cn/cloudream/common/pkgs/ipfs" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/task" | "gitlink.org.cn/cloudream/common/pkgs/task" | ||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| myref "gitlink.org.cn/cloudream/common/utils/reflect" | myref "gitlink.org.cn/cloudream/common/utils/reflect" | ||||
| "gitlink.org.cn/cloudream/common/utils/sort2" | "gitlink.org.cn/cloudream/common/utils/sort2" | ||||
| "gitlink.org.cn/cloudream/storage/common/consts" | "gitlink.org.cn/cloudream/storage/common/consts" | ||||
| @@ -93,8 +93,7 @@ func (t *StorageLoadPackage) do(task *task.Task[TaskContext], ctx TaskContext) e | |||||
| } | } | ||||
| t.FullOutputPath = outputDirPath | t.FullOutputPath = outputDirPath | ||||
| // 获取包对象详情 | |||||
| getObjectDetails, err := coorCli.GetPackageObjectDetails(coormq.NewGetPackageObjectDetails(t.packageID)) | |||||
| getObjectDetails, err := coorCli.GetPackageObjectDetails(coormq.ReqGetPackageObjectDetails(t.packageID)) | |||||
| if err != nil { | if err != nil { | ||||
| return fmt.Errorf("getting package object details: %w", err) | return fmt.Errorf("getting package object details: %w", err) | ||||
| } | } | ||||
| @@ -255,8 +254,7 @@ func (t *StorageLoadPackage) downloadECObject(coorCli *coormq.Client, ipfsCli *i | |||||
| if bsc < osc { | if bsc < osc { | ||||
| var fileStrs []io.ReadCloser | var fileStrs []io.ReadCloser | ||||
| // 初始化RS编码器 | |||||
| rs, err := ec.NewRs(ecRed.K, ecRed.N, ecRed.ChunkSize) | |||||
| rs, err := ec.NewStreamRs(ecRed.K, ecRed.N, ecRed.ChunkSize) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, nil, fmt.Errorf("new rs: %w", err) | return nil, nil, fmt.Errorf("new rs: %w", err) | ||||
| } | } | ||||
| @@ -276,8 +274,7 @@ func (t *StorageLoadPackage) downloadECObject(coorCli *coormq.Client, ipfsCli *i | |||||
| fileStrs = append(fileStrs, str) | fileStrs = append(fileStrs, str) | ||||
| } | } | ||||
| // 将多个文件流转换为统一的ReadCloser接口 | |||||
| fileReaders, filesCloser := myio.ToReaders(fileStrs) | |||||
| fileReaders, filesCloser := io2.ToReaders(fileStrs) | |||||
| // 准备恢复数据所需的信息和变量 | // 准备恢复数据所需的信息和变量 | ||||
| var indexes []int | var indexes []int | ||||
| @@ -292,9 +289,8 @@ func (t *StorageLoadPackage) downloadECObject(coorCli *coormq.Client, ipfsCli *i | |||||
| }) | }) | ||||
| } | } | ||||
| // 执行数据恢复,并将恢复后的数据转换为ReadCloser | |||||
| outputs, outputsCloser := myio.ToReaders(rs.ReconstructData(fileReaders, indexes)) | |||||
| return myio.AfterReadClosed(myio.Length(myio.ChunkedJoin(outputs, int(ecRed.ChunkSize)), obj.Object.Size), func(c io.ReadCloser) { | |||||
| outputs, outputsCloser := io2.ToReaders(rs.ReconstructData(fileReaders, indexes)) | |||||
| return io2.AfterReadClosed(io2.Length(io2.ChunkedJoin(outputs, int(ecRed.ChunkSize)), obj.Object.Size), func(c io.ReadCloser) { | |||||
| filesCloser() | filesCloser() | ||||
| outputsCloser() | outputsCloser() | ||||
| }), pinnedBlocks, nil | }), pinnedBlocks, nil | ||||
| @@ -1,10 +1,11 @@ | |||||
| package task | package task | ||||
| import ( | import ( | ||||
| "gitlink.org.cn/cloudream/common/pkgs/distlock" // 引入分布式锁服务 | |||||
| "gitlink.org.cn/cloudream/common/pkgs/task" // 引入任务处理相关的包 | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/connectivity" // 引入网络连接状态收集器 | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" // 引入IO开关服务 | |||||
| "gitlink.org.cn/cloudream/common/pkgs/distlock" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/task" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/connectivity" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/downloader" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | |||||
| ) | ) | ||||
| // TaskContext 定义了任务执行的上下文环境,包含分布式锁服务、IO开关和网络连接状态收集器 | // TaskContext 定义了任务执行的上下文环境,包含分布式锁服务、IO开关和网络连接状态收集器 | ||||
| @@ -12,6 +13,7 @@ type TaskContext struct { | |||||
| distlock *distlock.Service | distlock *distlock.Service | ||||
| sw *ioswitch.Switch | sw *ioswitch.Switch | ||||
| connectivity *connectivity.Collector | connectivity *connectivity.Collector | ||||
| downloader *downloader.Downloader | |||||
| } | } | ||||
| // CompleteFn 类型定义了任务完成时需要执行的函数,用于设置任务的执行结果 | // CompleteFn 类型定义了任务完成时需要执行的函数,用于设置任务的执行结果 | ||||
| @@ -29,11 +31,11 @@ type Task = task.Task[TaskContext] | |||||
| // CompleteOption 类型定义了任务完成时的选项,可用于定制化任务完成的处理方式 | // CompleteOption 类型定义了任务完成时的选项,可用于定制化任务完成的处理方式 | ||||
| type CompleteOption = task.CompleteOption | type CompleteOption = task.CompleteOption | ||||
| // NewManager 创建并返回一个新的任务管理器实例,需要提供分布式锁服务、IO开关和网络连接状态收集器 | |||||
| func NewManager(distlock *distlock.Service, sw *ioswitch.Switch, connectivity *connectivity.Collector) Manager { | |||||
| func NewManager(distlock *distlock.Service, sw *ioswitch.Switch, connectivity *connectivity.Collector, downloader *downloader.Downloader) Manager { | |||||
| return task.NewManager(TaskContext{ | return task.NewManager(TaskContext{ | ||||
| distlock: distlock, | distlock: distlock, | ||||
| sw: sw, | sw: sw, | ||||
| connectivity: connectivity, | connectivity: connectivity, | ||||
| downloader: downloader, | |||||
| }) | }) | ||||
| } | } | ||||
| @@ -13,6 +13,7 @@ import ( | |||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | stgglb "gitlink.org.cn/cloudream/storage/common/globals" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/connectivity" | "gitlink.org.cn/cloudream/storage/common/pkgs/connectivity" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/distlock" | "gitlink.org.cn/cloudream/storage/common/pkgs/distlock" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/downloader" | |||||
| agtrpc "gitlink.org.cn/cloudream/storage/common/pkgs/grpc/agent" | agtrpc "gitlink.org.cn/cloudream/storage/common/pkgs/grpc/agent" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| @@ -104,11 +105,13 @@ func main() { | |||||
| // 初始化数据切换开关 | // 初始化数据切换开关 | ||||
| sw := ioswitch.NewSwitch() | sw := ioswitch.NewSwitch() | ||||
| // 启动任务管理器和相关服务 | |||||
| dlder := downloader.NewDownloader(config.Cfg().Downloader) | |||||
| //处置协调端、客户端命令(可多建几个) | |||||
| wg := sync.WaitGroup{} | wg := sync.WaitGroup{} | ||||
| wg.Add(4) | wg.Add(4) | ||||
| taskMgr := task.NewManager(distlock, &sw, &conCol) | |||||
| taskMgr := task.NewManager(distlock, &sw, &conCol, &dlder) | |||||
| // 启动命令服务器 | // 启动命令服务器 | ||||
| agtSvr, err := agtmq.NewServer(cmdsvc.NewService(&taskMgr, &sw), config.Cfg().ID, &config.Cfg().RabbitMQ) | agtSvr, err := agtmq.NewServer(cmdsvc.NewService(&taskMgr, &sw), config.Cfg().ID, &config.Cfg().RabbitMQ) | ||||
| @@ -7,6 +7,7 @@ import ( | |||||
| "gitlink.org.cn/cloudream/common/utils/config" | "gitlink.org.cn/cloudream/common/utils/config" | ||||
| stgmodels "gitlink.org.cn/cloudream/storage/common/models" | stgmodels "gitlink.org.cn/cloudream/storage/common/models" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/connectivity" | "gitlink.org.cn/cloudream/storage/common/pkgs/connectivity" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/downloader" | |||||
| agtrpc "gitlink.org.cn/cloudream/storage/common/pkgs/grpc/agent" | agtrpc "gitlink.org.cn/cloudream/storage/common/pkgs/grpc/agent" | ||||
| stgmq "gitlink.org.cn/cloudream/storage/common/pkgs/mq" | stgmq "gitlink.org.cn/cloudream/storage/common/pkgs/mq" | ||||
| ) | ) | ||||
| @@ -19,6 +20,7 @@ type Config struct { | |||||
| IPFS *ipfs.Config `json:"ipfs"` // 此字段非空代表客户端上存在ipfs daemon | IPFS *ipfs.Config `json:"ipfs"` // 此字段非空代表客户端上存在ipfs daemon | ||||
| DistLock distlock.Config `json:"distlock"` | DistLock distlock.Config `json:"distlock"` | ||||
| Connectivity connectivity.Config `json:"connectivity"` | Connectivity connectivity.Config `json:"connectivity"` | ||||
| Downloader downloader.Config `json:"downloader"` | |||||
| } | } | ||||
| var cfg Config | var cfg Config | ||||
| @@ -13,6 +13,7 @@ import ( | |||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | ||||
| myhttp "gitlink.org.cn/cloudream/common/utils/http" | myhttp "gitlink.org.cn/cloudream/common/utils/http" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/downloader" | |||||
| ) | ) | ||||
| // ObjectService 服务结构体,处理对象相关的HTTP请求 | // ObjectService 服务结构体,处理对象相关的HTTP请求 | ||||
| @@ -100,7 +101,17 @@ func (s *ObjectService) Download(ctx *gin.Context) { | |||||
| return | return | ||||
| } | } | ||||
| file, err := s.svc.ObjectSvc().Download(req.UserID, req.ObjectID) | |||||
| off := req.Offset | |||||
| len := int64(-1) | |||||
| if req.Length != nil { | |||||
| len = *req.Length | |||||
| } | |||||
| file, err := s.svc.ObjectSvc().Download(req.UserID, downloader.DownloadReqeust{ | |||||
| ObjectID: req.ObjectID, | |||||
| Offset: off, | |||||
| Length: len, | |||||
| }) | |||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("downloading object: %s", err.Error()) | log.Warnf("downloading object: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "download object failed")) | ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "download object failed")) | ||||
| @@ -7,8 +7,8 @@ import ( | |||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | ||||
| mytask "gitlink.org.cn/cloudream/storage/client/internal/task" | mytask "gitlink.org.cn/cloudream/storage/client/internal/task" | ||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | stgglb "gitlink.org.cn/cloudream/storage/common/globals" | ||||
| stgmod "gitlink.org.cn/cloudream/storage/common/models" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/db/model" | "gitlink.org.cn/cloudream/storage/common/pkgs/db/model" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/downloader" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/iterator" | "gitlink.org.cn/cloudream/storage/common/pkgs/iterator" | ||||
| coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator" | coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator" | ||||
| ) | ) | ||||
| @@ -77,39 +77,15 @@ func (svc *ObjectService) Move(userID cdssdk.UserID, movings []cdssdk.MovingObje | |||||
| return resp.Successes, nil | return resp.Successes, nil | ||||
| } | } | ||||
| // Download 用于下载指定的对象。 | |||||
| // userID: 表示用户的唯一标识。 | |||||
| // objectID: 表示要下载的对象的唯一标识。 | |||||
| // 返回值: 返回一个正在下载的对象的迭代器和可能遇到的错误。 | |||||
| func (svc *ObjectService) Download(userID cdssdk.UserID, objectID cdssdk.ObjectID) (*iterator.IterDownloadingObject, error) { | |||||
| // 从协调器MQ池中获取客户端 | |||||
| coorCli, err := stgglb.CoordinatorMQPool.Acquire() | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("new coordinator client: %w", err) | |||||
| } | |||||
| // 确保在函数结束时释放客户端 | |||||
| defer stgglb.CoordinatorMQPool.Release(coorCli) | |||||
| // 向协调器请求对象详情 | |||||
| resp, err := coorCli.GetObjectDetails(coormq.ReqGetObjectDetails([]cdssdk.ObjectID{objectID})) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("requesting to coordinator") | |||||
| } | |||||
| // 检查对象是否存在 | |||||
| if resp.Objects[0] == nil { | |||||
| return nil, fmt.Errorf("object not found") | |||||
| } | |||||
| // 创建下载对象的迭代器 | |||||
| iter := iterator.NewDownloadObjectIterator([]stgmod.ObjectDetail{*resp.Objects[0]}, &iterator.DownloadContext{ | |||||
| Distlock: svc.DistLock, | |||||
| }) | |||||
| // 确保在函数结束时关闭迭代器 | |||||
| defer iter.Close() | |||||
| func (svc *ObjectService) Download(userID cdssdk.UserID, req downloader.DownloadReqeust) (*downloader.Downloading, error) { | |||||
| // TODO 检查用户ID | |||||
| iter := svc.Downloader.DownloadObjects([]downloader.DownloadReqeust{req}) | |||||
| // 初始化下载过程 | // 初始化下载过程 | ||||
| downloading, err := iter.MoveNext() | downloading, err := iter.MoveNext() | ||||
| if downloading.Object == nil { | |||||
| return nil, fmt.Errorf("object not found") | |||||
| } | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| @@ -6,7 +6,7 @@ import ( | |||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | ||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | stgglb "gitlink.org.cn/cloudream/storage/common/globals" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/iterator" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/downloader" | |||||
| coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator" | coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator" | ||||
| ) | ) | ||||
| @@ -82,27 +82,9 @@ func (svc *PackageService) Create(userID cdssdk.UserID, bucketID cdssdk.BucketID | |||||
| return resp.Package, nil | return resp.Package, nil | ||||
| } | } | ||||
| // DownloadPackage 下载指定包的内容 | |||||
| func (svc *PackageService) DownloadPackage(userID cdssdk.UserID, packageID cdssdk.PackageID) (iterator.DownloadingObjectIterator, error) { | |||||
| // 从协调器MQ池中获取客户端 | |||||
| coorCli, err := stgglb.CoordinatorMQPool.Acquire() | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("new coordinator client: %w", err) | |||||
| } | |||||
| defer stgglb.CoordinatorMQPool.Release(coorCli) | |||||
| // 向协调器请求获取包内对象的详情 | |||||
| getObjsResp, err := coorCli.GetPackageObjectDetails(coormq.NewGetPackageObjectDetails(packageID)) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("getting package object details: %w", err) | |||||
| } | |||||
| // 创建下载对象的迭代器 | |||||
| iter := iterator.NewDownloadObjectIterator(getObjsResp.Objects, &iterator.DownloadContext{ | |||||
| Distlock: svc.DistLock, | |||||
| }) | |||||
| return iter, nil | |||||
| func (svc *PackageService) DownloadPackage(userID cdssdk.UserID, packageID cdssdk.PackageID) (downloader.DownloadIterator, error) { | |||||
| // TODO 检查用户ID | |||||
| return svc.Downloader.DownloadPackage(packageID), nil | |||||
| } | } | ||||
| // DeletePackage 删除指定的包 | // DeletePackage 删除指定的包 | ||||
| @@ -3,30 +3,22 @@ | |||||
| package services | package services | ||||
| import ( | import ( | ||||
| "gitlink.org.cn/cloudream/common/pkgs/distlock" // 导入分布锁服务包 | |||||
| "gitlink.org.cn/cloudream/storage/client/internal/task" // 导入任务管理服务包 | |||||
| "gitlink.org.cn/cloudream/common/pkgs/distlock" | |||||
| "gitlink.org.cn/cloudream/storage/client/internal/task" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/downloader" | |||||
| ) | ) | ||||
| // Service 结构体封装了分布锁服务和任务管理服务。 | // Service 结构体封装了分布锁服务和任务管理服务。 | ||||
| type Service struct { | type Service struct { | ||||
| DistLock *distlock.Service // DistLock 用于分布式环境下的锁服务 | |||||
| TaskMgr *task.Manager // TaskMgr 用于任务的创建、管理和执行 | |||||
| DistLock *distlock.Service | |||||
| TaskMgr *task.Manager | |||||
| Downloader *downloader.Downloader | |||||
| } | } | ||||
| // NewService 创建一个新的Service实例。 | |||||
| // | |||||
| // 参数: | |||||
| // | |||||
| // distlock *distlock.Service: 分布式锁服务的实例。 | |||||
| // taskMgr *task.Manager: 任务管理器的实例。 | |||||
| // | |||||
| // 返回值: | |||||
| // | |||||
| // *Service: 初始化后的Service实例。 | |||||
| // error: 如果创建过程中遇到错误,则返回错误信息,否则为nil。 | |||||
| func NewService(distlock *distlock.Service, taskMgr *task.Manager) (*Service, error) { | |||||
| func NewService(distlock *distlock.Service, taskMgr *task.Manager, downloader *downloader.Downloader) (*Service, error) { | |||||
| return &Service{ | return &Service{ | ||||
| DistLock: distlock, | |||||
| TaskMgr: taskMgr, | |||||
| DistLock: distlock, | |||||
| TaskMgr: taskMgr, | |||||
| Downloader: downloader, | |||||
| }, nil | }, nil | ||||
| } | } | ||||
| @@ -14,6 +14,7 @@ import ( | |||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | stgglb "gitlink.org.cn/cloudream/storage/common/globals" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/connectivity" | "gitlink.org.cn/cloudream/storage/common/pkgs/connectivity" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/distlock" | "gitlink.org.cn/cloudream/storage/common/pkgs/distlock" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/downloader" | |||||
| ) | ) | ||||
| /* | /* | ||||
| @@ -76,8 +77,14 @@ func main() { | |||||
| // 创建任务管理器 | // 创建任务管理器 | ||||
| taskMgr := task.NewManager(distlockSvc, &conCol) | taskMgr := task.NewManager(distlockSvc, &conCol) | ||||
| <<<<<<< HEAD | |||||
| // 创建服务实例 | // 创建服务实例 | ||||
| svc, err := services.NewService(distlockSvc, &taskMgr) | svc, err := services.NewService(distlockSvc, &taskMgr) | ||||
| ======= | |||||
| dlder := downloader.NewDownloader(config.Cfg().Downloader) | |||||
| svc, err := services.NewService(distlockSvc, &taskMgr, &dlder) | |||||
| >>>>>>> 770feaf2da11a3de00fa3ec57b16dc54ff31b288 | |||||
| if err != nil { | if err != nil { | ||||
| logger.Warnf("new services failed, err: %s", err.Error()) | logger.Warnf("new services failed, err: %s", err.Error()) | ||||
| os.Exit(1) | os.Exit(1) | ||||
| @@ -35,5 +35,8 @@ | |||||
| }, | }, | ||||
| "connectivity": { | "connectivity": { | ||||
| "testInterval": 300 | "testInterval": 300 | ||||
| }, | |||||
| "downloader": { | |||||
| "maxStripCacheCount": 100 | |||||
| } | } | ||||
| } | } | ||||
| @@ -28,5 +28,8 @@ | |||||
| }, | }, | ||||
| "connectivity": { | "connectivity": { | ||||
| "testInterval": 300 | "testInterval": 300 | ||||
| }, | |||||
| "downloader": { | |||||
| "maxStripCacheCount": 100 | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,63 +0,0 @@ | |||||
| <setting> | |||||
| <attribute> | |||||
| <name>local.addr</name> | |||||
| <value>101.201.215.165</value> | |||||
| </attribute> | |||||
| <attribute> | |||||
| <name>controller.addr</name> | |||||
| <value>101.201.215.196</value> | |||||
| </attribute> | |||||
| <attribute> | |||||
| <name>agents.addr</name> | |||||
| <value>/hw-sh/123.60.146.162</value> | |||||
| <value>/hw-bj/120.46.183.86</value> | |||||
| <value>/ali/101.201.215.165</value> | |||||
| </attribute> | |||||
| <attribute> | |||||
| <name>agents.location</name> | |||||
| <value>ali</value> | |||||
| <value>hw-sh</value> | |||||
| <value>hw-bj</value> | |||||
| </attribute> | |||||
| <attribute> | |||||
| <name>oec.controller.thread.num</name> | |||||
| <value>4</value> | |||||
| </attribute> | |||||
| <attribute> | |||||
| <name>oec.agent.thread.num</name> | |||||
| <value>2</value> | |||||
| </attribute> | |||||
| <attribute> | |||||
| <name>oec.cmddist.thread.num</name> | |||||
| <value>2</value> | |||||
| </attribute> | |||||
| <attribute> | |||||
| <name>packet.size</name> | |||||
| <value>131072</value> | |||||
| </attribute> | |||||
| <attribute> | |||||
| <name>ec.concurrent.num</name> | |||||
| <value>2</value> | |||||
| </attribute> | |||||
| <attribute> | |||||
| <name>ec.policy</name> | |||||
| <value><ecid>rs_9_6</ecid><class>RS96</class><n>9</n><k>6</k><w>1</w><opt>-1</opt></value> | |||||
| <value><ecid>rs_3_2</ecid><class>RS96</class><n>3</n><k>2</k><w>1</w><opt>-1</opt></value> | |||||
| <value><ecid>edu_9_6</ecid><class>EDU96</class><n>9</n><k>6</k><w>1</w><opt>-1</opt></value> | |||||
| <value><ecid>edu_3_2</ecid><class>EDU32</class><n>3</n><k>2</k><w>1</w><opt>-1</opt></value> | |||||
| <value><ecid>dfc_9_4</ecid><class>DFC</class><n>9</n><k>4</k><w>1</w><opt>-1</opt><param>3,2</param></value> | |||||
| </attribute> | |||||
| <attribute> | |||||
| <name>inter.inner.addr</name> | |||||
| <inner> | |||||
| <dc><ip>172.23.85.69</ip><ip>172.23.85.71</ip><ip>172.23.85.70</ip></dc> | |||||
| <dc><ip>192.168.0.69</ip></dc> | |||||
| <dc><ip>192.168.0.76</ip></dc> | |||||
| </inner> | |||||
| <inter> | |||||
| <dc><ip>101.201.215.196</ip><ip>101.201.215.165</ip><ip>101.201.214.111</ip></dc> | |||||
| <dc><ip>123.60.146.162</ip></dc> | |||||
| <dc><ip>120.46.183.86</ip></dc> | |||||
| </inter> | |||||
| </attribute> | |||||
| </setting> | |||||
| @@ -4,7 +4,7 @@ import ( | |||||
| "database/sql" | "database/sql" | ||||
| "github.com/jmoiron/sqlx" | "github.com/jmoiron/sqlx" | ||||
| "gitlink.org.cn/cloudream/common/utils/math" | |||||
| "gitlink.org.cn/cloudream/common/utils/math2" | |||||
| ) | ) | ||||
| const ( | const ( | ||||
| @@ -27,7 +27,7 @@ func BatchNamedExec[T any](ctx SQLContext, sql string, argCnt int, arr []T, call | |||||
| batchSize := maxPlaceholderCount / argCnt | batchSize := maxPlaceholderCount / argCnt | ||||
| for len(arr) > 0 { | for len(arr) > 0 { | ||||
| curBatchSize := math.Min(batchSize, len(arr)) | |||||
| curBatchSize := math2.Min(batchSize, len(arr)) | |||||
| ret, err := ctx.NamedExec(sql, arr[:curBatchSize]) | ret, err := ctx.NamedExec(sql, arr[:curBatchSize]) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -59,7 +59,7 @@ func BatchNamedQuery[T any](ctx SQLContext, sql string, argCnt int, arr []T, cal | |||||
| batchSize := maxPlaceholderCount / argCnt | batchSize := maxPlaceholderCount / argCnt | ||||
| for len(arr) > 0 { | for len(arr) > 0 { | ||||
| curBatchSize := math.Min(batchSize, len(arr)) | |||||
| curBatchSize := math2.Min(batchSize, len(arr)) | |||||
| ret, err := ctx.NamedQuery(sql, arr[:curBatchSize]) | ret, err := ctx.NamedQuery(sql, arr[:curBatchSize]) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -0,0 +1,6 @@ | |||||
| package downloader | |||||
| type Config struct { | |||||
| // EC模式的Object的条带缓存数量 | |||||
| MaxStripCacheCount int `json:"maxStripCacheCount"` | |||||
| } | |||||
| @@ -0,0 +1,123 @@ | |||||
| package downloader | |||||
| import ( | |||||
| "fmt" | |||||
| "io" | |||||
| lru "github.com/hashicorp/golang-lru/v2" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/iterator" | |||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | |||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | |||||
| stgmod "gitlink.org.cn/cloudream/storage/common/models" | |||||
| coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator" | |||||
| ) | |||||
| const ( | |||||
| DefaultMaxStripCacheCount = 128 | |||||
| ) | |||||
| type DownloadIterator = iterator.Iterator[*Downloading] | |||||
| type DownloadReqeust struct { | |||||
| ObjectID cdssdk.ObjectID | |||||
| Offset int64 | |||||
| Length int64 | |||||
| } | |||||
| type downloadReqeust2 struct { | |||||
| Detail *stgmod.ObjectDetail | |||||
| Raw DownloadReqeust | |||||
| } | |||||
| type Downloading struct { | |||||
| Object *cdssdk.Object | |||||
| File io.ReadCloser // 文件流,如果文件不存在,那么为nil | |||||
| Request DownloadReqeust | |||||
| } | |||||
| type Downloader struct { | |||||
| strips *StripCache | |||||
| } | |||||
| func NewDownloader(cfg Config) Downloader { | |||||
| if cfg.MaxStripCacheCount == 0 { | |||||
| cfg.MaxStripCacheCount = DefaultMaxStripCacheCount | |||||
| } | |||||
| ch, _ := lru.New[ECStripKey, ObjectECStrip](cfg.MaxStripCacheCount) | |||||
| return Downloader{ | |||||
| strips: ch, | |||||
| } | |||||
| } | |||||
| func (d *Downloader) DownloadObjects(reqs []DownloadReqeust) DownloadIterator { | |||||
| coorCli, err := stgglb.CoordinatorMQPool.Acquire() | |||||
| if err != nil { | |||||
| return iterator.FuseError[*Downloading](fmt.Errorf("new coordinator client: %w", err)) | |||||
| } | |||||
| defer stgglb.CoordinatorMQPool.Release(coorCli) | |||||
| objIDs := make([]cdssdk.ObjectID, len(reqs)) | |||||
| for i, req := range reqs { | |||||
| objIDs[i] = req.ObjectID | |||||
| } | |||||
| if len(objIDs) == 0 { | |||||
| return iterator.Empty[*Downloading]() | |||||
| } | |||||
| objDetails, err := coorCli.GetObjectDetails(coormq.ReqGetObjectDetails(objIDs)) | |||||
| if err != nil { | |||||
| return iterator.FuseError[*Downloading](fmt.Errorf("request to coordinator: %w", err)) | |||||
| } | |||||
| req2s := make([]downloadReqeust2, len(reqs)) | |||||
| for i, req := range reqs { | |||||
| req2s[i] = downloadReqeust2{ | |||||
| Detail: objDetails.Objects[i], | |||||
| Raw: req, | |||||
| } | |||||
| } | |||||
| return NewDownloadObjectIterator(d, req2s) | |||||
| } | |||||
| func (d *Downloader) DownloadPackage(pkgID cdssdk.PackageID) DownloadIterator { | |||||
| coorCli, err := stgglb.CoordinatorMQPool.Acquire() | |||||
| if err != nil { | |||||
| return iterator.FuseError[*Downloading](fmt.Errorf("new coordinator client: %w", err)) | |||||
| } | |||||
| defer stgglb.CoordinatorMQPool.Release(coorCli) | |||||
| pkgDetail, err := coorCli.GetPackageObjectDetails(coormq.ReqGetPackageObjectDetails(pkgID)) | |||||
| if err != nil { | |||||
| return iterator.FuseError[*Downloading](fmt.Errorf("request to coordinator: %w", err)) | |||||
| } | |||||
| req2s := make([]downloadReqeust2, len(pkgDetail.Objects)) | |||||
| for i, objDetail := range pkgDetail.Objects { | |||||
| dt := objDetail | |||||
| req2s[i] = downloadReqeust2{ | |||||
| Detail: &dt, | |||||
| Raw: DownloadReqeust{ | |||||
| ObjectID: objDetail.Object.ObjectID, | |||||
| Offset: 0, | |||||
| Length: objDetail.Object.Size, | |||||
| }, | |||||
| } | |||||
| } | |||||
| return NewDownloadObjectIterator(d, req2s) | |||||
| } | |||||
| type ObjectECStrip struct { | |||||
| Data []byte | |||||
| ObjectFileHash string // 添加这条缓存时,Object的FileHash | |||||
| } | |||||
| type ECStripKey struct { | |||||
| ObjectID cdssdk.ObjectID | |||||
| StripPosition int64 | |||||
| } | |||||
| type StripCache = lru.Cache[ECStripKey, ObjectECStrip] | |||||
| @@ -0,0 +1,148 @@ | |||||
| package downloader | |||||
| import ( | |||||
| "fmt" | |||||
| "io" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/ipfs" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | |||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch/plans" | |||||
| ) | |||||
| type IPFSReader struct { | |||||
| node cdssdk.Node | |||||
| fileHash string | |||||
| stream io.ReadCloser | |||||
| offset int64 | |||||
| } | |||||
| func NewIPFSReader(node cdssdk.Node, fileHash string) *IPFSReader { | |||||
| return &IPFSReader{ | |||||
| node: node, | |||||
| fileHash: fileHash, | |||||
| } | |||||
| } | |||||
| func NewIPFSReaderWithRange(node cdssdk.Node, fileHash string, rng ipfs.ReadOption) io.ReadCloser { | |||||
| str := &IPFSReader{ | |||||
| node: node, | |||||
| fileHash: fileHash, | |||||
| } | |||||
| str.Seek(rng.Offset, io.SeekStart) | |||||
| if rng.Length > 0 { | |||||
| return io2.Length(str, rng.Length) | |||||
| } | |||||
| return str | |||||
| } | |||||
| func (r *IPFSReader) Seek(offset int64, whence int) (int64, error) { | |||||
| if whence == io.SeekEnd { | |||||
| return 0, fmt.Errorf("seek end not supported") | |||||
| } | |||||
| if whence == io.SeekCurrent { | |||||
| return 0, fmt.Errorf("seek current not supported") | |||||
| } | |||||
| if r.stream == nil { | |||||
| r.offset = offset | |||||
| return r.offset, nil | |||||
| } | |||||
| // 如果文件流已经打开,那么如果seek的位置和当前位置不同,那么需要重新打开文件流 | |||||
| if offset != r.offset { | |||||
| var err error | |||||
| r.stream.Close() | |||||
| r.offset = offset | |||||
| r.stream, err = r.openStream() | |||||
| if err != nil { | |||||
| return 0, fmt.Errorf("reopen stream: %w", err) | |||||
| } | |||||
| } | |||||
| return r.offset, nil | |||||
| } | |||||
| func (r *IPFSReader) Read(buf []byte) (int, error) { | |||||
| if r.stream == nil { | |||||
| var err error | |||||
| r.stream, err = r.openStream() | |||||
| if err != nil { | |||||
| return 0, err | |||||
| } | |||||
| } | |||||
| n, err := r.stream.Read(buf) | |||||
| r.offset += int64(n) | |||||
| return n, err | |||||
| } | |||||
| func (r *IPFSReader) Close() error { | |||||
| if r.stream != nil { | |||||
| return r.stream.Close() | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func (r *IPFSReader) openStream() (io.ReadCloser, error) { | |||||
| if stgglb.IPFSPool != nil { | |||||
| logger.Infof("try to use local IPFS to download file") | |||||
| reader, err := r.fromLocalIPFS() | |||||
| if err == nil { | |||||
| return reader, nil | |||||
| } | |||||
| logger.Warnf("download from local IPFS failed, so try to download from node %v, err: %s", r.node.Name, err.Error()) | |||||
| } | |||||
| return r.fromNode() | |||||
| } | |||||
| func (r *IPFSReader) fromNode() (io.ReadCloser, error) { | |||||
| planBld := plans.NewPlanBuilder() | |||||
| fileStr := planBld.AtAgent(r.node).IPFSRead(r.fileHash, ipfs.ReadOption{ | |||||
| Offset: r.offset, | |||||
| Length: -1, | |||||
| }).ToExecutor() | |||||
| plan, err := planBld.Build() | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("building plan: %w", err) | |||||
| } | |||||
| waiter, err := plans.Execute(*plan) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("execute plan: %w", err) | |||||
| } | |||||
| go func() { | |||||
| waiter.Wait() | |||||
| }() | |||||
| return waiter.ReadStream(fileStr) | |||||
| } | |||||
| func (r *IPFSReader) fromLocalIPFS() (io.ReadCloser, error) { | |||||
| ipfsCli, err := stgglb.IPFSPool.Acquire() | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("new ipfs client: %w", err) | |||||
| } | |||||
| reader, err := ipfsCli.OpenRead(r.fileHash, ipfs.ReadOption{ | |||||
| Offset: r.offset, | |||||
| Length: -1, | |||||
| }) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("read ipfs file failed, err: %w", err) | |||||
| } | |||||
| reader = io2.AfterReadClosed(reader, func(io.ReadCloser) { | |||||
| ipfsCli.Close() | |||||
| }) | |||||
| return reader, nil | |||||
| } | |||||
| @@ -1,4 +1,4 @@ | |||||
| package iterator | |||||
| package downloader | |||||
| import ( | import ( | ||||
| "fmt" | "fmt" | ||||
| @@ -9,26 +9,23 @@ import ( | |||||
| "github.com/samber/lo" | "github.com/samber/lo" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/bitmap" | "gitlink.org.cn/cloudream/common/pkgs/bitmap" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/ipfs" | |||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| "gitlink.org.cn/cloudream/common/utils/math2" | |||||
| "gitlink.org.cn/cloudream/common/utils/sort2" | "gitlink.org.cn/cloudream/common/utils/sort2" | ||||
| "gitlink.org.cn/cloudream/common/utils/sync2" | |||||
| "gitlink.org.cn/cloudream/storage/common/consts" | "gitlink.org.cn/cloudream/storage/common/consts" | ||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | stgglb "gitlink.org.cn/cloudream/storage/common/globals" | ||||
| stgmod "gitlink.org.cn/cloudream/storage/common/models" | stgmod "gitlink.org.cn/cloudream/storage/common/models" | ||||
| stgmodels "gitlink.org.cn/cloudream/storage/common/models" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/distlock" | "gitlink.org.cn/cloudream/storage/common/pkgs/distlock" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ec" | "gitlink.org.cn/cloudream/storage/common/pkgs/ec" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/iterator" | |||||
| coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator" | coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator" | ||||
| ) | ) | ||||
| type DownloadingObjectIterator = Iterator[*IterDownloadingObject] | |||||
| type IterDownloadingObject struct { | |||||
| Object cdssdk.Object | |||||
| File io.ReadCloser | |||||
| } | |||||
| var errNoDirectReadBlock = fmt.Errorf("no direct read block") | |||||
| type DownloadNodeInfo struct { | type DownloadNodeInfo struct { | ||||
| Node cdssdk.Node | Node cdssdk.Node | ||||
| @@ -43,23 +40,23 @@ type DownloadContext struct { | |||||
| type DownloadObjectIterator struct { | type DownloadObjectIterator struct { | ||||
| OnClosing func() | OnClosing func() | ||||
| objectDetails []stgmodels.ObjectDetail | |||||
| currentIndex int | |||||
| inited bool | |||||
| downloader *Downloader | |||||
| reqs []downloadReqeust2 | |||||
| currentIndex int | |||||
| inited bool | |||||
| downloadCtx *DownloadContext | |||||
| coorCli *coormq.Client | |||||
| allNodes map[cdssdk.NodeID]cdssdk.Node | |||||
| coorCli *coormq.Client | |||||
| allNodes map[cdssdk.NodeID]cdssdk.Node | |||||
| } | } | ||||
| func NewDownloadObjectIterator(objectDetails []stgmodels.ObjectDetail, downloadCtx *DownloadContext) *DownloadObjectIterator { | |||||
| func NewDownloadObjectIterator(downloader *Downloader, downloadObjs []downloadReqeust2) *DownloadObjectIterator { | |||||
| return &DownloadObjectIterator{ | return &DownloadObjectIterator{ | ||||
| objectDetails: objectDetails, | |||||
| downloadCtx: downloadCtx, | |||||
| downloader: downloader, | |||||
| reqs: downloadObjs, | |||||
| } | } | ||||
| } | } | ||||
| func (i *DownloadObjectIterator) MoveNext() (*IterDownloadingObject, error) { | |||||
| func (i *DownloadObjectIterator) MoveNext() (*Downloading, error) { | |||||
| if !i.inited { | if !i.inited { | ||||
| if err := i.init(); err != nil { | if err := i.init(); err != nil { | ||||
| return nil, err | return nil, err | ||||
| @@ -68,8 +65,8 @@ func (i *DownloadObjectIterator) MoveNext() (*IterDownloadingObject, error) { | |||||
| i.inited = true | i.inited = true | ||||
| } | } | ||||
| if i.currentIndex >= len(i.objectDetails) { | |||||
| return nil, ErrNoMoreItem | |||||
| if i.currentIndex >= len(i.reqs) { | |||||
| return nil, iterator.ErrNoMoreItem | |||||
| } | } | ||||
| item, err := i.doMove() | item, err := i.doMove() | ||||
| @@ -85,12 +82,12 @@ func (i *DownloadObjectIterator) init() error { | |||||
| i.coorCli = coorCli | i.coorCli = coorCli | ||||
| allNodeIDs := make(map[cdssdk.NodeID]bool) | allNodeIDs := make(map[cdssdk.NodeID]bool) | ||||
| for _, obj := range i.objectDetails { | |||||
| for _, p := range obj.PinnedAt { | |||||
| for _, obj := range i.reqs { | |||||
| for _, p := range obj.Detail.PinnedAt { | |||||
| allNodeIDs[p] = true | allNodeIDs[p] = true | ||||
| } | } | ||||
| for _, b := range obj.Blocks { | |||||
| for _, b := range obj.Detail.Blocks { | |||||
| allNodeIDs[b.NodeID] = true | allNodeIDs[b.NodeID] = true | ||||
| } | } | ||||
| } | } | ||||
| @@ -108,45 +105,55 @@ func (i *DownloadObjectIterator) init() error { | |||||
| return nil | return nil | ||||
| } | } | ||||
| func (iter *DownloadObjectIterator) doMove() (*IterDownloadingObject, error) { | |||||
| obj := iter.objectDetails[iter.currentIndex] | |||||
| func (iter *DownloadObjectIterator) doMove() (*Downloading, error) { | |||||
| req := iter.reqs[iter.currentIndex] | |||||
| if req.Detail == nil { | |||||
| return &Downloading{ | |||||
| Object: nil, | |||||
| File: nil, | |||||
| Request: req.Raw, | |||||
| }, nil | |||||
| } | |||||
| switch red := obj.Object.Redundancy.(type) { | |||||
| switch red := req.Detail.Object.Redundancy.(type) { | |||||
| case *cdssdk.NoneRedundancy: | case *cdssdk.NoneRedundancy: | ||||
| reader, err := iter.downloadNoneOrRepObject(obj) | |||||
| reader, err := iter.downloadNoneOrRepObject(req) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("downloading object: %w", err) | return nil, fmt.Errorf("downloading object: %w", err) | ||||
| } | } | ||||
| return &IterDownloadingObject{ | |||||
| Object: obj.Object, | |||||
| File: reader, | |||||
| return &Downloading{ | |||||
| Object: &req.Detail.Object, | |||||
| File: reader, | |||||
| Request: req.Raw, | |||||
| }, nil | }, nil | ||||
| case *cdssdk.RepRedundancy: | case *cdssdk.RepRedundancy: | ||||
| reader, err := iter.downloadNoneOrRepObject(obj) | |||||
| reader, err := iter.downloadNoneOrRepObject(req) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("downloading rep object: %w", err) | return nil, fmt.Errorf("downloading rep object: %w", err) | ||||
| } | } | ||||
| return &IterDownloadingObject{ | |||||
| Object: obj.Object, | |||||
| File: reader, | |||||
| return &Downloading{ | |||||
| Object: &req.Detail.Object, | |||||
| File: reader, | |||||
| Request: req.Raw, | |||||
| }, nil | }, nil | ||||
| case *cdssdk.ECRedundancy: | case *cdssdk.ECRedundancy: | ||||
| reader, err := iter.downloadECObject(obj, red) | |||||
| reader, err := iter.downloadECObject(req, red) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("downloading ec object: %w", err) | return nil, fmt.Errorf("downloading ec object: %w", err) | ||||
| } | } | ||||
| return &IterDownloadingObject{ | |||||
| Object: obj.Object, | |||||
| File: reader, | |||||
| return &Downloading{ | |||||
| Object: &req.Detail.Object, | |||||
| File: reader, | |||||
| Request: req.Raw, | |||||
| }, nil | }, nil | ||||
| } | } | ||||
| return nil, fmt.Errorf("unsupported redundancy type: %v", reflect.TypeOf(obj.Object.Redundancy)) | |||||
| return nil, fmt.Errorf("unsupported redundancy type: %v", reflect.TypeOf(req.Detail.Object.Redundancy)) | |||||
| } | } | ||||
| func (i *DownloadObjectIterator) Close() { | func (i *DownloadObjectIterator) Close() { | ||||
| @@ -155,15 +162,20 @@ func (i *DownloadObjectIterator) Close() { | |||||
| } | } | ||||
| } | } | ||||
| func (iter *DownloadObjectIterator) downloadNoneOrRepObject(obj stgmodels.ObjectDetail) (io.ReadCloser, error) { | |||||
| func (iter *DownloadObjectIterator) downloadNoneOrRepObject(obj downloadReqeust2) (io.ReadCloser, error) { | |||||
| allNodes, err := iter.sortDownloadNodes(obj) | allNodes, err := iter.sortDownloadNodes(obj) | ||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| bsc, blocks := iter.getMinReadingBlockSolution(allNodes, 1) | bsc, blocks := iter.getMinReadingBlockSolution(allNodes, 1) | ||||
| osc, node := iter.getMinReadingObjectSolution(allNodes, 1) | osc, node := iter.getMinReadingObjectSolution(allNodes, 1) | ||||
| if bsc < osc { | if bsc < osc { | ||||
| return downloadFile(iter.downloadCtx, blocks[0].Node, blocks[0].Block.FileHash) | |||||
| return NewIPFSReaderWithRange(blocks[0].Node, blocks[0].Block.FileHash, ipfs.ReadOption{ | |||||
| Offset: obj.Raw.Offset, | |||||
| Length: obj.Raw.Length, | |||||
| }), nil | |||||
| } | } | ||||
| // bsc >= osc,如果osc是MaxFloat64,那么bsc也一定是,也就意味着没有足够块来恢复文件 | // bsc >= osc,如果osc是MaxFloat64,那么bsc也一定是,也就意味着没有足够块来恢复文件 | ||||
| @@ -171,48 +183,118 @@ func (iter *DownloadObjectIterator) downloadNoneOrRepObject(obj stgmodels.Object | |||||
| return nil, fmt.Errorf("no node has this object") | return nil, fmt.Errorf("no node has this object") | ||||
| } | } | ||||
| return downloadFile(iter.downloadCtx, *node, obj.Object.FileHash) | |||||
| return NewIPFSReaderWithRange(*node, obj.Detail.Object.FileHash, ipfs.ReadOption{ | |||||
| Offset: obj.Raw.Offset, | |||||
| Length: obj.Raw.Length, | |||||
| }), nil | |||||
| } | } | ||||
| func (iter *DownloadObjectIterator) downloadECObject(obj stgmodels.ObjectDetail, ecRed *cdssdk.ECRedundancy) (io.ReadCloser, error) { | |||||
| allNodes, err := iter.sortDownloadNodes(obj) | |||||
| func (iter *DownloadObjectIterator) downloadECObject(req downloadReqeust2, ecRed *cdssdk.ECRedundancy) (io.ReadCloser, error) { | |||||
| allNodes, err := iter.sortDownloadNodes(req) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| bsc, blocks := iter.getMinReadingBlockSolution(allNodes, ecRed.K) | bsc, blocks := iter.getMinReadingBlockSolution(allNodes, ecRed.K) | ||||
| osc, node := iter.getMinReadingObjectSolution(allNodes, ecRed.K) | osc, node := iter.getMinReadingObjectSolution(allNodes, ecRed.K) | ||||
| if bsc < osc { | if bsc < osc { | ||||
| var fileStrs []io.ReadCloser | |||||
| var fileStrs []*IPFSReader | |||||
| for _, b := range blocks { | |||||
| str := NewIPFSReader(b.Node, b.Block.FileHash) | |||||
| rs, err := ec.NewRs(ecRed.K, ecRed.N, ecRed.ChunkSize) | |||||
| fileStrs = append(fileStrs, str) | |||||
| } | |||||
| rs, err := ec.NewRs(ecRed.K, ecRed.N) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("new rs: %w", err) | return nil, fmt.Errorf("new rs: %w", err) | ||||
| } | } | ||||
| for i, b := range blocks { | |||||
| str, err := downloadFile(iter.downloadCtx, b.Node, b.Block.FileHash) | |||||
| if err != nil { | |||||
| for i -= 1; i >= 0; i-- { | |||||
| fileStrs[i].Close() | |||||
| pr, pw := io.Pipe() | |||||
| go func() { | |||||
| defer func() { | |||||
| for _, str := range fileStrs { | |||||
| str.Close() | |||||
| } | } | ||||
| return nil, fmt.Errorf("donwloading file: %w", err) | |||||
| }() | |||||
| readPos := req.Raw.Offset | |||||
| totalReadLen := req.Detail.Object.Size - req.Raw.Offset | |||||
| if req.Raw.Length >= 0 { | |||||
| totalReadLen = req.Raw.Length | |||||
| } | } | ||||
| fileStrs = append(fileStrs, str) | |||||
| } | |||||
| for totalReadLen > 0 { | |||||
| curStripPos := readPos / int64(ecRed.K) / int64(ecRed.ChunkSize) | |||||
| curStripPosInBytes := curStripPos * int64(ecRed.K) * int64(ecRed.ChunkSize) | |||||
| nextStripPosInBytes := (curStripPos + 1) * int64(ecRed.K) * int64(ecRed.ChunkSize) | |||||
| curReadLen := math2.Min(totalReadLen, nextStripPosInBytes-readPos) | |||||
| readRelativePos := readPos - curStripPosInBytes | |||||
| cacheKey := ECStripKey{ | |||||
| ObjectID: req.Detail.Object.ObjectID, | |||||
| StripPosition: curStripPos, | |||||
| } | |||||
| fileReaders, filesCloser := myio.ToReaders(fileStrs) | |||||
| cache, ok := iter.downloader.strips.Get(cacheKey) | |||||
| if ok { | |||||
| if cache.ObjectFileHash == req.Detail.Object.FileHash { | |||||
| err := io2.WriteAll(pw, cache.Data[readRelativePos:readRelativePos+curReadLen]) | |||||
| if err != nil { | |||||
| pw.CloseWithError(err) | |||||
| break | |||||
| } | |||||
| totalReadLen -= curReadLen | |||||
| readPos += curReadLen | |||||
| continue | |||||
| } | |||||
| // 如果Object的Hash和Cache的Hash不一致,说明Cache是无效的,需要重新下载 | |||||
| iter.downloader.strips.Remove(cacheKey) | |||||
| } | |||||
| var indexes []int | |||||
| for _, b := range blocks { | |||||
| indexes = append(indexes, b.Block.Index) | |||||
| } | |||||
| for _, str := range fileStrs { | |||||
| _, err := str.Seek(curStripPosInBytes, io.SeekStart) | |||||
| if err != nil { | |||||
| pw.CloseWithError(err) | |||||
| break | |||||
| } | |||||
| } | |||||
| outputs, outputsCloser := myio.ToReaders(rs.ReconstructData(fileReaders, indexes)) | |||||
| return myio.AfterReadClosed(myio.Length(myio.ChunkedJoin(outputs, int(ecRed.ChunkSize)), obj.Object.Size), func(c io.ReadCloser) { | |||||
| filesCloser() | |||||
| outputsCloser() | |||||
| }), nil | |||||
| dataBuf := make([]byte, int64(ecRed.K*ecRed.ChunkSize)) | |||||
| blockArrs := make([][]byte, ecRed.N) | |||||
| for _, b := range blocks { | |||||
| if b.Block.Index < ecRed.K { | |||||
| blockArrs[b.Block.Index] = dataBuf[b.Block.Index*ecRed.ChunkSize : (b.Block.Index+1)*ecRed.ChunkSize] | |||||
| } else { | |||||
| blockArrs[b.Block.Index] = make([]byte, ecRed.ChunkSize) | |||||
| } | |||||
| } | |||||
| err := sync2.ParallelDo(blocks, func(b downloadBlock, idx int) error { | |||||
| _, err := io.ReadFull(fileStrs[idx], blockArrs[b.Block.Index]) | |||||
| return err | |||||
| }) | |||||
| if err != nil { | |||||
| pw.CloseWithError(err) | |||||
| break | |||||
| } | |||||
| err = rs.ReconstructData(blockArrs) | |||||
| if err != nil { | |||||
| pw.CloseWithError(err) | |||||
| break | |||||
| } | |||||
| iter.downloader.strips.Add(cacheKey, ObjectECStrip{ | |||||
| Data: dataBuf, | |||||
| ObjectFileHash: req.Detail.Object.FileHash, | |||||
| }) | |||||
| // 下次循环就能从Cache中读取数据 | |||||
| } | |||||
| }() | |||||
| return pr, nil | |||||
| } | } | ||||
| // bsc >= osc,如果osc是MaxFloat64,那么bsc也一定是,也就意味着没有足够块来恢复文件 | // bsc >= osc,如果osc是MaxFloat64,那么bsc也一定是,也就意味着没有足够块来恢复文件 | ||||
| @@ -220,24 +302,27 @@ func (iter *DownloadObjectIterator) downloadECObject(obj stgmodels.ObjectDetail, | |||||
| return nil, fmt.Errorf("no enough blocks to reconstruct the file, want %d, get only %d", ecRed.K, len(blocks)) | return nil, fmt.Errorf("no enough blocks to reconstruct the file, want %d, get only %d", ecRed.K, len(blocks)) | ||||
| } | } | ||||
| return downloadFile(iter.downloadCtx, *node, obj.Object.FileHash) | |||||
| return NewIPFSReaderWithRange(*node, req.Detail.Object.FileHash, ipfs.ReadOption{ | |||||
| Offset: req.Raw.Offset, | |||||
| Length: req.Raw.Length, | |||||
| }), nil | |||||
| } | } | ||||
| func (iter *DownloadObjectIterator) sortDownloadNodes(obj stgmodels.ObjectDetail) ([]*DownloadNodeInfo, error) { | |||||
| func (iter *DownloadObjectIterator) sortDownloadNodes(req downloadReqeust2) ([]*DownloadNodeInfo, error) { | |||||
| var nodeIDs []cdssdk.NodeID | var nodeIDs []cdssdk.NodeID | ||||
| for _, id := range obj.PinnedAt { | |||||
| for _, id := range req.Detail.PinnedAt { | |||||
| if !lo.Contains(nodeIDs, id) { | if !lo.Contains(nodeIDs, id) { | ||||
| nodeIDs = append(nodeIDs, id) | nodeIDs = append(nodeIDs, id) | ||||
| } | } | ||||
| } | } | ||||
| for _, b := range obj.Blocks { | |||||
| for _, b := range req.Detail.Blocks { | |||||
| if !lo.Contains(nodeIDs, b.NodeID) { | if !lo.Contains(nodeIDs, b.NodeID) { | ||||
| nodeIDs = append(nodeIDs, b.NodeID) | nodeIDs = append(nodeIDs, b.NodeID) | ||||
| } | } | ||||
| } | } | ||||
| downloadNodeMap := make(map[cdssdk.NodeID]*DownloadNodeInfo) | downloadNodeMap := make(map[cdssdk.NodeID]*DownloadNodeInfo) | ||||
| for _, id := range obj.PinnedAt { | |||||
| for _, id := range req.Detail.PinnedAt { | |||||
| node, ok := downloadNodeMap[id] | node, ok := downloadNodeMap[id] | ||||
| if !ok { | if !ok { | ||||
| mod := iter.allNodes[id] | mod := iter.allNodes[id] | ||||
| @@ -252,7 +337,7 @@ func (iter *DownloadObjectIterator) sortDownloadNodes(obj stgmodels.ObjectDetail | |||||
| node.ObjectPinned = true | node.ObjectPinned = true | ||||
| } | } | ||||
| for _, b := range obj.Blocks { | |||||
| for _, b := range req.Detail.Blocks { | |||||
| node, ok := downloadNodeMap[b.NodeID] | node, ok := downloadNodeMap[b.NodeID] | ||||
| if !ok { | if !ok { | ||||
| mod := iter.allNodes[b.NodeID] | mod := iter.allNodes[b.NodeID] | ||||
| @@ -326,62 +411,3 @@ func (iter *DownloadObjectIterator) getNodeDistance(node cdssdk.Node) float64 { | |||||
| return consts.NodeDistanceOther | return consts.NodeDistanceOther | ||||
| } | } | ||||
| func downloadFile(ctx *DownloadContext, node cdssdk.Node, fileHash string) (io.ReadCloser, error) { | |||||
| // 如果客户端与节点在同一个地域,则使用内网地址连接节点 | |||||
| nodeIP := node.ExternalIP | |||||
| grpcPort := node.ExternalGRPCPort | |||||
| if node.LocationID == stgglb.Local.LocationID { | |||||
| nodeIP = node.LocalIP | |||||
| grpcPort = node.LocalGRPCPort | |||||
| logger.Infof("client and node %d are at the same location, use local ip", node.NodeID) | |||||
| } | |||||
| if stgglb.IPFSPool != nil { | |||||
| logger.Infof("try to use local IPFS to download file") | |||||
| reader, err := downloadFromLocalIPFS(ctx, fileHash) | |||||
| if err == nil { | |||||
| return reader, nil | |||||
| } | |||||
| logger.Warnf("download from local IPFS failed, so try to download from node %s, err: %s", nodeIP, err.Error()) | |||||
| } | |||||
| return downloadFromNode(ctx, node.NodeID, nodeIP, grpcPort, fileHash) | |||||
| } | |||||
| func downloadFromNode(ctx *DownloadContext, nodeID cdssdk.NodeID, nodeIP string, grpcPort int, fileHash string) (io.ReadCloser, error) { | |||||
| agtCli, err := stgglb.AgentRPCPool.Acquire(nodeIP, grpcPort) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("new agent grpc client: %w", err) | |||||
| } | |||||
| reader, err := agtCli.GetIPFSFile(fileHash) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("getting ipfs file: %w", err) | |||||
| } | |||||
| reader = myio.AfterReadClosed(reader, func(io.ReadCloser) { | |||||
| agtCli.Close() | |||||
| }) | |||||
| return reader, nil | |||||
| } | |||||
| func downloadFromLocalIPFS(ctx *DownloadContext, fileHash string) (io.ReadCloser, error) { | |||||
| ipfsCli, err := stgglb.IPFSPool.Acquire() | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("new ipfs client: %w", err) | |||||
| } | |||||
| reader, err := ipfsCli.OpenRead(fileHash) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("read ipfs file failed, err: %w", err) | |||||
| } | |||||
| reader = myio.AfterReadClosed(reader, func(io.ReadCloser) { | |||||
| ipfsCli.Close() | |||||
| }) | |||||
| return reader, nil | |||||
| } | |||||
| @@ -1,38 +1,44 @@ | |||||
| package ec | package ec | ||||
| import ( | import ( | ||||
| "fmt" | |||||
| "os" | |||||
| "github.com/baohan10/reedsolomon" | |||||
| "github.com/klauspost/reedsolomon" | |||||
| ) | ) | ||||
| type rs struct { | |||||
| r *(reedsolomon.ReedSolomon) | |||||
| ecN int | |||||
| ecK int | |||||
| ecP int | |||||
| type Rs struct { | |||||
| encoder reedsolomon.Encoder | |||||
| ecN int | |||||
| ecK int | |||||
| ecP int | |||||
| } | } | ||||
| func NewRsEnc(ecK int, ecN int) *rs { | |||||
| enc := rs{ | |||||
| ecN: ecN, | |||||
| ecK: ecK, | |||||
| ecP: ecN - ecK, | |||||
| func NewRs(k int, n int) (*Rs, error) { | |||||
| enc := Rs{ | |||||
| ecN: n, | |||||
| ecK: k, | |||||
| ecP: n - k, | |||||
| } | } | ||||
| enc.r = reedsolomon.GetReedSolomonIns(ecK, ecN) | |||||
| return &enc | |||||
| } | |||||
| func (r *rs) Encode(all [][]byte) { | |||||
| r.r.Encode(all) | |||||
| encoder, err := reedsolomon.New(k, n-k) | |||||
| enc.encoder = encoder | |||||
| return &enc, err | |||||
| } | } | ||||
| func (r *rs) Repair(all [][]byte) error { | |||||
| return r.r.Reconstruct(all) | |||||
| // 任意k个块恢复出所有原始的数据块。 | |||||
| // blocks的长度必须为N,且至少有K个元素不为nil | |||||
| func (r *Rs) ReconstructData(blocks [][]byte) error { | |||||
| outIndexes := make([]int, r.ecK) | |||||
| for i := 0; i < r.ecK; i++ { | |||||
| outIndexes[i] = i | |||||
| } | |||||
| return r.ReconstructAny(blocks, outIndexes) | |||||
| } | } | ||||
| func checkErr(err error) { | |||||
| if err != nil { | |||||
| fmt.Fprintf(os.Stderr, "Error: %s", err.Error()) | |||||
| // 重建指定的任意块,可以是数据块或校验块。 | |||||
| // 在input上原地重建,因此input的长度必须为N。 | |||||
| func (r *Rs) ReconstructAny(blocks [][]byte, outBlockIdxes []int) error { | |||||
| required := make([]bool, len(blocks)) | |||||
| for _, idx := range outBlockIdxes { | |||||
| required[idx] = true | |||||
| } | } | ||||
| return r.encoder.ReconstructAny(blocks, required) | |||||
| } | } | ||||
| @@ -11,7 +11,7 @@ import ( | |||||
| func Test_EncodeReconstruct(t *testing.T) { | func Test_EncodeReconstruct(t *testing.T) { | ||||
| Convey("编码后使用校验块重建数据", t, func() { | Convey("编码后使用校验块重建数据", t, func() { | ||||
| rs, err := NewRs(2, 3, 5) | |||||
| rs, err := NewStreamRs(2, 3, 5) | |||||
| So(err, ShouldBeNil) | So(err, ShouldBeNil) | ||||
| outputs := rs.EncodeAll([]io.Reader{ | outputs := rs.EncodeAll([]io.Reader{ | ||||
| @@ -4,10 +4,10 @@ import ( | |||||
| "io" | "io" | ||||
| "github.com/klauspost/reedsolomon" | "github.com/klauspost/reedsolomon" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| ) | ) | ||||
| type Rs struct { | |||||
| type StreamRs struct { | |||||
| encoder reedsolomon.Encoder | encoder reedsolomon.Encoder | ||||
| ecN int | ecN int | ||||
| ecK int | ecK int | ||||
| @@ -15,8 +15,8 @@ type Rs struct { | |||||
| chunkSize int | chunkSize int | ||||
| } | } | ||||
| func NewRs(k int, n int, chunkSize int) (*Rs, error) { | |||||
| enc := Rs{ | |||||
| func NewStreamRs(k int, n int, chunkSize int) (*StreamRs, error) { | |||||
| enc := StreamRs{ | |||||
| ecN: n, | ecN: n, | ||||
| ecK: k, | ecK: k, | ||||
| ecP: n - k, | ecP: n - k, | ||||
| @@ -28,7 +28,7 @@ func NewRs(k int, n int, chunkSize int) (*Rs, error) { | |||||
| } | } | ||||
| // 编码。仅输出校验块 | // 编码。仅输出校验块 | ||||
| func (r *Rs) Encode(input []io.Reader) []io.ReadCloser { | |||||
| func (r *StreamRs) Encode(input []io.Reader) []io.ReadCloser { | |||||
| outReaders := make([]io.ReadCloser, r.ecP) | outReaders := make([]io.ReadCloser, r.ecP) | ||||
| outWriters := make([]*io.PipeWriter, r.ecP) | outWriters := make([]*io.PipeWriter, r.ecP) | ||||
| for i := 0; i < r.ecP; i++ { | for i := 0; i < r.ecP; i++ { | ||||
| @@ -60,7 +60,7 @@ func (r *Rs) Encode(input []io.Reader) []io.ReadCloser { | |||||
| //输出到outWriter | //输出到outWriter | ||||
| for i := range outWriters { | for i := range outWriters { | ||||
| err := myio.WriteAll(outWriters[i], chunks[i+r.ecK]) | |||||
| err := io2.WriteAll(outWriters[i], chunks[i+r.ecK]) | |||||
| if err != nil { | if err != nil { | ||||
| closeErr = err | closeErr = err | ||||
| break loop | break loop | ||||
| @@ -77,7 +77,7 @@ func (r *Rs) Encode(input []io.Reader) []io.ReadCloser { | |||||
| } | } | ||||
| // 编码。输出包含所有的数据块和校验块 | // 编码。输出包含所有的数据块和校验块 | ||||
| func (r *Rs) EncodeAll(input []io.Reader) []io.ReadCloser { | |||||
| func (r *StreamRs) EncodeAll(input []io.Reader) []io.ReadCloser { | |||||
| outReaders := make([]io.ReadCloser, r.ecN) | outReaders := make([]io.ReadCloser, r.ecN) | ||||
| outWriters := make([]*io.PipeWriter, r.ecN) | outWriters := make([]*io.PipeWriter, r.ecN) | ||||
| for i := 0; i < r.ecN; i++ { | for i := 0; i < r.ecN; i++ { | ||||
| @@ -109,7 +109,7 @@ func (r *Rs) EncodeAll(input []io.Reader) []io.ReadCloser { | |||||
| //输出到outWriter | //输出到outWriter | ||||
| for i := range outWriters { | for i := range outWriters { | ||||
| err := myio.WriteAll(outWriters[i], chunks[i]) | |||||
| err := io2.WriteAll(outWriters[i], chunks[i]) | |||||
| if err != nil { | if err != nil { | ||||
| closeErr = err | closeErr = err | ||||
| break loop | break loop | ||||
| @@ -126,7 +126,7 @@ func (r *Rs) EncodeAll(input []io.Reader) []io.ReadCloser { | |||||
| } | } | ||||
| // 降级读,任意k个块恢复出所有原始的数据块。 | // 降级读,任意k个块恢复出所有原始的数据块。 | ||||
| func (r *Rs) ReconstructData(input []io.Reader, inBlockIdx []int) []io.ReadCloser { | |||||
| func (r *StreamRs) ReconstructData(input []io.Reader, inBlockIdx []int) []io.ReadCloser { | |||||
| outIndexes := make([]int, r.ecK) | outIndexes := make([]int, r.ecK) | ||||
| for i := 0; i < r.ecK; i++ { | for i := 0; i < r.ecK; i++ { | ||||
| outIndexes[i] = i | outIndexes[i] = i | ||||
| @@ -137,7 +137,7 @@ func (r *Rs) ReconstructData(input []io.Reader, inBlockIdx []int) []io.ReadClose | |||||
| // 修复,任意k个块恢复指定的数据块。 | // 修复,任意k个块恢复指定的数据块。 | ||||
| // 调用者应该保证input的每一个流长度相同,且均为chunkSize的整数倍 | // 调用者应该保证input的每一个流长度相同,且均为chunkSize的整数倍 | ||||
| func (r *Rs) ReconstructSome(input []io.Reader, inBlockIdx []int, outBlockIdx []int) []io.ReadCloser { | |||||
| func (r *StreamRs) ReconstructSome(input []io.Reader, inBlockIdx []int, outBlockIdx []int) []io.ReadCloser { | |||||
| outReaders := make([]io.ReadCloser, len(outBlockIdx)) | outReaders := make([]io.ReadCloser, len(outBlockIdx)) | ||||
| outWriters := make([]*io.PipeWriter, len(outBlockIdx)) | outWriters := make([]*io.PipeWriter, len(outBlockIdx)) | ||||
| for i := 0; i < len(outBlockIdx); i++ { | for i := 0; i < len(outBlockIdx); i++ { | ||||
| @@ -181,7 +181,7 @@ func (r *Rs) ReconstructSome(input []io.Reader, inBlockIdx []int, outBlockIdx [] | |||||
| //输出到outWriter | //输出到outWriter | ||||
| for i := range outBlockIdx { | for i := range outBlockIdx { | ||||
| err := myio.WriteAll(outWriters[i], chunks[outBlockIdx[i]]) | |||||
| err := io2.WriteAll(outWriters[i], chunks[outBlockIdx[i]]) | |||||
| if err != nil { | if err != nil { | ||||
| closeErr = err | closeErr = err | ||||
| break loop | break loop | ||||
| @@ -204,7 +204,7 @@ func (r *Rs) ReconstructSome(input []io.Reader, inBlockIdx []int, outBlockIdx [] | |||||
| // 重建任意块,包括数据块和校验块。 | // 重建任意块,包括数据块和校验块。 | ||||
| // 当前的实现会把不需要的块都重建出来,所以应该避免使用这个函数。 | // 当前的实现会把不需要的块都重建出来,所以应该避免使用这个函数。 | ||||
| func (r *Rs) ReconstructAny(input []io.Reader, inBlockIdxes []int, outBlockIdxes []int) []io.ReadCloser { | |||||
| func (r *StreamRs) ReconstructAny(input []io.Reader, inBlockIdxes []int, outBlockIdxes []int) []io.ReadCloser { | |||||
| outReaders := make([]io.ReadCloser, len(outBlockIdxes)) | outReaders := make([]io.ReadCloser, len(outBlockIdxes)) | ||||
| outWriters := make([]*io.PipeWriter, len(outBlockIdxes)) | outWriters := make([]*io.PipeWriter, len(outBlockIdxes)) | ||||
| for i := 0; i < len(outBlockIdxes); i++ { | for i := 0; i < len(outBlockIdxes); i++ { | ||||
| @@ -250,7 +250,7 @@ func (r *Rs) ReconstructAny(input []io.Reader, inBlockIdxes []int, outBlockIdxes | |||||
| for i := range outBlockIdxes { | for i := range outBlockIdxes { | ||||
| outIndex := outBlockIdxes[i] | outIndex := outBlockIdxes[i] | ||||
| err := myio.WriteAll(outWriters[i], chunks[outIndex]) | |||||
| err := io2.WriteAll(outWriters[i], chunks[outIndex]) | |||||
| if err != nil { | if err != nil { | ||||
| closeErr = err | closeErr = err | ||||
| break loop | break loop | ||||
| @@ -5,7 +5,7 @@ import ( | |||||
| "io" | "io" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/future" | "gitlink.org.cn/cloudream/common/pkgs/future" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| ) | ) | ||||
| @@ -34,7 +34,7 @@ func (o *ChunkedJoin) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error | |||||
| fut := future.NewSetVoid() | fut := future.NewSetVoid() | ||||
| sw.StreamReady(planID, | sw.StreamReady(planID, | ||||
| ioswitch.NewStream(o.OutputID, | ioswitch.NewStream(o.OutputID, | ||||
| myio.AfterReadClosedOnce(myio.ChunkedJoin(strReaders, o.ChunkSize), func(closer io.ReadCloser) { | |||||
| io2.AfterReadClosedOnce(io2.ChunkedJoin(strReaders, o.ChunkSize), func(closer io.ReadCloser) { | |||||
| fut.SetVoid() | fut.SetVoid() | ||||
| }), | }), | ||||
| ), | ), | ||||
| @@ -4,7 +4,7 @@ import ( | |||||
| "io" | "io" | ||||
| "sync" | "sync" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| ) | ) | ||||
| @@ -24,7 +24,7 @@ func (o *ChunkedSplit) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) erro | |||||
| defer str[0].Stream.Close() | defer str[0].Stream.Close() | ||||
| wg := sync.WaitGroup{} | wg := sync.WaitGroup{} | ||||
| outputs := myio.ChunkedSplit(str[0].Stream, o.ChunkSize, o.StreamCount, myio.ChunkedSplitOption{ | |||||
| outputs := io2.ChunkedSplit(str[0].Stream, o.ChunkSize, o.StreamCount, io2.ChunkedSplitOption{ | |||||
| PaddingZeros: o.PaddingZeros, | PaddingZeros: o.PaddingZeros, | ||||
| }) | }) | ||||
| @@ -33,7 +33,7 @@ func (o *ChunkedSplit) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) erro | |||||
| sw.StreamReady(planID, ioswitch.NewStream( | sw.StreamReady(planID, ioswitch.NewStream( | ||||
| o.OutputIDs[i], | o.OutputIDs[i], | ||||
| myio.AfterReadClosedOnce(outputs[i], func(closer io.ReadCloser) { | |||||
| io2.AfterReadClosedOnce(outputs[i], func(closer io.ReadCloser) { | |||||
| wg.Done() | wg.Done() | ||||
| }), | }), | ||||
| )) | )) | ||||
| @@ -4,7 +4,7 @@ import ( | |||||
| "io" | "io" | ||||
| "sync" | "sync" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| ) | ) | ||||
| @@ -21,13 +21,13 @@ func (o *Clone) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | |||||
| defer strs[0].Stream.Close() | defer strs[0].Stream.Close() | ||||
| wg := sync.WaitGroup{} | wg := sync.WaitGroup{} | ||||
| cloned := myio.Clone(strs[0].Stream, len(o.OutputIDs)) | |||||
| cloned := io2.Clone(strs[0].Stream, len(o.OutputIDs)) | |||||
| for i, s := range cloned { | for i, s := range cloned { | ||||
| wg.Add(1) | wg.Add(1) | ||||
| sw.StreamReady(planID, | sw.StreamReady(planID, | ||||
| ioswitch.NewStream(o.OutputIDs[i], | ioswitch.NewStream(o.OutputIDs[i], | ||||
| myio.AfterReadClosedOnce(s, func(closer io.ReadCloser) { | |||||
| io2.AfterReadClosedOnce(s, func(closer io.ReadCloser) { | |||||
| wg.Done() | wg.Done() | ||||
| }), | }), | ||||
| ), | ), | ||||
| @@ -6,7 +6,7 @@ import ( | |||||
| "sync" | "sync" | ||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ec" | "gitlink.org.cn/cloudream/storage/common/pkgs/ec" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| ) | ) | ||||
| @@ -20,7 +20,7 @@ type ECReconstructAny struct { | |||||
| } | } | ||||
| func (o *ECReconstructAny) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | func (o *ECReconstructAny) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | ||||
| rs, err := ec.NewRs(o.EC.K, o.EC.N, o.EC.ChunkSize) | |||||
| rs, err := ec.NewStreamRs(o.EC.K, o.EC.N, o.EC.ChunkSize) | |||||
| if err != nil { | if err != nil { | ||||
| return fmt.Errorf("new ec: %w", err) | return fmt.Errorf("new ec: %w", err) | ||||
| } | } | ||||
| @@ -45,7 +45,7 @@ func (o *ECReconstructAny) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) | |||||
| wg := sync.WaitGroup{} | wg := sync.WaitGroup{} | ||||
| for i, id := range o.OutputIDs { | for i, id := range o.OutputIDs { | ||||
| wg.Add(1) | wg.Add(1) | ||||
| sw.StreamReady(planID, ioswitch.NewStream(id, myio.AfterReadClosedOnce(outputs[i], func(closer io.ReadCloser) { | |||||
| sw.StreamReady(planID, ioswitch.NewStream(id, io2.AfterReadClosedOnce(outputs[i], func(closer io.ReadCloser) { | |||||
| wg.Done() | wg.Done() | ||||
| }))) | }))) | ||||
| } | } | ||||
| @@ -62,7 +62,7 @@ type ECReconstruct struct { | |||||
| } | } | ||||
| func (o *ECReconstruct) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | func (o *ECReconstruct) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | ||||
| rs, err := ec.NewRs(o.EC.K, o.EC.N, o.EC.ChunkSize) | |||||
| rs, err := ec.NewStreamRs(o.EC.K, o.EC.N, o.EC.ChunkSize) | |||||
| if err != nil { | if err != nil { | ||||
| return fmt.Errorf("new ec: %w", err) | return fmt.Errorf("new ec: %w", err) | ||||
| } | } | ||||
| @@ -87,7 +87,7 @@ func (o *ECReconstruct) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) err | |||||
| wg := sync.WaitGroup{} | wg := sync.WaitGroup{} | ||||
| for i, id := range o.OutputIDs { | for i, id := range o.OutputIDs { | ||||
| wg.Add(1) | wg.Add(1) | ||||
| sw.StreamReady(planID, ioswitch.NewStream(id, myio.AfterReadClosedOnce(outputs[i], func(closer io.ReadCloser) { | |||||
| sw.StreamReady(planID, ioswitch.NewStream(id, io2.AfterReadClosedOnce(outputs[i], func(closer io.ReadCloser) { | |||||
| wg.Done() | wg.Done() | ||||
| }))) | }))) | ||||
| } | } | ||||
| @@ -8,7 +8,7 @@ import ( | |||||
| "path" | "path" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/future" | "gitlink.org.cn/cloudream/common/pkgs/future" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| ) | ) | ||||
| @@ -56,7 +56,7 @@ func (o *FileRead) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | |||||
| } | } | ||||
| fut := future.NewSetVoid() | fut := future.NewSetVoid() | ||||
| sw.StreamReady(planID, ioswitch.NewStream(o.OutputID, myio.AfterReadClosed(file, func(closer io.ReadCloser) { | |||||
| sw.StreamReady(planID, ioswitch.NewStream(o.OutputID, io2.AfterReadClosed(file, func(closer io.ReadCloser) { | |||||
| fut.SetVoid() | fut.SetVoid() | ||||
| }))) | }))) | ||||
| @@ -8,7 +8,7 @@ import ( | |||||
| "gitlink.org.cn/cloudream/common/pkgs/future" | "gitlink.org.cn/cloudream/common/pkgs/future" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | stgglb "gitlink.org.cn/cloudream/storage/common/globals" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| ) | ) | ||||
| @@ -66,7 +66,7 @@ func (o *GRPCFetch) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | |||||
| } | } | ||||
| fut := future.NewSetVoid() | fut := future.NewSetVoid() | ||||
| str = myio.AfterReadClosedOnce(str, func(closer io.ReadCloser) { | |||||
| str = io2.AfterReadClosedOnce(str, func(closer io.ReadCloser) { | |||||
| fut.SetVoid() | fut.SetVoid() | ||||
| }) | }) | ||||
| @@ -6,8 +6,9 @@ import ( | |||||
| "io" | "io" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/future" | "gitlink.org.cn/cloudream/common/pkgs/future" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/ipfs" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | stgglb "gitlink.org.cn/cloudream/storage/common/globals" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| ) | ) | ||||
| @@ -15,6 +16,7 @@ import ( | |||||
| type IPFSRead struct { | type IPFSRead struct { | ||||
| Output ioswitch.StreamID `json:"output"` | Output ioswitch.StreamID `json:"output"` | ||||
| FileHash string `json:"fileHash"` | FileHash string `json:"fileHash"` | ||||
| Option ipfs.ReadOption `json:"option"` | |||||
| } | } | ||||
| func (o *IPFSRead) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | func (o *IPFSRead) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | ||||
| @@ -30,13 +32,13 @@ func (o *IPFSRead) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | |||||
| } | } | ||||
| defer stgglb.IPFSPool.Release(ipfsCli) | defer stgglb.IPFSPool.Release(ipfsCli) | ||||
| file, err := ipfsCli.OpenRead(o.FileHash) | |||||
| file, err := ipfsCli.OpenRead(o.FileHash, o.Option) | |||||
| if err != nil { | if err != nil { | ||||
| return fmt.Errorf("reading ipfs: %w", err) | return fmt.Errorf("reading ipfs: %w", err) | ||||
| } | } | ||||
| fut := future.NewSetVoid() | fut := future.NewSetVoid() | ||||
| file = myio.AfterReadClosedOnce(file, func(closer io.ReadCloser) { | |||||
| file = io2.AfterReadClosedOnce(file, func(closer io.ReadCloser) { | |||||
| fut.SetVoid() | fut.SetVoid() | ||||
| }) | }) | ||||
| @@ -5,7 +5,7 @@ import ( | |||||
| "io" | "io" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/future" | "gitlink.org.cn/cloudream/common/pkgs/future" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| ) | ) | ||||
| @@ -34,7 +34,7 @@ func (o *Join) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | |||||
| fut := future.NewSetVoid() | fut := future.NewSetVoid() | ||||
| sw.StreamReady(planID, | sw.StreamReady(planID, | ||||
| ioswitch.NewStream(o.OutputID, | ioswitch.NewStream(o.OutputID, | ||||
| myio.AfterReadClosedOnce(myio.Length(myio.Join(strReaders), o.Length), func(closer io.ReadCloser) { | |||||
| io2.AfterReadClosedOnce(io2.Length(io2.Join(strReaders), o.Length), func(closer io.ReadCloser) { | |||||
| fut.SetVoid() | fut.SetVoid() | ||||
| }), | }), | ||||
| ), | ), | ||||
| @@ -5,7 +5,7 @@ import ( | |||||
| "io" | "io" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/future" | "gitlink.org.cn/cloudream/common/pkgs/future" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| ) | ) | ||||
| @@ -25,7 +25,7 @@ func (o *Length) Execute(sw *ioswitch.Switch, planID ioswitch.PlanID) error { | |||||
| fut := future.NewSetVoid() | fut := future.NewSetVoid() | ||||
| sw.StreamReady(planID, | sw.StreamReady(planID, | ||||
| ioswitch.NewStream(o.OutputID, | ioswitch.NewStream(o.OutputID, | ||||
| myio.AfterReadClosedOnce(myio.Length(strs[0].Stream, o.Length), func(closer io.ReadCloser) { | |||||
| io2.AfterReadClosedOnce(io2.Length(strs[0].Stream, o.Length), func(closer io.ReadCloser) { | |||||
| fut.SetVoid() | fut.SetVoid() | ||||
| }), | }), | ||||
| ), | ), | ||||
| @@ -1,6 +1,7 @@ | |||||
| package plans | package plans | ||||
| import ( | import ( | ||||
| "gitlink.org.cn/cloudream/common/pkgs/ipfs" | |||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch/ops" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch/ops" | ||||
| @@ -59,7 +60,15 @@ func (s *AgentStream) GRPCSend(node cdssdk.Node) *AgentStream { | |||||
| return agtStr | return agtStr | ||||
| } | } | ||||
| func (b *AgentPlanBuilder) IPFSRead(fileHash string) *AgentStream { | |||||
| func (b *AgentPlanBuilder) IPFSRead(fileHash string, opts ...ipfs.ReadOption) *AgentStream { | |||||
| opt := ipfs.ReadOption{ | |||||
| Offset: 0, | |||||
| Length: -1, | |||||
| } | |||||
| if len(opts) > 0 { | |||||
| opt = opts[0] | |||||
| } | |||||
| agtStr := &AgentStream{ | agtStr := &AgentStream{ | ||||
| owner: b, | owner: b, | ||||
| info: b.owner.newStream(), | info: b.owner.newStream(), | ||||
| @@ -68,6 +77,7 @@ func (b *AgentPlanBuilder) IPFSRead(fileHash string) *AgentStream { | |||||
| b.ops = append(b.ops, &ops.IPFSRead{ | b.ops = append(b.ops, &ops.IPFSRead{ | ||||
| Output: agtStr.info.ID, | Output: agtStr.info.ID, | ||||
| FileHash: fileHash, | FileHash: fileHash, | ||||
| Option: opt, | |||||
| }) | }) | ||||
| return agtStr | return agtStr | ||||
| @@ -9,7 +9,7 @@ import ( | |||||
| "sync/atomic" | "sync/atomic" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/future" | "gitlink.org.cn/cloudream/common/pkgs/future" | ||||
| myio "gitlink.org.cn/cloudream/common/utils/io" | |||||
| "gitlink.org.cn/cloudream/common/utils/io2" | |||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | stgglb "gitlink.org.cn/cloudream/storage/common/globals" | ||||
| "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch" | ||||
| agtmq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/agent" | agtmq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/agent" | ||||
| @@ -76,8 +76,15 @@ func Execute(plan ComposedPlan) (*Executor, error) { | |||||
| } | } | ||||
| func (e *Executor) SendStream(info *FromExecutorStream, stream io.Reader) error { | func (e *Executor) SendStream(info *FromExecutorStream, stream io.Reader) error { | ||||
| // TODO 根据地域选择IP | |||||
| agtCli, err := stgglb.AgentRPCPool.Acquire(info.toNode.ExternalIP, info.toNode.ExternalGRPCPort) | |||||
| // TODO 考虑不使用stgglb的Local | |||||
| nodeIP := info.toNode.ExternalIP | |||||
| grpcPort := info.toNode.ExternalGRPCPort | |||||
| if info.toNode.LocationID == stgglb.Local.LocationID { | |||||
| nodeIP = info.toNode.LocalIP | |||||
| grpcPort = info.toNode.LocalGRPCPort | |||||
| } | |||||
| agtCli, err := stgglb.AgentRPCPool.Acquire(nodeIP, grpcPort) | |||||
| if err != nil { | if err != nil { | ||||
| return fmt.Errorf("new agent rpc client: %w", err) | return fmt.Errorf("new agent rpc client: %w", err) | ||||
| } | } | ||||
| @@ -87,8 +94,15 @@ func (e *Executor) SendStream(info *FromExecutorStream, stream io.Reader) error | |||||
| } | } | ||||
| func (e *Executor) ReadStream(info *ToExecutorStream) (io.ReadCloser, error) { | func (e *Executor) ReadStream(info *ToExecutorStream) (io.ReadCloser, error) { | ||||
| // TODO 根据地域选择IP | |||||
| agtCli, err := stgglb.AgentRPCPool.Acquire(info.fromNode.ExternalIP, info.fromNode.ExternalGRPCPort) | |||||
| // TODO 考虑不使用stgglb的Local | |||||
| nodeIP := info.fromNode.ExternalIP | |||||
| grpcPort := info.fromNode.ExternalGRPCPort | |||||
| if info.fromNode.LocationID == stgglb.Local.LocationID { | |||||
| nodeIP = info.fromNode.LocalIP | |||||
| grpcPort = info.fromNode.LocalGRPCPort | |||||
| } | |||||
| agtCli, err := stgglb.AgentRPCPool.Acquire(nodeIP, grpcPort) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("new agent rpc client: %w", err) | return nil, fmt.Errorf("new agent rpc client: %w", err) | ||||
| } | } | ||||
| @@ -98,7 +112,7 @@ func (e *Executor) ReadStream(info *ToExecutorStream) (io.ReadCloser, error) { | |||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| return myio.AfterReadClosed(str, func(closer io.ReadCloser) { | |||||
| return io2.AfterReadClosed(str, func(closer io.ReadCloser) { | |||||
| stgglb.AgentRPCPool.Release(agtCli) | stgglb.AgentRPCPool.Release(agtCli) | ||||
| }), nil | }), nil | ||||
| } | } | ||||
| @@ -64,12 +64,12 @@ type GetPackageObjectDetailsResp struct { | |||||
| Objects []stgmod.ObjectDetail `json:"objects"` | Objects []stgmod.ObjectDetail `json:"objects"` | ||||
| } | } | ||||
| func NewGetPackageObjectDetails(packageID cdssdk.PackageID) *GetPackageObjectDetails { | |||||
| func ReqGetPackageObjectDetails(packageID cdssdk.PackageID) *GetPackageObjectDetails { | |||||
| return &GetPackageObjectDetails{ | return &GetPackageObjectDetails{ | ||||
| PackageID: packageID, | PackageID: packageID, | ||||
| } | } | ||||
| } | } | ||||
| func NewGetPackageObjectDetailsResp(objects []stgmod.ObjectDetail) *GetPackageObjectDetailsResp { | |||||
| func RespPackageObjectDetails(objects []stgmod.ObjectDetail) *GetPackageObjectDetailsResp { | |||||
| return &GetPackageObjectDetailsResp{ | return &GetPackageObjectDetailsResp{ | ||||
| Objects: objects, | Objects: objects, | ||||
| } | } | ||||
| @@ -63,7 +63,7 @@ func (svc *Service) GetPackageObjectDetails(msg *coormq.GetPackageObjectDetails) | |||||
| return nil, mq.Failed(errorcode.OperationFailed, "get package object block details failed") | return nil, mq.Failed(errorcode.OperationFailed, "get package object block details failed") | ||||
| } | } | ||||
| return mq.ReplyOK(coormq.NewGetPackageObjectDetailsResp(details)) | |||||
| return mq.ReplyOK(coormq.RespPackageObjectDetails(details)) | |||||
| } | } | ||||
| func (svc *Service) GetObjectDetails(msg *coormq.GetObjectDetails) (*coormq.GetObjectDetailsResp, *mq.CodeMessage) { | func (svc *Service) GetObjectDetails(msg *coormq.GetObjectDetails) (*coormq.GetObjectDetailsResp, *mq.CodeMessage) { | ||||
| @@ -5,10 +5,10 @@ go 1.20 | |||||
| replace gitlink.org.cn/cloudream/common v0.0.0 => ../common | replace gitlink.org.cn/cloudream/common v0.0.0 => ../common | ||||
| require ( | require ( | ||||
| github.com/baohan10/reedsolomon v0.0.0-20230406042632-43574cac9fa7 | |||||
| github.com/gin-gonic/gin v1.9.1 | github.com/gin-gonic/gin v1.9.1 | ||||
| github.com/go-sql-driver/mysql v1.7.1 | github.com/go-sql-driver/mysql v1.7.1 | ||||
| github.com/google/uuid v1.3.0 | |||||
| github.com/google/uuid v1.3.1 | |||||
| github.com/hashicorp/golang-lru/v2 v2.0.5 | |||||
| github.com/jedib0t/go-pretty/v6 v6.4.7 | github.com/jedib0t/go-pretty/v6 v6.4.7 | ||||
| github.com/jmoiron/sqlx v1.3.5 | github.com/jmoiron/sqlx v1.3.5 | ||||
| github.com/klauspost/reedsolomon v1.11.8 | github.com/klauspost/reedsolomon v1.11.8 | ||||
| @@ -43,8 +43,6 @@ require ( | |||||
| github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect | ||||
| github.com/golang/protobuf v1.5.3 // indirect | github.com/golang/protobuf v1.5.3 // indirect | ||||
| github.com/google/go-cmp v0.5.9 // indirect | github.com/google/go-cmp v0.5.9 // indirect | ||||
| github.com/google/licensecheck v0.3.1 // indirect | |||||
| github.com/google/safehtml v0.0.3-0.20211026203422-d6f0e11a5516 // indirect | |||||
| github.com/gopherjs/gopherjs v1.17.2 // indirect | github.com/gopherjs/gopherjs v1.17.2 // indirect | ||||
| github.com/hashicorp/errwrap v1.1.0 // indirect | github.com/hashicorp/errwrap v1.1.0 // indirect | ||||
| github.com/hashicorp/go-multierror v1.1.1 // indirect | github.com/hashicorp/go-multierror v1.1.1 // indirect | ||||
| @@ -52,7 +50,6 @@ require ( | |||||
| github.com/ipfs/boxo v0.12.0 // indirect | github.com/ipfs/boxo v0.12.0 // indirect | ||||
| github.com/ipfs/go-cid v0.4.1 // indirect | github.com/ipfs/go-cid v0.4.1 // indirect | ||||
| github.com/ipfs/go-ipfs-api v0.7.0 // indirect | github.com/ipfs/go-ipfs-api v0.7.0 // indirect | ||||
| github.com/jessevdk/go-flags v1.4.0 // indirect | |||||
| github.com/json-iterator/go v1.1.12 // indirect | github.com/json-iterator/go v1.1.12 // indirect | ||||
| github.com/jtolds/gls v4.20.0+incompatible // indirect | github.com/jtolds/gls v4.20.0+incompatible // indirect | ||||
| github.com/klauspost/cpuid/v2 v2.2.4 // indirect | github.com/klauspost/cpuid/v2 v2.2.4 // indirect | ||||
| @@ -77,7 +74,6 @@ require ( | |||||
| github.com/multiformats/go-multihash v0.2.3 // indirect | github.com/multiformats/go-multihash v0.2.3 // indirect | ||||
| github.com/multiformats/go-multistream v0.4.1 // indirect | github.com/multiformats/go-multistream v0.4.1 // indirect | ||||
| github.com/multiformats/go-varint v0.0.7 // indirect | github.com/multiformats/go-varint v0.0.7 // indirect | ||||
| github.com/ofabry/go-callvis v0.7.0 // indirect | |||||
| github.com/pelletier/go-toml/v2 v2.0.8 // indirect | github.com/pelletier/go-toml/v2 v2.0.8 // indirect | ||||
| github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect | ||||
| github.com/pkg/errors v0.9.1 // indirect | github.com/pkg/errors v0.9.1 // indirect | ||||
| @@ -101,18 +97,12 @@ require ( | |||||
| golang.org/x/arch v0.3.0 // indirect | golang.org/x/arch v0.3.0 // indirect | ||||
| golang.org/x/crypto v0.22.0 // indirect | golang.org/x/crypto v0.22.0 // indirect | ||||
| golang.org/x/exp v0.0.0-20230519143937-03e91628a987 // indirect | golang.org/x/exp v0.0.0-20230519143937-03e91628a987 // indirect | ||||
| golang.org/x/image v0.15.0 // indirect | |||||
| golang.org/x/mod v0.17.0 // indirect | |||||
| golang.org/x/net v0.24.0 // indirect | |||||
| golang.org/x/pkgsite v0.0.0-20240405142909-b8abe0819782 // indirect | |||||
| golang.org/x/sync v0.7.0 // indirect | |||||
| golang.org/x/sys v0.19.0 // indirect | |||||
| golang.org/x/text v0.14.0 // indirect | |||||
| golang.org/x/tools v0.20.0 // indirect | |||||
| golang.org/x/tools/go/pointer v0.1.0-deprecated // indirect | |||||
| google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect | |||||
| google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect | |||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect | |||||
| golang.org/x/net v0.10.0 // indirect | |||||
| golang.org/x/sys v0.8.0 // indirect | |||||
| golang.org/x/text v0.9.0 // indirect | |||||
| google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect | |||||
| google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect | |||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect | |||||
| gopkg.in/yaml.v3 v3.0.1 // indirect | gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| lukechampine.com/blake3 v1.1.7 // indirect | lukechampine.com/blake3 v1.1.7 // indirect | ||||
| rsc.io/markdown v0.0.0-20231214224604-88bb533a6020 // indirect | rsc.io/markdown v0.0.0-20231214224604-88bb533a6020 // indirect | ||||
| @@ -1,7 +1,10 @@ | |||||
| github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= | github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= | ||||
| github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= | github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= | ||||
| <<<<<<< HEAD | |||||
| github.com/baohan10/reedsolomon v0.0.0-20230406042632-43574cac9fa7 h1:wcvD6enR///dFvb9cRodx5SGbPH4G4jPjw+aVIWkAKE= | github.com/baohan10/reedsolomon v0.0.0-20230406042632-43574cac9fa7 h1:wcvD6enR///dFvb9cRodx5SGbPH4G4jPjw+aVIWkAKE= | ||||
| github.com/baohan10/reedsolomon v0.0.0-20230406042632-43574cac9fa7/go.mod h1:rAxMF6pVaFK/s6T4gGczvloccNbtwzuYaP2Y7W6flE8= | github.com/baohan10/reedsolomon v0.0.0-20230406042632-43574cac9fa7/go.mod h1:rAxMF6pVaFK/s6T4gGczvloccNbtwzuYaP2Y7W6flE8= | ||||
| ======= | |||||
| >>>>>>> 770feaf2da11a3de00fa3ec57b16dc54ff31b288 | |||||
| github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= | github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= | ||||
| github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= | github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= | ||||
| github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= | github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= | ||||
| @@ -61,10 +64,13 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ | |||||
| github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | ||||
| github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | ||||
| github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | ||||
| <<<<<<< HEAD | |||||
| github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs= | github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs= | ||||
| github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY= | github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY= | ||||
| github.com/google/safehtml v0.0.3-0.20211026203422-d6f0e11a5516 h1:pSEdbeokt55L2hwtWo6A2k7u5SG08rmw0LhWEyrdWgk= | github.com/google/safehtml v0.0.3-0.20211026203422-d6f0e11a5516 h1:pSEdbeokt55L2hwtWo6A2k7u5SG08rmw0LhWEyrdWgk= | ||||
| github.com/google/safehtml v0.0.3-0.20211026203422-d6f0e11a5516/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU= | github.com/google/safehtml v0.0.3-0.20211026203422-d6f0e11a5516/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU= | ||||
| ======= | |||||
| >>>>>>> 770feaf2da11a3de00fa3ec57b16dc54ff31b288 | |||||
| github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= | ||||
| github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||
| github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= | github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= | ||||
| @@ -74,6 +80,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY | |||||
| github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= | ||||
| github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= | ||||
| github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= | ||||
| github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= | |||||
| github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= | |||||
| github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= | github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= | ||||
| github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= | github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= | ||||
| github.com/ipfs/boxo v0.12.0 h1:AXHg/1ONZdRQHQLgG5JHsSC3XoE4DjCAMgK+asZvUcQ= | github.com/ipfs/boxo v0.12.0 h1:AXHg/1ONZdRQHQLgG5JHsSC3XoE4DjCAMgK+asZvUcQ= | ||||
| @@ -153,8 +161,11 @@ github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3d | |||||
| github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= | github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= | ||||
| github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= | github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= | ||||
| github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= | github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= | ||||
| <<<<<<< HEAD | |||||
| github.com/ofabry/go-callvis v0.7.0 h1:kh8TYgER49uZDlMrYviHchBs+I4n/SgiZXv45CVkqiE= | github.com/ofabry/go-callvis v0.7.0 h1:kh8TYgER49uZDlMrYviHchBs+I4n/SgiZXv45CVkqiE= | ||||
| github.com/ofabry/go-callvis v0.7.0/go.mod h1:z/1SpfLX72BjG8mgjy77/VWK5xJ9YBytCBnQeQnRObQ= | github.com/ofabry/go-callvis v0.7.0/go.mod h1:z/1SpfLX72BjG8mgjy77/VWK5xJ9YBytCBnQeQnRObQ= | ||||
| ======= | |||||
| >>>>>>> 770feaf2da11a3de00fa3ec57b16dc54ff31b288 | |||||
| github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= | github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= | ||||
| github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= | github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= | ||||
| github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= | ||||
| @@ -239,6 +250,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn | |||||
| golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | ||||
| <<<<<<< HEAD | |||||
| golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= | golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= | ||||
| golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= | golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= | ||||
| golang.org/x/pkgsite v0.0.0-20240405142909-b8abe0819782 h1:LpBNDVFgFjnIZg+JzqKB2rSZCwV5o0NaYRZyAHBy8oI= | golang.org/x/pkgsite v0.0.0-20240405142909-b8abe0819782 h1:LpBNDVFgFjnIZg+JzqKB2rSZCwV5o0NaYRZyAHBy8oI= | ||||
| @@ -248,6 +260,13 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ | |||||
| golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= | golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= | ||||
| golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= | golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= | ||||
| ======= | |||||
| golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= | |||||
| golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= | |||||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||||
| golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||||
| golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||||
| >>>>>>> 770feaf2da11a3de00fa3ec57b16dc54ff31b288 | |||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| @@ -256,8 +275,13 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc | |||||
| golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| <<<<<<< HEAD | |||||
| golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= | golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= | ||||
| golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | ||||
| ======= | |||||
| golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= | |||||
| golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||||
| >>>>>>> 770feaf2da11a3de00fa3ec57b16dc54ff31b288 | |||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||
| golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= | ||||
| @@ -1341,3 +1341,16 @@ | |||||
| 2024-04-11 22:53:21 [DEBU] [:Collector] do testing | 2024-04-11 22:53:21 [DEBU] [:Collector] do testing | ||||
| 2024-04-12 01:42:33 [DEBU] [:Collector] do testing | 2024-04-12 01:42:33 [DEBU] [:Collector] do testing | ||||
| 2024-04-12 08:50:14 [DEBU] [:Collector] do testing | 2024-04-12 08:50:14 [DEBU] [:Collector] do testing | ||||
| 2024-04-12 08:53:21 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 08:58:23 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 09:03:23 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 09:08:23 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 09:13:23 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 09:18:23 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 09:23:23 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 09:28:23 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 09:33:23 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 09:38:23 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 09:43:23 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 09:48:23 [DEBU] [:Collector] do testing | |||||
| 2024-04-12 09:53:23 [DEBU] [:Collector] do testing | |||||
| @@ -4948,3 +4948,76 @@ | |||||
| 2024-04-12 08:51:18 [DEBU] [Event:CheckPackage] end | 2024-04-12 08:51:18 [DEBU] [Event:CheckPackage] end | ||||
| 2024-04-12 08:53:04 [DEBU] [TickEvent:BatchCleanPinned] begin | 2024-04-12 08:53:04 [DEBU] [TickEvent:BatchCleanPinned] begin | ||||
| 2024-04-12 08:53:04 [DEBU] [TickEvent:BatchCleanPinned] end | 2024-04-12 08:53:04 [DEBU] [TickEvent:BatchCleanPinned] end | ||||
| 2024-04-12 08:54:40 [DEBU] [TickEvent:BatchCheckPackageRedundancy] begin | |||||
| 2024-04-12 08:54:40 [DEBU] [TickEvent:BatchCheckPackageRedundancy] end | |||||
| 2024-04-12 08:54:51 [DEBU] [TickEvent:BatchCheckAllStorage] begin | |||||
| 2024-04-12 08:54:51 [DEBU] [TickEvent:BatchCheckAllStorage] all storage checked, next time will start check at 0 | |||||
| 2024-04-12 08:54:51 [DEBU] [TickEvent:BatchCheckAllStorage] end | |||||
| 2024-04-12 08:54:51 [DEBU] [Event:AgentCheckStorage] begin with , StorageID: 1 | |||||
| 2024-04-12 08:54:51 [DEBU] [Event:AgentCheckStorage] end | |||||
| 2024-04-12 08:54:56 [DEBU] [TickEvent:BatchAllAgentCheckCache] begin | |||||
| 2024-04-12 08:54:56 [DEBU] [TickEvent:BatchAllAgentCheckCache] new check start, get all nodes | |||||
| 2024-04-12 08:54:56 [DEBU] [TickEvent:BatchAllAgentCheckCache] end | |||||
| 2024-04-12 08:54:56 [DEBU] [Event:AgentCheckCache] begin with , NodeID: 1 | |||||
| 2024-04-12 08:54:56 [WARN] [Event:AgentCheckCache] [NodeID:1] checking ipfs: requesting: sending message: publishing data: Exception (504) Reason: "channel/connection is not open" | |||||
| 2024-04-12 08:54:56 [DEBU] [Event:AgentCheckCache] end, time: 0s | |||||
| 2024-04-12 08:55:26 [DEBU] [TickEvent:CheckAgentState] begin | |||||
| 2024-04-12 08:55:26 [DEBU] [TickEvent:CheckAgentState] end | |||||
| 2024-04-12 08:55:26 [DEBU] [Event:AgentCheckState] begin with , NodeID: 1 | |||||
| 2024-04-12 08:55:26 [WARN] [Event:AgentCheckState] [NodeID:1] getting state: requesting: sending message: publishing data: Exception (504) Reason: "channel/connection is not open" | |||||
| 2024-04-12 08:55:26 [DEBU] [Event:AgentCheckState] end | |||||
| 2024-04-12 08:55:35 [DEBU] [TickEvent:BatchCheckAllPackage] begin | |||||
| 2024-04-12 08:55:35 [DEBU] [TickEvent:BatchCheckAllPackage] all package checked, next time will start check at 0 | |||||
| 2024-04-12 08:55:35 [DEBU] [TickEvent:BatchCheckAllPackage] end | |||||
| 2024-04-12 08:55:35 [DEBU] [Event:CheckPackage] begin with , len(PackageIDs): 1 | |||||
| 2024-04-12 08:55:35 [DEBU] [Event:CheckPackage] end | |||||
| 2024-04-12 08:58:06 [DEBU] [TickEvent:BatchCleanPinned] begin | |||||
| 2024-04-12 08:58:06 [DEBU] [TickEvent:BatchCleanPinned] end | |||||
| 2024-04-12 08:59:40 [DEBU] [TickEvent:BatchCheckPackageRedundancy] begin | |||||
| 2024-04-12 08:59:40 [DEBU] [TickEvent:BatchCheckPackageRedundancy] end | |||||
| 2024-04-12 08:59:51 [DEBU] [TickEvent:BatchCheckAllStorage] begin | |||||
| 2024-04-12 08:59:51 [DEBU] [TickEvent:BatchCheckAllStorage] all storage checked, next time will start check at 0 | |||||
| 2024-04-12 08:59:51 [DEBU] [TickEvent:BatchCheckAllStorage] end | |||||
| 2024-04-12 08:59:51 [DEBU] [Event:AgentCheckStorage] begin with , StorageID: 1 | |||||
| 2024-04-12 08:59:51 [DEBU] [Event:AgentCheckStorage] end | |||||
| 2024-04-12 08:59:56 [DEBU] [TickEvent:BatchAllAgentCheckCache] begin | |||||
| 2024-04-12 08:59:56 [DEBU] [TickEvent:BatchAllAgentCheckCache] new check start, get all nodes | |||||
| 2024-04-12 08:59:56 [DEBU] [TickEvent:BatchAllAgentCheckCache] end | |||||
| 2024-04-12 08:59:56 [DEBU] [Event:AgentCheckCache] begin with , NodeID: 1 | |||||
| 2024-04-12 08:59:56 [WARN] [Event:AgentCheckCache] [NodeID:1] checking ipfs: requesting: sending message: publishing data: Exception (504) Reason: "channel/connection is not open" | |||||
| 2024-04-12 08:59:56 [DEBU] [Event:AgentCheckCache] end, time: 0s | |||||
| 2024-04-12 09:00:26 [DEBU] [TickEvent:CheckAgentState] begin | |||||
| 2024-04-12 09:00:26 [DEBU] [TickEvent:CheckAgentState] end | |||||
| 2024-04-12 09:00:26 [DEBU] [Event:AgentCheckState] begin with , NodeID: 1 | |||||
| 2024-04-12 09:00:26 [WARN] [Event:AgentCheckState] [NodeID:1] getting state: requesting: sending message: publishing data: Exception (504) Reason: "channel/connection is not open" | |||||
| 2024-04-12 09:00:26 [DEBU] [Event:AgentCheckState] end | |||||
| 2024-04-12 09:00:35 [DEBU] [TickEvent:BatchCheckAllPackage] begin | |||||
| 2024-04-12 09:00:35 [DEBU] [TickEvent:BatchCheckAllPackage] all package checked, next time will start check at 0 | |||||
| 2024-04-12 09:00:35 [DEBU] [TickEvent:BatchCheckAllPackage] end | |||||
| 2024-04-12 09:00:35 [DEBU] [Event:CheckPackage] begin with , len(PackageIDs): 1 | |||||
| 2024-04-12 09:00:35 [DEBU] [Event:CheckPackage] end | |||||
| 2024-04-12 09:03:06 [DEBU] [TickEvent:BatchCleanPinned] begin | |||||
| 2024-04-12 09:03:06 [DEBU] [TickEvent:BatchCleanPinned] end | |||||
| 2024-04-12 09:04:40 [DEBU] [TickEvent:BatchCheckPackageRedundancy] begin | |||||
| 2024-04-12 09:04:40 [DEBU] [TickEvent:BatchCheckPackageRedundancy] end | |||||
| 2024-04-12 09:04:51 [DEBU] [TickEvent:BatchCheckAllStorage] begin | |||||
| 2024-04-12 09:04:51 [DEBU] [TickEvent:BatchCheckAllStorage] all storage checked, next time will start check at 0 | |||||
| 2024-04-12 09:04:51 [DEBU] [TickEvent:BatchCheckAllStorage] end | |||||
| 2024-04-12 09:04:51 [DEBU] [Event:AgentCheckStorage] begin with , StorageID: 1 | |||||
| 2024-04-12 09:04:51 [DEBU] [Event:AgentCheckStorage] end | |||||
| 2024-04-12 09:04:56 [DEBU] [TickEvent:BatchAllAgentCheckCache] begin | |||||
| 2024-04-12 09:04:56 [DEBU] [TickEvent:BatchAllAgentCheckCache] new check start, get all nodes | |||||
| 2024-04-12 09:04:56 [DEBU] [TickEvent:BatchAllAgentCheckCache] end | |||||
| 2024-04-12 09:04:56 [DEBU] [Event:AgentCheckCache] begin with , NodeID: 1 | |||||
| 2024-04-12 09:04:56 [WARN] [Event:AgentCheckCache] [NodeID:1] checking ipfs: requesting: sending message: publishing data: Exception (504) Reason: "channel/connection is not open" | |||||
| 2024-04-12 09:04:56 [DEBU] [Event:AgentCheckCache] end, time: 293.5µs | |||||
| 2024-04-12 09:05:26 [DEBU] [TickEvent:CheckAgentState] begin | |||||
| 2024-04-12 09:05:26 [DEBU] [TickEvent:CheckAgentState] end | |||||
| 2024-04-12 09:05:26 [DEBU] [Event:AgentCheckState] begin with , NodeID: 1 | |||||
| 2024-04-12 09:05:26 [WARN] [Event:AgentCheckState] [NodeID:1] getting state: requesting: sending message: publishing data: Exception (504) Reason: "channel/connection is not open" | |||||
| 2024-04-12 09:05:26 [DEBU] [Event:AgentCheckState] end | |||||
| 2024-04-12 09:05:35 [DEBU] [TickEvent:BatchCheckAllPackage] begin | |||||
| 2024-04-12 09:05:35 [DEBU] [TickEvent:BatchCheckAllPackage] all package checked, next time will start check at 0 | |||||
| 2024-04-12 09:05:35 [DEBU] [TickEvent:BatchCheckAllPackage] end | |||||
| 2024-04-12 09:05:35 [DEBU] [Event:CheckPackage] begin with , len(PackageIDs): 1 | |||||
| 2024-04-12 09:05:35 [DEBU] [Event:CheckPackage] end | |||||
| @@ -64,7 +64,7 @@ func (t *CheckPackageRedundancy) Execute(execCtx ExecuteContext) { | |||||
| } | } | ||||
| defer stgglb.CoordinatorMQPool.Release(coorCli) | defer stgglb.CoordinatorMQPool.Release(coorCli) | ||||
| getObjs, err := coorCli.GetPackageObjectDetails(coormq.NewGetPackageObjectDetails(t.PackageID)) | |||||
| getObjs, err := coorCli.GetPackageObjectDetails(coormq.ReqGetPackageObjectDetails(t.PackageID)) | |||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting package objects: %s", err.Error()) | log.Warnf("getting package objects: %s", err.Error()) | ||||
| return | return | ||||
| @@ -12,7 +12,7 @@ import ( | |||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | ||||
| "gitlink.org.cn/cloudream/common/utils/lo2" | "gitlink.org.cn/cloudream/common/utils/lo2" | ||||
| mymath "gitlink.org.cn/cloudream/common/utils/math" | |||||
| "gitlink.org.cn/cloudream/common/utils/math2" | |||||
| "gitlink.org.cn/cloudream/common/utils/sort2" | "gitlink.org.cn/cloudream/common/utils/sort2" | ||||
| "gitlink.org.cn/cloudream/storage/common/consts" | "gitlink.org.cn/cloudream/storage/common/consts" | ||||
| stgglb "gitlink.org.cn/cloudream/storage/common/globals" | stgglb "gitlink.org.cn/cloudream/storage/common/globals" | ||||
| @@ -58,7 +58,7 @@ func (t *CleanPinned) Execute(execCtx ExecuteContext) { | |||||
| } | } | ||||
| defer stgglb.CoordinatorMQPool.Release(coorCli) | defer stgglb.CoordinatorMQPool.Release(coorCli) | ||||
| getObjs, err := coorCli.GetPackageObjectDetails(coormq.NewGetPackageObjectDetails(t.PackageID)) | |||||
| getObjs, err := coorCli.GetPackageObjectDetails(coormq.ReqGetPackageObjectDetails(t.PackageID)) | |||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting package objects: %s", err.Error()) | log.Warnf("getting package objects: %s", err.Error()) | ||||
| return | return | ||||
| @@ -674,7 +674,7 @@ func (t *CleanPinned) calcMinAccessCost(state *annealingState) float64 { | |||||
| // 下面的if会在拿到k个块之后跳出循环,所以or多了块也没关系 | // 下面的if会在拿到k个块之后跳出循环,所以or多了块也没关系 | ||||
| gotBlocks.Or(tarNodeMp) | gotBlocks.Or(tarNodeMp) | ||||
| // 但是算读取块的消耗时,不能多算,最多算读了k个块的消耗 | // 但是算读取块的消耗时,不能多算,最多算读了k个块的消耗 | ||||
| willGetBlocks := mymath.Min(gotBlocks.Weight()-curWeigth, state.object.minBlockCnt-curWeigth) | |||||
| willGetBlocks := math2.Min(gotBlocks.Weight()-curWeigth, state.object.minBlockCnt-curWeigth) | |||||
| thisCost += float64(willGetBlocks) * float64(tar.Distance) | thisCost += float64(willGetBlocks) * float64(tar.Distance) | ||||
| if gotBlocks.Weight() >= state.object.minBlockCnt { | if gotBlocks.Weight() >= state.object.minBlockCnt { | ||||