1
0
mirror of https://github.com/astaxie/beego.git synced 2025-07-05 11:00:17 +00:00

update mod

This commit is contained in:
astaxie
2018-11-09 12:37:28 +08:00
parent 9fdc1eaf3a
commit 5ea04bdfd3
548 changed files with 339257 additions and 46 deletions

25
vendor/github.com/cupcake/rdb/.gitignore generated vendored Normal file
View File

@ -0,0 +1,25 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
# Project-specific files
diff

6
vendor/github.com/cupcake/rdb/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,6 @@
language: go
go:
- 1.1
- tip
before_install:
- go get gopkg.in/check.v1

21
vendor/github.com/cupcake/rdb/LICENCE generated vendored Normal file
View File

@ -0,0 +1,21 @@
Copyright (c) 2012 Jonathan Rudenberg
Copyright (c) 2012 Sripathi Krishnan
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

17
vendor/github.com/cupcake/rdb/README.md generated vendored Normal file
View File

@ -0,0 +1,17 @@
# rdb [![Build Status](https://travis-ci.org/cupcake/rdb.png?branch=master)](https://travis-ci.org/cupcake/rdb)
rdb is a Go package that implements parsing and encoding of the
[Redis](http://redis.io) [RDB file
format](https://github.com/sripathikrishnan/redis-rdb-tools/blob/master/docs/RDB_File_Format.textile).
This package was heavily inspired by
[redis-rdb-tools](https://github.com/sripathikrishnan/redis-rdb-tools) by
[Sripathi Krishnan](https://github.com/sripathikrishnan).
[**Documentation**](http://godoc.org/github.com/cupcake/rdb)
## Installation
```
go get github.com/cupcake/rdb
```

64
vendor/github.com/cupcake/rdb/crc64/crc64.go generated vendored Normal file

File diff suppressed because one or more lines are too long

824
vendor/github.com/cupcake/rdb/decoder.go generated vendored Normal file
View File

@ -0,0 +1,824 @@
// Package rdb implements parsing and encoding of the Redis RDB file format.
package rdb
import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
"github.com/cupcake/rdb/crc64"
)
// A Decoder must be implemented to parse a RDB file.
type Decoder interface {
// StartRDB is called when parsing of a valid RDB file starts.
StartRDB()
// StartDatabase is called when database n starts.
// Once a database starts, another database will not start until EndDatabase is called.
StartDatabase(n int)
// AUX field
Aux(key, value []byte)
// ResizeDB hint
ResizeDatabase(dbSize, expiresSize uint32)
// Set is called once for each string key.
Set(key, value []byte, expiry int64)
// StartHash is called at the beginning of a hash.
// Hset will be called exactly length times before EndHash.
StartHash(key []byte, length, expiry int64)
// Hset is called once for each field=value pair in a hash.
Hset(key, field, value []byte)
// EndHash is called when there are no more fields in a hash.
EndHash(key []byte)
// StartSet is called at the beginning of a set.
// Sadd will be called exactly cardinality times before EndSet.
StartSet(key []byte, cardinality, expiry int64)
// Sadd is called once for each member of a set.
Sadd(key, member []byte)
// EndSet is called when there are no more fields in a set.
EndSet(key []byte)
// StartList is called at the beginning of a list.
// Rpush will be called exactly length times before EndList.
// If length of the list is not known, then length is -1
StartList(key []byte, length, expiry int64)
// Rpush is called once for each value in a list.
Rpush(key, value []byte)
// EndList is called when there are no more values in a list.
EndList(key []byte)
// StartZSet is called at the beginning of a sorted set.
// Zadd will be called exactly cardinality times before EndZSet.
StartZSet(key []byte, cardinality, expiry int64)
// Zadd is called once for each member of a sorted set.
Zadd(key []byte, score float64, member []byte)
// EndZSet is called when there are no more members in a sorted set.
EndZSet(key []byte)
// EndDatabase is called at the end of a database.
EndDatabase(n int)
// EndRDB is called when parsing of the RDB file is complete.
EndRDB()
}
// Decode parses a RDB file from r and calls the decode hooks on d.
func Decode(r io.Reader, d Decoder) error {
decoder := &decode{d, make([]byte, 8), bufio.NewReader(r)}
return decoder.decode()
}
// Decode a byte slice from the Redis DUMP command. The dump does not contain the
// database, key or expiry, so they must be included in the function call (but
// can be zero values).
func DecodeDump(dump []byte, db int, key []byte, expiry int64, d Decoder) error {
err := verifyDump(dump)
if err != nil {
return err
}
decoder := &decode{d, make([]byte, 8), bytes.NewReader(dump[1:])}
decoder.event.StartRDB()
decoder.event.StartDatabase(db)
err = decoder.readObject(key, ValueType(dump[0]), expiry)
decoder.event.EndDatabase(db)
decoder.event.EndRDB()
return err
}
type byteReader interface {
io.Reader
io.ByteReader
}
type decode struct {
event Decoder
intBuf []byte
r byteReader
}
type ValueType byte
const (
TypeString ValueType = 0
TypeList ValueType = 1
TypeSet ValueType = 2
TypeZSet ValueType = 3
TypeHash ValueType = 4
TypeHashZipmap ValueType = 9
TypeListZiplist ValueType = 10
TypeSetIntset ValueType = 11
TypeZSetZiplist ValueType = 12
TypeHashZiplist ValueType = 13
TypeListQuicklist ValueType = 14
)
const (
rdb6bitLen = 0
rdb14bitLen = 1
rdb32bitLen = 2
rdbEncVal = 3
rdbFlagAux = 0xfa
rdbFlagResizeDB = 0xfb
rdbFlagExpiryMS = 0xfc
rdbFlagExpiry = 0xfd
rdbFlagSelectDB = 0xfe
rdbFlagEOF = 0xff
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
)
func (d *decode) decode() error {
err := d.checkHeader()
if err != nil {
return err
}
d.event.StartRDB()
var db uint32
var expiry int64
firstDB := true
for {
objType, err := d.r.ReadByte()
if err != nil {
return err
}
switch objType {
case rdbFlagAux:
auxKey, err := d.readString()
if err != nil {
return err
}
auxVal, err := d.readString()
if err != nil {
return err
}
d.event.Aux(auxKey, auxVal)
case rdbFlagResizeDB:
dbSize, _, err := d.readLength()
if err != nil {
return err
}
expiresSize, _, err := d.readLength()
if err != nil {
return err
}
d.event.ResizeDatabase(dbSize, expiresSize)
case rdbFlagExpiryMS:
_, err := io.ReadFull(d.r, d.intBuf)
if err != nil {
return err
}
expiry = int64(binary.LittleEndian.Uint64(d.intBuf))
case rdbFlagExpiry:
_, err := io.ReadFull(d.r, d.intBuf[:4])
if err != nil {
return err
}
expiry = int64(binary.LittleEndian.Uint32(d.intBuf)) * 1000
case rdbFlagSelectDB:
if !firstDB {
d.event.EndDatabase(int(db))
}
db, _, err = d.readLength()
if err != nil {
return err
}
d.event.StartDatabase(int(db))
case rdbFlagEOF:
d.event.EndDatabase(int(db))
d.event.EndRDB()
return nil
default:
key, err := d.readString()
if err != nil {
return err
}
err = d.readObject(key, ValueType(objType), expiry)
if err != nil {
return err
}
expiry = 0
}
}
panic("not reached")
}
func (d *decode) readObject(key []byte, typ ValueType, expiry int64) error {
switch typ {
case TypeString:
value, err := d.readString()
if err != nil {
return err
}
d.event.Set(key, value, expiry)
case TypeList:
length, _, err := d.readLength()
if err != nil {
return err
}
d.event.StartList(key, int64(length), expiry)
for i := uint32(0); i < length; i++ {
value, err := d.readString()
if err != nil {
return err
}
d.event.Rpush(key, value)
}
d.event.EndList(key)
case TypeListQuicklist:
length, _, err := d.readLength()
if err != nil {
return err
}
d.event.StartList(key, int64(-1), expiry)
for i := uint32(0); i < length; i++ {
d.readZiplist(key, 0, false)
}
d.event.EndList(key)
case TypeSet:
cardinality, _, err := d.readLength()
if err != nil {
return err
}
d.event.StartSet(key, int64(cardinality), expiry)
for i := uint32(0); i < cardinality; i++ {
member, err := d.readString()
if err != nil {
return err
}
d.event.Sadd(key, member)
}
d.event.EndSet(key)
case TypeZSet:
cardinality, _, err := d.readLength()
if err != nil {
return err
}
d.event.StartZSet(key, int64(cardinality), expiry)
for i := uint32(0); i < cardinality; i++ {
member, err := d.readString()
if err != nil {
return err
}
score, err := d.readFloat64()
if err != nil {
return err
}
d.event.Zadd(key, score, member)
}
d.event.EndZSet(key)
case TypeHash:
length, _, err := d.readLength()
if err != nil {
return err
}
d.event.StartHash(key, int64(length), expiry)
for i := uint32(0); i < length; i++ {
field, err := d.readString()
if err != nil {
return err
}
value, err := d.readString()
if err != nil {
return err
}
d.event.Hset(key, field, value)
}
d.event.EndHash(key)
case TypeHashZipmap:
return d.readZipmap(key, expiry)
case TypeListZiplist:
return d.readZiplist(key, expiry, true)
case TypeSetIntset:
return d.readIntset(key, expiry)
case TypeZSetZiplist:
return d.readZiplistZset(key, expiry)
case TypeHashZiplist:
return d.readZiplistHash(key, expiry)
default:
return fmt.Errorf("rdb: unknown object type %d for key %s", typ, key)
}
return nil
}
func (d *decode) readZipmap(key []byte, expiry int64) error {
var length int
zipmap, err := d.readString()
if err != nil {
return err
}
buf := newSliceBuffer(zipmap)
lenByte, err := buf.ReadByte()
if err != nil {
return err
}
if lenByte >= 254 { // we need to count the items manually
length, err = countZipmapItems(buf)
length /= 2
if err != nil {
return err
}
} else {
length = int(lenByte)
}
d.event.StartHash(key, int64(length), expiry)
for i := 0; i < length; i++ {
field, err := readZipmapItem(buf, false)
if err != nil {
return err
}
value, err := readZipmapItem(buf, true)
if err != nil {
return err
}
d.event.Hset(key, field, value)
}
d.event.EndHash(key)
return nil
}
func readZipmapItem(buf *sliceBuffer, readFree bool) ([]byte, error) {
length, free, err := readZipmapItemLength(buf, readFree)
if err != nil {
return nil, err
}
if length == -1 {
return nil, nil
}
value, err := buf.Slice(length)
if err != nil {
return nil, err
}
_, err = buf.Seek(int64(free), 1)
return value, err
}
func countZipmapItems(buf *sliceBuffer) (int, error) {
n := 0
for {
strLen, free, err := readZipmapItemLength(buf, n%2 != 0)
if err != nil {
return 0, err
}
if strLen == -1 {
break
}
_, err = buf.Seek(int64(strLen)+int64(free), 1)
if err != nil {
return 0, err
}
n++
}
_, err := buf.Seek(0, 0)
return n, err
}
func readZipmapItemLength(buf *sliceBuffer, readFree bool) (int, int, error) {
b, err := buf.ReadByte()
if err != nil {
return 0, 0, err
}
switch b {
case 253:
s, err := buf.Slice(5)
if err != nil {
return 0, 0, err
}
return int(binary.BigEndian.Uint32(s)), int(s[4]), nil
case 254:
return 0, 0, fmt.Errorf("rdb: invalid zipmap item length")
case 255:
return -1, 0, nil
}
var free byte
if readFree {
free, err = buf.ReadByte()
}
return int(b), int(free), err
}
func (d *decode) readZiplist(key []byte, expiry int64, addListEvents bool) error {
ziplist, err := d.readString()
if err != nil {
return err
}
buf := newSliceBuffer(ziplist)
length, err := readZiplistLength(buf)
if err != nil {
return err
}
if addListEvents {
d.event.StartList(key, length, expiry)
}
for i := int64(0); i < length; i++ {
entry, err := readZiplistEntry(buf)
if err != nil {
return err
}
d.event.Rpush(key, entry)
}
if addListEvents {
d.event.EndList(key)
}
return nil
}
func (d *decode) readZiplistZset(key []byte, expiry int64) error {
ziplist, err := d.readString()
if err != nil {
return err
}
buf := newSliceBuffer(ziplist)
cardinality, err := readZiplistLength(buf)
if err != nil {
return err
}
cardinality /= 2
d.event.StartZSet(key, cardinality, expiry)
for i := int64(0); i < cardinality; i++ {
member, err := readZiplistEntry(buf)
if err != nil {
return err
}
scoreBytes, err := readZiplistEntry(buf)
if err != nil {
return err
}
score, err := strconv.ParseFloat(string(scoreBytes), 64)
if err != nil {
return err
}
d.event.Zadd(key, score, member)
}
d.event.EndZSet(key)
return nil
}
func (d *decode) readZiplistHash(key []byte, expiry int64) error {
ziplist, err := d.readString()
if err != nil {
return err
}
buf := newSliceBuffer(ziplist)
length, err := readZiplistLength(buf)
if err != nil {
return err
}
length /= 2
d.event.StartHash(key, length, expiry)
for i := int64(0); i < length; i++ {
field, err := readZiplistEntry(buf)
if err != nil {
return err
}
value, err := readZiplistEntry(buf)
if err != nil {
return err
}
d.event.Hset(key, field, value)
}
d.event.EndHash(key)
return nil
}
func readZiplistLength(buf *sliceBuffer) (int64, error) {
buf.Seek(8, 0) // skip the zlbytes and zltail
lenBytes, err := buf.Slice(2)
if err != nil {
return 0, err
}
return int64(binary.LittleEndian.Uint16(lenBytes)), nil
}
func readZiplistEntry(buf *sliceBuffer) ([]byte, error) {
prevLen, err := buf.ReadByte()
if err != nil {
return nil, err
}
if prevLen == 254 {
buf.Seek(4, 1) // skip the 4-byte prevlen
}
header, err := buf.ReadByte()
if err != nil {
return nil, err
}
switch {
case header>>6 == rdbZiplist6bitlenString:
return buf.Slice(int(header & 0x3f))
case header>>6 == rdbZiplist14bitlenString:
b, err := buf.ReadByte()
if err != nil {
return nil, err
}
return buf.Slice((int(header&0x3f) << 8) | int(b))
case header>>6 == rdbZiplist32bitlenString:
lenBytes, err := buf.Slice(4)
if err != nil {
return nil, err
}
return buf.Slice(int(binary.BigEndian.Uint32(lenBytes)))
case header == rdbZiplistInt16:
intBytes, err := buf.Slice(2)
if err != nil {
return nil, err
}
return []byte(strconv.FormatInt(int64(int16(binary.LittleEndian.Uint16(intBytes))), 10)), nil
case header == rdbZiplistInt32:
intBytes, err := buf.Slice(4)
if err != nil {
return nil, err
}
return []byte(strconv.FormatInt(int64(int32(binary.LittleEndian.Uint32(intBytes))), 10)), nil
case header == rdbZiplistInt64:
intBytes, err := buf.Slice(8)
if err != nil {
return nil, err
}
return []byte(strconv.FormatInt(int64(binary.LittleEndian.Uint64(intBytes)), 10)), nil
case header == rdbZiplistInt24:
intBytes := make([]byte, 4)
_, err := buf.Read(intBytes[1:])
if err != nil {
return nil, err
}
return []byte(strconv.FormatInt(int64(int32(binary.LittleEndian.Uint32(intBytes))>>8), 10)), nil
case header == rdbZiplistInt8:
b, err := buf.ReadByte()
return []byte(strconv.FormatInt(int64(int8(b)), 10)), err
case header>>4 == rdbZiplistInt4:
return []byte(strconv.FormatInt(int64(header&0x0f)-1, 10)), nil
}
return nil, fmt.Errorf("rdb: unknown ziplist header byte: %d", header)
}
func (d *decode) readIntset(key []byte, expiry int64) error {
intset, err := d.readString()
if err != nil {
return err
}
buf := newSliceBuffer(intset)
intSizeBytes, err := buf.Slice(4)
if err != nil {
return err
}
intSize := binary.LittleEndian.Uint32(intSizeBytes)
if intSize != 2 && intSize != 4 && intSize != 8 {
return fmt.Errorf("rdb: unknown intset encoding: %d", intSize)
}
lenBytes, err := buf.Slice(4)
if err != nil {
return err
}
cardinality := binary.LittleEndian.Uint32(lenBytes)
d.event.StartSet(key, int64(cardinality), expiry)
for i := uint32(0); i < cardinality; i++ {
intBytes, err := buf.Slice(int(intSize))
if err != nil {
return err
}
var intString string
switch intSize {
case 2:
intString = strconv.FormatInt(int64(int16(binary.LittleEndian.Uint16(intBytes))), 10)
case 4:
intString = strconv.FormatInt(int64(int32(binary.LittleEndian.Uint32(intBytes))), 10)
case 8:
intString = strconv.FormatInt(int64(int64(binary.LittleEndian.Uint64(intBytes))), 10)
}
d.event.Sadd(key, []byte(intString))
}
d.event.EndSet(key)
return nil
}
func (d *decode) checkHeader() error {
header := make([]byte, 9)
_, err := io.ReadFull(d.r, header)
if err != nil {
return err
}
if !bytes.Equal(header[:5], []byte("REDIS")) {
return fmt.Errorf("rdb: invalid file format")
}
version, _ := strconv.ParseInt(string(header[5:]), 10, 64)
if version < 1 || version > 7 {
return fmt.Errorf("rdb: invalid RDB version number %d", version)
}
return nil
}
func (d *decode) readString() ([]byte, error) {
length, encoded, err := d.readLength()
if err != nil {
return nil, err
}
if encoded {
switch length {
case rdbEncInt8:
i, err := d.readUint8()
return []byte(strconv.FormatInt(int64(int8(i)), 10)), err
case rdbEncInt16:
i, err := d.readUint16()
return []byte(strconv.FormatInt(int64(int16(i)), 10)), err
case rdbEncInt32:
i, err := d.readUint32()
return []byte(strconv.FormatInt(int64(int32(i)), 10)), err
case rdbEncLZF:
clen, _, err := d.readLength()
if err != nil {
return nil, err
}
ulen, _, err := d.readLength()
if err != nil {
return nil, err
}
compressed := make([]byte, clen)
_, err = io.ReadFull(d.r, compressed)
if err != nil {
return nil, err
}
decompressed := lzfDecompress(compressed, int(ulen))
if len(decompressed) != int(ulen) {
return nil, fmt.Errorf("decompressed string length %d didn't match expected length %d", len(decompressed), ulen)
}
return decompressed, nil
}
}
str := make([]byte, length)
_, err = io.ReadFull(d.r, str)
return str, err
}
func (d *decode) readUint8() (uint8, error) {
b, err := d.r.ReadByte()
return uint8(b), err
}
func (d *decode) readUint16() (uint16, error) {
_, err := io.ReadFull(d.r, d.intBuf[:2])
if err != nil {
return 0, err
}
return binary.LittleEndian.Uint16(d.intBuf), nil
}
func (d *decode) readUint32() (uint32, error) {
_, err := io.ReadFull(d.r, d.intBuf[:4])
if err != nil {
return 0, err
}
return binary.LittleEndian.Uint32(d.intBuf), nil
}
func (d *decode) readUint64() (uint64, error) {
_, err := io.ReadFull(d.r, d.intBuf)
if err != nil {
return 0, err
}
return binary.LittleEndian.Uint64(d.intBuf), nil
}
func (d *decode) readUint32Big() (uint32, error) {
_, err := io.ReadFull(d.r, d.intBuf[:4])
if err != nil {
return 0, err
}
return binary.BigEndian.Uint32(d.intBuf), nil
}
// Doubles are saved as strings prefixed by an unsigned
// 8 bit integer specifying the length of the representation.
// This 8 bit integer has special values in order to specify the following
// conditions:
// 253: not a number
// 254: + inf
// 255: - inf
func (d *decode) readFloat64() (float64, error) {
length, err := d.readUint8()
if err != nil {
return 0, err
}
switch length {
case 253:
return math.NaN(), nil
case 254:
return math.Inf(0), nil
case 255:
return math.Inf(-1), nil
default:
floatBytes := make([]byte, length)
_, err := io.ReadFull(d.r, floatBytes)
if err != nil {
return 0, err
}
f, err := strconv.ParseFloat(string(floatBytes), 64)
return f, err
}
panic("not reached")
}
func (d *decode) readLength() (uint32, bool, error) {
b, err := d.r.ReadByte()
if err != nil {
return 0, false, err
}
// The first two bits of the first byte are used to indicate the length encoding type
switch (b & 0xc0) >> 6 {
case rdb6bitLen:
// When the first two bits are 00, the next 6 bits are the length.
return uint32(b & 0x3f), false, nil
case rdb14bitLen:
// When the first two bits are 01, the next 14 bits are the length.
bb, err := d.r.ReadByte()
if err != nil {
return 0, false, err
}
return (uint32(b&0x3f) << 8) | uint32(bb), false, nil
case rdbEncVal:
// When the first two bits are 11, the next object is encoded.
// The next 6 bits indicate the encoding type.
return uint32(b & 0x3f), true, nil
default:
// When the first two bits are 10, the next 6 bits are discarded.
// The next 4 bytes are the length.
length, err := d.readUint32Big()
return length, false, err
}
panic("not reached")
}
func verifyDump(d []byte) error {
if len(d) < 10 {
return fmt.Errorf("rdb: invalid dump length")
}
version := binary.LittleEndian.Uint16(d[len(d)-10:])
if version != uint16(Version) {
return fmt.Errorf("rdb: invalid version %d, expecting %d", version, Version)
}
if binary.LittleEndian.Uint64(d[len(d)-8:]) != crc64.Digest(d[:len(d)-8]) {
return fmt.Errorf("rdb: invalid CRC checksum")
}
return nil
}
func lzfDecompress(in []byte, outlen int) []byte {
out := make([]byte, outlen)
for i, o := 0, 0; 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++
}
}
}
return out
}

