Unexport as much as possible.

This commit is contained in:
Vladimir Mihailenco 2013-09-29 11:06:49 +03:00
parent 7f11168689
commit 773f2a03f3
12 changed files with 764 additions and 861 deletions

333
v2/command.go Normal file
View File

@ -0,0 +1,333 @@
package redis
import (
"fmt"
"strconv"
"strings"
"time"
)
type Cmder interface {
args() []string
parseReply(reader) (interface{}, error)
setErr(error)
setVal(interface{})
writeTimeout() *time.Duration
readTimeout() *time.Duration
Err() error
}
//------------------------------------------------------------------------------
type baseCmd struct {
_args []string
val interface{}
err error
_writeTimeout, _readTimeout *time.Duration
}
func newBaseCmd(args ...string) *baseCmd {
return &baseCmd{
_args: args,
}
}
func (cmd *baseCmd) String() string {
args := strings.Join(cmd._args, " ")
if cmd.err != nil {
return args + ": " + cmd.err.Error()
} else if cmd.val != nil {
return args + ": " + fmt.Sprint(cmd.val)
}
return args
}
func (cmd *baseCmd) Err() error {
if cmd.err != nil {
return cmd.err
}
if cmd.val == nil {
return errValNotSet
}
return nil
}
func (cmd *baseCmd) args() []string {
return cmd._args
}
func (cmd *baseCmd) setErr(err error) {
if err == nil {
panic("non-nil value expected")
}
cmd.err = err
}
func (cmd *baseCmd) setVal(val interface{}) {
if val == nil {
panic("non-nil value expected")
}
cmd.val = val
}
func (cmd *baseCmd) parseReply(rd reader) (interface{}, error) {
return parseReply(rd)
}
func (cmd *baseCmd) readTimeout() *time.Duration {
return cmd._readTimeout
}
func (cmd *baseCmd) setReadTimeout(d time.Duration) {
cmd._readTimeout = &d
}
func (cmd *baseCmd) writeTimeout() *time.Duration {
return cmd._writeTimeout
}
func (cmd *baseCmd) setWriteTimeout(d time.Duration) {
cmd._writeTimeout = &d
}
//------------------------------------------------------------------------------
type Cmd struct {
*baseCmd
}
func NewCmd(args ...string) *Cmd {
return &Cmd{
baseCmd: newBaseCmd(args...),
}
}
func (cmd *Cmd) Val() interface{} {
return cmd.val
}
//------------------------------------------------------------------------------
type StatusCmd struct {
*baseCmd
}
func NewStatusCmd(args ...string) *StatusCmd {
return &StatusCmd{
baseCmd: newBaseCmd(args...),
}
}
func (cmd *StatusCmd) Val() string {
if cmd.val == nil {
return ""
}
return cmd.val.(string)
}
//------------------------------------------------------------------------------
type IntCmd struct {
*baseCmd
}
func NewIntCmd(args ...string) *IntCmd {
return &IntCmd{
baseCmd: newBaseCmd(args...),
}
}
func (cmd *IntCmd) Val() int64 {
if cmd.val == nil {
return 0
}
return cmd.val.(int64)
}
//------------------------------------------------------------------------------
type BoolCmd struct {
*baseCmd
}
func NewBoolCmd(args ...string) *BoolCmd {
return &BoolCmd{
baseCmd: newBaseCmd(args...),
}
}
func (cmd *BoolCmd) parseReply(rd reader) (interface{}, error) {
v, err := parseReply(rd)
if err != nil {
return nil, err
}
return v.(int64) == 1, nil
}
func (cmd *BoolCmd) Val() bool {
if cmd.val == nil {
return false
}
return cmd.val.(bool)
}
//------------------------------------------------------------------------------
type StringCmd struct {
*baseCmd
}
func NewStringCmd(args ...string) *StringCmd {
return &StringCmd{
baseCmd: newBaseCmd(args...),
}
}
func (cmd *StringCmd) Val() string {
if cmd.val == nil {
return ""
}
return cmd.val.(string)
}
//------------------------------------------------------------------------------
type FloatCmd struct {
*baseCmd
}
func NewFloatCmd(args ...string) *FloatCmd {
return &FloatCmd{
baseCmd: newBaseCmd(args...),
}
}
func (cmd *FloatCmd) parseReply(rd reader) (interface{}, error) {
v, err := parseReply(rd)
if err != nil {
return nil, err
}
return strconv.ParseFloat(v.(string), 64)
}
func (cmd *FloatCmd) Val() float64 {
if cmd.val == nil {
return 0
}
return cmd.val.(float64)
}
//------------------------------------------------------------------------------
type SliceCmd struct {
*baseCmd
}
func NewSliceCmd(args ...string) *SliceCmd {
return &SliceCmd{
baseCmd: newBaseCmd(args...),
}
}
func (cmd *SliceCmd) Val() []interface{} {
if cmd.val == nil {
return nil
}
return cmd.val.([]interface{})
}
//------------------------------------------------------------------------------
type StringSliceCmd struct {
*baseCmd
}
func NewStringSliceCmd(args ...string) *StringSliceCmd {
return &StringSliceCmd{
baseCmd: newBaseCmd(args...),
}
}
func (cmd *StringSliceCmd) parseReply(rd reader) (interface{}, error) {
return parseStringSliceReply(rd)
}
func (cmd *StringSliceCmd) Val() []string {
if cmd.val == nil {
return nil
}
return cmd.val.([]string)
}
//------------------------------------------------------------------------------
type BoolSliceCmd struct {
*baseCmd
}
func NewBoolSliceCmd(args ...string) *BoolSliceCmd {
return &BoolSliceCmd{
baseCmd: newBaseCmd(args...),
}
}
func (cmd *BoolSliceCmd) parseReply(rd reader) (interface{}, error) {
return parseBoolSliceReply(rd)
}
func (cmd *BoolSliceCmd) Val() []bool {
if cmd.val == nil {
return nil
}
return cmd.val.([]bool)
}
//------------------------------------------------------------------------------
type StringStringMapCmd struct {
*baseCmd
}
func NewStringStringMapCmd(args ...string) *StringStringMapCmd {
return &StringStringMapCmd{
baseCmd: newBaseCmd(args...),
}
}
func (cmd *StringStringMapCmd) parseReply(rd reader) (interface{}, error) {
return parseStringStringMapReply(rd)
}
func (cmd *StringStringMapCmd) Val() map[string]string {
if cmd.val == nil {
return nil
}
return cmd.val.(map[string]string)
}
//------------------------------------------------------------------------------
type StringFloatMapCmd struct {
*baseCmd
}
func NewStringFloatMapCmd(args ...string) *StringFloatMapCmd {
return &StringFloatMapCmd{
baseCmd: newBaseCmd(args...),
}
}
func (cmd *StringFloatMapCmd) parseReply(rd reader) (interface{}, error) {
return parseStringFloatMapReply(rd)
}
func (cmd *StringFloatMapCmd) Val() map[string]float64 {
if cmd.val == nil {
return nil
}
return cmd.val.(map[string]float64)
}

