func slaveofCommand(req *requestContext) error { args := req.args if len(args) != 2 { return ErrCmdParams } masterAddr := "" if strings.ToLower(ledis.String(args[0])) == "no" && strings.ToLower(ledis.String(args[1])) == "one" { //stop replication, use master = "" } else { if _, err := strconv.ParseInt(ledis.String(args[1]), 10, 16); err != nil { return err } masterAddr = fmt.Sprintf("%s:%s", args[0], args[1]) } if err := req.app.slaveof(masterAddr); err != nil { return err } req.resp.writeStatus(OK) return nil }
func (w *httpWriter) writeFVPairArray(lst []ledis.FVPair) { m := make(map[string]string) for _, elem := range lst { m[ledis.String(elem.Field)] = ledis.String(elem.Value) } w.genericWrite(m) }
func zrangebyscoreGeneric(c *client, reverse bool) error { args := c.args if len(args) < 3 { return ErrCmdParams } key := args[0] min, max, err := zparseScoreRange(args[1], args[2]) if err != nil { return err } args = args[3:] var withScores bool = false if len(args) > 0 && strings.ToLower(ledis.String(args[0])) == "withscores" { withScores = true args = args[1:] } var offset int = 0 var count int = -1 if len(args) > 0 { if len(args) != 3 { return ErrCmdParams } if strings.ToLower(ledis.String(args[0])) != "limit" { return ErrCmdParams } if offset, err = strconv.Atoi(ledis.String(args[1])); err != nil { return ErrCmdParams } if count, err = strconv.Atoi(ledis.String(args[2])); err != nil { return ErrCmdParams } } if offset < 0 { //for redis, if offset < 0, a empty will return //so here we directly return a empty array c.writeArray([]interface{}{}) return nil } if v, err := c.db.ZRangeByScoreGeneric(key, min, max, withScores, offset, count, reverse); err != nil { return err } else { c.writeArray(v) } return nil }
func zparseRange(c *client, a1 []byte, a2 []byte) (start int, stop int, err error) { if start, err = strconv.Atoi(ledis.String(a1)); err != nil { return } if stop, err = strconv.Atoi(ledis.String(a2)); err != nil { return } return }
//A client sends to the Redis server a RESP Array consisting of just Bulk Strings. func (c *respClient) readRequest() ([][]byte, error) { l, err := c.readLine() if err != nil { return nil, err } else if len(l) == 0 || l[0] != '*' { return nil, errReadRequest } var nparams int if nparams, err = strconv.Atoi(ledis.String(l[1:])); err != nil { return nil, err } else if nparams <= 0 { return nil, errReadRequest } req := make([][]byte, 0, nparams) var n int for i := 0; i < nparams; i++ { if l, err = c.readLine(); err != nil { return nil, err } if len(l) == 0 { return nil, errReadRequest } else if l[0] == '$' { //handle resp string if n, err = strconv.Atoi(ledis.String(l[1:])); err != nil { return nil, err } else if n == -1 { req = append(req, nil) } else { buf := make([]byte, n) if _, err = io.ReadFull(c.rb, buf); err != nil { return nil, err } if l, err = c.readLine(); err != nil { return nil, err } else if len(l) != 0 { return nil, errors.New("bad bulk string format") } req = append(req, buf) } } else { return nil, errReadRequest } } return req, nil }
func (w *luaWriter) writeFVPairArray(lst []ledis.FVPair) { if lst == nil { w.l.PushBoolean(false) return } w.l.CreateTable(len(lst)*2, 0) for i, v := range lst { w.l.PushString(ledis.String(v.Field)) w.l.RawSeti(-2, 2*i+1) w.l.PushString(ledis.String(v.Value)) w.l.RawSeti(-2, 2*i+2) } }
func zrangeGeneric(req *requestContext, reverse bool) error { args := req.args if len(args) < 3 { return ErrCmdParams } key := args[0] start, stop, err := zparseRange(req, args[1], args[2]) if err != nil { return ErrValue } args = args[3:] var withScores bool = false if len(args) > 0 { if len(args) != 1 { return ErrCmdParams } if strings.ToLower(ledis.String(args[0])) == "withscores" { withScores = true } else { return ErrSyntax } } if datas, err := req.db.ZRangeGeneric(key, start, stop, reverse); err != nil { return err } else { req.resp.writeScorePairArray(datas, withScores) } return nil }
func (c *respClient) handleRequest(reqData [][]byte) { req := c.req if len(reqData) == 0 { c.req.cmd = "" c.req.args = reqData[0:0] } else { c.req.cmd = strings.ToLower(ledis.String(reqData[0])) c.req.args = reqData[1:] } if c.req.cmd == "quit" { c.req.resp.writeStatus(OK) c.req.resp.flush() c.conn.Close() return } req.db = c.db c.req.perform() c.db = req.db // "SELECT" return }
func scriptCommand(c *client) error { s := c.app.s l := s.l s.Lock() base := l.GetTop() defer func() { l.SetTop(base) s.Unlock() }() args := c.args if len(args) < 1 { return ErrCmdParams } switch strings.ToLower(ledis.String(args[0])) { case "load": return scriptLoadCommand(c) case "exists": return scriptExistsCommand(c) case "flush": return scriptFlushCommand(c) default: return fmt.Errorf("invalid script %s", args[0]) } return nil }
func ReadBulkTo(rb *bufio.Reader, w io.Writer) error { l, err := ReadLine(rb) if len(l) == 0 { return errBulkFormat } else if l[0] == '$' { var n int //handle resp string if n, err = strconv.Atoi(ledis.String(l[1:])); err != nil { return err } else if n == -1 { return nil } else { if _, err = io.CopyN(w, rb, int64(n)); err != nil { return err } if l, err = ReadLine(rb); err != nil { return err } else if len(l) != 0 { return errBulkFormat } } } else { return errBulkFormat } return nil }
func boptCommand(req *requestContext) error { args := req.args if len(args) < 2 { return ErrCmdParams } opDesc := strings.ToLower(ledis.String(args[0])) dstKey := args[1] srcKeys := args[2:] var op uint8 switch opDesc { case "and": op = ledis.OPand case "or": op = ledis.OPor case "xor": op = ledis.OPxor case "not": op = ledis.OPnot default: return ErrCmdParams } if len(srcKeys) == 0 { return ErrCmdParams } if blen, err := req.db.BOperation(op, dstKey, srcKeys...); err != nil { return err } else { req.resp.writeInteger(int64(blen)) } return nil }
func selectCommand(c *client) error { if len(c.args) != 1 { return ErrCmdParams } if index, err := strconv.Atoi(ledis.String(c.args[0])); err != nil { return err } else { if c.db.IsTransaction() { if err := c.tx.Select(index); err != nil { return err } else { c.db = c.tx.DB } } else if c.db.IsInMulti() { if err := c.script.Select(index); err != nil { return err } else { c.db = c.script.DB } } else { if db, err := c.ldb.Select(index); err != nil { return err } else { c.db = db } } c.resp.writeStatus(OK) } return nil }
func (w *luaWriter) writeBulk(b []byte) { if b == nil { w.l.PushBoolean(false) } else { w.l.PushString(ledis.String(b)) } }
func scriptLoadCommand(c *client) error { s := c.app.s l := s.l if len(c.args) != 2 { return ErrCmdParams } h := sha1.Sum(c.args[1]) key := hex.EncodeToString(h[0:20]) if r := l.LoadString(ledis.String(c.args[1])); r != 0 { err := fmt.Errorf("%s", l.ToString(-1)) l.Pop(1) return err } else { l.PushValue(-1) l.SetGlobal(key) s.chunks[key] = struct{}{} } c.resp.writeBulk(ledis.Slice(key)) return nil }
func (w *httpWriter) writeScorePairArray(lst []ledis.ScorePair, withScores bool) { var arr []string if withScores { arr = make([]string, 2*len(lst)) for i, data := range lst { arr[2*i] = ledis.String(data.Member) arr[2*i+1] = strconv.FormatInt(data.Score, 10) } } else { arr = make([]string, len(lst)) for i, data := range lst { arr[i] = ledis.String(data.Member) } } w.genericWrite(arr) }
func zrangeGeneric(c *client, reverse bool) error { args := c.args if len(args) < 3 { return ErrCmdParams } key := args[0] start, stop, err := zparseRange(c, args[1], args[2]) if err != nil { return err } args = args[3:] var withScores bool = false if len(args) > 0 && strings.ToLower(ledis.String(args[0])) == "withscores" { withScores = true } if datas, err := c.db.ZRangeGeneric(key, start, stop, reverse); err != nil { return err } else { c.writeScorePairArray(datas, withScores) } return nil }
func (w *httpWriter) writeBulk(b []byte) { if b == nil { w.genericWrite(nil) } else { w.genericWrite(ledis.String(b)) } }
func (c *client) handleRequest(req [][]byte) { var err error if len(req) == 0 { err = ErrEmptyCommand } else { c.cmd = strings.ToLower(ledis.String(req[0])) c.args = req[1:] f, ok := regCmds[c.cmd] if !ok { err = ErrNotFound } else { go func() { c.reqC <- f(c) }() err = <-c.reqC } } if err != nil { c.writeError(err) } c.wb.Flush() }
func luaSetGlobalArray(l *lua.State, name string, ay [][]byte) { l.NewTable() for i := 0; i < len(ay); i++ { l.PushString(ledis.String(ay[i])) l.RawSeti(-2, i+1) } l.SetGlobal(name) }
func (w *httpWriter) writeSliceArray(lst [][]byte) { arr := make([]interface{}, len(lst)) for i, elem := range lst { if elem == nil { arr[i] = nil } else { arr[i] = ledis.String(elem) } } w.genericWrite(arr) }
func (w *luaWriter) writeSliceArray(lst [][]byte) { if lst == nil { w.l.PushBoolean(false) return } w.l.CreateTable(len(lst), 0) for i, v := range lst { w.l.PushString(ledis.String(v)) w.l.RawSeti(-2, i+1) } }
func infoCommand(c *client) error { if len(c.args) > 1 { return ErrSyntax } var section string if len(c.args) == 1 { section = strings.ToLower(ledis.String(c.args[0])) } buf := c.app.info.Dump(section) c.resp.writeBulk(buf) return nil }
func (w *luaWriter) writeScorePairArray(lst []ledis.ScorePair, withScores bool) { if lst == nil { w.l.PushBoolean(false) return } if withScores { w.l.CreateTable(len(lst)*2, 0) for i, v := range lst { w.l.PushString(ledis.String(v.Member)) w.l.RawSeti(-2, 2*i+1) w.l.PushString(ledis.String(ledis.StrPutInt64(v.Score))) w.l.RawSeti(-2, 2*i+2) } } else { w.l.CreateTable(len(lst), 0) for i, v := range lst { w.l.PushString(ledis.String(v.Member)) w.l.RawSeti(-2, i+1) } } }
func (c *client) handleRequest(req [][]byte) { var err error start := time.Now() if len(req) == 0 { err = ErrEmptyCommand } else { c.cmd = strings.ToLower(ledis.String(req[0])) c.args = req[1:] f, ok := regCmds[c.cmd] if !ok { err = ErrNotFound } else { go func() { c.reqC <- f(c) }() err = <-c.reqC } } duration := time.Since(start) if c.app.access != nil { c.logBuf.Reset() for i, r := range req { left := 256 - c.logBuf.Len() if left <= 0 { break } else if len(r) <= left { c.logBuf.Write(r) if i != len(req)-1 { c.logBuf.WriteByte(' ') } } else { c.logBuf.Write(r[0:left]) } } c.app.access.Log(c.c.RemoteAddr().String(), duration.Nanoseconds()/1000000, c.logBuf.Bytes(), err) } if err != nil { c.writeError(err) } c.wb.Flush() }
func selectCommand(req *requestContext) error { if len(req.args) != 1 { return ErrCmdParams } if index, err := strconv.Atoi(ledis.String(req.args[0])); err != nil { return err } else { if db, err := req.ldb.Select(index); err != nil { return err } else { req.db = db req.resp.writeStatus(OK) } } return nil }
func selectCommand(c *client) error { if len(c.args) != 1 { return ErrCmdParams } if index, err := strconv.Atoi(ledis.String(c.args[0])); err != nil { return err } else { if db, err := c.ldb.Select(index); err != nil { return err } else { c.db = db c.writeStatus(OK) } } return nil }
func scriptExistsCommand(c *client) error { s := c.app.s if len(c.args) < 2 { return ErrCmdParams } ay := make([]interface{}, len(c.args[1:])) for i, n := range c.args[1:] { if _, ok := s.chunks[ledis.String(n)]; ok { ay[i] = int64(1) } else { ay[i] = int64(0) } } c.resp.writeArray(ay) return nil }
func parseScanArgs(c *client) (key []byte, match string, count int, err error) { args := c.args count = 10 switch len(args) { case 0: key = nil return case 1, 3, 5: key = args[0] break default: err = ErrCmdParams return } if len(args) == 3 { switch strings.ToLower(ledis.String(args[1])) { case "match": match = ledis.String(args[2]) return case "count": count, err = strconv.Atoi(ledis.String(args[2])) return default: err = ErrCmdParams return } } else if len(args) == 5 { if strings.ToLower(ledis.String(args[1])) != "match" { err = ErrCmdParams return } else if strings.ToLower(ledis.String(args[3])) != "count" { err = ErrCmdParams return } match = ledis.String(args[2]) count, err = strconv.Atoi(ledis.String(args[4])) return } return }
func parseEvalArgs(l *lua.State, c *client) error { args := c.args if len(args) < 2 { return ErrCmdParams } args = args[1:] n, err := strconv.Atoi(ledis.String(args[0])) if err != nil { return err } if n > len(args)-1 { return ErrCmdParams } luaSetGlobalArray(l, "KEYS", args[1:n+1]) luaSetGlobalArray(l, "ARGV", args[n+1:]) return nil }
func zparseScoreRange(minBuf []byte, maxBuf []byte) (min int64, max int64, err error) { if strings.ToLower(ledis.String(minBuf)) == "-inf" { min = math.MinInt64 } else { var lopen bool = false if minBuf[0] == '(' { lopen = true minBuf = minBuf[1:] } if len(minBuf) == 0 { err = ErrCmdParams return } min, err = ledis.StrInt64(minBuf, nil) if err != nil { return } if min <= ledis.MinScore || min >= ledis.MaxScore { err = errScoreOverflow return } if lopen { min++ } } if strings.ToLower(ledis.String(maxBuf)) == "+inf" { max = math.MaxInt64 } else { var ropen = false if maxBuf[0] == '(' { ropen = true maxBuf = maxBuf[1:] } if len(maxBuf) == 0 { err = ErrCmdParams return } max, err = ledis.StrInt64(maxBuf, nil) if err != nil { return } if max <= ledis.MinScore || max >= ledis.MaxScore { err = errScoreOverflow return } if ropen { max-- } } return }