예제 #1
0
func (mc *MultiKeyCmd) CoalesceRsp() *PipelineResponse {
	plRsp := &PipelineResponse{}
	var rsp *resp.Data
	switch mc.CmdType() {
	case MGET:
		rsp = &resp.Data{T: resp.T_Array, Array: make([]*resp.Data, mc.numSubCmds)}
	case MSET:
		rsp = OK_DATA
	case DEL:
		rsp = &resp.Data{T: resp.T_Integer}
	default:
		panic("invalid multi key cmd name")
	}
	for i, subCmdRsp := range mc.subCmdRsps {
		if subCmdRsp.err != nil {
			rsp = &resp.Data{T: resp.T_Error, String: []byte(subCmdRsp.err.Error())}
			break
		}
		reader := bufio.NewReader(bytes.NewReader(subCmdRsp.rsp.Raw()))
		data, err := resp.ReadData(reader)
		if err != nil {
			log.Errorf("re-parse response err=%s", err)
			rsp = &resp.Data{T: resp.T_Error, String: []byte(err.Error())}
			break
		}
		if data.T == resp.T_Error {
			rsp = data
			break
		}
		switch mc.CmdType() {
		case MGET:
			rsp.Array[i] = data
		case MSET:
		case DEL:
			rsp.Integer += data.Integer
		default:
			panic("invalid multi key cmd name")
		}
	}
	plRsp.rsp = resp.NewObjectFromData(rsp)
	return plRsp
}
예제 #2
0
// handleResp handles MOVED and ASK redirection and call write response
func (s *Session) handleResp(plRsp *PipelineResponse) error {
	if plRsp.ctx.seq != s.rspSeq {
		panic("impossible")
	}
	plRsp.ctx.wg.Done()
	if plRsp.ctx.parentCmd == nil {
		s.rspSeq++
	}

	if plRsp.err != nil {
		s.dispatcher.TriggerReloadSlots()
		rsp := &resp.Data{T: resp.T_Error, String: []byte(plRsp.err.Error())}
		plRsp.rsp = resp.NewObjectFromData(rsp)
	} else {
		raw := plRsp.rsp.Raw()
		if raw[0] == resp.T_Error {
			if bytes.HasPrefix(raw, MOVED) {
				_, server := ParseRedirectInfo(string(raw))
				s.dispatcher.TriggerReloadSlots()
				s.redirect(server, plRsp, false)
			} else if bytes.HasPrefix(raw, ASK) {
				_, server := ParseRedirectInfo(string(raw))
				s.redirect(server, plRsp, true)
			}
		}
	}

	if plRsp.err != nil {
		return plRsp.err
	}

	if !s.closed {
		if err := s.writeResp(plRsp); err != nil {
			return err
		}
	}

	return nil
}
예제 #3
0
func (s *Session) ReadingLoop() {
	for {
		cmd, err := resp.ReadCommand(s.r)
		if err != nil {
			log.Error(err)
			break
		}
		// convert all command name to upper case
		cmd.Args[0] = strings.ToUpper(cmd.Args[0])

		if n := atomic.AddUint64(&accessLogCount, 1); n%LogEveryN == 0 {
			if len(cmd.Args) > 1 {
				log.Infof("access %s %s %s", s.RemoteAddr(), cmd.Name(), cmd.Args[1])
			} else {
				log.Infof("access %s %s", s.RemoteAddr(), cmd.Name())
			}
		}

		// check if command is supported
		cmdFlag := CmdFlag(cmd)
		if cmdFlag&CMD_FLAG_BLACK != 0 {
			plReq := &PipelineRequest{
				seq: s.getNextReqSeq(),
				wg:  s.reqWg,
			}
			s.reqWg.Add(1)
			rsp := &resp.Data{T: resp.T_Error, String: BLACK_CMD_ERR}
			plRsp := &PipelineResponse{
				rsp: resp.NewObjectFromData(rsp),
				ctx: plReq,
			}
			s.backQ <- plRsp
			continue
		}

		// check if is multi key cmd
		if yes, numKeys := IsMultiCmd(cmd); yes && numKeys > 1 {
			s.handleMultiKeyCmd(cmd, numKeys)
			continue
		}

		// other general cmd
		key := cmd.Value(1)
		slot := Key2Slot(key)
		plReq := &PipelineRequest{
			cmd:      cmd,
			readOnly: cmdFlag&CMD_FLAG_READONLY != 0,
			slot:     slot,
			seq:      s.getNextReqSeq(),
			backQ:    s.backQ,
			wg:       s.reqWg,
		}

		s.reqWg.Add(1)
		s.dispatcher.Schedule(plReq)
	}
	// wait for all request done
	s.reqWg.Wait()

	// notify writer
	close(s.backQ)
	s.closeSignal.Wait()
}