File diff suppressed because it is too large Load Diff

View File

@ -53,13 +53,13 @@ func ExamplePipeline() {
})
defer client.Close()
var set *redis.StatusReq
var get *redis.StringReq
reqs, err := client.Pipelined(func(c *redis.Pipeline) {
var set *redis.StatusCmd
var get *redis.StringCmd
cmds, err := client.Pipelined(func(c *redis.Pipeline) {
set = c.Set("key1", "hello1")
get = c.Get("key2")
})
fmt.Println(err, reqs)
fmt.Println(err, cmds)
fmt.Println(set)
fmt.Println(get)
// Output: (nil) [SET key1 hello1: OK GET key2: (nil)]
@ -67,7 +67,7 @@ func ExamplePipeline() {
// GET key2: (nil)
}
func incr(tx *redis.Multi) ([]redis.Req, error) {
func incr(tx *redis.Multi) ([]redis.Cmder, error) {
get := tx.Get("key")
if err := get.Err(); err != nil && err != redis.Nil {
return nil, err
@ -75,14 +75,14 @@ func incr(tx *redis.Multi) ([]redis.Req, error) {
val, _ := strconv.ParseInt(get.Val(), 10, 64)
reqs, err := tx.Exec(func() {
cmds, err := tx.Exec(func() {
tx.Set("key", strconv.FormatInt(val+1, 10))
})
// Transaction failed. Repeat.
if err == redis.Nil {
return incr(tx)
}
return reqs, err
return cmds, err
}
func ExampleTransaction() {
@ -99,8 +99,8 @@ func ExampleTransaction() {
watch := tx.Watch("key")
_ = watch.Err()
reqs, err := incr(tx)
fmt.Println(err, reqs)
cmds, err := incr(tx)
fmt.Println(err, cmds)
// Output: <nil> [SET key 1: OK]
}
@ -130,10 +130,10 @@ func ExamplePubSub() {
// &{mychannel hello} <nil>
}
func Get(client *redis.Client, key string) *redis.StringReq {
req := redis.NewStringReq("GET", key)
client.Process(req)
return req
func Get(client *redis.Client, key string) *redis.StringCmd {
cmd := redis.NewStringCmd("GET", key)
client.Process(cmd)
return cmd
}
func ExampleCustomCommand() {

View File

@ -28,38 +28,38 @@ func (c *Multi) Close() error {
return c.Client.Close()
}
func (c *Multi) Watch(keys ...string) *StatusReq {
func (c *Multi) Watch(keys ...string) *StatusCmd {
args := append([]string{"WATCH"}, keys...)
req := NewStatusReq(args...)
c.Process(req)
return req
cmd := NewStatusCmd(args...)
c.Process(cmd)
return cmd
}
func (c *Multi) Unwatch(keys ...string) *StatusReq {
func (c *Multi) Unwatch(keys ...string) *StatusCmd {
args := append([]string{"UNWATCH"}, keys...)
req := NewStatusReq(args...)
c.Process(req)
return req
cmd := NewStatusCmd(args...)
c.Process(cmd)
return cmd
}
func (c *Multi) Discard() error {
if c.reqs == nil {
if c.cmds == nil {
return errDiscard
}
c.reqs = c.reqs[:1]
c.cmds = c.cmds[:1]
return nil
}
func (c *Multi) Exec(f func()) ([]Req, error) {
c.reqs = []Req{NewStatusReq("MULTI")}
func (c *Multi) Exec(f func()) ([]Cmder, error) {
c.cmds = []Cmder{NewStatusCmd("MULTI")}
f()
c.reqs = append(c.reqs, NewIfaceSliceReq("EXEC"))
c.cmds = append(c.cmds, NewSliceCmd("EXEC"))
reqs := c.reqs
c.reqs = nil
cmds := c.cmds
c.cmds = nil
if len(reqs) == 2 {
return []Req{}, nil
if len(cmds) == 2 {
return []Cmder{}, nil
}
cn, err := c.conn()
@ -68,30 +68,30 @@ func (c *Multi) Exec(f func()) ([]Req, error) {
}
// Synchronize writes and reads to the connection using mutex.
err = c.execReqs(reqs, cn)
err = c.execCmds(cmds, cn)
if err != nil {
c.removeConn(cn)
return nil, err
}
c.putConn(cn)
return reqs[1 : len(reqs)-1], nil
return cmds[1 : len(cmds)-1], nil
}
func (c *Multi) execReqs(reqs []Req, cn *conn) error {
err := c.writeReq(cn, reqs...)
func (c *Multi) execCmds(cmds []Cmder, cn *conn) error {
err := c.writeCmd(cn, cmds...)
if err != nil {
return err
}
statusReq := NewStatusReq()
statusCmd := NewStatusCmd()
// Omit last request (EXEC).
reqsLen := len(reqs) - 1
// Omit last cmduest (EXEC).
cmdsLen := len(cmds) - 1
// Parse queued replies.
for i := 0; i < reqsLen; i++ {
_, err = statusReq.ParseReply(cn.Rd)
for i := 0; i < cmdsLen; i++ {
_, err = statusCmd.parseReply(cn.Rd)
if err != nil {
return err
}
@ -110,14 +110,14 @@ func (c *Multi) execReqs(reqs []Req, cn *conn) error {
}
// Parse replies.
// Loop starts from 1 to omit first request (MULTI).
for i := 1; i < reqsLen; i++ {
req := reqs[i]
val, err := req.ParseReply(cn.Rd)
// Loop starts from 1 to omit first cmduest (MULTI).
for i := 1; i < cmdsLen; i++ {
cmd := cmds[i]
val, err := cmd.parseReply(cn.Rd)
if err != nil {
req.SetErr(err)
cmd.setErr(err)
} else {
req.SetVal(val)
cmd.setVal(val)
}
}

View File

@ -29,7 +29,7 @@ var (
//------------------------------------------------------------------------------
func appendReq(buf []byte, args []string) []byte {
func appendCmd(buf []byte, args []string) []byte {
buf = append(buf, '*')
buf = strconv.AppendUint(buf, uint64(len(args)), 10)
buf = append(buf, '\r', '\n')

View File

@ -12,18 +12,18 @@ func (c *Client) Pipeline() *Pipeline {
opt: c.opt,
connPool: c.connPool,
reqs: make([]Req, 0),
cmds: make([]Cmder, 0),
},
},
}
}
func (c *Client) Pipelined(f func(*Pipeline)) ([]Req, error) {
func (c *Client) Pipelined(f func(*Pipeline)) ([]Cmder, error) {
pc := c.Pipeline()
f(pc)
reqs, err := pc.Exec()
cmds, err := pc.Exec()
pc.Close()
return reqs, err
return cmds, err
}
func (c *Pipeline) Close() error {
@ -31,55 +31,55 @@ func (c *Pipeline) Close() error {
}
func (c *Pipeline) Discard() error {
c.reqs = c.reqs[:0]
c.cmds = c.cmds[:0]
return nil
}
// Always returns list of commands and error of the first failed
// command if any.
func (c *Pipeline) Exec() ([]Req, error) {
reqs := c.reqs
c.reqs = make([]Req, 0)
func (c *Pipeline) Exec() ([]Cmder, error) {
cmds := c.cmds
c.cmds = make([]Cmder, 0)
if len(reqs) == 0 {
return []Req{}, nil
if len(cmds) == 0 {
return []Cmder{}, nil
}
cn, err := c.conn()
if err != nil {
return reqs, err
return cmds, err
}
if err := c.execReqs(reqs, cn); err != nil {
if err := c.execCmds(cmds, cn); err != nil {
c.freeConn(cn, err)
return reqs, err
return cmds, err
}
c.putConn(cn)
return reqs, nil
return cmds, nil
}
func (c *Pipeline) execReqs(reqs []Req, cn *conn) error {
err := c.writeReq(cn, reqs...)
func (c *Pipeline) execCmds(cmds []Cmder, cn *conn) error {
err := c.writeCmd(cn, cmds...)
if err != nil {
for _, req := range reqs {
req.SetErr(err)
for _, cmd := range cmds {
cmd.setErr(err)
}
return err
}
var firstReqErr error
for _, req := range reqs {
val, err := req.ParseReply(cn.Rd)
var firstCmdErr error
for _, cmd := range cmds {
val, err := cmd.parseReply(cn.Rd)
if err != nil {
req.SetErr(err)
if err != nil {
firstReqErr = err
cmd.setErr(err)
if firstCmdErr == nil {
firstCmdErr = err
}
} else {
req.SetVal(val)
cmd.setVal(val)
}
}
return firstReqErr
return firstCmdErr
}

View File

@ -18,8 +18,8 @@ func (c *Client) PubSub() *PubSub {
}
}
func (c *Client) Publish(channel, message string) *IntReq {
req := NewIntReq("PUBLISH", channel, message)
func (c *Client) Publish(channel, message string) *IntCmd {
req := NewIntCmd("PUBLISH", channel, message)
c.Process(req)
return req
}
@ -52,7 +52,7 @@ func (c *PubSub) ReceiveTimeout(timeout time.Duration) (interface{}, error) {
}
cn.readTimeout = timeout
replyIface, err := NewIfaceSliceReq().ParseReply(cn.Rd)
replyIface, err := NewSliceCmd().parseReply(cn.Rd)
if err != nil {
return nil, err
}
@ -91,8 +91,8 @@ func (c *PubSub) subscribe(cmd string, channels ...string) error {
}
args := append([]string{cmd}, channels...)
req := NewIfaceSliceReq(args...)
return c.writeReq(cn, req)
req := NewSliceCmd(args...)
return c.writeCmd(cn, req)
}
func (c *PubSub) Subscribe(channels ...string) error {
@ -110,8 +110,8 @@ func (c *PubSub) unsubscribe(cmd string, channels ...string) error {
}
args := append([]string{cmd}, channels...)
req := NewIfaceSliceReq(args...)
return c.writeReq(cn, req)
req := NewSliceCmd(args...)
return c.writeCmd(cn, req)
}
func (c *PubSub) Unsubscribe(channels ...string) error {

View File

@ -18,13 +18,13 @@ type baseClient struct {
opt *Options
reqs []Req
cmds []Cmder
}
func (c *baseClient) writeReq(cn *conn, reqs ...Req) error {
func (c *baseClient) writeCmd(cn *conn, cmds ...Cmder) error {
buf := make([]byte, 0, 1000)
for _, req := range reqs {
buf = appendReq(buf, req.Args())
for _, cmd := range cmds {
buf = appendCmd(buf, cmd.args())
}
_, err := cn.Write(buf)
@ -93,46 +93,46 @@ func (c *baseClient) putConn(cn *conn) {
}
}
func (c *baseClient) Process(req Req) {
if c.reqs == nil {
c.run(req)
func (c *baseClient) Process(cmd Cmder) {
if c.cmds == nil {
c.run(cmd)
} else {
c.reqs = append(c.reqs, req)
c.cmds = append(c.cmds, cmd)
}
}
func (c *baseClient) run(req Req) {
func (c *baseClient) run(cmd Cmder) {
cn, err := c.conn()
if err != nil {
req.SetErr(err)
cmd.setErr(err)
return
}
cn.writeTimeout = c.opt.WriteTimeout
if timeout := req.writeTimeout(); timeout != nil {
if timeout := cmd.writeTimeout(); timeout != nil {
cn.writeTimeout = *timeout
}
cn.readTimeout = c.opt.ReadTimeout
if timeout := req.readTimeout(); timeout != nil {
if timeout := cmd.readTimeout(); timeout != nil {
cn.readTimeout = *timeout
}
if err := c.writeReq(cn, req); err != nil {
if err := c.writeCmd(cn, cmd); err != nil {
c.removeConn(cn)
req.SetErr(err)
cmd.setErr(err)
return
}
val, err := req.ParseReply(cn.Rd)
val, err := cmd.parseReply(cn.Rd)
if err != nil {
c.freeConn(cn, err)
req.SetErr(err)
cmd.setErr(err)
return
}
c.putConn(cn)
req.SetVal(val)
cmd.setVal(val)
}
func (c *baseClient) Close() error {

View File

@ -155,9 +155,9 @@ func (t *RedisConnectorTest) TestUnixConnector(c *C) {
// c.Assert(err, IsNil)
// ping := pipeline.Ping()
// reqs, err := pipeline.RunQueued()
// cmds, err := pipeline.RunQueued()
// c.Assert(err, IsNil)
// c.Assert(reqs, HasLen, 1)
// c.Assert(cmds, HasLen, 1)
// c.Assert(ping.Err(), IsNil)
// c.Assert(ping.Val(), Equals, "PONG")
@ -181,12 +181,12 @@ func (t *RedisConnectorTest) TestUnixConnector(c *C) {
// multi, err := t.client.MultiClient()
// c.Assert(err, IsNil)
// var ping *redis.StatusReq
// reqs, err := multi.Exec(func() {
// var ping *redis.StatusCmd
// cmds, err := multi.Exec(func() {
// ping = multi.Ping()
// })
// c.Assert(err, IsNil)
// c.Assert(reqs, HasLen, 1)
// c.Assert(cmds, HasLen, 1)
// c.Assert(ping.Err(), IsNil)
// c.Assert(ping.Val(), Equals, "PONG")
@ -257,7 +257,7 @@ func (t *RedisTest) resetRedis(c *C) {
//------------------------------------------------------------------------------
func (t *RedisTest) TestReqStringMethod(c *C) {
func (t *RedisTest) TestCmdStringMethod(c *C) {
set := t.client.Set("foo", "bar")
c.Assert(set.String(), Equals, "SET foo bar: OK")
@ -265,7 +265,7 @@ func (t *RedisTest) TestReqStringMethod(c *C) {
c.Assert(get.String(), Equals, "GET foo: bar")
}
func (t *RedisTest) TestReqStringMethodError(c *C) {
func (t *RedisTest) TestCmdStringMethodError(c *C) {
get2 := t.client.Get("key_does_not_exists")
c.Assert(get2.String(), Equals, "GET key_does_not_exists: (nil)")
}
@ -2403,9 +2403,9 @@ func (t *RedisTest) TestPipeline(c *C) {
incr := pipeline.Incr("key3")
getNil := pipeline.Get("key4")
reqs, err := pipeline.Exec()
cmds, err := pipeline.Exec()
c.Assert(err, Equals, redis.Nil)
c.Assert(reqs, HasLen, 4)
c.Assert(cmds, HasLen, 4)
c.Assert(set.Err(), IsNil)
c.Assert(set.Val(), Equals, "OK")
@ -2428,18 +2428,18 @@ func (t *RedisTest) TestPipelineDiscardQueued(c *C) {
pipeline.Get("key")
pipeline.Discard()
reqs, err := pipeline.Exec()
cmds, err := pipeline.Exec()
c.Assert(err, IsNil)
c.Assert(reqs, HasLen, 0)
c.Assert(cmds, HasLen, 0)
}
func (t *RedisTest) TestPipelineFunc(c *C) {
var get *redis.StringReq
reqs, err := t.client.Pipelined(func(c *redis.Pipeline) {
var get *redis.StringCmd
cmds, err := t.client.Pipelined(func(c *redis.Pipeline) {
get = c.Get("foo")
})
c.Assert(err, Equals, redis.Nil)
c.Assert(reqs, HasLen, 1)
c.Assert(cmds, HasLen, 1)
c.Assert(get.Err(), Equals, redis.Nil)
c.Assert(get.Val(), Equals, "")
}
@ -2460,9 +2460,9 @@ func (t *RedisTest) TestPipelineRunQueuedOnEmptyQueue(c *C) {
c.Assert(pipeline.Close(), IsNil)
}()
reqs, err := pipeline.Exec()
cmds, err := pipeline.Exec()
c.Assert(err, IsNil)
c.Assert(reqs, HasLen, 0)
c.Assert(cmds, HasLen, 0)
}
func (t *RedisTest) TestPipelineIncrFromGoroutines(c *C) {
@ -2481,12 +2481,12 @@ func (t *RedisTest) TestPipelineIncrFromGoroutines(c *C) {
}
wg.Wait()
reqs, err := pipeline.Exec()
cmds, err := pipeline.Exec()
c.Assert(err, IsNil)
c.Assert(reqs, HasLen, 20000)
for _, req := range reqs {
if req.Err() != nil {
c.Errorf("got %v, expected nil", req.Err())
c.Assert(cmds, HasLen, 20000)
for _, cmd := range cmds {
if cmd.Err() != nil {
c.Errorf("got %v, expected nil", cmd.Err())
}
}
@ -2511,9 +2511,9 @@ func (t *RedisTest) TestPipelineEchoFromGoroutines(c *C) {
echo1 := pipeline.Echo(msg1)
echo2 := pipeline.Echo(msg2)
reqs, err := pipeline.Exec()
cmds, err := pipeline.Exec()
c.Assert(err, IsNil)
c.Assert(reqs, HasLen, 2)
c.Assert(cmds, HasLen, 2)
c.Assert(echo1.Err(), IsNil)
c.Assert(echo1.Val(), Equals, msg1)
@ -2536,15 +2536,15 @@ func (t *RedisTest) TestMultiExec(c *C) {
}()
var (
set *redis.StatusReq
get *redis.StringReq
set *redis.StatusCmd
get *redis.StringCmd
)
reqs, err := multi.Exec(func() {
cmds, err := multi.Exec(func() {
set = multi.Set("key", "hello")
get = multi.Get("key")
})
c.Assert(err, IsNil)
c.Assert(reqs, HasLen, 2)
c.Assert(cmds, HasLen, 2)
c.Assert(set.Err(), IsNil)
c.Assert(set.Val(), Equals, "OK")
@ -2559,13 +2559,13 @@ func (t *RedisTest) TestMultiExecDiscard(c *C) {
c.Assert(multi.Close(), IsNil)
}()
reqs, err := multi.Exec(func() {
cmds, err := multi.Exec(func() {
multi.Set("key1", "hello1")
multi.Discard()
multi.Set("key2", "hello2")
})
c.Assert(err, IsNil)
c.Assert(reqs, HasLen, 1)
c.Assert(cmds, HasLen, 1)
get := t.client.Get("key1")
c.Assert(get.Err(), Equals, redis.Nil)
@ -2582,9 +2582,9 @@ func (t *RedisTest) TestMultiExecEmpty(c *C) {
c.Assert(multi.Close(), IsNil)
}()
reqs, err := multi.Exec(func() {})
cmds, err := multi.Exec(func() {})
c.Assert(err, IsNil)
c.Assert(reqs, HasLen, 0)
c.Assert(cmds, HasLen, 0)
ping := multi.Ping()
c.Check(ping.Err(), IsNil)
@ -2597,9 +2597,9 @@ func (t *RedisTest) TestMultiExecOnEmptyQueue(c *C) {
c.Assert(multi.Close(), IsNil)
}()
reqs, err := multi.Exec(func() {})
cmds, err := multi.Exec(func() {})
c.Assert(err, IsNil)
c.Assert(reqs, HasLen, 0)
c.Assert(cmds, HasLen, 0)
}
func (t *RedisTest) TestMultiExecIncr(c *C) {
@ -2608,16 +2608,16 @@ func (t *RedisTest) TestMultiExecIncr(c *C) {
c.Assert(multi.Close(), IsNil)
}()
reqs, err := multi.Exec(func() {
cmds, err := multi.Exec(func() {
for i := int64(0); i < 20000; i++ {
multi.Incr("key")
}
})
c.Assert(err, IsNil)
c.Assert(reqs, HasLen, 20000)
for _, req := range reqs {
if req.Err() != nil {
c.Errorf("got %v, expected nil", req.Err())
c.Assert(cmds, HasLen, 20000)
for _, cmd := range cmds {
if cmd.Err() != nil {
c.Errorf("got %v, expected nil", cmd.Err())
}
}
@ -2626,7 +2626,7 @@ func (t *RedisTest) TestMultiExecIncr(c *C) {
c.Assert(get.Val(), Equals, "20000")
}
func (t *RedisTest) transactionalIncr(c *C) ([]redis.Req, error) {
func (t *RedisTest) transactionalIncr(c *C) ([]redis.Cmder, error) {
multi := t.client.Multi()
defer func() {
c.Assert(multi.Close(), IsNil)
@ -2643,13 +2643,13 @@ func (t *RedisTest) transactionalIncr(c *C) ([]redis.Req, error) {
v, err := strconv.ParseInt(get.Val(), 10, 64)
c.Assert(err, IsNil)
reqs, err := multi.Exec(func() {
cmds, err := multi.Exec(func() {
multi.Set("key", strconv.FormatInt(v+1, 10))
})
if err == redis.Nil {
return t.transactionalIncr(c)
}
return reqs, err
return cmds, err
}
func (t *RedisTest) TestWatchUnwatch(c *C) {
@ -2661,10 +2661,10 @@ func (t *RedisTest) TestWatchUnwatch(c *C) {
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
reqs, err := t.transactionalIncr(c)
c.Assert(reqs, HasLen, 1)
cmds, err := t.transactionalIncr(c)
c.Assert(cmds, HasLen, 1)
c.Assert(err, IsNil)
c.Assert(reqs[0].Err(), IsNil)
c.Assert(cmds[0].Err(), IsNil)
wg.Done()
}()
}

337
v2/req.go
View File

@ -1,337 +0,0 @@
package redis
import (
"fmt"
"strconv"
"strings"
"time"
)
type Req interface {
Args() []string
ParseReply(reader) (interface{}, error)
SetErr(error)
Err() error
SetVal(interface{})
IfaceVal() interface{}
writeTimeout() *time.Duration
readTimeout() *time.Duration
}
//------------------------------------------------------------------------------
type baseReq struct {
args []string
val interface{}
err error
_writeTimeout, _readTimeout *time.Duration
}
func newBaseReq(args ...string) *baseReq {
return &baseReq{
args: args,
}
}
func (r *baseReq) Args() []string {
return r.args
}
func (r *baseReq) SetErr(err error) {
if err == nil {
panic("non-nil value expected")
}
r.err = err
}
func (r *baseReq) Err() error {
if r.err != nil {
return r.err
}
if r.val == nil {
return errValNotSet
}
return nil
}
func (r *baseReq) SetVal(val interface{}) {
if val == nil {
panic("non-nil value expected")
}
r.val = val
}
func (r *baseReq) IfaceVal() interface{} {
return r.val
}
func (r *baseReq) ParseReply(rd reader) (interface{}, error) {
return parseReply(rd)
}
func (r *baseReq) String() string {
args := strings.Join(r.args, " ")
if r.err != nil {
return args + ": " + r.err.Error()
} else if r.val != nil {
return args + ": " + fmt.Sprint(r.val)
}
return args
}
func (r *baseReq) readTimeout() *time.Duration {
return r._readTimeout
}
func (r *baseReq) setReadTimeout(d time.Duration) {
r._readTimeout = &d
}
func (r *baseReq) writeTimeout() *time.Duration {
return r._writeTimeout
}
func (r *baseReq) setWriteTimeout(d time.Duration) {
r._writeTimeout = &d
}
//------------------------------------------------------------------------------
type IfaceReq struct {
*baseReq
}
func NewIfaceReq(args ...string) *IfaceReq {
return &IfaceReq{
baseReq: newBaseReq(args...),
}
}
func (r *IfaceReq) Val() interface{} {
return r.val
}
//------------------------------------------------------------------------------
type StatusReq struct {
*baseReq
}
func NewStatusReq(args ...string) *StatusReq {
return &StatusReq{
baseReq: newBaseReq(args...),
}
}
func (r *StatusReq) Val() string {
if r.val == nil {
return ""
}
return r.val.(string)
}
//------------------------------------------------------------------------------
type IntReq struct {
*baseReq
}
func NewIntReq(args ...string) *IntReq {
return &IntReq{
baseReq: newBaseReq(args...),
}
}
func (r *IntReq) Val() int64 {
if r.val == nil {
return 0
}
return r.val.(int64)
}
//------------------------------------------------------------------------------
type BoolReq struct {
*baseReq
}
func NewBoolReq(args ...string) *BoolReq {
return &BoolReq{
baseReq: newBaseReq(args...),
}
}
func (r *BoolReq) ParseReply(rd reader) (interface{}, error) {
v, err := parseReply(rd)
if err != nil {
return nil, err
}
return v.(int64) == 1, nil
}
func (r *BoolReq) Val() bool {
if r.val == nil {
return false
}
return r.val.(bool)
}
//------------------------------------------------------------------------------
type StringReq struct {
*baseReq
}
func NewStringReq(args ...string) *StringReq {
return &StringReq{
baseReq: newBaseReq(args...),
}
}
func (r *StringReq) Val() string {
if r.val == nil {
return ""
}
return r.val.(string)
}
//------------------------------------------------------------------------------
type FloatReq struct {
*baseReq
}
func NewFloatReq(args ...string) *FloatReq {
return &FloatReq{
baseReq: newBaseReq(args...),
}
}
func (r *FloatReq) ParseReply(rd reader) (interface{}, error) {
v, err := parseReply(rd)
if err != nil {
return nil, err
}
return strconv.ParseFloat(v.(string), 64)
}
func (r *FloatReq) Val() float64 {
if r.val == nil {
return 0
}
return r.val.(float64)
}
//------------------------------------------------------------------------------
type IfaceSliceReq struct {
*baseReq
}
func NewIfaceSliceReq(args ...string) *IfaceSliceReq {
return &IfaceSliceReq{
baseReq: newBaseReq(args...),
}
}
func (r *IfaceSliceReq) Val() []interface{} {
if r.val == nil {
return nil
}
return r.val.([]interface{})
}
//------------------------------------------------------------------------------
type StringSliceReq struct {
*baseReq
}
func NewStringSliceReq(args ...string) *StringSliceReq {
return &StringSliceReq{
baseReq: newBaseReq(args...),
}
}
func (r *StringSliceReq) ParseReply(rd reader) (interface{}, error) {
return parseStringSliceReply(rd)
}
func (r *StringSliceReq) Val() []string {
if r.val == nil {
return nil
}
return r.val.([]string)
}
//------------------------------------------------------------------------------
type BoolSliceReq struct {
*baseReq
}
func NewBoolSliceReq(args ...string) *BoolSliceReq {
return &BoolSliceReq{
baseReq: newBaseReq(args...),
}
}
func (r *BoolSliceReq) ParseReply(rd reader) (interface{}, error) {
return parseBoolSliceReply(rd)
}
func (r *BoolSliceReq) Val() []bool {
if r.val == nil {
return nil
}
return r.val.([]bool)
}
//------------------------------------------------------------------------------
type StringStringMapReq struct {
*baseReq
}
func NewStringStringMapReq(args ...string) *StringStringMapReq {
return &StringStringMapReq{
baseReq: newBaseReq(args...),
}
}
func (r *StringStringMapReq) ParseReply(rd reader) (interface{}, error) {
return parseStringStringMapReply(rd)
}
func (r *StringStringMapReq) Val() map[string]string {
if r.val == nil {
return nil
}
return r.val.(map[string]string)
}
//------------------------------------------------------------------------------
type StringFloatMapReq struct {
*baseReq
}
func NewStringFloatMapReq(args ...string) *StringFloatMapReq {
return &StringFloatMapReq{
baseReq: newBaseReq(args...),
}
}
func (r *StringFloatMapReq) ParseReply(rd reader) (interface{}, error) {
return parseStringFloatMapReply(rd)
}
func (r *StringFloatMapReq) Val() map[string]float64 {
if r.val == nil {
return nil
}
return r.val.(map[string]float64)
}

View File

@ -1,93 +0,0 @@
package redis_test
import (
"github.com/vmihailenco/bufio"
. "launchpad.net/gocheck"
"github.com/vmihailenco/redis"
)
//------------------------------------------------------------------------------
type LineReader struct {
line []byte
}
func NewLineReader(line []byte) *LineReader {
return &LineReader{line: line}
}
func (r *LineReader) Read(buf []byte) (int, error) {
return copy(buf, r.line), nil
}
//------------------------------------------------------------------------------
type RequestTest struct{}
var _ = Suite(&RequestTest{})
//------------------------------------------------------------------------------
func (t *RequestTest) SetUpTest(c *C) {}
func (t *RequestTest) TearDownTest(c *C) {}
//------------------------------------------------------------------------------
func (t *RequestTest) benchmarkReq(c *C, reqString string, req redis.Req, checker Checker, expected interface{}) {
c.StopTimer()
lineReader := NewLineReader([]byte(reqString))
rd := bufio.NewReaderSize(lineReader, 1024)
for i := 0; i < 10; i++ {
vIface, err := req.ParseReply(rd)
c.Check(err, IsNil)
c.Check(vIface, checker, expected)
req.SetVal(vIface)
}
c.StartTimer()
for i := 0; i < c.N; i++ {
v, _ := req.ParseReply(rd)
req.SetVal(v)
}
}
func (t *RequestTest) BenchmarkStatusReq(c *C) {
t.benchmarkReq(c, "+OK\r\n", redis.NewStatusReq(), Equals, "OK")
}
func (t *RequestTest) BenchmarkIntReq(c *C) {
t.benchmarkReq(c, ":1\r\n", redis.NewIntReq(), Equals, int64(1))
}
func (t *RequestTest) BenchmarkStringReq(c *C) {
t.benchmarkReq(c, "$5\r\nhello\r\n", redis.NewStringReq(), Equals, "hello")
}
func (t *RequestTest) BenchmarkFloatReq(c *C) {
t.benchmarkReq(c, "$5\r\n1.111\r\n", redis.NewFloatReq(), Equals, 1.111)
}
func (t *RequestTest) BenchmarkStringSliceReq(c *C) {
t.benchmarkReq(
c,
"*2\r\n$5\r\nhello\r\n$5\r\nhello\r\n",
redis.NewStringSliceReq(),
DeepEquals,
[]string{"hello", "hello"},
)
}
func (t *RequestTest) BenchmarkIfaceSliceReq(c *C) {
t.benchmarkReq(
c,
"*2\r\n$5\r\nhello\r\n$5\r\nhello\r\n",
redis.NewIfaceSliceReq(),
DeepEquals,
[]interface{}{"hello", "hello"},
)
}

View File

@ -20,23 +20,23 @@ func NewScript(src string) *Script {
}
}
func (s *Script) Load(c *Client) *StringReq {
func (s *Script) Load(c *Client) *StringCmd {
return c.ScriptLoad(s.src)
}
func (s *Script) Exists(c *Client) *BoolSliceReq {
func (s *Script) Exists(c *Client) *BoolSliceCmd {
return c.ScriptExists(s.src)
}
func (s *Script) Eval(c *Client, keys []string, args []string) *IfaceReq {
func (s *Script) Eval(c *Client, keys []string, args []string) *Cmd {
return c.Eval(s.src, keys, args)
}
func (s *Script) EvalSha(c *Client, keys []string, args []string) *IfaceReq {
func (s *Script) EvalSha(c *Client, keys []string, args []string) *Cmd {
return c.EvalSha(s.hash, keys, args)
}
func (s *Script) Run(c *Client, keys []string, args []string) *IfaceReq {
func (s *Script) Run(c *Client, keys []string, args []string) *Cmd {
r := s.EvalSha(c, keys, args)
if err := r.Err(); err != nil && strings.HasPrefix(err.Error(), "NOSCRIPT ") {
return s.Eval(c, keys, args)