forked from mirror/ledisdb
113 lines
2.2 KiB
Go
113 lines
2.2 KiB
Go
// Copyright 2014 Wandoujia Inc. All Rights Reserved.
|
|
// Licensed under the MIT (MIT-LICENSE.txt) license.
|
|
|
|
package rdb
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"hash"
|
|
"io"
|
|
"strconv"
|
|
)
|
|
|
|
type Loader struct {
|
|
*rdbReader
|
|
crc hash.Hash64
|
|
db uint32
|
|
}
|
|
|
|
func NewLoader(r io.Reader) *Loader {
|
|
l := &Loader{}
|
|
l.crc = newDigest()
|
|
l.rdbReader = newRdbReader(io.TeeReader(r, l.crc))
|
|
return l
|
|
}
|
|
|
|
func (l *Loader) LoadHeader() error {
|
|
header := make([]byte, 9)
|
|
if err := l.readFull(header); err != nil {
|
|
return err
|
|
}
|
|
if !bytes.Equal(header[:5], []byte("REDIS")) {
|
|
return fmt.Errorf("verify magic string, invalid file format")
|
|
}
|
|
if version, err := strconv.ParseInt(string(header[5:]), 10, 64); err != nil {
|
|
return err
|
|
} else if version <= 0 || version > Version {
|
|
return fmt.Errorf("verify version, invalid RDB version number %d", version)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (l *Loader) LoadChecksum() error {
|
|
crc1 := l.crc.Sum64()
|
|
if crc2, err := l.readUint64(); err != nil {
|
|
return err
|
|
} else if crc1 != crc2 {
|
|
return fmt.Errorf("checksum validation failed")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Entry struct {
|
|
DB uint32
|
|
Key []byte
|
|
ValDump []byte
|
|
ExpireAt uint64
|
|
}
|
|
|
|
func (l *Loader) LoadEntry() (entry *Entry, err error) {
|
|
var expireat uint64
|
|
for {
|
|
var otype byte
|
|
if otype, err = l.readByte(); err != nil {
|
|
return
|
|
}
|
|
switch otype {
|
|
case rdbFlagExpiryMS:
|
|
if expireat, err = l.readUint64(); err != nil {
|
|
return
|
|
}
|
|
case rdbFlagExpiry:
|
|
var sec uint32
|
|
if sec, err = l.readUint32(); err != nil {
|
|
return
|
|
}
|
|
expireat = uint64(sec) * 1000
|
|
case rdbFlagSelectDB:
|
|
if l.db, err = l.readLength(); err != nil {
|
|
return
|
|
}
|
|
case rdbFlagEOF:
|
|
return
|
|
default:
|
|
var key, obj []byte
|
|
if key, err = l.readString(); err != nil {
|
|
return
|
|
}
|
|
if obj, err = l.readObject(otype); err != nil {
|
|
return
|
|
}
|
|
entry = &Entry{}
|
|
entry.DB = l.db
|
|
entry.Key = key
|
|
entry.ValDump = createValDump(otype, obj)
|
|
entry.ExpireAt = expireat
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func createValDump(otype byte, obj []byte) []byte {
|
|
var b bytes.Buffer
|
|
c := newDigest()
|
|
w := io.MultiWriter(&b, c)
|
|
w.Write([]byte{otype})
|
|
w.Write(obj)
|
|
binary.Write(w, binary.LittleEndian, uint16(Version))
|
|
binary.Write(w, binary.LittleEndian, c.Sum64())
|
|
return b.Bytes()
|
|
}
|