333 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			333 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2014 Wandoujia Inc. All Rights Reserved.
 | |
| // Licensed under the MIT (MIT-LICENSE.txt) license.
 | |
| 
 | |
| package rdb
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/binary"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"math"
 | |
| 	"strconv"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	Version = 6
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	rdbTypeString = 0
 | |
| 	rdbTypeList   = 1
 | |
| 	rdbTypeSet    = 2
 | |
| 	rdbTypeZSet   = 3
 | |
| 	rdbTypeHash   = 4
 | |
| 
 | |
| 	rdbTypeHashZipmap  = 9
 | |
| 	rdbTypeListZiplist = 10
 | |
| 	rdbTypeSetIntset   = 11
 | |
| 	rdbTypeZSetZiplist = 12
 | |
| 	rdbTypeHashZiplist = 13
 | |
| 
 | |
| 	rdbFlagExpiryMS = 0xfc
 | |
| 	rdbFlagExpiry   = 0xfd
 | |
| 	rdbFlagSelectDB = 0xfe
 | |
| 	rdbFlagEOF      = 0xff
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	rdb6bitLen  = 0
 | |
| 	rdb14bitLen = 1
 | |
| 	rdb32bitLen = 2
 | |
| 	rdbEncVal   = 3
 | |
| 
 | |
| 	rdbEncInt8  = 0
 | |
| 	rdbEncInt16 = 1
 | |
| 	rdbEncInt32 = 2
 | |
| 	rdbEncLZF   = 3
 | |
| 
 | |
| 	rdbZiplist6bitlenString  = 0
 | |
| 	rdbZiplist14bitlenString = 1
 | |
| 	rdbZiplist32bitlenString = 2
 | |
| 
 | |
| 	rdbZiplistInt16 = 0xc0
 | |
| 	rdbZiplistInt32 = 0xd0
 | |
| 	rdbZiplistInt64 = 0xe0
 | |
| 	rdbZiplistInt24 = 0xf0
 | |
| 	rdbZiplistInt8  = 0xfe
 | |
| 	rdbZiplistInt4  = 15
 | |
| )
 | |
| 
 | |
| type rdbReader struct {
 | |
| 	raw   io.Reader
 | |
| 	buf   [8]byte
 | |
| 	nread int64
 | |
| }
 | |
| 
 | |
