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() } } }