// 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) }
func (s *testServiceSuite) TestBgsaveTo(c *C) { k := randomKey(c) s.checkOK(c, "flushall") const max = 100 for i := 0; i < max; i++ { s.checkOK(c, "set", k+strconv.Itoa(i), i) } path := "/tmp/testdb-dump.rdb" s.checkOK(c, "bgsaveto", path) f, err := os.Open(path) c.Assert(err, IsNil) defer f.Close() l := rdb.NewLoader(f) c.Assert(l.Header(), IsNil) m := make(map[string][]byte) for { e, err := l.NextBinEntry() c.Assert(err, IsNil) if e == nil { break } c.Assert(e.DB, Equals, uint32(0)) c.Assert(e.ExpireAt, Equals, uint64(0)) m[string(e.Key)] = e.Value } c.Assert(l.Footer(), IsNil) for i := 0; i < max; i++ { b := m[k+strconv.Itoa(i)] o, err := rdb.DecodeDump(b) c.Assert(err, IsNil) x, ok := o.(rdb.String) c.Assert(ok, Equals, true) c.Assert(string(x), Equals, string(store.FormatInt(int64(i)))) } }
// 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 err } if err := s.acquire(); err != nil { return 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 err } return s.commit(bt, fw) }
func (cmd *cmdDecode) decoderMain(ipipe <-chan *rdb.BinEntry, opipe chan<- string) { toText := func(p []byte) string { var b bytes.Buffer for _, c := range p { switch { case c >= '#' && c <= '~': b.WriteByte(c) default: b.WriteByte('.') } } return b.String() } toBase64 := func(p []byte) string { return base64.StdEncoding.EncodeToString(p) } toJson := func(o interface{}) string { b, err := json.Marshal(o) if err != nil { log.PanicError(err, "encode to json failed") } return string(b) } for e := range ipipe { o, err := rdb.DecodeDump(e.Value) if err != nil { log.PanicError(err, "decode failed") } var b bytes.Buffer switch obj := o.(type) { default: log.Panicf("unknown object %v", o) case rdb.String: o := &struct { DB uint32 `json:"db"` Type string `json:"type"` ExpireAt uint64 `json:"expireat"` Key string `json:"key"` Key64 string `json:"key64"` Value64 string `json:"value64"` }{ e.DB, "string", e.ExpireAt, toText(e.Key), toBase64(e.Key), toBase64(obj), } fmt.Fprintf(&b, "%s\n", toJson(o)) case rdb.List: for i, ele := range obj { o := &struct { DB uint32 `json:"db"` Type string `json:"type"` ExpireAt uint64 `json:"expireat"` Key string `json:"key"` Key64 string `json:"key64"` Index int `json:"index"` Value64 string `json:"value64"` }{ e.DB, "list", e.ExpireAt, toText(e.Key), toBase64(e.Key), i, toBase64(ele), } fmt.Fprintf(&b, "%s\n", toJson(o)) } case rdb.Hash: for _, ele := range obj { o := &struct { DB uint32 `json:"db"` Type string `json:"type"` ExpireAt uint64 `json:"expireat"` Key string `json:"key"` Key64 string `json:"key64"` Field string `json:"field"` Field64 string `json:"field64"` Value64 string `json:"value64"` }{ e.DB, "hash", e.ExpireAt, toText(e.Key), toBase64(e.Key), toText(ele.Field), toBase64(ele.Field), toBase64(ele.Value), } fmt.Fprintf(&b, "%s\n", toJson(o)) } case rdb.Set: for _, mem := range obj { o := &struct { DB uint32 `json:"db"` Type string `json:"type"` ExpireAt uint64 `json:"expireat"` Key string `json:"key"` Key64 string `json:"key64"` Member string `json:"member"` Member64 string `json:"member64"` }{ e.DB, "set", e.ExpireAt, toText(e.Key), toBase64(e.Key), toText(mem), toBase64(mem), } fmt.Fprintf(&b, "%s\n", toJson(o)) } case rdb.ZSet: for _, ele := range obj { o := &struct { DB uint32 `json:"db"` Type string `json:"type"` ExpireAt uint64 `json:"expireat"` Key string `json:"key"` Key64 string `json:"key64"` Member string `json:"member"` Member64 string `json:"member64"` Score float64 `json:"score"` }{ e.DB, "zset", e.ExpireAt, toText(e.Key), toBase64(e.Key), toText(ele.Member), toBase64(ele.Member), ele.Score, } fmt.Fprintf(&b, "%s\n", toJson(o)) } } cmd.nobjs.Incr() opipe <- b.String() } }
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") } }