mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 02:00:56 +00:00
feat(access): sdk put blob, delete blob from shard node
with: #22549147 of #22357707 Signed-off-by: mawei029 <mawei2@oppo.com>
This commit is contained in:
parent
7706c4b4b3
commit
84d6df46af
@ -1,51 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
"github.com/cubefs/cubefs/blobstore/common/rpc"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
rpc.Config
|
||||
}
|
||||
|
||||
type client struct {
|
||||
rpc.Client
|
||||
}
|
||||
|
||||
func New(cfg *Config) ShardnodeAPI {
|
||||
return &client{rpc.NewClient(&cfg.Config)}
|
||||
}
|
||||
|
||||
type ShardnodeAPI interface {
|
||||
CreateBlob(ctx context.Context, host string, args *shardnode.CreateBlobArgs) (*shardnode.CreateBlobRet, error)
|
||||
ListBlob(ctx context.Context, host string, args *shardnode.ListBlobArgs) (*shardnode.ListBlobRet, error)
|
||||
GetBlob(ctx context.Context, host string, args *shardnode.GetBlobArgs) (*shardnode.GetBlobRet, error)
|
||||
DeleteBlob(ctx context.Context, host string, args *shardnode.DeleteBlobArgs) error
|
||||
SealBlob(ctx context.Context, host string, args *shardnode.SealBlobArgs) error
|
||||
}
|
||||
|
||||
func (c *client) CreateBlob(ctx context.Context, host string, args *shardnode.CreateBlobArgs) (*shardnode.CreateBlobRet, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *client) ListBlob(ctx context.Context, host string, args *shardnode.ListBlobArgs) (*shardnode.ListBlobRet, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *client) GetBlob(ctx context.Context, host string, args *shardnode.GetBlobArgs) (ret *shardnode.GetBlobRet, err error) {
|
||||
// urlStr := fmt.Sprintf("%s/blob/get", host)
|
||||
// ret = &shardnode.GetBlobResponse{}
|
||||
// err = c.PostWith(ctx, urlStr, ret, args)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *client) DeleteBlob(ctx context.Context, host string, args *shardnode.DeleteBlobArgs) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *client) SealBlob(ctx context.Context, host string, args *shardnode.SealBlobArgs) error {
|
||||
return nil
|
||||
}
|
||||
@ -115,6 +115,7 @@ func init() {
|
||||
return cmapi.ServiceInfo{}, errNotFound
|
||||
})
|
||||
cli.EXPECT().ListDisk(A, A).AnyTimes().Return(cmapi.ListDiskRet{}, nil)
|
||||
cli.EXPECT().ListShardNodeDisk(A, A).AnyTimes().Return(cmapi.ListShardNodeDiskRet{}, nil)
|
||||
cmcli = cli
|
||||
|
||||
pcli := mocks.NewMockProxyClient(C(&testing.T{}))
|
||||
|
||||
@ -108,9 +108,10 @@ type ServiceConfig struct {
|
||||
|
||||
type serviceControllerImpl struct {
|
||||
// allServices hold all disk/service host map, use for quickly find out
|
||||
allServices sync.Map
|
||||
serviceHosts serviceMap
|
||||
brokenDisks sync.Map
|
||||
allServices sync.Map
|
||||
serviceHosts serviceMap
|
||||
brokenDisks sync.Map
|
||||
sdBrokenDisks sync.Map // shard node broken disks
|
||||
|
||||
group singleflight.Group
|
||||
serviceLocks map[string]*sync.RWMutex
|
||||
@ -164,13 +165,12 @@ func NewServiceController(cfg ServiceConfig,
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
controller.loadBrokenDisks()
|
||||
tick := time.NewTicker(time.Duration(cfg.LoadDiskInterval) * time.Second)
|
||||
defer tick.Stop()
|
||||
for {
|
||||
controller.loadBrokenDisks()
|
||||
select {
|
||||
case <-tick.C:
|
||||
controller.loadBrokenDisks()
|
||||
case <-stopCh:
|
||||
return
|
||||
}
|
||||
@ -210,7 +210,44 @@ func (s *serviceControllerImpl) load(cid proto.ClusterID, idc string) error {
|
||||
}
|
||||
|
||||
func (s *serviceControllerImpl) loadBrokenDisks() {
|
||||
span, ctx := trace.StartSpanFromContext(context.Background(), "access_cluster_load_disks")
|
||||
_, ctx := trace.StartSpanFromContext(context.Background(), "access_cluster_load_disks")
|
||||
|
||||
fnBlobnode := func(ctx context.Context, args *clustermgr.ListOptionArgs, diskMap map[proto.DiskID]struct{}) error {
|
||||
list, err := s.cmClient.ListDisk(ctx, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, disk := range list.Disks {
|
||||
diskMap[disk.DiskID] = struct{}{}
|
||||
}
|
||||
args.Marker = list.Marker
|
||||
return nil
|
||||
}
|
||||
|
||||
fnShardnode := func(ctx context.Context, args *clustermgr.ListOptionArgs, diskMap map[proto.DiskID]struct{}) error {
|
||||
list, err := s.cmClient.ListShardNodeDisk(ctx, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, disk := range list.Disks {
|
||||
diskMap[disk.DiskID] = struct{}{}
|
||||
}
|
||||
args.Marker = list.Marker
|
||||
return nil
|
||||
}
|
||||
|
||||
s.processBrokenDisks(ctx, fnBlobnode, &s.brokenDisks)
|
||||
s.processBrokenDisks(ctx, fnShardnode, &s.sdBrokenDisks)
|
||||
}
|
||||
|
||||
func (s *serviceControllerImpl) processBrokenDisks(
|
||||
ctx context.Context,
|
||||
fn func(context.Context, *clustermgr.ListOptionArgs, map[proto.DiskID]struct{}) error,
|
||||
disks *sync.Map,
|
||||
) {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
|
||||
brokenDiskIDs := make(map[proto.DiskID]struct{})
|
||||
for _, st := range []proto.DiskStatus{proto.DiskStatusBroken, proto.DiskStatusRepairing} {
|
||||
@ -219,13 +256,11 @@ func (s *serviceControllerImpl) loadBrokenDisks() {
|
||||
args := &clustermgr.ListOptionArgs{Status: st, Count: 1 << 10}
|
||||
for {
|
||||
list, err := s.cmClient.ListDisk(ctx, args)
|
||||
err = fn(ctx, args, brokenDiskIDs)
|
||||
if err != nil {
|
||||
span.Errorf("load disks of cluster %d %s", s.config.ClusterID, err.Error())
|
||||
span.Errorf("load disks of cluster %d, err:%+v", s.config.ClusterID, err)
|
||||
return
|
||||
}
|
||||
for _, disk := range list.Disks {
|
||||
brokenDiskIDs[disk.DiskID] = struct{}{}
|
||||
}
|
||||
if args.Marker = list.Marker; args.Marker <= proto.InvalidDiskID {
|
||||
break
|
||||
}
|
||||
@ -233,8 +268,8 @@ func (s *serviceControllerImpl) loadBrokenDisks() {
|
||||
}
|
||||
|
||||
// clean cached disks, ignore cases when concurrency getting disk.
|
||||
s.brokenDisks.Range(func(key, value interface{}) bool {
|
||||
s.brokenDisks.Delete(key)
|
||||
disks.Range(func(key, value interface{}) bool {
|
||||
disks.Delete(key)
|
||||
return true
|
||||
})
|
||||
if len(brokenDiskIDs) == 0 {
|
||||
@ -242,7 +277,7 @@ func (s *serviceControllerImpl) loadBrokenDisks() {
|
||||
}
|
||||
span.Warnf("load disks of cluster %d broken %v", s.config.ClusterID, brokenDiskIDs)
|
||||
for diskID := range brokenDiskIDs {
|
||||
s.brokenDisks.Store(diskID, struct{}{})
|
||||
disks.Store(diskID, struct{}{})
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,18 +414,19 @@ func (s *serviceControllerImpl) GetDiskHost(ctx context.Context, diskID proto.Di
|
||||
func (s *serviceControllerImpl) GetShardnodeHost(ctx context.Context, diskID proto.DiskID) (hostIDC *HostIDC, err error) {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
|
||||
_, broken := s.sdBrokenDisks.Load(diskID)
|
||||
v, ok := s.allServices.Load(_shardnodeDiskServicePrefix + (diskID.ToString()))
|
||||
if ok {
|
||||
item := v.(*hostItem)
|
||||
return &HostIDC{
|
||||
Host: item.host,
|
||||
IDC: item.idc,
|
||||
Punished: item.isPunish(), // todo: judge broken disk
|
||||
Punished: broken || item.isPunish(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
ret, err, _ := s.group.Do("get-shardnode-diskinfo-"+diskID.ToString(), func() (interface{}, error) {
|
||||
// todo: support proxy get disk host
|
||||
// todo: support proxy get disk host, next version
|
||||
info, err := s.cmClient.ShardNodeDiskInfo(ctx, diskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -409,7 +445,7 @@ func (s *serviceControllerImpl) GetShardnodeHost(ctx context.Context, diskID pro
|
||||
return &HostIDC{
|
||||
Host: item.host,
|
||||
IDC: item.idc,
|
||||
Punished: item.isPunish(), // broken || item.isPunish(),
|
||||
Punished: broken || item.isPunish(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@ -218,6 +218,7 @@ func TestAccessServiceGetBrokenDiskHost(t *testing.T) {
|
||||
return cmapi.ServiceInfo{}, errNotFound
|
||||
})
|
||||
cli.EXPECT().ListDisk(A, A).Times(6).Return(brokenRet, nil)
|
||||
cli.EXPECT().ListShardNodeDisk(A, A).Times(6).Return(cmapi.ListShardNodeDiskRet{}, nil)
|
||||
|
||||
pcli := mocks.NewMockProxyClient(C(t))
|
||||
pcli.EXPECT().GetCacheDisk(A, A, A).AnyTimes().DoAndReturn(
|
||||
@ -269,6 +270,7 @@ func TestAccessServiceGetBrokenDiskHost(t *testing.T) {
|
||||
brokenRet.Disks[0].DiskID = 10000
|
||||
brokenRet.Disks[1].DiskID = 10000
|
||||
cli.EXPECT().ListDisk(A, A).Times(1).Return(brokenRet, errors.New("list error"))
|
||||
cli.EXPECT().ListShardNodeDisk(A, A).Times(1).Return(cmapi.ListShardNodeDiskRet{}, errors.New("list error"))
|
||||
time.Sleep(time.Second)
|
||||
{
|
||||
host, err := sc.GetDiskHost(serviceCtx, 10001)
|
||||
@ -281,6 +283,7 @@ func TestAccessServiceGetBrokenDiskHost(t *testing.T) {
|
||||
|
||||
brokenRet.Disks = brokenRet.Disks[:0]
|
||||
cli.EXPECT().ListDisk(A, A).Times(2).Return(brokenRet, nil)
|
||||
cli.EXPECT().ListShardNodeDisk(A, A).Times(2).Return(cmapi.ListShardNodeDiskRet{}, nil)
|
||||
time.Sleep(time.Second)
|
||||
{
|
||||
host, err := sc.GetDiskHost(serviceCtx, 10001)
|
||||
|
||||
@ -16,7 +16,6 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
@ -24,6 +23,9 @@ import (
|
||||
"github.com/google/btree"
|
||||
|
||||
"github.com/cubefs/cubefs/blobstore/api/clustermgr"
|
||||
"github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
"github.com/cubefs/cubefs/blobstore/cli/common"
|
||||
errcode "github.com/cubefs/cubefs/blobstore/common/errors"
|
||||
"github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
"github.com/cubefs/cubefs/blobstore/common/sharding"
|
||||
"github.com/cubefs/cubefs/blobstore/common/trace"
|
||||
@ -36,9 +38,14 @@ const (
|
||||
)
|
||||
|
||||
type IShardController interface {
|
||||
GetShard(ctx context.Context, blobName []byte) (Shard, error)
|
||||
GetShard(ctx context.Context, shardKeys [][]byte) (Shard, error)
|
||||
GetShardByID(ctx context.Context, shardID proto.ShardID) (Shard, error)
|
||||
GetShardByRange(ctx context.Context, shardRange sharding.Range) (Shard, error)
|
||||
GetFisrtShard(ctx context.Context) (Shard, error)
|
||||
GetNextShard(ctx context.Context, shardRange sharding.Range) (Shard, error)
|
||||
GetSpaceID() proto.SpaceID
|
||||
Update(ctx context.Context) error
|
||||
UpdateRoute(ctx context.Context) error
|
||||
UpdateShard(ctx context.Context, ss shardnode.ShardStats) error
|
||||
}
|
||||
|
||||
type shardCtrlConf struct {
|
||||
@ -76,12 +83,12 @@ func NewShardController(conf shardCtrlConf, cmCli clustermgr.ClientAPI, stopCh <
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.initShard(ctx)
|
||||
err = s.initRoute(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go s.incrementalShard()
|
||||
go s.incrementalRoute()
|
||||
|
||||
return s, nil
|
||||
}
|
||||
@ -91,40 +98,113 @@ type shardControllerImpl struct {
|
||||
ranges *btree.BTree
|
||||
version proto.RouteVersion
|
||||
spaceID proto.SpaceID
|
||||
sync.RWMutex // todo: I will optimize locker in the next MR
|
||||
sync.RWMutex // todo: I will optimize locker in the next version
|
||||
|
||||
conf shardCtrlConf
|
||||
cmCli clustermgr.ClientAPI
|
||||
stopCh <-chan struct{}
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) GetShard(ctx context.Context, blobName []byte) (Shard, error) {
|
||||
func (s *shardControllerImpl) GetShard(ctx context.Context, shardKeys [][]byte) (Shard, error) {
|
||||
// shard_1 ranges [1, 100) , shard 2: [100, 200), shard 3: [200, 300) ...
|
||||
// if compare shard keys=20, it belong to shard 1 ; if keys=100, it belong to shard 2 ; keys=220, belong to shard 3
|
||||
// if keys=120, will walk [shard 2, shard end]
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
keys := [][]byte{blobName} // todo: support two specified shard keys
|
||||
|
||||
ci := sharding.NewCompareItem(sharding.RangeType_RangeTypeHash, keys)
|
||||
ci := sharding.NewCompareItem(sharding.RangeType_RangeTypeHash, shardKeys)
|
||||
var si *shard
|
||||
pivot := s.ranges.Max()
|
||||
pivot := &compareItem{ci: *ci}
|
||||
|
||||
s.ranges.DescendLessOrEqual(pivot, func(i btree.Item) bool {
|
||||
s.ranges.AscendGreaterOrEqual(pivot, func(i btree.Item) bool {
|
||||
si = i.(*shard)
|
||||
|
||||
// span.Debugf("shardID=%d, max boundary=%d, compare=%d", si.shardID, si.rangeExt.MaxBoundary(), ci.GetBoundary())
|
||||
if si.belong(ci) {
|
||||
return false
|
||||
}
|
||||
|
||||
si = nil
|
||||
return true
|
||||
})
|
||||
|
||||
if si == nil { // not found
|
||||
span.Errorf("not find shard. blobName:%s, shard len:%d", blobName, s.ranges.Len())
|
||||
return nil, fmt.Errorf("can not find expect shard")
|
||||
if si == nil { // not found expect shard
|
||||
span.Errorf("not find shard. name:%s, shard len:%d", shardKeys, s.ranges.Len())
|
||||
return nil, errcode.ErrAccessNotFoundShard
|
||||
}
|
||||
return si, nil
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) GetShardByID(ctx context.Context, shardID proto.ShardID) (Shard, error) {
|
||||
sd, ok := s.getShardByID(shardID)
|
||||
if ok {
|
||||
return sd, nil
|
||||
}
|
||||
|
||||
// not found expect shard
|
||||
return nil, errcode.ErrAccessNotFoundShard
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) GetFisrtShard(ctx context.Context) (Shard, error) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
min := s.ranges.Min()
|
||||
if min == nil { // not found expect shard
|
||||
span.Errorf("not find shard. name:%s, shard len:%d", s.ranges.Len())
|
||||
return nil, errcode.ErrAccessNotFoundShard
|
||||
}
|
||||
|
||||
return min.(*shard), nil
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) GetShardByRange(ctx context.Context, shardRange sharding.Range) (Shard, error) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
var si *shard
|
||||
pivot := &shard{rangeExt: shardRange}
|
||||
|
||||
// todo: shard ranges split, old shard range cant find
|
||||
s.ranges.DescendLessOrEqual(pivot, func(i btree.Item) bool {
|
||||
si = i.(*shard)
|
||||
if si.contain(&shardRange) {
|
||||
return false
|
||||
}
|
||||
si = nil
|
||||
return true
|
||||
})
|
||||
|
||||
if si == nil { // not found expect shard
|
||||
span.Errorf("not find shard. range:%s, shard len:%d", common.RawString(shardRange), s.ranges.Len())
|
||||
return nil, errcode.ErrAccessNotFoundShard
|
||||
}
|
||||
return si, nil
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) GetNextShard(ctx context.Context, shardRange sharding.Range) (Shard, error) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
var si *shard
|
||||
pivot := &shard{rangeExt: shardRange}
|
||||
|
||||
// todo: If two shard merge, it is possible that the shard queried contains the shard range
|
||||
s.ranges.AscendGreaterOrEqual(pivot, func(i btree.Item) bool {
|
||||
si = i.(*shard)
|
||||
if !si.contain(&shardRange) {
|
||||
return false
|
||||
}
|
||||
si = nil
|
||||
return true
|
||||
})
|
||||
|
||||
if si == nil { // not found expect shard
|
||||
span.Errorf("not find shard. range:%s, shard len:%d", common.RawString(shardRange), s.ranges.Len())
|
||||
return nil, errcode.ErrAccessNotFoundShard
|
||||
}
|
||||
return si, nil
|
||||
}
|
||||
|
||||
@ -132,8 +212,24 @@ func (s *shardControllerImpl) GetSpaceID() proto.SpaceID {
|
||||
return s.spaceID
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) Update(ctx context.Context) error {
|
||||
return s.updateShard(ctx)
|
||||
func (s *shardControllerImpl) UpdateRoute(ctx context.Context) error {
|
||||
return s.updateRoute(ctx)
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) UpdateShard(ctx context.Context, sd shardnode.ShardStats) error {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("will update shard=%v", sd)
|
||||
|
||||
newShard := &shard{
|
||||
shardID: sd.Suid.ShardID(),
|
||||
version: sd.RouteVersion,
|
||||
leaderDiskID: sd.LeaderDiskID,
|
||||
rangeExt: sd.Range,
|
||||
units: sd.Units,
|
||||
}
|
||||
s.replaceShard(newShard)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) initSpace(ctx context.Context) error {
|
||||
@ -164,11 +260,11 @@ func (s *shardControllerImpl) initSpace(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) initShard(ctx context.Context) error {
|
||||
return s.updateShard(ctx)
|
||||
func (s *shardControllerImpl) initRoute(ctx context.Context) error {
|
||||
return s.updateRoute(ctx)
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) incrementalShard() {
|
||||
func (s *shardControllerImpl) incrementalRoute() {
|
||||
span, ctx := trace.StartSpanFromContext(context.Background(), "")
|
||||
tk := time.NewTicker(time.Second * time.Duration(s.conf.reloadSecs))
|
||||
defer tk.Stop()
|
||||
@ -176,7 +272,7 @@ func (s *shardControllerImpl) incrementalShard() {
|
||||
for {
|
||||
select {
|
||||
case <-tk.C:
|
||||
s.updateShard(ctx)
|
||||
s.updateRoute(ctx)
|
||||
case <-s.stopCh:
|
||||
span.Info("exit shard controller")
|
||||
return
|
||||
@ -185,10 +281,10 @@ func (s *shardControllerImpl) incrementalShard() {
|
||||
}
|
||||
|
||||
// called by period task, or read/write fail
|
||||
func (s *shardControllerImpl) updateShard(ctx context.Context) error {
|
||||
func (s *shardControllerImpl) updateRoute(ctx context.Context) error {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
|
||||
version := s.getVersion() // todo: optimize locker
|
||||
version := s.getVersion()
|
||||
|
||||
ret, err := s.cmCli.GetCatalogChanges(ctx, &clustermgr.GetCatalogChangesArgs{
|
||||
RouteVersion: version,
|
||||
@ -274,7 +370,7 @@ func (s *shardControllerImpl) setVersion(version proto.RouteVersion) {
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) addShard(si *shard) {
|
||||
// todo: I will optimize locker in the next MR
|
||||
// todo: I will optimize locker in the next version
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
@ -282,17 +378,27 @@ func (s *shardControllerImpl) addShard(si *shard) {
|
||||
s.ranges.ReplaceOrInsert(si)
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) delShard(si *shard) {
|
||||
func (s *shardControllerImpl) replaceShard(si *shard) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
shard, ok := s.shards[si.shardID]
|
||||
s.delShardNoLock(si)
|
||||
s.addShardNoLock(si)
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) delShardNoLock(si *shard) {
|
||||
sd, ok := s.shards[si.shardID]
|
||||
if ok {
|
||||
s.ranges.Delete(shard)
|
||||
s.ranges.Delete(sd)
|
||||
delete(s.shards, si.shardID)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) addShardNoLock(si *shard) {
|
||||
s.shards[si.shardID] = si
|
||||
s.ranges.ReplaceOrInsert(si)
|
||||
}
|
||||
|
||||
func (s *shardControllerImpl) getShardByID(shardID proto.ShardID) (*shard, bool) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
@ -330,6 +436,8 @@ type ShardOpInfo struct {
|
||||
type Shard interface {
|
||||
GetShardLeader() ShardOpInfo
|
||||
GetShardRandom() ShardOpInfo
|
||||
GetShardID() proto.ShardID
|
||||
GetRange() sharding.Range
|
||||
}
|
||||
|
||||
// shard implement btree.Item interface, shard route information
|
||||
@ -342,13 +450,14 @@ type shard struct {
|
||||
}
|
||||
|
||||
func (i *shard) Less(item btree.Item) bool {
|
||||
than := item.(*shard)
|
||||
|
||||
return i.rangeExt.MaxBoundary().Less(than.rangeExt.MaxBoundary())
|
||||
}
|
||||
|
||||
func (i *shard) Copy() btree.Item {
|
||||
return i
|
||||
switch than := item.(type) {
|
||||
case *shard:
|
||||
return i.rangeExt.MaxBoundary().Less(than.rangeExt.MaxBoundary())
|
||||
case *compareItem:
|
||||
return i.rangeExt.MaxBoundary().Less(than.ci.GetBoundary())
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (i *shard) String() string {
|
||||
@ -365,6 +474,14 @@ func (i *shard) GetShardRandom() ShardOpInfo {
|
||||
return *i.getShardOpInfo(idx)
|
||||
}
|
||||
|
||||
func (i *shard) GetShardID() proto.ShardID {
|
||||
return i.shardID
|
||||
}
|
||||
|
||||
func (i *shard) GetRange() sharding.Range {
|
||||
return i.rangeExt
|
||||
}
|
||||
|
||||
func (i *shard) getShardOpInfo(idx int) *ShardOpInfo {
|
||||
return &ShardOpInfo{
|
||||
DiskID: i.units[idx].DiskID,
|
||||
@ -386,6 +503,23 @@ func (i *shard) belong(ci *sharding.CompareItem) bool {
|
||||
return i.rangeExt.Belong(ci)
|
||||
}
|
||||
|
||||
func (i *shard) contain(rg *sharding.Range) bool {
|
||||
return i.rangeExt.Contain(rg)
|
||||
}
|
||||
|
||||
type compareItem struct {
|
||||
ci sharding.CompareItem
|
||||
}
|
||||
|
||||
func (i *compareItem) Less(item btree.Item) bool {
|
||||
than := item.(*shard)
|
||||
return i.ci.GetBoundary().Less(than.rangeExt.MaxBoundary())
|
||||
}
|
||||
|
||||
func (i *compareItem) String() string {
|
||||
return i.ci.String()
|
||||
}
|
||||
|
||||
func convertShardUnitInfo(units []clustermgr.ShardUnitInfo) []clustermgr.ShardUnit {
|
||||
ret := make([]clustermgr.ShardUnit, len(units))
|
||||
|
||||
|
||||
@ -6,23 +6,28 @@ import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/types"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/btree"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cubefs/cubefs/blobstore/api/clustermgr"
|
||||
"github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
"github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
"github.com/cubefs/cubefs/blobstore/common/sharding"
|
||||
"github.com/cubefs/cubefs/blobstore/testing/mocks"
|
||||
)
|
||||
|
||||
var (
|
||||
gAny = gomock.Any()
|
||||
errMock = errors.New("fake error")
|
||||
)
|
||||
|
||||
func TestShardController(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
gAny := gomock.Any()
|
||||
errMock := errors.New("fake error")
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
ctr := gomock.NewController(&testing.T{})
|
||||
ctr := gomock.NewController(t)
|
||||
cmCli := mocks.NewMockClientAPI(ctr)
|
||||
cmCli.EXPECT().AuthSpace(gAny, gAny).Return(nil)
|
||||
cmCli.EXPECT().GetSpaceByName(gAny, gAny).Return(&clustermgr.Space{
|
||||
@ -38,8 +43,9 @@ func TestShardController(t *testing.T) {
|
||||
require.NotEqual(t, errMock, err)
|
||||
|
||||
blobName := []byte("blob1")
|
||||
shardKeys := [][]byte{blobName}
|
||||
// empty tree
|
||||
_, err = s.GetShard(ctx, blobName)
|
||||
_, err = s.GetShard(ctx, shardKeys)
|
||||
require.NotNil(t, err)
|
||||
|
||||
sh := &shard{
|
||||
@ -49,8 +55,8 @@ func TestShardController(t *testing.T) {
|
||||
// rangePtr := sharding.New(sharding.RangeType_RangeTypeHash, 2) // keys len=1; subs len=2. will panic
|
||||
rangePtr := sharding.New(sharding.RangeType_RangeTypeHash, 1)
|
||||
for i := range rangePtr.Subs {
|
||||
rangePtr.Subs[i].Min = uint64(i * 10)
|
||||
rangePtr.Subs[i].Max = uint64(i+1) * 10
|
||||
rangePtr.Subs[i].Min = uint64(i * 1)
|
||||
rangePtr.Subs[i].Max = uint64(i+1) * 1
|
||||
}
|
||||
sh.rangeExt = *rangePtr
|
||||
svr := &shardControllerImpl{
|
||||
@ -60,54 +66,260 @@ func TestShardController(t *testing.T) {
|
||||
|
||||
// add one, not found blob
|
||||
svr.addShard(sh)
|
||||
_, err = svr.GetShard(ctx, blobName)
|
||||
_, err = svr.GetShard(ctx, shardKeys)
|
||||
require.NotNil(t, err)
|
||||
svr.delShard(sh)
|
||||
svr.delShardNoLock(sh)
|
||||
|
||||
ranges := sharding.InitShardingRange(sharding.RangeType_RangeTypeHash, 1, 8)
|
||||
{
|
||||
// add 8 shard
|
||||
shards := make([]*shard, 8)
|
||||
for i := 0; i < 8; i++ {
|
||||
shard := &shard{
|
||||
sd := &shard{
|
||||
shardID: proto.ShardID(i + 1),
|
||||
version: 1,
|
||||
}
|
||||
shard.rangeExt = sharding.Range{
|
||||
Type: sharding.RangeType_RangeTypeHash,
|
||||
Subs: []sharding.SubRange{
|
||||
{Min: uint64(i * 10), Max: uint64(i+1) * 10},
|
||||
// {Min: 0, Max: math.MaxUint64},
|
||||
},
|
||||
}
|
||||
shards[i] = shard
|
||||
sd.rangeExt = *ranges[i]
|
||||
shards[i] = sd
|
||||
}
|
||||
shards[7].rangeExt.Subs[0].Max = math.MaxUint64
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
svr.addShard(shards[i])
|
||||
}
|
||||
|
||||
ret, err := svr.GetShard(ctx, []byte("blob1__xxx")) // expect 2 keys
|
||||
ret, err := svr.GetShard(ctx, [][]byte{[]byte("blob1__xxx")}) // expect 2 keys
|
||||
sk := [][]byte{[]byte("blob1__xxx")}
|
||||
bd := sharding.NewCompareItem(sharding.RangeType_RangeTypeHash, sk).GetBoundary()
|
||||
t.Logf("shard key 1, get boundary=%d", bd)
|
||||
// for i := range shards {
|
||||
// sBd := shards[i].rangeExt.MaxBoundary()
|
||||
// t.Logf("shard=%d, boundary=%d, isLess=%v", shards[i].shardID, sBd, bd.Less(sBd))
|
||||
// }
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, proto.ShardID(8), ret.(*shard).shardID)
|
||||
require.Equal(t, proto.ShardID(2), ret.(*shard).shardID)
|
||||
|
||||
// require.Panics(t, func() {
|
||||
// // will panic at hashrange.go Belong, not math array length; key len=1, subRange=2
|
||||
// _, err = svr.GetShard(ctx, blobName)
|
||||
// })
|
||||
|
||||
ret, err = svr.GetShard(ctx, []byte("blob2__yy"))
|
||||
ret, err = svr.GetShard(ctx, [][]byte{[]byte("blob2__yy")})
|
||||
bd = sharding.NewCompareItem(sharding.RangeType_RangeTypeHash, [][]byte{[]byte("blob2__yy")}).GetBoundary()
|
||||
t.Logf("shard key 2, get boundary=%d", bd)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, proto.ShardID(8), ret.(*shard).shardID)
|
||||
|
||||
// ret, err = svr.GetShard(ctx, []byte("blob1__xx__xx"))
|
||||
// require.NotNil(t, err)
|
||||
// require.Equal(t, proto.ShardID(0), ret.ShardID)
|
||||
require.Equal(t, proto.ShardID(7), ret.(*shard).shardID)
|
||||
}
|
||||
|
||||
{
|
||||
// get
|
||||
si, ok := svr.getShardByID(1)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, proto.ShardID(1), si.shardID)
|
||||
|
||||
svr.spaceID = 1
|
||||
spID := svr.GetSpaceID()
|
||||
require.Equal(t, proto.SpaceID(1), spID)
|
||||
|
||||
// update shard
|
||||
newShard := *si
|
||||
newShard.version++
|
||||
err = svr.UpdateShard(ctx, shardnode.ShardStats{
|
||||
Suid: proto.EncodeSuid(newShard.shardID, 1, 2),
|
||||
LeaderDiskID: newShard.leaderDiskID,
|
||||
RouteVersion: newShard.version,
|
||||
Range: newShard.rangeExt,
|
||||
Units: newShard.units,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, svr.version, si.version)
|
||||
// require.Equal(t, svr.version, newShard.version)
|
||||
|
||||
si, ok = svr.getShardByID(1)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, newShard, *si)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShardUpdate(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctr := gomock.NewController(t)
|
||||
cmCli := mocks.NewMockClientAPI(ctr)
|
||||
svr := &shardControllerImpl{
|
||||
shards: make(map[proto.ShardID]*shard),
|
||||
ranges: btree.New(defaultBTreeDegree),
|
||||
}
|
||||
|
||||
{
|
||||
// update
|
||||
cmCli.EXPECT().GetCatalogChanges(gAny, gAny).Return(&clustermgr.GetCatalogChangesRet{}, errMock)
|
||||
svr.cmCli = cmCli
|
||||
err := svr.UpdateRoute(ctx)
|
||||
require.ErrorIs(t, err, errMock)
|
||||
}
|
||||
|
||||
ranges := sharding.InitShardingRange(sharding.RangeType_RangeTypeHash, 1, 10)
|
||||
{
|
||||
const shardID = 9
|
||||
const version = 3
|
||||
val := clustermgr.CatalogChangeShardAdd{
|
||||
ShardID: shardID,
|
||||
RouteVersion: version,
|
||||
Units: []clustermgr.ShardUnitInfo{
|
||||
{
|
||||
Suid: proto.EncodeSuid(shardID, 0, 0),
|
||||
DiskID: 0,
|
||||
AppliedIndex: 0,
|
||||
LeaderDiskID: 0,
|
||||
Range: *ranges[8],
|
||||
RouteVersion: version,
|
||||
Host: "",
|
||||
Learner: false,
|
||||
Status: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
data, err := val.Marshal()
|
||||
require.NoError(t, err)
|
||||
retCatlog := &clustermgr.GetCatalogChangesRet{
|
||||
RouteVersion: version,
|
||||
Items: []clustermgr.CatalogChangeItem{
|
||||
{
|
||||
RouteVersion: version,
|
||||
Type: proto.CatalogChangeItemAddShard,
|
||||
Item: &types.Any{
|
||||
TypeUrl: "",
|
||||
Value: data,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
cmCli.EXPECT().GetCatalogChanges(gAny, gAny).Return(retCatlog, nil)
|
||||
svr.cmCli = cmCli
|
||||
err = svr.UpdateRoute(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, proto.RouteVersion(version), svr.version)
|
||||
|
||||
si, ok := svr.getShardByID(shardID)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, proto.ShardID(shardID), si.shardID)
|
||||
}
|
||||
|
||||
{
|
||||
const shardID = 10
|
||||
const oldVersion = 4
|
||||
const version = 5
|
||||
sd := &shard{
|
||||
shardID: proto.ShardID(shardID),
|
||||
version: oldVersion,
|
||||
units: make([]clustermgr.ShardUnit, 1),
|
||||
}
|
||||
sd.rangeExt = *ranges[9]
|
||||
svr.addShard(sd)
|
||||
|
||||
val := clustermgr.CatalogChangeShardUpdate{
|
||||
ShardID: shardID,
|
||||
RouteVersion: version,
|
||||
Unit: clustermgr.ShardUnitInfo{
|
||||
Suid: proto.EncodeSuid(shardID, 0, 0),
|
||||
DiskID: 0,
|
||||
AppliedIndex: 0,
|
||||
LeaderDiskID: 0,
|
||||
Range: *ranges[9],
|
||||
RouteVersion: version,
|
||||
Host: "",
|
||||
Learner: false,
|
||||
Status: 0,
|
||||
},
|
||||
}
|
||||
data, err := val.Marshal()
|
||||
require.NoError(t, err)
|
||||
retCatlog := &clustermgr.GetCatalogChangesRet{
|
||||
RouteVersion: version,
|
||||
Items: []clustermgr.CatalogChangeItem{
|
||||
{
|
||||
Type: proto.CatalogChangeItemUpdateShard,
|
||||
Item: &types.Any{
|
||||
TypeUrl: "",
|
||||
Value: data,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
cmCli.EXPECT().GetCatalogChanges(gAny, gAny).Return(retCatlog, nil)
|
||||
svr.cmCli = cmCli
|
||||
err = svr.UpdateRoute(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, proto.RouteVersion(version), svr.version)
|
||||
|
||||
si, ok := svr.getShardByID(shardID)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, proto.ShardID(shardID), si.shardID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShardGetShard(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
svr := &shardControllerImpl{
|
||||
shards: make(map[proto.ShardID]*shard),
|
||||
ranges: btree.New(defaultBTreeDegree),
|
||||
}
|
||||
// add 8 shard
|
||||
shards := make([]*shard, 8)
|
||||
ranges := sharding.InitShardingRange(sharding.RangeType_RangeTypeHash, 1, 8)
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
sd := &shard{
|
||||
shardID: proto.ShardID(i + 1),
|
||||
version: 1,
|
||||
units: []clustermgr.ShardUnit{
|
||||
{
|
||||
Suid: proto.EncodeSuid(proto.ShardID(i+1), 0, 0),
|
||||
DiskID: 1,
|
||||
Learner: true,
|
||||
Host: "testHost",
|
||||
},
|
||||
},
|
||||
}
|
||||
sd.rangeExt = *ranges[i]
|
||||
shards[i] = sd
|
||||
}
|
||||
shards[7].rangeExt.Subs[0].Max = math.MaxUint64
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
svr.addShard(shards[i])
|
||||
}
|
||||
|
||||
{
|
||||
// shard others
|
||||
ret, err := svr.GetShardByID(ctx, proto.ShardID(1))
|
||||
require.NoError(t, err)
|
||||
|
||||
shardInfo := ret.GetShardLeader()
|
||||
require.Equal(t, shards[0].shardID, shardInfo.Suid.ShardID())
|
||||
|
||||
shardInfo = ret.GetShardRandom()
|
||||
require.Equal(t, shards[0].shardID, shardInfo.Suid.ShardID())
|
||||
|
||||
shardID := ret.GetShardID()
|
||||
require.Equal(t, shards[0].shardID, shardID)
|
||||
}
|
||||
|
||||
// get first shard
|
||||
{
|
||||
sd, err := svr.GetFisrtShard(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, proto.ShardID(1), sd.GetShardID())
|
||||
}
|
||||
|
||||
// get shard by range
|
||||
{
|
||||
ret, err := svr.GetShardByID(ctx, proto.ShardID(2))
|
||||
require.NoError(t, err)
|
||||
shardRange := ret.GetRange()
|
||||
|
||||
sd, err := svr.GetShardByRange(ctx, shardRange)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, proto.ShardID(2), sd.GetShardID())
|
||||
require.Equal(t, shardRange, sd.GetRange())
|
||||
|
||||
sd, err = svr.GetNextShard(ctx, shardRange)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, proto.ShardID(3), sd.GetShardID())
|
||||
require.NotEqual(t, shardRange, sd.GetRange())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/cubefs/cubefs/blobstore/access/controller (interfaces: ClusterController,ServiceController,VolumeGetter)
|
||||
// Source: github.com/cubefs/cubefs/blobstore/access/controller (interfaces: ClusterController,ServiceController,VolumeGetter,IShardController,Shard)
|
||||
|
||||
// Package stream is a generated GoMock package.
|
||||
package stream
|
||||
@ -10,7 +10,9 @@ import (
|
||||
|
||||
controller "github.com/cubefs/cubefs/blobstore/access/controller"
|
||||
clustermgr "github.com/cubefs/cubefs/blobstore/api/clustermgr"
|
||||
shardnode "github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
proto "github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
sharding "github.com/cubefs/cubefs/blobstore/common/sharding"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
@ -357,3 +359,222 @@ func (mr *MockVolumeGetterMockRecorder) Update(arg0, arg1 interface{}) *gomock.C
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockVolumeGetter)(nil).Update), arg0, arg1)
|
||||
}
|
||||
|
||||
// MockShardController is a mock of IShardController interface.
|
||||
type MockShardController struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockShardControllerMockRecorder
|
||||
}
|
||||
|
||||
// MockShardControllerMockRecorder is the mock recorder for MockShardController.
|
||||
type MockShardControllerMockRecorder struct {
|
||||
mock *MockShardController
|
||||
}
|
||||
|
||||
// NewMockShardController creates a new mock instance.
|
||||
func NewMockShardController(ctrl *gomock.Controller) *MockShardController {
|
||||
mock := &MockShardController{ctrl: ctrl}
|
||||
mock.recorder = &MockShardControllerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockShardController) EXPECT() *MockShardControllerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetFisrtShard mocks base method.
|
||||
func (m *MockShardController) GetFisrtShard(arg0 context.Context) (controller.Shard, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetFisrtShard", arg0)
|
||||
ret0, _ := ret[0].(controller.Shard)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetFisrtShard indicates an expected call of GetFisrtShard.
|
||||
func (mr *MockShardControllerMockRecorder) GetFisrtShard(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFisrtShard", reflect.TypeOf((*MockShardController)(nil).GetFisrtShard), arg0)
|
||||
}
|
||||
|
||||
// GetNextShard mocks base method.
|
||||
func (m *MockShardController) GetNextShard(arg0 context.Context, arg1 sharding.Range) (controller.Shard, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetNextShard", arg0, arg1)
|
||||
ret0, _ := ret[0].(controller.Shard)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetNextShard indicates an expected call of GetNextShard.
|
||||
func (mr *MockShardControllerMockRecorder) GetNextShard(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNextShard", reflect.TypeOf((*MockShardController)(nil).GetNextShard), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetShard mocks base method.
|
||||
func (m *MockShardController) GetShard(arg0 context.Context, arg1 [][]byte) (controller.Shard, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetShard", arg0, arg1)
|
||||
ret0, _ := ret[0].(controller.Shard)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetShard indicates an expected call of GetShard.
|
||||
func (mr *MockShardControllerMockRecorder) GetShard(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetShard", reflect.TypeOf((*MockShardController)(nil).GetShard), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetShardByID mocks base method.
|
||||
func (m *MockShardController) GetShardByID(arg0 context.Context, arg1 proto.ShardID) (controller.Shard, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetShardByID", arg0, arg1)
|
||||
ret0, _ := ret[0].(controller.Shard)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetShardByID indicates an expected call of GetShardByID.
|
||||
func (mr *MockShardControllerMockRecorder) GetShardByID(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetShardByID", reflect.TypeOf((*MockShardController)(nil).GetShardByID), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetShardByRange mocks base method.
|
||||
func (m *MockShardController) GetShardByRange(arg0 context.Context, arg1 sharding.Range) (controller.Shard, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetShardByRange", arg0, arg1)
|
||||
ret0, _ := ret[0].(controller.Shard)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetShardByRange indicates an expected call of GetShardByRange.
|
||||
func (mr *MockShardControllerMockRecorder) GetShardByRange(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetShardByRange", reflect.TypeOf((*MockShardController)(nil).GetShardByRange), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetSpaceID mocks base method.
|
||||
func (m *MockShardController) GetSpaceID() proto.SpaceID {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetSpaceID")
|
||||
ret0, _ := ret[0].(proto.SpaceID)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetSpaceID indicates an expected call of GetSpaceID.
|
||||
func (mr *MockShardControllerMockRecorder) GetSpaceID() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSpaceID", reflect.TypeOf((*MockShardController)(nil).GetSpaceID))
|
||||
}
|
||||
|
||||
// UpdateRoute mocks base method.
|
||||
func (m *MockShardController) UpdateRoute(arg0 context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateRoute", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateRoute indicates an expected call of UpdateRoute.
|
||||
func (mr *MockShardControllerMockRecorder) UpdateRoute(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateRoute", reflect.TypeOf((*MockShardController)(nil).UpdateRoute), arg0)
|
||||
}
|
||||
|
||||
// UpdateShard mocks base method.
|
||||
func (m *MockShardController) UpdateShard(arg0 context.Context, arg1 shardnode.ShardStats) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateShard", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateShard indicates an expected call of UpdateShard.
|
||||
func (mr *MockShardControllerMockRecorder) UpdateShard(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateShard", reflect.TypeOf((*MockShardController)(nil).UpdateShard), arg0, arg1)
|
||||
}
|
||||
|
||||
// MockShard is a mock of Shard interface.
|
||||
type MockShard struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockShardMockRecorder
|
||||
}
|
||||
|
||||
// MockShardMockRecorder is the mock recorder for MockShard.
|
||||
type MockShardMockRecorder struct {
|
||||
mock *MockShard
|
||||
}
|
||||
|
||||
// NewMockShard creates a new mock instance.
|
||||
func NewMockShard(ctrl *gomock.Controller) *MockShard {
|
||||
mock := &MockShard{ctrl: ctrl}
|
||||
mock.recorder = &MockShardMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockShard) EXPECT() *MockShardMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetRange mocks base method.
|
||||
func (m *MockShard) GetRange() sharding.Range {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetRange")
|
||||
ret0, _ := ret[0].(sharding.Range)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetRange indicates an expected call of GetRange.
|
||||
func (mr *MockShardMockRecorder) GetRange() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRange", reflect.TypeOf((*MockShard)(nil).GetRange))
|
||||
}
|
||||
|
||||
// GetShardID mocks base method.
|
||||
func (m *MockShard) GetShardID() proto.ShardID {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetShardID")
|
||||
ret0, _ := ret[0].(proto.ShardID)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetShardID indicates an expected call of GetShardID.
|
||||
func (mr *MockShardMockRecorder) GetShardID() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetShardID", reflect.TypeOf((*MockShard)(nil).GetShardID))
|
||||
}
|
||||
|
||||
// GetShardLeader mocks base method.
|
||||
func (m *MockShard) GetShardLeader() controller.ShardOpInfo {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetShardLeader")
|
||||
ret0, _ := ret[0].(controller.ShardOpInfo)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetShardLeader indicates an expected call of GetShardLeader.
|
||||
func (mr *MockShardMockRecorder) GetShardLeader() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetShardLeader", reflect.TypeOf((*MockShard)(nil).GetShardLeader))
|
||||
}
|
||||
|
||||
// GetShardRandom mocks base method.
|
||||
func (m *MockShard) GetShardRandom() controller.ShardOpInfo {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetShardRandom")
|
||||
ret0, _ := ret[0].(controller.ShardOpInfo)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetShardRandom indicates an expected call of GetShardRandom.
|
||||
func (mr *MockShardMockRecorder) GetShardRandom() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetShardRandom", reflect.TypeOf((*MockShard)(nil).GetShardRandom))
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@ import (
|
||||
|
||||
"github.com/afex/hystrix-go/hystrix"
|
||||
|
||||
"github.com/cubefs/cubefs/blobstore/access/client"
|
||||
"github.com/cubefs/cubefs/blobstore/access/controller"
|
||||
"github.com/cubefs/cubefs/blobstore/api/access"
|
||||
"github.com/cubefs/cubefs/blobstore/api/blobnode"
|
||||
@ -31,12 +30,9 @@ import (
|
||||
"github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
"github.com/cubefs/cubefs/blobstore/common/codemode"
|
||||
"github.com/cubefs/cubefs/blobstore/common/ec"
|
||||
errcode "github.com/cubefs/cubefs/blobstore/common/errors"
|
||||
"github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
"github.com/cubefs/cubefs/blobstore/common/resourcepool"
|
||||
"github.com/cubefs/cubefs/blobstore/common/rpc"
|
||||
"github.com/cubefs/cubefs/blobstore/common/trace"
|
||||
sdkproto "github.com/cubefs/cubefs/blobstore/sdk/base"
|
||||
"github.com/cubefs/cubefs/blobstore/util/defaulter"
|
||||
"github.com/cubefs/cubefs/blobstore/util/errors"
|
||||
"github.com/cubefs/cubefs/blobstore/util/retry"
|
||||
@ -105,8 +101,18 @@ type StreamHandler interface {
|
||||
|
||||
// Admin returns internal admin interface.
|
||||
Admin() interface{}
|
||||
// GetBlob returns blobs
|
||||
GetBlob(ctx context.Context, args *sdkproto.GetBlobArgs) (*proto.Location, error)
|
||||
// GetBlob returns location
|
||||
GetBlob(ctx context.Context, args *access.GetBlobArgs) (*proto.Location, error)
|
||||
// DeleteBlob returns error
|
||||
DeleteBlob(ctx context.Context, args *access.DelBlobArgs) error
|
||||
// SealBlob returns error
|
||||
SealBlob(ctx context.Context, args *access.SealBlobArgs) error
|
||||
// CreateBlob returns location
|
||||
CreateBlob(ctx context.Context, args *access.CreateBlobArgs) (*proto.Location, error)
|
||||
// ListBlob returns blobs
|
||||
ListBlob(ctx context.Context, args *access.ListBlobArgs) (*shardnode.ListBlobRet, error)
|
||||
// AllocSlice returns alloc blob
|
||||
AllocSlice(ctx context.Context, args *access.AllocSliceArgs) (*shardnode.AllocSliceRet, error)
|
||||
}
|
||||
|
||||
type StreamAdmin struct {
|
||||
@ -115,6 +121,10 @@ type StreamAdmin struct {
|
||||
Controller controller.ClusterController
|
||||
}
|
||||
|
||||
type ShardnodeConfig struct {
|
||||
shardnode.Config
|
||||
}
|
||||
|
||||
// StreamConfig access stream handler config
|
||||
type StreamConfig struct {
|
||||
IDC string `json:"idc"`
|
||||
@ -145,7 +155,7 @@ type StreamConfig struct {
|
||||
ClusterConfig controller.ClusterConfig `json:"cluster_config"`
|
||||
BlobnodeConfig blobnode.Config `json:"blobnode_config"`
|
||||
ProxyConfig proxy.Config `json:"proxy_config"`
|
||||
ShardnodeConfig client.Config `json:"shardnode_config"`
|
||||
ShardnodeConfig *ShardnodeConfig `json:"shardnode_config"`
|
||||
|
||||
// hystrix command config
|
||||
AllocCommandConfig hystrix.CommandConfig `json:"alloc_command_config"`
|
||||
@ -177,7 +187,7 @@ type Handler struct {
|
||||
|
||||
blobnodeClient blobnode.StorageAPI
|
||||
proxyClient proxy.Client
|
||||
shardnodeClient client.ShardnodeAPI // todo: now use mock client, i will update it when api/shardnode/blob.go is ok
|
||||
shardnodeClient shardnode.AccessAPI
|
||||
|
||||
allCodeModes CodeModePairs
|
||||
maxObjectSize int64
|
||||
@ -265,11 +275,14 @@ func NewStreamHandler(cfg *StreamConfig, stopCh <-chan struct{}) (h StreamHandle
|
||||
|
||||
blobnodeClient: blobnode.New(&cfg.BlobnodeConfig),
|
||||
proxyClient: proxyClient,
|
||||
shardnodeClient: client.New(&cfg.ShardnodeConfig),
|
||||
shardnodeClient: shardnode.NewNonsupportShardnode(),
|
||||
|
||||
maxObjectSize: defaultMaxObjectSize,
|
||||
StreamConfig: *cfg,
|
||||
}
|
||||
if cfg.ShardnodeConfig != nil { // enable shard node
|
||||
handler.shardnodeClient = shardnode.New(cfg.ShardnodeConfig.Config)
|
||||
}
|
||||
|
||||
rawCodeModePolicies, err := handler.clusterController.GetConfig(context.Background(), proto.CodeModeConfigKey)
|
||||
if err != nil {
|
||||
@ -342,32 +355,6 @@ func (h *Handler) Admin() interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) GetBlob(ctx context.Context, args *sdkproto.GetBlobArgs) (*proto.Location, error) {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("get blob args:%+v", *args)
|
||||
|
||||
header, err := h.getShardOpHeader(ctx, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
host, err := h.getShardHost(ctx, args.ClusterID, header.DiskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blob, err := h.shardnodeClient.GetBlob(ctx, host, &shardnode.GetBlobArgs{
|
||||
Header: *header,
|
||||
Name: args.BlobName,
|
||||
})
|
||||
if err != nil {
|
||||
h.punishAndUpdate(ctx, args.ClusterID, header.DiskID, host, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &blob.Blob.Location, nil
|
||||
}
|
||||
|
||||
func (h *Handler) sendRepairMsgBg(ctx context.Context, blob blobIdent, badIdxes []uint8) {
|
||||
ctx = trace.NewContextFromContext(ctx)
|
||||
go func() {
|
||||
@ -512,13 +499,6 @@ func (h *Handler) punishDisk(ctx context.Context, clusterID proto.ClusterID, dis
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) punishShardnodeDisk(ctx context.Context, clusterID proto.ClusterID, diskID proto.DiskID, host, reason string) {
|
||||
reportUnhealth(clusterID, "punish", "shardnode", host, reason)
|
||||
if serviceController, err := h.clusterController.GetServiceController(clusterID); err == nil {
|
||||
serviceController.PunishShardnode(ctx, diskID, h.DiskPunishIntervalS)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) punishDiskWith(ctx context.Context, clusterID proto.ClusterID, diskID proto.DiskID, host, reason string) {
|
||||
reportUnhealth(clusterID, "punish", "diskwith", host, reason)
|
||||
if serviceController, err := h.clusterController.GetServiceController(clusterID); err == nil {
|
||||
@ -526,87 +506,6 @@ func (h *Handler) punishDiskWith(ctx context.Context, clusterID proto.ClusterID,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) getShardOpHeader(ctx context.Context, args *sdkproto.GetBlobArgs) (*shardnode.ShardOpHeader, error) {
|
||||
shardMgr, err := h.clusterController.GetShardController(args.ClusterID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shardInfo, err := shardMgr.GetShard(ctx, args.BlobName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var info controller.ShardOpInfo
|
||||
switch args.Mode {
|
||||
case sdkproto.GetShardModeLeader:
|
||||
info = shardInfo.GetShardLeader()
|
||||
case sdkproto.GetShardModeRandom:
|
||||
info = shardInfo.GetShardRandom()
|
||||
default:
|
||||
return nil, errors.Newf("not support get shard mode")
|
||||
}
|
||||
|
||||
spaceID := shardMgr.GetSpaceID()
|
||||
shardKeys := args.ShardKeys
|
||||
if shardKeys == nil {
|
||||
shardKeys = [][]byte{args.BlobName}
|
||||
}
|
||||
|
||||
return &shardnode.ShardOpHeader{
|
||||
SpaceID: spaceID,
|
||||
DiskID: info.DiskID,
|
||||
Suid: info.Suid,
|
||||
RouteVersion: info.RouteVersion,
|
||||
ShardKeys: shardKeys,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Handler) getShardHost(ctx context.Context, clusterID proto.ClusterID, diskID proto.DiskID) (string, error) {
|
||||
s, err := h.clusterController.GetServiceController(clusterID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
hostInfo, err := s.GetShardnodeHost(ctx, diskID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return hostInfo.Host, nil
|
||||
}
|
||||
|
||||
func (h *Handler) punishAndUpdate(ctx context.Context, clusterID proto.ClusterID, diskID proto.DiskID, host string, err error) {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
code := rpc.DetectStatusCode(err)
|
||||
|
||||
switch code {
|
||||
case errcode.CodeDiskBroken: // punish
|
||||
h.punishShardnodeDisk(ctx, clusterID, diskID, host, "Broken")
|
||||
|
||||
case errcode.CodeShardNodeDiskNotFound: // update and punish
|
||||
if err1 := h.updateShardnode(ctx, clusterID); err1 != nil {
|
||||
span.Warnf("need update shard node, cluster:%d, err:%+v", clusterID, err1)
|
||||
}
|
||||
h.punishShardnodeDisk(ctx, clusterID, diskID, host, "NotFound")
|
||||
|
||||
case errcode.CodeShardDoesNotExist, errcode.CodeShardRouteVersionNeedUpdate: // update
|
||||
if err1 := h.updateShardnode(ctx, clusterID); err1 != nil {
|
||||
span.Warnf("need update shard node, cluster:%d, err:%+v", clusterID, err1)
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) updateShardnode(ctx context.Context, clusterID proto.ClusterID) error {
|
||||
shardMgr, err := h.clusterController.GetShardController(clusterID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return shardMgr.Update(ctx)
|
||||
}
|
||||
|
||||
// blobCount blobSize > 0 is certain
|
||||
func blobCount(size uint64, blobSize uint32) uint64 {
|
||||
return (size + uint64(blobSize) - 1) / uint64(blobSize)
|
||||
|
||||
554
blobstore/access/stream/stream_blob.go
Normal file
554
blobstore/access/stream/stream_blob.go
Normal file
@ -0,0 +1,554 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/cubefs/cubefs/blobstore/access/controller"
|
||||
acapi "github.com/cubefs/cubefs/blobstore/api/access"
|
||||
"github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
errcode "github.com/cubefs/cubefs/blobstore/common/errors"
|
||||
"github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
"github.com/cubefs/cubefs/blobstore/common/rpc"
|
||||
"github.com/cubefs/cubefs/blobstore/common/trace"
|
||||
"github.com/cubefs/cubefs/blobstore/util/retry"
|
||||
)
|
||||
|
||||
func (h *Handler) GetBlob(ctx context.Context, args *acapi.GetBlobArgs) (*proto.Location, error) {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("get blob args:%+v", *args)
|
||||
|
||||
var blob shardnode.GetBlobRet
|
||||
rerr := retry.ExponentialBackoff(3, 200).RuptOn(func() (bool, error) {
|
||||
header, err := h.getShardOpHeader(ctx, &acapi.GetShardCommonArgs{
|
||||
ClusterID: args.ClusterID,
|
||||
BlobName: args.BlobName,
|
||||
Mode: args.Mode,
|
||||
ShardKeys: args.ShardKeys,
|
||||
})
|
||||
if err != nil {
|
||||
return true, err // not retry
|
||||
}
|
||||
|
||||
host, err := h.getShardHost(ctx, args.ClusterID, header.DiskID)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
blob, err = h.shardnodeClient.GetBlob(ctx, host, shardnode.GetBlobArgs{
|
||||
Header: header,
|
||||
Name: args.BlobName,
|
||||
})
|
||||
if err != nil {
|
||||
interrupt := h.punishAndUpdate(ctx, &punishArgs{
|
||||
ShardOpHeader: header,
|
||||
clusterID: args.ClusterID,
|
||||
host: host,
|
||||
err: err,
|
||||
})
|
||||
return interrupt, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
|
||||
return &blob.Blob.Location, rerr
|
||||
}
|
||||
|
||||
func (h *Handler) CreateBlob(ctx context.Context, args *acapi.CreateBlobArgs) (*proto.Location, error) {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("create blob args:%+v", *args)
|
||||
|
||||
err := h.fixCreateBlobArgs(ctx, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var blob shardnode.CreateBlobRet
|
||||
rerr := retry.ExponentialBackoff(3, 200).RuptOn(func() (bool, error) {
|
||||
header, err := h.getShardOpHeader(ctx, &acapi.GetShardCommonArgs{
|
||||
ClusterID: args.ClusterID,
|
||||
BlobName: args.BlobName,
|
||||
Mode: acapi.GetShardModeLeader,
|
||||
ShardKeys: args.ShardKeys,
|
||||
})
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
host, err := h.getShardHost(ctx, args.ClusterID, header.DiskID)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
blob, err = h.shardnodeClient.CreateBlob(ctx, host, shardnode.CreateBlobArgs{
|
||||
Header: header,
|
||||
Name: args.BlobName,
|
||||
CodeMode: args.CodeMode,
|
||||
Size_: args.Size,
|
||||
SliceSize: args.SliceSize,
|
||||
})
|
||||
if err != nil {
|
||||
interrupt := h.punishAndUpdate(ctx, &punishArgs{
|
||||
ShardOpHeader: header,
|
||||
clusterID: args.ClusterID,
|
||||
host: host,
|
||||
err: err,
|
||||
})
|
||||
return interrupt, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
||||
return &blob.Blob.Location, rerr
|
||||
}
|
||||
|
||||
func (h *Handler) DeleteBlob(ctx context.Context, args *acapi.DelBlobArgs) error {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("delete blob args:%+v", *args)
|
||||
|
||||
var blob shardnode.GetBlobRet
|
||||
rerr := retry.ExponentialBackoff(3, 200).RuptOn(func() (bool, error) {
|
||||
header, err := h.getShardOpHeader(ctx, &acapi.GetShardCommonArgs{
|
||||
ClusterID: args.ClusterID,
|
||||
BlobName: args.BlobName,
|
||||
Mode: acapi.GetShardModeLeader,
|
||||
ShardKeys: args.ShardKeys,
|
||||
})
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
host, err := h.getShardHost(ctx, args.ClusterID, header.DiskID)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
blob, err = h.shardnodeClient.GetBlob(ctx, host, shardnode.GetBlobArgs{
|
||||
Header: header,
|
||||
Name: args.BlobName,
|
||||
})
|
||||
|
||||
punishFunc := func() bool {
|
||||
return h.punishAndUpdate(ctx, &punishArgs{
|
||||
ShardOpHeader: header,
|
||||
clusterID: args.ClusterID,
|
||||
host: host,
|
||||
err: err,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
interrupt := punishFunc()
|
||||
return interrupt, err
|
||||
}
|
||||
|
||||
err = h.shardnodeClient.DeleteBlob(ctx, host, shardnode.DeleteBlobArgs{
|
||||
Header: header,
|
||||
Name: args.BlobName,
|
||||
})
|
||||
if err != nil {
|
||||
interrupt := punishFunc()
|
||||
return interrupt, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
if rerr != nil {
|
||||
return rerr
|
||||
}
|
||||
|
||||
return h.Delete(ctx, &blob.Blob.Location)
|
||||
}
|
||||
|
||||
func (h *Handler) SealBlob(ctx context.Context, args *acapi.SealBlobArgs) error {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("seal blob args:%+v", *args)
|
||||
|
||||
rerr := retry.ExponentialBackoff(3, 200).RuptOn(func() (bool, error) {
|
||||
header, err := h.getShardOpHeader(ctx, &acapi.GetShardCommonArgs{
|
||||
ClusterID: args.ClusterID,
|
||||
BlobName: args.BlobName,
|
||||
Mode: acapi.GetShardModeLeader,
|
||||
ShardKeys: args.ShardKeys,
|
||||
})
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
host, err := h.getShardHost(ctx, args.ClusterID, header.DiskID)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
err = h.shardnodeClient.SealBlob(ctx, host, shardnode.SealBlobArgs{
|
||||
Header: header,
|
||||
Name: args.BlobName,
|
||||
Slices: args.Slices,
|
||||
})
|
||||
if err != nil {
|
||||
interrupt := h.punishAndUpdate(ctx, &punishArgs{
|
||||
ShardOpHeader: header,
|
||||
clusterID: args.ClusterID,
|
||||
host: host,
|
||||
err: err,
|
||||
})
|
||||
return interrupt, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
||||
return rerr
|
||||
}
|
||||
|
||||
func (h *Handler) ListBlob(ctx context.Context, args *acapi.ListBlobArgs) (*shardnode.ListBlobRet, error) {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("list blob args:%+v", *args)
|
||||
|
||||
if args.ShardID != 0 {
|
||||
return h.listSpecificShard(ctx, args)
|
||||
}
|
||||
|
||||
return h.listManyShards(ctx, args)
|
||||
}
|
||||
|
||||
func (h *Handler) AllocSlice(ctx context.Context, args *acapi.AllocSliceArgs) (*shardnode.AllocSliceRet, error) {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("alloc blob args:%+v", *args)
|
||||
|
||||
var slices shardnode.AllocSliceRet
|
||||
rerr := retry.ExponentialBackoff(3, 200).RuptOn(func() (bool, error) {
|
||||
header, err := h.getShardOpHeader(ctx, &acapi.GetShardCommonArgs{
|
||||
ClusterID: args.ClusterID,
|
||||
BlobName: args.BlobName,
|
||||
Mode: acapi.GetShardModeLeader,
|
||||
ShardKeys: args.ShardKeys,
|
||||
})
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
host, err := h.getShardHost(ctx, args.ClusterID, header.DiskID)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
slices, err = h.shardnodeClient.AllocSlice(ctx, host, shardnode.AllocSliceArgs{
|
||||
Header: header,
|
||||
Name: args.BlobName,
|
||||
CodeMode: args.CodeMode,
|
||||
Size_: args.Size,
|
||||
FailedSlice: args.FailSlice,
|
||||
})
|
||||
if err != nil {
|
||||
interrupt := h.punishAndUpdate(ctx, &punishArgs{
|
||||
ShardOpHeader: header,
|
||||
clusterID: args.ClusterID,
|
||||
host: host,
|
||||
err: err,
|
||||
})
|
||||
return interrupt, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
||||
return &slices, rerr
|
||||
}
|
||||
|
||||
func (h *Handler) listSpecificShard(ctx context.Context, args *acapi.ListBlobArgs) (*shardnode.ListBlobRet, error) {
|
||||
var ret *shardnode.ListBlobRet
|
||||
rerr := retry.ExponentialBackoff(3, 200).RuptOn(func() (bool, error) {
|
||||
header, err := h.getShardHeaderByID(ctx, args.ClusterID, args.ShardID)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
interrupt := false
|
||||
ret, interrupt, err = h.listSingleShardEnough(ctx, args, header)
|
||||
if err != nil {
|
||||
return interrupt, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
return ret, rerr
|
||||
}
|
||||
|
||||
func (h *Handler) listManyShards(ctx context.Context, args *acapi.ListBlobArgs) (*shardnode.ListBlobRet, error) {
|
||||
shardMgr, err := h.clusterController.GetShardController(args.ClusterID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
shard controller.Shard
|
||||
allBlob shardnode.ListBlobRet
|
||||
)
|
||||
if len(args.Marker) == 0 {
|
||||
shard, err = shardMgr.GetFisrtShard(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
unionMarker := shardnode.ListBlobEncodeMarker{}
|
||||
if err = unionMarker.Unmarshal(args.Marker); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
allBlob.NextMarker = unionMarker.Marker
|
||||
shard, err = shardMgr.GetShardByRange(ctx, unionMarker.Range)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
lastRange := shard.GetRange()
|
||||
count := args.Count
|
||||
for count > 0 {
|
||||
var ret *shardnode.ListBlobRet
|
||||
interrupt := false
|
||||
rerr := retry.ExponentialBackoff(3, 200).RuptOn(func() (bool, error) {
|
||||
header := h.getOpHeader(shardMgr, shard)
|
||||
args.Marker = allBlob.NextMarker
|
||||
ret, interrupt, err = h.listSingleShardEnough(ctx, args, header)
|
||||
if err != nil {
|
||||
return interrupt, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
if rerr != nil {
|
||||
return nil, rerr
|
||||
}
|
||||
|
||||
allBlob.Blobs = append(allBlob.Blobs, ret.Blobs...)
|
||||
allBlob.NextMarker = ret.NextMarker
|
||||
count -= uint64(len(ret.Blobs))
|
||||
if ret.NextMarker == nil {
|
||||
shard, err = shardMgr.GetNextShard(ctx, lastRange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lastRange = shard.GetRange()
|
||||
}
|
||||
}
|
||||
|
||||
markers := shardnode.ListBlobEncodeMarker{
|
||||
Range: lastRange,
|
||||
Marker: allBlob.NextMarker,
|
||||
}
|
||||
unionMarker, err := markers.Marshal()
|
||||
allBlob.NextMarker = unionMarker
|
||||
return &allBlob, err
|
||||
}
|
||||
|
||||
func (h *Handler) listSingleShardEnough(ctx context.Context, args *acapi.ListBlobArgs, header shardnode.ShardOpHeader) (*shardnode.ListBlobRet, bool, error) {
|
||||
host, err := h.getShardHost(ctx, args.ClusterID, header.DiskID)
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
|
||||
ret, err := h.shardnodeClient.ListBlob(ctx, host, shardnode.ListBlobArgs{
|
||||
Header: header,
|
||||
Prefix: args.Prefix,
|
||||
Marker: args.Marker,
|
||||
Count: args.Count,
|
||||
})
|
||||
if err != nil {
|
||||
interrupt := h.punishAndUpdate(ctx, &punishArgs{
|
||||
ShardOpHeader: header,
|
||||
clusterID: args.ClusterID,
|
||||
host: host,
|
||||
err: err,
|
||||
})
|
||||
return nil, interrupt, err
|
||||
}
|
||||
|
||||
return &ret, true, nil
|
||||
}
|
||||
|
||||
func (h *Handler) getShardOpHeader(ctx context.Context, args *acapi.GetShardCommonArgs) (shardnode.ShardOpHeader, error) {
|
||||
shardMgr, err := h.clusterController.GetShardController(args.ClusterID)
|
||||
if err != nil {
|
||||
return shardnode.ShardOpHeader{}, err
|
||||
}
|
||||
|
||||
shardKeys := args.ShardKeys
|
||||
if shardKeys == nil {
|
||||
shardKeys = [][]byte{args.BlobName}
|
||||
}
|
||||
shardInfo, err := shardMgr.GetShard(ctx, shardKeys)
|
||||
if err != nil {
|
||||
return shardnode.ShardOpHeader{}, err
|
||||
}
|
||||
|
||||
var info controller.ShardOpInfo
|
||||
switch args.Mode {
|
||||
case acapi.GetShardModeLeader:
|
||||
info = shardInfo.GetShardLeader()
|
||||
case acapi.GetShardModeRandom:
|
||||
info = shardInfo.GetShardRandom()
|
||||
default:
|
||||
return shardnode.ShardOpHeader{}, errcode.ErrIllegalArguments
|
||||
}
|
||||
|
||||
spaceID := shardMgr.GetSpaceID()
|
||||
return shardnode.ShardOpHeader{
|
||||
SpaceID: spaceID,
|
||||
DiskID: info.DiskID,
|
||||
Suid: info.Suid,
|
||||
RouteVersion: info.RouteVersion,
|
||||
ShardKeys: shardKeys,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Handler) getShardHeaderByID(ctx context.Context, clusterID proto.ClusterID, shardID proto.ShardID) (shardnode.ShardOpHeader, error) {
|
||||
shardMgr, err := h.clusterController.GetShardController(clusterID)
|
||||
if err != nil {
|
||||
return shardnode.ShardOpHeader{}, err
|
||||
}
|
||||
|
||||
shard, err := shardMgr.GetShardByID(ctx, shardID)
|
||||
if err != nil {
|
||||
return shardnode.ShardOpHeader{}, err
|
||||
}
|
||||
|
||||
info := shard.GetShardRandom()
|
||||
|
||||
spaceID := shardMgr.GetSpaceID()
|
||||
return shardnode.ShardOpHeader{
|
||||
SpaceID: spaceID,
|
||||
DiskID: info.DiskID,
|
||||
Suid: info.Suid,
|
||||
RouteVersion: info.RouteVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Handler) getOpHeader(shardMgr controller.IShardController, shard controller.Shard) shardnode.ShardOpHeader {
|
||||
info := shard.GetShardRandom()
|
||||
|
||||
spaceID := shardMgr.GetSpaceID()
|
||||
return shardnode.ShardOpHeader{
|
||||
SpaceID: spaceID,
|
||||
DiskID: info.DiskID,
|
||||
Suid: info.Suid,
|
||||
RouteVersion: info.RouteVersion,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) getShardHost(ctx context.Context, clusterID proto.ClusterID, diskID proto.DiskID) (string, error) {
|
||||
s, err := h.clusterController.GetServiceController(clusterID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
hostInfo, err := s.GetShardnodeHost(ctx, diskID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return hostInfo.Host, nil
|
||||
}
|
||||
|
||||
type punishArgs struct {
|
||||
shardnode.ShardOpHeader
|
||||
clusterID proto.ClusterID
|
||||
host string
|
||||
err error
|
||||
}
|
||||
|
||||
func (h *Handler) punishAndUpdate(ctx context.Context, args *punishArgs) bool {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
code := rpc.DetectStatusCode(args.err)
|
||||
|
||||
switch code {
|
||||
case errcode.CodeDiskBroken: // punish
|
||||
h.punishShardnodeDisk(ctx, args.clusterID, args.DiskID, args.host, "Broken")
|
||||
return true
|
||||
|
||||
case errcode.CodeShardNodeDiskNotFound: // update and punish
|
||||
if err1 := h.updateShardRoute(ctx, args.clusterID); err1 != nil {
|
||||
span.Warnf("need update shard node, cluster:%d, err:%+v", args.clusterID, err1)
|
||||
}
|
||||
h.punishShardnodeDisk(ctx, args.clusterID, args.DiskID, args.host, "NotFound")
|
||||
return false
|
||||
|
||||
case errcode.CodeShardDoesNotExist, errcode.CodeShardRouteVersionNeedUpdate: // update
|
||||
if err1 := h.updateShardRoute(ctx, args.clusterID); err1 != nil {
|
||||
span.Warnf("need update shard node, cluster:%d, err:%+v", args.clusterID, err1)
|
||||
}
|
||||
return false
|
||||
|
||||
case errcode.CodeShardNodeNotLeader:
|
||||
if err1 := h.updateShard(ctx, args); err1 != nil {
|
||||
span.Warnf("need update shard node, cluster:%d, err:%+v", args.clusterID, err1)
|
||||
}
|
||||
return false
|
||||
|
||||
default:
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *Handler) punishShardnodeDisk(ctx context.Context, clusterID proto.ClusterID, diskID proto.DiskID, host, reason string) {
|
||||
reportUnhealth(clusterID, "punish", "shardnode", host, reason)
|
||||
if serviceController, err := h.clusterController.GetServiceController(clusterID); err == nil {
|
||||
serviceController.PunishShardnode(ctx, diskID, h.DiskPunishIntervalS)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) updateShardRoute(ctx context.Context, clusterID proto.ClusterID) error {
|
||||
shardMgr, err := h.clusterController.GetShardController(clusterID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return shardMgr.UpdateRoute(ctx)
|
||||
}
|
||||
|
||||
func (h *Handler) updateShard(ctx context.Context, args *punishArgs) error {
|
||||
shardMgr, err := h.clusterController.GetShardController(args.clusterID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ret, err := h.shardnodeClient.GetShardStats(ctx, args.host, shardnode.GetShardArgs{
|
||||
DiskID: args.DiskID,
|
||||
Suid: args.Suid,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return shardMgr.UpdateShard(ctx, ret)
|
||||
}
|
||||
|
||||
func (h *Handler) fixCreateBlobArgs(ctx context.Context, args *acapi.CreateBlobArgs) error {
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
if int64(args.Size) > h.maxObjectSize {
|
||||
span.Info("exceed max object size", h.maxObjectSize)
|
||||
return errcode.ErrAccessExceedSize
|
||||
}
|
||||
|
||||
if args.SliceSize == 0 {
|
||||
args.SliceSize = atomic.LoadUint32(&h.MaxBlobSize)
|
||||
span.Debugf("fill slice size:%d", args.SliceSize)
|
||||
}
|
||||
|
||||
if args.CodeMode == 0 {
|
||||
args.CodeMode = h.allCodeModes.SelectCodeMode(int64(args.Size))
|
||||
span.Debugf("select codemode:%d", args.CodeMode)
|
||||
}
|
||||
|
||||
if !args.CodeMode.IsValid() {
|
||||
span.Infof("invalid codemode:%d", args.CodeMode)
|
||||
return errcode.ErrIllegalArguments
|
||||
}
|
||||
|
||||
if args.ClusterID == 0 {
|
||||
cluster, err := h.clusterController.ChooseOne()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
args.ClusterID = cluster.ClusterID
|
||||
span.Debugf("choose cluster[%v]", cluster)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
425
blobstore/access/stream/stream_blob_test.go
Normal file
425
blobstore/access/stream/stream_blob_test.go
Normal file
@ -0,0 +1,425 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cubefs/cubefs/blobstore/access/controller"
|
||||
acapi "github.com/cubefs/cubefs/blobstore/api/access"
|
||||
"github.com/cubefs/cubefs/blobstore/api/clustermgr"
|
||||
"github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
"github.com/cubefs/cubefs/blobstore/common/codemode"
|
||||
errcode "github.com/cubefs/cubefs/blobstore/common/errors"
|
||||
"github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
"github.com/cubefs/cubefs/blobstore/common/sharding"
|
||||
"github.com/cubefs/cubefs/blobstore/testing/mocks"
|
||||
)
|
||||
|
||||
func newStreamHandlerSuccess(t *testing.T) *Handler {
|
||||
ctr := gomock.NewController(t)
|
||||
gAny := gomock.Any()
|
||||
|
||||
info := controller.ShardOpInfo{
|
||||
DiskID: 101,
|
||||
Suid: proto.EncodeSuid(1, 0, 1),
|
||||
RouteVersion: 1,
|
||||
}
|
||||
|
||||
shardInfo := NewMockShard(ctr)
|
||||
shardInfo.EXPECT().GetShardRandom().Return(info).AnyTimes()
|
||||
shardInfo.EXPECT().GetShardLeader().Return(info).AnyTimes()
|
||||
|
||||
shardMgr := NewMockShardController(ctr)
|
||||
shardMgr.EXPECT().GetShard(gAny, gAny).Return(shardInfo, nil).AnyTimes()
|
||||
shardMgr.EXPECT().GetSpaceID().Return(proto.SpaceID(1)).AnyTimes()
|
||||
shardMgr.EXPECT().UpdateRoute(gAny).Return(nil).AnyTimes()
|
||||
|
||||
svrCtrl := NewMockServiceController(ctr)
|
||||
svrCtrl.EXPECT().GetShardnodeHost(gAny, gAny).Return(&controller.HostIDC{Host: "host"}, nil).AnyTimes()
|
||||
|
||||
clu := NewMockClusterController(ctr)
|
||||
clu.EXPECT().GetShardController(gAny).Return(shardMgr, nil).AnyTimes()
|
||||
clu.EXPECT().GetServiceController(gAny).Return(svrCtrl, nil).Times(2)
|
||||
|
||||
shardCli := mocks.NewMockShardnodeAccess(ctr)
|
||||
proxyClient := mocks.NewMockProxyClient(ctr)
|
||||
|
||||
allCodeModes := CodeModePairs{
|
||||
codemode.EC3P3: CodeModePair{
|
||||
Policy: codemode.Policy{
|
||||
ModeName: codemode.EC3P3.Name(),
|
||||
MaxSize: math.MaxInt64,
|
||||
Enable: true,
|
||||
},
|
||||
Tactic: codemode.EC3P3.Tactic(),
|
||||
},
|
||||
}
|
||||
handler := &Handler{
|
||||
clusterController: clu,
|
||||
shardnodeClient: shardCli,
|
||||
proxyClient: proxyClient,
|
||||
|
||||
maxObjectSize: 100,
|
||||
allCodeModes: allCodeModes,
|
||||
}
|
||||
|
||||
return handler
|
||||
}
|
||||
|
||||
func TestStreamGetBlob(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctr := gomock.NewController(t)
|
||||
gAny := gomock.Any()
|
||||
|
||||
info := controller.ShardOpInfo{}
|
||||
|
||||
shardInfo := NewMockShard(ctr)
|
||||
shardInfo.EXPECT().GetShardRandom().Return(info).Times(2)
|
||||
|
||||
shardMgr := NewMockShardController(ctr)
|
||||
shardMgr.EXPECT().GetShard(gAny, gAny).Return(shardInfo, nil).Times(2)
|
||||
shardMgr.EXPECT().GetSpaceID().Return(proto.SpaceID(1)).Times(2)
|
||||
shardMgr.EXPECT().UpdateRoute(gAny).Return(nil)
|
||||
|
||||
svrCtrl := NewMockServiceController(ctr)
|
||||
svrCtrl.EXPECT().GetShardnodeHost(gAny, gAny).Return(&controller.HostIDC{Host: "host"}, nil).Times(2)
|
||||
|
||||
clu := NewMockClusterController(ctr)
|
||||
clu.EXPECT().GetShardController(gAny).Return(shardMgr, nil).Times(3)
|
||||
clu.EXPECT().GetServiceController(gAny).Return(svrCtrl, nil).Times(2)
|
||||
|
||||
blobName := []byte("blob1")
|
||||
blob := &proto.Blob{
|
||||
Name: blobName,
|
||||
Location: proto.Location{
|
||||
ClusterID: 1,
|
||||
CodeMode: codemode.EC3P3,
|
||||
Size_: 1,
|
||||
SliceSize: 1,
|
||||
Crc: 1,
|
||||
Slices: nil,
|
||||
},
|
||||
}
|
||||
ret := shardnode.GetBlobRet{
|
||||
Blob: *blob,
|
||||
}
|
||||
shardCli := mocks.NewMockShardnodeAccess(ctr)
|
||||
shardCli.EXPECT().GetBlob(gAny, gAny, gAny).Return(ret, errcode.ErrShardRouteVersionNeedUpdate)
|
||||
shardCli.EXPECT().GetBlob(gAny, gAny, gAny).Return(ret, nil)
|
||||
|
||||
handler := &Handler{
|
||||
clusterController: clu,
|
||||
shardnodeClient: shardCli,
|
||||
}
|
||||
args := acapi.GetBlobArgs{
|
||||
BlobName: blobName,
|
||||
Mode: acapi.GetShardModeRandom,
|
||||
}
|
||||
|
||||
loc, err := handler.GetBlob(ctx, &args)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ret.Blob.Location, *loc)
|
||||
}
|
||||
|
||||
func TestStreamBlobCreate(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
gAny := gomock.Any()
|
||||
h := newStreamHandlerSuccess(t)
|
||||
|
||||
args := acapi.CreateBlobArgs{
|
||||
BlobName: []byte("blob-create"),
|
||||
CodeMode: 0,
|
||||
ClusterID: 0,
|
||||
Size: 10,
|
||||
SliceSize: 4,
|
||||
ShardKeys: nil,
|
||||
}
|
||||
|
||||
ret := shardnode.CreateBlobRet{
|
||||
Blob: proto.Blob{
|
||||
Name: []byte("blob-create"),
|
||||
Location: proto.Location{
|
||||
ClusterID: 1,
|
||||
CodeMode: codemode.EC3P3,
|
||||
Size_: 10,
|
||||
SliceSize: 4,
|
||||
Crc: 1,
|
||||
Slices: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().CreateBlob(gAny, gAny, gAny).Return(ret, errcode.ErrShardRouteVersionNeedUpdate)
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().CreateBlob(gAny, gAny, gAny).Return(ret, nil)
|
||||
h.clusterController.(*MockClusterController).EXPECT().ChooseOne().Return(&clustermgr.ClusterInfo{
|
||||
ClusterID: 1,
|
||||
}, nil)
|
||||
|
||||
loc, err := h.CreateBlob(ctx, &args)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ret.Blob.Location, *loc)
|
||||
}
|
||||
|
||||
func TestStreamBlobDelete(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
gAny := gomock.Any()
|
||||
h := newStreamHandlerSuccess(t)
|
||||
|
||||
args := acapi.DelBlobArgs{
|
||||
BlobName: []byte("blob-del"),
|
||||
ClusterID: 1,
|
||||
ShardKeys: nil,
|
||||
}
|
||||
|
||||
blob := shardnode.GetBlobRet{
|
||||
Blob: proto.Blob{
|
||||
Name: []byte("blob-del"),
|
||||
Location: proto.Location{
|
||||
ClusterID: 1,
|
||||
CodeMode: codemode.EC3P3,
|
||||
},
|
||||
},
|
||||
}
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().GetBlob(gAny, gAny, gAny).Return(blob, errcode.ErrShardRouteVersionNeedUpdate)
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().GetBlob(gAny, gAny, gAny).Return(blob, nil).Times(2)
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().DeleteBlob(gAny, gAny, gAny).Return(errcode.ErrShardRouteVersionNeedUpdate)
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().DeleteBlob(gAny, gAny, gAny).Return(nil)
|
||||
h.proxyClient.(*mocks.MockProxyClient).EXPECT().SendDeleteMsg(gAny, gAny, gAny).Return(nil)
|
||||
|
||||
svrCtrl := NewMockServiceController(gomock.NewController(t))
|
||||
svrCtrl.EXPECT().GetServiceHost(gAny, gAny).Return("host", nil)
|
||||
svrCtrl.EXPECT().GetShardnodeHost(gAny, gAny).Return(&controller.HostIDC{Host: "host"}, nil)
|
||||
h.clusterController.(*MockClusterController).EXPECT().GetServiceController(gAny).Return(svrCtrl, nil).Times(2)
|
||||
|
||||
err := h.DeleteBlob(ctx, &args)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestStreamBlobSeal(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
gAny := gomock.Any()
|
||||
h := newStreamHandlerSuccess(t)
|
||||
|
||||
args := acapi.SealBlobArgs{
|
||||
BlobName: []byte("blob-seal"),
|
||||
ShardKeys: nil,
|
||||
ClusterID: 1,
|
||||
Slices: make([]proto.Slice, 1),
|
||||
}
|
||||
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().SealBlob(gAny, gAny, gAny).Return(errcode.ErrShardRouteVersionNeedUpdate)
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().SealBlob(gAny, gAny, gAny).Return(nil)
|
||||
|
||||
err := h.SealBlob(ctx, &args)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestStreamBlobList(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
gAny := gomock.Any()
|
||||
errMock := errors.New("fake error")
|
||||
ctr := gomock.NewController(t)
|
||||
|
||||
info := controller.ShardOpInfo{
|
||||
DiskID: 101,
|
||||
Suid: proto.EncodeSuid(1, 0, 1),
|
||||
RouteVersion: 1,
|
||||
}
|
||||
|
||||
shardInfo := NewMockShard(ctr)
|
||||
shardInfo.EXPECT().GetShardRandom().Return(info).Times(3)
|
||||
|
||||
shardMgr := NewMockShardController(ctr)
|
||||
shardMgr.EXPECT().GetShardByID(gAny, gAny).Return(shardInfo, nil).Times(3)
|
||||
shardMgr.EXPECT().GetSpaceID().Return(proto.SpaceID(1)).Times(3)
|
||||
shardMgr.EXPECT().UpdateRoute(gAny).Return(nil).Times(3)
|
||||
|
||||
svrCtrl := NewMockServiceController(ctr)
|
||||
svrCtrl.EXPECT().GetShardnodeHost(gAny, gAny).Return(&controller.HostIDC{Host: "host"}, nil).Times(3)
|
||||
|
||||
clu := NewMockClusterController(ctr)
|
||||
clu.EXPECT().GetShardController(gAny).Return(shardMgr, nil).Times(3 * 2)
|
||||
clu.EXPECT().GetServiceController(gAny).Return(svrCtrl, nil).Times(3)
|
||||
|
||||
h := &Handler{
|
||||
clusterController: clu,
|
||||
shardnodeClient: mocks.NewMockShardnodeAccess(ctr),
|
||||
}
|
||||
|
||||
args := acapi.ListBlobArgs{
|
||||
ClusterID: 1,
|
||||
ShardID: 1,
|
||||
Prefix: []byte("test-"),
|
||||
Marker: []byte("test-blob-1"),
|
||||
Count: 4,
|
||||
}
|
||||
// list one shard
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().ListBlob(gAny, gAny, gAny).Return(shardnode.ListBlobRet{}, errcode.ErrShardRouteVersionNeedUpdate).Times(3)
|
||||
ret, err := h.ListBlob(ctx, &args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, errcode.ErrShardRouteVersionNeedUpdate, err)
|
||||
require.Nil(t, ret)
|
||||
|
||||
// list one shard, 3 blob
|
||||
shardInfo.EXPECT().GetShardRandom().Return(info)
|
||||
shardMgr.EXPECT().GetShardByID(gAny, gAny).Return(shardInfo, nil)
|
||||
shardMgr.EXPECT().GetSpaceID().Return(proto.SpaceID(1))
|
||||
svrCtrl.EXPECT().GetShardnodeHost(gAny, gAny).Return(&controller.HostIDC{Host: "host"}, nil)
|
||||
clu.EXPECT().GetShardController(gAny).Return(shardMgr, nil)
|
||||
clu.EXPECT().GetServiceController(gAny).Return(svrCtrl, nil)
|
||||
listRet := shardnode.ListBlobRet{
|
||||
Blobs: []proto.Blob{
|
||||
{Name: []byte("test-blob-1")},
|
||||
{Name: []byte("test-blob-2")},
|
||||
{Name: []byte("test-blob-3")},
|
||||
},
|
||||
NextMarker: nil,
|
||||
}
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().ListBlob(gAny, gAny, gAny).Return(listRet, nil)
|
||||
|
||||
ret, err = h.ListBlob(ctx, &args)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []byte(nil), ret.NextMarker)
|
||||
require.Equal(t, 3, len(ret.Blobs))
|
||||
|
||||
// list all
|
||||
shards := make([]controller.Shard, 3)
|
||||
ranges := sharding.InitShardingRange(sharding.RangeType_RangeTypeHash, 1, 3)
|
||||
for i := range shards {
|
||||
shards[i] = NewMockShard(ctr)
|
||||
shards[i].(*MockShard).EXPECT().GetShardID().Return(proto.ShardID(i + 1)).AnyTimes()
|
||||
shards[i].(*MockShard).EXPECT().GetRange().Return(*ranges[i]).AnyTimes()
|
||||
shards[i].(*MockShard).EXPECT().GetShardRandom().Return(info).AnyTimes()
|
||||
}
|
||||
|
||||
shardMgr.EXPECT().GetFisrtShard(gAny).Return(shards[0], nil).Times(1)
|
||||
shardMgr.EXPECT().GetNextShard(gAny, gAny).Return(shards[1], nil)
|
||||
shardMgr.EXPECT().GetNextShard(gAny, gAny).Return(shards[2], nil)
|
||||
shardMgr.EXPECT().GetSpaceID().Return(proto.SpaceID(1)).Times(2)
|
||||
|
||||
svrCtrl.EXPECT().GetShardnodeHost(gAny, gAny).Return(&controller.HostIDC{Host: "host"}, nil).Times(2)
|
||||
h.clusterController.(*MockClusterController).EXPECT().GetShardController(gAny).Return(shardMgr, nil).Times(1)
|
||||
h.clusterController.(*MockClusterController).EXPECT().GetServiceController(gAny).Return(svrCtrl, nil).Times(2)
|
||||
listRet = shardnode.ListBlobRet{
|
||||
Blobs: []proto.Blob{
|
||||
{Name: []byte("test-blob-1")},
|
||||
{Name: []byte("test-blob-2")},
|
||||
},
|
||||
NextMarker: nil,
|
||||
}
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().ListBlob(gAny, gAny, gAny).Return(listRet, nil).Times(2)
|
||||
|
||||
args.ShardID = 0
|
||||
args.Marker = nil
|
||||
args.Count = 4
|
||||
ret, err = h.ListBlob(ctx, &args)
|
||||
expectMarker := shardnode.ListBlobEncodeMarker{
|
||||
Range: *ranges[2],
|
||||
Marker: args.Marker,
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 4, len(ret.Blobs))
|
||||
|
||||
actual := shardnode.ListBlobEncodeMarker{}
|
||||
err = actual.Unmarshal(ret.NextMarker)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectMarker, actual) // string(ret.NextMarker))
|
||||
|
||||
// list all, from next shard 3
|
||||
args.ShardID = 0
|
||||
args.Count = 2
|
||||
args.Marker = ret.NextMarker
|
||||
|
||||
shardMgr.EXPECT().GetSpaceID().Return(proto.SpaceID(1))
|
||||
shardMgr.EXPECT().GetShardByRange(gAny, expectMarker.Range).Return(shards[2], nil)
|
||||
shardMgr.EXPECT().GetNextShard(gAny, gAny).Return(nil, errMock)
|
||||
svrCtrl.EXPECT().GetShardnodeHost(gAny, gAny).Return(&controller.HostIDC{Host: "host"}, nil)
|
||||
h.clusterController.(*MockClusterController).EXPECT().GetShardController(gAny).Return(shardMgr, nil).Times(1)
|
||||
h.clusterController.(*MockClusterController).EXPECT().GetServiceController(gAny).Return(svrCtrl, nil)
|
||||
listRet.NextMarker = nil
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().ListBlob(gAny, gAny, gAny).Return(listRet, nil)
|
||||
|
||||
ret, err = h.ListBlob(ctx, &args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errMock)
|
||||
require.Nil(t, ret)
|
||||
}
|
||||
|
||||
func TestStreamBlobAlloc(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
gAny := gomock.Any()
|
||||
h := newStreamHandlerSuccess(t)
|
||||
|
||||
args := acapi.AllocSliceArgs{
|
||||
BlobName: []byte("blob-seal"),
|
||||
ShardKeys: nil,
|
||||
ClusterID: 1,
|
||||
CodeMode: 1,
|
||||
Size: 1,
|
||||
FailSlice: proto.Slice{},
|
||||
}
|
||||
|
||||
ret := shardnode.AllocSliceRet{
|
||||
Slices: make([]proto.Slice, 1),
|
||||
}
|
||||
ret.Slices[0].Vid = 1
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().AllocSlice(gAny, gAny, gAny).Return(ret, errcode.ErrShardRouteVersionNeedUpdate)
|
||||
h.shardnodeClient.(*mocks.MockShardnodeAccess).EXPECT().AllocSlice(gAny, gAny, gAny).Return(ret, nil)
|
||||
|
||||
loc, err := h.AllocSlice(ctx, &args)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, loc)
|
||||
require.Equal(t, 1, len(loc.Slices))
|
||||
require.Equal(t, proto.Vid(1), loc.Slices[0].Vid)
|
||||
}
|
||||
|
||||
func TestStreamBlobOther(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
gAny := gomock.Any()
|
||||
ctr := gomock.NewController(t)
|
||||
|
||||
svrCtrl := NewMockServiceController(ctr)
|
||||
svrCtrl.EXPECT().PunishShardnode(gAny, gAny, gAny).Times(2)
|
||||
|
||||
shardMgr := NewMockShardController(ctr)
|
||||
shardMgr.EXPECT().UpdateRoute(gAny).Return(nil).Times(2)
|
||||
shardMgr.EXPECT().UpdateShard(gAny, gAny).Return(nil)
|
||||
|
||||
clu := NewMockClusterController(ctr)
|
||||
clu.EXPECT().GetServiceController(gAny).Return(svrCtrl, nil).Times(2)
|
||||
clu.EXPECT().GetShardController(gAny).Return(shardMgr, nil).Times(3)
|
||||
|
||||
h := &Handler{
|
||||
clusterController: clu,
|
||||
}
|
||||
|
||||
interrupt := h.punishAndUpdate(ctx, &punishArgs{
|
||||
ShardOpHeader: shardnode.ShardOpHeader{},
|
||||
clusterID: 0,
|
||||
host: "",
|
||||
err: errcode.ErrDiskBroken,
|
||||
})
|
||||
require.Equal(t, true, interrupt)
|
||||
|
||||
interrupt = h.punishAndUpdate(ctx, &punishArgs{
|
||||
err: errcode.ErrShardNodeDiskNotFound,
|
||||
})
|
||||
require.Equal(t, false, interrupt)
|
||||
|
||||
interrupt = h.punishAndUpdate(ctx, &punishArgs{
|
||||
err: errcode.ErrShardDoesNotExist,
|
||||
})
|
||||
require.Equal(t, false, interrupt)
|
||||
|
||||
shardnodeClient := mocks.NewMockShardnodeAccess(ctr)
|
||||
shardnodeClient.EXPECT().GetShardStats(gAny, gAny, gAny).Return(shardnode.ShardStats{}, nil)
|
||||
h.shardnodeClient = shardnodeClient
|
||||
interrupt = h.punishAndUpdate(ctx, &punishArgs{
|
||||
err: errcode.ErrShardNodeNotLeader,
|
||||
})
|
||||
require.Equal(t, false, interrupt)
|
||||
}
|
||||
@ -15,7 +15,7 @@
|
||||
package stream
|
||||
|
||||
// github.com/cubefs/cubefs/blobstore/access/... module access interfaces
|
||||
//go:generate mockgen -destination=./controller_mock_test.go -package=stream -mock_names ClusterController=MockClusterController,ServiceController=MockServiceController,VolumeGetter=MockVolumeGetter github.com/cubefs/cubefs/blobstore/access/controller ClusterController,ServiceController,VolumeGetter
|
||||
//go:generate mockgen -destination=./controller_mock_test.go -package=stream -mock_names ClusterController=MockClusterController,ServiceController=MockServiceController,VolumeGetter=MockVolumeGetter,IShardController=MockShardController,Shard=MockShard github.com/cubefs/cubefs/blobstore/access/controller ClusterController,ServiceController,VolumeGetter,IShardController,Shard
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
@ -28,6 +28,7 @@ import (
|
||||
"github.com/hashicorp/consul/api"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
|
||||
"github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
errcode "github.com/cubefs/cubefs/blobstore/common/errors"
|
||||
"github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
"github.com/cubefs/cubefs/blobstore/common/resourcepool"
|
||||
@ -214,6 +215,16 @@ type API interface {
|
||||
Delete(ctx context.Context, args *DeleteArgs) (failedLocations []proto.Location, err error)
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
API
|
||||
CreateBlob(ctx context.Context, args *CreateBlobArgs) (CreateBlobRet, error)
|
||||
ListBlob(ctx context.Context, args *ListBlobArgs) (*shardnode.ListBlobRet, error)
|
||||
SealBlob(ctx context.Context, args *SealBlobArgs) error
|
||||
GetBlob(ctx context.Context, args *GetBlobArgs) (io.ReadCloser, error)
|
||||
DeleteBlob(ctx context.Context, args *DelBlobArgs) error
|
||||
PutBlob(ctx context.Context, args *PutBlobArgs) (proto.ClusterID, error)
|
||||
}
|
||||
|
||||
var _ API = (*client)(nil)
|
||||
|
||||
type noopBody struct{}
|
||||
|
||||
@ -354,3 +354,148 @@ func (args *SignArgs) IsValid() bool {
|
||||
type SignResp struct {
|
||||
Location proto.Location `json:"location"`
|
||||
}
|
||||
|
||||
// Shardnode Blob
|
||||
|
||||
type GetShardMode int
|
||||
|
||||
const (
|
||||
GetShardModeRandom = GetShardMode(iota)
|
||||
GetShardModeLeader
|
||||
)
|
||||
|
||||
type CreateBlobArgs struct {
|
||||
BlobName []byte
|
||||
CodeMode codemode.CodeMode
|
||||
ClusterID proto.ClusterID
|
||||
Size uint64
|
||||
SliceSize uint32
|
||||
ShardKeys [][]byte
|
||||
}
|
||||
|
||||
func (args *CreateBlobArgs) IsValid() bool {
|
||||
if args == nil {
|
||||
return false
|
||||
}
|
||||
return args.Size != 0 && (len(args.BlobName) != 0 || len(args.ShardKeys) != 0)
|
||||
}
|
||||
|
||||
type CreateBlobRet struct {
|
||||
Location proto.Location
|
||||
}
|
||||
|
||||
type ListBlobArgs struct {
|
||||
ClusterID proto.ClusterID
|
||||
ShardID proto.ShardID
|
||||
Prefix []byte
|
||||
Marker []byte
|
||||
Count uint64
|
||||
}
|
||||
|
||||
func (args *ListBlobArgs) IsValid() bool {
|
||||
if args == nil {
|
||||
return false
|
||||
}
|
||||
return args.ClusterID != 0
|
||||
}
|
||||
|
||||
type StatBlobArgs struct {
|
||||
BlobName []byte
|
||||
ClusterID proto.ClusterID
|
||||
Mode GetShardMode
|
||||
ShardKeys [][]byte
|
||||
}
|
||||
|
||||
func (args *StatBlobArgs) IsValid() bool {
|
||||
if args == nil {
|
||||
return false
|
||||
}
|
||||
return args.ClusterID != 0 && (len(args.BlobName) != 0 || len(args.ShardKeys) != 0)
|
||||
}
|
||||
|
||||
type SealBlobArgs struct {
|
||||
BlobName []byte
|
||||
ShardKeys [][]byte
|
||||
ClusterID proto.ClusterID
|
||||
Slices []proto.Slice
|
||||
}
|
||||
|
||||
func (args *SealBlobArgs) IsValid() bool {
|
||||
if args == nil {
|
||||
return false
|
||||
}
|
||||
return args.ClusterID != 0 && len(args.Slices) != 0 && (len(args.BlobName) != 0 || len(args.ShardKeys) != 0)
|
||||
}
|
||||
|
||||
type GetBlobArgs struct {
|
||||
ClusterID proto.ClusterID
|
||||
BlobName []byte
|
||||
Mode GetShardMode
|
||||
ShardKeys [][]byte
|
||||
|
||||
Offset uint64
|
||||
ReadSize uint64
|
||||
Writer io.Writer
|
||||
}
|
||||
|
||||
// IsValid is valid get args
|
||||
func (args *GetBlobArgs) IsValid() bool {
|
||||
if args == nil {
|
||||
return false
|
||||
}
|
||||
return args.ClusterID != 0 && (len(args.BlobName) != 0 || len(args.ShardKeys) != 0)
|
||||
}
|
||||
|
||||
type DelBlobArgs struct {
|
||||
BlobName []byte
|
||||
ClusterID proto.ClusterID
|
||||
ShardKeys [][]byte
|
||||
}
|
||||
|
||||
func (args *DelBlobArgs) IsValid() bool {
|
||||
if args == nil {
|
||||
return false
|
||||
}
|
||||
return args.ClusterID != 0 && (len(args.BlobName) != 0 || len(args.ShardKeys) != 0)
|
||||
}
|
||||
|
||||
type AllocSliceArgs struct {
|
||||
ClusterID proto.ClusterID
|
||||
BlobName []byte
|
||||
ShardKeys [][]byte
|
||||
CodeMode codemode.CodeMode
|
||||
Size uint64
|
||||
FailSlice proto.Slice
|
||||
}
|
||||
|
||||
func (args *AllocSliceArgs) IsValid() bool {
|
||||
if args == nil {
|
||||
return false
|
||||
}
|
||||
return args.ClusterID != 0 && args.CodeMode.IsValid() && args.Size != 0 && (len(args.BlobName) != 0 || len(args.ShardKeys) != 0)
|
||||
}
|
||||
|
||||
type PutBlobArgs struct {
|
||||
BlobName []byte
|
||||
CodeMode codemode.CodeMode
|
||||
NeedSeal bool
|
||||
ShardKeys [][]byte
|
||||
Size uint64
|
||||
Hashes HashAlgorithm
|
||||
Body io.Reader
|
||||
}
|
||||
|
||||
func (args *PutBlobArgs) IsValid() bool {
|
||||
if args == nil {
|
||||
return false
|
||||
}
|
||||
return args.CodeMode != 0 && args.Size != 0 && (len(args.BlobName) != 0 || len(args.ShardKeys) != 0)
|
||||
}
|
||||
|
||||
type GetShardCommonArgs struct {
|
||||
ClusterID proto.ClusterID
|
||||
ShardID proto.ShardID
|
||||
BlobName []byte
|
||||
Mode GetShardMode
|
||||
ShardKeys [][]byte
|
||||
}
|
||||
|
||||
@ -64,6 +64,7 @@ type APIAccess interface {
|
||||
GetSpaceByName(ctx context.Context, args *GetSpaceByNameArgs) (ret *Space, err error)
|
||||
GetCatalogChanges(ctx context.Context, args *GetCatalogChangesArgs) (ret *GetCatalogChangesRet, err error)
|
||||
ShardNodeDiskInfo(ctx context.Context, id proto.DiskID) (ret *ShardNodeDiskInfo, err error)
|
||||
ListShardNodeDisk(ctx context.Context, options *ListOptionArgs) (ret ListShardNodeDiskRet, err error)
|
||||
}
|
||||
|
||||
// APIProxy sub of cluster manager api for allocator
|
||||
|
||||
@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
errcode "github.com/cubefs/cubefs/blobstore/common/errors"
|
||||
"github.com/cubefs/cubefs/blobstore/common/rpc2"
|
||||
"github.com/cubefs/cubefs/blobstore/util/defaulter"
|
||||
)
|
||||
@ -34,6 +35,16 @@ func New(cli Config) *Client {
|
||||
return &Client{Client: cli}
|
||||
}
|
||||
|
||||
type AccessAPI interface {
|
||||
CreateBlob(ctx context.Context, host string, args CreateBlobArgs) (CreateBlobRet, error)
|
||||
ListBlob(ctx context.Context, host string, args ListBlobArgs) (ListBlobRet, error)
|
||||
GetBlob(ctx context.Context, host string, args GetBlobArgs) (GetBlobRet, error)
|
||||
DeleteBlob(ctx context.Context, host string, args DeleteBlobArgs) error
|
||||
SealBlob(ctx context.Context, host string, args SealBlobArgs) error
|
||||
GetShardStats(ctx context.Context, host string, args GetShardArgs) (ret ShardStats, err error)
|
||||
AllocSlice(ctx context.Context, host string, args AllocSliceArgs) (ret AllocSliceRet, err error)
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(ctx context.Context, host, path string, args rpc2.Marshaler, ret rpc2.Unmarshaler) (err error) {
|
||||
req, err := rpc2.NewRequest(ctx, host, path, nil, rpc2.Codec2Reader(args))
|
||||
if err != nil {
|
||||
@ -41,3 +52,37 @@ func (c *Client) doRequest(ctx context.Context, host, path string, args rpc2.Mar
|
||||
}
|
||||
return c.DoWith(req, ret)
|
||||
}
|
||||
|
||||
type FakeClient struct{}
|
||||
|
||||
func NewNonsupportShardnode() *FakeClient {
|
||||
return &FakeClient{}
|
||||
}
|
||||
|
||||
func (c *FakeClient) CreateBlob(ctx context.Context, host string, args CreateBlobArgs) (CreateBlobRet, error) {
|
||||
return CreateBlobRet{}, errcode.ErrShardNodeUnsupport
|
||||
}
|
||||
|
||||
func (c *FakeClient) ListBlob(ctx context.Context, host string, args ListBlobArgs) (ListBlobRet, error) {
|
||||
return ListBlobRet{}, errcode.ErrShardNodeUnsupport
|
||||
}
|
||||
|
||||
func (c *FakeClient) GetBlob(ctx context.Context, host string, args GetBlobArgs) (GetBlobRet, error) {
|
||||
return GetBlobRet{}, errcode.ErrShardNodeUnsupport
|
||||
}
|
||||
|
||||
func (c *FakeClient) DeleteBlob(ctx context.Context, host string, args DeleteBlobArgs) error {
|
||||
return errcode.ErrShardNodeUnsupport
|
||||
}
|
||||
|
||||
func (c *FakeClient) SealBlob(ctx context.Context, host string, args SealBlobArgs) error {
|
||||
return errcode.ErrShardNodeUnsupport
|
||||
}
|
||||
|
||||
func (c *FakeClient) GetShardStats(ctx context.Context, host string, args GetShardArgs) (ret ShardStats, err error) {
|
||||
return ShardStats{}, errcode.ErrShardNodeUnsupport
|
||||
}
|
||||
|
||||
func (c *FakeClient) AllocSlice(ctx context.Context, host string, args AllocSliceArgs) (ret AllocSliceRet, err error) {
|
||||
return AllocSliceRet{}, errcode.ErrShardNodeUnsupport
|
||||
}
|
||||
|
||||
@ -1522,6 +1522,61 @@ func (m *ListBlobRet) GetNextMarker() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListBlobEncodeMarker struct {
|
||||
Range sharding.Range `protobuf:"bytes,1,opt,name=range,proto3" json:"range"`
|
||||
Marker []byte `protobuf:"bytes,2,opt,name=marker,proto3" json:"marker,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ListBlobEncodeMarker) Reset() { *m = ListBlobEncodeMarker{} }
|
||||
func (m *ListBlobEncodeMarker) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListBlobEncodeMarker) ProtoMessage() {}
|
||||
func (*ListBlobEncodeMarker) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{27}
|
||||
}
|
||||
func (m *ListBlobEncodeMarker) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *ListBlobEncodeMarker) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_ListBlobEncodeMarker.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *ListBlobEncodeMarker) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ListBlobEncodeMarker.Merge(m, src)
|
||||
}
|
||||
func (m *ListBlobEncodeMarker) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *ListBlobEncodeMarker) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ListBlobEncodeMarker.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ListBlobEncodeMarker proto.InternalMessageInfo
|
||||
|
||||
func (m *ListBlobEncodeMarker) GetRange() sharding.Range {
|
||||
if m != nil {
|
||||
return m.Range
|
||||
}
|
||||
return sharding.Range{}
|
||||
}
|
||||
|
||||
func (m *ListBlobEncodeMarker) GetMarker() []byte {
|
||||
if m != nil {
|
||||
return m.Marker
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DeleteBlobArgs struct {
|
||||
Header ShardOpHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header"`
|
||||
Name []byte `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
@ -1534,7 +1589,7 @@ func (m *DeleteBlobArgs) Reset() { *m = DeleteBlobArgs{} }
|
||||
func (m *DeleteBlobArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteBlobArgs) ProtoMessage() {}
|
||||
func (*DeleteBlobArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{27}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{28}
|
||||
}
|
||||
func (m *DeleteBlobArgs) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -1587,7 +1642,7 @@ func (m *DeleteBlobRet) Reset() { *m = DeleteBlobRet{} }
|
||||
func (m *DeleteBlobRet) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteBlobRet) ProtoMessage() {}
|
||||
func (*DeleteBlobRet) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{28}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{29}
|
||||
}
|
||||
func (m *DeleteBlobRet) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -1629,7 +1684,7 @@ func (m *RetainBlobArgs) Reset() { *m = RetainBlobArgs{} }
|
||||
func (m *RetainBlobArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*RetainBlobArgs) ProtoMessage() {}
|
||||
func (*RetainBlobArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{29}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{30}
|
||||
}
|
||||
func (m *RetainBlobArgs) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -1689,7 +1744,7 @@ func (m *RetainBlobRet) Reset() { *m = RetainBlobRet{} }
|
||||
func (m *RetainBlobRet) String() string { return proto.CompactTextString(m) }
|
||||
func (*RetainBlobRet) ProtoMessage() {}
|
||||
func (*RetainBlobRet) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{30}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{31}
|
||||
}
|
||||
func (m *RetainBlobRet) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -1732,7 +1787,7 @@ func (m *SealBlobArgs) Reset() { *m = SealBlobArgs{} }
|
||||
func (m *SealBlobArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*SealBlobArgs) ProtoMessage() {}
|
||||
func (*SealBlobArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{31}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{32}
|
||||
}
|
||||
func (m *SealBlobArgs) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -1799,7 +1854,7 @@ func (m *SealBlobRet) Reset() { *m = SealBlobRet{} }
|
||||
func (m *SealBlobRet) String() string { return proto.CompactTextString(m) }
|
||||
func (*SealBlobRet) ProtoMessage() {}
|
||||
func (*SealBlobRet) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{32}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{33}
|
||||
}
|
||||
func (m *SealBlobRet) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -1843,7 +1898,7 @@ func (m *AllocSliceArgs) Reset() { *m = AllocSliceArgs{} }
|
||||
func (m *AllocSliceArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*AllocSliceArgs) ProtoMessage() {}
|
||||
func (*AllocSliceArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{33}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{34}
|
||||
}
|
||||
func (m *AllocSliceArgs) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -1918,7 +1973,7 @@ func (m *AllocSliceRet) Reset() { *m = AllocSliceRet{} }
|
||||
func (m *AllocSliceRet) String() string { return proto.CompactTextString(m) }
|
||||
func (*AllocSliceRet) ProtoMessage() {}
|
||||
func (*AllocSliceRet) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{34}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{35}
|
||||
}
|
||||
func (m *AllocSliceRet) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -1974,7 +2029,7 @@ func (m *ShardStats) Reset() { *m = ShardStats{} }
|
||||
func (m *ShardStats) String() string { return proto.CompactTextString(m) }
|
||||
func (*ShardStats) ProtoMessage() {}
|
||||
func (*ShardStats) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{35}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{36}
|
||||
}
|
||||
func (m *ShardStats) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -2084,7 +2139,7 @@ func (m *ListVolumeArgs) Reset() { *m = ListVolumeArgs{} }
|
||||
func (m *ListVolumeArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListVolumeArgs) ProtoMessage() {}
|
||||
func (*ListVolumeArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{36}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{37}
|
||||
}
|
||||
func (m *ListVolumeArgs) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -2131,7 +2186,7 @@ func (m *ListVolumeRet) Reset() { *m = ListVolumeRet{} }
|
||||
func (m *ListVolumeRet) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListVolumeRet) ProtoMessage() {}
|
||||
func (*ListVolumeRet) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{37}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{38}
|
||||
}
|
||||
func (m *ListVolumeRet) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -2179,7 +2234,7 @@ func (m *ListShardArgs) Reset() { *m = ListShardArgs{} }
|
||||
func (m *ListShardArgs) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListShardArgs) ProtoMessage() {}
|
||||
func (*ListShardArgs) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{38}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{39}
|
||||
}
|
||||
func (m *ListShardArgs) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -2233,7 +2288,7 @@ func (m *ListShardRet) Reset() { *m = ListShardRet{} }
|
||||
func (m *ListShardRet) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListShardRet) ProtoMessage() {}
|
||||
func (*ListShardRet) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{39}
|
||||
return fileDescriptor_9d3815ca0e5f30f0, []int{40}
|
||||
}
|
||||
func (m *ListShardRet) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@ -2297,6 +2352,7 @@ func init() {
|
||||
proto.RegisterType((*GetBlobRet)(nil), "cubefs.blobstore.api.shardnode.GetBlobRet")
|
||||
proto.RegisterType((*ListBlobArgs)(nil), "cubefs.blobstore.api.shardnode.ListBlobArgs")
|
||||
proto.RegisterType((*ListBlobRet)(nil), "cubefs.blobstore.api.shardnode.ListBlobRet")
|
||||
proto.RegisterType((*ListBlobEncodeMarker)(nil), "cubefs.blobstore.api.shardnode.ListBlobEncodeMarker")
|
||||
proto.RegisterType((*DeleteBlobArgs)(nil), "cubefs.blobstore.api.shardnode.DeleteBlobArgs")
|
||||
proto.RegisterType((*DeleteBlobRet)(nil), "cubefs.blobstore.api.shardnode.DeleteBlobRet")
|
||||
proto.RegisterType((*RetainBlobArgs)(nil), "cubefs.blobstore.api.shardnode.RetainBlobArgs")
|
||||
@ -2315,96 +2371,98 @@ func init() {
|
||||
func init() { proto.RegisterFile("shardnode.proto", fileDescriptor_9d3815ca0e5f30f0) }
|
||||
|
||||
var fileDescriptor_9d3815ca0e5f30f0 = []byte{
|
||||
// 1424 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x58, 0x4d, 0x6f, 0x1b, 0xc5,
|
||||
0x1b, 0xff, 0xaf, 0xb3, 0x76, 0x92, 0xc7, 0x6b, 0xe7, 0xaf, 0x55, 0x55, 0xac, 0x48, 0x64, 0xa3,
|
||||
0x6d, 0x51, 0x23, 0x5e, 0x6c, 0x29, 0x45, 0x70, 0x28, 0xd0, 0xc6, 0xb1, 0xda, 0xba, 0x49, 0x41,
|
||||
0xac, 0xdb, 0x48, 0x20, 0x90, 0xb5, 0xf1, 0x8c, 0x9d, 0x21, 0xeb, 0x5d, 0xb3, 0x3b, 0xae, 0x9a,
|
||||
0x9e, 0x38, 0x20, 0x71, 0x42, 0x7c, 0x02, 0x0e, 0x7c, 0x0a, 0x24, 0x24, 0x4e, 0x1c, 0xe8, 0x11,
|
||||
0x4e, 0xdc, 0x56, 0xc8, 0x1f, 0x23, 0x27, 0x34, 0xcf, 0xcc, 0xac, 0xdd, 0x97, 0x34, 0x75, 0x12,
|
||||
0x47, 0x54, 0x5c, 0xac, 0x9d, 0xc7, 0xcf, 0xcb, 0xef, 0x79, 0x9d, 0x67, 0x17, 0x96, 0x92, 0x3d,
|
||||
0x3f, 0x26, 0x61, 0x44, 0x68, 0x75, 0x10, 0x47, 0x3c, 0xb2, 0x57, 0x3a, 0xc3, 0x5d, 0xda, 0x4d,
|
||||
0xaa, 0xbb, 0x41, 0xb4, 0x9b, 0xf0, 0x28, 0xa6, 0x55, 0x7f, 0xc0, 0xaa, 0x19, 0xd7, 0xf2, 0x85,
|
||||
0x5e, 0xd4, 0x8b, 0x90, 0xb5, 0x26, 0x9e, 0xa4, 0xd4, 0xf2, 0xdb, 0x52, 0xaa, 0x96, 0x49, 0xd5,
|
||||
0x3a, 0x51, 0xbf, 0x1f, 0x85, 0x35, 0x14, 0x64, 0x61, 0xaf, 0x16, 0xfb, 0x61, 0x4f, 0xd9, 0x58,
|
||||
0x7e, 0xeb, 0x19, 0x6e, 0x7f, 0xc0, 0x6a, 0x9d, 0x60, 0x98, 0x70, 0x1a, 0xf7, 0x7b, 0xb1, 0x94,
|
||||
0x52, 0xcc, 0x6b, 0x47, 0xa9, 0x96, 0x20, 0x04, 0x59, 0x71, 0x5e, 0x39, 0x8a, 0x33, 0xf6, 0xbb,
|
||||
0x1c, 0x7f, 0x24, 0xa3, 0xdb, 0x01, 0xb3, 0xc9, 0x69, 0xdf, 0xbe, 0x08, 0x39, 0x46, 0x2a, 0xc6,
|
||||
0xaa, 0xb1, 0x66, 0xd5, 0x0b, 0xa3, 0xd4, 0xc9, 0x35, 0x1b, 0x5e, 0x8e, 0x11, 0x7b, 0x13, 0x0a,
|
||||
0x5d, 0x46, 0x03, 0x92, 0x54, 0x72, 0xab, 0x73, 0x6b, 0xc5, 0xf5, 0x37, 0xaa, 0x2f, 0x0e, 0x4a,
|
||||
0xf5, 0xa6, 0xe0, 0xae, 0x9b, 0x8f, 0x53, 0xe7, 0x7f, 0x9e, 0x12, 0x75, 0x07, 0x90, 0x47, 0xb2,
|
||||
0xfd, 0x69, 0x66, 0xa5, 0x54, 0xdf, 0x90, 0x56, 0x0e, 0x53, 0xe7, 0xfd, 0x1e, 0xe3, 0x7b, 0xc3,
|
||||
0xdd, 0x6a, 0x27, 0xea, 0xd7, 0x14, 0xee, 0x17, 0x3a, 0x2a, 0x6d, 0x28, 0x80, 0x17, 0x20, 0xff,
|
||||
0xc0, 0x0f, 0x86, 0xb4, 0x92, 0x13, 0xd8, 0x3d, 0x79, 0x70, 0xff, 0x9c, 0x83, 0x52, 0x4b, 0x60,
|
||||
0xfa, 0x64, 0x70, 0x9b, 0xfa, 0x84, 0xc6, 0xb6, 0x0f, 0x0b, 0xc9, 0xc0, 0xef, 0xd0, 0xb6, 0x02,
|
||||
0x60, 0xd6, 0x6f, 0x8e, 0x52, 0x67, 0xbe, 0x25, 0x68, 0x27, 0x43, 0xa1, 0x44, 0xbd, 0x79, 0xd4,
|
||||
0xdb, 0x24, 0xf6, 0x97, 0x30, 0x4f, 0x58, 0xb2, 0x2f, 0x2c, 0xe4, 0xd0, 0xc5, 0xc6, 0x28, 0x75,
|
||||
0x0a, 0x0d, 0x96, 0xec, 0xa3, 0x81, 0xf7, 0xa6, 0x35, 0x20, 0x25, 0xbd, 0x82, 0x50, 0xda, 0x24,
|
||||
0xf6, 0x3d, 0x30, 0x93, 0x21, 0x23, 0x95, 0x39, 0xd4, 0x7d, 0x63, 0x94, 0x3a, 0x66, 0x6b, 0xc8,
|
||||
0xc8, 0x61, 0xea, 0xbc, 0x3b, 0x35, 0xf4, 0x21, 0x23, 0x1e, 0x6a, 0xb3, 0x5d, 0xb0, 0x10, 0xff,
|
||||
0x0e, 0x8d, 0x13, 0x16, 0x85, 0x15, 0x53, 0xc4, 0xc6, 0x7b, 0x82, 0x66, 0x53, 0x28, 0xc5, 0xd1,
|
||||
0x90, 0xd3, 0xf6, 0x03, 0xc5, 0x94, 0xc7, 0x00, 0xde, 0x38, 0x4c, 0x9d, 0x0f, 0xa6, 0x35, 0xed,
|
||||
0x09, 0x45, 0x4a, 0xb1, 0x67, 0xc5, 0x13, 0x27, 0xfb, 0x75, 0x00, 0xac, 0xa3, 0xf6, 0x3e, 0x3d,
|
||||
0x48, 0x2a, 0x85, 0xd5, 0xb9, 0x35, 0xcb, 0x5b, 0x44, 0xca, 0x16, 0x3d, 0x48, 0xdc, 0x1f, 0x0d,
|
||||
0x28, 0x37, 0xc3, 0x84, 0xc6, 0x5c, 0x54, 0xec, 0x46, 0xdc, 0x4b, 0xec, 0x2d, 0x28, 0xec, 0x61,
|
||||
0x7a, 0x31, 0xa5, 0xc5, 0xf5, 0x77, 0x8e, 0xab, 0xce, 0x27, 0x6a, 0x42, 0x57, 0xa9, 0x54, 0x61,
|
||||
0x7f, 0x04, 0x26, 0xe3, 0xb4, 0x8f, 0xb9, 0x2b, 0xae, 0x5f, 0x3e, 0x4e, 0x95, 0x00, 0xa1, 0x34,
|
||||
0xa0, 0x9c, 0xbb, 0x04, 0xa5, 0x31, 0x3c, 0x8f, 0x72, 0x04, 0x7c, 0x7f, 0x40, 0x7c, 0x4e, 0xff,
|
||||
0xb5, 0x80, 0xc7, 0xf0, 0x04, 0xe0, 0x21, 0x94, 0x1b, 0x34, 0xa0, 0xb3, 0xc2, 0x2b, 0x67, 0x4c,
|
||||
0xee, 0xe9, 0x19, 0x23, 0x70, 0x8c, 0xcd, 0x0a, 0x1c, 0x31, 0x14, 0x6f, 0x51, 0x7e, 0xbe, 0x20,
|
||||
0xb6, 0x01, 0x94, 0x4d, 0x8f, 0xf2, 0x2c, 0xb4, 0xc6, 0x09, 0x43, 0xfb, 0x93, 0x01, 0xd6, 0x36,
|
||||
0x4b, 0x66, 0xe6, 0x43, 0x61, 0x10, 0xd3, 0x2e, 0x7b, 0xa8, 0x86, 0x9e, 0x3a, 0x09, 0x7a, 0xdf,
|
||||
0x8f, 0xf7, 0x69, 0x8c, 0x33, 0xc2, 0xf2, 0xd4, 0x49, 0xcc, 0xc8, 0x4e, 0x34, 0x0c, 0xb9, 0x6a,
|
||||
0x6e, 0x79, 0x70, 0x23, 0x28, 0x6a, 0x88, 0xc2, 0xe5, 0x1b, 0x90, 0x17, 0xd0, 0x93, 0x8a, 0x81,
|
||||
0x83, 0x7e, 0x1a, 0x9f, 0xa5, 0xa0, 0xbd, 0x02, 0x10, 0xd2, 0x87, 0xfc, 0xae, 0x84, 0x20, 0xa1,
|
||||
0x4d, 0x50, 0xdc, 0x9f, 0xe7, 0xc0, 0xda, 0x20, 0x04, 0x3d, 0xc3, 0xa0, 0x4c, 0x0c, 0x4c, 0x63,
|
||||
0x86, 0x03, 0x33, 0x27, 0xa7, 0xd5, 0x19, 0x0d, 0xcc, 0x4d, 0xc8, 0xe3, 0x05, 0x8e, 0x31, 0x2e,
|
||||
0xae, 0x5f, 0x79, 0x36, 0x4e, 0x52, 0xb2, 0xaa, 0xef, 0xfb, 0xaa, 0x27, 0xd8, 0x75, 0xa8, 0x50,
|
||||
0xd6, 0xbe, 0x09, 0xf9, 0x61, 0xc8, 0x78, 0x52, 0x31, 0x31, 0xd8, 0x6f, 0x3e, 0x3f, 0xd8, 0xe3,
|
||||
0x35, 0x40, 0x96, 0xc3, 0xfd, 0x90, 0x71, 0xad, 0x07, 0xc5, 0xcf, 0x69, 0x32, 0xbb, 0x25, 0x28,
|
||||
0xea, 0xc4, 0x89, 0xfe, 0xfc, 0x61, 0x0e, 0x96, 0xe4, 0xe4, 0x78, 0xc5, 0x73, 0xf9, 0x8d, 0x01,
|
||||
0x4b, 0x32, 0xb2, 0xe8, 0xcd, 0xbd, 0x83, 0x01, 0x55, 0xd7, 0xeb, 0xce, 0x28, 0x75, 0x9e, 0xfe,
|
||||
0xeb, 0x30, 0x75, 0xae, 0x4f, 0x6d, 0xec, 0x49, 0x15, 0xde, 0xd3, 0x3a, 0xed, 0x06, 0x98, 0x22,
|
||||
0x95, 0xd8, 0x9a, 0x27, 0x29, 0x04, 0x94, 0x76, 0xff, 0xaf, 0x6f, 0x9a, 0x2c, 0x47, 0xbf, 0xe4,
|
||||
0xe0, 0xb5, 0x7b, 0xb1, 0x1f, 0x26, 0x5d, 0x1a, 0x23, 0x71, 0x1b, 0x67, 0xc7, 0xab, 0x9b, 0xab,
|
||||
0xaf, 0xc0, 0x22, 0x34, 0xe1, 0x6d, 0x8d, 0x5c, 0xe6, 0xe9, 0xf6, 0x28, 0x75, 0xa0, 0x41, 0x13,
|
||||
0x7e, 0x6a, 0xf4, 0x40, 0xb4, 0x16, 0xe2, 0x56, 0xe0, 0xe2, 0x73, 0x62, 0x27, 0xc2, 0xfa, 0x9b,
|
||||
0x01, 0xd6, 0x2d, 0xca, 0x5f, 0xed, 0xba, 0x77, 0x3f, 0xc3, 0x0b, 0x56, 0xd7, 0x8a, 0x7d, 0x07,
|
||||
0xf2, 0x38, 0xac, 0xd4, 0xdd, 0x54, 0x7d, 0xf9, 0x22, 0x6c, 0x86, 0xdd, 0x48, 0x4f, 0x24, 0x54,
|
||||
0xe1, 0x7e, 0x9f, 0x83, 0xf2, 0x66, 0x4c, 0x7d, 0x4e, 0xeb, 0x41, 0xb4, 0x7b, 0xf6, 0x77, 0x9f,
|
||||
0x0d, 0x66, 0xe8, 0xf7, 0xf5, 0xba, 0x8f, 0xcf, 0x76, 0x0f, 0x16, 0x3a, 0x11, 0xa1, 0xfd, 0x88,
|
||||
0xe8, 0xf6, 0xdd, 0x1a, 0xa5, 0xce, 0xc2, 0x66, 0x44, 0xe8, 0xdd, 0x88, 0x88, 0xbe, 0xbd, 0xf6,
|
||||
0xf2, 0xc1, 0xd2, 0x9a, 0xaa, 0x5a, 0xdc, 0xcb, 0x94, 0x0b, 0xe3, 0x09, 0x7b, 0x44, 0xd5, 0x3d,
|
||||
0x8a, 0xcf, 0xb8, 0xb5, 0x06, 0xac, 0x43, 0xdb, 0xf8, 0x8f, 0x98, 0xbf, 0x25, 0x6f, 0x11, 0x29,
|
||||
0x2d, 0xf6, 0x88, 0xba, 0x1f, 0x43, 0x69, 0x1c, 0x0e, 0x11, 0xec, 0x0f, 0xc1, 0x14, 0x36, 0x55,
|
||||
0x2c, 0x2e, 0x1d, 0x79, 0x7d, 0xc8, 0xa4, 0x09, 0x29, 0xdd, 0xe9, 0x82, 0xc5, 0x0d, 0x31, 0x75,
|
||||
0xe7, 0x16, 0x5b, 0x77, 0x0b, 0xf7, 0xa2, 0x33, 0x02, 0xaf, 0xd7, 0xa2, 0xd9, 0xc0, 0x3f, 0x9b,
|
||||
0xb5, 0x28, 0x94, 0x6b, 0x91, 0xf6, 0xf8, 0x3a, 0xe4, 0x11, 0x8b, 0x5a, 0x8b, 0xa6, 0x70, 0x59,
|
||||
0xca, 0x1d, 0xbb, 0x15, 0x7d, 0xad, 0x97, 0xee, 0xf3, 0xcb, 0x69, 0xb6, 0x70, 0x2b, 0x27, 0xdd,
|
||||
0xef, 0x0c, 0x28, 0x7b, 0x94, 0xfb, 0x2c, 0x3c, 0xbf, 0xa6, 0xbd, 0x00, 0xf9, 0x80, 0xfa, 0x89,
|
||||
0xec, 0x58, 0xd3, 0x93, 0x07, 0x01, 0x6d, 0x0c, 0x44, 0x40, 0xfb, 0xdd, 0x00, 0xab, 0x45, 0xfd,
|
||||
0x60, 0x66, 0xc0, 0xb0, 0x6d, 0x73, 0x13, 0x0d, 0xad, 0xc1, 0xce, 0x4d, 0x80, 0xad, 0x43, 0x01,
|
||||
0x5b, 0x5a, 0x2f, 0x6c, 0x97, 0x8f, 0x29, 0x83, 0x96, 0x60, 0xd6, 0xb6, 0xa4, 0xa4, 0x58, 0xa2,
|
||||
0xb4, 0x23, 0xc2, 0xb1, 0x5f, 0x73, 0x50, 0xde, 0x08, 0x82, 0xa8, 0x83, 0xbc, 0xff, 0x81, 0x41,
|
||||
0x79, 0x17, 0xac, 0xae, 0xcf, 0x02, 0x4a, 0xda, 0x18, 0x10, 0x1c, 0x95, 0xd3, 0x45, 0xb2, 0x28,
|
||||
0xe5, 0x91, 0xe4, 0xb6, 0xa0, 0x34, 0x0e, 0x9f, 0xe8, 0xd4, 0x71, 0x8e, 0x8c, 0x13, 0xe7, 0xe8,
|
||||
0xaf, 0x3c, 0x00, 0x06, 0xb5, 0xc5, 0x7d, 0x9e, 0x64, 0xb7, 0xaf, 0x71, 0xa6, 0x9b, 0xcc, 0x25,
|
||||
0x28, 0xf9, 0x83, 0x41, 0xc0, 0x28, 0x69, 0xb3, 0x90, 0xd0, 0x87, 0xaa, 0xfa, 0x2c, 0x45, 0x6c,
|
||||
0x0a, 0x9a, 0xed, 0x40, 0x31, 0xc0, 0x44, 0xb6, 0xf7, 0xa2, 0x84, 0x63, 0xb6, 0x16, 0x3d, 0x90,
|
||||
0xa4, 0xdb, 0x51, 0xc2, 0xed, 0x01, 0x94, 0x15, 0x83, 0xde, 0x3f, 0x4c, 0xcc, 0xe8, 0x9d, 0x51,
|
||||
0xea, 0x58, 0x72, 0x61, 0x39, 0xf5, 0x16, 0x62, 0x05, 0x63, 0x3d, 0xc4, 0xee, 0x65, 0x90, 0x30,
|
||||
0x28, 0xf9, 0xec, 0x2b, 0x1a, 0x48, 0x73, 0xa7, 0x0a, 0x8d, 0x72, 0x4d, 0x3c, 0xdb, 0x15, 0x98,
|
||||
0x0f, 0xa8, 0x1f, 0x87, 0x34, 0xae, 0x14, 0x56, 0x8d, 0xb5, 0x05, 0x4f, 0x1f, 0x9f, 0x7d, 0xdf,
|
||||
0x99, 0x9f, 0xc9, 0x97, 0xa8, 0xec, 0x1d, 0x6f, 0xe1, 0x2c, 0xde, 0xf1, 0x16, 0x4f, 0xf7, 0x8e,
|
||||
0xd7, 0x80, 0x85, 0xd8, 0xef, 0x72, 0x51, 0x91, 0x15, 0x40, 0x3c, 0xee, 0x91, 0x78, 0xf0, 0xcb,
|
||||
0xae, 0xe0, 0x54, 0x2a, 0x32, 0x49, 0xf7, 0x00, 0xca, 0xe2, 0x5a, 0xdb, 0x89, 0x82, 0x61, 0x5f,
|
||||
0x4e, 0x9b, 0xc9, 0x61, 0x60, 0xcc, 0x70, 0x18, 0xb8, 0x04, 0x4a, 0x63, 0xd3, 0xa2, 0x53, 0x5b,
|
||||
0x60, 0x3e, 0x60, 0x44, 0xf6, 0x69, 0xa9, 0x7e, 0x5d, 0xb4, 0xd5, 0x0e, 0x23, 0xc9, 0x61, 0xea,
|
||||
0x5c, 0x9d, 0x36, 0x89, 0x3b, 0xa2, 0xab, 0x84, 0x32, 0xf7, 0x5b, 0x43, 0x9a, 0x39, 0xb7, 0xd5,
|
||||
0x3c, 0x5b, 0x1f, 0x72, 0x93, 0xeb, 0xc3, 0x17, 0x72, 0xc3, 0xc9, 0x76, 0xeb, 0x6d, 0x28, 0x60,
|
||||
0x91, 0xe8, 0xa9, 0x74, 0xb2, 0xe5, 0x5a, 0xe9, 0xa8, 0x2f, 0x3f, 0x1e, 0xad, 0x18, 0x7f, 0x8c,
|
||||
0x56, 0x8c, 0xbf, 0x47, 0x2b, 0xc6, 0xe7, 0x56, 0xb5, 0x76, 0x2d, 0xbb, 0x0c, 0x76, 0x0b, 0x88,
|
||||
0xf2, 0xea, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbd, 0xe5, 0x97, 0xae, 0xc8, 0x18, 0x00, 0x00,
|
||||
// 1446 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x58, 0xcd, 0x6f, 0x1b, 0x45,
|
||||
0x14, 0x67, 0xd7, 0x6b, 0x27, 0x79, 0x5e, 0x3b, 0x68, 0x15, 0x15, 0x2b, 0x12, 0xd9, 0x68, 0x5b,
|
||||
0xd4, 0x88, 0x0f, 0x5b, 0x4a, 0x11, 0x1c, 0x0a, 0xb4, 0x71, 0x4c, 0x5b, 0x37, 0x29, 0x88, 0x75,
|
||||
0x1b, 0x09, 0x04, 0xb2, 0x36, 0x9e, 0xb1, 0xb3, 0x64, 0xbd, 0x6b, 0x76, 0xc7, 0x55, 0xd3, 0x13,
|
||||
0x07, 0x24, 0x4e, 0x88, 0xbf, 0x80, 0x03, 0x7f, 0x05, 0x12, 0x12, 0x27, 0x0e, 0xf4, 0x08, 0x27,
|
||||
0x6e, 0x2b, 0xe4, 0x3f, 0x23, 0x27, 0x34, 0x6f, 0x66, 0xd6, 0xee, 0x47, 0x9a, 0x3a, 0x89, 0x23,
|
||||
0x2a, 0x2e, 0xd1, 0xee, 0xcb, 0xfb, 0xf8, 0xbd, 0x8f, 0xf9, 0xcd, 0x5b, 0xc3, 0x62, 0xb2, 0xe7,
|
||||
0xc5, 0x24, 0x8c, 0x08, 0xad, 0x0e, 0xe2, 0x88, 0x45, 0xd6, 0x4a, 0x67, 0xb8, 0x4b, 0xbb, 0x49,
|
||||
0x75, 0x37, 0x88, 0x76, 0x13, 0x16, 0xc5, 0xb4, 0xea, 0x0d, 0xfc, 0x6a, 0xa6, 0xb5, 0xbc, 0xd4,
|
||||
0x8b, 0x7a, 0x11, 0xaa, 0xd6, 0xf8, 0x93, 0xb0, 0x5a, 0x7e, 0x5b, 0x58, 0xd5, 0x32, 0xab, 0x5a,
|
||||
0x27, 0xea, 0xf7, 0xa3, 0xb0, 0x86, 0x86, 0x7e, 0xd8, 0xab, 0xc5, 0x5e, 0xd8, 0x93, 0x31, 0x96,
|
||||
0xdf, 0x7a, 0x4a, 0xdb, 0x1b, 0xf8, 0xb5, 0x4e, 0x30, 0x4c, 0x18, 0x8d, 0xfb, 0xbd, 0x58, 0x58,
|
||||
0x49, 0xe5, 0xb5, 0xa3, 0x5c, 0x0b, 0x10, 0x5c, 0x2c, 0x35, 0x2f, 0x1f, 0xa5, 0x19, 0x7b, 0x5d,
|
||||
0x86, 0x7f, 0x84, 0xa2, 0xd3, 0x01, 0xa3, 0xc9, 0x68, 0xdf, 0xba, 0x00, 0xba, 0x4f, 0x2a, 0xda,
|
||||
0xaa, 0xb6, 0x66, 0xd6, 0x0b, 0xa3, 0xd4, 0xd6, 0x9b, 0x0d, 0x57, 0xf7, 0x89, 0xb5, 0x09, 0x85,
|
||||
0xae, 0x4f, 0x03, 0x92, 0x54, 0xf4, 0xd5, 0xdc, 0x5a, 0x71, 0xfd, 0x8d, 0xea, 0xf3, 0x8b, 0x52,
|
||||
0xbd, 0xc1, 0xb5, 0xeb, 0xc6, 0xa3, 0xd4, 0x7e, 0xc5, 0x95, 0xa6, 0xce, 0x00, 0xf2, 0x28, 0xb6,
|
||||
0x3e, 0xcb, 0xa2, 0x94, 0xea, 0x1b, 0x22, 0xca, 0x61, 0x6a, 0xbf, 0xdf, 0xf3, 0xd9, 0xde, 0x70,
|
||||
0xb7, 0xda, 0x89, 0xfa, 0x35, 0x89, 0xfb, 0xb9, 0x89, 0x8a, 0x18, 0x12, 0xe0, 0x12, 0xe4, 0xef,
|
||||
0x7b, 0xc1, 0x90, 0x56, 0x74, 0x8e, 0xdd, 0x15, 0x2f, 0xce, 0x5f, 0x39, 0x28, 0xb5, 0x38, 0xa6,
|
||||
0x4f, 0x07, 0xb7, 0xa8, 0x47, 0x68, 0x6c, 0x79, 0x30, 0x9f, 0x0c, 0xbc, 0x0e, 0x6d, 0x4b, 0x00,
|
||||
0x46, 0xfd, 0xc6, 0x28, 0xb5, 0xe7, 0x5a, 0x5c, 0x76, 0x32, 0x14, 0xd2, 0xd4, 0x9d, 0x43, 0xbf,
|
||||
0x4d, 0x62, 0x7d, 0x05, 0x73, 0xc4, 0x4f, 0xf6, 0x79, 0x04, 0x1d, 0x53, 0x6c, 0x8c, 0x52, 0xbb,
|
||||
0xd0, 0xf0, 0x93, 0x7d, 0x0c, 0xf0, 0xde, 0xb4, 0x01, 0x84, 0xa5, 0x5b, 0xe0, 0x4e, 0x9b, 0xc4,
|
||||
0xba, 0x0b, 0x46, 0x32, 0xf4, 0x49, 0x25, 0x87, 0xbe, 0xaf, 0x8f, 0x52, 0xdb, 0x68, 0x0d, 0x7d,
|
||||
0x72, 0x98, 0xda, 0xef, 0x4e, 0x0d, 0x7d, 0xe8, 0x13, 0x17, 0xbd, 0x59, 0x0e, 0x98, 0x88, 0x7f,
|
||||
0x87, 0xc6, 0x89, 0x1f, 0x85, 0x15, 0x83, 0xd7, 0xc6, 0x7d, 0x4c, 0x66, 0x51, 0x28, 0xc5, 0xd1,
|
||||
0x90, 0xd1, 0xf6, 0x7d, 0xa9, 0x94, 0xc7, 0x02, 0x5e, 0x3f, 0x4c, 0xed, 0x0f, 0xa6, 0x0d, 0xed,
|
||||
0x72, 0x47, 0xd2, 0xb1, 0x6b, 0xc6, 0x13, 0x6f, 0xd6, 0xeb, 0x00, 0x38, 0x47, 0xed, 0x7d, 0x7a,
|
||||
0x90, 0x54, 0x0a, 0xab, 0xb9, 0x35, 0xd3, 0x5d, 0x40, 0xc9, 0x16, 0x3d, 0x48, 0x9c, 0x9f, 0x34,
|
||||
0x28, 0x37, 0xc3, 0x84, 0xc6, 0x8c, 0x4f, 0xec, 0x46, 0xdc, 0x4b, 0xac, 0x2d, 0x28, 0xec, 0x61,
|
||||
0x7b, 0xb1, 0xa5, 0xc5, 0xf5, 0x77, 0x8e, 0x9b, 0xce, 0xc7, 0x66, 0x42, 0x4d, 0xa9, 0x70, 0x61,
|
||||
0x7d, 0x04, 0x86, 0xcf, 0x68, 0x1f, 0x7b, 0x57, 0x5c, 0xbf, 0x74, 0x9c, 0x2b, 0x0e, 0x42, 0x7a,
|
||||
0x40, 0x3b, 0x67, 0x11, 0x4a, 0x63, 0x78, 0x2e, 0x65, 0x08, 0xf8, 0xde, 0x80, 0x78, 0x8c, 0xfe,
|
||||
0x67, 0x01, 0x8f, 0xe1, 0x71, 0xc0, 0x43, 0x28, 0x37, 0x68, 0x40, 0x67, 0x85, 0x57, 0x70, 0x8c,
|
||||
0xfe, 0x24, 0xc7, 0x70, 0x1c, 0xe3, 0xb0, 0x1c, 0x47, 0x0c, 0xc5, 0x9b, 0x94, 0x9d, 0x2f, 0x88,
|
||||
0x6d, 0x00, 0x19, 0xd3, 0xa5, 0x2c, 0x2b, 0xad, 0x76, 0xc2, 0xd2, 0xfe, 0xac, 0x81, 0xb9, 0xed,
|
||||
0x27, 0x33, 0xcb, 0xa1, 0x30, 0x88, 0x69, 0xd7, 0x7f, 0x20, 0x49, 0x4f, 0xbe, 0x71, 0x79, 0xdf,
|
||||
0x8b, 0xf7, 0x69, 0x8c, 0x1c, 0x61, 0xba, 0xf2, 0x8d, 0x73, 0x64, 0x27, 0x1a, 0x86, 0x4c, 0x1e,
|
||||
0x6e, 0xf1, 0xe2, 0x44, 0x50, 0x54, 0x10, 0x79, 0xca, 0xd7, 0x21, 0xcf, 0xa1, 0x27, 0x15, 0x0d,
|
||||
0x89, 0x7e, 0x9a, 0x9c, 0x85, 0xa1, 0xb5, 0x02, 0x10, 0xd2, 0x07, 0xec, 0x8e, 0x80, 0x20, 0xa0,
|
||||
0x4d, 0x48, 0x9c, 0x5f, 0x72, 0x60, 0x6e, 0x10, 0x82, 0x99, 0x61, 0x51, 0x26, 0x08, 0x53, 0x9b,
|
||||
0x21, 0x61, 0xea, 0x82, 0xad, 0xce, 0x88, 0x30, 0x37, 0x21, 0x8f, 0x17, 0x38, 0xd6, 0xb8, 0xb8,
|
||||
0x7e, 0xf9, 0xe9, 0x3a, 0x09, 0xcb, 0xaa, 0xba, 0xef, 0xab, 0x2e, 0x57, 0x57, 0xa5, 0x42, 0x5b,
|
||||
0xeb, 0x06, 0xe4, 0x87, 0xa1, 0xcf, 0x92, 0x8a, 0x81, 0xc5, 0x7e, 0xf3, 0xd9, 0xc5, 0x1e, 0xaf,
|
||||
0x01, 0x62, 0x1c, 0xee, 0x85, 0x3e, 0x53, 0x7e, 0xd0, 0xfc, 0x9c, 0x98, 0xd9, 0x29, 0x41, 0x51,
|
||||
0x35, 0x8e, 0x9f, 0xcf, 0x1f, 0x73, 0xb0, 0x28, 0x98, 0xe3, 0x25, 0xef, 0xe5, 0xb7, 0x1a, 0x2c,
|
||||
0x8a, 0xca, 0x62, 0x36, 0x77, 0x0f, 0x06, 0x54, 0x5e, 0xaf, 0x3b, 0xa3, 0xd4, 0x7e, 0xf2, 0x5f,
|
||||
0x87, 0xa9, 0x7d, 0x6d, 0xea, 0x60, 0x8f, 0xbb, 0x70, 0x9f, 0xf4, 0x69, 0x35, 0xc0, 0xe0, 0xad,
|
||||
0xc4, 0xa3, 0x79, 0x92, 0x41, 0x40, 0x6b, 0xe7, 0x55, 0x75, 0xd3, 0x64, 0x3d, 0xfa, 0x55, 0x87,
|
||||
0xd7, 0xee, 0xc6, 0x5e, 0x98, 0x74, 0x69, 0x8c, 0xc2, 0x6d, 0xe4, 0x8e, 0x97, 0xb7, 0x57, 0x5f,
|
||||
0x83, 0x49, 0x68, 0xc2, 0xda, 0x0a, 0xb9, 0xe8, 0xd3, 0xad, 0x51, 0x6a, 0x43, 0x83, 0x26, 0xec,
|
||||
0xd4, 0xe8, 0x81, 0x28, 0x2f, 0xc4, 0xa9, 0xc0, 0x85, 0x67, 0xd4, 0x8e, 0x97, 0xf5, 0x77, 0x0d,
|
||||
0xcc, 0x9b, 0x94, 0xbd, 0xdc, 0x73, 0xef, 0x7c, 0x8e, 0x17, 0xac, 0x9a, 0x15, 0xeb, 0x36, 0xe4,
|
||||
0x91, 0xac, 0xe4, 0xdd, 0x54, 0x7d, 0xf1, 0x21, 0x6c, 0x86, 0xdd, 0x48, 0x31, 0x12, 0xba, 0x70,
|
||||
0x7e, 0xd0, 0xa1, 0xbc, 0x19, 0x53, 0x8f, 0xd1, 0x7a, 0x10, 0xed, 0x9e, 0xfd, 0xdd, 0x67, 0x81,
|
||||
0x11, 0x7a, 0x7d, 0xb5, 0xee, 0xe3, 0xb3, 0xd5, 0x83, 0xf9, 0x4e, 0x44, 0x68, 0x3f, 0x22, 0xea,
|
||||
0xf8, 0x6e, 0x8d, 0x52, 0x7b, 0x7e, 0x33, 0x22, 0xf4, 0x4e, 0x44, 0xf8, 0xb9, 0xbd, 0xfa, 0xe2,
|
||||
0xc5, 0x52, 0x9e, 0xaa, 0xca, 0xdc, 0xcd, 0x9c, 0xf3, 0xe0, 0x89, 0xff, 0x90, 0xca, 0x7b, 0x14,
|
||||
0x9f, 0x71, 0x6b, 0x0d, 0xfc, 0x0e, 0x6d, 0xe3, 0x7f, 0x38, 0xff, 0x96, 0xdc, 0x05, 0x94, 0xb4,
|
||||
0xfc, 0x87, 0xd4, 0xf9, 0x04, 0x4a, 0xe3, 0x72, 0xf0, 0x62, 0x7f, 0x08, 0x06, 0x8f, 0x29, 0x6b,
|
||||
0x71, 0xf1, 0xc8, 0xeb, 0x43, 0x34, 0x8d, 0x5b, 0xa9, 0x93, 0xce, 0x55, 0x9c, 0x10, 0x5b, 0x77,
|
||||
0x6e, 0xb5, 0x75, 0xb6, 0x70, 0x2f, 0x3a, 0x23, 0xf0, 0x6a, 0x2d, 0x9a, 0x0d, 0xfc, 0xb3, 0x59,
|
||||
0x8b, 0x42, 0xb1, 0x16, 0xa9, 0x8c, 0xaf, 0x41, 0x1e, 0xb1, 0xc8, 0xb5, 0x68, 0x8a, 0x94, 0x85,
|
||||
0xdd, 0xb1, 0x5b, 0x51, 0x02, 0x4b, 0x2a, 0xde, 0xc7, 0x21, 0x9f, 0x34, 0x21, 0x1f, 0xef, 0x19,
|
||||
0xda, 0x29, 0xf6, 0x8c, 0x71, 0xea, 0xfa, 0x64, 0xea, 0xce, 0x37, 0x6a, 0xd3, 0x3f, 0xbf, 0x41,
|
||||
0xca, 0xb6, 0x7c, 0x59, 0x59, 0xe7, 0x7b, 0x0d, 0xca, 0x2e, 0x65, 0x9e, 0x1f, 0x9e, 0x1f, 0x53,
|
||||
0x2c, 0x41, 0x3e, 0xa0, 0x5e, 0x22, 0x68, 0xc2, 0x70, 0xc5, 0x0b, 0x87, 0x36, 0x06, 0xc2, 0xa1,
|
||||
0xfd, 0xa1, 0x81, 0xd9, 0xa2, 0x5e, 0x30, 0x33, 0x60, 0xc8, 0x15, 0xfa, 0x04, 0x8b, 0x28, 0xb0,
|
||||
0xb9, 0x09, 0xb0, 0x75, 0x28, 0x20, 0x8f, 0xa8, 0x2d, 0xf1, 0xd2, 0x31, 0xb3, 0xd7, 0xe2, 0xca,
|
||||
0x2a, 0x96, 0xb0, 0xe4, 0x9b, 0x9b, 0x4a, 0x84, 0x27, 0xf6, 0x9b, 0x0e, 0xe5, 0x8d, 0x20, 0x88,
|
||||
0x3a, 0xa8, 0xfb, 0x3f, 0x60, 0xe7, 0x3b, 0x60, 0x76, 0x3d, 0x3f, 0xa0, 0xa4, 0x8d, 0x05, 0x41,
|
||||
0x7e, 0x9e, 0xae, 0x92, 0x45, 0x61, 0x8f, 0x22, 0xa7, 0x05, 0xa5, 0x71, 0xf9, 0x38, 0x3d, 0x8c,
|
||||
0x7b, 0xa4, 0x9d, 0xb8, 0x47, 0x7f, 0xe7, 0x01, 0xb0, 0xa8, 0x2d, 0xe6, 0xb1, 0x24, 0xbb, 0xf2,
|
||||
0xb5, 0x33, 0x5d, 0x9f, 0x2e, 0x42, 0xc9, 0x1b, 0x0c, 0x02, 0x9f, 0x92, 0xb6, 0x1f, 0x12, 0xfa,
|
||||
0x40, 0x4e, 0x9f, 0x29, 0x85, 0x4d, 0x2e, 0xb3, 0x6c, 0x28, 0x06, 0xd8, 0xc8, 0xf6, 0x5e, 0x94,
|
||||
0x30, 0xec, 0xd6, 0x82, 0x0b, 0x42, 0x74, 0x2b, 0x4a, 0x98, 0x35, 0x80, 0xb2, 0x54, 0x50, 0x4b,
|
||||
0x8f, 0x81, 0x1d, 0xbd, 0x3d, 0x4a, 0x6d, 0x53, 0x6c, 0x49, 0xa7, 0x5e, 0x7d, 0xcc, 0x60, 0xec,
|
||||
0x87, 0x58, 0xbd, 0x0c, 0x12, 0x16, 0x25, 0x9f, 0xfd, 0x74, 0x07, 0x22, 0xdc, 0xa9, 0x4a, 0x23,
|
||||
0x53, 0xe3, 0xcf, 0x56, 0x05, 0xe6, 0x02, 0xea, 0xc5, 0x21, 0x8d, 0x2b, 0x85, 0x55, 0x6d, 0x6d,
|
||||
0xde, 0x55, 0xaf, 0x4f, 0x7f, 0x64, 0xcd, 0xcd, 0xe4, 0xe7, 0xaf, 0x8c, 0xf0, 0xe7, 0xcf, 0xe2,
|
||||
0xc3, 0x72, 0xe1, 0x74, 0x1f, 0x96, 0x0d, 0x98, 0x8f, 0xbd, 0x2e, 0xe3, 0x13, 0x59, 0x01, 0xc4,
|
||||
0xe3, 0x1c, 0x89, 0x07, 0x7f, 0x4e, 0xe6, 0x9a, 0xd2, 0x45, 0x66, 0xe9, 0x1c, 0x40, 0x99, 0xdf,
|
||||
0x6d, 0x3b, 0x51, 0x30, 0xec, 0x0b, 0xb6, 0x99, 0x24, 0x03, 0x6d, 0x86, 0x64, 0xe0, 0x10, 0x28,
|
||||
0x8d, 0x43, 0xf3, 0x93, 0xda, 0x02, 0xe3, 0xbe, 0x4f, 0xc4, 0x39, 0x2d, 0xd5, 0xaf, 0xf1, 0x63,
|
||||
0xb5, 0xe3, 0x93, 0xe4, 0x30, 0xb5, 0xaf, 0x4c, 0xdb, 0xc4, 0x1d, 0x7e, 0xaa, 0xb8, 0x33, 0xe7,
|
||||
0x3b, 0x4d, 0x84, 0x39, 0xb7, 0xef, 0x81, 0x6c, 0x67, 0xd1, 0x27, 0x77, 0x96, 0x2f, 0xc5, 0x5a,
|
||||
0x95, 0x2d, 0xf4, 0xdb, 0x50, 0xc0, 0x21, 0x51, 0xac, 0x74, 0xb2, 0x8d, 0x5e, 0xfa, 0xa8, 0x2f,
|
||||
0x3f, 0x1a, 0xad, 0x68, 0x7f, 0x8e, 0x56, 0xb4, 0x7f, 0x46, 0x2b, 0xda, 0x17, 0x66, 0xb5, 0x76,
|
||||
0x35, 0xbb, 0x0c, 0x76, 0x0b, 0x88, 0xf2, 0xca, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x99,
|
||||
0xac, 0x3c, 0x3d, 0x19, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *Item) Marshal() (dAtA []byte, err error) {
|
||||
@ -3555,6 +3613,50 @@ func (m *ListBlobRet) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *ListBlobEncodeMarker) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *ListBlobEncodeMarker) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *ListBlobEncodeMarker) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.XXX_unrecognized != nil {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.Marker) > 0 {
|
||||
i -= len(m.Marker)
|
||||
copy(dAtA[i:], m.Marker)
|
||||
i = encodeVarintShardnode(dAtA, i, uint64(len(m.Marker)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
{
|
||||
size, err := m.Range.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintShardnode(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *DeleteBlobArgs) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
@ -4057,20 +4159,20 @@ func (m *ListVolumeRet) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.Vids) > 0 {
|
||||
dAtA25 := make([]byte, len(m.Vids)*10)
|
||||
var j24 int
|
||||
dAtA26 := make([]byte, len(m.Vids)*10)
|
||||
var j25 int
|
||||
for _, num := range m.Vids {
|
||||
for num >= 1<<7 {
|
||||
dAtA25[j24] = uint8(uint64(num)&0x7f | 0x80)
|
||||
dAtA26[j25] = uint8(uint64(num)&0x7f | 0x80)
|
||||
num >>= 7
|
||||
j24++
|
||||
j25++
|
||||
}
|
||||
dAtA25[j24] = uint8(num)
|
||||
j24++
|
||||
dAtA26[j25] = uint8(num)
|
||||
j25++
|
||||
}
|
||||
i -= j24
|
||||
copy(dAtA[i:], dAtA25[:j24])
|
||||
i = encodeVarintShardnode(dAtA, i, uint64(j24))
|
||||
i -= j25
|
||||
copy(dAtA[i:], dAtA26[:j25])
|
||||
i = encodeVarintShardnode(dAtA, i, uint64(j25))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
@ -4666,6 +4768,24 @@ func (m *ListBlobRet) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *ListBlobEncodeMarker) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = m.Range.Size()
|
||||
n += 1 + l + sovShardnode(uint64(l))
|
||||
l = len(m.Marker)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovShardnode(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *DeleteBlobArgs) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@ -7831,6 +7951,124 @@ func (m *ListBlobRet) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *ListBlobEncodeMarker) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowShardnode
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: ListBlobEncodeMarker: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: ListBlobEncodeMarker: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Range", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowShardnode
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthShardnode
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthShardnode
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if err := m.Range.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Marker", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowShardnode
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthShardnode
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthShardnode
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Marker = append(m.Marker[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Marker == nil {
|
||||
m.Marker = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipShardnode(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthShardnode
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *DeleteBlobArgs) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
|
||||
@ -158,6 +158,11 @@ message ListBlobRet {
|
||||
bytes nextMarker = 2;
|
||||
}
|
||||
|
||||
message ListBlobEncodeMarker {
|
||||
cubefs.blobstore.common.sharding.Range range = 1 [(gogoproto.nullable) = false];
|
||||
bytes marker = 2;
|
||||
}
|
||||
|
||||
message DeleteBlobArgs {
|
||||
ShardOpHeader header = 1 [(gogoproto.nullable) = false];
|
||||
bytes name = 2;
|
||||
|
||||
@ -21,6 +21,7 @@ const (
|
||||
CodeAccessServiceDiscovery = 551 // service discovery for access api client
|
||||
CodeAccessLimited = 429 // read write limited for access api client
|
||||
CodeAccessExceedSize = 400 // exceed max size
|
||||
CodeAccessNotFoundShard = 404
|
||||
)
|
||||
|
||||
// errro of access
|
||||
@ -30,4 +31,5 @@ var (
|
||||
ErrAccessServiceDiscovery = Error(CodeAccessServiceDiscovery)
|
||||
ErrAccessLimited = Error(CodeAccessLimited)
|
||||
ErrAccessExceedSize = Error(CodeAccessExceedSize)
|
||||
ErrAccessNotFoundShard = Error(CodeAccessNotFoundShard)
|
||||
)
|
||||
|
||||
@ -24,9 +24,10 @@ const (
|
||||
CodeShardNoLeader = 1007
|
||||
CodeIllegalSlices = 1008
|
||||
CodeBlobAlreadyExists = 1009
|
||||
CodeUnsupport = 1010
|
||||
)
|
||||
|
||||
// 2xx
|
||||
// 10xx
|
||||
var (
|
||||
ErrShardNodeNotLeader = newError(CodeShardNodeNotLeader, "shard node is not leader")
|
||||
ErrShardRangeMismatch = newError(CodeShardRangeMismatch, "shard range mismatch")
|
||||
@ -37,4 +38,5 @@ var (
|
||||
ErrShardNoLeader = newError(CodeShardNoLeader, "shard has no leader")
|
||||
ErrIllegalSlices = newError(CodeIllegalSlices, "illegal slices")
|
||||
ErrBlobAlreadyExists = newError(CodeAlreadyExist, "blob already exists")
|
||||
ErrShardNodeUnsupport = newError(CodeUnsupport, "unsupport shard node")
|
||||
)
|
||||
|
||||
@ -1,74 +0,0 @@
|
||||
package base
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/cubefs/cubefs/blobstore/common/codemode"
|
||||
"github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
)
|
||||
|
||||
type GetShardMode int
|
||||
|
||||
const (
|
||||
GetShardModeLeader = GetShardMode(iota + 1)
|
||||
GetShardModeRandom
|
||||
)
|
||||
|
||||
type CreateBlobArgs struct {
|
||||
BlobName []byte
|
||||
CodeMode codemode.CodeMode
|
||||
}
|
||||
|
||||
type ListBlobArgs struct {
|
||||
Prefix string
|
||||
Marker string
|
||||
Count int
|
||||
}
|
||||
|
||||
type ListBlobResponse struct {
|
||||
Blobs []proto.Blob
|
||||
NextMarker string
|
||||
}
|
||||
|
||||
type StatBlobArgs struct {
|
||||
BlobName []byte
|
||||
ClusterID proto.ClusterID
|
||||
}
|
||||
|
||||
type SealBlobArgs struct {
|
||||
BlobName []byte
|
||||
ClusterID proto.ClusterID
|
||||
BlobSize uint64
|
||||
}
|
||||
|
||||
type GetBlobArgs struct {
|
||||
ClusterID proto.ClusterID
|
||||
BlobName []byte
|
||||
Offset uint64
|
||||
ReadSize uint64
|
||||
Writer io.Writer
|
||||
Mode GetShardMode
|
||||
ShardKeys [][]byte
|
||||
}
|
||||
|
||||
// IsValid is valid get args
|
||||
func (args *GetBlobArgs) IsValid() bool {
|
||||
if args == nil {
|
||||
return false
|
||||
}
|
||||
return args.ClusterID != 0
|
||||
}
|
||||
|
||||
type DelBlobArgs struct {
|
||||
BlobName []byte
|
||||
ClusterID proto.ClusterID
|
||||
}
|
||||
|
||||
type PutBlobArgs struct {
|
||||
BlobName []byte
|
||||
CodeMode codemode.CodeMode
|
||||
NeedSeal bool
|
||||
|
||||
Size uint64
|
||||
Body io.Reader
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/cubefs/cubefs/blobstore/api/access"
|
||||
"github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
"github.com/cubefs/cubefs/blobstore/sdk/base"
|
||||
)
|
||||
|
||||
type EbsClient interface {
|
||||
access.API
|
||||
CreateBlob(ctx context.Context, args *base.CreateBlobArgs) (proto.Blob, error)
|
||||
ListBlob(ctx context.Context, args *base.ListBlobArgs) (base.ListBlobResponse, error)
|
||||
StatBlob(ctx context.Context, args *base.StatBlobArgs) (proto.Blob, error)
|
||||
SealBlob(ctx context.Context, args *base.SealBlobArgs) error
|
||||
GetBlob(ctx context.Context, args *base.GetBlobArgs) (io.ReadCloser, error)
|
||||
DeleteBlob(ctx context.Context, args *base.DelBlobArgs) error
|
||||
PutBlob(ctx context.Context, args *base.PutBlobArgs) (proto.ClusterID, error)
|
||||
}
|
||||
@ -23,13 +23,13 @@ import (
|
||||
|
||||
"github.com/cubefs/cubefs/blobstore/access/stream"
|
||||
acapi "github.com/cubefs/cubefs/blobstore/api/access"
|
||||
"github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
errcode "github.com/cubefs/cubefs/blobstore/common/errors"
|
||||
"github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
"github.com/cubefs/cubefs/blobstore/common/resourcepool"
|
||||
"github.com/cubefs/cubefs/blobstore/common/rpc"
|
||||
"github.com/cubefs/cubefs/blobstore/common/security"
|
||||
"github.com/cubefs/cubefs/blobstore/common/trace"
|
||||
"github.com/cubefs/cubefs/blobstore/sdk/base"
|
||||
"github.com/cubefs/cubefs/blobstore/util/closer"
|
||||
"github.com/cubefs/cubefs/blobstore/util/defaulter"
|
||||
"github.com/cubefs/cubefs/blobstore/util/errors"
|
||||
@ -43,6 +43,7 @@ const (
|
||||
defaultMaxRetry int = 3
|
||||
defaultRetryDelayMs uint32 = 10
|
||||
defaultPartConcurrence int = 4
|
||||
defaultListCount uint64 = 100
|
||||
|
||||
limitNameGet = "get"
|
||||
limitNamePut = "put"
|
||||
@ -95,7 +96,7 @@ type sdkHandler struct {
|
||||
closer closer.Closer
|
||||
}
|
||||
|
||||
func New(conf *Config) (EbsClient, error) {
|
||||
func New(conf *Config) (acapi.Client, error) {
|
||||
fixConfig(conf)
|
||||
// add region magic checksum to the secret keys
|
||||
security.InitWithRegionMagic(conf.StreamConfig.ClusterConfig.RegionMagic)
|
||||
@ -223,32 +224,69 @@ func (s *sdkHandler) Put(ctx context.Context, args *acapi.PutArgs) (lc proto.Loc
|
||||
return s.putParts(ctx, args)
|
||||
}
|
||||
|
||||
func (s *sdkHandler) CreateBlob(ctx context.Context, args *base.CreateBlobArgs) (proto.Blob, error) {
|
||||
return proto.Blob{}, nil
|
||||
}
|
||||
|
||||
func (s *sdkHandler) ListBlob(ctx context.Context, args *base.ListBlobArgs) (base.ListBlobResponse, error) {
|
||||
return base.ListBlobResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *sdkHandler) StatBlob(ctx context.Context, args *base.StatBlobArgs) (proto.Blob, error) {
|
||||
return proto.Blob{}, nil
|
||||
}
|
||||
|
||||
func (s *sdkHandler) SealBlob(ctx context.Context, args *base.SealBlobArgs) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sdkHandler) GetBlob(ctx context.Context, args *base.GetBlobArgs) (io.ReadCloser, error) {
|
||||
func (s *sdkHandler) ListBlob(ctx context.Context, args *acapi.ListBlobArgs) (*shardnode.ListBlobRet, error) {
|
||||
if !args.IsValid() {
|
||||
return nil, errcode.ErrIllegalArguments
|
||||
}
|
||||
|
||||
ctx = acapi.ClientWithReqidContext(ctx)
|
||||
loc, err := s.handler.GetBlob(ctx, &base.GetBlobArgs{
|
||||
ClusterID: args.ClusterID,
|
||||
BlobName: args.BlobName,
|
||||
})
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("accept sdk list blob request args: %v", *args)
|
||||
if args.Count == 0 {
|
||||
args.Count = defaultListCount
|
||||
}
|
||||
|
||||
return s.handler.ListBlob(ctx, args)
|
||||
}
|
||||
|
||||
func (s *sdkHandler) CreateBlob(ctx context.Context, args *acapi.CreateBlobArgs) (acapi.CreateBlobRet, error) {
|
||||
if !args.IsValid() {
|
||||
return acapi.CreateBlobRet{}, errcode.ErrIllegalArguments
|
||||
}
|
||||
|
||||
ctx = acapi.ClientWithReqidContext(ctx)
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("accept sdk create blob request args: %v", *args)
|
||||
|
||||
loc, err := s.handler.CreateBlob(ctx, args)
|
||||
if err != nil {
|
||||
return acapi.CreateBlobRet{}, err
|
||||
}
|
||||
return acapi.CreateBlobRet{Location: *loc}, nil
|
||||
}
|
||||
|
||||
func (s *sdkHandler) DeleteBlob(ctx context.Context, args *acapi.DelBlobArgs) error {
|
||||
if !args.IsValid() {
|
||||
return errcode.ErrIllegalArguments
|
||||
}
|
||||
|
||||
// delete meta at shardnode, then delete data at blobnode
|
||||
ctx = acapi.ClientWithReqidContext(ctx)
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("accept sdk delete blob request args: %v", *args)
|
||||
return s.handler.DeleteBlob(ctx, args)
|
||||
}
|
||||
|
||||
func (s *sdkHandler) SealBlob(ctx context.Context, args *acapi.SealBlobArgs) error {
|
||||
if !args.IsValid() {
|
||||
return errcode.ErrIllegalArguments
|
||||
}
|
||||
|
||||
ctx = acapi.ClientWithReqidContext(ctx)
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("accept sdk seal blob request args: %v", *args)
|
||||
return s.handler.SealBlob(ctx, args)
|
||||
}
|
||||
|
||||
func (s *sdkHandler) GetBlob(ctx context.Context, args *acapi.GetBlobArgs) (io.ReadCloser, error) {
|
||||
if !args.IsValid() {
|
||||
return nil, errcode.ErrIllegalArguments
|
||||
}
|
||||
|
||||
ctx = acapi.ClientWithReqidContext(ctx)
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("accept sdk get blob request args: %v", *args)
|
||||
loc, err := s.handler.GetBlob(ctx, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -259,15 +297,57 @@ func (s *sdkHandler) GetBlob(ctx context.Context, args *base.GetBlobArgs) (io.Re
|
||||
ReadSize: args.ReadSize,
|
||||
Writer: args.Writer,
|
||||
}
|
||||
if arg.Location.Size_ == 0 { // means blob not seal, we will fix size
|
||||
// At the last of the Slices, maybe some of the slices is an empty slice that hasn't been written yet
|
||||
for _, slice := range arg.Location.Slices {
|
||||
arg.Location.Size_ += slice.ValidSize
|
||||
}
|
||||
}
|
||||
|
||||
return s.Get(ctx, arg)
|
||||
}
|
||||
|
||||
func (s *sdkHandler) DeleteBlob(ctx context.Context, args *base.DelBlobArgs) error {
|
||||
return nil
|
||||
}
|
||||
func (s *sdkHandler) PutBlob(ctx context.Context, args *acapi.PutBlobArgs) (cid proto.ClusterID, err error) {
|
||||
if !args.IsValid() {
|
||||
return 0, errcode.ErrIllegalArguments
|
||||
}
|
||||
|
||||
func (s *sdkHandler) PutBlob(ctx context.Context, args *base.PutBlobArgs) (proto.ClusterID, error) {
|
||||
return 0, nil
|
||||
ctx = acapi.ClientWithReqidContext(ctx)
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("accept sdk put blob request args: %v", *args)
|
||||
|
||||
defer func() {
|
||||
// cid != 0, means create ok, but put fail, or seal fail. need delete
|
||||
if err != nil && cid != 0 {
|
||||
delArgs := &acapi.DelBlobArgs{
|
||||
BlobName: args.BlobName,
|
||||
ClusterID: cid,
|
||||
ShardKeys: args.ShardKeys,
|
||||
}
|
||||
if err1 := s.DeleteBlob(ctx, delArgs); err1 != nil {
|
||||
span.Warnf("put fail, clean args=%v, cluster=%d, err=%+v", delArgs, cid, err1)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
loc, err := s.putBlobs(ctx, args)
|
||||
if err != nil {
|
||||
return loc.ClusterID, err
|
||||
}
|
||||
|
||||
if args.NeedSeal {
|
||||
sealArgs := &acapi.SealBlobArgs{
|
||||
BlobName: args.BlobName,
|
||||
ShardKeys: args.ShardKeys,
|
||||
ClusterID: loc.ClusterID,
|
||||
Slices: loc.Slices,
|
||||
}
|
||||
if err = s.SealBlob(ctx, sealArgs); err != nil {
|
||||
span.Warnf("seal fail, seal args=%v", sealArgs)
|
||||
return loc.ClusterID, err
|
||||
}
|
||||
}
|
||||
return loc.ClusterID, nil
|
||||
}
|
||||
|
||||
func (s *sdkHandler) alloc(ctx context.Context, args *acapi.AllocArgs) (acapi.AllocResp, error) {
|
||||
@ -309,19 +389,6 @@ func (s *sdkHandler) deleteBlob(ctx context.Context, args *acapi.DeleteBlobArgs)
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("accept /deleteblob request args:%+v", args)
|
||||
|
||||
valid := false
|
||||
for _, secretKey := range security.TokenSecretKeys() {
|
||||
token := security.DecodeToken(args.Token)
|
||||
if token.IsValid(args.ClusterID, args.Vid, args.BlobID, uint32(args.Size), secretKey[:]) {
|
||||
valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !valid {
|
||||
span.Warnf("invalid token:%s", args.Token)
|
||||
return errcode.ErrIllegalArguments
|
||||
}
|
||||
|
||||
if err := s.handler.Delete(ctx, &proto.Location{
|
||||
ClusterID: args.ClusterID,
|
||||
SliceSize: 1,
|
||||
@ -516,19 +583,6 @@ func (s *sdkHandler) doPutAt(ctx context.Context, args *acapi.PutAtArgs) (hashSu
|
||||
span := trace.SpanFromContextSafe(ctx)
|
||||
span.Debugf("accept sdk putat request args:%+v", args)
|
||||
|
||||
valid := false
|
||||
for _, secretKey := range security.TokenSecretKeys() {
|
||||
token := security.DecodeToken(args.Token)
|
||||
if token.IsValid(args.ClusterID, args.Vid, args.BlobID, uint32(args.Size), secretKey[:]) {
|
||||
valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !valid {
|
||||
span.Warnf("invalid token:%s", args.Token)
|
||||
return nil, errcode.ErrIllegalArguments
|
||||
}
|
||||
|
||||
hashSumMap = args.Hashes.ToHashSumMap()
|
||||
hasherMap := make(acapi.HasherMap, len(hashSumMap))
|
||||
for alg := range hashSumMap {
|
||||
@ -561,11 +615,6 @@ func (s *sdkHandler) doAlloc(ctx context.Context, args *acapi.AllocArgs) (resp a
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if err = security.LocationCrcFill(location); err != nil {
|
||||
span.Error("stream alloc fill location crc", err)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
resp = acapi.AllocResp{
|
||||
Location: *location,
|
||||
Tokens: security.StreamGenTokens(location),
|
||||
@ -595,7 +644,6 @@ func (s *sdkHandler) putPartsBatch(ctx context.Context, parts []blobPart) error
|
||||
BlobID: part.bid,
|
||||
Size: int64(part.size),
|
||||
Hashes: 0,
|
||||
Token: part.token,
|
||||
Body: bytes.NewReader(part.buf),
|
||||
})
|
||||
return err
|
||||
@ -613,7 +661,6 @@ func (s *sdkHandler) putPartsBatch(ctx context.Context, parts []blobPart) error
|
||||
Vid: part.vid,
|
||||
BlobID: part.bid,
|
||||
Size: int64(part.size),
|
||||
Token: part.token,
|
||||
})
|
||||
}()
|
||||
}
|
||||
@ -877,6 +924,192 @@ func (s *sdkHandler) putParts(ctx context.Context, args *acapi.PutArgs) (proto.L
|
||||
return loc, hashSumMap, nil
|
||||
}
|
||||
|
||||
func (s *sdkHandler) putBlobs(ctx context.Context, args *acapi.PutBlobArgs) (proto.Location, error) {
|
||||
// create
|
||||
created, err := s.CreateBlob(ctx, &acapi.CreateBlobArgs{
|
||||
BlobName: args.BlobName,
|
||||
ShardKeys: args.ShardKeys,
|
||||
CodeMode: args.CodeMode,
|
||||
Size: args.Size,
|
||||
})
|
||||
if err != nil {
|
||||
return proto.Location{}, err
|
||||
}
|
||||
|
||||
// buf
|
||||
loc := created.Location
|
||||
failLoc := proto.Location{ClusterID: loc.ClusterID}
|
||||
buf, err := memPool.Alloc(int(loc.SliceSize))
|
||||
if err != nil {
|
||||
return failLoc, err
|
||||
}
|
||||
defer memPool.Put(buf[:loc.SliceSize]) // prevent buf get smaller
|
||||
|
||||
// put every slice
|
||||
needRead := true
|
||||
for blobIdx, retryCnt := 0, 0; blobIdx < len(loc.Slices); {
|
||||
buf1, sliceIdx, remainSize, err := s.putOneSlice(ctx, args, loc, blobIdx, needRead, buf)
|
||||
if err == nil { // reset put next slice
|
||||
blobIdx++
|
||||
retryCnt = 0
|
||||
needRead = true
|
||||
buf = buf[:loc.SliceSize]
|
||||
continue
|
||||
}
|
||||
|
||||
if remainSize == 0 { // means: read error
|
||||
return failLoc, err
|
||||
}
|
||||
if err = s.delFailSlice(ctx, loc, blobIdx, sliceIdx, remainSize); err != nil {
|
||||
return failLoc, err
|
||||
}
|
||||
retryCnt++ // prevent one slice from failing all the time, and cant put ok after alloc
|
||||
if retryCnt > s.conf.MaxRetry {
|
||||
return failLoc, err
|
||||
}
|
||||
|
||||
allocs, err := s.retryAllocSlice(ctx, args, loc, blobIdx, sliceIdx, remainSize)
|
||||
if err != nil {
|
||||
return failLoc, err
|
||||
}
|
||||
loc.Slices, blobIdx = s.updateLocationSlices(loc.Slices, allocs, blobIdx, sliceIdx, remainSize)
|
||||
needRead = false
|
||||
buf = buf1 // prevent repeated io read
|
||||
}
|
||||
|
||||
return loc, nil
|
||||
}
|
||||
|
||||
func (s *sdkHandler) putOneSlice(ctx context.Context, args *acapi.PutBlobArgs, loc proto.Location,
|
||||
blobIdx int, needRead bool, buf []byte,
|
||||
) ([]byte, int, uint64, error) {
|
||||
slice := loc.Slices[blobIdx]
|
||||
var err error
|
||||
|
||||
// todo: dont concurrency, support concurrency next version
|
||||
for cnt, remainSize := 0, slice.ValidSize; uint32(cnt) < slice.Count; {
|
||||
readSize := uint64(loc.SliceSize)
|
||||
if readSize > remainSize {
|
||||
readSize = remainSize // maybe less SliceSize, last one
|
||||
buf = buf[:readSize]
|
||||
}
|
||||
if needRead {
|
||||
if _, err = io.ReadFull(args.Body, buf); err != nil {
|
||||
return []byte{}, 0, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = s.doPutAt(ctx, &acapi.PutAtArgs{
|
||||
ClusterID: loc.ClusterID,
|
||||
Vid: slice.Vid,
|
||||
BlobID: slice.MinSliceID + proto.BlobID(cnt),
|
||||
Size: int64(len(buf)), // maybe less SliceSize
|
||||
Body: bytes.NewReader(buf),
|
||||
})
|
||||
if err != nil {
|
||||
return buf, cnt, remainSize, err // remainSize must not 0
|
||||
}
|
||||
cnt++
|
||||
remainSize -= readSize
|
||||
needRead = true
|
||||
}
|
||||
return []byte{}, 0, 0, nil
|
||||
}
|
||||
|
||||
// e.g. Slices[
|
||||
// {bid:1~4; vid:1} first
|
||||
// {bid:10~14; vid:2} second
|
||||
// {bid:100~104; vid:3} third
|
||||
// ],
|
||||
// will split slice: if first slice all ok, second slice 10,11 ok; 12,13,14 fail
|
||||
// slice{bid:1~4; vid:1}, slice{10,11; vid:2}, slice{15,16,17; vid:4}, slice{200~204; vid:5} ; fail 12,13,14-> 15,16,17
|
||||
func (s *sdkHandler) retryAllocSlice(ctx context.Context, args *acapi.PutBlobArgs, loc proto.Location,
|
||||
blobIdx, sliceIdx int, remainSize uint64,
|
||||
) ([]proto.Slice, error) {
|
||||
var err error
|
||||
slice := loc.Slices[blobIdx] // current
|
||||
fail := proto.Slice{
|
||||
MinSliceID: slice.MinSliceID + proto.BlobID(sliceIdx),
|
||||
Vid: slice.Vid,
|
||||
Count: slice.Count - uint32(sliceIdx), // e.g. slice.Count=3, sliceIdx in [0,3)
|
||||
ValidSize: remainSize,
|
||||
}
|
||||
|
||||
var alloc *shardnode.AllocSliceRet
|
||||
rerr := retry.Timed(s.conf.MaxRetry, s.conf.RetryDelayMs).RuptOn(func() (bool, error) {
|
||||
alloc, err = s.handler.AllocSlice(ctx, &acapi.AllocSliceArgs{
|
||||
ClusterID: loc.ClusterID,
|
||||
BlobName: args.BlobName,
|
||||
ShardKeys: args.ShardKeys,
|
||||
CodeMode: loc.CodeMode,
|
||||
Size: remainSize, // expect fail size
|
||||
FailSlice: fail, // fail part of current slice
|
||||
})
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
for i := range alloc.Slices {
|
||||
if alloc.Slices[i].Vid == loc.Slices[blobIdx].Vid {
|
||||
return false, fmt.Errorf("alloc the same vid %d", alloc.Slices[i].Vid)
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
if rerr != nil {
|
||||
return []proto.Slice{}, rerr
|
||||
}
|
||||
return alloc.Slices, nil
|
||||
}
|
||||
|
||||
func (s *sdkHandler) delFailSlice(ctx context.Context, loc proto.Location, blobIdx, sliceIdx int, remainSize uint64) error {
|
||||
slice := loc.Slices[blobIdx]
|
||||
delLoc := proto.Location{
|
||||
ClusterID: loc.ClusterID,
|
||||
CodeMode: loc.CodeMode,
|
||||
Size_: remainSize,
|
||||
SliceSize: loc.SliceSize,
|
||||
Slices: []proto.Slice{{
|
||||
MinSliceID: slice.MinSliceID + proto.BlobID(sliceIdx),
|
||||
Vid: slice.Vid,
|
||||
Count: slice.Count - uint32(sliceIdx), // e.g. slice.Count=3, sliceIdx in [0,3)
|
||||
ValidSize: remainSize,
|
||||
}},
|
||||
}
|
||||
crc, err := security.LocationCrcCalculate(&delLoc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
delLoc.Crc = crc
|
||||
if _, err = s.Delete(ctx, &acapi.DeleteArgs{Locations: []proto.Location{delLoc}}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sdkHandler) updateLocationSlices(oldAll, fail []proto.Slice, blobIdx, sliceIdx int, remainSize uint64) ([]proto.Slice, int) {
|
||||
slice := oldAll[blobIdx] // current
|
||||
undo := oldAll[blobIdx+1:]
|
||||
succAll := make([]proto.Slice, 0, blobIdx+1)
|
||||
succAll = append(succAll, oldAll[:blobIdx]...) // success slices, include previous success and part of current
|
||||
if sliceIdx > 0 {
|
||||
succAll = append(succAll, proto.Slice{
|
||||
MinSliceID: slice.MinSliceID,
|
||||
Vid: slice.Vid,
|
||||
Count: uint32(sliceIdx), // cant be zero
|
||||
ValidSize: slice.ValidSize - remainSize,
|
||||
})
|
||||
blobIdx++ // insert split slice, so current idx++
|
||||
}
|
||||
|
||||
newSlice := make([]proto.Slice, 0, len(succAll)+len(fail)+len(undo))
|
||||
newSlice = append(newSlice, succAll...) // all success slice, include before+current
|
||||
newSlice = append(newSlice, fail...) // alloc fail slice
|
||||
newSlice = append(newSlice, undo...) // undo slice
|
||||
// modifying the loc.Slices in this function is useless. unless it's a pointer
|
||||
return newSlice, blobIdx
|
||||
}
|
||||
|
||||
func httpError(err error) error {
|
||||
if e, ok := err.(rpc.HTTPError); ok {
|
||||
return e
|
||||
|
||||
@ -12,17 +12,23 @@ import (
|
||||
|
||||
"github.com/cubefs/cubefs/blobstore/access/stream"
|
||||
acapi "github.com/cubefs/cubefs/blobstore/api/access"
|
||||
"github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
"github.com/cubefs/cubefs/blobstore/common/codemode"
|
||||
errcode "github.com/cubefs/cubefs/blobstore/common/errors"
|
||||
"github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
"github.com/cubefs/cubefs/blobstore/common/security"
|
||||
mocks "github.com/cubefs/cubefs/blobstore/testing/mocks"
|
||||
"github.com/cubefs/cubefs/blobstore/testing/mocks"
|
||||
"github.com/cubefs/cubefs/blobstore/util/closer"
|
||||
"github.com/cubefs/cubefs/blobstore/util/log"
|
||||
)
|
||||
|
||||
func newSdkHandler() *sdkHandler {
|
||||
ctr := gomock.NewController(&testing.T{})
|
||||
var (
|
||||
gAny = gomock.Any()
|
||||
errMock = errors.New("fake error")
|
||||
)
|
||||
|
||||
func newSdkHandler(t *testing.T) *sdkHandler {
|
||||
ctr := gomock.NewController(t)
|
||||
h := mocks.NewMockStreamHandler(ctr)
|
||||
l := stream.NewLimiter(stream.LimitConfig{
|
||||
NameRps: map[string]int{"alloc": 2},
|
||||
@ -52,10 +58,8 @@ func TestSdkBlobstore_New(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSdkHandler_Delete(t *testing.T) {
|
||||
any := gomock.Any()
|
||||
errMock := errors.New("fake error")
|
||||
ctx := context.Background()
|
||||
hd := newSdkHandler()
|
||||
hd := newSdkHandler(t)
|
||||
_, err := hd.Delete(ctx, nil)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
@ -75,7 +79,7 @@ func TestSdkHandler_Delete(t *testing.T) {
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
// retry 3 time
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(any, any).Times(3).Return(errMock)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(gAny, gAny).Times(3).Return(errMock)
|
||||
crc, _ := security.LocationCrcCalculate(&args.Locations[0])
|
||||
args.Locations[0].Crc = crc
|
||||
args.Locations[0].Slices = make([]proto.Slice, 0)
|
||||
@ -84,7 +88,7 @@ func TestSdkHandler_Delete(t *testing.T) {
|
||||
require.ErrorIs(t, err, errcode.ErrUnexpected)
|
||||
require.Equal(t, args.Locations, ret)
|
||||
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(any, any).Return(nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(gAny, gAny).Return(nil)
|
||||
ret, err = hd.Delete(ctx, args)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, ret)
|
||||
@ -101,12 +105,12 @@ func TestSdkHandler_Delete(t *testing.T) {
|
||||
for len(args.Locations) < 3 {
|
||||
args.Locations = append(args.Locations, loc)
|
||||
}
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(any, any).Return(nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(gAny, gAny).Return(nil)
|
||||
ret, err = hd.Delete(ctx, args)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, ret)
|
||||
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(any, any).Return(errMock).Times(3) // retry
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(gAny, gAny).Return(errMock).Times(3) // retry
|
||||
ret, err = hd.Delete(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrUnexpected)
|
||||
@ -114,10 +118,8 @@ func TestSdkHandler_Delete(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSdkHandler_Get(t *testing.T) {
|
||||
any := gomock.Any()
|
||||
errMock := errors.New("fake error")
|
||||
ctx := context.Background()
|
||||
hd := newSdkHandler()
|
||||
hd := newSdkHandler(t)
|
||||
|
||||
_, err := hd.Get(ctx, nil)
|
||||
require.NotNil(t, err)
|
||||
@ -144,7 +146,7 @@ func TestSdkHandler_Get(t *testing.T) {
|
||||
// stream get error, get nil
|
||||
crc, _ := security.LocationCrcCalculate(&args.Location)
|
||||
args.Location.Crc = crc
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Get(any, any, any, any, any).Return(nil, errMock)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Get(gAny, gAny, gAny, gAny, gAny).Return(nil, errMock)
|
||||
args.ReadSize = 2
|
||||
ret, err = hd.Get(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
@ -153,14 +155,14 @@ func TestSdkHandler_Get(t *testing.T) {
|
||||
require.Equal(t, 0, n)
|
||||
|
||||
// stream get error, do transfer error
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Get(any, any, any, any, any).Return(func() error { return errMock }, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Get(gAny, gAny, gAny, gAny, gAny).Return(func() error { return errMock }, nil)
|
||||
ret, err = hd.Get(ctx, args)
|
||||
require.NoError(t, err)
|
||||
n, err = ret.Read(retBuf)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, 0, n)
|
||||
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Get(any, any, any, any, any).Return(func() error { return nil }, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Get(gAny, gAny, gAny, gAny, gAny).Return(func() error { return nil }, nil)
|
||||
ret, err = hd.Get(ctx, args)
|
||||
require.NoError(t, err)
|
||||
n, _ = ret.Read(retBuf)
|
||||
@ -173,7 +175,7 @@ func TestSdkHandler_Get(t *testing.T) {
|
||||
crc, _ = security.LocationCrcCalculate(&args.Location)
|
||||
args.Location.Crc = crc
|
||||
rd, wr := io.Pipe()
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Get(any, any, any, any, any).DoAndReturn(
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Get(gAny, gAny, gAny, gAny, gAny).DoAndReturn(
|
||||
func(ctx context.Context, w io.Writer, location proto.Location, readSize, offset uint64) (func() error, error) {
|
||||
w = wr
|
||||
if readSize > 0 && readSize < 1024 {
|
||||
@ -200,7 +202,7 @@ func TestSdkHandler_Get(t *testing.T) {
|
||||
args.Location.Crc = crc
|
||||
buff := bytes.NewBuffer([]byte{})
|
||||
args.Writer = buff
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Get(any, args.Writer, any, any, any).DoAndReturn(
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Get(gAny, args.Writer, gAny, gAny, gAny).DoAndReturn(
|
||||
func(ctx context.Context, w io.Writer, location proto.Location, readSize, offset uint64) (func() error, error) {
|
||||
if readSize > 0 && readSize < 1024 {
|
||||
return func() error {
|
||||
@ -218,10 +220,8 @@ func TestSdkHandler_Get(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSdkHandler_Put(t *testing.T) {
|
||||
any := gomock.Any()
|
||||
errMock := errors.New("fake error")
|
||||
ctx := context.Background()
|
||||
hd := newSdkHandler()
|
||||
hd := newSdkHandler(t)
|
||||
|
||||
_, _, err := hd.Put(ctx, nil)
|
||||
require.NotNil(t, err)
|
||||
@ -238,7 +238,7 @@ func TestSdkHandler_Put(t *testing.T) {
|
||||
args := &acapi.PutArgs{Size: 2}
|
||||
|
||||
// stream put error
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Put(any, any, any, any).Return(nil, errMock)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Put(gAny, gAny, gAny, gAny).Return(nil, errMock)
|
||||
loc, hash, err = hd.Put(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, uint64(0), loc.Size_)
|
||||
@ -247,7 +247,7 @@ func TestSdkHandler_Put(t *testing.T) {
|
||||
// ok
|
||||
args.Hashes = 1
|
||||
mockLoc := proto.Location{Size_: 2}
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Put(any, any, any, any).Return(&mockLoc, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Put(gAny, gAny, gAny, gAny).Return(&mockLoc, nil)
|
||||
loc, hash, err = hd.Put(ctx, args)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, mockLoc.Size_, loc.Size_)
|
||||
@ -257,7 +257,7 @@ func TestSdkHandler_Put(t *testing.T) {
|
||||
args.GetBody = func() (io.ReadCloser, error) {
|
||||
return nil, nil
|
||||
}
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Put(any, any, any, any).Return(nil, errMock).Times(3)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Put(gAny, gAny, gAny, gAny).Return(nil, errMock).Times(3)
|
||||
loc, hash, err = hd.Put(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, uint64(0), loc.Size_)
|
||||
@ -269,8 +269,8 @@ func TestSdkHandler_Put(t *testing.T) {
|
||||
buff := bytes.NewBuffer(data)
|
||||
return io.NopCloser(buff), nil
|
||||
}
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Put(any, any, any, any).Return(nil, errMock)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Put(any, any, any, any).Return(&mockLoc, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Put(gAny, gAny, gAny, gAny).Return(nil, errMock)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Put(gAny, gAny, gAny, gAny).Return(&mockLoc, nil)
|
||||
loc, hash, err = hd.Put(ctx, args)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, mockLoc.Size_, loc.Size_)
|
||||
@ -278,10 +278,8 @@ func TestSdkHandler_Put(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSdkHandler_Alloc(t *testing.T) {
|
||||
any := gomock.Any()
|
||||
errMock := errors.New("fake error")
|
||||
ctx := context.Background()
|
||||
hd := newSdkHandler()
|
||||
hd := newSdkHandler(t)
|
||||
|
||||
_, err := hd.alloc(ctx, nil)
|
||||
require.NotNil(t, err)
|
||||
@ -295,7 +293,7 @@ func TestSdkHandler_Alloc(t *testing.T) {
|
||||
AssignClusterID: 1,
|
||||
CodeMode: codemode.EC3P3,
|
||||
}
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(any, any, any, any, any).Return(nil, errMock)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(gAny, gAny, gAny, gAny, gAny).Return(nil, errMock)
|
||||
ret, err := hd.alloc(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, proto.Location{}, ret.Location)
|
||||
@ -307,24 +305,22 @@ func TestSdkHandler_Alloc(t *testing.T) {
|
||||
}
|
||||
crc, _ := security.LocationCrcCalculate(loca)
|
||||
loca.Crc = crc
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(any, any, any, any, any).Return(loca, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(gAny, gAny, gAny, gAny, gAny).Return(loca, nil)
|
||||
ret, err = hd.alloc(ctx, args)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, *loca, ret.Location)
|
||||
}
|
||||
|
||||
func TestSdkHandler_putParts(t *testing.T) {
|
||||
any := gomock.Any()
|
||||
errMock := errors.New("fake error")
|
||||
ctx := context.Background()
|
||||
hd := newSdkHandler()
|
||||
hd := newSdkHandler(t)
|
||||
|
||||
hd.conf.MaxSizePutOnce = 8
|
||||
args := &acapi.PutArgs{Size: 12}
|
||||
|
||||
// alloc fail
|
||||
args.Hashes = 1
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(any, any, any, any, any).Return(nil, errMock)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(gAny, gAny, gAny, gAny, gAny).Return(nil, errMock)
|
||||
loc, hash, err := hd.Put(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errMock)
|
||||
@ -337,6 +333,7 @@ func TestSdkHandler_putParts(t *testing.T) {
|
||||
args.Size = int64(len(data))
|
||||
loca := &proto.Location{
|
||||
ClusterID: 1,
|
||||
CodeMode: codemode.EC3P3,
|
||||
Size_: uint64(args.Size),
|
||||
SliceSize: 4,
|
||||
Slices: []proto.Slice{{
|
||||
@ -347,16 +344,16 @@ func TestSdkHandler_putParts(t *testing.T) {
|
||||
}
|
||||
crc, _ := security.LocationCrcCalculate(loca)
|
||||
loca.Crc = crc
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(any, any, any, any, any).Return(loca, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(any, any, any, any, any, any, any).Return(nil).Times(14/4 + 1)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(gAny, gAny, gAny, gAny, gAny).Return(loca, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).Return(nil).Times(14/4 + 1)
|
||||
loc, hash, err = hd.Put(ctx, args)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(hash))
|
||||
require.Equal(t, *loca, loc)
|
||||
|
||||
// waiting at least one blob, errcode.ErrAccessReadRequestBody
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(any, any, any, any, any).Return(loca, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(any, any).Return(nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(gAny, gAny, gAny, gAny, gAny).Return(loca, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(gAny, gAny).Return(nil)
|
||||
_, _, err = hd.Put(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrAccessReadRequestBody)
|
||||
@ -364,9 +361,9 @@ func TestSdkHandler_putParts(t *testing.T) {
|
||||
// alloc the rest parts failed
|
||||
loca.CodeMode = codemode.EC3P3
|
||||
args.Body = bytes.NewBuffer([]byte(data))
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(any, any, any, any, any).Return(loca, nil).Times(4) // init, retry3
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(any, any, any, any, any, any, any).Return(errMock).Times(4)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(any, any).Return(nil).Times(4 + 1) // 4 blobs, fail del
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(gAny, gAny, gAny, gAny, gAny).Return(loca, nil).Times(4) // init, retry3
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).Return(errMock).Times(4)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(gAny, gAny).Return(nil).Times(4 + 1) // 4 blobs, fail del
|
||||
_, _, err = hd.Put(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrUnexpected)
|
||||
@ -375,7 +372,7 @@ func TestSdkHandler_putParts(t *testing.T) {
|
||||
{
|
||||
loca.CodeMode = codemode.EC3P3
|
||||
args.Body = bytes.NewBuffer([]byte(data))
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(any, any, any, any, any).Return(loca, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(gAny, gAny, gAny, gAny, gAny).Return(loca, nil)
|
||||
locb := &proto.Location{
|
||||
ClusterID: 1,
|
||||
Size_: uint64(args.Size),
|
||||
@ -388,12 +385,394 @@ func TestSdkHandler_putParts(t *testing.T) {
|
||||
}
|
||||
err = security.LocationCrcFill(locb)
|
||||
require.Nil(t, err)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(any, any, any, any, any).Return(locb, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(any, any, any, any, any, any, any).Return(errMock).Times(1)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(any, any, any, any, any, any, any).Return(nil).AnyTimes()
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(any, any).Return(nil).Times(4 + 1 + 1) // 4 blobs, fail del
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Alloc(gAny, gAny, gAny, gAny, gAny).Return(locb, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).Return(errMock).Times(1)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).Return(nil).AnyTimes()
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(gAny, gAny).Return(nil).Times(4 + 1) // 4 blobs, fail del
|
||||
_, _, err = hd.Put(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrUnexpected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSdkBlob_Get(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
hd := newSdkHandler(t)
|
||||
hd.conf.ShardnodeConfig = &stream.ShardnodeConfig{}
|
||||
|
||||
// err
|
||||
_, err := hd.GetBlob(ctx, nil)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
// err
|
||||
_, err = hd.GetBlob(ctx, &acapi.GetBlobArgs{
|
||||
ClusterID: 0,
|
||||
BlobName: nil,
|
||||
})
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
// err mock
|
||||
args := &acapi.GetBlobArgs{
|
||||
ClusterID: 1,
|
||||
BlobName: []byte("blob1"),
|
||||
Mode: acapi.GetShardModeRandom,
|
||||
Offset: 0,
|
||||
}
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().GetBlob(gAny, gAny).Return(nil, errMock)
|
||||
_, err = hd.GetBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errMock)
|
||||
|
||||
// get size 0
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().GetBlob(gAny, gAny).Return(&proto.Location{
|
||||
ClusterID: 1,
|
||||
CodeMode: codemode.EC3P3,
|
||||
Size_: 1,
|
||||
}, nil)
|
||||
ret, err := hd.GetBlob(ctx, args)
|
||||
require.NoError(t, err)
|
||||
retBuf := make([]byte, 2)
|
||||
n, _ := ret.Read(retBuf)
|
||||
require.Equal(t, 0, n)
|
||||
|
||||
// ok
|
||||
data := "test read"
|
||||
args.ReadSize = uint64(len(data))
|
||||
|
||||
loc := proto.Location{
|
||||
ClusterID: 1,
|
||||
CodeMode: codemode.EC3P3,
|
||||
Size_: 1,
|
||||
SliceSize: 1,
|
||||
Slices: make([]proto.Slice, 0),
|
||||
}
|
||||
crc, _ := security.LocationCrcCalculate(&loc)
|
||||
loc.Crc = crc
|
||||
|
||||
rd, wr := io.Pipe()
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Get(gAny, gAny, gAny, gAny, gAny).DoAndReturn(
|
||||
func(ctx context.Context, w io.Writer, location proto.Location, readSize, offset uint64) (func() error, error) {
|
||||
w = wr
|
||||
if readSize > 0 && readSize < 1024 {
|
||||
return func() error {
|
||||
_, err1 := w.Write([]byte(data))
|
||||
return err1
|
||||
}, nil
|
||||
}
|
||||
return nil, errMock
|
||||
})
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().GetBlob(gAny, gAny).Return(&loc, nil)
|
||||
_, err = hd.GetBlob(ctx, &acapi.GetBlobArgs{
|
||||
ClusterID: 1,
|
||||
BlobName: []byte("blob1"),
|
||||
ReadSize: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
retBuf = make([]byte, args.ReadSize*2)
|
||||
n, _ = rd.Read(retBuf)
|
||||
require.Equal(t, args.ReadSize, uint64(n))
|
||||
require.Equal(t, data, string(retBuf[:n]))
|
||||
}
|
||||
|
||||
func TestSdkBlob_List(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
hd := newSdkHandler(t)
|
||||
|
||||
hd.conf.ShardnodeConfig = &stream.ShardnodeConfig{}
|
||||
_, err := hd.ListBlob(ctx, nil)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
args := &acapi.ListBlobArgs{}
|
||||
_, err = hd.ListBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().ListBlob(gAny, gAny).Return(nil, errMock)
|
||||
args.ClusterID = 1
|
||||
_, err = hd.ListBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errMock)
|
||||
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().ListBlob(gAny, gAny).Return(&shardnode.ListBlobRet{}, nil)
|
||||
_, err = hd.ListBlob(ctx, args)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSdkBlob_Create(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
hd := newSdkHandler(t)
|
||||
|
||||
hd.conf.ShardnodeConfig = &stream.ShardnodeConfig{}
|
||||
_, err := hd.CreateBlob(ctx, nil)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
args := &acapi.CreateBlobArgs{}
|
||||
_, err = hd.CreateBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().CreateBlob(gAny, gAny).Return(nil, errMock)
|
||||
args.CodeMode = codemode.EC3P3
|
||||
args.Size = 1
|
||||
args.BlobName = []byte("blob1")
|
||||
_, err = hd.CreateBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errMock)
|
||||
|
||||
loca := &proto.Location{
|
||||
ClusterID: 1,
|
||||
Size_: 2,
|
||||
SliceSize: 1,
|
||||
}
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().CreateBlob(gAny, gAny).Return(loca, nil)
|
||||
_, err = hd.CreateBlob(ctx, args)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSdkBlob_Seal(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
hd := newSdkHandler(t)
|
||||
|
||||
hd.conf.ShardnodeConfig = &stream.ShardnodeConfig{}
|
||||
err := hd.SealBlob(ctx, nil)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
args := &acapi.SealBlobArgs{}
|
||||
err = hd.SealBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().SealBlob(gAny, gAny).Return(errMock)
|
||||
args.ClusterID = 1
|
||||
args.BlobName = []byte("blob1")
|
||||
args.Slices = make([]proto.Slice, 1)
|
||||
err = hd.SealBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errMock)
|
||||
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().SealBlob(gAny, gAny).Return(nil)
|
||||
err = hd.SealBlob(ctx, args)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSdkBlob_Delete(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
hd := newSdkHandler(t)
|
||||
|
||||
hd.conf.ShardnodeConfig = &stream.ShardnodeConfig{}
|
||||
err := hd.DeleteBlob(ctx, nil)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
args := &acapi.DelBlobArgs{}
|
||||
err = hd.DeleteBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().DeleteBlob(gAny, gAny).Return(errMock)
|
||||
args.ClusterID = 1
|
||||
args.BlobName = []byte("blob1")
|
||||
err = hd.DeleteBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errMock)
|
||||
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().DeleteBlob(gAny, gAny).Return(nil)
|
||||
err = hd.DeleteBlob(ctx, args)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSdkBlob_Put(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
hd := newSdkHandler(t)
|
||||
|
||||
hd.conf.ShardnodeConfig = &stream.ShardnodeConfig{}
|
||||
args := &acapi.PutBlobArgs{}
|
||||
_, err := hd.PutBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errcode.ErrIllegalArguments)
|
||||
|
||||
args = &acapi.PutBlobArgs{
|
||||
BlobName: []byte("blob1"),
|
||||
CodeMode: codemode.EC3P3,
|
||||
NeedSeal: false,
|
||||
ShardKeys: nil,
|
||||
Hashes: 0,
|
||||
}
|
||||
data := "test_put1"
|
||||
args.Body = bytes.NewBuffer([]byte(data))
|
||||
args.Size = uint64(len(data))
|
||||
loca := &proto.Location{
|
||||
ClusterID: 1,
|
||||
Size_: uint64(len(data)),
|
||||
SliceSize: 4,
|
||||
Slices: []proto.Slice{
|
||||
{
|
||||
MinSliceID: 1,
|
||||
Vid: 10,
|
||||
Count: 3,
|
||||
ValidSize: uint64(len(data)),
|
||||
},
|
||||
},
|
||||
}
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().CreateBlob(gAny, gAny).Return(loca, nil)
|
||||
wt := bytes.NewBuffer(nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).DoAndReturn(
|
||||
func(ctx context.Context, rd io.Reader, cid proto.ClusterID, vid proto.Vid, bid proto.BlobID, sz int64, hm acapi.HasherMap) error {
|
||||
io.Copy(wt, rd)
|
||||
return nil
|
||||
}).Times(9/4 + 1)
|
||||
// put ok
|
||||
cid, err := hd.PutBlob(ctx, args)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, proto.ClusterID(1), cid)
|
||||
require.Equal(t, data, wt.String())
|
||||
|
||||
// put fail, not have read, return EOF
|
||||
args.BlobName = []byte("blob0")
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().CreateBlob(gAny, gAny).Return(loca, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().DeleteBlob(gAny, gAny).Return(nil)
|
||||
cid, err = hd.PutBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, io.EOF)
|
||||
require.Equal(t, proto.ClusterID(1), cid)
|
||||
|
||||
// put fail, create fail
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().CreateBlob(gAny, gAny).Return(&proto.Location{}, errMock)
|
||||
cid, err = hd.PutBlob(ctx, args)
|
||||
require.NotNil(t, err)
|
||||
require.ErrorIs(t, err, errMock)
|
||||
require.Equal(t, proto.ClusterID(0), cid)
|
||||
|
||||
// split slice. blobID 2 fail
|
||||
hd.conf.MaxRetry = 3
|
||||
args.BlobName = []byte("blob2")
|
||||
data = "test_put2"
|
||||
args.Body = bytes.NewBuffer([]byte(data))
|
||||
locb := &proto.Location{
|
||||
ClusterID: 1,
|
||||
Size_: uint64(len(data)),
|
||||
SliceSize: 2,
|
||||
Slices: []proto.Slice{{
|
||||
MinSliceID: 1, // 1,2,3
|
||||
Vid: 1,
|
||||
Count: 3,
|
||||
ValidSize: 6,
|
||||
}, {
|
||||
MinSliceID: 10, // 10,11
|
||||
Vid: 2,
|
||||
Count: 2,
|
||||
ValidSize: 3,
|
||||
}},
|
||||
}
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().CreateBlob(gAny, gAny).Return(locb, nil)
|
||||
wt = bytes.NewBuffer(nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).DoAndReturn(
|
||||
func(ctx context.Context, rd io.Reader, cid proto.ClusterID, vid proto.Vid, bid proto.BlobID, sz int64, hm acapi.HasherMap) error {
|
||||
io.Copy(wt, rd)
|
||||
return nil
|
||||
}).Times(1)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).Return(errMock) // .Times(hd.conf.MaxRetry)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(gAny, gAny).Return(nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().AllocSlice(gAny, gAny).Return(&shardnode.AllocSliceRet{
|
||||
Slices: []proto.Slice{{
|
||||
MinSliceID: 4, // 2,3 -> 4,5
|
||||
Vid: 3,
|
||||
Count: 2,
|
||||
ValidSize: 4,
|
||||
}},
|
||||
}, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).DoAndReturn(
|
||||
func(ctx context.Context, rd io.Reader, cid proto.ClusterID, vid proto.Vid, bid proto.BlobID, sz int64, hm acapi.HasherMap) error {
|
||||
io.Copy(wt, rd)
|
||||
return nil
|
||||
}).Times(4)
|
||||
retLoc, err := hd.putBlobs(ctx, args)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, proto.ClusterID(1), retLoc.ClusterID)
|
||||
require.Equal(t, args.Size, retLoc.Size_)
|
||||
require.Equal(t, 3, len(retLoc.Slices))
|
||||
sz := uint64(0)
|
||||
for i := range retLoc.Slices {
|
||||
sz += retLoc.Slices[i].ValidSize
|
||||
}
|
||||
require.Equal(t, args.Size, sz)
|
||||
require.Equal(t, data, wt.String())
|
||||
|
||||
// first slice idx fail(blobID 1 fail), retry alloc all slices
|
||||
hd.conf.MaxRetry = 3
|
||||
data = "test_put3"
|
||||
args.BlobName = []byte("blob3")
|
||||
args.Body = bytes.NewBuffer([]byte(data))
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().CreateBlob(gAny, gAny).Return(locb, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).Return(errMock) // .Times(hd.conf.MaxRetry)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(gAny, gAny).Return(nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().AllocSlice(gAny, gAny).Return(&shardnode.AllocSliceRet{
|
||||
Slices: []proto.Slice{{
|
||||
MinSliceID: 4, // 1,2,3 -> 4,5,6
|
||||
Vid: 3,
|
||||
Count: 3,
|
||||
ValidSize: 6,
|
||||
}},
|
||||
}, nil)
|
||||
wt = bytes.NewBuffer(nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).DoAndReturn(
|
||||
func(ctx context.Context, rd io.Reader, cid proto.ClusterID, vid proto.Vid, bid proto.BlobID, sz int64, hm acapi.HasherMap) error {
|
||||
io.Copy(wt, rd)
|
||||
return nil
|
||||
}).Times(3 + 2) // count 3+2
|
||||
retLoc, err = hd.putBlobs(ctx, args)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, proto.ClusterID(1), retLoc.ClusterID)
|
||||
require.Equal(t, args.Size, retLoc.Size_)
|
||||
require.Equal(t, 2, len(retLoc.Slices))
|
||||
sz = uint64(0)
|
||||
for i := range retLoc.Slices {
|
||||
sz += retLoc.Slices[i].ValidSize
|
||||
}
|
||||
require.Equal(t, args.Size, sz)
|
||||
require.Equal(t, data, wt.String())
|
||||
|
||||
// last slice idx fail(blobID 11 fail), retry alloc last blobId of last slice
|
||||
hd.conf.MaxRetry = 3
|
||||
data = "test_put4"
|
||||
args.BlobName = []byte("blob4")
|
||||
args.Body = bytes.NewBuffer([]byte(data))
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().CreateBlob(gAny, gAny).Return(locb, nil)
|
||||
wt = bytes.NewBuffer(nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).DoAndReturn(
|
||||
func(ctx context.Context, rd io.Reader, cid proto.ClusterID, vid proto.Vid, bid proto.BlobID, sz int64, hm acapi.HasherMap) error {
|
||||
io.Copy(wt, rd)
|
||||
return nil
|
||||
}).Times(3 + 1) // count 3+2
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).Return(errMock) // .Times(hd.conf.MaxRetry)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().Delete(gAny, gAny).Return(nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().AllocSlice(gAny, gAny).Return(&shardnode.AllocSliceRet{
|
||||
Slices: []proto.Slice{{
|
||||
MinSliceID: 12, // 11 -> 12
|
||||
Vid: 3,
|
||||
Count: 1,
|
||||
ValidSize: 1,
|
||||
}},
|
||||
}, nil)
|
||||
hd.handler.(*mocks.MockStreamHandler).EXPECT().PutAt(gAny, gAny, gAny, gAny, gAny, gAny, gAny).DoAndReturn(
|
||||
func(ctx context.Context, rd io.Reader, cid proto.ClusterID, vid proto.Vid, bid proto.BlobID, sz int64, hm acapi.HasherMap) error {
|
||||
io.Copy(wt, rd)
|
||||
return nil
|
||||
}).Times(1)
|
||||
retLoc, err = hd.putBlobs(ctx, args)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, proto.ClusterID(1), retLoc.ClusterID)
|
||||
require.Equal(t, args.Size, retLoc.Size_)
|
||||
require.Equal(t, 3, len(retLoc.Slices))
|
||||
sz = uint64(0)
|
||||
for i := range retLoc.Slices {
|
||||
sz += retLoc.Slices[i].ValidSize
|
||||
}
|
||||
require.Equal(t, args.Size, sz)
|
||||
require.Equal(t, data, wt.String())
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@ package testing
|
||||
//go:generate mockgen -destination=./mocks/api_blobnode.go -package=mocks -mock_names StorageAPI=MockStorageAPI github.com/cubefs/cubefs/blobstore/api/blobnode StorageAPI
|
||||
//go:generate mockgen -destination=./mocks/api_scheduler.go -package=mocks -mock_names IScheduler=MockIScheduler github.com/cubefs/cubefs/blobstore/api/scheduler IScheduler
|
||||
//go:generate mockgen -destination=./mocks/api_proxy.go -package=mocks -mock_names Client=MockProxyClient,LbMsgSender=MockProxyLbRpcClient github.com/cubefs/cubefs/blobstore/api/proxy Client,LbMsgSender
|
||||
//go:generate mockgen -destination=./mocks/api_shardnode.go -package=mocks -mock_names AccessAPI=MockShardnodeAccess github.com/cubefs/cubefs/blobstore/api/shardnode AccessAPI
|
||||
|
||||
// github.com/cubefs/cubefs/blobstore/access/... access interfaces
|
||||
//go:generate mockgen -destination=./mocks/access_stream.go -package=mocks -mock_names StreamHandler=MockStreamHandler github.com/cubefs/cubefs/blobstore/access/stream StreamHandler
|
||||
|
||||
@ -10,9 +10,9 @@ import (
|
||||
reflect "reflect"
|
||||
|
||||
access "github.com/cubefs/cubefs/blobstore/api/access"
|
||||
shardnode "github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
codemode "github.com/cubefs/cubefs/blobstore/common/codemode"
|
||||
proto "github.com/cubefs/cubefs/blobstore/common/proto"
|
||||
base "github.com/cubefs/cubefs/blobstore/sdk/base"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
@ -68,6 +68,36 @@ func (mr *MockStreamHandlerMockRecorder) Alloc(arg0, arg1, arg2, arg3, arg4 inte
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Alloc", reflect.TypeOf((*MockStreamHandler)(nil).Alloc), arg0, arg1, arg2, arg3, arg4)
|
||||
}
|
||||
|
||||
// AllocSlice mocks base method.
|
||||
func (m *MockStreamHandler) AllocSlice(arg0 context.Context, arg1 *access.AllocSliceArgs) (*shardnode.AllocSliceRet, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AllocSlice", arg0, arg1)
|
||||
ret0, _ := ret[0].(*shardnode.AllocSliceRet)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// AllocSlice indicates an expected call of AllocSlice.
|
||||
func (mr *MockStreamHandlerMockRecorder) AllocSlice(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllocSlice", reflect.TypeOf((*MockStreamHandler)(nil).AllocSlice), arg0, arg1)
|
||||
}
|
||||
|
||||
// CreateBlob mocks base method.
|
||||
func (m *MockStreamHandler) CreateBlob(arg0 context.Context, arg1 *access.CreateBlobArgs) (*proto.Location, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateBlob", arg0, arg1)
|
||||
ret0, _ := ret[0].(*proto.Location)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateBlob indicates an expected call of CreateBlob.
|
||||
func (mr *MockStreamHandlerMockRecorder) CreateBlob(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBlob", reflect.TypeOf((*MockStreamHandler)(nil).CreateBlob), arg0, arg1)
|
||||
}
|
||||
|
||||
// Delete mocks base method.
|
||||
func (m *MockStreamHandler) Delete(arg0 context.Context, arg1 *proto.Location) error {
|
||||
m.ctrl.T.Helper()
|
||||
@ -82,6 +112,20 @@ func (mr *MockStreamHandlerMockRecorder) Delete(arg0, arg1 interface{}) *gomock.
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockStreamHandler)(nil).Delete), arg0, arg1)
|
||||
}
|
||||
|
||||
// DeleteBlob mocks base method.
|
||||
func (m *MockStreamHandler) DeleteBlob(arg0 context.Context, arg1 *access.DelBlobArgs) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteBlob", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteBlob indicates an expected call of DeleteBlob.
|
||||
func (mr *MockStreamHandlerMockRecorder) DeleteBlob(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBlob", reflect.TypeOf((*MockStreamHandler)(nil).DeleteBlob), arg0, arg1)
|
||||
}
|
||||
|
||||
// Get mocks base method.
|
||||
func (m *MockStreamHandler) Get(arg0 context.Context, arg1 io.Writer, arg2 proto.Location, arg3, arg4 uint64) (func() error, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -98,7 +142,7 @@ func (mr *MockStreamHandlerMockRecorder) Get(arg0, arg1, arg2, arg3, arg4 interf
|
||||
}
|
||||
|
||||
// GetBlob mocks base method.
|
||||
func (m *MockStreamHandler) GetBlob(arg0 context.Context, arg1 *base.GetBlobArgs) (*proto.Location, error) {
|
||||
func (m *MockStreamHandler) GetBlob(arg0 context.Context, arg1 *access.GetBlobArgs) (*proto.Location, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetBlob", arg0, arg1)
|
||||
ret0, _ := ret[0].(*proto.Location)
|
||||
@ -112,6 +156,21 @@ func (mr *MockStreamHandlerMockRecorder) GetBlob(arg0, arg1 interface{}) *gomock
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlob", reflect.TypeOf((*MockStreamHandler)(nil).GetBlob), arg0, arg1)
|
||||
}
|
||||
|
||||
// ListBlob mocks base method.
|
||||
func (m *MockStreamHandler) ListBlob(arg0 context.Context, arg1 *access.ListBlobArgs) (*shardnode.ListBlobRet, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListBlob", arg0, arg1)
|
||||
ret0, _ := ret[0].(*shardnode.ListBlobRet)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListBlob indicates an expected call of ListBlob.
|
||||
func (mr *MockStreamHandlerMockRecorder) ListBlob(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListBlob", reflect.TypeOf((*MockStreamHandler)(nil).ListBlob), arg0, arg1)
|
||||
}
|
||||
|
||||
// Put mocks base method.
|
||||
func (m *MockStreamHandler) Put(arg0 context.Context, arg1 io.Reader, arg2 int64, arg3 access.HasherMap) (*proto.Location, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -140,3 +199,17 @@ func (mr *MockStreamHandlerMockRecorder) PutAt(arg0, arg1, arg2, arg3, arg4, arg
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutAt", reflect.TypeOf((*MockStreamHandler)(nil).PutAt), arg0, arg1, arg2, arg3, arg4, arg5, arg6)
|
||||
}
|
||||
|
||||
// SealBlob mocks base method.
|
||||
func (m *MockStreamHandler) SealBlob(arg0 context.Context, arg1 *access.SealBlobArgs) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SealBlob", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SealBlob indicates an expected call of SealBlob.
|
||||
func (mr *MockStreamHandlerMockRecorder) SealBlob(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SealBlob", reflect.TypeOf((*MockStreamHandler)(nil).SealBlob), arg0, arg1)
|
||||
}
|
||||
|
||||
@ -185,6 +185,21 @@ func (mr *MockClientAPIMockRecorder) ListDisk(arg0, arg1 interface{}) *gomock.Ca
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDisk", reflect.TypeOf((*MockClientAPI)(nil).ListDisk), arg0, arg1)
|
||||
}
|
||||
|
||||
// ListShardNodeDisk mocks base method.
|
||||
func (m *MockClientAPI) ListShardNodeDisk(arg0 context.Context, arg1 *clustermgr.ListOptionArgs) (clustermgr.ListShardNodeDiskRet, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListShardNodeDisk", arg0, arg1)
|
||||
ret0, _ := ret[0].(clustermgr.ListShardNodeDiskRet)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListShardNodeDisk indicates an expected call of ListShardNodeDisk.
|
||||
func (mr *MockClientAPIMockRecorder) ListShardNodeDisk(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListShardNodeDisk", reflect.TypeOf((*MockClientAPI)(nil).ListShardNodeDisk), arg0, arg1)
|
||||
}
|
||||
|
||||
// RegisterService mocks base method.
|
||||
func (m *MockClientAPI) RegisterService(arg0 context.Context, arg1 clustermgr.ServiceNode, arg2, arg3, arg4 uint32) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
139
blobstore/testing/mocks/api_shardnode.go
Normal file
139
blobstore/testing/mocks/api_shardnode.go
Normal file
@ -0,0 +1,139 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/cubefs/cubefs/blobstore/api/shardnode (interfaces: AccessAPI)
|
||||
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
shardnode "github.com/cubefs/cubefs/blobstore/api/shardnode"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockShardnodeAccess is a mock of AccessAPI interface.
|
||||
type MockShardnodeAccess struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockShardnodeAccessMockRecorder
|
||||
}
|
||||
|
||||
// MockShardnodeAccessMockRecorder is the mock recorder for MockShardnodeAccess.
|
||||
type MockShardnodeAccessMockRecorder struct {
|
||||
mock *MockShardnodeAccess
|
||||
}
|
||||
|
||||
// NewMockShardnodeAccess creates a new mock instance.
|
||||
func NewMockShardnodeAccess(ctrl *gomock.Controller) *MockShardnodeAccess {
|
||||
mock := &MockShardnodeAccess{ctrl: ctrl}
|
||||
mock.recorder = &MockShardnodeAccessMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockShardnodeAccess) EXPECT() *MockShardnodeAccessMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AllocSlice mocks base method.
|
||||
func (m *MockShardnodeAccess) AllocSlice(arg0 context.Context, arg1 string, arg2 shardnode.AllocSliceArgs) (shardnode.AllocSliceRet, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AllocSlice", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(shardnode.AllocSliceRet)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// AllocSlice indicates an expected call of AllocSlice.
|
||||
func (mr *MockShardnodeAccessMockRecorder) AllocSlice(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllocSlice", reflect.TypeOf((*MockShardnodeAccess)(nil).AllocSlice), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// CreateBlob mocks base method.
|
||||
func (m *MockShardnodeAccess) CreateBlob(arg0 context.Context, arg1 string, arg2 shardnode.CreateBlobArgs) (shardnode.CreateBlobRet, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateBlob", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(shardnode.CreateBlobRet)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateBlob indicates an expected call of CreateBlob.
|
||||
func (mr *MockShardnodeAccessMockRecorder) CreateBlob(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBlob", reflect.TypeOf((*MockShardnodeAccess)(nil).CreateBlob), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// DeleteBlob mocks base method.
|
||||
func (m *MockShardnodeAccess) DeleteBlob(arg0 context.Context, arg1 string, arg2 shardnode.DeleteBlobArgs) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteBlob", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteBlob indicates an expected call of DeleteBlob.
|
||||
func (mr *MockShardnodeAccessMockRecorder) DeleteBlob(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBlob", reflect.TypeOf((*MockShardnodeAccess)(nil).DeleteBlob), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// GetBlob mocks base method.
|
||||
func (m *MockShardnodeAccess) GetBlob(arg0 context.Context, arg1 string, arg2 shardnode.GetBlobArgs) (shardnode.GetBlobRet, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetBlob", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(shardnode.GetBlobRet)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetBlob indicates an expected call of GetBlob.
|
||||
func (mr *MockShardnodeAccessMockRecorder) GetBlob(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlob", reflect.TypeOf((*MockShardnodeAccess)(nil).GetBlob), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// GetShardStats mocks base method.
|
||||
func (m *MockShardnodeAccess) GetShardStats(arg0 context.Context, arg1 string, arg2 shardnode.GetShardArgs) (shardnode.ShardStats, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetShardStats", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(shardnode.ShardStats)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetShardStats indicates an expected call of GetShardStats.
|
||||
func (mr *MockShardnodeAccessMockRecorder) GetShardStats(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetShardStats", reflect.TypeOf((*MockShardnodeAccess)(nil).GetShardStats), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ListBlob mocks base method.
|
||||
func (m *MockShardnodeAccess) ListBlob(arg0 context.Context, arg1 string, arg2 shardnode.ListBlobArgs) (shardnode.ListBlobRet, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListBlob", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(shardnode.ListBlobRet)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListBlob indicates an expected call of ListBlob.
|
||||
func (mr *MockShardnodeAccessMockRecorder) ListBlob(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListBlob", reflect.TypeOf((*MockShardnodeAccess)(nil).ListBlob), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// SealBlob mocks base method.
|
||||
func (m *MockShardnodeAccess) SealBlob(arg0 context.Context, arg1 string, arg2 shardnode.SealBlobArgs) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SealBlob", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SealBlob indicates an expected call of SealBlob.
|
||||
func (mr *MockShardnodeAccessMockRecorder) SealBlob(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SealBlob", reflect.TypeOf((*MockShardnodeAccess)(nil).SealBlob), arg0, arg1, arg2)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user