From 7ed8450e9c6acd432fc090a6befc4336fa244ada Mon Sep 17 00:00:00 2001 From: Sydonian <794346190@qq.com> Date: Fri, 23 May 2025 09:21:21 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=88=A4=E6=96=AD=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E7=B3=BB=E7=BB=9F=E7=BB=84=E4=BB=B6=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=9F=90=E4=B8=AA=E7=89=B9=E6=80=A7=E7=9A=84?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/pkgs/ioswitch2/parser/opt/ec.go | 10 +++- common/pkgs/ioswitch2/parser/opt/multipart.go | 2 +- common/pkgs/ioswitch2/parser/opt/s2s.go | 28 ++-------- common/pkgs/storage/efile/efile.go | 6 ++- common/pkgs/storage/local/local.go | 29 +++++++--- common/pkgs/storage/local/s2s.go | 4 +- common/pkgs/storage/obs/obs.go | 32 +++++++---- common/pkgs/storage/obs/s2s.go | 54 +++++++++---------- common/pkgs/storage/pool/pool.go | 10 ++-- common/pkgs/storage/s3/s3.go | 26 +++++---- common/pkgs/storage/types/empty_builder.go | 10 ++-- common/pkgs/storage/types/s2s.go | 4 +- common/pkgs/storage/types/s3_client.go | 2 + common/pkgs/storage/types/types.go | 26 ++++----- 14 files changed, 128 insertions(+), 115 deletions(-) diff --git a/common/pkgs/ioswitch2/parser/opt/ec.go b/common/pkgs/ioswitch2/parser/opt/ec.go index 7fcf1f4..85a0c78 100644 --- a/common/pkgs/ioswitch2/parser/opt/ec.go +++ b/common/pkgs/ioswitch2/parser/opt/ec.go @@ -7,6 +7,7 @@ import ( "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch2/ops2" "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch2/parser/state" "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/factory" + "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/types" cortypes "gitlink.org.cn/cloudream/jcs-pub/coordinator/types" ) @@ -79,7 +80,7 @@ func UseECMultiplier(ctx *state.GenerateState) { } bwNodes = append(bwNodes, swNode) } - _, err := factory.GetBuilder(&to.Space).CreateECMultiplier() + _, err := factory.GetBuilder(&to.Space).CreateECMultiplier(true) if err != nil { return true } @@ -98,7 +99,12 @@ func UseECMultiplier(ctx *state.GenerateState) { return true } - if !factory.GetBuilder(&brNode.UserSpace).FeatureDesc().HasBypassHTTPRead { + store, err := factory.GetBuilder(&brNode.UserSpace).CreateShardStore(true) + if err != nil { + return true + } + _, ok = store.(types.HTTPShardRead) + if !ok { return true } diff --git a/common/pkgs/ioswitch2/parser/opt/multipart.go b/common/pkgs/ioswitch2/parser/opt/multipart.go index 4b1d23c..128f49a 100644 --- a/common/pkgs/ioswitch2/parser/opt/multipart.go +++ b/common/pkgs/ioswitch2/parser/opt/multipart.go @@ -34,7 +34,7 @@ func UseMultipartUploadToShardStore(ctx *state.GenerateState) { } // Join的目的地必须支持MultipartUpload功能才能替换成分片上传 - multiUpload, err := factory.GetBuilder(&bwNode.UserSpace).CreateMultiparter() + multiUpload, err := factory.GetBuilder(&bwNode.UserSpace).CreateMultiparter(true) if err != nil { return true } diff --git a/common/pkgs/ioswitch2/parser/opt/s2s.go b/common/pkgs/ioswitch2/parser/opt/s2s.go index fa99fbf..7b20b0c 100644 --- a/common/pkgs/ioswitch2/parser/opt/s2s.go +++ b/common/pkgs/ioswitch2/parser/opt/s2s.go @@ -26,11 +26,7 @@ func UseS2STransfer(ctx *state.GenerateState) { func s2sFromShardStore(ctx *state.GenerateState, fromShard *ioswitch2.FromShardStore, frNode ops2.FromNode) { fromStgBld := factory.GetBuilder(&fromShard.UserSpace) - if !fromStgBld.FeatureDesc().HasBypassShardRead { - return - } - - s2s, err := fromStgBld.CreateS2STransfer() + s2s, err := fromStgBld.CreateS2STransfer(true) if err != nil { return } @@ -50,13 +46,7 @@ loop: switch dstNode := dstNode.(type) { case *ops2.BaseWriteNode: - dstStgBld := factory.GetBuilder(&dstNode.UserSpace) - if !dstStgBld.FeatureDesc().HasBypassBaseWrite { - failed = true - break - } - - if !s2s.CanTransfer(&dstNode.UserSpace) { + if !s2s.CanTransfer(&fromShard.UserSpace, &dstNode.UserSpace) { failed = true break } @@ -99,11 +89,7 @@ loop: func s2sFromBaseStore(ctx *state.GenerateState, fromBase *ioswitch2.FromBaseStore, frNode ops2.FromNode) { fromStgBld := factory.GetBuilder(&fromBase.UserSpace) - if !fromStgBld.FeatureDesc().HasBypassBaseRead { - return - } - - s2s, err := fromStgBld.CreateS2STransfer() + s2s, err := fromStgBld.CreateS2STransfer(true) if err != nil { return } @@ -123,13 +109,7 @@ loop: switch dstNode := dstNode.(type) { case *ops2.BaseWriteNode: - dstStgBld := factory.GetBuilder(&dstNode.UserSpace) - if !dstStgBld.FeatureDesc().HasBypassBaseWrite { - failed = true - break - } - - if !s2s.CanTransfer(&dstNode.UserSpace) { + if !s2s.CanTransfer(&fromBase.UserSpace, &dstNode.UserSpace) { failed = true break } diff --git a/common/pkgs/storage/efile/efile.go b/common/pkgs/storage/efile/efile.go index 7d197d2..57b96a0 100644 --- a/common/pkgs/storage/efile/efile.go +++ b/common/pkgs/storage/efile/efile.go @@ -91,7 +91,11 @@ func (b *builder) getToken() (string, error) { return "", fmt.Errorf("clusterID %s not found", stgType.ClusterID) } -func (b *builder) CreateECMultiplier() (types.ECMultiplier, error) { +func (b *builder) CreateECMultiplier(typeOnly bool) (types.ECMultiplier, error) { + if typeOnly { + return (*ECMultiplier)(nil), nil + } + feat := utils.FindFeature[*cortypes.ECMultiplierFeature](b.detail) if feat == nil { return nil, fmt.Errorf("feature ECMultiplier not found") diff --git a/common/pkgs/storage/local/local.go b/common/pkgs/storage/local/local.go index bb0cfd1..8d7e637 100644 --- a/common/pkgs/storage/local/local.go +++ b/common/pkgs/storage/local/local.go @@ -24,13 +24,14 @@ type builder struct { } func (b *builder) FeatureDesc() types.FeatureDesc { - return types.FeatureDesc{ - HasBypassShardWrite: true, - HasBypassShardRead: true, - } + return types.FeatureDesc{} } -func (b *builder) CreateShardStore() (types.ShardStore, error) { +func (b *builder) CreateShardStore(typeOnly bool) (types.ShardStore, error) { + if typeOnly { + return (*ShardStore)(nil), nil + } + cred, ok := b.detail.UserSpace.Credential.(*cortypes.LocalCred) if !ok { return nil, fmt.Errorf("invalid storage credential type %T for local storage", b.detail.UserSpace.Credential) @@ -39,7 +40,11 @@ func (b *builder) CreateShardStore() (types.ShardStore, error) { return NewShardStore(cred.RootDir, b.detail) } -func (b *builder) CreateBaseStore() (types.BaseStore, error) { +func (b *builder) CreateBaseStore(typeOnly bool) (types.BaseStore, error) { + if typeOnly { + return (*BaseStore)(nil), nil + } + cred, ok := b.detail.UserSpace.Credential.(*cortypes.LocalCred) if !ok { return nil, fmt.Errorf("invalid storage credential type %T for local storage", b.detail.UserSpace.Credential) @@ -48,7 +53,11 @@ func (b *builder) CreateBaseStore() (types.BaseStore, error) { return NewBaseStore(cred.RootDir, b.detail) } -func (b *builder) CreateMultiparter() (types.Multiparter, error) { +func (b *builder) CreateMultiparter(typeOnly bool) (types.Multiparter, error) { + if typeOnly { + return (*Multiparter)(nil), nil + } + feat := utils.FindFeature[*cortypes.MultipartUploadFeature](b.detail) if feat == nil { return nil, fmt.Errorf("feature %T not found", cortypes.MultipartUploadFeature{}) @@ -59,7 +68,11 @@ func (b *builder) CreateMultiparter() (types.Multiparter, error) { }, nil } -func (b *builder) CreateS2STransfer() (types.S2STransfer, error) { +func (b *builder) CreateS2STransfer(typeOnly bool) (types.S2STransfer, error) { + if typeOnly { + return (*S2STransfer)(nil), nil + } + feat := utils.FindFeature[*cortypes.S2STransferFeature](b.detail) if feat == nil { return nil, fmt.Errorf("feature %T not found", cortypes.S2STransferFeature{}) diff --git a/common/pkgs/storage/local/s2s.go b/common/pkgs/storage/local/s2s.go index cd6b5d8..bbc68f4 100644 --- a/common/pkgs/storage/local/s2s.go +++ b/common/pkgs/storage/local/s2s.go @@ -17,13 +17,13 @@ type S2STransfer struct { } // 只有同一个机器的存储之间才可以进行数据直传 -func (s *S2STransfer) CanTransfer(src *clitypes.UserSpaceDetail) bool { +func (*S2STransfer) CanTransfer(src, dst *clitypes.UserSpaceDetail) bool { _, ok := src.UserSpace.Storage.(*cortypes.LocalType) if !ok { return false } - if src.RecommendHub != s.detail.RecommendHub { + if src.RecommendHub.HubID != dst.RecommendHub.HubID { return false } diff --git a/common/pkgs/storage/obs/obs.go b/common/pkgs/storage/obs/obs.go index b281802..1fd9955 100644 --- a/common/pkgs/storage/obs/obs.go +++ b/common/pkgs/storage/obs/obs.go @@ -30,16 +30,14 @@ func newBuilder(detail *clitypes.UserSpaceDetail) types.StorageBuilder { } func (b *builder) FeatureDesc() types.FeatureDesc { - return types.FeatureDesc{ - HasBypassShardWrite: true, - HasBypassBaseWrite: true, - HasBypassShardRead: true, - HasBypassBaseRead: true, - HasBypassHTTPRead: true, - } + return types.FeatureDesc{} } -func (b *builder) CreateShardStore() (types.ShardStore, error) { +func (b *builder) CreateShardStore(typeOnly bool) (types.ShardStore, error) { + if typeOnly { + return (*ShardStore)(nil), nil + } + stgType := b.detail.UserSpace.Storage.(*cortypes.OBSType) cred, ok := b.detail.UserSpace.Credential.(*cortypes.OBSCred) if !ok { @@ -54,7 +52,11 @@ func (b *builder) CreateShardStore() (types.ShardStore, error) { return NewShardStore(b.detail, stgType, cred, cli, bucket) } -func (b *builder) CreateBaseStore() (types.BaseStore, error) { +func (b *builder) CreateBaseStore(typeOnly bool) (types.BaseStore, error) { + if typeOnly { + return (*s3stg.BaseStore)(nil), nil + } + stgType := b.detail.UserSpace.Storage.(*cortypes.OBSType) cred, ok := b.detail.UserSpace.Credential.(*cortypes.OBSCred) if !ok { @@ -88,7 +90,11 @@ func createClient(stgType *cortypes.OBSType, cred *cortypes.OBSCred) (*s3.Client return cli, stgType.Bucket, nil } -func (b *builder) CreateMultiparter() (types.Multiparter, error) { +func (b *builder) CreateMultiparter(typeOnly bool) (types.Multiparter, error) { + if typeOnly { + return (*s3stg.Multiparter)(nil), nil + } + stgType := b.detail.UserSpace.Storage.(*cortypes.OBSType) feat := utils.FindFeature[*cortypes.MultipartUploadFeature](b.detail) if feat == nil { @@ -113,7 +119,11 @@ func (b *builder) CreateMultiparter() (types.Multiparter, error) { ), nil } -func (b *builder) CreateS2STransfer() (types.S2STransfer, error) { +func (b *builder) CreateS2STransfer(typeOnly bool) (types.S2STransfer, error) { + if typeOnly { + return (*S2STransfer)(nil), nil + } + stgType := b.detail.UserSpace.Storage.(*cortypes.OBSType) feat := utils.FindFeature[*cortypes.S2STransferFeature](b.detail) if feat == nil { diff --git a/common/pkgs/storage/obs/s2s.go b/common/pkgs/storage/obs/s2s.go index 1023c5e..f78d534 100644 --- a/common/pkgs/storage/obs/s2s.go +++ b/common/pkgs/storage/obs/s2s.go @@ -36,14 +36,14 @@ func NewS2STransfer(stgType *cortypes.OBSType, cred *cortypes.OBSCred, feat *cor } // 判断是否能从指定的源存储中直传到当前存储的目的路径 -func (s *S2STransfer) CanTransfer(src *clitypes.UserSpaceDetail) bool { - req := s.makeRequest(src, "") +func (*S2STransfer) CanTransfer(src, dst *clitypes.UserSpaceDetail) bool { + req := makeRequest(src, "") return req != nil } // 执行数据直传。返回传输后的文件路径 func (s *S2STransfer) Transfer(ctx context.Context, src *clitypes.UserSpaceDetail, srcPath string, dstPath string) (types.FileInfo, error) { - req := s.makeRequest(src, srcPath) + req := makeRequest(src, srcPath) if req == nil { return types.FileInfo{}, fmt.Errorf("unsupported source storage type: %T", src.UserSpace.Storage) } @@ -122,30 +122,6 @@ func (s *S2STransfer) Transfer(ctx context.Context, src *clitypes.UserSpaceDetai }, nil } -func (s *S2STransfer) makeRequest(srcStg *clitypes.UserSpaceDetail, srcPath string) *model.SrcNodeReq { - switch srcType := srcStg.UserSpace.Storage.(type) { - case *cortypes.OBSType: - cloudType := "HuaweiCloud" - - cred, ok := srcStg.UserSpace.Credential.(*cortypes.OBSCred) - if !ok { - return nil - } - - return &model.SrcNodeReq{ - CloudType: &cloudType, - Region: &srcType.Region, - Ak: &cred.AK, - Sk: &cred.SK, - Bucket: &srcType.Bucket, - ObjectKey: &[]string{srcPath}, - } - - default: - return nil - } -} - func (s *S2STransfer) waitTask(ctx context.Context, taskId int64) (int64, error) { ticker := time.NewTicker(time.Second * 5) defer ticker.Stop() @@ -198,3 +174,27 @@ func (s *S2STransfer) Close() { }) } } + +func makeRequest(srcStg *clitypes.UserSpaceDetail, srcPath string) *model.SrcNodeReq { + switch srcType := srcStg.UserSpace.Storage.(type) { + case *cortypes.OBSType: + cloudType := "HuaweiCloud" + + cred, ok := srcStg.UserSpace.Credential.(*cortypes.OBSCred) + if !ok { + return nil + } + + return &model.SrcNodeReq{ + CloudType: &cloudType, + Region: &srcType.Region, + Ak: &cred.AK, + Sk: &cred.SK, + Bucket: &srcType.Bucket, + ObjectKey: &[]string{srcPath}, + } + + default: + return nil + } +} diff --git a/common/pkgs/storage/pool/pool.go b/common/pkgs/storage/pool/pool.go index c81fa27..5862ccb 100644 --- a/common/pkgs/storage/pool/pool.go +++ b/common/pkgs/storage/pool/pool.go @@ -64,7 +64,7 @@ func (p *Pool) GetShardStore(spaceDetail *clitypes.UserSpaceDetail) (types.Shard if space.store == nil { bld := factory.GetBuilder(spaceDetail) - store, err := bld.CreateShardStore() + store, err := bld.CreateShardStore(false) if err != nil { return nil, err } @@ -76,17 +76,17 @@ func (p *Pool) GetShardStore(spaceDetail *clitypes.UserSpaceDetail) (types.Shard } func (p *Pool) GetBaseStore(spaceDetail *clitypes.UserSpaceDetail) (types.BaseStore, error) { - return factory.GetBuilder(spaceDetail).CreateBaseStore() + return factory.GetBuilder(spaceDetail).CreateBaseStore(false) } func (p *Pool) GetMultiparter(spaceDetail *clitypes.UserSpaceDetail) (types.Multiparter, error) { - return factory.GetBuilder(spaceDetail).CreateMultiparter() + return factory.GetBuilder(spaceDetail).CreateMultiparter(false) } func (p *Pool) GetS2STransfer(spaceDetail *clitypes.UserSpaceDetail) (types.S2STransfer, error) { - return factory.GetBuilder(spaceDetail).CreateS2STransfer() + return factory.GetBuilder(spaceDetail).CreateS2STransfer(false) } func (p *Pool) GetECMultiplier(spaceDetail *clitypes.UserSpaceDetail) (types.ECMultiplier, error) { - return factory.GetBuilder(spaceDetail).CreateECMultiplier() + return factory.GetBuilder(spaceDetail).CreateECMultiplier(false) } diff --git a/common/pkgs/storage/s3/s3.go b/common/pkgs/storage/s3/s3.go index 52f9ae0..9cffe3b 100644 --- a/common/pkgs/storage/s3/s3.go +++ b/common/pkgs/storage/s3/s3.go @@ -29,16 +29,14 @@ func newBuilder(detail *clitypes.UserSpaceDetail) types.StorageBuilder { } func (b *builder) FeatureDesc() types.FeatureDesc { - return types.FeatureDesc{ - HasBypassShardWrite: true, - HasBypassBaseWrite: true, - HasBypassShardRead: true, - HasBypassBaseRead: true, - HasBypassHTTPRead: false, - } + return types.FeatureDesc{} } -func (b *builder) CreateShardStore() (types.ShardStore, error) { +func (b *builder) CreateShardStore(typeOnly bool) (types.ShardStore, error) { + if typeOnly { + return (*ShardStore)(nil), nil + } + stgType := b.detail.UserSpace.Storage.(*cortypes.S3Type) s3Cred, ok := b.detail.UserSpace.Credential.(*cortypes.S3Cred) if !ok { @@ -53,7 +51,11 @@ func (b *builder) CreateShardStore() (types.ShardStore, error) { return NewShardStore(b.detail, cli, bkt, ShardStoreOption{UseAWSSha256: true}) } -func (b *builder) CreateBaseStore() (types.BaseStore, error) { +func (b *builder) CreateBaseStore(typeOnly bool) (types.BaseStore, error) { + if typeOnly { + return (*BaseStore)(nil), nil + } + stgType := b.detail.UserSpace.Storage.(*cortypes.S3Type) s3Cred, ok := b.detail.UserSpace.Credential.(*cortypes.S3Cred) if !ok { @@ -89,7 +91,11 @@ func createClient(stgType *cortypes.S3Type, cred *cortypes.S3Cred) (*s3.Client, return cli, stgType.Bucket, nil } -func (b *builder) CreateMultiparter() (types.Multiparter, error) { +func (b *builder) CreateMultiparter(typeOnly bool) (types.Multiparter, error) { + if typeOnly { + return (*Multiparter)(nil), nil + } + stgType := b.detail.UserSpace.Storage.(*cortypes.S3Type) feat := utils.FindFeature[*cortypes.MultipartUploadFeature](b.detail) if feat == nil { diff --git a/common/pkgs/storage/types/empty_builder.go b/common/pkgs/storage/types/empty_builder.go index 9925e0a..6424075 100644 --- a/common/pkgs/storage/types/empty_builder.go +++ b/common/pkgs/storage/types/empty_builder.go @@ -14,22 +14,22 @@ func (b *EmptyBuilder) FeatureDesc() FeatureDesc { return FeatureDesc{} } -func (b *EmptyBuilder) CreateShardStore() (ShardStore, error) { +func (b *EmptyBuilder) CreateShardStore(typeOnly bool) (ShardStore, error) { return nil, fmt.Errorf("create shard store for %T: %w", b.Detail.UserSpace.Storage, ErrUnsupported) } -func (b *EmptyBuilder) CreateBaseStore() (BaseStore, error) { +func (b *EmptyBuilder) CreateBaseStore(typeOnly bool) (BaseStore, error) { return nil, fmt.Errorf("create base store for %T: %w", b.Detail.UserSpace.Storage, ErrUnsupported) } -func (b *EmptyBuilder) CreateMultiparter() (Multiparter, error) { +func (b *EmptyBuilder) CreateMultiparter(typeOnly bool) (Multiparter, error) { return nil, fmt.Errorf("create multipart initiator for %T: %w", b.Detail.UserSpace.Storage, ErrUnsupported) } -func (b *EmptyBuilder) CreateS2STransfer() (S2STransfer, error) { +func (b *EmptyBuilder) CreateS2STransfer(typeOnly bool) (S2STransfer, error) { return nil, fmt.Errorf("create s2s transfer for %T: %w", b.Detail.UserSpace.Storage, ErrUnsupported) } -func (b *EmptyBuilder) CreateECMultiplier() (ECMultiplier, error) { +func (b *EmptyBuilder) CreateECMultiplier(typeOnly bool) (ECMultiplier, error) { return nil, fmt.Errorf("create ec multiplier for %T: %w", b.Detail.UserSpace.Storage, ErrUnsupported) } diff --git a/common/pkgs/storage/types/s2s.go b/common/pkgs/storage/types/s2s.go index 7feb1ce..12d0230 100644 --- a/common/pkgs/storage/types/s2s.go +++ b/common/pkgs/storage/types/s2s.go @@ -7,8 +7,8 @@ import ( ) type S2STransfer interface { - // 判断是否能从指定的源存储中直传到当前存储的目的路径。仅在生成计划时使用 - CanTransfer(src *clitypes.UserSpaceDetail) bool + // 【静态方法】判断是否能从指定的源存储中直传到当前存储的目的路径。仅在生成计划时使用 + CanTransfer(src, dst *clitypes.UserSpaceDetail) bool // 从远端获取文件并保存到本地路径 Transfer(ctx context.Context, src *clitypes.UserSpaceDetail, srcPath string, dstPath string) (FileInfo, error) Close() diff --git a/common/pkgs/storage/types/s3_client.go b/common/pkgs/storage/types/s3_client.go index f4a4d3f..a760e1f 100644 --- a/common/pkgs/storage/types/s3_client.go +++ b/common/pkgs/storage/types/s3_client.go @@ -6,7 +6,9 @@ import ( ) type Multiparter interface { + // 【静态方法】 MaxPartSize() int64 + // 【静态方法】 MinPartSize() int64 // 启动一个分片上传 Initiate(ctx context.Context) (MultipartTask, error) diff --git a/common/pkgs/storage/types/types.go b/common/pkgs/storage/types/types.go index ed317d1..497ab80 100644 --- a/common/pkgs/storage/types/types.go +++ b/common/pkgs/storage/types/types.go @@ -18,32 +18,24 @@ type StorageEvent interface{} type StorageEventChan = async.UnboundChannel[StorageEvent] +// 创建存储系统各种组件。 +// +// typeOnly参数为true时仅创建组件类型(带类型的nil值),不创建组件实例。 type StorageBuilder interface { // 关于此存储系统特性功能的描述 FeatureDesc() FeatureDesc // 创建一个提供基础读写存储服务能力的组件 - CreateBaseStore() (BaseStore, error) + CreateBaseStore(typeOnly bool) (BaseStore, error) // 创建一个分片存储组件 - CreateShardStore() (ShardStore, error) + CreateShardStore(typeOnly bool) (ShardStore, error) // 创建一个分片上传组件 - CreateMultiparter() (Multiparter, error) + CreateMultiparter(typeOnly bool) (Multiparter, error) // 创建一个存储服务直传组件 - CreateS2STransfer() (S2STransfer, error) - CreateECMultiplier() (ECMultiplier, error) + CreateS2STransfer(typeOnly bool) (S2STransfer, error) + CreateECMultiplier(typeOnly bool) (ECMultiplier, error) } -type FeatureDesc struct { - // 是否能旁路上传分片 - HasBypassShardWrite bool - // 是否能旁路上传公共存储 - HasBypassBaseWrite bool - // 是否能旁路读取分片 - HasBypassShardRead bool - // 公共存储是否支持旁路读取 - HasBypassBaseRead bool - // 是否能通过HTTP读取 - HasBypassHTTPRead bool -} +type FeatureDesc struct{} type FileInfo struct { // 分片在存储系统中的路径,可以通过BaseStore读取的