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:
mawei029 2024-08-12 17:03:36 +08:00 committed by slasher
parent 7706c4b4b3
commit 84d6df46af
27 changed files with 3205 additions and 577 deletions

View File

@ -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
}

View File

@ -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{}))

View File

@ -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
}

View File

@ -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)

View File

@ -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))

View File

@ -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())
}
}

View File

@ -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))
}

View File

@ -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)

View 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
}

View 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)
}

View File

@ -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"

View File

@ -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{}

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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;

View File

@ -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)
)

View File

@ -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")
)

View File

@ -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
}

View File

@ -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)
}

View File

@ -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

View File

@ -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())
}

View File

@ -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

View File

@ -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)
}

View File

@ -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()

View 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)
}