forked from mirror/redis
Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
Vladimir Mihailenco | 83ac308add | |
Wesley Powell | 03a86486ea | |
Vladimir Mihailenco | 5fec34b901 | |
Vladimir Mihailenco | 9c3799ce57 | |
Vladimir Mihailenco | 6a48fe0243 | |
Vladimir Mihailenco | d83d4514bd | |
Vladimir Mihailenco | 1244ca3ec9 | |
y_uuki | 23f6dd4187 |
|
@ -1,2 +1,3 @@
|
|||
*.rdb
|
||||
testdata/*/
|
||||
.idea/
|
||||
|
|
|
@ -5,7 +5,6 @@ services:
|
|||
- redis-server
|
||||
|
||||
go:
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- tip
|
||||
|
|
2
Makefile
2
Makefile
|
@ -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
|
||||
|
|
15
README.md
15
README.md
|
@ -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()
|
||||
|
||||
|
|
33
command.go
33
command.go
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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() {
|
||||
|
|
10
race_test.go
10
race_test.go
|
@ -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() {
|
||||
|
|
10
redis.go
10
redis.go
|
@ -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 {
|
||||
|
|
|
@ -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"))
|
||||
})
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in New Issue