Compare commits

...

8 Commits
master ... v7

Author SHA1 Message Date
Vladimir Mihailenco 83ac308add chore: update 2021-12-04 17:35:52 +02:00
Wesley Powell 03a86486ea
Backport wrapMultiExec() cmds copy bug fix from v8 (#1823) 2021-07-16 15:41:17 +08:00
Vladimir Mihailenco 5fec34b901 Fix build 2020-06-29 15:16:05 +03:00
Vladimir Mihailenco 9c3799ce57 Use different ports 2020-06-05 10:37:55 +03:00
Vladimir Mihailenco 6a48fe0243 Fix build 2020-06-05 10:34:40 +03:00
Vladimir Mihailenco d83d4514bd Fix Command parsing 2020-06-05 10:33:39 +03:00
Vladimir Mihailenco 1244ca3ec9 Use Redis stable for testing 2020-06-05 10:33:25 +03:00
y_uuki 23f6dd4187 Support additional flags for ACL in CommandsInfo 2020-06-05 10:33:06 +03:00
12 changed files with 89 additions and 28 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
*.rdb
testdata/*/
.idea/

View File

@ -5,7 +5,6 @@ services:
- redis-server
go:
- 1.11.x
- 1.12.x
- 1.13.x
- tip

View File

@ -14,7 +14,7 @@ bench: testdeps
testdata/redis:
mkdir -p $@
wget -qO- http://download.redis.io/releases/redis-5.0.7.tar.gz | tar xvz --strip-components=1 -C $@
wget -qO- http://download.redis.io/redis-stable.tar.gz | tar xvz --strip-components=1 -C $@
testdata/redis/src/redis-server: testdata/redis
cd $< && make all

View File

@ -1,8 +1,13 @@
<p align="center">
<a href="https://uptrace.dev/?utm_source=gh-redis&utm_campaign=gh-redis-banner1">
<img src="https://raw.githubusercontent.com/uptrace/roadmap/master/banner1.png" alt="All-in-one tool to optimize performance and monitor errors & logs">
</a>
</p>
# Redis client for Golang
[![Build Status](https://travis-ci.org/go-redis/redis.png?branch=master)](https://travis-ci.org/go-redis/redis)
[![GoDoc](https://godoc.org/github.com/go-redis/redis?status.svg)](https://godoc.org/github.com/go-redis/redis)
[![Airbrake](https://img.shields.io/badge/kudos-airbrake.io-orange.svg)](https://airbrake.io)
Supports:
@ -29,20 +34,20 @@ Examples: https://godoc.org/github.com/go-redis/redis#pkg-examples.
go-redis requires a Go version with [Modules](https://github.com/golang/go/wiki/Modules) support and uses import versioning. So please make sure to initialize a Go module before installing go-redis:
``` shell
```shell
go mod init github.com/my/repo
go get github.com/go-redis/redis/v7
```
Import:
``` go
```go
import "github.com/go-redis/redis/v7"
```
## Quickstart
``` go
```go
func ExampleNewClient() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
@ -93,7 +98,7 @@ Please go through [examples](https://godoc.org/github.com/go-redis/redis#pkg-exa
Some corner cases:
``` go
```go
// SET key value EX 10 NX
set, err := client.SetNX("key", "value", 10*time.Second).Result()

View File

@ -1885,6 +1885,7 @@ type CommandInfo struct {
Name string
Arity int8
Flags []string
ACLFlags []string
FirstKeyPos int8
LastKeyPos int8
StepCount int8
@ -1934,8 +1935,14 @@ func (cmd *CommandsInfoCmd) readReply(rd *proto.Reader) error {
}
func commandInfoParser(rd *proto.Reader, n int64) (interface{}, error) {
if n != 6 {
return nil, fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 6", n)
const numArgRedis5 = 6
const numArgRedis6 = 7
switch n {
case numArgRedis5, numArgRedis6:
// continue
default:
return nil, fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 7", n)
}
var cmd CommandInfo
@ -1995,6 +2002,28 @@ func commandInfoParser(rd *proto.Reader, n int64) (interface{}, error) {
}
}
if n == numArgRedis5 {
return &cmd, nil
}
_, err = rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
cmd.ACLFlags = make([]string, n)
for i := 0; i < len(cmd.ACLFlags); i++ {
switch s, err := rd.ReadString(); {
case err == Nil:
cmd.ACLFlags[i] = ""
case err != nil:
return nil, err
default:
cmd.ACLFlags[i] = s
}
}
return nil, nil
})
if err != nil {
return nil, err
}
return &cmd, nil
}

View File

@ -33,9 +33,10 @@ var _ = Describe("Commands", func() {
pipe.Auth("")
return nil
})
Expect(err).To(MatchError("ERR Client sent AUTH, but no password is set"))
Expect(cmds[0].Err()).To(MatchError("ERR Client sent AUTH, but no password is set"))
Expect(cmds[1].Err()).To(MatchError("ERR Client sent AUTH, but no password is set"))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("ERR AUTH"))
Expect(cmds[0].Err().Error()).To(ContainSubstring("ERR AUTH"))
Expect(cmds[1].Err().Error()).To(ContainSubstring("ERR AUTH"))
stats := client.PoolStats()
Expect(stats.Hits).To(Equal(uint32(1)))

View File

@ -9,7 +9,9 @@ var _ = Describe("newClusterState", func() {
var state *clusterState
createClusterState := func(slots []ClusterSlot) *clusterState {
nodes := newClusterNodes(&ClusterOptions{})
opt := &ClusterOptions{}
opt.init()
nodes := newClusterNodes(opt)
state, err := newClusterState(nodes, slots, "10.10.10.10:1234")
Expect(err).NotTo(HaveOccurred())
return state

View File

@ -32,10 +32,10 @@ const (
const (
sentinelName = "mymaster"
sentinelMasterPort = "8123"
sentinelSlave1Port = "8124"
sentinelSlave2Port = "8125"
sentinelPort = "8126"
sentinelMasterPort = "9123"
sentinelSlave1Port = "9124"
sentinelSlave2Port = "9125"
sentinelPort = "9126"
)
var (

View File

@ -1,6 +1,8 @@
package redis_test
import (
"strconv"
"github.com/go-redis/redis/v7"
. "github.com/onsi/ginkgo"
@ -67,6 +69,21 @@ var _ = Describe("pipelining", func() {
Expect(err).NotTo(HaveOccurred())
Expect(cmds).To(HaveLen(1))
})
It("handles large pipelines", func() {
for callCount := 1; callCount < 16; callCount++ {
for i := 1; i <= callCount; i++ {
pipe.SetNX(strconv.Itoa(i)+"_key", strconv.Itoa(i)+"_value", 0)
}
cmds, err := pipe.Exec()
Expect(err).NotTo(HaveOccurred())
Expect(cmds).To(HaveLen(callCount))
for _, cmd := range cmds {
Expect(cmd).To(BeAssignableToTypeOf(&redis.BoolCmd{}))
}
}
})
}
Describe("Pipeline", func() {

View File

@ -261,13 +261,17 @@ var _ = Describe("races", func() {
Expect(n).To(Equal(int64(N)))
})
It("should BLPop", func() {
PIt("should BLPop", func() {
var received uint32
wg := performAsync(C, func(id int) {
for {
v, err := client.BLPop(3*time.Second, "list").Result()
if err != nil {
break
if err == redis.Nil {
break
}
Expect(err).NotTo(HaveOccurred())
}
Expect(v).To(Equal([]string{"list", "hello"}))
atomic.AddUint32(&received, 1)
@ -282,7 +286,7 @@ var _ = Describe("races", func() {
})
wg.Wait()
Expect(received).To(Equal(uint32(C * N)))
Expect(atomic.LoadUint32(&received)).To(Equal(uint32(C * N)))
})
It("should WithContext", func() {

View File

@ -473,11 +473,11 @@ func wrapMultiExec(cmds []Cmder) []Cmder {
if len(cmds) == 0 {
panic("not reached")
}
cmds = append(cmds, make([]Cmder, 2)...)
copy(cmds[1:], cmds[:len(cmds)-2])
cmds[0] = NewStatusCmd("multi")
cmds[len(cmds)-1] = NewSliceCmd("exec")
return cmds
cmdCopy := make([]Cmder, len(cmds)+2)
cmdCopy[0] = NewStatusCmd("multi")
copy(cmdCopy[1:], cmds)
cmdCopy[len(cmdCopy)-1] = NewSliceCmd("exec")
return cmdCopy
}
func txPipelineReadQueued(rd *proto.Reader, statusCmd *StatusCmd, cmds []Cmder) error {

View File

@ -180,7 +180,8 @@ var _ = Describe("Redis Ring", func() {
ring = redis.NewRing(opts)
err := ring.Ping().Err()
Expect(err).To(MatchError("ERR Client sent AUTH, but no password is set"))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("ERR AUTH"))
})
It("can be initialized with a passwords map, one for each shard", func() {
@ -192,7 +193,8 @@ var _ = Describe("Redis Ring", func() {
ring = redis.NewRing(opts)
err := ring.Ping().Err()
Expect(err).To(MatchError("ERR Client sent AUTH, but no password is set"))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("ERR AUTH"))
})
})
@ -206,7 +208,8 @@ var _ = Describe("Redis Ring", func() {
ring = redis.NewRing(opts)
err := ring.Ping().Err()
Expect(err).To(MatchError("ERR Client sent AUTH, but no password is set"))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("ERR AUTH"))
})
})