// SLOTSRESTORE key ttlms value [key ttlms value ...] func (s *Store) SlotsRestore(db uint32, args [][]byte) 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++ { key := args[i*3] ttlms, err := ParseInt(args[i*3+1]) if err != nil { return errArguments("parse args failed - %s", err) } value := args[i*3+2] expireat := int64(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: uint64(expireat), Value: obj, } } if err := s.acquire(); err != nil { return errors.Trace(err) } defer s.release() ms := &markSet{} bt := engine.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 := s.restore(bt, e.DB, e.Key, int64(e.ExpireAt), e.Value); err != nil { log.Warningf("restore object failed, db = %d, key = %v, err = %s", e.DB, e.Key, err) return errors.Trace(err) } ms.Set(e.Key) } fw := &Forward{DB: db, Op: "SlotsRestore", Args: args} return s.commit(bt, fw) }
// RESTORE key ttlms value func (s *Store) Restore(db uint32, args [][]byte) error { if len(args) != 3 { return errArguments("len(args) = %d, expect = 3", len(args)) } key := args[0] ttlms, err := ParseInt(args[1]) if err != nil { return errArguments("parse args failed - %s", err) } value := args[2] expireat := int64(0) if ttlms != 0 { if v, ok := TTLmsToExpireAt(ttlms); ok && v > 0 { expireat = v } else { return errArguments("parse ttlms = %d", ttlms) } } obj, err := rdb.DecodeDump(value) if err != nil { return errors.Trace(err) } if err := s.acquire(); err != nil { return errors.Trace(err) } defer s.release() fw := &Forward{DB: db, Op: "Restore", Args: args} bt := engine.NewBatch() if err := s.restore(bt, db, key, expireat, obj); err != nil { return errors.Trace(err) } return s.commit(bt, fw) }
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") } }