130
vendor/github.com/cupcake/rdb/encoder.go generated vendored Normal file
View File

@ -0,0 +1,130 @@
package rdb
import (
"encoding/binary"
"fmt"
"hash"
"io"
"math"
"strconv"
"github.com/cupcake/rdb/crc64"
)
const Version = 6
type Encoder struct {
w io.Writer
crc hash.Hash
}
func NewEncoder(w io.Writer) *Encoder {
e := &Encoder{crc: crc64.New()}
e.w = io.MultiWriter(w, e.crc)
return e
}
func (e *Encoder) EncodeHeader() error {
_, err := fmt.Fprintf(e.w, "REDIS%04d", Version)
return err
}
func (e *Encoder) EncodeFooter() error {
e.w.Write([]byte{rdbFlagEOF})
_, err := e.w.Write(e.crc.Sum(nil))
return err
}
func (e *Encoder) EncodeDumpFooter() error {
binary.Write(e.w, binary.LittleEndian, uint16(Version))
_, err := e.w.Write(e.crc.Sum(nil))
return err
}
func (e *Encoder) EncodeDatabase(n int) error {
e.w.Write([]byte{rdbFlagSelectDB})
return e.EncodeLength(uint32(n))
}
func (e *Encoder) EncodeExpiry(expiry uint64) error {
b := make([]byte, 9)
b[0] = rdbFlagExpiryMS
binary.LittleEndian.PutUint64(b[1:], expiry)
_, err := e.w.Write(b)
return err
}
func (e *Encoder) EncodeType(v ValueType) error {
_, err := e.w.Write([]byte{byte(v)})
return err
}
func (e *Encoder) EncodeString(s []byte) error {
written, err := e.encodeIntString(s)
if written {
return err
}
e.EncodeLength(uint32(len(s)))
_, err = e.w.Write(s)
return err
}
func (e *Encoder) EncodeLength(l uint32) (err error) {
switch {
case l < 1<<6:
_, err = e.w.Write([]byte{byte(l)})
case l < 1<<14:
_, err = e.w.Write([]byte{byte(l>>8) | rdb14bitLen<<6, byte(l)})
default:
b := make([]byte, 5)
b[0] = rdb32bitLen << 6
binary.BigEndian.PutUint32(b[1:], l)
_, err = e.w.Write(b)
}
return
}
func (e *Encoder) EncodeFloat(f float64) (err error) {
switch {
case math.IsNaN(f):
_, err = e.w.Write([]byte{253})
case math.IsInf(f, 1):
_, err = e.w.Write([]byte{254})
case math.IsInf(f, -1):
_, err = e.w.Write([]byte{255})
default:
b := []byte(strconv.FormatFloat(f, 'g', 17, 64))
e.w.Write([]byte{byte(len(b))})
_, err = e.w.Write(b)
}
return
}
func (e *Encoder) encodeIntString(b []byte) (written bool, err error) {
s := string(b)
i, err := strconv.ParseInt(s, 10, 32)
if err != nil {
return
}
// if the stringified parsed int isn't exactly the same, we can't encode it as an int
if s != strconv.FormatInt(i, 10) {
return
}
switch {
case i >= math.MinInt8 && i <= math.MaxInt8:
_, err = e.w.Write([]byte{rdbEncVal << 6, byte(int8(i))})
case i >= math.MinInt16 && i <= math.MaxInt16:
b := make([]byte, 3)
b[0] = rdbEncVal<<6 | rdbEncInt16
binary.LittleEndian.PutUint16(b[1:], uint16(int16(i)))
_, err = e.w.Write(b)
case i >= math.MinInt32 && i <= math.MaxInt32:
b := make([]byte, 5)
b[0] = rdbEncVal<<6 | rdbEncInt32
binary.LittleEndian.PutUint32(b[1:], uint32(int32(i)))
_, err = e.w.Write(b)
default:
return
}
return true, err
}

