Skip to content

Commit 9aba95a

Browse files
authored
feat: Add support for CLUSTER SHARDS command (redis#2507)
* feat: Adding support for CLUSTER SHARDS command Co-authored-by: Anuragkillswitch <70265851+Anuragkillswitch@users.noreply.github.com>
1 parent 2cdd5ea commit 9aba95a

File tree

3 files changed

+188
-0
lines changed

3 files changed

+188
-0
lines changed

cluster_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,37 @@ var _ = Describe("ClusterClient", func() {
677677
Expect(assertSlotsEqual(res, wanted)).NotTo(HaveOccurred())
678678
})
679679

680+
It("should CLUSTER SHARDS", func() {
681+
res, err := client.ClusterShards(ctx).Result()
682+
Expect(err).NotTo(HaveOccurred())
683+
Expect(res).NotTo(BeEmpty())
684+
685+
// Iterate over the ClusterShard results and validate the fields.
686+
for _, shard := range res {
687+
Expect(shard.Slots).NotTo(BeEmpty())
688+
for _, slotRange := range shard.Slots {
689+
Expect(slotRange.Start).To(BeNumerically(">=", 0))
690+
Expect(slotRange.End).To(BeNumerically(">=", slotRange.Start))
691+
}
692+
693+
Expect(shard.Nodes).NotTo(BeEmpty())
694+
for _, node := range shard.Nodes {
695+
Expect(node.ID).NotTo(BeEmpty())
696+
Expect(node.Endpoint).NotTo(BeEmpty())
697+
Expect(node.IP).NotTo(BeEmpty())
698+
Expect(node.Port).To(BeNumerically(">", 0))
699+
700+
validRoles := []string{"master", "slave", "replica"}
701+
Expect(validRoles).To(ContainElement(node.Role))
702+
703+
Expect(node.ReplicationOffset).To(BeNumerically(">=", 0))
704+
705+
validHealthStatuses := []string{"online", "failed", "loading"}
706+
Expect(validHealthStatuses).To(ContainElement(node.Health))
707+
}
708+
}
709+
})
710+
680711
It("should CLUSTER LINKS", func() {
681712
res, err := client.ClusterLinks(ctx).Result()
682713
Expect(err).NotTo(HaveOccurred())

command.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4335,3 +4335,153 @@ func (cmd *ClusterLinksCmd) readReply(rd *proto.Reader) error {
43354335

43364336
return nil
43374337
}
4338+
4339+
// ------------------------------------------------------------------------------------------------------------------
4340+
4341+
type SlotRange struct {
4342+
Start int64
4343+
End int64
4344+
}
4345+
4346+
type Node struct {
4347+
ID string
4348+
Endpoint string
4349+
IP string
4350+
Hostname string
4351+
Port int64
4352+
TLSPort int64
4353+
Role string
4354+
ReplicationOffset int64
4355+
Health string
4356+
}
4357+
4358+
type ClusterShard struct {
4359+
Slots []SlotRange
4360+
Nodes []Node
4361+
}
4362+
4363+
type ClusterShardsCmd struct {
4364+
baseCmd
4365+
4366+
val []ClusterShard
4367+
}
4368+
4369+
var _ Cmder = (*ClusterShardsCmd)(nil)
4370+
4371+
func NewClusterShardsCmd(ctx context.Context, args ...interface{}) *ClusterShardsCmd {
4372+
return &ClusterShardsCmd{
4373+
baseCmd: baseCmd{
4374+
ctx: ctx,
4375+
args: args,
4376+
},
4377+
}
4378+
}
4379+
4380+
func (cmd *ClusterShardsCmd) SetVal(val []ClusterShard) {
4381+
cmd.val = val
4382+
}
4383+
4384+
func (cmd *ClusterShardsCmd) Val() []ClusterShard {
4385+
return cmd.val
4386+
}
4387+
4388+
func (cmd *ClusterShardsCmd) Result() ([]ClusterShard, error) {
4389+
return cmd.Val(), cmd.Err()
4390+
}
4391+
4392+
func (cmd *ClusterShardsCmd) String() string {
4393+
return cmdString(cmd, cmd.val)
4394+
}
4395+
4396+
func (cmd *ClusterShardsCmd) readReply(rd *proto.Reader) error {
4397+
n, err := rd.ReadArrayLen()
4398+
if err != nil {
4399+
return err
4400+
}
4401+
cmd.val = make([]ClusterShard, n)
4402+
4403+
for i := 0; i < n; i++ {
4404+
m, err := rd.ReadMapLen()
4405+
if err != nil {
4406+
return err
4407+
}
4408+
4409+
for j := 0; j < m; j++ {
4410+
key, err := rd.ReadString()
4411+
if err != nil {
4412+
return err
4413+
}
4414+
4415+
switch key {
4416+
case "slots":
4417+
l, err := rd.ReadArrayLen()
4418+
if err != nil {
4419+
return err
4420+
}
4421+
for k := 0; k < l; k += 2 {
4422+
start, err := rd.ReadInt()
4423+
if err != nil {
4424+
return err
4425+
}
4426+
4427+
end, err := rd.ReadInt()
4428+
if err != nil {
4429+
return err
4430+
}
4431+
4432+
cmd.val[i].Slots = append(cmd.val[i].Slots, SlotRange{Start: start, End: end})
4433+
}
4434+
case "nodes":
4435+
nodesLen, err := rd.ReadArrayLen()
4436+
if err != nil {
4437+
return err
4438+
}
4439+
cmd.val[i].Nodes = make([]Node, nodesLen)
4440+
for k := 0; k < nodesLen; k++ {
4441+
nodeMapLen, err := rd.ReadMapLen()
4442+
if err != nil {
4443+
return err
4444+
}
4445+
4446+
for l := 0; l < nodeMapLen; l++ {
4447+
nodeKey, err := rd.ReadString()
4448+
if err != nil {
4449+
return err
4450+
}
4451+
4452+
switch nodeKey {
4453+
case "id":
4454+
cmd.val[i].Nodes[k].ID, err = rd.ReadString()
4455+
case "endpoint":
4456+
cmd.val[i].Nodes[k].Endpoint, err = rd.ReadString()
4457+
case "ip":
4458+
cmd.val[i].Nodes[k].IP, err = rd.ReadString()
4459+
case "hostname":
4460+
cmd.val[i].Nodes[k].Hostname, err = rd.ReadString()
4461+
case "port":
4462+
cmd.val[i].Nodes[k].Port, err = rd.ReadInt()
4463+
case "tls-port":
4464+
cmd.val[i].Nodes[k].TLSPort, err = rd.ReadInt()
4465+
case "role":
4466+
cmd.val[i].Nodes[k].Role, err = rd.ReadString()
4467+
case "replication-offset":
4468+
cmd.val[i].Nodes[k].ReplicationOffset, err = rd.ReadInt()
4469+
case "health":
4470+
cmd.val[i].Nodes[k].Health, err = rd.ReadString()
4471+
default:
4472+
return fmt.Errorf("redis: unexpected key %q in CLUSTER SHARDS node reply", nodeKey)
4473+
}
4474+
4475+
if err != nil {
4476+
return err
4477+
}
4478+
}
4479+
}
4480+
default:
4481+
return fmt.Errorf("redis: unexpected key %q in CLUSTER SHARDS reply", key)
4482+
}
4483+
}
4484+
}
4485+
4486+
return nil
4487+
}

commands.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ type Cmdable interface {
422422
PubSubShardNumSub(ctx context.Context, channels ...string) *MapStringIntCmd
423423

424424
ClusterSlots(ctx context.Context) *ClusterSlotsCmd
425+
ClusterShards(ctx context.Context) *ClusterShardsCmd
425426
ClusterLinks(ctx context.Context) *ClusterLinksCmd
426427
ClusterNodes(ctx context.Context) *StringCmd
427428
ClusterMeet(ctx context.Context, host, port string) *StatusCmd
@@ -3506,6 +3507,12 @@ func (c cmdable) ClusterSlots(ctx context.Context) *ClusterSlotsCmd {
35063507
return cmd
35073508
}
35083509

3510+
func (c cmdable) ClusterShards(ctx context.Context) *ClusterShardsCmd {
3511+
cmd := NewClusterShardsCmd(ctx, "cluster", "shards")
3512+
_ = c(ctx, cmd)
3513+
return cmd
3514+
}
3515+
35093516
func (c cmdable) ClusterLinks(ctx context.Context) *ClusterLinksCmd {
35103517
cmd := NewClusterLinksCmd(ctx, "cluster", "links")
35113518
_ = c(ctx, cmd)

0 commit comments

Comments
 (0)