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 }
func TestEncodeRdb(t *testing.T) { objs := make([]struct { db uint32 expireat uint64 key []byte obj interface{} typ string }, 128) var b bytes.Buffer enc := NewEncoder(&b) assert.MustNoError(enc.EncodeHeader()) for i := 0; i < len(objs); i++ { db := uint32(i + 32) expireat := uint64(i) key := []byte(strconv.Itoa(i)) var obj interface{} var typ string switch i % 5 { case 0: s := strconv.Itoa(i) obj = s typ = "string" assert.MustNoError(enc.EncodeObject(db, key, expireat, toString(s))) case 1: list := []string{} for j := 0; j < 32; j++ { list = append(list, fmt.Sprintf("l%d_%d", i, rand.Int())) } obj = list typ = "list" assert.MustNoError(enc.EncodeObject(db, key, expireat, toList(list...))) case 2: hash := make(map[string]string) for j := 0; j < 32; j++ { hash[strconv.Itoa(j)] = fmt.Sprintf("h%d_%d", i, rand.Int()) } obj = hash typ = "hash" assert.MustNoError(enc.EncodeObject(db, key, expireat, toHash(hash))) case 3: zset := make(map[string]float64) for j := 0; j < 32; j++ { zset[strconv.Itoa(j)] = rand.Float64() } obj = zset typ = "zset" assert.MustNoError(enc.EncodeObject(db, key, expireat, toZSet(zset))) case 4: set := []string{} for j := 0; j < 32; j++ { set = append(set, fmt.Sprintf("s%d_%d", i, rand.Int())) } obj = set typ = "set" assert.MustNoError(enc.EncodeObject(db, key, expireat, toSet(set...))) } objs[i].db = db objs[i].expireat = expireat objs[i].key = key objs[i].obj = obj objs[i].typ = typ } assert.MustNoError(enc.EncodeFooter()) rdb := b.Bytes() var c atomic2.Int64 l := NewLoader(stats.NewCountReader(bytes.NewReader(rdb), &c)) assert.MustNoError(l.Header()) var i int = 0 for { e, err := l.NextBinEntry() assert.MustNoError(err) if e == nil { break } assert.Must(objs[i].db == e.DB) assert.Must(objs[i].expireat == e.ExpireAt) assert.Must(bytes.Equal(objs[i].key, e.Key)) o, err := DecodeDump(e.Value) assert.MustNoError(err) switch objs[i].typ { case "string": checkString(t, o, objs[i].obj.(string)) case "list": checkList(t, o, objs[i].obj.([]string)) case "hash": checkHash(t, o, objs[i].obj.(map[string]string)) case "zset": checkZSet(t, o, objs[i].obj.(map[string]float64)) case "set": checkSet(t, o, objs[i].obj.([]string)) } i++ } assert.Must(i == len(objs)) assert.MustNoError(l.Footer()) assert.Must(c.Get() == int64(len(rdb))) }