Locate object-storing shards #1635

Merged
dstepanov-yadro merged 3 commits from elebedeva/frostfs-node:feat/shard-info-for-object into master 2025-03-07 13:07:12 +00:00
19 changed files with 1053 additions and 14 deletions

View file

@ -0,0 +1,118 @@
package control
import (
"bytes"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
object "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/object"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
rawclient "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/mr-tron/base58"
"github.com/spf13/cobra"
)
const (
FullInfoFlag = "full"
FullInfoFlagUsage = "Print full ShardInfo."
)
var locateObjectCmd = &cobra.Command{
a-savchuk marked this conversation as resolved Outdated

Control commands have different common flags, see the command for shard listing

initControlFlags(listShardsCmd)

Please double-check and fix if needed

Control commands have different common flags, see the command for shard listing https://git.frostfs.info/TrueCloudLab/frostfs-node/src/commit/5d79abe523b0254fe0484220d6d2c57a172090e1/cmd/frostfs-cli/modules/control/shards_list.go#L27 Please double-check and fix if needed

Fixed

Fixed
Use: "locate-object",
Short: "List shards storing the object",
Long: "List shards storing the object",
Run: locateObject,
}
func initControlLocateObjectCmd() {
initControlFlags(locateObjectCmd)
flags := locateObjectCmd.Flags()
flags.String(commonflags.CIDFlag, "", commonflags.CIDFlagUsage)
_ = locateObjectCmd.MarkFlagRequired(commonflags.CIDFlag)
flags.String(commonflags.OIDFlag, "", commonflags.OIDFlagUsage)
_ = locateObjectCmd.MarkFlagRequired(commonflags.OIDFlag)
flags.Bool(commonflags.JSON, false, "Print shard info as a JSON array. Requires --full flag.")
flags.Bool(FullInfoFlag, false, FullInfoFlagUsage)
}
func locateObject(cmd *cobra.Command, _ []string) {
var cnr cid.ID
var obj oid.ID
_ = object.ReadObjectAddress(cmd, &cnr, &obj)
pk := key.Get(cmd)
a-savchuk marked this conversation as resolved Outdated

You should use control endpoint, please see the command for shard listing

cli := getClient(cmd, pk)

You should use control endpoint, please see the command for shard listing https://git.frostfs.info/TrueCloudLab/frostfs-node/src/commit/5d79abe523b0254fe0484220d6d2c57a172090e1/cmd/frostfs-cli/modules/control/shards_list.go#L41

Fixed

Fixed
body := new(control.ListShardsForObjectRequest_Body)
body.SetContainerId(cnr.EncodeToString())
body.SetObjectId(obj.EncodeToString())
req := new(control.ListShardsForObjectRequest)
req.SetBody(body)
signRequest(cmd, pk, req)
cli := getClient(cmd, pk)
var err error
var resp *control.ListShardsForObjectResponse
err = cli.ExecRaw(func(client *rawclient.Client) error {
resp, err = control.ListShardsForObject(client, req)
return err
})
commonCmd.ExitOnErr(cmd, "rpc error: %w", err)
verifyResponse(cmd, resp.GetSignature(), resp.GetBody())
shardIDs := resp.GetBody().GetShard_ID()
dstepanov-yadro marked this conversation as resolved Outdated

duplicate

func readObjectAddress(cmd *cobra.Command, cnr *cid.ID, obj *oid.ID) oid.Address {

duplicate https://git.frostfs.info/TrueCloudLab/frostfs-node/src/commit/5d79abe523b0254fe0484220d6d2c57a172090e1/cmd/frostfs-cli/modules/object/util.go#L77

Made object.readObjectAddress() public and reused it in locateObject().

Made `object.readObjectAddress()` public and reused it in `locateObject()`.
isFull, _ := cmd.Flags().GetBool(FullInfoFlag)
if !isFull {
for _, id := range shardIDs {
cmd.Println(base58.Encode(id))
}
return
}
// get full shard info
listShardsReq := new(control.ListShardsRequest)
listShardsReq.SetBody(new(control.ListShardsRequest_Body))
signRequest(cmd, pk, listShardsReq)
var listShardsResp *control.ListShardsResponse
err = cli.ExecRaw(func(client *rawclient.Client) error {
listShardsResp, err = control.ListShards(client, listShardsReq)
return err
})
commonCmd.ExitOnErr(cmd, "rpc error: %w", err)
verifyResponse(cmd, listShardsResp.GetSignature(), listShardsResp.GetBody())
shards := listShardsResp.GetBody().GetShards()
sortShardsByID(shards)
shards = filterShards(shards, shardIDs)
isJSON, _ := cmd.Flags().GetBool(commonflags.JSON)
if isJSON {
prettyPrintShardsJSON(cmd, shards)
} else {
prettyPrintShards(cmd, shards)
}
}
func filterShards(info []control.ShardInfo, ids [][]byte) []control.ShardInfo {
var res []control.ShardInfo
for _, id := range ids {
for _, inf := range info {
if bytes.Equal(inf.Shard_ID, id) {
res = append(res, inf)
}
}
}
return res
}

View file

@ -39,6 +39,7 @@ func init() {
listRulesCmd,
getRuleCmd,
listTargetsCmd,
locateObjectCmd,
)
initControlHealthCheckCmd()
@ -52,4 +53,5 @@ func init() {
initControlListRulesCmd()
initControGetRuleCmd()
initControlListTargetsCmd()
initControlLocateObjectCmd()
}

View file

@ -55,7 +55,7 @@ func deleteObject(cmd *cobra.Command, _ []string) {
commonCmd.ExitOnErr(cmd, "", fmt.Errorf("required flag \"%s\" not set", commonflags.OIDFlag))
}
objAddr = readObjectAddress(cmd, &cnr, &obj)
objAddr = ReadObjectAddress(cmd, &cnr, &obj)
}
pk := key.GetOrGenerate(cmd)