View File

@ -0,0 +1,24 @@
package nopdecoder
// NopDecoder may be embedded in a real Decoder to avoid implementing methods.
type NopDecoder struct{}
func (d NopDecoder) StartRDB() {}
func (d NopDecoder) StartDatabase(n int) {}
func (d NopDecoder) Aux(key, value []byte) {}
func (d NopDecoder) ResizeDatabase(dbSize, expiresSize uint32) {}
func (d NopDecoder) EndDatabase(n int) {}
func (d NopDecoder) EndRDB() {}
func (d NopDecoder) Set(key, value []byte, expiry int64) {}
func (d NopDecoder) StartHash(key []byte, length, expiry int64) {}
func (d NopDecoder) Hset(key, field, value []byte) {}
func (d NopDecoder) EndHash(key []byte) {}
func (d NopDecoder) StartSet(key []byte, cardinality, expiry int64) {}
func (d NopDecoder) Sadd(key, member []byte) {}
func (d NopDecoder) EndSet(key []byte) {}
func (d NopDecoder) StartList(key []byte, length, expiry int64) {}
func (d NopDecoder) Rpush(key, value []byte) {}
func (d NopDecoder) EndList(key []byte) {}
func (d NopDecoder) StartZSet(key []byte, cardinality, expiry int64) {}
func (d NopDecoder) Zadd(key []byte, score float64, member []byte) {}
func (d NopDecoder) EndZSet(key []byte) {}