| func newRdbReader(r io.Reader) *rdbReader {
 | |
| 	return &rdbReader{raw: r}
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) Read(p []byte) (int, error) {
 | |
| 	n, err := r.raw.Read(p)
 | |
| 	r.nread += int64(n)
 | |
| 	return n, err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) offset() int64 {
 | |
| 	return r.nread
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readObject(otype byte) ([]byte, error) {
 | |
| 	var b bytes.Buffer
 | |
| 	r = newRdbReader(io.TeeReader(r, &b))
 | |
| 	switch otype {
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf("unknown object-type %02x", otype)
 | |
| 	case rdbTypeHashZipmap:
 | |
| 		fallthrough
 | |
| 	case rdbTypeListZiplist:
 | |
| 		fallthrough
 | |
| 	case rdbTypeSetIntset:
 | |
| 		fallthrough
 | |
| 	case rdbTypeZSetZiplist:
 | |
| 		fallthrough
 | |
| 	case rdbTypeHashZiplist:
 | |
| 		fallthrough
 | |
| 	case rdbTypeString:
 | |
| 		if _, err := r.readString(); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	case rdbTypeList, rdbTypeSet:
 | |
| 		if n, err := r.readLength(); err != nil {
 | |
| 			return nil, err
 | |
| 		} else {
 | |
| 			for i := 0; i < int(n); i++ {
 | |
| 				if _, err := r.readString(); err != nil {
 | |
| 					return nil, err
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	case rdbTypeZSet:
 | |
| 		if n, err := r.readLength(); err != nil {
 | |
| 			return nil, err
 | |
| 		} else {
 | |
| 			for i := 0; i < int(n); i++ {
 | |
| 				if _, err := r.readString(); err != nil {
 | |
| 					return nil, err
 | |
| 				}
 | |
| 				if _, err := r.readFloat(); err != nil {
 | |
| 					return nil, err
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	case rdbTypeHash:
 | |
| 		if n, err := r.readLength(); err != nil {
 | |
| 			return nil, err
 | |
| 		} else {
 | |
| 			for i := 0; i < int(n); i++ {
 | |
| 				if _, err := r.readString(); err != nil {
 | |
| 					return nil, err
 | |
| 				}
 | |
| 				if _, err := r.readString(); err != nil {
 | |
| 					return nil, err
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return b.Bytes(), nil
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readString() ([]byte, error) {
 | |
| 	length, encoded, err := r.readEncodedLength()
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if !encoded {
 | |
| 		return r.readBytes(int(length))
 | |
| 	}
 | |
| 	switch t := uint8(length); t {
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf("invalid encoded-string %02x", t)
 | |
| 	case rdbEncInt8:
 | |
| 		i, err := r.readInt8()
 | |
| 		return []byte(strconv.FormatInt(int64(i), 10)), err
 | |
| 	case rdbEncInt16:
 | |
| 		i, err := r.readInt16()
 | |
| 		return []byte(strconv.FormatInt(int64(i), 10)), err
 | |
| 	case rdbEncInt32:
 | |
| 		i, err := r.readInt32()
 | |
| 		return []byte(strconv.FormatInt(int64(i), 10)), err
 | |
| 	case rdbEncLZF:
 | |
| 		var inlen, outlen uint32
 | |
| 		if inlen, err = r.readLength(); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		if outlen, err = r.readLength(); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		if in, err := r.readBytes(int(inlen)); err != nil {
 | |
| 			return nil, err
 | |
| 		} else {
 | |
| 			return lzfDecompress(in, int(outlen))
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readEncodedLength() (length uint32, encoded bool, err error) {
 | |
| 	var u uint8
 | |
| 	if u, err = r.readUint8(); err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 	length = uint32(u & 0x3f)
 | |
| 	switch u >> 6 {
 | |
| 	case rdb6bitLen:
 | |
| 	case rdb14bitLen:
 | |
| 		u, err = r.readUint8()
 | |
| 		length = (length << 8) + uint32(u)
 | |
| 	case rdbEncVal:
 | |
| 		encoded = true
 | |
| 	default:
 | |
| 		length, err = r.readUint32BigEndian()
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readLength() (uint32, error) {
 | |
| 	length, encoded, err := r.readEncodedLength()
 | |
| 	if err == nil && encoded {
 | |
| 		err = fmt.Errorf("encoded-length")
 | |
| 	}
 | |
| 	return length, err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readFloat() (float64, error) {
 | |
| 	u, err := r.readUint8()
 | |
| 	if err != nil {
 | |
| 		return 0, err
 | |
| 	}
 | |
| 	switch u {
 | |
| 	case 253:
 | |
| 		return math.NaN(), nil
 | |
| 	case 254:
 | |
| 		return math.Inf(0), nil
 | |
| 	case 255:
 | |
| 		return math.Inf(-1), nil
 | |
| 	default:
 | |
| 		if b, err := r.readBytes(int(u)); err != nil {
 | |
| 			return 0, err
 | |
| 		} else {
 | |
| 			v, err := strconv.ParseFloat(string(b), 64)
 | |
| 			return v, err
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readByte() (byte, error) {
 | |
| 	b := r.buf[:1]
 | |
| 	_, err := r.Read(b)
 | |
| 	return b[0], err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readFull(p []byte) error {
 | |
| 	_, err := io.ReadFull(r, p)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readBytes(n int) ([]byte, error) {
 | |
| 	p := make([]byte, n)
 | |
| 	return p, r.readFull(p)
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readUint8() (uint8, error) {
 | |
| 	b, err := r.readByte()
 | |
| 	return uint8(b), err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readUint16() (uint16, error) {
 | |
| 	b := r.buf[:2]
 | |
| 	err := r.readFull(b)
 | |
| 	return binary.LittleEndian.Uint16(b), err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readUint32() (uint32, error) {
 | |
| 	b := r.buf[:4]
 | |
| 	err := r.readFull(b)
 | |
| 	return binary.LittleEndian.Uint32(b), err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readUint64() (uint64, error) {
 | |
| 	b := r.buf[:8]
 | |
| 	err := r.readFull(b)
 | |
| 	return binary.LittleEndian.Uint64(b), err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readUint32BigEndian() (uint32, error) {
 | |
| 	b := r.buf[:4]
 | |
| 	err := r.readFull(b)
 | |
| 	return binary.BigEndian.Uint32(b), err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readInt8() (int8, error) {
 | |
| 	u, err := r.readUint8()
 | |
| 	return int8(u), err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readInt16() (int16, error) {
 | |
| 	u, err := r.readUint16()
 | |
| 	return int16(u), err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readInt32() (int32, error) {
 | |
| 	u, err := r.readUint32()
 | |
| 	return int32(u), err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readInt64() (int64, error) {
 | |
| 	u, err := r.readUint64()
 | |
| 	return int64(u), err
 | |
| }
 | |
| 
 | |
| func (r *rdbReader) readInt32BigEndian() (int32, error) {
 | |
| 	u, err := r.readUint32BigEndian()
 | |
| 	return int32(u), err
 | |
| }
 | |
| 
 | |
| func lzfDecompress(in []byte, outlen int) (out []byte, err error) {
 | |
| 	defer func() {
 | |
| 		if x := recover(); x != nil {
 | |
| 			err = fmt.Errorf("decompress exception: %v", x)
 | |
| 		}
 | |
| 	}()
 | |
| 	out = make([]byte, outlen)
 | |
| 	i, o := 0, 0
 | |
| 	for i < len(in) {
 | |
| 		ctrl := int(in[i])
 | |
| 		i++
 | |
| 		if ctrl < 32 {
 | |
| 			for x := 0; x <= ctrl; x++ {
 | |
| 				out[o] = in[i]
 | |
| 				i++
 | |
| 				o++
 | |
| 			}
 | |
| 		} else {
 | |
| 			length := ctrl >> 5
 | |
| 			if length == 7 {
 | |
| 				length = length + int(in[i])
 | |
| 				i++
 | |
| 			}
 | |
| 			ref := o - ((ctrl & 0x1f) << 8) - int(in[i]) - 1
 | |
| 			i++
 | |
| 			for x := 0; x <= length+1; x++ {
 | |
| 				out[o] = out[ref]
 | |
| 				ref++
 | |
| 				o++
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	if o != outlen {
 | |
| 		return nil, fmt.Errorf("decompress length is %d != expected %d", o, outlen)
 | |
| 	}
 | |
| 	return out, nil
 | |
| }
 |