View file

@ -46,7 +46,7 @@ func getObject(cmd *cobra.Command, _ []string) {
var cnr cid.ID
var obj oid.ID
objAddr := readObjectAddress(cmd, &cnr, &obj)
objAddr := ReadObjectAddress(cmd, &cnr, &obj)
filename := cmd.Flag(fileFlag).Value.String()
out, closer := createOutWriter(cmd, filename)

View file

@ -52,7 +52,7 @@ func getObjectHash(cmd *cobra.Command, _ []string) {
var cnr cid.ID
var obj oid.ID
objAddr := readObjectAddress(cmd, &cnr, &obj)
objAddr := ReadObjectAddress(cmd, &cnr, &obj)
ranges, err := getRangeList(cmd)
commonCmd.ExitOnErr(cmd, "", err)

View file

@ -47,7 +47,7 @@ func getObjectHeader(cmd *cobra.Command, _ []string) {
var cnr cid.ID
var obj oid.ID
objAddr := readObjectAddress(cmd, &cnr, &obj)
objAddr := ReadObjectAddress(cmd, &cnr, &obj)
pk := key.GetOrGenerate(cmd)
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)

View file

@ -101,7 +101,7 @@ func initObjectNodesCmd() {
func objectNodes(cmd *cobra.Command, _ []string) {
var cnrID cid.ID
var objID oid.ID
readObjectAddress(cmd, &cnrID, &objID)
ReadObjectAddress(cmd, &cnrID, &objID)
pk := key.GetOrGenerate(cmd)
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)

View file

@ -56,7 +56,7 @@ func patch(cmd *cobra.Command, _ []string) {
var cnr cid.ID
var obj oid.ID
objAddr := readObjectAddress(cmd, &cnr, &obj)
objAddr := ReadObjectAddress(cmd, &cnr, &obj)
ranges, err := getRangeSlice(cmd)
commonCmd.ExitOnErr(cmd, "", err)

View file

@ -47,7 +47,7 @@ func getObjectRange(cmd *cobra.Command, _ []string) {
var cnr cid.ID
var obj oid.ID
objAddr := readObjectAddress(cmd, &cnr, &obj)
objAddr := ReadObjectAddress(cmd, &cnr, &obj)
ranges, err := getRangeList(cmd)
commonCmd.ExitOnErr(cmd, "", err)

View file

@ -74,7 +74,7 @@ func parseXHeaders(cmd *cobra.Command) []string {
return xs
}
func readObjectAddress(cmd *cobra.Command, cnr *cid.ID, obj *oid.ID) oid.Address {
func ReadObjectAddress(cmd *cobra.Command, cnr *cid.ID, obj *oid.ID) oid.Address {
readCID(cmd, cnr)
readOID(cmd, obj)

4
go.mod
View file

@ -4,7 +4,7 @@ go 1.22
require (
code.gitea.io/sdk/gitea v0.17.1
git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1-0.20241205083807-762d7f9f9f08
git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0
git.frostfs.info/TrueCloudLab/frostfs-locode-db v0.4.1-0.20240710074952-65761deb5c0d
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20250212111929-d34e1329c824
@ -12,7 +12,7 @@ require (
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20250306092416-69b0711d12d9
git.frostfs.info/TrueCloudLab/hrw v1.2.1
git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240814080254-96225afacb88
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240822104152-a3bc3099bd5b
git.frostfs.info/TrueCloudLab/tzhash v1.8.0
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02
github.com/VictoriaMetrics/easyproto v0.1.4

8
go.sum
View file

@ -1,7 +1,7 @@
code.gitea.io/sdk/gitea v0.17.1 h1:3jCPOG2ojbl8AcfaUCRYLT5MUcBMFwS0OSK2mA5Zok8=
code.gitea.io/sdk/gitea v0.17.1/go.mod h1:aCnBqhHpoEWA180gMbaCtdX9Pl6BWBAuuP2miadoTNM=
git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1-0.20241205083807-762d7f9f9f08 h1:tl1TT+zNk1lF/J5EaD3syDrTaYbQwvJKVOVENM4oQ+k=
git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1-0.20241205083807-762d7f9f9f08/go.mod h1:5fSm/l5xSjGWqsPUffSdboiGFUHa7y/1S0fvxzQowN8=
git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1 h1:k1Qw8dWUQczfo0eVXlhrq9eXEbUMyDLW8jEMzY+gxMc=
git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1/go.mod h1:5fSm/l5xSjGWqsPUffSdboiGFUHa7y/1S0fvxzQowN8=
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
git.frostfs.info/TrueCloudLab/frostfs-locode-db v0.4.1-0.20240710074952-65761deb5c0d h1:uJ/wvuMdepbkaV8XMS5uN9B0FQWMep0CttSuDZiDhq0=
@ -18,8 +18,8 @@ git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972 h1:/96
git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972/go.mod h1:2hM42MBrlhvN6XToaW6OWNk5ZLcu1FhaukGgxtfpDDI=
git.frostfs.info/TrueCloudLab/neoneo-go v0.106.1-0.20241015133823-8aee80dbdc07 h1:gPaqGsk6gSWQyNVjaStydfUz6Z/loHc9XyvGrJ5qSPY=
git.frostfs.info/TrueCloudLab/neoneo-go v0.106.1-0.20241015133823-8aee80dbdc07/go.mod h1:bZyJexBlrja4ngxiBgo8by5pVHuAbhg9l09/8yVGDyg=
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240814080254-96225afacb88 h1:vgbfkcnIexZUm3vREBBSa/Gv1Whjd1SFCUd0A+IaGPQ=
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240814080254-96225afacb88/go.mod h1:SgioiGhQNWqiV5qpFAXRDJF81SEFRBhtwGEiU0FViyA=
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240822104152-a3bc3099bd5b h1:M50kdfrf/h8c3cz0bJ2AEUcbXvAlPFVC1Wp1WkfZ/8E=
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240822104152-a3bc3099bd5b/go.mod h1:GZTk55RI4dKzsK6BCn5h2xxE28UHNfgoq/NJxW/LQ6A=
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 h1:M2KR3iBj7WpY3hP10IevfIB9MURr4O9mwVfJ+SjT3HA=
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0/go.mod h1:okpbKfVYf/BpejtfFTfhZqFP+sZ8rsHrP8Rr/jYPNRc=
git.frostfs.info/TrueCloudLab/tzhash v1.8.0 h1:UFMnUIk0Zh17m8rjGHJMqku2hCgaXDqjqZzS4gsb4UA=

View file

@ -252,6 +252,7 @@ const (
ShardFailureToMarkLockersAsGarbage = "failure to mark lockers as garbage"
ShardFailureToGetExpiredUnlockedObjects = "failure to get expired unlocked objects"
ShardCouldNotMarkObjectToDeleteInMetabase = "could not mark object to delete in metabase"
ShardCouldNotFindObject = "could not find object"
WritecacheWaitingForChannelsToFlush = "waiting for channels to flush"
WritecacheCantRemoveObjectFromWritecache = "can't remove object from write-cache"
BlobovniczatreeCouldNotGetObjectFromLevel = "could not get object from level"

View file

@ -11,6 +11,9 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/hrw"
"github.com/google/uuid"
@ -442,3 +445,46 @@ func (e *StorageEngine) deleteShards(ctx context.Context, ids []*shard.ID) ([]ha
func (s hashedShard) Hash() uint64 {
return s.hash

Need to take mtx here to iterate over shards.

Need to take mtx here to iterate over shards.

Fixed.

Fixed.
}
fyrchik marked this conversation as resolved Outdated

We do not actually know slice capacity, and most likely there is 0 or 1 shard.
Preallocation is not needed here, just var info []shard.Info.

We do not actually know slice capacity, and _most likely_ there is 0 or 1 shard. Preallocation is not needed here, just `var info []shard.Info`.

Fixed

Fixed
func (e *StorageEngine) ListShardsForObject(ctx context.Context, obj oid.Address) ([]shard.Info, error) {
var err error
var info []shard.Info
prm := shard.ExistsPrm{
Address: obj,
dstepanov-yadro marked this conversation as resolved Outdated

Engine.Exists has some error handling:

func (e *StorageEngine) exists(ctx context.Context, shPrm shard.ExistsPrm) (bool, bool, error) {


Is this error checking not performed here intentionally?

`Engine.Exists` has some error handling: https://git.frostfs.info/TrueCloudLab/frostfs-node/src/commit/5d79abe523b0254fe0484220d6d2c57a172090e1/pkg/local_object_storage/engine/exists.go#L16 Is this error checking not performed here intentionally?

It was intentional as I assumed we should stop on every error. I didn't consider that ObjectNotFound could be an error.
Added error checks.

It was intentional as I assumed we should stop on every error. I didn't consider that `ObjectNotFound` could be an error. Added error checks.
}
var siErr *objectSDK.SplitInfoError
var ecErr *objectSDK.ECInfoError
a-savchuk marked this conversation as resolved Outdated

Let's iterate over sorted shards

Let's iterate over _sorted_ shards

Why? It is required to find all shards store object, but not the first shard stores object.

Why? It is required to find all shards store object, but not the first shard stores object.

Ok, nevermind

Ok, nevermind
e.iterateOverUnsortedShards(func(hs hashedShard) (stop bool) {
res, exErr := hs.Exists(ctx, prm)
if exErr != nil {
if client.IsErrObjectAlreadyRemoved(exErr) {
fyrchik marked this conversation as resolved Outdated

Imagine an object is removed by the user, but it was a mistake, so we want quickly locate this object, which is still physically stored. Not saying it is will be used, but let's discuss.

Imagine an object is removed by the user, but it was a mistake, so we want quickly locate this object, which is still physically stored. Not saying it is will be used, but let's discuss.

Why would a user need to quickly locate this object?

Why would a user need to quickly locate this object?

control service is not for a user, it is for administrator and service engineers.
I may want to save and quarantine these objects.
But, anyway, fetching part is currently missing, so we may discuss this separately.

`control` service is not for a user, it is for administrator and service engineers. I may want to save and quarantine these objects. But, anyway, fetching part is currently missing, so we may discuss this separately.
err = new(apistatus.ObjectAlreadyRemoved)
return true
}
a-savchuk marked this conversation as resolved Outdated

ECInfoError too

`ECInfoError` too

Added check for ECInfoError

Added check for `ECInfoError`
a-savchuk marked this conversation as resolved Outdated

Move these variables definitions outside shard iterating

Move these variables definitions outside shard iterating

Fixed

Fixed
a-savchuk marked this conversation as resolved Outdated

Let's merge similar check together and make less ifs

Let's merge similar check together and make less `if`s

Ok, fixed

Ok, fixed
// Check if error is either SplitInfoError or ECInfoError.
// True means the object is virtual.
fyrchik marked this conversation as resolved Outdated

I would argue that these errors are, actually, useful: this means that queried object is virtual and this shard stores a part of it (a chunk of it). IMO this command should somewhat resemble object nodes, but instead of object we find shards on a single node.
WDYT? @dstepanov-yadro

I would argue that these errors are, actually, useful: this means that queried object is virtual and this shard stores a part of it (a chunk of it). IMO this command should somewhat resemble `object nodes`, but instead of object we find shards on a single node. WDYT? @dstepanov-yadro

Good point, didn't consider it.

Good point, didn't consider it.
if errors.As(exErr, &siErr) || errors.As(exErr, &ecErr) {
info = append(info, hs.DumpInfo())
return false
}
if shard.IsErrObjectExpired(exErr) {
err = exErr
return true
}
if !client.IsErrObjectNotFound(exErr) {
e.reportShardError(ctx, hs, "could not check existence of object in shard", exErr, zap.Stringer("address", prm.Address))
}
return false
}
if res.Exists() {
info = append(info, hs.DumpInfo())
a-savchuk marked this conversation as resolved Outdated

I think Exists should not be called if an error was returned. Now this happens if you get an unexpected error you then report. You can either add return false after error reporting or use else or do something else

I think `Exists` should not be called if an error was returned. Now this happens if you get an unexpected error you then report. You can either add return `false` after error reporting or use `else` or do something else

Fair point, added return false at the end of error check.

Fair point, added `return false` at the end of error check.
}
return false
})
return info, err
}

View file

@ -32,6 +32,7 @@ const (
rpcListTargetsLocalOverrides = "ListTargetsLocalOverrides"
rpcDetachShards = "DetachShards"
rpcStartShardRebuild = "StartShardRebuild"
rpcListShardsForObject = "ListShardsForObject"
)
// HealthCheck executes ControlService.HealthCheck RPC.
@ -364,3 +365,22 @@ func StartShardRebuild(cli *client.Client, req *StartShardRebuildRequest, opts .
return wResp.message, nil
}
// ListShardsForObject executes ControlService.ListShardsForObject RPC.
func ListShardsForObject(
cli *client.Client,
req *ListShardsForObjectRequest,
opts ...client.CallOption,
) (*ListShardsForObjectResponse, error) {
wResp := newResponseWrapper[ListShardsForObjectResponse]()
wReq := &requestWrapper{
m: req,
}
err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceName, rpcListShardsForObject), wReq, wResp, opts...)
if err != nil {
return nil, err
}
return wResp.message, nil
}

View file

@ -0,0 +1,66 @@
package control
import (
"context"
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/server/ctrlmessage"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func (s *Server) ListShardsForObject(ctx context.Context, req *control.ListShardsForObjectRequest) (*control.ListShardsForObjectResponse, error) {
err := s.isValidRequest(req)
if err != nil {
return nil, status.Error(codes.PermissionDenied, err.Error())
}
var obj oid.ID
err = obj.DecodeString(req.GetBody().GetObjectId())
if err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
var cnr cid.ID
err = cnr.DecodeString(req.GetBody().GetContainerId())
if err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
resp := new(control.ListShardsForObjectResponse)
body := new(control.ListShardsForObjectResponse_Body)
resp.SetBody(body)
var objAddr oid.Address
objAddr.SetContainer(cnr)
objAddr.SetObject(obj)
info, err := s.s.ListShardsForObject(ctx, objAddr)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
if len(info) == 0 {
return nil, status.Error(codes.NotFound, logs.ShardCouldNotFindObject)

codes.NotFound?

`codes.NotFound`?

Fixed

Fixed
}
body.SetShard_ID(shardInfoToProto(info))
// Sign the response
if err := ctrlmessage.Sign(s.key, resp); err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return resp, nil
}
func shardInfoToProto(infos []shard.Info) [][]byte {
shardInfos := make([][]byte, 0, len(infos))
for _, info := range infos {
shardInfos = append(shardInfos, *info.ID)
}
return shardInfos
}

View file

@ -89,6 +89,9 @@ service ControlService {
// StartShardRebuild starts shard rebuild process.
rpc StartShardRebuild(StartShardRebuildRequest) returns (StartShardRebuildResponse);
// ListShardsForObject returns shard info where object is stored.
fyrchik marked this conversation as resolved Outdated

I think GetShardByObjectID is a bad naming -- ObjectID is not some persistent identifier of a shard, it is something that a shard can store.
May be sth like ListShardsForObject?

I think `GetShardByObjectID` is a bad naming -- `ObjectID` is not some persistent identifier of a shard, it is something that a shard can store. May be sth like `ListShardsForObject`?

Thanks, renamed GetShardByObjectID to ListShardsForObject.

Thanks, renamed `GetShardByObjectID` to `ListShardsForObject`.
rpc ListShardsForObject(ListShardsForObjectRequest) returns (ListShardsForObjectResponse);
}
// Health check request.
@ -729,3 +732,23 @@ message StartShardRebuildResponse {
Signature signature = 2;
}
message ListShardsForObjectRequest {
message Body {
string object_id = 1;
fyrchik marked this conversation as resolved Outdated

object_id and container_id would be better (in accordance with other fields like chain_id or shard_id)

`object_id` and `container_id` would be better (in accordance with other fields like `chain_id` or `shard_id`)

Fixed

Fixed
a-savchuk marked this conversation as resolved Outdated

How about using bytes instead of string? An ID as bytes takes 32 bytes, the same ID as a string takes about 44 bytes. Also I see we already use bytes in control IR service.

What do you think?

How about using bytes instead of string? An ID as bytes takes 32 bytes, the same ID as a string takes about 44 bytes. Also I see we already use bytes in control IR service. What do you think?

I think it is an an error that we use bytes for shardID. String is more human readable and control API is not so performance critical to save 12 bytes:)

I think it is an an error that we use `bytes` for shardID. String is more human readable and control API is not so performance critical to save 12 bytes:)
string container_id = 2;
}
Body body = 1;
Signature signature = 2;
}
message ListShardsForObjectResponse {
message Body {
// List of the node's shards storing object.
repeated bytes shard_ID = 1;

I don't really mind having ShardInfo here, but still think that shard ID is the only thing we need (may be another struct with a single field in it, to allow extension).
ShardInfo is primarily to be fetched with shards list command.
These will be changed independently.

I don't _really_ mind having `ShardInfo` here, but still think that shard ID is the only thing we need (may be another struct with a single field in it, to allow extension). `ShardInfo` is primarily to be fetched with `shards list` command. These will be changed independently.

If you find at least one approval from other team member, fine by me.

If you find at least one approval from other team member, fine by me.

Made ListShardsForObject return only shard ids.
Full shard info can be listed with --full flag.

Made `ListShardsForObject` return only `shard ids`. Full shard info can be listed with `--full` flag.
}
Body body = 1;
Signature signature = 2;
}

View file

@ -17303,3 +17303,727 @@ func (x *StartShardRebuildResponse) UnmarshalEasyJSON(in *jlexer.Lexer) {
in.Consumed()
}
}
type ListShardsForObjectRequest_Body struct {
ObjectId string `json:"objectId"`
ContainerId string `json:"containerId"`
}
var (
_ encoding.ProtoMarshaler = (*ListShardsForObjectRequest_Body)(nil)
_ encoding.ProtoUnmarshaler = (*ListShardsForObjectRequest_Body)(nil)
_ json.Marshaler = (*ListShardsForObjectRequest_Body)(nil)
_ json.Unmarshaler = (*ListShardsForObjectRequest_Body)(nil)
)
// StableSize returns the size of x in protobuf format.
//
// Structures with the same field values have the same binary size.
func (x *ListShardsForObjectRequest_Body) StableSize() (size int) {
if x == nil {
return 0
}
size += proto.StringSize(1, x.ObjectId)
size += proto.StringSize(2, x.ContainerId)
return size
}
// MarshalProtobuf implements the encoding.ProtoMarshaler interface.
func (x *ListShardsForObjectRequest_Body) MarshalProtobuf(dst []byte) []byte {
m := pool.MarshalerPool.Get()
defer pool.MarshalerPool.Put(m)
x.EmitProtobuf(m.MessageMarshaler())
dst = m.Marshal(dst)
return dst
}
func (x *ListShardsForObjectRequest_Body) EmitProtobuf(mm *easyproto.MessageMarshaler) {
if x == nil {
return
}
if len(x.ObjectId) != 0 {
mm.AppendString(1, x.ObjectId)
}
if len(x.ContainerId) != 0 {
mm.AppendString(2, x.ContainerId)
}
}
// UnmarshalProtobuf implements the encoding.ProtoUnmarshaler interface.
func (x *ListShardsForObjectRequest_Body) UnmarshalProtobuf(src []byte) (err error) {
var fc easyproto.FieldContext
for len(src) > 0 {
src, err = fc.NextField(src)
if err != nil {
return fmt.Errorf("cannot read next field in %s", "ListShardsForObjectRequest_Body")
}
switch fc.FieldNum {
case 1: // ObjectId
data, ok := fc.String()
if !ok {
return fmt.Errorf("cannot unmarshal field %s", "ObjectId")
}
x.ObjectId = data
case 2: // ContainerId
data, ok := fc.String()
if !ok {
return fmt.Errorf("cannot unmarshal field %s", "ContainerId")
}
x.ContainerId = data
}
}
return nil
}
func (x *ListShardsForObjectRequest_Body) GetObjectId() string {
if x != nil {
return x.ObjectId
}
return ""
}
func (x *ListShardsForObjectRequest_Body) SetObjectId(v string) {
x.ObjectId = v
}
func (x *ListShardsForObjectRequest_Body) GetContainerId() string {
if x != nil {
return x.ContainerId
}
return ""
}
func (x *ListShardsForObjectRequest_Body) SetContainerId(v string) {
x.ContainerId = v
}
// MarshalJSON implements the json.Marshaler interface.
func (x *ListShardsForObjectRequest_Body) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
x.MarshalEasyJSON(&w)
return w.Buffer.BuildBytes(), w.Error
}
func (x *ListShardsForObjectRequest_Body) MarshalEasyJSON(out *jwriter.Writer) {
if x == nil {
out.RawString("null")
return
}
first := true
out.RawByte('{')
{
if !first {
out.RawByte(',')
} else {
first = false
}
const prefix string = "\"objectId\":"
out.RawString(prefix)
out.String(x.ObjectId)
}
{
if !first {
out.RawByte(',')
} else {
first = false
}
const prefix string = "\"containerId\":"
out.RawString(prefix)
out.String(x.ContainerId)
}
out.RawByte('}')
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (x *ListShardsForObjectRequest_Body) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
x.UnmarshalEasyJSON(&r)
return r.Error()
}
func (x *ListShardsForObjectRequest_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeFieldName(false)
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "objectId":
{
var f string
f = in.String()
x.ObjectId = f
}
case "containerId":
{
var f string
f = in.String()
x.ContainerId = f
}
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
type ListShardsForObjectRequest struct {
Body *ListShardsForObjectRequest_Body `json:"body"`
Signature *Signature `json:"signature"`
}
var (
_ encoding.ProtoMarshaler = (*ListShardsForObjectRequest)(nil)
_ encoding.ProtoUnmarshaler = (*ListShardsForObjectRequest)(nil)
_ json.Marshaler = (*ListShardsForObjectRequest)(nil)
_ json.Unmarshaler = (*ListShardsForObjectRequest)(nil)
)
// StableSize returns the size of x in protobuf format.
//
// Structures with the same field values have the same binary size.
func (x *ListShardsForObjectRequest) StableSize() (size int) {
if x == nil {
return 0
}
size += proto.NestedStructureSize(1, x.Body)
size += proto.NestedStructureSize(2, x.Signature)
return size
}
// ReadSignedData fills buf with signed data of x.
// If buffer length is less than x.SignedDataSize(), new buffer is allocated.
//
// Returns any error encountered which did not allow writing the data completely.
// Otherwise, returns the buffer in which the data is written.
//
// Structures with the same field values have the same signed data.
func (x *ListShardsForObjectRequest) SignedDataSize() int {
return x.GetBody().StableSize()
}
// SignedDataSize returns size of the request signed data in bytes.
//
// Structures with the same field values have the same signed data size.
func (x *ListShardsForObjectRequest) ReadSignedData(buf []byte) ([]byte, error) {
return x.GetBody().MarshalProtobuf(buf), nil
}
// MarshalProtobuf implements the encoding.ProtoMarshaler interface.
func (x *ListShardsForObjectRequest) MarshalProtobuf(dst []byte) []byte {
m := pool.MarshalerPool.Get()
defer pool.MarshalerPool.Put(m)
x.EmitProtobuf(m.MessageMarshaler())
dst = m.Marshal(dst)
return dst
}
func (x *ListShardsForObjectRequest) EmitProtobuf(mm *easyproto.MessageMarshaler) {
if x == nil {
return
}
if x.Body != nil {
x.Body.EmitProtobuf(mm.AppendMessage(1))
}
if x.Signature != nil {
x.Signature.EmitProtobuf(mm.AppendMessage(2))
}
}
// UnmarshalProtobuf implements the encoding.ProtoUnmarshaler interface.
func (x *ListShardsForObjectRequest) UnmarshalProtobuf(src []byte) (err error) {
var fc easyproto.FieldContext
for len(src) > 0 {
src, err = fc.NextField(src)
if err != nil {
return fmt.Errorf("cannot read next field in %s", "ListShardsForObjectRequest")
}
switch fc.FieldNum {
case 1: // Body
data, ok := fc.MessageData()
if !ok {
return fmt.Errorf("cannot unmarshal field %s", "Body")
}
x.Body = new(ListShardsForObjectRequest_Body)
if err := x.Body.UnmarshalProtobuf(data); err != nil {
return fmt.Errorf("unmarshal: %w", err)
}
case 2: // Signature
data, ok := fc.MessageData()
if !ok {
return fmt.Errorf("cannot unmarshal field %s", "Signature")
}
x.Signature = new(Signature)
if err := x.Signature.UnmarshalProtobuf(data); err != nil {
return fmt.Errorf("unmarshal: %w", err)
}
}
}
return nil
}
func (x *ListShardsForObjectRequest) GetBody() *ListShardsForObjectRequest_Body {
if x != nil {
return x.Body
}
return nil
}
func (x *ListShardsForObjectRequest) SetBody(v *ListShardsForObjectRequest_Body) {
x.Body = v
}
func (x *ListShardsForObjectRequest) GetSignature() *Signature {
if x != nil {
return x.Signature
}
return nil
}
func (x *ListShardsForObjectRequest) SetSignature(v *Signature) {
x.Signature = v
}
// MarshalJSON implements the json.Marshaler interface.
func (x *ListShardsForObjectRequest) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
x.MarshalEasyJSON(&w)
return w.Buffer.BuildBytes(), w.Error
}
func (x *ListShardsForObjectRequest) MarshalEasyJSON(out *jwriter.Writer) {
if x == nil {
out.RawString("null")
return
}
first := true
out.RawByte('{')
{
if !first {
out.RawByte(',')
} else {
first = false
}
const prefix string = "\"body\":"
out.RawString(prefix)
x.Body.MarshalEasyJSON(out)
}
{
if !first {
out.RawByte(',')
} else {
first = false
}
const prefix string = "\"signature\":"
out.RawString(prefix)
x.Signature.MarshalEasyJSON(out)
}
out.RawByte('}')
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (x *ListShardsForObjectRequest) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
x.UnmarshalEasyJSON(&r)
return r.Error()
}
func (x *ListShardsForObjectRequest) UnmarshalEasyJSON(in *jlexer.Lexer) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeFieldName(false)
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "body":
{
var f *ListShardsForObjectRequest_Body
f = new(ListShardsForObjectRequest_Body)
f.UnmarshalEasyJSON(in)
x.Body = f
}
case "signature":
{
var f *Signature
f = new(Signature)
f.UnmarshalEasyJSON(in)
x.Signature = f
}
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
type ListShardsForObjectResponse_Body struct {
Shard_ID [][]byte `json:"shardID"`
}
var (
_ encoding.ProtoMarshaler = (*ListShardsForObjectResponse_Body)(nil)
_ encoding.ProtoUnmarshaler = (*ListShardsForObjectResponse_Body)(nil)
_ json.Marshaler = (*ListShardsForObjectResponse_Body)(nil)
_ json.Unmarshaler = (*ListShardsForObjectResponse_Body)(nil)
)
// StableSize returns the size of x in protobuf format.
//
// Structures with the same field values have the same binary size.
func (x *ListShardsForObjectResponse_Body) StableSize() (size int) {
if x == nil {
return 0
}
size += proto.RepeatedBytesSize(1, x.Shard_ID)
return size
}
// MarshalProtobuf implements the encoding.ProtoMarshaler interface.
func (x *ListShardsForObjectResponse_Body) MarshalProtobuf(dst []byte) []byte {
m := pool.MarshalerPool.Get()
defer pool.MarshalerPool.Put(m)
x.EmitProtobuf(m.MessageMarshaler())
dst = m.Marshal(dst)
return dst
}
func (x *ListShardsForObjectResponse_Body) EmitProtobuf(mm *easyproto.MessageMarshaler) {
if x == nil {
return
}
for j := range x.Shard_ID {
mm.AppendBytes(1, x.Shard_ID[j])
}
}
// UnmarshalProtobuf implements the encoding.ProtoUnmarshaler interface.
func (x *ListShardsForObjectResponse_Body) UnmarshalProtobuf(src []byte) (err error) {
var fc easyproto.FieldContext
for len(src) > 0 {
src, err = fc.NextField(src)
if err != nil {
return fmt.Errorf("cannot read next field in %s", "ListShardsForObjectResponse_Body")
}
switch fc.FieldNum {
case 1: // Shard_ID
data, ok := fc.Bytes()
if !ok {
return fmt.Errorf("cannot unmarshal field %s", "Shard_ID")
}
x.Shard_ID = append(x.Shard_ID, data)
}
}
return nil
}
func (x *ListShardsForObjectResponse_Body) GetShard_ID() [][]byte {
if x != nil {
return x.Shard_ID
}
return nil
}
func (x *ListShardsForObjectResponse_Body) SetShard_ID(v [][]byte) {
x.Shard_ID = v
}
// MarshalJSON implements the json.Marshaler interface.
func (x *ListShardsForObjectResponse_Body) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
x.MarshalEasyJSON(&w)
return w.Buffer.BuildBytes(), w.Error
}
func (x *ListShardsForObjectResponse_Body) MarshalEasyJSON(out *jwriter.Writer) {
if x == nil {
out.RawString("null")
return
}
first := true
out.RawByte('{')
{
if !first {
out.RawByte(',')
} else {
first = false
}
const prefix string = "\"shardID\":"
out.RawString(prefix)
out.RawByte('[')
for i := range x.Shard_ID {
if i != 0 {
out.RawByte(',')
}
if x.Shard_ID[i] != nil {
out.Base64Bytes(x.Shard_ID[i])
} else {
out.String("")
}
}
out.RawByte(']')
}
out.RawByte('}')
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (x *ListShardsForObjectResponse_Body) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
x.UnmarshalEasyJSON(&r)
return r.Error()
}
func (x *ListShardsForObjectResponse_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeFieldName(false)
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "shardID":
{
var f []byte
var list [][]byte
in.Delim('[')
for !in.IsDelim(']') {
{
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
list = append(list, f)
in.WantComma()
}
x.Shard_ID = list
in.Delim(']')
}
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
type ListShardsForObjectResponse struct {
Body *ListShardsForObjectResponse_Body `json:"body"`
Signature *Signature `json:"signature"`
}
var (
_ encoding.ProtoMarshaler = (*ListShardsForObjectResponse)(nil)
_ encoding.ProtoUnmarshaler = (*ListShardsForObjectResponse)(nil)
_ json.Marshaler = (*ListShardsForObjectResponse)(nil)
_ json.Unmarshaler = (*ListShardsForObjectResponse)(nil)
)
// StableSize returns the size of x in protobuf format.
//
// Structures with the same field values have the same binary size.
func (x *ListShardsForObjectResponse) StableSize() (size int) {
if x == nil {
return 0
}
size += proto.NestedStructureSize(1, x.Body)
size += proto.NestedStructureSize(2, x.Signature)
return size
}
// ReadSignedData fills buf with signed data of x.
// If buffer length is less than x.SignedDataSize(), new buffer is allocated.
//
// Returns any error encountered which did not allow writing the data completely.
// Otherwise, returns the buffer in which the data is written.
//
// Structures with the same field values have the same signed data.
func (x *ListShardsForObjectResponse) SignedDataSize() int {
return x.GetBody().StableSize()
}
// SignedDataSize returns size of the request signed data in bytes.
//
// Structures with the same field values have the same signed data size.
func (x *ListShardsForObjectResponse) ReadSignedData(buf []byte) ([]byte, error) {
return x.GetBody().MarshalProtobuf(buf), nil
}
// MarshalProtobuf implements the encoding.ProtoMarshaler interface.
func (x *ListShardsForObjectResponse) MarshalProtobuf(dst []byte) []byte {
m := pool.MarshalerPool.Get()
defer pool.MarshalerPool.Put(m)
x.EmitProtobuf(m.MessageMarshaler())
dst = m.Marshal(dst)
return dst
}
func (x *ListShardsForObjectResponse) EmitProtobuf(mm *easyproto.MessageMarshaler) {
if x == nil {
return
}
if x.Body != nil {
x.Body.EmitProtobuf(mm.AppendMessage(1))
}
if x.Signature != nil {
x.Signature.EmitProtobuf(mm.AppendMessage(2))
}
}
// UnmarshalProtobuf implements the encoding.ProtoUnmarshaler interface.
func (x *ListShardsForObjectResponse) UnmarshalProtobuf(src []byte) (err error) {
var fc easyproto.FieldContext
for len(src) > 0 {
src, err = fc.NextField(src)
if err != nil {
return fmt.Errorf("cannot read next field in %s", "ListShardsForObjectResponse")
}
switch fc.FieldNum {
case 1: // Body
data, ok := fc.MessageData()
if !ok {
return fmt.Errorf("cannot unmarshal field %s", "Body")
}
x.Body = new(ListShardsForObjectResponse_Body)
if err := x.Body.UnmarshalProtobuf(data); err != nil {
return fmt.Errorf("unmarshal: %w", err)
}
case 2: // Signature
data, ok := fc.MessageData()
if !ok {
return fmt.Errorf("cannot unmarshal field %s", "Signature")
}
x.Signature = new(Signature)
if err := x.Signature.UnmarshalProtobuf(data); err != nil {
return fmt.Errorf("unmarshal: %w", err)
}
}
}
return nil
}
func (x *ListShardsForObjectResponse) GetBody() *ListShardsForObjectResponse_Body {
if x != nil {
return x.Body
}
return nil
}
func (x *ListShardsForObjectResponse) SetBody(v *ListShardsForObjectResponse_Body) {
x.Body = v
}
func (x *ListShardsForObjectResponse) GetSignature() *Signature {
if x != nil {
return x.Signature
}
return nil
}
func (x *ListShardsForObjectResponse) SetSignature(v *Signature) {
x.Signature = v
}
// MarshalJSON implements the json.Marshaler interface.
func (x *ListShardsForObjectResponse) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
x.MarshalEasyJSON(&w)
return w.Buffer.BuildBytes(), w.Error
}
func (x *ListShardsForObjectResponse) MarshalEasyJSON(out *jwriter.Writer) {
if x == nil {
out.RawString("null")
return
}
first := true
out.RawByte('{')
{
if !first {
out.RawByte(',')
} else {
first = false
}
const prefix string = "\"body\":"
out.RawString(prefix)
x.Body.MarshalEasyJSON(out)
}
{
if !first {
out.RawByte(',')
} else {
first = false
}
const prefix string = "\"signature\":"
out.RawString(prefix)
x.Signature.MarshalEasyJSON(out)
}
out.RawByte('}')
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (x *ListShardsForObjectResponse) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
x.UnmarshalEasyJSON(&r)
return r.Error()
}
func (x *ListShardsForObjectResponse) UnmarshalEasyJSON(in *jlexer.Lexer) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeFieldName(false)
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "body":
{
var f *ListShardsForObjectResponse_Body
f = new(ListShardsForObjectResponse_Body)
f.UnmarshalEasyJSON(in)
x.Body = f
}
case "signature":
{
var f *Signature
f = new(Signature)
f.UnmarshalEasyJSON(in)
x.Signature = f
}
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}

View file

@ -41,6 +41,7 @@ const (
ControlService_SealWriteCache_FullMethodName = "/control.ControlService/SealWriteCache"
ControlService_DetachShards_FullMethodName = "/control.ControlService/DetachShards"
ControlService_StartShardRebuild_FullMethodName = "/control.ControlService/StartShardRebuild"
ControlService_ListShardsForObject_FullMethodName = "/control.ControlService/ListShardsForObject"
)
// ControlServiceClient is the client API for ControlService service.
@ -95,6 +96,8 @@ type ControlServiceClient interface {
DetachShards(ctx context.Context, in *DetachShardsRequest, opts ...grpc.CallOption) (*DetachShardsResponse, error)
// StartShardRebuild starts shard rebuild process.
StartShardRebuild(ctx context.Context, in *StartShardRebuildRequest, opts ...grpc.CallOption) (*StartShardRebuildResponse, error)
// ListShardsForObject returns shard info where object is stored.
ListShardsForObject(ctx context.Context, in *ListShardsForObjectRequest, opts ...grpc.CallOption) (*ListShardsForObjectResponse, error)
}
type controlServiceClient struct {
@ -303,6 +306,15 @@ func (c *controlServiceClient) StartShardRebuild(ctx context.Context, in *StartS
return out, nil
}
func (c *controlServiceClient) ListShardsForObject(ctx context.Context, in *ListShardsForObjectRequest, opts ...grpc.CallOption) (*ListShardsForObjectResponse, error) {
out := new(ListShardsForObjectResponse)
err := c.cc.Invoke(ctx, ControlService_ListShardsForObject_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ControlServiceServer is the server API for ControlService service.
// All implementations should embed UnimplementedControlServiceServer
// for forward compatibility
@ -355,6 +367,8 @@ type ControlServiceServer interface {
DetachShards(context.Context, *DetachShardsRequest) (*DetachShardsResponse, error)
// StartShardRebuild starts shard rebuild process.
StartShardRebuild(context.Context, *StartShardRebuildRequest) (*StartShardRebuildResponse, error)
// ListShardsForObject returns shard info where object is stored.
ListShardsForObject(context.Context, *ListShardsForObjectRequest) (*ListShardsForObjectResponse, error)
}
// UnimplementedControlServiceServer should be embedded to have forward compatible implementations.
@ -427,6 +441,9 @@ func (UnimplementedControlServiceServer) DetachShards(context.Context, *DetachSh
func (UnimplementedControlServiceServer) StartShardRebuild(context.Context, *StartShardRebuildRequest) (*StartShardRebuildResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method StartShardRebuild not implemented")
}
func (UnimplementedControlServiceServer) ListShardsForObject(context.Context, *ListShardsForObjectRequest) (*ListShardsForObjectResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListShardsForObject not implemented")
}
// UnsafeControlServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ControlServiceServer will
@ -835,6 +852,24 @@ func _ControlService_StartShardRebuild_Handler(srv interface{}, ctx context.Cont
return interceptor(ctx, in, info, handler)
}
func _ControlService_ListShardsForObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListShardsForObjectRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControlServiceServer).ListShardsForObject(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ControlService_ListShardsForObject_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControlServiceServer).ListShardsForObject(ctx, req.(*ListShardsForObjectRequest))
}
return interceptor(ctx, in, info, handler)
}
// ControlService_ServiceDesc is the grpc.ServiceDesc for ControlService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@ -930,6 +965,10 @@ var ControlService_ServiceDesc = grpc.ServiceDesc{
MethodName: "StartShardRebuild",
Handler: _ControlService_StartShardRebuild_Handler,
},
{
MethodName: "ListShardsForObject",
Handler: _ControlService_ListShardsForObject_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "pkg/services/control/service.proto",