Beispiel #1
0
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))))
	}
}
Beispiel #2
0
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
}
Beispiel #3
0
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()
		}
	}
}