67
vendor/github.com/cupcake/rdb/slice_buffer.go generated vendored Normal file
View File

@ -0,0 +1,67 @@
package rdb
import (
"errors"
"io"
)
type sliceBuffer struct {
s []byte
i int
}
func newSliceBuffer(s []byte) *sliceBuffer {
return &sliceBuffer{s, 0}
}
func (s *sliceBuffer) Slice(n int) ([]byte, error) {
if s.i+n > len(s.s) {
return nil, io.EOF
}
b := s.s[s.i : s.i+n]
s.i += n
return b, nil
}
func (s *sliceBuffer) ReadByte() (byte, error) {
if s.i >= len(s.s) {
return 0, io.EOF
}
b := s.s[s.i]
s.i++
return b, nil
}
func (s *sliceBuffer) Read(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
if s.i >= len(s.s) {
return 0, io.EOF
}
n := copy(b, s.s[s.i:])
s.i += n
return n, nil
}
func (s *sliceBuffer) Seek(offset int64, whence int) (int64, error) {
var abs int64
switch whence {
case 0:
abs = offset
case 1:
abs = int64(s.i) + offset
case 2:
abs = int64(len(s.s)) + offset
default:
return 0, errors.New("invalid whence")
}
if abs < 0 {
return 0, errors.New("negative position")
}
if abs >= 1<<31 {
return 0, errors.New("position out of range")
}
s.i = int(abs)
return abs, nil
}