Example #1
0
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)
}
Example #2
0
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))
	}
}
Example #3
0
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)
}
Example #4
0
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)
	}
}