// Dispatch takes in a client whose command has already been read off the // socket, a list of arguments from that command (not including the command name // itself), and handles that command func Dispatch(client *clients.Client, cmd string, args []string) { cmdInfo, ok := commandMap[strings.ToUpper(cmd)] if !ok { writeErrf(client.Conn, "ERR unknown command %q", cmd) return } if len(args) < cmdInfo.minArgs { writeErrf(client.Conn, "ERR missing args") return } ret, err := cmdInfo.f(client, args) if err != nil { writeErrf(client.Conn, "ERR unexpected server-side error") log.L.Print(client.Sprintf("command %s %#v err: %s", cmd, args, err)) return } redis.NewResp(ret).WriteTo(client.Conn) }
func TestSaveEvent(t *testing.T) { fake := FakeRedis{} db := DB{"", fake} fakeHLEN = redis.NewResp(22) fakeHSET = redis.NewResp(nil) buf := bytes.NewBufferString("test") if err := db.SaveEvent(1, buf); err != nil { t.Errorf("Should not have errored: %s", err.Error()) } if len(capture) != 3 { t.Fatalf("Need 3 params to HSET, got %d", len(capture)) } store, _ := capture[0].(string) if store != "ES:1" { t.Errorf("Should have saved to store ES:1, but got %s", store) } eid, _ := capture[1].(int) if eid != 22 { t.Errorf("Should have saved with event id 22, but got %d", eid) } if buf != capture[2] { t.Errorf("Should have used the provided buffer") } }
func (d *clusterDB) Lua(cmd string, numKeys int, args ...interface{}) *redis.Resp { key, err := redis.KeyFromArgs(args) if err != nil { return redis.NewResp(err) } c, err := d.GetForKey(key) if err != nil { return redis.NewResp(err) } defer d.Put(c) return luaHelper(c, cmd, numKeys, args...) }
func TestLoadStores(t *testing.T) { fake := FakeRedis{} db := DB{"", fake} fakeKEYS = redis.NewResp([]string{ "ES:1", "ES:2", "ES:3", }) stores, err := db.LoadStores() if err != nil { t.Fatalf("LoadStores should not have errored: %s", err.Error()) } if len(stores) != 3 { t.Fatalf("Expected 3 stores but got %d", len(stores)) } if stores[0] != "ES:1" { t.Errorf("Expected store 0 to be ES:1 but was %s", stores[0]) } if stores[1] != "ES:2" { t.Errorf("Expected store 1 to be ES:2 but was %s", stores[1]) } if stores[2] != "ES:3" { t.Errorf("Expected store 2 to be ES:3 but was %s", stores[2]) } }
func luaHelper( c *redis.Client, cmd string, numKeys int, args ...interface{}, ) *redis.Resp { cmd = strings.ToUpper(cmd) l, ok := luaScripts[cmd] if !ok { return redis.NewResp(fmt.Errorf("unknown lua script: %s", cmd)) } realArgs := make([]interface{}, 0, len(args)+2) realArgs = append(realArgs, l.hash, numKeys) realArgs = append(realArgs, args...) r, notLoaded := luaEvalSha(c, realArgs) if !notLoaded { return r } if err := c.Cmd("SCRIPT", "LOAD", l.script).Err; err != nil { return r } r, _ = luaEvalSha(c, realArgs) return r }
func TestGetEvents(t *testing.T) { fake := FakeRedis{} db := DB{"", fake} fakeHGETALL = redis.NewResp([]string{ "1", "test1", "0", "test2", "2", "test3", }) bufs, err := db.GetEvents(1) if err != nil { t.Fatalf("Should not have errored getting events: %s", err.Error()) } if len(bufs) != 3 { t.Fatalf("Expected 3 events but got %d", len(bufs)) } zero := bufs[0].String() if zero != "test2" { t.Errorf("Expected event 0 to be test2 but got %s", zero) } one := bufs[1].String() if one != "test1" { t.Errorf("Expected event 1 to be test1 but got %s", one) } two := bufs[2].String() if two != "test3" { t.Errorf("Expected event 2 to be test3 but got %s", two) } }
// Cmd automatically gets one client from the pool, executes the given command // (returning its result), and puts the client back in the pool func (p *Pool) Cmd(cmd string, args ...interface{}) *redis.Resp { c, err := p.Get() if err != nil { return redis.NewResp(err) } defer p.Put(c) return c.Cmd(cmd, args...) }
func (d *sentinelDB) Cmd(cmd string, args ...interface{}) *redis.Resp { sentinel, conn, err := d.getSentinelAndMaster() if err != nil { return redis.NewResp(err) } defer sentinel.PutMaster(config.RedisSentinelGroup, conn) return conn.Cmd(cmd, args...) }
func (d sentinelDB) Lua(cmd string, numKeys int, args ...interface{}) *redis.Resp { sentinel, c, err := d.getSentinelAndMaster() if err != nil { return redis.NewResp(err) } defer sentinel.PutMaster(config.RedisSentinelGroup, c) r := luaHelper(c, cmd, numKeys, args...) return r }
func (d normalDB) Lua(cmd string, numKeys int, args ...interface{}) *redis.Resp { c, err := d.Get() if err != nil { return redis.NewResp(err) } r := luaHelper(c, cmd, numKeys, args...) d.Put(c) return r }
func (d *normalDB) Cmd(cmd string, args ...interface{}) *redis.Resp { c, err := d.Get() if err != nil { return redis.NewResp(err) } r := c.Cmd(cmd, args...) d.Put(c) return r }
func TestNextStoreID(t *testing.T) { fake := FakeRedis{} db := DB{"", fake} fakeINCR = redis.NewResp(11) sid, err := db.NextStoreID() if err != nil { t.Fatalf("Should not have errored during id increment: %s", err.Error()) } if sid != 11 { t.Errorf("Expected next store id to be 11 but was %d", sid) } }
func (rs *RedisStorage) Cmd(cmd string, args ...interface{}) *redis.Resp { c, err := rs.db.Get() if err != nil { return redis.NewResp(err) } result := c.Cmd(cmd, args...) if result.IsType(redis.IOErr) { rs.IncreasePool() utils.Logger.Warning(fmt.Sprintf("RedisClient error '%s'", result.String())) return rs.Cmd(cmd, args...) } rs.db.Put(c) return result }
// LuaEval calls EVAL on the given Cmder for the given script, passing the key // count and argument list in as well. See http://redis.io/commands/eval for // more on how EVAL works and for the meaning of the keys argument. // // LuaEval will automatically try to call EVALSHA first in order to preserve // bandwidth, and only falls back on EVAL if the script has never been used // before. // // This method works with any of the Cmder's implemented in radix.v2, including // Client, Pool, and Cluster. // // r := util.LuaEval(c, `return redis.call('GET', KEYS[1])`, 1, "foo") // func LuaEval(c Cmder, script string, keys int, args ...interface{}) *redis.Resp { mainKey, _ := redis.KeyFromArgs(args...) sumRaw := sha1.Sum([]byte(script)) sum := hex.EncodeToString(sumRaw[:]) var r *redis.Resp if err := withClientForKey(c, mainKey, func(cc Cmder) { r = c.Cmd("EVALSHA", sum, keys, args) if r.Err != nil && strings.HasPrefix(r.Err.Error(), "NOSCRIPT") { r = c.Cmd("EVAL", script, keys, args) } }); err != nil { return redis.NewResp(err) } return r }
// This CMD function get a connection from the pool. // Handles automatic failover in case of network disconnects func (rs *RedisStorage) Cmd(cmd string, args ...interface{}) *redis.Resp { c1, err := rs.dbPool.Get() if err != nil { return redis.NewResp(err) } result := c1.Cmd(cmd, args...) if result.IsType(redis.IOErr) { // Failover mecanism utils.Logger.Warning(fmt.Sprintf("<RedisStorage> error <%s>, attempting failover.", result.Err.Error())) for i := 0; i < rs.maxConns; i++ { // Two attempts, one on connection of original pool, one on new pool c2, err := rs.dbPool.Get() if err == nil { if result2 := c2.Cmd(cmd, args...); !result2.IsType(redis.IOErr) { rs.dbPool.Put(c2) return result2 } } } } else { rs.dbPool.Put(c1) } return result }
func TestPublishEvent(t *testing.T) { fake := FakeRedis{} db := DB{"", fake} fakePUBLISH = redis.NewResp(1) buf := bytes.NewBufferString("test") if err := db.PublishEvent("ename", buf); err != nil { t.Fatalf("Should not have errored: %s", err.Error()) } if len(capture) != 2 { t.Fatalf("Need 2 params to PUBLISH, got %d", len(capture)) } channel, _ := capture[0].(string) if channel != "ename" { t.Errorf("Should have published to ename but went to %s", channel) } if buf != capture[1] { t.Errorf("Should have used the provided buffer") } }
func errorResp(err error) *redis.Resp { return redis.NewResp(err) }
go serveClient(client) } } func acceptConns(listener net.Listener, incomingConns chan net.Conn) { for { conn, err := listener.Accept() if conn == nil { log.L.Printf("couldn't accept: %q", err) continue } incomingConns <- conn } } var invalidCmdResp = redis.NewResp(errors.New("ERR invalid command")) func serveClient(client *clients.Client) { conn := client.Conn rr := redis.NewRespReader(conn) outer: for { var command string var args []string m := rr.Read() if m.IsType(redis.IOErr) { log.L.Debug(client.Sprintf("client connection error %q", m.Err)) if len(client.Queues) > 0 { consumers.UpdateQueues(client, []string{})
func writeErrf(w io.Writer, format string, args ...interface{}) { err := fmt.Errorf(format, args...) redis.NewResp(err).WriteTo(w) }