Beispiel #1
0
func newRDBLoader(reader *bufio.Reader, rbytes *atomic2.Int64, size int) chan *rdb.BinEntry {
	pipe := make(chan *rdb.BinEntry, size)
	go func() {
		defer close(pipe)
		l := rdb.NewLoader(stats.NewCountReader(reader, rbytes))
		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 #2
0
func TestBgsaveTo(t *testing.T) {
	c := client(t)
	k := random(t)
	checkok(t, c, "reset")
	const max = 100
	for i := 0; i < max; i++ {
		checkok(t, c, "set", k+strconv.Itoa(i), i)
	}
	path := "/tmp/testdb-dump.rdb"
	checkok(t, c, "bgsaveto", path)
	f, err := os.Open(path)
	checkerror(t, err, true)
	defer f.Close()
	l := rdb.NewLoader(f)
	checkerror(t, l.Header(), true)
	m := make(map[string][]byte)
	for {
		e, err := l.NextBinEntry()
		checkerror(t, err, true)
		if e == nil {
			break
		}
		checkerror(t, nil, e.DB == 0)
		checkerror(t, nil, e.ExpireAt == 0)
		m[string(e.Key)] = e.Value
	}
	checkerror(t, l.Footer(), true)
	for i := 0; i < max; i++ {
		b := m[k+strconv.Itoa(i)]
		o, err := rdb.DecodeDump(b)
		checkerror(t, err, true)
		x, ok := o.(rdb.String)
		checkerror(t, nil, ok)
		checkerror(t, nil, string(x) == string(rpdb.FormatInt(int64(i))))
	}
}
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 counter.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 := rpdb.ExpireAtToTTLms(entry.ExpireAt); ok && v > 0 {
						ttlms = v
					} else {
						ttlms = 1
					}
				}
				if err := c.Rpdb().SlotsRestore(db, key, 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()
		}
	}
}