Example #1
0
func (tr *taskRunner) readloop() {
	for {
		resp, err := parser.Parse(tr.c.BufioReader())
		if err != nil {
			tr.out <- err
			return
		}

		tr.out <- resp
	}
}
Example #2
0
func (s *Server) handleMigrateState(slotIndex int, key []byte) error {
	shd := s.slots[slotIndex]
	if shd.slotInfo.State.Status != models.SLOT_STATUS_MIGRATE {
		return nil
	}

	if shd.migrateFrom == nil {
		log.Fatalf("migrateFrom not exist %+v", shd)
	}

	if shd.dst.Master() == shd.migrateFrom.Master() {
		log.Fatalf("the same migrate src and dst, %+v", shd)
	}

	redisConn, err := s.pools.GetConn(shd.migrateFrom.Master())
	if err != nil {
		return errors.Trace(err)
	}

	defer s.pools.ReleaseConn(redisConn)

	redisReader := redisConn.(*redispool.PooledConn).BufioReader()

	err = WriteMigrateKeyCmd(redisConn.(*redispool.PooledConn), shd.dst.Master(), 30*1000, key)
	if err != nil {
		redisConn.Close()
		log.Warningf("migrate key %s error, from %s to %s",
			string(key), shd.migrateFrom.Master(), shd.dst.Master())
		return errors.Trace(err)
	}

	//handle migrate result
	resp, err := parser.Parse(redisReader)
	if err != nil {
		redisConn.Close()
		return errors.Trace(err)
	}

	result, err := resp.Bytes()

	log.Debug("migrate", string(key), "from", shd.migrateFrom.Master(), "to", shd.dst.Master(),
		string(result))

	if resp.Type == parser.ErrorResp {
		redisConn.Close()
		log.Error(string(key), string(resp.Raw), "migrateFrom", shd.migrateFrom.Master())
		return errors.New(string(resp.Raw))
	}

	s.counter.Add("Migrate", 1)
	return nil
}
Example #3
0
func (s *Server) sendBack(c *session, op []byte, keys [][]byte, resp *parser.Resp, result []byte) {
	c.pipelineSeq++
	pr := &PipelineRequest{
		op:    op,
		keys:  keys,
		seq:   c.pipelineSeq,
		backQ: c.backQ,
		req:   resp,
	}

	resp, err := parser.Parse(bufio.NewReader(bytes.NewReader(result)))
	//just send to backQ
	c.backQ <- &PipelineResponse{ctx: pr, err: err, resp: resp}
}
Example #4
0
func write2Client(redisReader *bufio.Reader, clientWriter io.Writer) (redisErr error, clientErr error) {
	resp, err := parser.Parse(redisReader)
	if err != nil {
		return errors.Trace(err), errors.Trace(err)
	}

	b, err := resp.Bytes()
	if err != nil {
		return errors.Trace(err), errors.Trace(err)
	}

	_, err = clientWriter.Write(b)
	return nil, errors.Trace(err)
}
Example #5
0
func TestForward(t *testing.T) {
	client := &fakeDeadlineReadWriter{r: bufio.NewReader(bytes.NewBuffer([]byte(simple_request))),
		w: bufio.NewWriter(&bytes.Buffer{})}
	redis := &fakeDeadlineReadWriter{r: bufio.NewReader(bytes.NewBuffer([]byte(simple_request))),
		w: bufio.NewWriter(&bytes.Buffer{})}

	resp, err := parser.Parse(bufio.NewReader(bytes.NewBuffer([]byte(simple_request))))
	if err != nil {
		t.Error(err)
	}

	_, clientErr := forward(client, redis, resp)
	if clientErr != nil {
		t.Error(clientErr)
	}
}
Example #6
0
func getRespOpKeys(c *session) (*parser.Resp, []byte, [][]byte, error) {
	resp, err := parser.Parse(c.r) // read client request
	if err != nil {
		return nil, nil, nil, errors.Trace(err)
	}

	op, keys, err := resp.GetOpKeys()
	if err != nil {
		return nil, nil, nil, errors.Trace(err)
	}

	if len(keys) == 0 {
		keys = [][]byte{[]byte("fakeKey")}
	}

	return resp, op, keys, nil
}
Example #7
0
func TestWrite2Redis(t *testing.T) {
	var result bytes.Buffer
	var input bytes.Buffer
	input.WriteString(simple_request)
	resp, err := parser.Parse(bufio.NewReader(&input))
	if err != nil {
		t.Error(err)
	}

	err = write2Redis(resp, &result)
	if err != nil {
		t.Error(err)
	}

	if string(result.Bytes()) != simple_request {
		t.Error("not match")
	}
}
Example #8
0
func TestHandleSpecCommand(t *testing.T) {
	var tbl = map[string]string{
		"PING":   "+PONG\r\n",
		"QUIT":   string(OK_BYTES),
		"SELECT": string(OK_BYTES),
		"AUTH":   string(OK_BYTES),
	}

	for k, v := range tbl {
		resp, err := parser.Parse(bufio.NewReader(bytes.NewBufferString(k + string(parser.NEW_LINE))))
		if err != nil {
			t.Error(err)
		}

		_, keys, err := resp.GetOpKeys()
		if err != nil {
			t.Error(errors.ErrorStack(err))
		}

		result := &bytes.Buffer{}
		w := &fakeDeadlineReadWriter{w: bufio.NewWriter(result)}
		_, _, err = handleSpecCommand(k, w, keys)
		if err != nil {
			t.Error(err)
		}

		w.w.Flush()
		if string(result.Bytes()) != v {
			t.Error("result not match", string(result.Bytes()))
		}
	}

	//"ECHO xxxx": "xxxx\r\n",
	{
		resp, err := parser.Parse(bufio.NewReader(bytes.NewBufferString("ECHO xxxx\r\n")))
		if err != nil {
			t.Error(errors.ErrorStack(err))
		}

		result := &bytes.Buffer{}
		w := &fakeDeadlineReadWriter{w: bufio.NewWriter(result)}
		_, keys, _ := resp.GetOpKeys()

		_, _, err = handleSpecCommand("ECHO", w, keys)
		if err != nil {
			t.Error(errors.ErrorStack(err))
		}

		w.w.Flush()
		if string(result.Bytes()) != "$4\r\nxxxx\r\n" {
			t.Error("result not match", string(result.Bytes()))
		}
	}

	//test empty key
	{
		resp, err := parser.Parse(bufio.NewReader(bytes.NewBufferString("ECHO\r\n")))
		if err != nil {
			t.Error(errors.ErrorStack(err))
		}

		result := &bytes.Buffer{}
		w := &fakeDeadlineReadWriter{w: bufio.NewWriter(result)}
		_, keys, _ := resp.GetOpKeys()
		shouldClose, _, err := handleSpecCommand("ECHO", w, keys)
		if !shouldClose {
			t.Error(errors.ErrorStack(err))
		}
	}

	//test not specific command
	{
		result := &bytes.Buffer{}
		w := &fakeDeadlineReadWriter{w: bufio.NewWriter(result)}
		_, handled, err := handleSpecCommand("get", w, nil)
		if handled {
			t.Error(errors.ErrorStack(err))
		}
	}
}
Example #9
0
func (s *Server) redisTunnel(c *session) error {
	resp, err := parser.Parse(c.r) // read client request
	if err != nil {
		return errors.Trace(err)
	}

	op, keys, err := resp.GetOpKeys()
	if err != nil {
		return errors.Trace(err)
	}

	if len(keys) == 0 {
		keys = [][]byte{[]byte("fakeKey")}
	}

	start := time.Now()
	k := keys[0]

	opstr := strings.ToUpper(string(op))
	//log.Debugf("op: %s, %s", opstr, keys[0])
	next, err := s.filter(opstr, keys, c)
	if err != nil {
		return errors.Trace(err)
	}

	s.counter.Add(opstr, 1)
	s.counter.Add("ops", 1)
	if !next {
		return nil
	}

	i := mapKey2Slot(k)
	token := s.concurrentLimiter.Get()

check_state:
	s.mu.RLock()
	if s.slots[i] == nil {
		s.mu.Unlock()
		return errors.Errorf("should never happend, slot %d is empty", i)
	}
	//wait for state change, should be soon
	if s.slots[i].slotInfo.State.Status == models.SLOT_STATUS_PRE_MIGRATE {
		s.mu.RUnlock()
		time.Sleep(10 * time.Millisecond)
		goto check_state
	}

	defer func() {
		s.mu.RUnlock()
		sec := time.Since(start).Seconds()
		if sec > 2 {
			log.Warningf("op: %s, key:%s, on: %s, too long %d", opstr,
				string(k), s.slots[i].dst.Master(), int(sec))
		}
		recordResponseTime(s.counter, time.Duration(sec)*1000)
		s.concurrentLimiter.Put(token)
	}()

	if err := s.handleMigrateState(i, k); err != nil {
		return errors.Trace(err)
	}

	//get redis connection
	redisConn, err := s.pools.GetConn(s.slots[i].dst.Master())
	if err != nil {
		return errors.Trace(err)
	}

	redisErr, clientErr := forward(c, redisConn.(*redispool.PooledConn), resp)
	if redisErr != nil {
		redisConn.Close()
	}
	s.pools.ReleaseConn(redisConn)
	return errors.Trace(clientErr)
}