예제 #1
0
파일: slots.go 프로젝트: cuiwm/reborn
// SLOTSRESTORE key ttlms value [key ttlms value ...]
func SlotsRestoreCmd(s Session, args [][]byte) (redis.Resp, error) {
	if err := s.Store().SlotsRestore(s.DB(), args); err != nil {
		return toRespError(err)
	} else {
		return redis.NewString("OK"), nil
	}
}
예제 #2
0
파일: repl.go 프로젝트: CowLeo/qdb
// REPLCONF listening-port port / ack sync-offset
func ReplConfCmd(s Session, args [][]byte) (redis.Resp, error) {
	if len(args) != 2 {
		return toRespErrorf("len(args) = %d, expect = 2", len(args))
	}

	c, _ := s.(*conn)
	if c == nil {
		return nil, errors.New("invalid connection")
	}

	switch strings.ToLower(string(args[0])) {
	case "listening-port":
		if port, err := strconv.ParseInt(string(args[1]), 10, 16); err != nil {
			return toRespErrorf("invalid port REPLCONF listening-port, err: %v", err)
		} else {
			c.listeningPort.Set(int64(port))
		}
	case "ack":
		if ack, err := strconv.ParseInt(string(args[1]), 10, 64); err != nil {
			return toRespErrorf("invalid port REPLCONF ACK, err: %v", err)
		} else {
			c.backlogACKOffset.Set(ack)
			c.backlogACKTime.Set(time.Now().Unix())
			// ACK will not reply anything
			return nil, nil
		}
	default:
		return toRespErrorf("Unrecognized REPLCONF option:%s", args[0])
	}

	return redis.NewString("OK"), nil
}
예제 #3
0
파일: misc.go 프로젝트: vebin/reborn
// PING
func PingCmd(s Session, args [][]byte) (redis.Resp, error) {
	if len(args) != 0 {
		return toRespErrorf("len(args) = %d, expect = 0", len(args))
	}

	return redis.NewString("PONG"), nil
}
예제 #4
0
파일: keys.go 프로젝트: CowLeo/qdb
// TYPE key
func TypeCmd(s Session, args [][]byte) (redis.Resp, error) {
	if c, err := s.Store().Type(s.DB(), args); err != nil {
		return toRespError(err)
	} else {
		return redis.NewString(c.String()), nil
	}
}
예제 #5
0
파일: sync.go 프로젝트: vebin/reborn
// BGSAVETO path
func BgsaveToCmd(s Session, args [][]byte) (redis.Resp, error) {
	if len(args) != 1 {
		return toRespErrorf("len(args) = %d, expect = 1", len(args))
	}

	c, _ := s.(*conn)
	if c == nil {
		return nil, errors.New("invalid connection")
	}

	if ok := c.h.bgSaveSem.AcquireTimeout(time.Second); !ok {
		return toRespErrorf("wait others do bgsave timeout")
	}
	defer c.h.bgSaveSem.Release()

	sp, err := c.Store().NewSnapshot()
	if err != nil {
		return toRespError(err)
	}
	defer c.Store().ReleaseSnapshot(sp)

	if err := c.h.bgsaveTo(sp, string(args[0])); err != nil {
		return toRespError(err)
	} else {
		return redis.NewString("OK"), nil
	}
}
예제 #6
0
파일: sync.go 프로젝트: vebin/reborn
// SLAVEOF host port
func SlaveOfCmd(s Session, args [][]byte) (redis.Resp, error) {
	if len(args) != 2 {
		return toRespErrorf("len(args) = %d, expect = 2", len(args))
	}

	addr := fmt.Sprintf("%s:%s", string(args[0]), string(args[1]))
	log.Infof("set slave of %s", addr)

	c, _ := s.(*conn)
	if c == nil {
		return nil, errors.New("invalid connection")
	}

	var cc *conn
	var err error
	if strings.ToLower(addr) != "no:one" {
		if cc, err = c.h.replicationConnectMaster(addr); err != nil {
			return toRespError(errors.Trace(err))
		}
	}

	select {
	case <-c.h.signal:
		if cc != nil {
			cc.Close()
		}
		return toRespErrorf("sync master has been closed")
	case c.h.master <- cc:
		<-c.h.slaveofReply
		return redis.NewString("OK"), nil
	}
}
예제 #7
0
파일: string.go 프로젝트: CowLeo/qdb
// SET key value [EX seconds] [PX milliseconds] [NX|XX]
func SetCmd(s Session, args [][]byte) (redis.Resp, error) {
	if err := s.Store().Set(s.DB(), args); err != nil && errors2.ErrorNotEqual(err, store.ErrSetAborted) {
		return toRespError(err)
	} else if errors2.ErrorEqual(err, store.ErrSetAborted) {
		return redis.NewBulkBytes(nil), nil
	} else {
		return redis.NewString("OK"), nil
	}
}
예제 #8
0
파일: misc.go 프로젝트: CowLeo/qdb
// SELECT db
func SelectCmd(s Session, args [][]byte) (redis.Resp, error) {
	if db, err := store.ParseUint(args[0]); err != nil {
		return toRespError(err)
	} else if db > math.MaxUint32 {
		return toRespErrorf("parse db = %d", db)
	} else {
		s.SetDB(uint32(db))
		return redis.NewString("OK"), nil
	}
}
예제 #9
0
파일: misc.go 프로젝트: vebin/reborn
// COMPACTALL
func CompactAllCmd(s Session, args [][]byte) (redis.Resp, error) {
	if len(args) != 0 {
		return toRespErrorf("len(args) = %d, expect = 0", len(args))
	}

	if err := s.Store().CompactAll(); err != nil {
		return toRespError(err)
	} else {
		return redis.NewString("OK"), nil
	}
}
예제 #10
0
파일: command.go 프로젝트: CowLeo/qdb
func RegisterStringReply(name string, f CommandSimpleStringFunc, flag CommandFlag) {
	v := func(s Session, args [][]byte) (redis.Resp, error) {
		r, err := f(s, args)
		if err != nil {
			return toRespError(err)
		}
		return redis.NewString(r), nil
	}

	register(name, v, flag)
}
예제 #11
0
파일: command.go 프로젝트: vebin/reborn
func RegisterOKReply(name string, f CommandOKFunc) {
	v := func(s Session, args [][]byte) (redis.Resp, error) {
		err := f(s, args)
		if err != nil {
			return toRespError(err)
		}
		return redis.NewString("OK"), nil

	}

	register(name, v)
}
예제 #12
0
파일: misc.go 프로젝트: vebin/reborn
// CONFIG get key / set key value
func ConfigCmd(s Session, args [][]byte) (redis.Resp, error) {
	if len(args) != 2 && len(args) != 3 {
		return toRespErrorf("len(args) = %d, expect = 2 or 3", len(args))
	}

	c, _ := s.(*conn)
	if c == nil {
		return nil, errors.New("invalid connection")
	}

	sub := strings.ToLower(string(args[0]))

	switch sub {
	default:
		return toRespErrorf("unknown sub-command = %s", sub)
	case "get":
		if len(args) != 2 {
			return toRespErrorf("len(args) = %d, expect = 2", len(args))
		}
		switch e := strings.ToLower(string(args[1])); e {
		default:
			return toRespErrorf("unknown entry %s", e)
		case "maxmemory":
			return redis.NewString("0"), nil
		}
	case "set":
		if len(args) != 3 {
			return toRespErrorf("len(args) = %d, expect = 3", len(args))
		}
		switch e := strings.ToLower(string(args[1])); e {
		default:
			return toRespErrorf("unknown entry %s", e)
		case "requirepass":
			auth := string(args[2])
			c.h.config.Auth = auth
			return redis.NewString("OK"), nil
		}
	}
}
예제 #13
0
파일: repl.go 프로젝트: CowLeo/qdb
func (h *Handler) handleSyncCommand(opt string, c *conn, args [][]byte) (redis.Resp, error) {
	if h.isSlave(c) {
		// ignore SYNC if already slave
		return nil, nil
	}

	if opt == "psync" {
		// first try whether full resync or not
		need, syncOffset := h.needFullReSync(c, args)
		if !need {
			// write CONTINUE and resume replication
			if err := c.writeRESP(redis.NewString("CONTINUE")); err != nil {
				log.Errorf("reply slave %s psync CONTINUE err - %s", c, err)
				c.Close()
				return nil, errors.Trace(err)
			}

			h.counters.syncPartialOK.Add(1)

			h.startSlaveReplication(c, syncOffset)
			return nil, nil
		}

		// we must handle full resync
		if err := h.replicationReplyFullReSync(c); err != nil {
			return nil, errors.Trace(err)
		}

		// slave will use ? to force resync, this is not error
		if !bytes.Equal(args[0], []byte{'?'}) {
			h.counters.syncPartialErr.Add(1)
		}
	}

	offset, resp, err := h.replicationSlaveFullSync(c)
	if err != nil {
		return resp, errors.Trace(err)
	}

	h.startSlaveReplication(c, offset)

	return nil, nil
}
예제 #14
0
파일: misc.go 프로젝트: vebin/reborn
// AUTH password
func AuthCmd(s Session, args [][]byte) (redis.Resp, error) {
	if len(args) != 1 {
		return toRespErrorf("len(args) = %d, expect = 1", len(args))
	}

	c, _ := s.(*conn)
	if c == nil {
		return nil, errors.New("invalid connection")
	}

	if len(c.h.config.Auth) == 0 {
		return toRespErrorf("Client sent AUTH, but no password is set")
	} else if c.h.config.Auth == string(args[0]) {
		c.authenticated = true
		return redis.NewString("OK"), nil
	} else {
		c.authenticated = false
		return toRespErrorf("invalid password")
	}
}
예제 #15
0
파일: repl.go 프로젝트: CowLeo/qdb
func (h *Handler) replicationReplyFullReSync(c *conn) error {
	// lock all to get the current master replication offset
	if err := c.Store().Acquire(); err != nil {
		return errors.Trace(err)
	}

	syncOffset := h.repl.masterOffset
	if h.repl.backlogBuf == nil {
		// we will increment the master offset by one when backlog buffer created
		syncOffset++
	}
	c.Store().Release()

	if err := c.writeRESP(redis.NewString(fmt.Sprintf("FULLRESYNC %s %d", h.runID, syncOffset))); err != nil {
		log.Errorf("reply slave %s psync FULLRESYNC err - %s", c, err)
		c.Close()
		return errors.Trace(err)
	}
	return nil
}
예제 #16
0
func (s *testStoreSuite) checkSlotsMgrt(c *C, r *bufio.Reader, w *bufio.Writer, cc chan error, expect ...interface{}) {
	if len(expect) != 0 {
		req1, err := redis.Decode(r)
		c.Assert(err, IsNil)

		cmd1, args1, err := redis.ParseArgs(req1)
		c.Assert(err, IsNil)
		c.Assert(cmd1, Equals, "select")
		c.Assert(len(args1), Equals, 1)

		err = redis.Encode(w, redis.NewString("OK"))
		c.Assert(err, IsNil)

		err = w.Flush()
		c.Assert(err, IsNil)

		req2, err := redis.Decode(r)
		cmd2, args2, err := redis.ParseArgs(req2)
		c.Assert(err, IsNil)
		c.Assert(cmd2, Equals, "slotsrestore")
		c.Assert(len(args2), Equals, len(expect))

		m := make(map[string]*struct {
			key, value string
			ttlms      uint64
		})
		for i := 0; i < len(expect)/3; i++ {
			v := &struct {
				key, value string
				ttlms      uint64
			}{key: expect[i*3].(string), value: expect[i*3+2].(string)}
			v.ttlms, err = ParseUint(expect[i*3+1])
			c.Assert(err, IsNil)
			m[v.key] = v
		}

		for i := 0; i < len(expect)/3; i++ {
			key := args2[i*3]
			ttlms := args2[i*3+1]
			value := args2[i*3+2]

			v := m[string(key)]
			c.Assert(v, NotNil)
			c.Assert(string(key), Equals, v.key)

			b, err := rdb.DecodeDump(value)
			c.Assert(err, IsNil)
			c.Assert(string(b.(rdb.String)), Equals, v.value)

			x, err := strconv.Atoi(string(ttlms))
			c.Assert(err, IsNil)

			if v.ttlms == 0 {
				c.Assert(x, Equals, 0)
			} else {
				c.Assert(x, Not(Equals), 0)
				c.Assert(math.Abs(float64(x)-float64(v.ttlms)) < 1000, Equals, true)
			}
		}

		err = redis.Encode(w, redis.NewString("OK"))
		c.Assert(err, IsNil)

		err = w.Flush()
		c.Assert(err, IsNil)
	}

	select {
	case err := <-cc:
		c.Assert(err, IsNil)
	case <-time.After(time.Second):
		c.Fatal("timeout error")
	}
}