func (s *Session) DEL(req *redis.Request) { var result int64 // 串行会很慢,可以考滤开goroutine并行执行 // 但是这个goroutine量一定要控制,不能有多少key就多少goroutine p := make(chan int, s.MulOpParallel) for i := 0; i < s.MulOpParallel; i++ { p <- 1 } defer func() { close(p) }() keys := req.Args() wg := sync.WaitGroup{} wg.Add(len(keys)) for _, key := range keys { go func(key string) { <-p // log.Info("In DEL goroutine ", key) cmdslice := []string{"DEL", key} r := redis.NewRequest(cmdslice) resp := s.Proxy.Backend.OnDEL(r) result += resp.Val() p <- 1 wg.Done() }(key) } wg.Wait() mergeResp := redis.FormatInt(result) // log.Info("DEL merger resp ", mergeResp, result) s.write2client(mergeResp) }
func (s *Session) MSET(req *redis.Request) { pair := req.Args() if len(pair)%2 != 0 { err := fmt.Sprintf("-%s\r\n", WrongArgumentCount) s.write2client([]byte(err)) return } p := make(chan int, s.MulOpParallel) for i := 0; i < s.MulOpParallel; i++ { p <- 1 } defer func() { close(p) }() wg := sync.WaitGroup{} wg.Add(len(pair) / 2) partialErr := 0 // we just ignore return code, MSET reuturn OK unless anyone set error for i := 0; i < len(pair); i += 2 { go func(k string, v string) { <-p // log.Info("In MSET goroutine ", k, v) cmdslice := []string{"SET", k, v} r := redis.NewRequest(cmdslice) resp := s.Proxy.Backend.OnSET(r) if resp.Err() != nil && resp.Err() != redis.Nil { // log.Warning("MSET error ", cmdslice, resp.Err()) partialErr += 1 } p <- 1 wg.Done() }(pair[i], pair[i+1]) } wg.Wait() if partialErr == 0 { s.write2client(OK_BYTES) } else { d := fmt.Sprintf("- %d MSET failed, partial key/value %d set\r\n", partialErr, len(pair)/2-partialErr) s.write2client([]byte(d)) } }
func (s *Session) MGET(req *redis.Request) { p := make(chan int, s.MulOpParallel) for i := 0; i < s.MulOpParallel; i++ { p <- 1 } defer func() { close(p) }() keys := req.Args() wg := sync.WaitGroup{} wg.Add(len(keys)) // we should ensure the KEY's order result := make([][]byte, len(keys)) for idx, key := range keys { go func(key string, idx int) { <-p // log.Info("In MGET goroutine ", key) cmdslice := []string{"GET", key} r := redis.NewRequest(cmdslice) resp := s.Proxy.Backend.OnGET(r) result[idx] = resp.Reply() p <- 1 wg.Done() }(key, idx) } wg.Wait() mergeResp := []byte(fmt.Sprintf("*%d\r\n", len(keys))) for _, res := range result { mergeResp = append(mergeResp, res...) } // log.Info("MGET merger resp ", string(mergeResp)) s.write2client(mergeResp) }
func HandleConn(ps *ProxyServer, c net.Conn) { addr := c.RemoteAddr().String() // log.Info("start process Session, receive remote host ", addr) s := NewSession(ps, c) if int64(len(ps.SessMgr)) > ps.Conf.MaxConn { log.Warning("reached max connection, close ", addr) s.Close() return } ps.SessMgr[addr] = s defer delete(ps.SessMgr, addr) for { reqstr, err := parseReq(s.r) //for stats s.LastAccess = time.Now().UnixNano() / 1e3 atomic.AddInt64(&s.Proxy.OpCount, 1) req := redis.NewRequest(reqstr) req.SetError(err) if err != nil { if strings.Contains(err.Error(), "connection reset by peer") || strings.Contains(err.Error(), "broken pipe") || strings.Contains(err.Error(), "use of closed network connection") { // log.Warning("Session ended by ", err.Error()) return } e := s.Write2client(req) if e != nil { // log.Warning("Write2client ", e) return } continue } reply, shouldClose, handled, err := preCheckCommand(req) // log.Info(req, reply, shouldClose, handled, err) req.SetReply(reply) req.SetError(err) if err != nil || shouldClose || handled { s.Write2client(req) if shouldClose { // log.("should close from ", c.RemoteAddr()) s.Close() return } continue } // spec command : mget mset del inter union ..... if isSpecCommand(req.Name()) { s.SpecCommandProcess(req) continue } s.Forward(req) } }