func processMc(c net.Conn, pool *redis.Pool) { defer log.Printf("%v end processMc", c) defer c.Close() stats.Connect() defer stats.Disconnect() // process br := bufio.NewReader(c) bw := bufio.NewWriter(c) // take it per need conn := pool.Get() defer conn.Close() redisProxy := proxy.NewRedisProxy(conn) proxy := stats.NewStatsProxy(redisProxy) for { req, err := protocol.ReadRequest(br) if perr, ok := err.(protocol.ProtocolError); ok { log.Printf("%v ReadRequest protocol err: %v", c, err) bw.WriteString("CLIENT_ERROR " + perr.Error() + "\r\n") bw.Flush() continue } else if err != nil { log.Printf("%v ReadRequest err: %v", c, err) return } log.Printf("%v Req: %+v\n", c, req) switch req.Command { case "quit": return case "version": res := protocol.McResponse{Response: "VERSION mrproxy " + version} bw.WriteString(res.Protocol()) bw.Flush() default: res := proxy.Process(req) if !req.Noreply { log.Printf("%v Res: %+v\n", c, res) bw.WriteString(res.Protocol()) bw.Flush() } } } }
// process a request and generate a response func (p *RedisProxy) Process(req *protocol.McRequest) protocol.McResponse { switch req.Command { case "get": res := protocol.McResponse{} for i := range req.Keys { r, err := redis.Values(p.conn.Do("MGET", req.Keys[i], req.Keys[i]+"_mcflags")) if err != nil { // hmm, barf errors, or just ignore? return serverError(err) } if r[0] != nil { data, err := redis.Bytes(r[0], nil) if err != nil { return serverErrorText(err, "data") } flags := "0" if r[1] != nil { flags, err = redis.String(r[1], nil) if err != nil { return serverErrorText(err, "flags") } } // todo, both can return error res.Values = append(res.Values, protocol.McValue{req.Keys[i], flags, data}) } } res.Response = "END" return res case "set": r, err := redis.String(p.conn.Do("MSET", req.Key, req.Data, req.Key+"_mcflags", req.Flags)) if err != nil || r != "OK" { return serverError(err) } if req.Exptime != 0 { _, err = p.conn.Do("EXPIREAT", req.Key, req.Exptime) if err != nil { return serverError(err) } } return protocol.McResponse{Response: "STORED"} case "delete": r, err := redis.Int(p.conn.Do("DEL", toInterface(req.Keys)...)) if err != nil { return serverError(err) } if r > 0 { return protocol.McResponse{Response: "DELETED"} } return protocol.McResponse{Response: "NOT_FOUND"} // todo "touch"... } return protocol.McResponse{Response: "ERROR"} }