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)))) } }
func newRDBLoader(reader *bufio.Reader, size int) chan *rdb.BinEntry { pipe := make(chan *rdb.BinEntry, size) go func() { defer close(pipe) l := rdb.NewLoader(reader) if err := l.Header(); err != nil { log.PanicError(err, "parse rdb header error") } for { if entry, err := l.NextBinEntry(); err != nil { log.PanicError(err, "parse rdb entry error") } else { if entry != nil { pipe <- entry } else { if err := l.Footer(); err != nil { log.PanicError(err, "parse rdb checksum error") } return } } } }() return pipe }
func (h *Handler) doSyncRDB(c *conn, size int64) error { defer h.counters.syncRdbRemains.Set(0) h.counters.syncRdbRemains.Set(size) r := ioutils.NewCountReader(c.r, nil) l := rdb.NewLoader(r) if err := l.Header(); err != nil { return err } ncpu := runtime.GOMAXPROCS(0) errs := make(chan error, ncpu) var lock sync.Mutex var flag atomic2.Int64 loadNextEntry := func() (*rdb.BinEntry, error) { lock.Lock() defer lock.Unlock() if flag.Get() != 0 { return nil, nil } entry, err := l.NextBinEntry() if err != nil || entry == nil { flag.Set(1) return nil, err } return entry, nil } for i := 0; i < ncpu; i++ { go func() { defer flag.Set(1) for { entry, err := loadNextEntry() if err != nil || entry == nil { errs <- err return } db, key, value := entry.DB, entry.Key, entry.Value ttlms := int64(0) if entry.ExpireAt != 0 { if v, ok := store.ExpireAtToTTLms(int64(entry.ExpireAt)); ok && v > 0 { ttlms = v } else { ttlms = 1 } } if err := c.Store().SlotsRestore(db, [][]byte{key, store.FormatInt(ttlms), value}); err != nil { errs <- err return } } }() } for { select { case <-time.After(time.Second): h.counters.syncRdbRemains.Set(size - r.Count()) case err := <-errs: for i := 1; i < cap(errs); i++ { e := <-errs if err == nil && e != nil { err = e } } if err != nil { return err } return l.Footer() } } }