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, errors.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) readObjectValue(t byte) ([]byte, error) { var b bytes.Buffer r = newRdbReader(io.TeeReader(r, &b)) switch t { default: return nil, errors.Errorf("unknown object-type %02x", t) 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 parseInt(s string, min, max int) (int, error) { n, err := strconv.Atoi(s) if err != nil { return 0, err } if n >= min && n <= max { return n, nil } return 0, errors.Errorf("out of range [%d,%d], got %d", min, max, n) }
func ParseArgs(resp Resp) (cmd string, args [][]byte, err error) { var array []Resp if o, ok := resp.(*Array); !ok { return "", nil, errors.Errorf("expect array, but got type = '%s'", resp.Type()) } else if o == nil || len(o.Value) == 0 { return "", nil, errors.New("request is an empty array") } else { array = o.Value } slices := make([][]byte, 0, len(array)) for i, resp := range array { if o, ok := resp.(*BulkBytes); !ok { return "", nil, errors.Errorf("args[%d], expect bulkbytes, but got '%s'", i, resp.Type()) } else if i == 0 && len(o.Value) == 0 { return "", nil, errors.New("command is empty") } else { slices = append(slices, o.Value) } } return strings.ToLower(string(slices[0])), slices[1:], nil }
func lzfDecompress(in []byte, outlen int) (out []byte, err error) { defer func() { if x := recover(); x != nil { err = errors.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, errors.Errorf("decompress length is %d != expected %d", o, outlen) } return out, nil }
func (l *Loader) Header() error { header := make([]byte, 9) if err := l.readFull(header); err != nil { return err } if !bytes.Equal(header[:5], []byte("REDIS")) { return errors.New("verify magic string, invalid file format") } if version, err := strconv.ParseInt(string(header[5:]), 10, 64); err != nil { return errors.Trace(err) } else if version <= 0 || version > Version { return errors.Errorf("verify version, invalid RDB version number %d", version) } return nil }