Exemple #1
0
// SLOTSRESTORE key ttlms value [key ttlms value ...]
func (b *Rpdb) SlotsRestore(db uint32, args ...interface{}) error {
	if len(args) == 0 || len(args)%3 != 0 {
		return errArguments("len(args) = %d, expect != 0 && mod 3 = 0", len(args))
	}

	objs := make([]*rdb.ObjEntry, len(args)/3)
	for i := 0; i < len(objs); i++ {
		var key, value []byte
		var ttlms int64
		for j, ref := range []interface{}{&key, &ttlms, &value} {
			if err := parseArgument(args[i*3+j], ref); err != nil {
				return errArguments("parse args[%d] failed, %s", i*3+j, err)
			}
		}
		expireat := uint64(0)
		if ttlms != 0 {
			if v, ok := TTLmsToExpireAt(ttlms); ok && v > 0 {
				expireat = v
			} else {
				return errArguments("parse args[%d] ttlms = %d", i*3+1, ttlms)
			}
		}
		obj, err := rdb.DecodeDump(value)
		if err != nil {
			return errArguments("decode args[%d] failed, %s", i*3+2, err)
		}
		objs[i] = &rdb.ObjEntry{
			DB:       db,
			Key:      key,
			ExpireAt: expireat,
			Value:    obj,
		}
	}

	if err := b.acquire(); err != nil {
		return err
	}
	defer b.release()

	ms := &markSet{}
	bt := store.NewBatch()
	for i := len(objs) - 1; i >= 0; i-- {
		e := objs[i]
		if ms.Has(e.Key) {
			log.Debugf("[%d] restore batch, db = %d, key = %v, ignore", i, e.DB, e.Key)
			continue
		} else {
			log.Debugf("[%d] restore batch, db = %d, key = %v", i, e.DB, e.Key)
		}
		if err := b.restore(bt, e.DB, e.Key, e.ExpireAt, e.Value); err != nil {
			log.DebugErrorf(err, "restore object failed, db = %d, key = %v", e.DB, e.Key)
			return err
		}
		ms.Set(e.Key)
	}
	fw := &Forward{DB: db, Op: "SlotsRestore", Args: args}
	return b.commit(bt, fw)
}
Exemple #2
0
// SLOTSMGRTTAGONE host port timeout key
func (b *Rpdb) SlotsMgrtTagOne(db uint32, args ...interface{}) (int64, error) {
	if len(args) != 4 {
		return 0, errArguments("len(args) = %d, expect = 4", len(args))
	}

	var host string
	var port int64
	var ttlms uint64
	var key []byte
	for i, ref := range []interface{}{&host, &port, &ttlms, &key} {
		if err := parseArgument(args[i], ref); err != nil {
			return 0, errArguments("parse args[%d] failed, %s", i, err)
		}
	}
	var timeout = time.Duration(ttlms) * time.Millisecond
	if timeout == 0 {
		timeout = time.Second
	}
	addr := fmt.Sprintf("%s:%d", host, port)

	if err := b.acquire(); err != nil {
		return 0, err
	}
	defer b.release()

	log.Debugf("migrate one with tag, addr = %s, timeout = %d, db = %d, key = %v", addr, timeout, db, key)

	if tag := HashTag(key); len(tag) == len(key) {
		return b.migrateOne(addr, timeout, db, key)
	} else {
		return b.migrateTag(addr, timeout, db, tag)
	}
}
Exemple #3
0
func (b *Rpdb) restore(bt *store.Batch, db uint32, key []byte, expireat uint64, obj interface{}) error {
	_, err := b.deleteIfExists(bt, db, key)
	if err != nil {
		return err
	}

	if !IsExpired(expireat) {
		var o rpdbRow
		switch obj.(type) {
		default:
			return errors.Trace(ErrObjectValue)
		case rdb.String:
			o = newStringRow(db, key)
		case rdb.Hash:
			o = newHashRow(db, key)
		case rdb.List:
			o = newListRow(db, key)
		case rdb.ZSet:
			o = newZSetRow(db, key)
		case rdb.Set:
			o = newSetRow(db, key)
		}
		return o.storeObject(b, bt, expireat, obj)
	}

	log.Debugf("restore an expired object, db = %d, key = %v, expireat = %d", db, key, expireat)
	return nil
}
Exemple #4
0
func (b *Rpdb) migrate(addr string, timeout time.Duration, db uint32, keys ...[]byte) (int64, error) {
	var rows []rpdbRow
	var bins []*rdb.BinEntry

	for i, key := range keys {
		o, bin, err := loadBinEntry(b, db, key)
		if err != nil {
			return 0, err
		}
		if o == nil {
			log.Debugf("[%d] missing, db = %d, key = %v", i, db, key)
			continue
		}

		rows = append(rows, o)
		if bin != nil {
			log.Debugf("[%d] migrate, db = %d, key = %v, expireat = %d", i, db, key, o.GetExpireAt())
			bins = append(bins, bin)
		} else {
			log.Debugf("[%d] expired, db = %d, key = %v, expireat = %d", i, db, key, o.GetExpireAt())
		}
	}

	if len(bins) != 0 {
		if err := doMigrate(addr, timeout, db, bins); err != nil {
			return 0, err
		}
	}

	if len(rows) == 0 {
		return 0, nil
	}

	bt := store.NewBatch()
	for _, o := range rows {
		if err := o.deleteObject(b, bt); err != nil {
			return 0, err
		}
	}
	fw := &Forward{DB: db, Op: "Del"}
	for _, key := range keys {
		fw.Args = append(fw.Args, key)
	}
	return int64(len(rows)), b.commit(bt, fw)
}
Exemple #5
0
func doMigrate(addr string, timeout time.Duration, db uint32, bins []*rdb.BinEntry) error {
	c, err := getSockConn(addr, timeout)
	if err != nil {
		log.WarnErrorf(err, "connect to %s failed, timeout = %d", addr, timeout)
		return err
	}
	defer putSockConn(addr, c)

	cmd1 := redis.NewArray()
	cmd1.AppendBulkBytes([]byte("select"))
	cmd1.AppendBulkBytes([]byte(FormatUint(uint64(db))))

	if err := c.DoMustOK(cmd1, timeout); err != nil {
		log.WarnErrorf(err, "command select failed, addr = %s, db = %d", addr, db)
		return err
	}
	log.Debugf("command select ok, addr = %s, db = %d", addr, db)

	cmd2 := redis.NewArray()
	cmd2.AppendBulkBytes([]byte("slotsrestore"))
	for _, bin := range bins {
		cmd2.AppendBulkBytes(bin.Key)
		ttlms := int64(0)
		if bin.ExpireAt != 0 {
			if v, ok := ExpireAtToTTLms(bin.ExpireAt); ok && v > 0 {
				ttlms = v
			} else {
				ttlms = 1
			}
		}
		cmd2.AppendBulkBytes([]byte(FormatInt(ttlms)))
		cmd2.AppendBulkBytes(bin.Value)
	}

	if err := c.DoMustOK(cmd2, timeout); err != nil {
		log.WarnErrorf(err, "command restore failed, addr = %s, db = %d, len(bins) = %d", addr, db, len(bins))
		return err
	} else {
		log.Debugf("command restore ok, addr = %s, db = %d, len(bins) = %d", addr, db, len(bins))
		return nil
	}
}
Exemple #6
0
// SLOTSMGRTSLOT host port timeout slot
func (b *Rpdb) SlotsMgrtSlot(db uint32, args ...interface{}) (int64, error) {
	if len(args) != 4 {
		return 0, errArguments("len(args) = %d, expect = 4", len(args))
	}

	var host string
	var port int64
	var ttlms uint64
	var slot uint32
	for i, ref := range []interface{}{&host, &port, &ttlms, &slot} {
		if err := parseArgument(args[i], ref); err != nil {
			return 0, errArguments("parse args[%d] failed, %s", i, err)
		}
	}
	var timeout = time.Duration(ttlms) * time.Millisecond
	if slot >= MaxSlotNum {
		return 0, errArguments("slot = %d", slot)
	}
	if timeout == 0 {
		timeout = time.Second
	}
	addr := fmt.Sprintf("%s:%d", host, port)

	if err := b.acquire(); err != nil {
		return 0, err
	}
	defer b.release()

	log.Debugf("migrate slot, addr = %s, timeout = %d, db = %d, slot = %d", addr, timeout, db, slot)

	key, err := firstKeyUnderSlot(b, db, slot)
	if err != nil || key == nil {
		return 0, err
	}
	return b.migrateOne(addr, timeout, db, key)
}