forked from mirror/ledisdb
Merge branch 'develop'
This commit is contained in:
commit
add345c119
|
@ -4,4 +4,5 @@ build
|
|||
nohup.out
|
||||
build_config.mk
|
||||
var*
|
||||
*.log
|
||||
*.log
|
||||
bin
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"ImportPath": "github.com/siddontang/ledisdb",
|
||||
"GoVersion": "go1.4",
|
||||
"GoVersion": "go1.4.2",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
|
@ -58,6 +58,14 @@
|
|||
"ImportPath": "github.com/siddontang/go/sync2",
|
||||
"Rev": "c2b33271306fcb7c6532efceac33ec45ee2439e0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/siddontang/goredis",
|
||||
"Rev": "6d2857b0488d1e8b9f96b46802eacb68e29fb003"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/siddontang/rdb",
|
||||
"Rev": "fc89ed2e418d27e3ea76e708e54276d2b44ae9cf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
|
||||
"Rev": "e9e2c8f6d3b9c313fb4acaac5ab06285bcf30b04"
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 siddontang
|
||||
|
||||
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.
|
||||
|
77
client/goledis/client.go → Godeps/_workspace/src/github.com/siddontang/goredis/client.go
generated
vendored
77
client/goledis/client.go → Godeps/_workspace/src/github.com/siddontang/goredis/client.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
package ledis
|
||||
package goredis
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
|
@ -7,17 +7,23 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Addr string
|
||||
MaxIdleConns int
|
||||
ReadBufferSize int
|
||||
WriteBufferSize int
|
||||
type PoolConn struct {
|
||||
*Conn
|
||||
c *Client
|
||||
}
|
||||
|
||||
func (c *PoolConn) Close() {
|
||||
c.c.put(c.Conn)
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
sync.Mutex
|
||||
|
||||
cfg *Config
|
||||
addr string
|
||||
maxIdleConns int
|
||||
readBufferSize int
|
||||
writeBufferSize int
|
||||
password string
|
||||
|
||||
conns *list.List
|
||||
}
|
||||
|
@ -30,22 +36,36 @@ func getProto(addr string) string {
|
|||
}
|
||||
}
|
||||
|
||||
func NewClient(cfg *Config) *Client {
|
||||
func NewClient(addr string, password string) *Client {
|
||||
c := new(Client)
|
||||
|
||||
c.cfg = cfg
|
||||
if c.cfg.ReadBufferSize == 0 {
|
||||
c.cfg.ReadBufferSize = 4096
|
||||
}
|
||||
if c.cfg.WriteBufferSize == 0 {
|
||||
c.cfg.WriteBufferSize = 4096
|
||||
}
|
||||
c.addr = addr
|
||||
c.maxIdleConns = 4
|
||||
c.readBufferSize = 1024
|
||||
c.writeBufferSize = 1024
|
||||
c.password = password
|
||||
|
||||
c.conns = list.New()
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) SetPassword(pass string) {
|
||||
c.password = pass
|
||||
}
|
||||
|
||||
func (c *Client) SetReadBufferSize(s int) {
|
||||
c.readBufferSize = s
|
||||
}
|
||||
|
||||
func (c *Client) SetWriteBufferSize(s int) {
|
||||
c.writeBufferSize = s
|
||||
}
|
||||
|
||||
func (c *Client) SetMaxIdleConns(n int) {
|
||||
c.maxIdleConns = n
|
||||
}
|
||||
|
||||
func (c *Client) Do(cmd string, args ...interface{}) (interface{}, error) {
|
||||
var co *Conn
|
||||
var err error
|
||||
|
@ -59,7 +79,7 @@ func (c *Client) Do(cmd string, args ...interface{}) (interface{}, error) {
|
|||
|
||||
r, err = co.Do(cmd, args...)
|
||||
if err != nil {
|
||||
co.finalize()
|
||||
co.Close()
|
||||
|
||||
if e, ok := err.(*net.OpError); ok && strings.Contains(e.Error(), "use of closed network connection") {
|
||||
//send to a closed connection, try again
|
||||
|
@ -86,36 +106,41 @@ func (c *Client) Close() {
|
|||
co := e.Value.(*Conn)
|
||||
c.conns.Remove(e)
|
||||
|
||||
co.finalize()
|
||||
co.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Get() (*Conn, error) {
|
||||
return c.get()
|
||||
func (c *Client) Get() (*PoolConn, error) {
|
||||
co, err := c.get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PoolConn{co, c}, err
|
||||
}
|
||||
|
||||
func (c *Client) get() (*Conn, error) {
|
||||
func (c *Client) get() (co *Conn, err error) {
|
||||
c.Lock()
|
||||
if c.conns.Len() == 0 {
|
||||
c.Unlock()
|
||||
|
||||
return c.newConn(c.cfg.Addr)
|
||||
co, err = c.newConn(c.addr, c.password)
|
||||
} else {
|
||||
e := c.conns.Front()
|
||||
co := e.Value.(*Conn)
|
||||
co = e.Value.(*Conn)
|
||||
c.conns.Remove(e)
|
||||
|
||||
c.Unlock()
|
||||
|
||||
return co, nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) put(conn *Conn) {
|
||||
c.Lock()
|
||||
if c.conns.Len() >= c.cfg.MaxIdleConns {
|
||||
if c.conns.Len() >= c.maxIdleConns {
|
||||
c.Unlock()
|
||||
conn.finalize()
|
||||
conn.Close()
|
||||
} else {
|
||||
c.conns.PushFront(conn)
|
||||
c.Unlock()
|
83
client/goledis/conn.go → Godeps/_workspace/src/github.com/siddontang/goredis/conn.go
generated
vendored
83
client/goledis/conn.go → Godeps/_workspace/src/github.com/siddontang/goredis/conn.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
package ledis
|
||||
package goredis
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
@ -16,9 +16,14 @@ type Error string
|
|||
|
||||
func (err Error) Error() string { return string(err) }
|
||||
|
||||
type Conn struct {
|
||||
client *Client
|
||||
type sizeWriter int64
|
||||
|
||||
func (s *sizeWriter) Write(p []byte) (int, error) {
|
||||
*s += sizeWriter(len(p))
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
type Conn struct {
|
||||
c net.Conn
|
||||
br *bufio.Reader
|
||||
bw *bufio.Writer
|
||||
|
@ -29,10 +34,13 @@ type Conn struct {
|
|||
|
||||
// Scratch space for formatting integers and floats.
|
||||
numScratch [40]byte
|
||||
|
||||
totalReadSize sizeWriter
|
||||
totalWriteSize sizeWriter
|
||||
}
|
||||
|
||||
func Connect(addr string) (*Conn, error) {
|
||||
return ConnectWithSize(addr, 4096, 4096)
|
||||
return ConnectWithSize(addr, 1024, 1024)
|
||||
}
|
||||
|
||||
func ConnectWithSize(addr string, readSize int, writeSize int) (*Conn, error) {
|
||||
|
@ -44,18 +52,22 @@ func ConnectWithSize(addr string, readSize int, writeSize int) (*Conn, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
c.br = bufio.NewReaderSize(c.c, readSize)
|
||||
c.bw = bufio.NewWriterSize(c.c, writeSize)
|
||||
c.br = bufio.NewReaderSize(io.TeeReader(c.c, &c.totalReadSize), readSize)
|
||||
c.bw = bufio.NewWriterSize(io.MultiWriter(c.c, &c.totalWriteSize), writeSize)
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Conn) Close() {
|
||||
if c.client != nil {
|
||||
c.client.put(c)
|
||||
} else {
|
||||
c.finalize()
|
||||
}
|
||||
c.c.Close()
|
||||
}
|
||||
|
||||
func (c *Conn) GetTotalReadSize() int64 {
|
||||
return int64(c.totalReadSize)
|
||||
}
|
||||
|
||||
func (c *Conn) GetTotalWriteSize() int64 {
|
||||
return int64(c.totalWriteSize)
|
||||
}
|
||||
|
||||
func (c *Conn) SetReadDeadline(t time.Time) {
|
||||
|
@ -76,12 +88,12 @@ func (c *Conn) Do(cmd string, args ...interface{}) (interface{}, error) {
|
|||
|
||||
func (c *Conn) Send(cmd string, args ...interface{}) error {
|
||||
if err := c.writeCommand(cmd, args); err != nil {
|
||||
c.finalize()
|
||||
c.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.bw.Flush(); err != nil {
|
||||
c.finalize()
|
||||
c.Close()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -89,7 +101,7 @@ func (c *Conn) Send(cmd string, args ...interface{}) error {
|
|||
|
||||
func (c *Conn) Receive() (interface{}, error) {
|
||||
if reply, err := c.readReply(); err != nil {
|
||||
c.finalize()
|
||||
c.Close()
|
||||
return nil, err
|
||||
} else {
|
||||
if e, ok := reply.(Error); ok {
|
||||
|
@ -104,16 +116,12 @@ func (c *Conn) ReceiveBulkTo(w io.Writer) error {
|
|||
err := c.readBulkReplyTo(w)
|
||||
if err != nil {
|
||||
if _, ok := err.(Error); !ok {
|
||||
c.finalize()
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Conn) finalize() {
|
||||
c.c.Close()
|
||||
}
|
||||
|
||||
func (c *Conn) writeLen(prefix byte, n int) error {
|
||||
c.lenScratch[len(c.lenScratch)-1] = '\n'
|
||||
c.lenScratch[len(c.lenScratch)-2] = '\r'
|
||||
|
@ -191,14 +199,14 @@ func (c *Conn) writeCommand(cmd string, args []interface{}) (err error) {
|
|||
func (c *Conn) readLine() ([]byte, error) {
|
||||
p, err := c.br.ReadSlice('\n')
|
||||
if err == bufio.ErrBufferFull {
|
||||
return nil, errors.New("ledis: long response line")
|
||||
return nil, errors.New("long response line")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i := len(p) - 2
|
||||
if i < 0 || p[i] != '\r' {
|
||||
return nil, errors.New("ledis: bad response line terminator")
|
||||
return nil, errors.New("bad response line terminator")
|
||||
}
|
||||
return p[:i], nil
|
||||
}
|
||||
|
@ -206,7 +214,7 @@ func (c *Conn) readLine() ([]byte, error) {
|
|||
// parseLen parses bulk string and array lengths.
|
||||
func parseLen(p []byte) (int, error) {
|
||||
if len(p) == 0 {
|
||||
return -1, errors.New("ledis: malformed length")
|
||||
return -1, errors.New("malformed length")
|
||||
}
|
||||
|
||||
if p[0] == '-' && len(p) == 2 && p[1] == '1' {
|
||||
|
@ -218,7 +226,7 @@ func parseLen(p []byte) (int, error) {
|
|||
for _, b := range p {
|
||||
n *= 10
|
||||
if b < '0' || b > '9' {
|
||||
return -1, errors.New("ledis: illegal bytes in length")
|
||||
return -1, errors.New("illegal bytes in length")
|
||||
}
|
||||
n += int(b - '0')
|
||||
}
|
||||
|
@ -229,7 +237,7 @@ func parseLen(p []byte) (int, error) {
|
|||
// parseInt parses an integer reply.
|
||||
func parseInt(p []byte) (interface{}, error) {
|
||||
if len(p) == 0 {
|
||||
return 0, errors.New("ledis: malformed integer")
|
||||
return 0, errors.New("malformed integer")
|
||||
}
|
||||
|
||||
var negate bool
|
||||
|
@ -237,7 +245,7 @@ func parseInt(p []byte) (interface{}, error) {
|
|||
negate = true
|
||||
p = p[1:]
|
||||
if len(p) == 0 {
|
||||
return 0, errors.New("ledis: malformed integer")
|
||||
return 0, errors.New("malformed integer")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,7 +253,7 @@ func parseInt(p []byte) (interface{}, error) {
|
|||
for _, b := range p {
|
||||
n *= 10
|
||||
if b < '0' || b > '9' {
|
||||
return 0, errors.New("ledis: illegal bytes in length")
|
||||
return 0, errors.New("illegal bytes in length")
|
||||
}
|
||||
n += int64(b - '0')
|
||||
}
|
||||
|
@ -288,11 +296,11 @@ func (c *Conn) readBulkReplyTo(w io.Writer) error {
|
|||
if line, err := c.readLine(); err != nil {
|
||||
return err
|
||||
} else if len(line) != 0 {
|
||||
return errors.New("ledis: bad bulk string format")
|
||||
return errors.New("bad bulk string format")
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("ledis: not invalid bulk string type, but %c", line[0])
|
||||
return fmt.Errorf("not invalid bulk string type, but %c", line[0])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,7 +310,7 @@ func (c *Conn) readReply() (interface{}, error) {
|
|||
return nil, err
|
||||
}
|
||||
if len(line) == 0 {
|
||||
return nil, errors.New("ledis: short response line")
|
||||
return nil, errors.New("short response line")
|
||||
}
|
||||
switch line[0] {
|
||||
case '+':
|
||||
|
@ -333,7 +341,7 @@ func (c *Conn) readReply() (interface{}, error) {
|
|||
if line, err := c.readLine(); err != nil {
|
||||
return nil, err
|
||||
} else if len(line) != 0 {
|
||||
return nil, errors.New("ledis: bad bulk string format")
|
||||
return nil, errors.New("bad bulk string format")
|
||||
}
|
||||
return p, nil
|
||||
case '*':
|
||||
|
@ -350,15 +358,22 @@ func (c *Conn) readReply() (interface{}, error) {
|
|||
}
|
||||
return r, nil
|
||||
}
|
||||
return nil, errors.New("ledis: unexpected response line")
|
||||
return nil, errors.New("unexpected response line")
|
||||
}
|
||||
|
||||
func (c *Client) newConn(addr string) (*Conn, error) {
|
||||
co, err := ConnectWithSize(addr, c.cfg.ReadBufferSize, c.cfg.WriteBufferSize)
|
||||
func (c *Client) newConn(addr string, pass string) (*Conn, error) {
|
||||
co, err := ConnectWithSize(addr, c.readBufferSize, c.writeBufferSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
co.client = c
|
||||
|
||||
if len(pass) > 0 {
|
||||
_, err = co.Do("AUTH", pass)
|
||||
if err != nil {
|
||||
co.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return co, nil
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// Package goredis is a client for the redis and ledisdb.
|
||||
//
|
||||
// Client
|
||||
//
|
||||
// The client is the primary interface for redis. You must first create a client with redis address for working.
|
||||
//
|
||||
// c := NewClient("127.0.0.1:6380")
|
||||
//
|
||||
// The most important function for client is Do function to send commands to remote server.
|
||||
//
|
||||
// reply, err := c.Do("ping")
|
||||
//
|
||||
// reply, err := c.Do("set", "key", "value")
|
||||
//
|
||||
// reply, err := c.Do("get", "key")
|
||||
//
|
||||
// Connection
|
||||
//
|
||||
// You can use an independent connection to send commands.
|
||||
//
|
||||
// //get a connection
|
||||
// conn, _ := c.Get()
|
||||
//
|
||||
// //connection send command
|
||||
// conn.Do("ping")
|
||||
//
|
||||
// Reply Helper
|
||||
//
|
||||
// You can use reply helper to convert a reply to a specific type.
|
||||
//
|
||||
// exists, err := Bool(c.Do("exists", "key"))
|
||||
//
|
||||
// score, err := Int64(c.Do("zscore", "key", "member"))
|
||||
package goredis
|
39
Godeps/_workspace/src/github.com/siddontang/goredis/goredis_test.go
generated
vendored
Normal file
39
Godeps/_workspace/src/github.com/siddontang/goredis/goredis_test.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
package goredis
|
||||
|
||||
import (
|
||||
"github.com/alicebob/miniredis"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
s, err := miniredis.Run()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
s.RequireAuth("123456")
|
||||
|
||||
addr := s.Addr()
|
||||
|
||||
c := NewClient(addr, "123456")
|
||||
defer c.Close()
|
||||
|
||||
conn, err := c.Get()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
if pong, err := String(conn.Do("PING")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if pong != "PONG" {
|
||||
t.Fatal(pong)
|
||||
}
|
||||
|
||||
if pong, err := String(conn.Do("PING")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if pong != "PONG" {
|
||||
t.Fatal(pong)
|
||||
}
|
||||
}
|
26
client/goledis/reply.go → Godeps/_workspace/src/github.com/siddontang/goredis/reply.go
generated
vendored
26
client/goledis/reply.go → Godeps/_workspace/src/github.com/siddontang/goredis/reply.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
package ledis
|
||||
package goredis
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
// ErrNil indicates that a reply value is nil.
|
||||
var ErrNil = errors.New("ledis: nil returned")
|
||||
var ErrNil = errors.New("nil returned")
|
||||
|
||||
// Int is a helper that converts a command reply to an integer. If err is not
|
||||
// equal to nil, then Int returns 0, err. Otherwise, Int converts the
|
||||
|
@ -37,7 +37,7 @@ func Int(reply interface{}, err error) (int, error) {
|
|||
case Error:
|
||||
return 0, reply
|
||||
}
|
||||
return 0, fmt.Errorf("ledis: unexpected type for Int, got type %T", reply)
|
||||
return 0, fmt.Errorf("unexpected type for Int, got type %T", reply)
|
||||
}
|
||||
|
||||
// Int64 is a helper that converts a command reply to 64 bit integer. If err is
|
||||
|
@ -64,10 +64,10 @@ func Int64(reply interface{}, err error) (int64, error) {
|
|||
case Error:
|
||||
return 0, reply
|
||||
}
|
||||
return 0, fmt.Errorf("ledis: unexpected type for Int64, got type %T", reply)
|
||||
return 0, fmt.Errorf("unexpected type for Int64, got type %T", reply)
|
||||
}
|
||||
|
||||
var errNegativeInt = errors.New("ledis: unexpected value for Uint64")
|
||||
var errNegativeInt = errors.New("unexpected value for Uint64")
|
||||
|
||||
// Uint64 is a helper that converts a command reply to 64 bit integer. If err is
|
||||
// not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the
|
||||
|
@ -96,7 +96,7 @@ func Uint64(reply interface{}, err error) (uint64, error) {
|
|||
case Error:
|
||||
return 0, reply
|
||||
}
|
||||
return 0, fmt.Errorf("ledis: unexpected type for Uint64, got type %T", reply)
|
||||
return 0, fmt.Errorf("unexpected type for Uint64, got type %T", reply)
|
||||
}
|
||||
|
||||
// Float64 is a helper that converts a command reply to 64 bit float. If err is
|
||||
|
@ -120,7 +120,7 @@ func Float64(reply interface{}, err error) (float64, error) {
|
|||
case Error:
|
||||
return 0, reply
|
||||
}
|
||||
return 0, fmt.Errorf("ledis: unexpected type for Float64, got type %T", reply)
|
||||
return 0, fmt.Errorf("unexpected type for Float64, got type %T", reply)
|
||||
}
|
||||
|
||||
// String is a helper that converts a command reply to a string. If err is not
|
||||
|
@ -146,7 +146,7 @@ func String(reply interface{}, err error) (string, error) {
|
|||
case Error:
|
||||
return "", reply
|
||||
}
|
||||
return "", fmt.Errorf("ledis: unexpected type for String, got type %T", reply)
|
||||
return "", fmt.Errorf("unexpected type for String, got type %T", reply)
|
||||
}
|
||||
|
||||
// Bytes is a helper that converts a command reply to a slice of bytes. If err
|
||||
|
@ -172,7 +172,7 @@ func Bytes(reply interface{}, err error) ([]byte, error) {
|
|||
case Error:
|
||||
return nil, reply
|
||||
}
|
||||
return nil, fmt.Errorf("ledis: unexpected type for Bytes, got type %T", reply)
|
||||
return nil, fmt.Errorf("unexpected type for Bytes, got type %T", reply)
|
||||
}
|
||||
|
||||
// Bool is a helper that converts a command reply to a boolean. If err is not
|
||||
|
@ -198,7 +198,7 @@ func Bool(reply interface{}, err error) (bool, error) {
|
|||
case Error:
|
||||
return false, reply
|
||||
}
|
||||
return false, fmt.Errorf("ledis: unexpected type for Bool, got type %T", reply)
|
||||
return false, fmt.Errorf("unexpected type for Bool, got type %T", reply)
|
||||
}
|
||||
|
||||
// MultiBulk is deprecated. Use Values.
|
||||
|
@ -224,7 +224,7 @@ func Values(reply interface{}, err error) ([]interface{}, error) {
|
|||
case Error:
|
||||
return nil, reply
|
||||
}
|
||||
return nil, fmt.Errorf("ledis: unexpected type for Values, got type %T", reply)
|
||||
return nil, fmt.Errorf("unexpected type for Values, got type %T", reply)
|
||||
}
|
||||
|
||||
// Strings is a helper that converts an array command reply to a []string. If
|
||||
|
@ -243,7 +243,7 @@ func Strings(reply interface{}, err error) ([]string, error) {
|
|||
}
|
||||
p, ok := reply[i].([]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("ledis: unexpected element type for Strings, got type %T", reply[i])
|
||||
return nil, fmt.Errorf("unexpected element type for Strings, got type %T", reply[i])
|
||||
}
|
||||
result[i] = string(p)
|
||||
}
|
||||
|
@ -253,5 +253,5 @@ func Strings(reply interface{}, err error) ([]string, error) {
|
|||
case Error:
|
||||
return nil, reply
|
||||
}
|
||||
return nil, fmt.Errorf("ledis: unexpected type for Strings, got type %T", reply)
|
||||
return nil, fmt.Errorf("unexpected type for Strings, got type %T", reply)
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 siddontang
|
||||
Copyright (c) 2015 siddontang
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
|
@ -0,0 +1,3 @@
|
|||
# rdb
|
||||
|
||||
Handling Redis RDB format.
|
6
ledis/rdb/decode.go → Godeps/_workspace/src/github.com/siddontang/rdb/decode.go
generated
vendored
6
ledis/rdb/decode.go → Godeps/_workspace/src/github.com/siddontang/rdb/decode.go
generated
vendored
|
@ -40,7 +40,7 @@ func (d *decoder) Set(key, value []byte, expiry int64) {
|
|||
}
|
||||
|
||||
func (d *decoder) StartHash(key []byte, length, expiry int64) {
|
||||
d.initObject(HashMap(nil))
|
||||
d.initObject(Hash(nil))
|
||||
}
|
||||
|
||||
func (d *decoder) Hset(key, field, value []byte) {
|
||||
|
@ -50,7 +50,7 @@ func (d *decoder) Hset(key, field, value []byte) {
|
|||
switch h := d.obj.(type) {
|
||||
default:
|
||||
d.err = fmt.Errorf("invalid object, not a hashmap")
|
||||
case HashMap:
|
||||
case Hash:
|
||||
v := struct {
|
||||
Field, Value []byte
|
||||
}{
|
||||
|
@ -118,7 +118,7 @@ func (d *decoder) Zadd(key []byte, score float64, member []byte) {
|
|||
|
||||
type String []byte
|
||||
type List [][]byte
|
||||
type HashMap []struct {
|
||||
type Hash []struct {
|
||||
Field, Value []byte
|
||||
}
|
||||
type Set [][]byte
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2014 Wandoujia Inc. All Rights Reserved.
|
||||
// Licensed under the MIT (MIT-LICENSE.txt) license.
|
||||
|
||||
package rdb
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"hash"
|
||||
)
|
||||
|
||||
var crc64_table = [256]uint64{
|
||||
0x0000000000000000, 0x7ad870c830358979, 0xf5b0e190606b12f2, 0x8f689158505e9b8b,
|
||||
0xc038e5739841b68f, 0xbae095bba8743ff6, 0x358804e3f82aa47d, 0x4f50742bc81f2d04,
|
||||
0xab28ecb46814fe75, 0xd1f09c7c5821770c, 0x5e980d24087fec87, 0x24407dec384a65fe,
|
||||
0x6b1009c7f05548fa, 0x11c8790fc060c183, 0x9ea0e857903e5a08, 0xe478989fa00bd371,
|
||||
0x7d08ff3b88be6f81, 0x07d08ff3b88be6f8, 0x88b81eabe8d57d73, 0xf2606e63d8e0f40a,
|
||||
0xbd301a4810ffd90e, 0xc7e86a8020ca5077, 0x4880fbd87094cbfc, 0x32588b1040a14285,
|
||||
0xd620138fe0aa91f4, 0xacf86347d09f188d, 0x2390f21f80c18306, 0x594882d7b0f40a7f,
|
||||
0x1618f6fc78eb277b, 0x6cc0863448deae02, 0xe3a8176c18803589, 0x997067a428b5bcf0,
|
||||
0xfa11fe77117cdf02, 0x80c98ebf2149567b, 0x0fa11fe77117cdf0, 0x75796f2f41224489,
|
||||
0x3a291b04893d698d, 0x40f16bccb908e0f4, 0xcf99fa94e9567b7f, 0xb5418a5cd963f206,
|
||||
0x513912c379682177, 0x2be1620b495da80e, 0xa489f35319033385, 0xde51839b2936bafc,
|
||||
0x9101f7b0e12997f8, 0xebd98778d11c1e81, 0x64b116208142850a, 0x1e6966e8b1770c73,
|
||||
0x8719014c99c2b083, 0xfdc17184a9f739fa, 0x72a9e0dcf9a9a271, 0x08719014c99c2b08,
|
||||
0x4721e43f0183060c, 0x3df994f731b68f75, 0xb29105af61e814fe, 0xc849756751dd9d87,
|
||||
0x2c31edf8f1d64ef6, 0x56e99d30c1e3c78f, 0xd9810c6891bd5c04, 0xa3597ca0a188d57d,
|
||||
0xec09088b6997f879, 0x96d1784359a27100, 0x19b9e91b09fcea8b, 0x636199d339c963f2,
|
||||
0xdf7adabd7a6e2d6f, 0xa5a2aa754a5ba416, 0x2aca3b2d1a053f9d, 0x50124be52a30b6e4,
|
||||
0x1f423fcee22f9be0, 0x659a4f06d21a1299, 0xeaf2de5e82448912, 0x902aae96b271006b,
|
||||
0x74523609127ad31a, 0x0e8a46c1224f5a63, 0x81e2d7997211c1e8, 0xfb3aa75142244891,
|
||||
0xb46ad37a8a3b6595, 0xceb2a3b2ba0eecec, 0x41da32eaea507767, 0x3b024222da65fe1e,
|
||||
0xa2722586f2d042ee, 0xd8aa554ec2e5cb97, 0x57c2c41692bb501c, 0x2d1ab4dea28ed965,
|
||||
0x624ac0f56a91f461, 0x1892b03d5aa47d18, 0x97fa21650afae693, 0xed2251ad3acf6fea,
|
||||
0x095ac9329ac4bc9b, 0x7382b9faaaf135e2, 0xfcea28a2faafae69, 0x8632586aca9a2710,
|
||||
0xc9622c4102850a14, 0xb3ba5c8932b0836d, 0x3cd2cdd162ee18e6, 0x460abd1952db919f,
|
||||
0x256b24ca6b12f26d, 0x5fb354025b277b14, 0xd0dbc55a0b79e09f, 0xaa03b5923b4c69e6,
|
||||
0xe553c1b9f35344e2, 0x9f8bb171c366cd9b, 0x10e3202993385610, 0x6a3b50e1a30ddf69,
|
||||
0x8e43c87e03060c18, 0xf49bb8b633338561, 0x7bf329ee636d1eea, 0x012b592653589793,
|
||||
0x4e7b2d0d9b47ba97, 0x34a35dc5ab7233ee, 0xbbcbcc9dfb2ca865, 0xc113bc55cb19211c,
|
||||
0x5863dbf1e3ac9dec, 0x22bbab39d3991495, 0xadd33a6183c78f1e, 0xd70b4aa9b3f20667,
|
||||
0x985b3e827bed2b63, 0xe2834e4a4bd8a21a, 0x6debdf121b863991, 0x1733afda2bb3b0e8,
|
||||
0xf34b37458bb86399, 0x8993478dbb8deae0, 0x06fbd6d5ebd3716b, 0x7c23a61ddbe6f812,
|
||||
0x3373d23613f9d516, 0x49aba2fe23cc5c6f, 0xc6c333a67392c7e4, 0xbc1b436e43a74e9d,
|
||||
0x95ac9329ac4bc9b5, 0xef74e3e19c7e40cc, 0x601c72b9cc20db47, 0x1ac40271fc15523e,
|
||||
0x5594765a340a7f3a, 0x2f4c0692043ff643, 0xa02497ca54616dc8, 0xdafce7026454e4b1,
|
||||
0x3e847f9dc45f37c0, 0x445c0f55f46abeb9, 0xcb349e0da4342532, 0xb1eceec59401ac4b,
|
||||
0xfebc9aee5c1e814f, 0x8464ea266c2b0836, 0x0b0c7b7e3c7593bd, 0x71d40bb60c401ac4,
|
||||
0xe8a46c1224f5a634, 0x927c1cda14c02f4d, 0x1d148d82449eb4c6, 0x67ccfd4a74ab3dbf,
|
||||
0x289c8961bcb410bb, 0x5244f9a98c8199c2, 0xdd2c68f1dcdf0249, 0xa7f41839ecea8b30,
|
||||
0x438c80a64ce15841, 0x3954f06e7cd4d138, 0xb63c61362c8a4ab3, 0xcce411fe1cbfc3ca,
|
||||
0x83b465d5d4a0eece, 0xf96c151de49567b7, 0x76048445b4cbfc3c, 0x0cdcf48d84fe7545,
|
||||
0x6fbd6d5ebd3716b7, 0x15651d968d029fce, 0x9a0d8ccedd5c0445, 0xe0d5fc06ed698d3c,
|
||||
0xaf85882d2576a038, 0xd55df8e515432941, 0x5a3569bd451db2ca, 0x20ed197575283bb3,
|
||||
0xc49581ead523e8c2, 0xbe4df122e51661bb, 0x3125607ab548fa30, 0x4bfd10b2857d7349,
|
||||
0x04ad64994d625e4d, 0x7e7514517d57d734, 0xf11d85092d094cbf, 0x8bc5f5c11d3cc5c6,
|
||||
0x12b5926535897936, 0x686de2ad05bcf04f, 0xe70573f555e26bc4, 0x9ddd033d65d7e2bd,
|
||||
0xd28d7716adc8cfb9, 0xa85507de9dfd46c0, 0x273d9686cda3dd4b, 0x5de5e64efd965432,
|
||||
0xb99d7ed15d9d8743, 0xc3450e196da80e3a, 0x4c2d9f413df695b1, 0x36f5ef890dc31cc8,
|
||||
0x79a59ba2c5dc31cc, 0x037deb6af5e9b8b5, 0x8c157a32a5b7233e, 0xf6cd0afa9582aa47,
|
||||
0x4ad64994d625e4da, 0x300e395ce6106da3, 0xbf66a804b64ef628, 0xc5bed8cc867b7f51,
|
||||
0x8aeeace74e645255, 0xf036dc2f7e51db2c, 0x7f5e4d772e0f40a7, 0x05863dbf1e3ac9de,
|
||||
0xe1fea520be311aaf, 0x9b26d5e88e0493d6, 0x144e44b0de5a085d, 0x6e963478ee6f8124,
|
||||
0x21c640532670ac20, 0x5b1e309b16452559, 0xd476a1c3461bbed2, 0xaeaed10b762e37ab,
|
||||
0x37deb6af5e9b8b5b, 0x4d06c6676eae0222, 0xc26e573f3ef099a9, 0xb8b627f70ec510d0,
|
||||
0xf7e653dcc6da3dd4, 0x8d3e2314f6efb4ad, 0x0256b24ca6b12f26, 0x788ec2849684a65f,
|
||||
0x9cf65a1b368f752e, 0xe62e2ad306bafc57, 0x6946bb8b56e467dc, 0x139ecb4366d1eea5,
|
||||
0x5ccebf68aecec3a1, 0x2616cfa09efb4ad8, 0xa97e5ef8cea5d153, 0xd3a62e30fe90582a,
|
||||
0xb0c7b7e3c7593bd8, 0xca1fc72bf76cb2a1, 0x45775673a732292a, 0x3faf26bb9707a053,
|
||||
0x70ff52905f188d57, 0x0a2722586f2d042e, 0x854fb3003f739fa5, 0xff97c3c80f4616dc,
|
||||
0x1bef5b57af4dc5ad, 0x61372b9f9f784cd4, 0xee5fbac7cf26d75f, 0x9487ca0fff135e26,
|
||||
0xdbd7be24370c7322, 0xa10fceec0739fa5b, 0x2e675fb4576761d0, 0x54bf2f7c6752e8a9,
|
||||
0xcdcf48d84fe75459, 0xb71738107fd2dd20, 0x387fa9482f8c46ab, 0x42a7d9801fb9cfd2,
|
||||
0x0df7adabd7a6e2d6, 0x772fdd63e7936baf, 0xf8474c3bb7cdf024, 0x829f3cf387f8795d,
|
||||
0x66e7a46c27f3aa2c, 0x1c3fd4a417c62355, 0x935745fc4798b8de, 0xe98f353477ad31a7,
|
||||
0xa6df411fbfb21ca3, 0xdc0731d78f8795da, 0x536fa08fdfd90e51, 0x29b7d047efec8728}
|
||||
|
||||
type digest struct {
|
||||
crc uint64
|
||||
}
|
||||
|
||||
func (d *digest) update(p []byte) {
|
||||
for _, b := range p {
|
||||
d.crc = crc64_table[byte(d.crc)^b] ^ (d.crc >> 8)
|
||||
}
|
||||
}
|
||||
|
||||
func newDigest() hash.Hash64 {
|
||||
d := &digest{}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *digest) Write(p []byte) (int, error) {
|
||||
d.update(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
buf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(buf, d.crc)
|
||||
return append(in, buf...)
|
||||
}
|
||||
|
||||
func (d *digest) Sum64() uint64 { return d.crc }
|
||||
func (d *digest) BlockSize() int { return 1 }
|
||||
func (d *digest) Size() int { return 8 }
|
||||
func (d *digest) Reset() { d.crc = 0 }
|
2
ledis/rdb/encode.go → Godeps/_workspace/src/github.com/siddontang/rdb/encode.go
generated
vendored
2
ledis/rdb/encode.go → Godeps/_workspace/src/github.com/siddontang/rdb/encode.go
generated
vendored
|
@ -15,7 +15,7 @@ func Dump(obj interface{}) ([]byte, error) {
|
|||
case String:
|
||||
e.EncodeType(rdb.TypeString)
|
||||
e.EncodeString(v)
|
||||
case HashMap:
|
||||
case Hash:
|
||||
e.EncodeType(rdb.TypeHash)
|
||||
e.EncodeLength(uint32(len(v)))
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
// 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()
|
||||
}
|
|
@ -0,0 +1,373 @@
|
|||
// Copyright 2014 Wandoujia Inc. All Rights Reserved.
|
||||
// Licensed under the MIT (MIT-LICENSE.txt) license.
|
||||
|
||||
package rdb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func AssertNoError(t *testing.T, err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
func Assert(t *testing.T, b bool) {
|
||||
if b {
|
||||
return
|
||||
}
|
||||
t.Fatal("assertion failed")
|
||||
}
|
||||
|
||||
func DecodeHexRdb(t *testing.T, s string, n int) map[string]*Entry {
|
||||
p, err := hex.DecodeString(strings.NewReplacer("\t", "", "\r", "", "\n", "", " ", "").Replace(s))
|
||||
AssertNoError(t, err)
|
||||
r := bytes.NewReader(p)
|
||||
l := NewLoader(r)
|
||||
AssertNoError(t, l.LoadHeader())
|
||||
entries := make(map[string]*Entry)
|
||||
var i int = 0
|
||||
for {
|
||||
e, err := l.LoadEntry()
|
||||
AssertNoError(t, err)
|
||||
if e == nil {
|
||||
break
|
||||
}
|
||||
Assert(t, e.DB == 0)
|
||||
entries[string(e.Key)] = e
|
||||
i++
|
||||
}
|
||||
AssertNoError(t, l.LoadChecksum())
|
||||
Assert(t, r.Len() == 0)
|
||||
Assert(t, len(entries) == i && i == n)
|
||||
return entries
|
||||
}
|
||||
|
||||
func getobj(t *testing.T, entries map[string]*Entry, key string) (*Entry, interface{}) {
|
||||
e := entries[key]
|
||||
Assert(t, e != nil)
|
||||
val, err := DecodeDump(e.ValDump)
|
||||
AssertNoError(t, err)
|
||||
return e, val
|
||||
}
|
||||
|
||||
/*
|
||||
#!/bin/bash
|
||||
./redis-cli flushall
|
||||
for i in 1 255 256 65535 65536 2147483647 2147483648 4294967295 4294967296 -2147483648; do
|
||||
./redis-cli set string_${i} ${i}
|
||||
done
|
||||
./redis-cli save && xxd -p -c 32 dump.rdb
|
||||
*/
|
||||
func TestLoadIntString(t *testing.T) {
|
||||
s := `
|
||||
524544495330303036fe00000a737472696e675f323535c1ff00000873747269
|
||||
6e675f31c0010011737472696e675f343239343936373239360a343239343936
|
||||
373239360011737472696e675f343239343936373239350a3432393439363732
|
||||
39350012737472696e675f2d32313437343833363438c200000080000c737472
|
||||
696e675f3635353335c2ffff00000011737472696e675f323134373438333634
|
||||
380a32313437343833363438000c737472696e675f3635353336c20000010000
|
||||
0a737472696e675f323536c100010011737472696e675f323134373438333634
|
||||
37c2ffffff7fffe49d9f131fb5c3b5
|
||||
`
|
||||
values := []int{1, 255, 256, 65535, 65536, 2147483647, 2147483648, 4294967295, 4294967296, -2147483648}
|
||||
entries := DecodeHexRdb(t, s, len(values))
|
||||
for _, value := range values {
|
||||
key := fmt.Sprintf("string_%d", value)
|
||||
_, obj := getobj(t, entries, key)
|
||||
val := obj.(String)
|
||||
Assert(t, bytes.Equal([]byte(val), []byte(strconv.Itoa(value))))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#!/bin/bash
|
||||
./redis-cli flushall
|
||||
./redis-cli set string_ttls string_ttls
|
||||
./redis-cli expireat string_ttls 1500000000
|
||||
./redis-cli set string_ttlms string_ttlms
|
||||
./redis-cli pexpireat string_ttlms 1500000000000
|
||||
./redis-cli save && xxd -p -c 32 dump.rdb
|
||||
*/
|
||||
func TestLoadStringTTL(t *testing.T) {
|
||||
s := `
|
||||
524544495330303036fe00fc0098f73e5d010000000c737472696e675f74746c
|
||||
6d730c737472696e675f74746c6d73fc0098f73e5d010000000b737472696e67
|
||||
5f74746c730b737472696e675f74746c73ffd15acd935a3fe949
|
||||
`
|
||||
expireat := uint64(1500000000000)
|
||||
entries := DecodeHexRdb(t, s, 2)
|
||||
keys := []string{"string_ttls", "string_ttlms"}
|
||||
for _, key := range keys {
|
||||
e, obj := getobj(t, entries, key)
|
||||
val := obj.(String)
|
||||
Assert(t, bytes.Equal([]byte(val), []byte(key)))
|
||||
Assert(t, e.ExpireAt == expireat)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#!/bin/bash
|
||||
s="01"
|
||||
for ((i=0;i<15;i++)); do
|
||||
s=$s$s
|
||||
done
|
||||
./redis-cli flushall
|
||||
./redis-cli set string_long $s
|
||||
./redis-cli save && xxd -p -c 32 dump.rdb
|
||||
*/
|
||||
func TestLoadLongString(t *testing.T) {
|
||||
s := `
|
||||
524544495330303036fe00000b737472696e675f6c6f6e67c342f28000010000
|
||||
02303130e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
|
||||
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
|
||||
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
|
||||
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
|
||||
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
|
||||
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
|
||||
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
|
||||
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
|
||||
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
|
||||
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
|
||||
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
|
||||
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
|
||||
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
|
||||
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
|
||||
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
|
||||
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
|
||||
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
|
||||
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
|
||||
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
|
||||
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
|
||||
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
|
||||
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
|
||||
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
|
||||
e0ff01e0ff01e0ff01e0ff01e03201013031ffdfdb02bd6d5da5e6
|
||||
`
|
||||
entries := DecodeHexRdb(t, s, 1)
|
||||
_, obj := getobj(t, entries, "string_long")
|
||||
val := []byte(obj.(String))
|
||||
for i := 0; i < (1 << 15); i++ {
|
||||
var c uint8 = '0'
|
||||
if i%2 != 0 {
|
||||
c = '1'
|
||||
}
|
||||
Assert(t, val[i] == c)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#!/bin/bash
|
||||
./redis-cli flushall
|
||||
for ((i=0;i<256;i++)); do
|
||||
./redis-cli rpush list_lzf 0
|
||||
./redis-cli rpush list_lzf 1
|
||||
done
|
||||
./redis-cli save && xxd -p -c 32 dump.rdb
|
||||
*/
|
||||
func TestLoadListZipmap(t *testing.T) {
|
||||
s := `
|
||||
524544495330303036fe000a086c6973745f6c7a66c31f440b040b0400000820
|
||||
0306000200f102f202e0ff03e1ff07e1ff07e1d90701f2ffff6a1c2d51c02301
|
||||
16
|
||||
`
|
||||
entries := DecodeHexRdb(t, s, 1)
|
||||
_, obj := getobj(t, entries, "list_lzf")
|
||||
val := obj.(List)
|
||||
Assert(t, len(val) == 512)
|
||||
for i := 0; i < 256; i++ {
|
||||
var s string = "0"
|
||||
if i%2 != 0 {
|
||||
s = "1"
|
||||
}
|
||||
Assert(t, string(val[i]) == s)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#!/bin/bash
|
||||
./redis-cli flushall
|
||||
for ((i=0;i<32;i++)); do
|
||||
./redis-cli rpush list ${i}
|
||||
done
|
||||
./redis-cli save && xxd -p -c 32 dump.rdb
|
||||
*/
|
||||
func TestLoadList(t *testing.T) {
|
||||
s := `
|
||||
524544495330303036fe0001046c69737420c000c001c002c003c004c005c006
|
||||
c007c008c009c00ac00bc00cc00dc00ec00fc010c011c012c013c014c015c016
|
||||
c017c018c019c01ac01bc01cc01dc01ec01fff756ea1fa90adefe3
|
||||
`
|
||||
entries := DecodeHexRdb(t, s, 1)
|
||||
_, obj := getobj(t, entries, "list")
|
||||
val := obj.(List)
|
||||
Assert(t, len(val) == 32)
|
||||
for i := 0; i < 32; i++ {
|
||||
Assert(t, string(val[i]) == strconv.Itoa(i))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#!/bin/bash
|
||||
./redis-cli flushall
|
||||
for ((i=0;i<16;i++)); do
|
||||
./redis-cli sadd set1 ${i}
|
||||
done
|
||||
for ((i=0;i<32;i++)); do
|
||||
./redis-cli sadd set2 ${i}
|
||||
done
|
||||
./redis-cli save && xxd -p -c 32 dump.rdb
|
||||
*/
|
||||
func TestLoadSetAndSetIntset(t *testing.T) {
|
||||
s := `
|
||||
524544495330303036fe0002047365743220c016c00dc01bc012c01ac004c014
|
||||
c002c017c01dc01cc013c019c01ec008c006c000c001c007c00fc009c01fc00e
|
||||
c003c00ac015c010c00bc018c011c00cc0050b04736574312802000000100000
|
||||
0000000100020003000400050006000700080009000a000b000c000d000e000f
|
||||
00ff3a0a9697324d19c3
|
||||
`
|
||||
entries := DecodeHexRdb(t, s, 2)
|
||||
|
||||
_, obj1 := getobj(t, entries, "set1")
|
||||
val1 := obj1.(Set)
|
||||
set1 := make(map[string]bool)
|
||||
for _, mem := range val1 {
|
||||
set1[string(mem)] = true
|
||||
}
|
||||
Assert(t, len(set1) == 16)
|
||||
Assert(t, len(set1) == len(val1))
|
||||
for i := 0; i < 16; i++ {
|
||||
_, ok := set1[strconv.Itoa(i)]
|
||||
Assert(t, ok)
|
||||
}
|
||||
|
||||
_, obj2 := getobj(t, entries, "set2")
|
||||
val2 := obj2.(Set)
|
||||
set2 := make(map[string]bool)
|
||||
for _, mem := range val2 {
|
||||
set2[string(mem)] = true
|
||||
}
|
||||
Assert(t, len(set2) == 32)
|
||||
Assert(t, len(set2) == len(val2))
|
||||
for i := 0; i < 32; i++ {
|
||||
_, ok := set2[strconv.Itoa(i)]
|
||||
Assert(t, ok)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#!/bin/bash
|
||||
./redis-cli flushall
|
||||
for ((i=0;i<16;i++)); do
|
||||
./redis-cli hset hash1 ${i}
|
||||
done
|
||||
for ((i=-16;i<16;i++)); do
|
||||
./redis-cli hset hash2 ${i}
|
||||
done
|
||||
./redis-cli save && xxd -p -c 32 dump.rdb
|
||||
*/
|
||||
func TestLoadHashAndHashZiplist(t *testing.T) {
|
||||
s := `
|
||||
524544495330303036fe000405686173683220c00dc00dc0fcc0fcc0ffc0ffc0
|
||||
04c004c002c002c0fbc0fbc0f0c0f0c0f9c0f9c008c008c0fac0fac006c006c0
|
||||
00c000c001c001c0fec0fec007c007c0f6c0f6c00fc00fc009c009c0f7c0f7c0
|
||||
fdc0fdc0f1c0f1c0f2c0f2c0f3c0f3c00ec00ec003c003c00ac00ac00bc00bc0
|
||||
f8c0f8c00cc00cc0f5c0f5c0f4c0f4c005c0050d056861736831405151000000
|
||||
4d000000200000f102f102f202f202f302f302f402f402f502f502f602f602f7
|
||||
02f702f802f802f902f902fa02fa02fb02fb02fc02fc02fd02fd02fe0d03fe0d
|
||||
03fe0e03fe0e03fe0f03fe0fffffa423d3036c15e534
|
||||
`
|
||||
entries := DecodeHexRdb(t, s, 2)
|
||||
|
||||
_, obj1 := getobj(t, entries, "hash1")
|
||||
val1 := obj1.(Hash)
|
||||
hash1 := make(map[string]string)
|
||||
for _, ent := range val1 {
|
||||
hash1[string(ent.Field)] = string(ent.Value)
|
||||
}
|
||||
Assert(t, len(hash1) == 16)
|
||||
Assert(t, len(hash1) == len(val1))
|
||||
for i := 0; i < 16; i++ {
|
||||
s := strconv.Itoa(i)
|
||||
Assert(t, hash1[s] == s)
|
||||
}
|
||||
|
||||
_, obj2 := getobj(t, entries, "hash2")
|
||||
val2 := obj2.(Hash)
|
||||
hash2 := make(map[string]string)
|
||||
for _, ent := range val2 {
|
||||
hash2[string(ent.Field)] = string(ent.Value)
|
||||
}
|
||||
Assert(t, len(hash2) == 32)
|
||||
Assert(t, len(hash2) == len(val2))
|
||||
for i := -16; i < 16; i++ {
|
||||
s := strconv.Itoa(i)
|
||||
Assert(t, hash2[s] == s)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#!/bin/bash
|
||||
./redis-cli flushall
|
||||
for ((i=0;i<16;i++)); do
|
||||
./redis-cli zadd zset1 ${i} ${i}
|
||||
done
|
||||
for ((i=0;i<32;i++)); do
|
||||
./redis-cli zadd zset2 -${i} ${i}
|
||||
done
|
||||
./redis-cli save && xxd -p -c 32 dump.rdb
|
||||
*/
|
||||
func TestLoadZSetAndZSetZiplist(t *testing.T) {
|
||||
s := `
|
||||
524544495330303036fe0003057a7365743220c016032d3232c00d032d3133c0
|
||||
1b032d3237c012032d3138c01a032d3236c004022d34c014032d3230c002022d
|
||||
32c017032d3233c01d032d3239c01c032d3238c013032d3139c019032d3235c0
|
||||
1e032d3330c008022d38c006022d36c000022d30c001022d31c007022d37c009
|
||||
022d39c00f032d3135c01f032d3331c00e032d3134c003022d33c00a032d3130
|
||||
c015032d3231c010032d3136c00b032d3131c018032d3234c011032d3137c00c
|
||||
032d3132c005022d350c057a736574314051510000004d000000200000f102f1
|
||||
02f202f202f302f302f402f402f502f502f602f602f702f702f802f802f902f9
|
||||
02fa02fa02fb02fb02fc02fc02fd02fd02fe0d03fe0d03fe0e03fe0e03fe0f03
|
||||
fe0fffff2addedbf4f5a8f93
|
||||
`
|
||||
entries := DecodeHexRdb(t, s, 2)
|
||||
|
||||
_, obj1 := getobj(t, entries, "zset1")
|
||||
val1 := obj1.(ZSet)
|
||||
zset1 := make(map[string]float64)
|
||||
for _, ent := range val1 {
|
||||
zset1[string(ent.Member)] = ent.Score
|
||||
}
|
||||
Assert(t, len(zset1) == 16)
|
||||
Assert(t, len(zset1) == len(val1))
|
||||
for i := 0; i < 16; i++ {
|
||||
s := strconv.Itoa(i)
|
||||
score, ok := zset1[s]
|
||||
Assert(t, ok)
|
||||
Assert(t, math.Abs(score-float64(i)) < 1e-10)
|
||||
}
|
||||
|
||||
_, obj2 := getobj(t, entries, "zset2")
|
||||
val2 := obj2.(ZSet)
|
||||
zset2 := make(map[string]float64)
|
||||
for _, ent := range val2 {
|
||||
zset2[string(ent.Member)] = ent.Score
|
||||
}
|
||||
Assert(t, len(zset2) == 32)
|
||||
Assert(t, len(zset2) == len(val2))
|
||||
for i := 0; i < 32; i++ {
|
||||
s := strconv.Itoa(i)
|
||||
score, ok := zset2[s]
|
||||
Assert(t, ok)
|
||||
Assert(t, math.Abs(score+float64(i)) < 1e-10)
|
||||
}
|
||||
}
|
0
ledis/rdb/rdb_test.go → Godeps/_workspace/src/github.com/siddontang/rdb/rdb_test.go
generated
vendored
0
ledis/rdb/rdb_test.go → Godeps/_workspace/src/github.com/siddontang/rdb/rdb_test.go
generated
vendored
|
@ -0,0 +1,332 @@
|
|||
// 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
|
||||
}
|
14
Makefile
14
Makefile
|
@ -14,14 +14,17 @@ export GO_BUILD_TAGS
|
|||
all: build
|
||||
|
||||
build:
|
||||
$(GO) install -tags '$(GO_BUILD_TAGS)' ./...
|
||||
|
||||
clean:
|
||||
$(GO) clean -i ./...
|
||||
$(GO) install -tags 'linenoise $(GO_BUILD_TAGS)' ./...
|
||||
|
||||
build_use_lmdb:
|
||||
$(GO) install -tags 'linenoise $(GO_BUILD_TAGS) lmdb' ./...
|
||||
|
||||
test:
|
||||
$(GO) test --race -tags '$(GO_BUILD_TAGS)' ./...
|
||||
|
||||
test_use_lmdb:
|
||||
$(GO) test --race -tags '$(GO_BUILD_TAGS) lmdb' ./...
|
||||
|
||||
test_ledis:
|
||||
$(GO) test --race -tags '$(GO_BUILD_TAGS)' ./ledis
|
||||
|
||||
|
@ -34,5 +37,8 @@ test_store:
|
|||
test_rpl:
|
||||
$(GO) test --race -tags '$(GO_BUILD_TAGS)' ./rpl
|
||||
|
||||
clean:
|
||||
$(GO) clean -i ./...
|
||||
|
||||
fmt:
|
||||
go fmt ./...
|
|
@ -19,3 +19,5 @@ go get -u github.com/syndtr/goleveldb/leveldb
|
|||
go get -u github.com/cupcake/rdb
|
||||
|
||||
go get -u github.com/siddontang/go
|
||||
go get -u github.com/siddontang/goredis
|
||||
go get -u github.com/siddontang/rdb
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
[Clients](https://github.com/siddontang/ledisdb/wiki/Clients)
|
|
@ -1,45 +0,0 @@
|
|||
// Package ledis is a client for the ledisdb.
|
||||
//
|
||||
// Config
|
||||
//
|
||||
// Config struct contains configuration for ledisdb:
|
||||
//
|
||||
// Addr ledisdb server address, like 127.0.0.1:6380
|
||||
// MaxIdleConns max idle connections for ledisdb
|
||||
//
|
||||
// Client
|
||||
//
|
||||
// The client is the primary interface for ledisdb. You must first create a client with proper config for working.
|
||||
//
|
||||
// cfg := new(Config)
|
||||
// cfg.Addr = "127.0.0.1:6380"
|
||||
// cfg.MaxIdleConns = 4
|
||||
//
|
||||
// c := NewClient(cfg)
|
||||
//
|
||||
// The most important function for client is Do function to send commands to remote server.
|
||||
//
|
||||
// reply, err := c.Do("ping")
|
||||
//
|
||||
// reply, err := c.Do("set", "key", "value")
|
||||
//
|
||||
// reply, err := c.Do("get", "key")
|
||||
//
|
||||
// Connection
|
||||
//
|
||||
// You can use an independent connection to send commands.
|
||||
//
|
||||
// //get a connection
|
||||
// conn := c.Get()
|
||||
//
|
||||
// //connection send command
|
||||
// conn.Do("ping")
|
||||
//
|
||||
// Reply Helper
|
||||
//
|
||||
// You can use reply helper to convert a reply to a specific type.
|
||||
//
|
||||
// exists, err := ledis.Bool(c.Do("exists", "key"))
|
||||
//
|
||||
// score, err := ledis.Int64(c.Do("zscore", "key", "member"))
|
||||
package ledis
|
|
@ -1,15 +0,0 @@
|
|||
package ledis
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestClient(t *testing.T) {
|
||||
cfg := new(Config)
|
||||
cfg.Addr = "127.0.0.1:6380"
|
||||
cfg.MaxIdleConns = 4
|
||||
|
||||
c := NewClient(cfg)
|
||||
|
||||
c.Close()
|
||||
}
|
|
@ -3,7 +3,7 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"math/rand"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -21,10 +21,10 @@ var valueSize = flag.Int("vsize", 100, "kv value size")
|
|||
var tests = flag.String("t", "set,get,randget,del,lpush,lrange,lpop,hset,hget,hdel,zadd,zincr,zrange,zrevrange,zdel", "only run the comma separated list of tests")
|
||||
var wg sync.WaitGroup
|
||||
|
||||
var client *ledis.Client
|
||||
var client *goredis.Client
|
||||
var loop int = 0
|
||||
|
||||
func waitBench(c *ledis.Conn, cmd string, args ...interface{}) {
|
||||
func waitBench(c *goredis.PoolConn, cmd string, args ...interface{}) {
|
||||
_, err := c.Do(strings.ToUpper(cmd), args...)
|
||||
if err != nil {
|
||||
fmt.Printf("do %s error %s\n", cmd, err.Error())
|
||||
|
@ -32,7 +32,7 @@ func waitBench(c *ledis.Conn, cmd string, args ...interface{}) {
|
|||
|
||||
}
|
||||
|
||||
func bench(cmd string, f func(c *ledis.Conn)) {
|
||||
func bench(cmd string, f func(c *goredis.PoolConn)) {
|
||||
wg.Add(*clients)
|
||||
|
||||
t1 := time.Now()
|
||||
|
@ -66,7 +66,7 @@ var kvIncrBase int64 = 0
|
|||
var kvDelBase int64 = 0
|
||||
|
||||
func benchSet() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
value := make([]byte, *valueSize)
|
||||
n := atomic.AddInt64(&kvSetBase, 1)
|
||||
waitBench(c, "SET", n, value)
|
||||
|
@ -76,7 +76,7 @@ func benchSet() {
|
|||
}
|
||||
|
||||
func benchGet() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
n := atomic.AddInt64(&kvGetBase, 1)
|
||||
waitBench(c, "GET", n)
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ func benchGet() {
|
|||
}
|
||||
|
||||
func benchRandGet() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
n := rand.Int() % *number
|
||||
waitBench(c, "GET", n)
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ func benchRandGet() {
|
|||
}
|
||||
|
||||
func benchDel() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
n := atomic.AddInt64(&kvDelBase, 1)
|
||||
waitBench(c, "DEL", n)
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ func benchDel() {
|
|||
}
|
||||
|
||||
func benchPushList() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
value := make([]byte, 100)
|
||||
waitBench(c, "RPUSH", "mytestlist", value)
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ func benchPushList() {
|
|||
}
|
||||
|
||||
func benchRangeList10() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
waitBench(c, "LRANGE", "mytestlist", 0, 10)
|
||||
}
|
||||
|
||||
|
@ -120,7 +120,7 @@ func benchRangeList10() {
|
|||
}
|
||||
|
||||
func benchRangeList50() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
waitBench(c, "LRANGE", "mytestlist", 0, 50)
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ func benchRangeList50() {
|
|||
}
|
||||
|
||||
func benchRangeList100() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
waitBench(c, "LRANGE", "mytestlist", 0, 100)
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ func benchRangeList100() {
|
|||
}
|
||||
|
||||
func benchPopList() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
waitBench(c, "LPOP", "mytestlist")
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ var hashGetBase int64 = 0
|
|||
var hashDelBase int64 = 0
|
||||
|
||||
func benchHset() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
value := make([]byte, 100)
|
||||
|
||||
n := atomic.AddInt64(&hashSetBase, 1)
|
||||
|
@ -160,7 +160,7 @@ func benchHset() {
|
|||
}
|
||||
|
||||
func benchHGet() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
n := atomic.AddInt64(&hashGetBase, 1)
|
||||
waitBench(c, "HGET", "myhashkey", n)
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ func benchHGet() {
|
|||
}
|
||||
|
||||
func benchHRandGet() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
n := rand.Int() % *number
|
||||
waitBench(c, "HGET", "myhashkey", n)
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ func benchHRandGet() {
|
|||
}
|
||||
|
||||
func benchHDel() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
n := atomic.AddInt64(&hashDelBase, 1)
|
||||
waitBench(c, "HDEL", "myhashkey", n)
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ var zsetDelBase int64 = 0
|
|||
var zsetIncrBase int64 = 0
|
||||
|
||||
func benchZAdd() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
member := make([]byte, 16)
|
||||
n := atomic.AddInt64(&zsetAddBase, 1)
|
||||
waitBench(c, "ZADD", "myzsetkey", n, member)
|
||||
|
@ -201,7 +201,7 @@ func benchZAdd() {
|
|||
}
|
||||
|
||||
func benchZDel() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
n := atomic.AddInt64(&zsetDelBase, 1)
|
||||
waitBench(c, "ZREM", "myzsetkey", n)
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ func benchZDel() {
|
|||
}
|
||||
|
||||
func benchZIncr() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
n := atomic.AddInt64(&zsetIncrBase, 1)
|
||||
waitBench(c, "ZINCRBY", "myzsetkey", 1, n)
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ func benchZIncr() {
|
|||
}
|
||||
|
||||
func benchZRangeByScore() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
waitBench(c, "ZRANGEBYSCORE", "myzsetkey", 0, rand.Int(), "withscores", "limit", rand.Int()%100, 100)
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ func benchZRangeByScore() {
|
|||
}
|
||||
|
||||
func benchZRangeByRank() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
waitBench(c, "ZRANGE", "myzsetkey", 0, rand.Int()%100)
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,7 @@ func benchZRangeByRank() {
|
|||
}
|
||||
|
||||
func benchZRevRangeByScore() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
waitBench(c, "ZREVRANGEBYSCORE", "myzsetkey", 0, rand.Int(), "withscores", "limit", rand.Int()%100, 100)
|
||||
}
|
||||
|
||||
|
@ -243,7 +243,7 @@ func benchZRevRangeByScore() {
|
|||
}
|
||||
|
||||
func benchZRevRangeByRank() {
|
||||
f := func(c *ledis.Conn) {
|
||||
f := func(c *goredis.PoolConn) {
|
||||
waitBench(c, "ZREVRANGE", "myzsetkey", 0, rand.Int()%100)
|
||||
}
|
||||
|
||||
|
@ -269,12 +269,10 @@ func main() {
|
|||
|
||||
addr := fmt.Sprintf("%s:%d", *ip, *port)
|
||||
|
||||
cfg := new(ledis.Config)
|
||||
cfg.Addr = addr
|
||||
cfg.MaxIdleConns = *clients
|
||||
cfg.ReadBufferSize = 10240
|
||||
cfg.WriteBufferSize = 10240
|
||||
client = ledis.NewClient(cfg)
|
||||
client = goredis.NewClient(addr, "")
|
||||
client.SetReadBufferSize(10240)
|
||||
client.SetWriteBufferSize(10240)
|
||||
client.SetMaxIdleConns(16)
|
||||
|
||||
for i := 0; i < *clients; i++ {
|
||||
c, _ := client.Get()
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package main
|
||||
|
||||
// CompletionHandler provides possible completions for given input
|
||||
type CompletionHandler func(input string) []string
|
||||
|
||||
// DefaultCompletionHandler simply returns an empty slice.
|
||||
var DefaultCompletionHandler = func(input string) []string {
|
||||
return make([]string, 0)
|
||||
}
|
||||
|
||||
var complHandler = DefaultCompletionHandler
|
||||
|
||||
// SetCompletionHandler sets the CompletionHandler to be used for completion
|
||||
func SetCompletionHandler(c CompletionHandler) {
|
||||
complHandler = c
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
//This file was generated by .tools/generate_commands.py on Wed Mar 04 2015 09:31:59 +0800
|
||||
//This file was generated by .tools/generate_commands.py on Thu Mar 05 2015 15:42:49 +0800
|
||||
package main
|
||||
|
||||
var helpCommands = [][]string{
|
||||
|
@ -106,10 +106,13 @@ var helpCommands = [][]string{
|
|||
{"SYNC", "logid", "Replication"},
|
||||
{"TIME", "-", "Server"},
|
||||
{"TTL", "key", "KV"},
|
||||
{"XHSCAN", "key cursor [MATCH match] [COUNT count]", "Hash"},
|
||||
{"XSCAN", "type cursor [MATCH match] [COUNT count]", "Server"},
|
||||
{"XSSCAN", "key cursor [MATCH match] [COUNT count]", "Set"},
|
||||
{"XZSCAN", "key cursor [MATCH match] [COUNT count]", "ZSet"},
|
||||
{"XHSCAN", "key cursor [MATCH match] [COUNT count] [ASC|DESC]", "Hash"},
|
||||
{"XLSORT", "key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]", "List"},
|
||||
{"XSCAN", "type cursor [MATCH match] [COUNT count] [ASC|DESC]", "Server"},
|
||||
{"XSSCAN", "key cursor [MATCH match] [COUNT count] [ASC|DESC]", "Set"},
|
||||
{"XSSORT", "key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]", "Set"},
|
||||
{"XZSCAN", "key cursor [MATCH match] [COUNT count] [ASC|DESC]", "ZSet"},
|
||||
{"XZSORT", "key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]", "ZSet"},
|
||||
{"ZADD", "key score member [score member ...]", "ZSet"},
|
||||
{"ZCARD", "key", "ZSet"},
|
||||
{"ZCLEAR", "key", "ZSet"},
|
||||
|
@ -119,7 +122,7 @@ var helpCommands = [][]string{
|
|||
{"ZEXPIREAT", "key timestamp", "ZSet"},
|
||||
{"ZINCRBY", "key increment member", "ZSet"},
|
||||
{"ZINTERSTORE", "destkey numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]", "ZSet"},
|
||||
{"ZKEYEXISTS", "ZSet", "Hash"},
|
||||
{"ZKEYEXISTS", "key", "ZSet"},
|
||||
{"ZLEXCOUNT", "key min max", "ZSet"},
|
||||
{"ZMCLEAR", "key [key ...]", "ZSet"},
|
||||
{"ZPERSIST", "key", "ZSet"},
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build linenoise
|
||||
|
||||
/* linenoise.c -- guerrilla line editing library against the idea that a
|
||||
* line editing lib needs to be 20,000 lines of C code.
|
||||
*
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build linenoise
|
||||
|
||||
package main
|
||||
|
||||
//#include <stdlib.h>
|
||||
|
@ -47,21 +49,6 @@ func setHistoryCapacity(capacity int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// CompletionHandler provides possible completions for given input
|
||||
type CompletionHandler func(input string) []string
|
||||
|
||||
// DefaultCompletionHandler simply returns an empty slice.
|
||||
var DefaultCompletionHandler = func(input string) []string {
|
||||
return make([]string, 0)
|
||||
}
|
||||
|
||||
var complHandler = DefaultCompletionHandler
|
||||
|
||||
// SetCompletionHandler sets the CompletionHandler to be used for completion
|
||||
func SetCompletionHandler(c CompletionHandler) {
|
||||
complHandler = c
|
||||
}
|
||||
|
||||
// typedef struct linenoiseCompletions {
|
||||
// size_t len;
|
||||
// char **cvec;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build linenoise
|
||||
|
||||
/* linenoise.h -- guerrilla line editing library against the idea that a
|
||||
* line editing lib needs to be 20,000 lines of C code.
|
||||
*
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// +build linenoise
|
||||
|
||||
#include "linenoiseCompletionCallbackHook.h"
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// +build linenoise
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "linenoise.h"
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
// +build linenoise
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -17,16 +19,15 @@ var dbn = flag.Int("n", 0, "ledisdb database number(default 0)")
|
|||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
cfg := new(ledis.Config)
|
||||
var addr string
|
||||
if len(*socket) > 0 {
|
||||
cfg.Addr = *socket
|
||||
addr = *socket
|
||||
} else {
|
||||
cfg.Addr = fmt.Sprintf("%s:%d", *ip, *port)
|
||||
addr = fmt.Sprintf("%s:%d", *ip, *port)
|
||||
}
|
||||
|
||||
cfg.MaxIdleConns = 1
|
||||
|
||||
c := ledis.NewClient(cfg)
|
||||
c := goredis.NewClient(addr, "")
|
||||
c.SetMaxIdleConns(1)
|
||||
sendSelect(c, *dbn)
|
||||
|
||||
SetCompletionHandler(completionHandler)
|
||||
|
@ -38,9 +39,9 @@ func main() {
|
|||
|
||||
for {
|
||||
if *dbn > 0 && *dbn < 16 {
|
||||
prompt = fmt.Sprintf("%s[%d]>", cfg.Addr, *dbn)
|
||||
prompt = fmt.Sprintf("%s[%d]>", addr, *dbn)
|
||||
} else {
|
||||
prompt = fmt.Sprintf("%s>", cfg.Addr)
|
||||
prompt = fmt.Sprintf("%s>", addr)
|
||||
}
|
||||
|
||||
cmd, err := line(prompt)
|
||||
|
@ -102,7 +103,7 @@ func printReply(level int, reply interface{}) {
|
|||
fmt.Printf("%q", reply)
|
||||
case nil:
|
||||
fmt.Printf("(nil)")
|
||||
case ledis.Error:
|
||||
case goredis.Error:
|
||||
fmt.Printf("%s", string(reply))
|
||||
case []interface{}:
|
||||
for i, v := range reply {
|
||||
|
@ -154,7 +155,7 @@ func printHelp(cmds []string) {
|
|||
}
|
||||
}
|
||||
|
||||
func sendSelect(client *ledis.Client, index int) {
|
||||
func sendSelect(client *goredis.Client, index int) {
|
||||
if index > 16 || index < 0 {
|
||||
index = 0
|
||||
fmt.Println("index out of range, should less than 16")
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
// +build !linenoise
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
println("Please use linenoise to build again, or use redis-cli instead")
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/siddontang/go/num"
|
||||
"github.com/siddontang/ledisdb/config"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var KB = config.KB
|
||||
var MB = config.MB
|
||||
var GB = config.GB
|
||||
|
||||
var name = flag.String("db_name", "goleveldb", "db name")
|
||||
var number = flag.Int("n", 10000, "request number")
|
||||
var clients = flag.Int("c", 50, "number of clients")
|
||||
var round = flag.Int("r", 1, "benchmark round number")
|
||||
var valueSize = flag.Int("vsize", 100, "kv value size")
|
||||
var wg sync.WaitGroup
|
||||
|
||||
var ldb *ledis.Ledis
|
||||
var db *ledis.DB
|
||||
|
||||
var loop int = 0
|
||||
|
||||
func bench(cmd string, f func()) {
|
||||
wg.Add(*clients)
|
||||
|
||||
t1 := time.Now()
|
||||
for i := 0; i < *clients; i++ {
|
||||
go func() {
|
||||
for j := 0; j < loop; j++ {
|
||||
f()
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
t2 := time.Now()
|
||||
|
||||
d := t2.Sub(t1)
|
||||
fmt.Printf("%s %s: %0.3f micros/op, %0.2fmb/s %0.2fop/s\n",
|
||||
cmd,
|
||||
d.String(),
|
||||
float64(d.Nanoseconds()/1e3)/float64(*number),
|
||||
float64((*valueSize+16)*(*number))/(1024.0*1024.0*(d.Seconds())),
|
||||
float64(*number)/d.Seconds())
|
||||
}
|
||||
|
||||
var kvSetBase int64 = 0
|
||||
var kvGetBase int64 = 0
|
||||
|
||||
var value []byte
|
||||
|
||||
func benchSet() {
|
||||
f := func() {
|
||||
n := atomic.AddInt64(&kvSetBase, 1)
|
||||
|
||||
db.Set(num.Int64ToBytes(n), value)
|
||||
}
|
||||
|
||||
bench("set", f)
|
||||
}
|
||||
|
||||
func benchGet() {
|
||||
kvGetBase = 0
|
||||
f := func() {
|
||||
n := atomic.AddInt64(&kvGetBase, 1)
|
||||
v, err := db.Get(num.Int64ToBytes(n))
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
} else if len(v) != *valueSize {
|
||||
println(len(v), *valueSize)
|
||||
}
|
||||
}
|
||||
|
||||
bench("get", f)
|
||||
}
|
||||
|
||||
var kvGetSliceBase int64 = 0
|
||||
|
||||
func benchGetSlice() {
|
||||
kvGetSliceBase = 0
|
||||
f := func() {
|
||||
n := atomic.AddInt64(&kvGetSliceBase, 1)
|
||||
v, err := db.GetSlice(num.Int64ToBytes(n))
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
} else if v != nil {
|
||||
v.Free()
|
||||
}
|
||||
}
|
||||
|
||||
bench("getslice", f)
|
||||
}
|
||||
|
||||
func setRocksDB(cfg *config.RocksDBConfig) {
|
||||
cfg.BlockSize = 64 * KB
|
||||
cfg.WriteBufferSize = 64 * MB
|
||||
cfg.MaxWriteBufferNum = 2
|
||||
cfg.MaxBytesForLevelBase = 512 * MB
|
||||
cfg.TargetFileSizeBase = 64 * MB
|
||||
cfg.BackgroundThreads = 4
|
||||
cfg.HighPriorityBackgroundThreads = 1
|
||||
cfg.MaxBackgroundCompactions = 3
|
||||
cfg.MaxBackgroundFlushes = 1
|
||||
cfg.CacheSize = 512 * MB
|
||||
cfg.EnableStatistics = true
|
||||
cfg.StatsDumpPeriodSec = 5
|
||||
cfg.Level0FileNumCompactionTrigger = 8
|
||||
cfg.MaxBytesForLevelMultiplier = 8
|
||||
}
|
||||
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
flag.Parse()
|
||||
|
||||
value = make([]byte, *valueSize)
|
||||
|
||||
cfg := config.NewConfigDefault()
|
||||
cfg.DataDir = "./var/ledis_dbbench"
|
||||
cfg.DBName = *name
|
||||
os.RemoveAll(cfg.DBPath)
|
||||
defer os.RemoveAll(cfg.DBPath)
|
||||
|
||||
os.MkdirAll(cfg.DBPath, 0755)
|
||||
|
||||
cfg.LevelDB.BlockSize = 32 * KB
|
||||
cfg.LevelDB.CacheSize = 512 * MB
|
||||
cfg.LevelDB.WriteBufferSize = 64 * MB
|
||||
cfg.LevelDB.MaxOpenFiles = 1000
|
||||
|
||||
setRocksDB(&cfg.RocksDB)
|
||||
|
||||
var err error
|
||||
ldb, err = ledis.Open(cfg)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
db, _ = ldb.Select(0)
|
||||
|
||||
if *number <= 0 {
|
||||
panic("invalid number")
|
||||
return
|
||||
}
|
||||
|
||||
if *clients <= 0 || *number < *clients {
|
||||
panic("invalid client number")
|
||||
return
|
||||
}
|
||||
|
||||
loop = *number / *clients
|
||||
|
||||
if *round <= 0 {
|
||||
*round = 1
|
||||
}
|
||||
|
||||
for i := 0; i < *round; i++ {
|
||||
benchSet()
|
||||
benchGet()
|
||||
benchGetSlice()
|
||||
benchGet()
|
||||
benchGetSlice()
|
||||
|
||||
println("")
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"os"
|
||||
)
|
||||
|
||||
|
@ -32,7 +32,7 @@ func main() {
|
|||
addr = fmt.Sprintf("%s:%d", *host, *port)
|
||||
}
|
||||
|
||||
c, err := ledis.ConnectWithSize(addr, 16*1024, 4096)
|
||||
c, err := goredis.ConnectWithSize(addr, 16*1024, 4096)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/siddontang/go/arena"
|
||||
"github.com/siddontang/ledisdb/config"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
"github.com/siddontang/ledisdb/server"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
var KB = config.KB
|
||||
var MB = config.MB
|
||||
var GB = config.GB
|
||||
|
||||
var addr = flag.String("addr", ":6380", "listen addr")
|
||||
var name = flag.String("db_name", "", "db name")
|
||||
|
||||
var ldb *ledis.Ledis
|
||||
var db *ledis.DB
|
||||
|
||||
func setRocksDB(cfg *config.RocksDBConfig) {
|
||||
cfg.BlockSize = 64 * KB
|
||||
cfg.WriteBufferSize = 64 * MB
|
||||
cfg.MaxWriteBufferNum = 2
|
||||
cfg.MaxBytesForLevelBase = 512 * MB
|
||||
cfg.TargetFileSizeBase = 64 * MB
|
||||
cfg.BackgroundThreads = 4
|
||||
cfg.HighPriorityBackgroundThreads = 1
|
||||
cfg.MaxBackgroundCompactions = 3
|
||||
cfg.MaxBackgroundFlushes = 1
|
||||
cfg.CacheSize = 512 * MB
|
||||
cfg.EnableStatistics = true
|
||||
cfg.StatsDumpPeriodSec = 5
|
||||
cfg.Level0FileNumCompactionTrigger = 8
|
||||
cfg.MaxBytesForLevelMultiplier = 8
|
||||
}
|
||||
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
|
||||
flag.Parse()
|
||||
l, err := net.Listen("tcp", *addr)
|
||||
|
||||
println("listen", *addr)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(*name) > 0 {
|
||||
cfg := config.NewConfigDefault()
|
||||
cfg.DataDir = "./var/ledis_respbench"
|
||||
cfg.DBName = *name
|
||||
os.RemoveAll(cfg.DBPath)
|
||||
defer os.RemoveAll(cfg.DBPath)
|
||||
|
||||
os.MkdirAll(cfg.DBPath, 0755)
|
||||
|
||||
cfg.LevelDB.BlockSize = 32 * KB
|
||||
cfg.LevelDB.CacheSize = 512 * MB
|
||||
cfg.LevelDB.WriteBufferSize = 64 * MB
|
||||
cfg.LevelDB.MaxOpenFiles = 1000
|
||||
|
||||
setRocksDB(&cfg.RocksDB)
|
||||
|
||||
ldb, err = ledis.Open(cfg)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
db, _ = ldb.Select(0)
|
||||
}
|
||||
|
||||
for {
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
continue
|
||||
}
|
||||
go run(c)
|
||||
}
|
||||
}
|
||||
|
||||
func run(c net.Conn) {
|
||||
//buf := make([]byte, 10240)
|
||||
ok := []byte("+OK\r\n")
|
||||
data := []byte("$4096\r\n")
|
||||
data = append(data, make([]byte, 4096)...)
|
||||
data = append(data, "\r\n"...)
|
||||
|
||||
var rt time.Duration
|
||||
var wt time.Duration
|
||||
var st time.Duration
|
||||
var gt time.Duration
|
||||
|
||||
rb := bufio.NewReaderSize(c, 10240)
|
||||
wb := bufio.NewWriterSize(c, 10240)
|
||||
|
||||
a := arena.NewArena(10240)
|
||||
|
||||
for {
|
||||
t1 := time.Now()
|
||||
|
||||
a.Reset()
|
||||
|
||||
req, err := server.ReadRequest(rb, a)
|
||||
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
t2 := time.Now()
|
||||
|
||||
rt += t2.Sub(t1)
|
||||
|
||||
cmd := string(bytes.ToUpper(req[0]))
|
||||
switch cmd {
|
||||
case "SET":
|
||||
if db != nil {
|
||||
db.Set(req[1], req[2])
|
||||
st += time.Now().Sub(t2)
|
||||
}
|
||||
wb.Write(ok)
|
||||
case "GET":
|
||||
if db != nil {
|
||||
d, _ := db.GetSlice(req[1])
|
||||
gt += time.Now().Sub(t2)
|
||||
if d == nil {
|
||||
wb.Write(data)
|
||||
} else {
|
||||
wb.WriteString(fmt.Sprintf("$%d\r\n", d.Size()))
|
||||
wb.Write(d.Data())
|
||||
wb.WriteString("\r\n")
|
||||
d.Free()
|
||||
}
|
||||
} else {
|
||||
wb.Write(data)
|
||||
}
|
||||
default:
|
||||
wb.WriteString(fmt.Sprintf("-Err %s Not Supported Now\r\n", req[0]))
|
||||
}
|
||||
|
||||
wb.Flush()
|
||||
|
||||
t3 := time.Now()
|
||||
wt += t3.Sub(t2)
|
||||
}
|
||||
|
||||
fmt.Printf("rt:%s wt %s, gt:%s, st:%s\n", rt.String(), wt.String(), gt.String(), st.String())
|
||||
}
|
|
@ -604,25 +604,25 @@
|
|||
},
|
||||
|
||||
"XSCAN": {
|
||||
"arguments": "type cursor [MATCH match] [COUNT count]",
|
||||
"arguments": "type cursor [MATCH match] [COUNT count] [ASC|DESC]",
|
||||
"group": "Server",
|
||||
"readonly": true
|
||||
},
|
||||
|
||||
"XHSCAN": {
|
||||
"arguments": "key cursor [MATCH match] [COUNT count]",
|
||||
"arguments": "key cursor [MATCH match] [COUNT count] [ASC|DESC]",
|
||||
"group": "Hash",
|
||||
"readonly": true
|
||||
},
|
||||
|
||||
"XSSCAN": {
|
||||
"arguments": "key cursor [MATCH match] [COUNT count]",
|
||||
"arguments": "key cursor [MATCH match] [COUNT count] [ASC|DESC]",
|
||||
"group": "Set",
|
||||
"readonly": true
|
||||
},
|
||||
|
||||
"XZSCAN": {
|
||||
"arguments": "key cursor [MATCH match] [COUNT count]",
|
||||
"arguments": "key cursor [MATCH match] [COUNT count] [ASC|DESC]",
|
||||
"group": "ZSet",
|
||||
"readonly": true
|
||||
},
|
||||
|
@ -712,8 +712,26 @@
|
|||
},
|
||||
|
||||
"ZKEYEXISTS": {
|
||||
"arguments" : "ZSet",
|
||||
"group" : "Hash",
|
||||
"arguments" : "key",
|
||||
"group" : "ZSet",
|
||||
"readonly" : true
|
||||
},
|
||||
|
||||
"XLSORT": {
|
||||
"arguments" : "key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]",
|
||||
"group" : "List",
|
||||
"readonly" : false
|
||||
},
|
||||
|
||||
"XSSORT": {
|
||||
"arguments" : "key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]",
|
||||
"group" : "Set",
|
||||
"readonly" : false
|
||||
},
|
||||
|
||||
"XZSORT": {
|
||||
"arguments" : "key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]",
|
||||
"group" : "ZSet",
|
||||
"readonly" : false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,10 +125,14 @@ Most of the Ledisdb's commands are the same as Redis's, you can see the redis co
|
|||
- [ZDUMP key](#zdump-key)
|
||||
- [ZKEYEXISTS key](#zkeyexists-key)
|
||||
- [Scan](#scan)
|
||||
- [XSCAN type cursor [MATCH match] [COUNT count]](#xscan-type-cursor-match-match-count-count)
|
||||
- [XHSCAN key cursor [MATCH match] [COUNT count]](#xhscan-key-cursor-match-match-count-count)
|
||||
- [XSSCAN key cursor [MATCH match] [COUNT count]](#xsscan-key-cursor-match-match-count-count)
|
||||
- [XZSCAN key cursor [MATCH match] [COUNT count]](#xzscan-key-cursor-match-match-count-count)
|
||||
- [XSCAN type cursor [MATCH match] [COUNT count] [ASC|DESC]](#xscan-type-cursor-match-match-count-count-asc|desc)
|
||||
- [XHSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]](#xhscan-key-cursor-match-match-count-count-asc|desc)
|
||||
- [XSSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]](#xsscan-key-cursor-match-match-count-count-asc|desc)
|
||||
- [XZSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]](#xzscan-key-cursor-match-match-count-count-asc|desc)
|
||||
- [Sort](#sort)
|
||||
- [XLSORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]](#xlsort-key-by-pattern-limit-offset-count-get-pattern-get-pattern--asc|desc-alpha-store-destination)
|
||||
- [XSSORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]](#xssort-key-by-pattern-limit-offset-count-get-pattern-get-pattern--asc|desc-alpha-store-destination)
|
||||
- [XZSORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]](#xzsort-key-by-pattern-limit-offset-count-get-pattern-get-pattern--asc|desc-alpha-store-destination)
|
||||
- [Replication](#replication)
|
||||
- [SLAVEOF host port [RESTART] [READONLY]](#slaveof-host-port-restart-readonly)
|
||||
- [FULLSYNC [NEW]](#fullsync-new)
|
||||
|
@ -2371,7 +2375,7 @@ Check key exists for zset data, like [EXISTS key](#exists-key)
|
|||
|
||||
## Scan
|
||||
|
||||
### XSCAN type cursor [MATCH match] [COUNT count]
|
||||
### XSCAN type cursor [MATCH match] [COUNT count] [ASC|DESC]
|
||||
|
||||
Iterate data type keys incrementally.
|
||||
|
||||
|
@ -2379,6 +2383,7 @@ Type is "KV", "LIST", "HASH", "SET" or "ZSET".
|
|||
Cursor is the start for the current iteration.
|
||||
Match is the regexp for checking matched key.
|
||||
Count is the maximum retrieved elememts number, default is 10.
|
||||
DESC for reverse iterator.
|
||||
|
||||
**Return value**
|
||||
|
||||
|
@ -2410,20 +2415,33 @@ ledis>xscan "KV" "c" count 1
|
|||
2) []
|
||||
```
|
||||
|
||||
### XHSCAN key cursor [MATCH match] [COUNT count]
|
||||
### XHSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]
|
||||
|
||||
Same like [XSCAN type cursor [MATCH match] [COUNT count]](#xscan-type-cursor-match-match-count-count), but return array of elements
|
||||
Same like XSCAN, but return array of elements.
|
||||
contains two elements, a field and a value.
|
||||
|
||||
### XSSCAN key cursor [MATCH match] [COUNT count]
|
||||
### XSSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]
|
||||
|
||||
Same like [XSCAN type cursor [MATCH match] [COUNT count]](#xscan-type-cursor-match-match-count-count)
|
||||
Same like XSCAN.
|
||||
|
||||
### XZSCAN key cursor [MATCH match] [COUNT count]
|
||||
### XZSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]
|
||||
|
||||
Same like [XSCAN type cursor [MATCH match] [COUNT count]](#xscan-type-cursor-match-match-count-count), but return array of elements
|
||||
Same like XSCAN, but return array of elements.
|
||||
contains two elements, a member and its associated score.
|
||||
|
||||
## Sort
|
||||
|
||||
### XLSORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]
|
||||
|
||||
Returns or stores the elements contained in the list at key.
|
||||
|
||||
### XSSORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]
|
||||
|
||||
Returns or stores the elements contained in the set at key.
|
||||
|
||||
### XZSORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]
|
||||
|
||||
Returns or stores the elements contained in the zset at key.
|
||||
|
||||
## Replication
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ package ledis
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/ledis/rdb"
|
||||
"github.com/siddontang/rdb"
|
||||
)
|
||||
|
||||
/*
|
||||
|
@ -43,7 +43,7 @@ func (db *DB) HDump(key []byte) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
o := make(rdb.HashMap, len(v))
|
||||
o := make(rdb.Hash, len(v))
|
||||
for i := 0; i < len(v); i++ {
|
||||
o[i].Field = v[i].Field
|
||||
o[i].Value = v[i].Value
|
||||
|
@ -110,7 +110,7 @@ func (db *DB) Restore(key []byte, ttl int64, data []byte) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
case rdb.HashMap:
|
||||
case rdb.Hash:
|
||||
//first clear old key
|
||||
if _, err = db.HClear(key); err != nil {
|
||||
return err
|
||||
|
|
226
ledis/scan.go
226
ledis/scan.go
|
@ -61,44 +61,19 @@ func buildMatchRegexp(match string) (*regexp.Regexp, error) {
|
|||
return r, nil
|
||||
}
|
||||
|
||||
func (db *DB) scanGeneric(storeDataType byte, key []byte, count int,
|
||||
inclusive bool, match string, reverse bool) ([][]byte, error) {
|
||||
var minKey, maxKey []byte
|
||||
r, err := buildMatchRegexp(match)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (db *DB) buildScanIterator(minKey []byte, maxKey []byte, inclusive bool, reverse bool) *store.RangeLimitIterator {
|
||||
tp := store.RangeOpen
|
||||
|
||||
if !reverse {
|
||||
if minKey, err = db.encodeScanMinKey(storeDataType, key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if maxKey, err = db.encodeScanMaxKey(storeDataType, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if inclusive {
|
||||
tp = store.RangeROpen
|
||||
}
|
||||
} else {
|
||||
if minKey, err = db.encodeScanMinKey(storeDataType, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if maxKey, err = db.encodeScanMaxKey(storeDataType, key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if inclusive {
|
||||
tp = store.RangeLOpen
|
||||
}
|
||||
}
|
||||
|
||||
if count <= 0 {
|
||||
count = defaultScanCount
|
||||
}
|
||||
|
||||
var it *store.RangeLimitIterator
|
||||
if !reverse {
|
||||
it = db.bucket.RangeIterator(minKey, maxKey, tp)
|
||||
|
@ -106,6 +81,53 @@ func (db *DB) scanGeneric(storeDataType byte, key []byte, count int,
|
|||
it = db.bucket.RevRangeIterator(minKey, maxKey, tp)
|
||||
}
|
||||
|
||||
return it
|
||||
}
|
||||
|
||||
func (db *DB) buildScanKeyRange(storeDataType byte, key []byte, reverse bool) (minKey []byte, maxKey []byte, err error) {
|
||||
if !reverse {
|
||||
if minKey, err = db.encodeScanMinKey(storeDataType, key); err != nil {
|
||||
return
|
||||
}
|
||||
if maxKey, err = db.encodeScanMaxKey(storeDataType, nil); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if minKey, err = db.encodeScanMinKey(storeDataType, nil); err != nil {
|
||||
return
|
||||
}
|
||||
if maxKey, err = db.encodeScanMaxKey(storeDataType, key); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkScanCount(count int) int {
|
||||
if count <= 0 {
|
||||
count = defaultScanCount
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func (db *DB) scanGeneric(storeDataType byte, key []byte, count int,
|
||||
inclusive bool, match string, reverse bool) ([][]byte, error) {
|
||||
|
||||
r, err := buildMatchRegexp(match)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
minKey, maxKey, err := db.buildScanKeyRange(storeDataType, key, reverse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count = checkScanCount(count)
|
||||
|
||||
it := db.buildScanIterator(minKey, maxKey, inclusive, reverse)
|
||||
|
||||
v := make([][]byte, 0, count)
|
||||
|
||||
for i := 0; it.Valid() && i < count; it.Next() {
|
||||
|
@ -123,22 +145,11 @@ func (db *DB) scanGeneric(storeDataType byte, key []byte, count int,
|
|||
}
|
||||
|
||||
func (db *DB) encodeScanMinKey(storeDataType byte, key []byte) ([]byte, error) {
|
||||
if len(key) == 0 {
|
||||
return db.encodeScanKey(storeDataType, nil)
|
||||
} else {
|
||||
if err := checkKeySize(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db.encodeScanKey(storeDataType, key)
|
||||
}
|
||||
return db.encodeScanKey(storeDataType, key)
|
||||
}
|
||||
|
||||
func (db *DB) encodeScanMaxKey(storeDataType byte, key []byte) ([]byte, error) {
|
||||
if len(key) > 0 {
|
||||
if err := checkKeySize(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return db.encodeScanKey(storeDataType, key)
|
||||
}
|
||||
|
||||
|
@ -162,12 +173,11 @@ func (db *DB) encodeScanKey(storeDataType byte, key []byte) ([]byte, error) {
|
|||
return db.zEncodeSizeKey(key), nil
|
||||
case SSizeType:
|
||||
return db.sEncodeSizeKey(key), nil
|
||||
// case BitMetaType:
|
||||
// return db.bEncodeMetaKey(key), nil
|
||||
default:
|
||||
return nil, errDataType
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DB) decodeScanKey(storeDataType byte, ek []byte) ([]byte, error) {
|
||||
if len(ek) < 2 || ek[0] != db.index || ek[1] != storeDataType {
|
||||
return nil, errMetaKey
|
||||
|
@ -177,33 +187,89 @@ func (db *DB) decodeScanKey(storeDataType byte, ek []byte) ([]byte, error) {
|
|||
|
||||
// for specail data scan
|
||||
|
||||
func (db *DB) buildDataScanIterator(start []byte, stop []byte, inclusive bool) *store.RangeLimitIterator {
|
||||
tp := store.RangeROpen
|
||||
|
||||
if !inclusive {
|
||||
tp = store.RangeOpen
|
||||
func (db *DB) buildDataScanKeyRange(storeDataType byte, key []byte, cursor []byte, reverse bool) (minKey []byte, maxKey []byte, err error) {
|
||||
if !reverse {
|
||||
if minKey, err = db.encodeDataScanMinKey(storeDataType, key, cursor); err != nil {
|
||||
return
|
||||
}
|
||||
if maxKey, err = db.encodeDataScanMaxKey(storeDataType, key, nil); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if minKey, err = db.encodeDataScanMinKey(storeDataType, key, nil); err != nil {
|
||||
return
|
||||
}
|
||||
if maxKey, err = db.encodeDataScanMaxKey(storeDataType, key, cursor); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
it := db.bucket.RangeIterator(start, stop, tp)
|
||||
return it
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) HScan(key []byte, cursor []byte, count int, inclusive bool, match string) ([]FVPair, error) {
|
||||
func (db *DB) encodeDataScanMinKey(storeDataType byte, key []byte, cursor []byte) ([]byte, error) {
|
||||
return db.encodeDataScanKey(storeDataType, key, cursor)
|
||||
}
|
||||
|
||||
func (db *DB) encodeDataScanMaxKey(storeDataType byte, key []byte, cursor []byte) ([]byte, error) {
|
||||
if len(cursor) > 0 {
|
||||
return db.encodeDataScanKey(storeDataType, key, cursor)
|
||||
}
|
||||
|
||||
k, err := db.encodeDataScanKey(storeDataType, key, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// here, the last byte is the start seperator, set it to stop seperator
|
||||
k[len(k)-1] = k[len(k)-1] + 1
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func (db *DB) encodeDataScanKey(storeDataType byte, key []byte, cursor []byte) ([]byte, error) {
|
||||
switch storeDataType {
|
||||
case HashType:
|
||||
return db.hEncodeHashKey(key, cursor), nil
|
||||
case ZSetType:
|
||||
return db.zEncodeSetKey(key, cursor), nil
|
||||
case SetType:
|
||||
return db.sEncodeSetKey(key, cursor), nil
|
||||
default:
|
||||
return nil, errDataType
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DB) buildDataScanIterator(storeDataType byte, key []byte, cursor []byte, count int,
|
||||
inclusive bool, reverse bool) (*store.RangeLimitIterator, error) {
|
||||
|
||||
if err := checkKeySize(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
start := db.hEncodeHashKey(key, cursor)
|
||||
stop := db.hEncodeStopKey(key)
|
||||
minKey, maxKey, err := db.buildDataScanKeyRange(storeDataType, key, cursor, reverse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := make([]FVPair, 0, 16)
|
||||
it := db.buildScanIterator(minKey, maxKey, inclusive, reverse)
|
||||
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (db *DB) hScanGeneric(key []byte, cursor []byte, count int, inclusive bool, match string, reverse bool) ([]FVPair, error) {
|
||||
count = checkScanCount(count)
|
||||
|
||||
r, err := buildMatchRegexp(match)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
it := db.buildDataScanIterator(start, stop, inclusive)
|
||||
v := make([]FVPair, 0, count)
|
||||
|
||||
it, err := db.buildDataScanIterator(HashType, key, cursor, count, inclusive, reverse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer it.Close()
|
||||
|
||||
for i := 0; it.Valid() && i < count; it.Next() {
|
||||
|
@ -222,22 +288,29 @@ func (db *DB) HScan(key []byte, cursor []byte, count int, inclusive bool, match
|
|||
return v, nil
|
||||
}
|
||||
|
||||
func (db *DB) SScan(key []byte, cursor []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
||||
if err := checkKeySize(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func (db *DB) HScan(key []byte, cursor []byte, count int, inclusive bool, match string) ([]FVPair, error) {
|
||||
return db.hScanGeneric(key, cursor, count, inclusive, match, false)
|
||||
}
|
||||
|
||||
start := db.sEncodeSetKey(key, cursor)
|
||||
stop := db.sEncodeStopKey(key)
|
||||
func (db *DB) HRevScan(key []byte, cursor []byte, count int, inclusive bool, match string) ([]FVPair, error) {
|
||||
return db.hScanGeneric(key, cursor, count, inclusive, match, true)
|
||||
}
|
||||
|
||||
v := make([][]byte, 0, 16)
|
||||
func (db *DB) sScanGeneric(key []byte, cursor []byte, count int, inclusive bool, match string, reverse bool) ([][]byte, error) {
|
||||
count = checkScanCount(count)
|
||||
|
||||
r, err := buildMatchRegexp(match)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
it := db.buildDataScanIterator(start, stop, inclusive)
|
||||
v := make([][]byte, 0, count)
|
||||
|
||||
it, err := db.buildDataScanIterator(SetType, key, cursor, count, inclusive, reverse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer it.Close()
|
||||
|
||||
for i := 0; it.Valid() && i < count; it.Next() {
|
||||
|
@ -256,22 +329,29 @@ func (db *DB) SScan(key []byte, cursor []byte, count int, inclusive bool, match
|
|||
return v, nil
|
||||
}
|
||||
|
||||
func (db *DB) ZScan(key []byte, cursor []byte, count int, inclusive bool, match string) ([]ScorePair, error) {
|
||||
if err := checkKeySize(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func (db *DB) SScan(key []byte, cursor []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
||||
return db.sScanGeneric(key, cursor, count, inclusive, match, false)
|
||||
}
|
||||
|
||||
start := db.zEncodeSetKey(key, cursor)
|
||||
stop := db.zEncodeStopSetKey(key)
|
||||
func (db *DB) SRevScan(key []byte, cursor []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
||||
return db.sScanGeneric(key, cursor, count, inclusive, match, true)
|
||||
}
|
||||
|
||||
v := make([]ScorePair, 0, 16)
|
||||
func (db *DB) zScanGeneric(key []byte, cursor []byte, count int, inclusive bool, match string, reverse bool) ([]ScorePair, error) {
|
||||
count = checkScanCount(count)
|
||||
|
||||
r, err := buildMatchRegexp(match)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
it := db.buildDataScanIterator(start, stop, inclusive)
|
||||
v := make([]ScorePair, 0, count)
|
||||
|
||||
it, err := db.buildDataScanIterator(ZSetType, key, cursor, count, inclusive, reverse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer it.Close()
|
||||
|
||||
for i := 0; it.Valid() && i < count; it.Next() {
|
||||
|
@ -294,3 +374,11 @@ func (db *DB) ZScan(key []byte, cursor []byte, count int, inclusive bool, match
|
|||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (db *DB) ZScan(key []byte, cursor []byte, count int, inclusive bool, match string) ([]ScorePair, error) {
|
||||
return db.zScanGeneric(key, cursor, count, inclusive, match, false)
|
||||
}
|
||||
|
||||
func (db *DB) ZRevScan(key []byte, cursor []byte, count int, inclusive bool, match string) ([]ScorePair, error) {
|
||||
return db.zScanGeneric(key, cursor, count, inclusive, match, true)
|
||||
}
|
||||
|
|
|
@ -323,6 +323,16 @@ func TestDBHScan(t *testing.T) {
|
|||
} else if string(v[0].Field) != "222" {
|
||||
t.Fatal(string(v[0].Field))
|
||||
}
|
||||
|
||||
v, err = db.HRevScan(key, []byte("19"), 1, false, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(v) != 1 {
|
||||
t.Fatal("invalid count", len(v))
|
||||
} else if string(v[0].Field) != "1234" {
|
||||
t.Fatal(string(v[0].Field))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestDBSScan(t *testing.T) {
|
||||
|
@ -346,6 +356,16 @@ func TestDBSScan(t *testing.T) {
|
|||
} else if string(v[0]) != "222" {
|
||||
t.Fatal(string(v[0]))
|
||||
}
|
||||
|
||||
v, err = db.SRevScan(key, []byte("19"), 1, false, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(v) != 1 {
|
||||
t.Fatal("invalid count", len(v))
|
||||
} else if string(v[0]) != "1234" {
|
||||
t.Fatal(string(v[0]))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestDBZScan(t *testing.T) {
|
||||
|
@ -369,4 +389,14 @@ func TestDBZScan(t *testing.T) {
|
|||
} else if string(v[0].Member) != "222" {
|
||||
t.Fatal(string(v[0].Member))
|
||||
}
|
||||
|
||||
v, err = db.ZRevScan(key, []byte("19"), 1, false, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(v) != 1 {
|
||||
t.Fatal("invalid count", len(v))
|
||||
} else if string(v[0].Member) != "1234" {
|
||||
t.Fatal(string(v[0].Member))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package ledis
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/siddontang/go/log"
|
||||
"github.com/siddontang/ledisdb/store"
|
||||
)
|
||||
|
||||
|
@ -26,6 +27,8 @@ func (db *DB) IsTransaction() bool {
|
|||
// Begin a transaction, it will block all other write operations before calling Commit or Rollback.
|
||||
// You must be very careful to prevent long-time transaction.
|
||||
func (db *DB) Begin() (*Tx, error) {
|
||||
log.Warn("Transaction support will be removed later, use your own risk!!!")
|
||||
|
||||
if db.IsTransaction() {
|
||||
return nil, ErrNestTx
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
goledis "github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"github.com/siddontang/ledisdb/config"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
"net"
|
||||
|
@ -44,8 +44,9 @@ type App struct {
|
|||
rcm sync.Mutex
|
||||
rcs map[*respClient]struct{}
|
||||
|
||||
migrateM sync.Mutex
|
||||
migrateClients map[string]*goledis.Client
|
||||
migrateM sync.Mutex
|
||||
migrateClients map[string]*goredis.Client
|
||||
migrateKeyLockers map[string]*migrateKeyLocker
|
||||
}
|
||||
|
||||
func netType(s string) string {
|
||||
|
@ -75,7 +76,8 @@ func NewApp(cfg *config.Config) (*App, error) {
|
|||
|
||||
app.rcs = make(map[*respClient]struct{})
|
||||
|
||||
app.migrateClients = make(map[string]*goledis.Client)
|
||||
app.migrateClients = make(map[string]*goredis.Client)
|
||||
app.newMigrateKeyLockers()
|
||||
|
||||
var err error
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"github.com/siddontang/ledisdb/config"
|
||||
"os"
|
||||
"sync"
|
||||
|
@ -11,16 +11,14 @@ import (
|
|||
var testAppOnce sync.Once
|
||||
var testApp *App
|
||||
|
||||
var testLedisClient *ledis.Client
|
||||
var testLedisClient *goredis.Client
|
||||
|
||||
func newTestLedisClient() {
|
||||
cfg := new(ledis.Config)
|
||||
cfg.Addr = "127.0.0.1:16380"
|
||||
cfg.MaxIdleConns = 4
|
||||
testLedisClient = ledis.NewClient(cfg)
|
||||
testLedisClient = goredis.NewClient("127.0.0.1:16380", "")
|
||||
testLedisClient.SetMaxIdleConns(4)
|
||||
}
|
||||
|
||||
func getTestConn() *ledis.Conn {
|
||||
func getTestConn() *goredis.PoolConn {
|
||||
startTestApp()
|
||||
conn, _ := testLedisClient.Get()
|
||||
return conn
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package server
|
||||
|
||||
// import (
|
||||
// "github.com/siddontang/ledisdb/client/goledis"
|
||||
// "github.com/siddontang/goredis"
|
||||
// "testing"
|
||||
// )
|
||||
|
||||
|
@ -19,19 +19,19 @@ package server
|
|||
// key := []byte("test_cmd_bin_basic")
|
||||
|
||||
// // get / set
|
||||
// if v, err := ledis.Int(c.Do("bgetbit", key, 1024)); err != nil {
|
||||
// if v, err := goredis.Int(c.Do("bgetbit", key, 1024)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if v != 0 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// if ori, err := ledis.Int(c.Do("bsetbit", key, 1024, 1)); err != nil {
|
||||
// if ori, err := goredis.Int(c.Do("bsetbit", key, 1024, 1)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if ori != 0 {
|
||||
// t.Fatal(ori)
|
||||
// }
|
||||
|
||||
// if v, err := ledis.Int(c.Do("bgetbit", key, 1024)); err != nil {
|
||||
// if v, err := goredis.Int(c.Do("bgetbit", key, 1024)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if v != 1 {
|
||||
// t.Fatal(v)
|
||||
|
@ -40,26 +40,26 @@ package server
|
|||
// // fetch from revert pos
|
||||
// c.Do("bsetbit", key, 1000, 1)
|
||||
|
||||
// if v, err := ledis.Int(c.Do("bgetbit", key, -1)); err != nil {
|
||||
// if v, err := goredis.Int(c.Do("bgetbit", key, -1)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if v != 1 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// if v, err := ledis.Int(c.Do("bgetbit", key, -25)); err != nil {
|
||||
// if v, err := goredis.Int(c.Do("bgetbit", key, -25)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if v != 1 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// // delete
|
||||
// if drop, err := ledis.Int(c.Do("bdelete", key)); err != nil {
|
||||
// if drop, err := goredis.Int(c.Do("bdelete", key)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if drop != 1 {
|
||||
// t.Fatal(drop)
|
||||
// }
|
||||
|
||||
// if drop, err := ledis.Int(c.Do("bdelete", key)); err != nil {
|
||||
// if drop, err := goredis.Int(c.Do("bdelete", key)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if drop != 0 {
|
||||
// t.Fatal(drop)
|
||||
|
@ -72,7 +72,7 @@ package server
|
|||
|
||||
// key := []byte("test_cmd_bin_mset")
|
||||
|
||||
// if n, err := ledis.Int(
|
||||
// if n, err := goredis.Int(
|
||||
// c.Do("bmsetbit", key,
|
||||
// 500, 0,
|
||||
// 100, 1,
|
||||
|
@ -90,14 +90,14 @@ package server
|
|||
|
||||
// fillPos := []int{100, 200, 300, 1000, 100000, 500000}
|
||||
// for _, pos := range fillPos {
|
||||
// v, err := ledis.Int(c.Do("bgetbit", key, pos))
|
||||
// v, err := goredis.Int(c.Do("bgetbit", key, pos))
|
||||
// if err != nil || v != 1 {
|
||||
// t.Fatal(pos)
|
||||
// }
|
||||
// }
|
||||
|
||||
// // err
|
||||
// if n, err := ledis.Int(
|
||||
// if n, err := goredis.Int(
|
||||
// c.Do("bmsetbit", key, 3, 0, 2, 1, 3, 0, 1, 1)); err == nil || n != 0 {
|
||||
// t.Fatal(n) // duplication on pos
|
||||
// }
|
||||
|
@ -114,7 +114,7 @@ package server
|
|||
// sum++
|
||||
// }
|
||||
|
||||
// if n, err := ledis.Int(c.Do("bcount", key)); err != nil {
|
||||
// if n, err := goredis.Int(c.Do("bcount", key)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if n != sum {
|
||||
// t.Fatal(n)
|
||||
|
@ -137,21 +137,21 @@ package server
|
|||
// // todo ...
|
||||
|
||||
// // case - 'not' on inexisting key
|
||||
// if blen, err := ledis.Int(
|
||||
// if blen, err := goredis.Int(
|
||||
// c.Do("bopt", "not", dstk, kmiss)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if blen != 0 {
|
||||
// t.Fatal(blen)
|
||||
// }
|
||||
|
||||
// if v, _ := ledis.String(c.Do("bget", dstk)); v != "" {
|
||||
// if v, _ := goredis.String(c.Do("bget", dstk)); v != "" {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// // case - 'and', 'or', 'xor' with inexisting key
|
||||
// opts := []string{"and", "or", "xor"}
|
||||
// for _, op := range opts {
|
||||
// if blen, err := ledis.Int(
|
||||
// if blen, err := goredis.Int(
|
||||
// c.Do("bopt", op, dstk, kmiss, k0)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if blen != 0 {
|
||||
|
@ -160,62 +160,62 @@ package server
|
|||
// }
|
||||
|
||||
// // case - 'and'
|
||||
// if blen, err := ledis.Int(
|
||||
// if blen, err := goredis.Int(
|
||||
// c.Do("bopt", "and", dstk, k0, k1)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if blen != 101 {
|
||||
// t.Fatal(blen)
|
||||
// }
|
||||
|
||||
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 100)); v != 1 {
|
||||
// if v, _ := goredis.Int(c.Do("bgetbit", dstk, 100)); v != 1 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 20)); v != 0 {
|
||||
// if v, _ := goredis.Int(c.Do("bgetbit", dstk, 20)); v != 0 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 40)); v != 0 {
|
||||
// if v, _ := goredis.Int(c.Do("bgetbit", dstk, 40)); v != 0 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// // case - 'or'
|
||||
// if blen, err := ledis.Int(
|
||||
// if blen, err := goredis.Int(
|
||||
// c.Do("bopt", "or", dstk, k0, k1)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if blen != 101 {
|
||||
// t.Fatal(blen)
|
||||
// }
|
||||
|
||||
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 100)); v != 1 {
|
||||
// if v, _ := goredis.Int(c.Do("bgetbit", dstk, 100)); v != 1 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 20)); v != 1 {
|
||||
// if v, _ := goredis.Int(c.Do("bgetbit", dstk, 20)); v != 1 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 40)); v != 1 {
|
||||
// if v, _ := goredis.Int(c.Do("bgetbit", dstk, 40)); v != 1 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// // case - 'xor'
|
||||
// if blen, err := ledis.Int(
|
||||
// if blen, err := goredis.Int(
|
||||
// c.Do("bopt", "xor", dstk, k0, k1)); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else if blen != 101 {
|
||||
// t.Fatal(blen)
|
||||
// }
|
||||
|
||||
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 100)); v != 0 {
|
||||
// if v, _ := goredis.Int(c.Do("bgetbit", dstk, 100)); v != 0 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 20)); v != 1 {
|
||||
// if v, _ := goredis.Int(c.Do("bgetbit", dstk, 20)); v != 1 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 40)); v != 1 {
|
||||
// if v, _ := goredis.Int(c.Do("bgetbit", dstk, 40)); v != 1 {
|
||||
// t.Fatal(v)
|
||||
// }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
@ -12,54 +12,54 @@ func TestHash(t *testing.T) {
|
|||
defer c.Close()
|
||||
|
||||
key := []byte("a")
|
||||
if n, err := ledis.Int(c.Do("hkeyexists", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hkeyexists", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hset", key, 1, 0)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hset", key, 1, 0)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
if n, err := ledis.Int(c.Do("hkeyexists", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hkeyexists", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hexists", key, 1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hexists", key, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hexists", key, -1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hexists", key, -1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hget", key, 1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hget", key, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hset", key, 1, 1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hset", key, 1, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hget", key, 1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hget", key, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hlen", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hlen", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
|
@ -95,19 +95,19 @@ func TestHashM(t *testing.T) {
|
|||
defer c.Close()
|
||||
|
||||
key := []byte("b")
|
||||
if ok, err := ledis.String(c.Do("hmset", key, 1, 1, 2, 2, 3, 3)); err != nil {
|
||||
if ok, err := goredis.String(c.Do("hmset", key, 1, 1, 2, 2, 3, 3)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if ok != OK {
|
||||
t.Fatal(ok)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hlen", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hlen", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 3 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("hmget", key, 1, 2, 3, 4)); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("hmget", key, 1, 2, 3, 4)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testHashArray(v, 1, 2, 3, 0); err != nil {
|
||||
|
@ -115,19 +115,19 @@ func TestHashM(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hdel", key, 1, 2, 3, 4)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hdel", key, 1, 2, 3, 4)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 3 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hlen", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hlen", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("hmget", key, 1, 2, 3, 4)); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("hmget", key, 1, 2, 3, 4)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testHashArray(v, 0, 0, 0, 0); err != nil {
|
||||
|
@ -135,7 +135,7 @@ func TestHashM(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hlen", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hlen", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
|
@ -147,31 +147,31 @@ func TestHashIncr(t *testing.T) {
|
|||
defer c.Close()
|
||||
|
||||
key := []byte("c")
|
||||
if n, err := ledis.Int(c.Do("hincrby", key, 1, 1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hincrby", key, 1, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hlen", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hlen", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hincrby", key, 1, 10)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hincrby", key, 1, 10)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 11 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hlen", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hlen", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hincrby", key, 1, -11)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hincrby", key, 1, -11)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(err)
|
||||
|
@ -185,13 +185,13 @@ func TestHashGetAll(t *testing.T) {
|
|||
|
||||
key := []byte("d")
|
||||
|
||||
if ok, err := ledis.String(c.Do("hmset", key, 1, 1, 2, 2, 3, 3)); err != nil {
|
||||
if ok, err := goredis.String(c.Do("hmset", key, 1, 1, 2, 2, 3, 3)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if ok != OK {
|
||||
t.Fatal(ok)
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("hgetall", key)); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("hgetall", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testHashArray(v, 1, 1, 2, 2, 3, 3); err != nil {
|
||||
|
@ -199,7 +199,7 @@ func TestHashGetAll(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("hkeys", key)); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("hkeys", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testHashArray(v, 1, 2, 3); err != nil {
|
||||
|
@ -207,7 +207,7 @@ func TestHashGetAll(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("hvals", key)); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("hvals", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testHashArray(v, 1, 2, 3); err != nil {
|
||||
|
@ -215,13 +215,13 @@ func TestHashGetAll(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hclear", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hclear", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 3 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("hlen", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("hlen", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -9,121 +9,121 @@ func TestKV(t *testing.T) {
|
|||
c := getTestConn()
|
||||
defer c.Close()
|
||||
|
||||
if ok, err := ledis.String(c.Do("set", "a", "1234")); err != nil {
|
||||
if ok, err := goredis.String(c.Do("set", "a", "1234")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if ok != OK {
|
||||
t.Fatal(ok)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("setnx", "a", "123")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("setnx", "a", "123")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("setnx", "b", "123")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("setnx", "b", "123")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if ok, err := ledis.String(c.Do("setex", "xx", 10, "hello world")); err != nil {
|
||||
if ok, err := goredis.String(c.Do("setex", "xx", 10, "hello world")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if ok != OK {
|
||||
t.Fatal(ok)
|
||||
}
|
||||
|
||||
if v, err := ledis.String(c.Do("get", "a")); err != nil {
|
||||
if v, err := goredis.String(c.Do("get", "a")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if v != "1234" {
|
||||
t.Fatal(v)
|
||||
}
|
||||
|
||||
if v, err := ledis.String(c.Do("getset", "a", "123")); err != nil {
|
||||
if v, err := goredis.String(c.Do("getset", "a", "123")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if v != "1234" {
|
||||
t.Fatal(v)
|
||||
}
|
||||
|
||||
if v, err := ledis.String(c.Do("get", "a")); err != nil {
|
||||
if v, err := goredis.String(c.Do("get", "a")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if v != "123" {
|
||||
t.Fatal(v)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("exists", "a")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("exists", "a")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("exists", "empty_key_test")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("exists", "empty_key_test")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if _, err := ledis.Int(c.Do("del", "a", "b")); err != nil {
|
||||
if _, err := goredis.Int(c.Do("del", "a", "b")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("exists", "a")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("exists", "a")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("exists", "b")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("exists", "b")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
rangeKey := "range_key"
|
||||
if n, err := ledis.Int(c.Do("append", rangeKey, "Hello ")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("append", rangeKey, "Hello ")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 6 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("setrange", rangeKey, 6, "Redis")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("setrange", rangeKey, 6, "Redis")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 11 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("strlen", rangeKey)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("strlen", rangeKey)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 11 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if v, err := ledis.String(c.Do("getrange", rangeKey, 0, -1)); err != nil {
|
||||
if v, err := goredis.String(c.Do("getrange", rangeKey, 0, -1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if v != "Hello Redis" {
|
||||
t.Fatal(v)
|
||||
}
|
||||
|
||||
bitKey := "bit_key"
|
||||
if n, err := ledis.Int(c.Do("setbit", bitKey, 7, 1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("setbit", bitKey, 7, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("getbit", bitKey, 7)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("getbit", bitKey, 7)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("bitcount", bitKey)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("bitcount", bitKey)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("bitpos", bitKey, 1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("bitpos", bitKey, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 7 {
|
||||
t.Fatal(n)
|
||||
|
@ -132,13 +132,13 @@ func TestKV(t *testing.T) {
|
|||
c.Do("set", "key1", "foobar")
|
||||
c.Do("set", "key2", "abcdef")
|
||||
|
||||
if n, err := ledis.Int(c.Do("bitop", "and", "bit_dest_key", "key1", "key2")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("bitop", "and", "bit_dest_key", "key1", "key2")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 6 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if v, err := ledis.String(c.Do("get", "bit_dest_key")); err != nil {
|
||||
if v, err := goredis.String(c.Do("get", "bit_dest_key")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if v != "`bc`ab" {
|
||||
t.Fatal(v)
|
||||
|
@ -150,13 +150,13 @@ func TestKVM(t *testing.T) {
|
|||
c := getTestConn()
|
||||
defer c.Close()
|
||||
|
||||
if ok, err := ledis.String(c.Do("mset", "a", "1", "b", "2")); err != nil {
|
||||
if ok, err := goredis.String(c.Do("mset", "a", "1", "b", "2")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if ok != OK {
|
||||
t.Fatal(ok)
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("mget", "a", "b", "c")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("mget", "a", "b", "c")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(v) != 3 {
|
||||
t.Fatal(len(v))
|
||||
|
@ -179,31 +179,31 @@ func TestKVIncrDecr(t *testing.T) {
|
|||
c := getTestConn()
|
||||
defer c.Close()
|
||||
|
||||
if n, err := ledis.Int64(c.Do("incr", "n")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("incr", "n")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("incr", "n")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("incr", "n")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("decr", "n")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("decr", "n")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("incrby", "n", 10)); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("incrby", "n", 10)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 11 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("decrby", "n", 10)); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("decrby", "n", 10)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
|
|
|
@ -2,7 +2,7 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
@ -11,10 +11,10 @@ func testListIndex(key []byte, index int64, v int) error {
|
|||
c := getTestConn()
|
||||
defer c.Close()
|
||||
|
||||
n, err := ledis.Int(c.Do("lindex", key, index))
|
||||
if err == ledis.ErrNil && v != 0 {
|
||||
n, err := goredis.Int(c.Do("lindex", key, index))
|
||||
if err == goredis.ErrNil && v != 0 {
|
||||
return fmt.Errorf("must nil")
|
||||
} else if err != nil && err != ledis.ErrNil {
|
||||
} else if err != nil && err != goredis.ErrNil {
|
||||
return err
|
||||
} else if n != v {
|
||||
return fmt.Errorf("index err number %d != %d", n, v)
|
||||
|
@ -27,7 +27,7 @@ func testListRange(key []byte, start int64, stop int64, checkValues ...int) erro
|
|||
c := getTestConn()
|
||||
defer c.Close()
|
||||
|
||||
vs, err := ledis.MultiBulk(c.Do("lrange", key, start, stop))
|
||||
vs, err := goredis.MultiBulk(c.Do("lrange", key, start, stop))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -58,37 +58,37 @@ func TestList(t *testing.T) {
|
|||
defer c.Close()
|
||||
|
||||
key := []byte("a")
|
||||
if n, err := ledis.Int(c.Do("lkeyexists", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("lkeyexists", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("lpush", key, 1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("lpush", key, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("lkeyexists", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("lkeyexists", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(1)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("rpush", key, 2)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("rpush", key, 2)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("rpush", key, 3)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("rpush", key, 3)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 3 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("llen", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("llen", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 3 {
|
||||
t.Fatal(n)
|
||||
|
@ -212,7 +212,7 @@ func TestListMPush(t *testing.T) {
|
|||
defer c.Close()
|
||||
|
||||
key := []byte("b")
|
||||
if n, err := ledis.Int(c.Do("rpush", key, 1, 2, 3)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("rpush", key, 1, 2, 3)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 3 {
|
||||
t.Fatal(n)
|
||||
|
@ -222,7 +222,7 @@ func TestListMPush(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("lpush", key, 1, 2, 3)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("lpush", key, 1, 2, 3)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 6 {
|
||||
t.Fatal(n)
|
||||
|
@ -238,25 +238,25 @@ func TestPop(t *testing.T) {
|
|||
defer c.Close()
|
||||
|
||||
key := []byte("c")
|
||||
if n, err := ledis.Int(c.Do("rpush", key, 1, 2, 3, 4, 5, 6)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("rpush", key, 1, 2, 3, 4, 5, 6)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 6 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if v, err := ledis.Int(c.Do("lpop", key)); err != nil {
|
||||
if v, err := goredis.Int(c.Do("lpop", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if v != 1 {
|
||||
t.Fatal(v)
|
||||
}
|
||||
|
||||
if v, err := ledis.Int(c.Do("rpop", key)); err != nil {
|
||||
if v, err := goredis.Int(c.Do("rpop", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if v != 6 {
|
||||
t.Fatal(v)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("lpush", key, 1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("lpush", key, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 5 {
|
||||
t.Fatal(n)
|
||||
|
@ -267,14 +267,14 @@ func TestPop(t *testing.T) {
|
|||
}
|
||||
|
||||
for i := 1; i <= 5; i++ {
|
||||
if v, err := ledis.Int(c.Do("lpop", key)); err != nil {
|
||||
if v, err := goredis.Int(c.Do("lpop", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if v != i {
|
||||
t.Fatal(v)
|
||||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("llen", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("llen", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
|
@ -282,13 +282,13 @@ func TestPop(t *testing.T) {
|
|||
|
||||
c.Do("rpush", key, 1, 2, 3, 4, 5)
|
||||
|
||||
if n, err := ledis.Int(c.Do("lclear", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("lclear", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 5 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("llen", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("llen", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
goledis "github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/siddontang/go/hack"
|
||||
"github.com/siddontang/go/log"
|
||||
"github.com/siddontang/goredis"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
)
|
||||
|
||||
func dumpCommand(c *client) error {
|
||||
|
@ -106,19 +111,42 @@ func restoreCommand(c *client) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// maybe only used in xcodis for redis data port
|
||||
func xrestoreCommand(c *client) error {
|
||||
args := c.args
|
||||
if len(args) != 4 {
|
||||
return ErrCmdParams
|
||||
}
|
||||
|
||||
// tp := strings.ToUpper(string(args[2]))
|
||||
key := args[1]
|
||||
ttl, err := ledis.StrInt64(args[2], nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data := args[3]
|
||||
|
||||
if err = c.db.Restore(key, ttl, data); err != nil {
|
||||
return err
|
||||
} else {
|
||||
c.resp.writeStatus(OK)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func xdump(db *ledis.DB, tp string, key []byte) ([]byte, error) {
|
||||
var err error
|
||||
var data []byte
|
||||
switch strings.ToUpper(tp) {
|
||||
case "KV":
|
||||
case KVName:
|
||||
data, err = db.Dump(key)
|
||||
case "HASH":
|
||||
case HashName:
|
||||
data, err = db.HDump(key)
|
||||
case "LIST":
|
||||
case ListName:
|
||||
data, err = db.LDump(key)
|
||||
case "SET":
|
||||
case SetName:
|
||||
data, err = db.SDump(key)
|
||||
case "ZSET":
|
||||
case ZSetName:
|
||||
data, err = db.ZDump(key)
|
||||
default:
|
||||
err = fmt.Errorf("invalid key type %s", tp)
|
||||
|
@ -129,15 +157,15 @@ func xdump(db *ledis.DB, tp string, key []byte) ([]byte, error) {
|
|||
func xdel(db *ledis.DB, tp string, key []byte) error {
|
||||
var err error
|
||||
switch strings.ToUpper(tp) {
|
||||
case "KV":
|
||||
case KVName:
|
||||
_, err = db.Del(key)
|
||||
case "HASH":
|
||||
case HashName:
|
||||
_, err = db.HClear(key)
|
||||
case "LIST":
|
||||
case ListName:
|
||||
_, err = db.LClear(key)
|
||||
case "SET":
|
||||
case SetName:
|
||||
_, err = db.SClear(key)
|
||||
case "ZSET":
|
||||
case ZSetName:
|
||||
_, err = db.ZClear(key)
|
||||
default:
|
||||
err = fmt.Errorf("invalid key type %s", tp)
|
||||
|
@ -147,15 +175,15 @@ func xdel(db *ledis.DB, tp string, key []byte) error {
|
|||
|
||||
func xttl(db *ledis.DB, tp string, key []byte) (int64, error) {
|
||||
switch strings.ToUpper(tp) {
|
||||
case "KV":
|
||||
case KVName:
|
||||
return db.TTL(key)
|
||||
case "HASH":
|
||||
case HashName:
|
||||
return db.HTTL(key)
|
||||
case "LIST":
|
||||
case ListName:
|
||||
return db.LTTL(key)
|
||||
case "SET":
|
||||
case SetName:
|
||||
return db.STTL(key)
|
||||
case "ZSET":
|
||||
case ZSetName:
|
||||
return db.ZTTL(key)
|
||||
default:
|
||||
return 0, fmt.Errorf("invalid key type %s", tp)
|
||||
|
@ -164,15 +192,15 @@ func xttl(db *ledis.DB, tp string, key []byte) (int64, error) {
|
|||
|
||||
func xscan(db *ledis.DB, tp string, count int) ([][]byte, error) {
|
||||
switch strings.ToUpper(tp) {
|
||||
case "KV":
|
||||
case KVName:
|
||||
return db.Scan(KV, nil, count, false, "")
|
||||
case "HASH":
|
||||
case HashName:
|
||||
return db.Scan(HASH, nil, count, false, "")
|
||||
case "LIST":
|
||||
case ListName:
|
||||
return db.Scan(LIST, nil, count, false, "")
|
||||
case "SET":
|
||||
case SetName:
|
||||
return db.Scan(SET, nil, count, false, "")
|
||||
case "ZSET":
|
||||
case ZSetName:
|
||||
return db.Scan(ZSET, nil, count, false, "")
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid key type %s", tp)
|
||||
|
@ -185,7 +213,7 @@ func xdumpCommand(c *client) error {
|
|||
return ErrCmdParams
|
||||
}
|
||||
|
||||
tp := string(args[0])
|
||||
tp := strings.ToUpper(string(args[0]))
|
||||
key := args[1]
|
||||
|
||||
if data, err := xdump(c.db, tp, key); err != nil {
|
||||
|
@ -196,14 +224,13 @@ func xdumpCommand(c *client) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (app *App) getMigrateClient(addr string) *goledis.Client {
|
||||
func (app *App) getMigrateClient(addr string) *goredis.Client {
|
||||
app.migrateM.Lock()
|
||||
|
||||
mc, ok := app.migrateClients[addr]
|
||||
if !ok {
|
||||
mc = goledis.NewClient(&goledis.Config{addr, 4, 0, 0})
|
||||
mc = goredis.NewClient(addr, "")
|
||||
app.migrateClients[addr] = mc
|
||||
|
||||
}
|
||||
|
||||
app.migrateM.Unlock()
|
||||
|
@ -211,6 +238,68 @@ func (app *App) getMigrateClient(addr string) *goledis.Client {
|
|||
return mc
|
||||
}
|
||||
|
||||
type migrateKeyLocker struct {
|
||||
m sync.Mutex
|
||||
|
||||
locks map[string]struct{}
|
||||
}
|
||||
|
||||
func (m *migrateKeyLocker) Lock(key []byte) bool {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
k := hack.String(key)
|
||||
_, ok := m.locks[k]
|
||||
if ok {
|
||||
return false
|
||||
}
|
||||
m.locks[k] = struct{}{}
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *migrateKeyLocker) Unlock(key []byte) {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
delete(m.locks, hack.String(key))
|
||||
}
|
||||
|
||||
func newMigrateKeyLocker() *migrateKeyLocker {
|
||||
m := new(migrateKeyLocker)
|
||||
|
||||
m.locks = make(map[string]struct{})
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (a *App) newMigrateKeyLockers() {
|
||||
a.migrateKeyLockers = make(map[string]*migrateKeyLocker)
|
||||
|
||||
a.migrateKeyLockers[KVName] = newMigrateKeyLocker()
|
||||
a.migrateKeyLockers[HashName] = newMigrateKeyLocker()
|
||||
a.migrateKeyLockers[ListName] = newMigrateKeyLocker()
|
||||
a.migrateKeyLockers[SetName] = newMigrateKeyLocker()
|
||||
a.migrateKeyLockers[ZSetName] = newMigrateKeyLocker()
|
||||
}
|
||||
|
||||
func (a *App) migrateKeyLock(tp string, key []byte) bool {
|
||||
l, ok := a.migrateKeyLockers[strings.ToUpper(tp)]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return l.Lock(key)
|
||||
}
|
||||
|
||||
func (a *App) migrateKeyUnlock(tp string, key []byte) {
|
||||
l, ok := a.migrateKeyLockers[strings.ToUpper(tp)]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
l.Unlock(key)
|
||||
}
|
||||
|
||||
//XMIGRATEDB host port tp count db timeout
|
||||
//select count tp type keys and migrate
|
||||
//will block any other write operations
|
||||
|
@ -227,7 +316,7 @@ func xmigratedbCommand(c *client) error {
|
|||
return fmt.Errorf("migrate in same server is not allowed")
|
||||
}
|
||||
|
||||
tp := string(args[2])
|
||||
tp := strings.ToUpper(string(args[2]))
|
||||
|
||||
count, err := ledis.StrInt64(args[3], nil)
|
||||
if err != nil {
|
||||
|
@ -236,11 +325,9 @@ func xmigratedbCommand(c *client) error {
|
|||
count = 10
|
||||
}
|
||||
|
||||
db, err := ledis.StrUint64(args[4], nil)
|
||||
db, err := parseMigrateDB(c, args[4])
|
||||
if err != nil {
|
||||
return err
|
||||
} else if db >= uint64(c.app.cfg.Databases) {
|
||||
return fmt.Errorf("invalid db index %d, must < %d", db, c.app.cfg.Databases)
|
||||
}
|
||||
|
||||
timeout, err := ledis.StrInt64(args[5], nil)
|
||||
|
@ -250,13 +337,7 @@ func xmigratedbCommand(c *client) error {
|
|||
return fmt.Errorf("invalid timeout %d", timeout)
|
||||
}
|
||||
|
||||
m, err := c.db.Multi()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer m.Close()
|
||||
|
||||
keys, err := xscan(m.DB, tp, int(count))
|
||||
keys, err := xscan(c.db, tp, int(count))
|
||||
if err != nil {
|
||||
return err
|
||||
} else if len(keys) == 0 {
|
||||
|
@ -264,49 +345,41 @@ func xmigratedbCommand(c *client) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
mc := c.app.getMigrateClient(addr)
|
||||
|
||||
conn, err := mc.Get()
|
||||
conn, err := getMigrateDBConn(c, addr, db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
//timeout is milliseconds
|
||||
t := time.Duration(timeout) * time.Millisecond
|
||||
|
||||
if _, err = conn.Do("select", db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
migrateNum := int64(0)
|
||||
for _, key := range keys {
|
||||
data, err := xdump(m.DB, tp, key)
|
||||
err = migrateKey(c, conn, tp, key, timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ttl, err := xttl(m.DB, tp, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn.SetReadDeadline(time.Now().Add(t))
|
||||
|
||||
//ttl is second, but restore need millisecond
|
||||
if _, err = conn.Do("restore", key, ttl*1e3, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = xdel(m.DB, tp, key); err != nil {
|
||||
return err
|
||||
if err == errNoKey || err == errKeyInMigrating {
|
||||
continue
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
migrateNum++
|
||||
}
|
||||
|
||||
c.resp.writeInteger(int64(len(keys)))
|
||||
c.resp.writeInteger(migrateNum)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseMigrateDB(c *client, arg []byte) (uint64, error) {
|
||||
db, err := ledis.StrUint64(arg, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
} else if db >= uint64(c.app.cfg.Databases) {
|
||||
return 0, fmt.Errorf("invalid db index %d, must < %d", db, c.app.cfg.Databases)
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
//XMIGRATE host port type key destination-db timeout
|
||||
//will block any other write operations
|
||||
//maybe only for xcodis
|
||||
|
@ -323,13 +396,11 @@ func xmigrateCommand(c *client) error {
|
|||
return fmt.Errorf("migrate in same server is not allowed")
|
||||
}
|
||||
|
||||
tp := string(args[2])
|
||||
tp := strings.ToUpper(string(args[2]))
|
||||
key := args[3]
|
||||
db, err := ledis.StrUint64(args[4], nil)
|
||||
db, err := parseMigrateDB(c, args[4])
|
||||
if err != nil {
|
||||
return err
|
||||
} else if db >= uint64(c.app.cfg.Databases) {
|
||||
return fmt.Errorf("invalid db index %d, must < %d", db, c.app.cfg.Databases)
|
||||
}
|
||||
|
||||
timeout, err := ledis.StrInt64(args[5], nil)
|
||||
|
@ -339,28 +410,80 @@ func xmigrateCommand(c *client) error {
|
|||
return fmt.Errorf("invalid timeout %d", timeout)
|
||||
}
|
||||
|
||||
m, err := c.db.Multi()
|
||||
conn, err := getMigrateDBConn(c, addr, db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer m.Close()
|
||||
defer conn.Close()
|
||||
|
||||
data, err := xdump(m.DB, tp, key)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if data == nil {
|
||||
c.resp.writeStatus(NOKEY)
|
||||
return nil
|
||||
// if key is in migrating, we will wait 500ms and retry again
|
||||
for i := 0; i < 10; i++ {
|
||||
if tp == "ALL" {
|
||||
// if tp is ALL, we will migrate the key in all types
|
||||
// this feature is useful for xcodis RESTORE or other commands that we don't know the data type exactly
|
||||
err = migrateAllTypeKeys(c, conn, key, timeout)
|
||||
} else {
|
||||
err = migrateKey(c, conn, tp, key, timeout)
|
||||
}
|
||||
|
||||
if err != errKeyInMigrating {
|
||||
break
|
||||
} else {
|
||||
log.Infof("%s key %s is in migrating, wait 500ms and retry", tp, key)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
ttl, err := xttl(m.DB, tp, key)
|
||||
if err != nil {
|
||||
return err
|
||||
if err == errNoKey {
|
||||
c.resp.writeStatus(NOKEY)
|
||||
return nil
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
c.resp.writeStatus(OK)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMigrateDBConn(c *client, addr string, db uint64) (*goredis.PoolConn, error) {
|
||||
mc := c.app.getMigrateClient(addr)
|
||||
|
||||
conn, err := mc.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = conn.Do("select", db); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
var (
|
||||
errNoKey = errors.New("migrate key is not exists")
|
||||
errKeyInMigrating = errors.New("key is in migrating yet")
|
||||
)
|
||||
|
||||
func migrateKey(c *client, conn *goredis.PoolConn, tp string, key []byte, timeout int64) error {
|
||||
if !c.app.migrateKeyLock(tp, key) {
|
||||
// other may also migrate this key, skip it
|
||||
return errKeyInMigrating
|
||||
}
|
||||
|
||||
defer c.app.migrateKeyUnlock(tp, key)
|
||||
|
||||
data, err := xdump(c.db, tp, key)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if data == nil {
|
||||
return errNoKey
|
||||
}
|
||||
|
||||
ttl, err := xttl(c.db, tp, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -368,10 +491,6 @@ func xmigrateCommand(c *client) error {
|
|||
//timeout is milliseconds
|
||||
t := time.Duration(timeout) * time.Millisecond
|
||||
|
||||
if _, err = conn.Do("select", db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn.SetReadDeadline(time.Now().Add(t))
|
||||
|
||||
//ttl is second, but restore need millisecond
|
||||
|
@ -379,11 +498,25 @@ func xmigrateCommand(c *client) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err = xdel(m.DB, tp, key); err != nil {
|
||||
if err = xdel(c.db, tp, key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.resp.writeStatus(OK)
|
||||
return nil
|
||||
}
|
||||
|
||||
func migrateAllTypeKeys(c *client, conn *goredis.PoolConn, key []byte, timeout int64) error {
|
||||
for _, tp := range TypeNames {
|
||||
err := migrateKey(c, conn, tp, key, timeout)
|
||||
if err != nil {
|
||||
if err == errNoKey {
|
||||
continue
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -394,6 +527,7 @@ func init() {
|
|||
register("sdump", sdumpCommand)
|
||||
register("zdump", zdumpCommand)
|
||||
register("restore", restoreCommand)
|
||||
register("xrestore", xrestoreCommand)
|
||||
register("xdump", xdumpCommand)
|
||||
register("xmigrate", xmigrateCommand)
|
||||
register("xmigratedb", xmigratedbCommand)
|
||||
|
|
|
@ -2,7 +2,7 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"github.com/siddontang/ledisdb/config"
|
||||
"os"
|
||||
"testing"
|
||||
|
@ -42,8 +42,8 @@ func TestDumpRestore(t *testing.T) {
|
|||
testDumpRestore(c, "zdump", "mtest_za", t)
|
||||
}
|
||||
|
||||
func testDumpRestore(c *ledis.Conn, dump string, key string, t *testing.T) {
|
||||
if data, err := ledis.Bytes(c.Do(dump, key)); err != nil {
|
||||
func testDumpRestore(c *goredis.PoolConn, dump string, key string, t *testing.T) {
|
||||
if data, err := goredis.Bytes(c.Do(dump, key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if _, err := c.Do("restore", key, 0, data); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -80,10 +80,10 @@ func TestMigrate(t *testing.T) {
|
|||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
c1, _ := ledis.Connect(s1Cfg.Addr)
|
||||
c1, _ := goredis.Connect(s1Cfg.Addr)
|
||||
defer c1.Close()
|
||||
|
||||
c2, _ := ledis.Connect(s2Cfg.Addr)
|
||||
c2, _ := goredis.Connect(s2Cfg.Addr)
|
||||
defer c2.Close()
|
||||
|
||||
if _, err = c1.Do("set", "a", "1"); err != nil {
|
||||
|
@ -95,34 +95,49 @@ func TestMigrate(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if s, err := ledis.String(c2.Do("get", "a")); err != nil {
|
||||
if s, err := goredis.String(c2.Do("get", "a")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if s != "1" {
|
||||
t.Fatal(s, "must 1")
|
||||
}
|
||||
|
||||
if s, err := ledis.String(c1.Do("get", "a")); err != nil && err != ledis.ErrNil {
|
||||
if s, err := goredis.String(c1.Do("get", "a")); err != nil && err != goredis.ErrNil {
|
||||
t.Fatal(err)
|
||||
} else if s != "" {
|
||||
t.Fatal(s, "must empty")
|
||||
}
|
||||
|
||||
if num, err := ledis.Int(c2.Do("xmigratedb", "127.0.0.1", 11185, "KV", 10, 0, timeout)); err != nil {
|
||||
if num, err := goredis.Int(c2.Do("xmigratedb", "127.0.0.1", 11185, "KV", 10, 0, timeout)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if num != 1 {
|
||||
t.Fatal(num, "must number 1")
|
||||
}
|
||||
|
||||
if s, err := ledis.String(c1.Do("get", "a")); err != nil {
|
||||
if s, err := goredis.String(c1.Do("get", "a")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if s != "1" {
|
||||
t.Fatal(s, "must 1")
|
||||
}
|
||||
|
||||
if s, err := ledis.String(c2.Do("get", "a")); err != nil && err != ledis.ErrNil {
|
||||
if s, err := goredis.String(c2.Do("get", "a")); err != nil && err != goredis.ErrNil {
|
||||
t.Fatal(err)
|
||||
} else if s != "" {
|
||||
t.Fatal(s, "must empty")
|
||||
}
|
||||
|
||||
if _, err = c1.Do("xmigrate", "127.0.0.1", 11186, "ALL", "a", 0, timeout); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if s, err := goredis.String(c2.Do("get", "a")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if s != "1" {
|
||||
t.Fatal(s, "must 1")
|
||||
}
|
||||
|
||||
if s, err := goredis.String(c1.Do("get", "a")); err != nil && err != goredis.ErrNil {
|
||||
t.Fatal(err)
|
||||
} else if s != "" {
|
||||
t.Fatal(s, "must empty")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
goledis "github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"github.com/siddontang/ledisdb/config"
|
||||
"os"
|
||||
"reflect"
|
||||
|
@ -159,9 +159,9 @@ func TestReplication(t *testing.T) {
|
|||
}
|
||||
|
||||
func checkTestRole(addr string, checkRoles []interface{}) error {
|
||||
conn, _ := goledis.Connect(addr)
|
||||
conn, _ := goredis.Connect(addr)
|
||||
defer conn.Close()
|
||||
roles, err := goledis.MultiBulk(conn.Do("ROLE"))
|
||||
roles, err := goredis.MultiBulk(conn.Do("ROLE"))
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !reflect.DeepEqual(roles, checkRoles) {
|
||||
|
|
|
@ -9,13 +9,15 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func parseScanArgs(args [][]byte) (cursor []byte, match string, count int, err error) {
|
||||
func parseScanArgs(args [][]byte) (cursor []byte, match string, count int, desc bool, err error) {
|
||||
cursor = args[0]
|
||||
|
||||
args = args[1:]
|
||||
|
||||
count = 10
|
||||
|
||||
desc = false
|
||||
|
||||
for i := 0; i < len(args); {
|
||||
switch strings.ToUpper(hack.String(args[i])) {
|
||||
case "MATCH":
|
||||
|
@ -25,7 +27,7 @@ func parseScanArgs(args [][]byte) (cursor []byte, match string, count int, err e
|
|||
}
|
||||
|
||||
match = hack.String(args[i+1])
|
||||
i = i + 2
|
||||
i++
|
||||
case "COUNT":
|
||||
if i+1 >= len(args) {
|
||||
err = ErrCmdParams
|
||||
|
@ -37,17 +39,23 @@ func parseScanArgs(args [][]byte) (cursor []byte, match string, count int, err e
|
|||
return
|
||||
}
|
||||
|
||||
i = i + 2
|
||||
i++
|
||||
case "ASC":
|
||||
desc = false
|
||||
case "DESC":
|
||||
desc = true
|
||||
default:
|
||||
err = fmt.Errorf("invalid argument %s", args[i])
|
||||
return
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// XSCAN type cursor [MATCH match] [COUNT count]
|
||||
// XSCAN type cursor [MATCH match] [COUNT count] [ASC|DESC]
|
||||
func xscanCommand(c *client) error {
|
||||
args := c.args
|
||||
|
||||
|
@ -71,13 +79,20 @@ func xscanCommand(c *client) error {
|
|||
return fmt.Errorf("invalid key type %s", args[0])
|
||||
}
|
||||
|
||||
cursor, match, count, err := parseScanArgs(args[1:])
|
||||
cursor, match, count, desc, err := parseScanArgs(args[1:])
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ay, err := c.db.Scan(dataType, cursor, count, false, match)
|
||||
var ay [][]byte
|
||||
|
||||
if !desc {
|
||||
ay, err = c.db.Scan(dataType, cursor, count, false, match)
|
||||
} else {
|
||||
ay, err = c.db.RevScan(dataType, cursor, count, false, match)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -93,7 +108,7 @@ func xscanCommand(c *client) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// XHSCAN key cursor [MATCH match] [COUNT count]
|
||||
// XHSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]
|
||||
func xhscanCommand(c *client) error {
|
||||
args := c.args
|
||||
|
||||
|
@ -103,13 +118,20 @@ func xhscanCommand(c *client) error {
|
|||
|
||||
key := args[0]
|
||||
|
||||
cursor, match, count, err := parseScanArgs(args[1:])
|
||||
cursor, match, count, desc, err := parseScanArgs(args[1:])
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ay, err := c.db.HScan(key, cursor, count, false, match)
|
||||
var ay []ledis.FVPair
|
||||
|
||||
if !desc {
|
||||
ay, err = c.db.HScan(key, cursor, count, false, match)
|
||||
} else {
|
||||
ay, err = c.db.HRevScan(key, cursor, count, false, match)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -133,7 +155,7 @@ func xhscanCommand(c *client) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// XSSCAN key cursor [MATCH match] [COUNT count]
|
||||
// XSSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]
|
||||
func xsscanCommand(c *client) error {
|
||||
args := c.args
|
||||
|
||||
|
@ -143,13 +165,20 @@ func xsscanCommand(c *client) error {
|
|||
|
||||
key := args[0]
|
||||
|
||||
cursor, match, count, err := parseScanArgs(args[1:])
|
||||
cursor, match, count, desc, err := parseScanArgs(args[1:])
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ay, err := c.db.SScan(key, cursor, count, false, match)
|
||||
var ay [][]byte
|
||||
|
||||
if !desc {
|
||||
ay, err = c.db.SScan(key, cursor, count, false, match)
|
||||
} else {
|
||||
ay, err = c.db.SRevScan(key, cursor, count, false, match)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -167,7 +196,7 @@ func xsscanCommand(c *client) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// XZSCAN key cursor [MATCH match] [COUNT count]
|
||||
// XZSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]
|
||||
func xzscanCommand(c *client) error {
|
||||
args := c.args
|
||||
|
||||
|
@ -177,13 +206,20 @@ func xzscanCommand(c *client) error {
|
|||
|
||||
key := args[0]
|
||||
|
||||
cursor, match, count, err := parseScanArgs(args[1:])
|
||||
cursor, match, count, desc, err := parseScanArgs(args[1:])
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ay, err := c.db.ZScan(key, cursor, count, false, match)
|
||||
var ay []ledis.ScorePair
|
||||
|
||||
if !desc {
|
||||
ay, err = c.db.ZScan(key, cursor, count, false, match)
|
||||
} else {
|
||||
ay, err = c.db.ZRevScan(key, cursor, count, false, match)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"github.com/siddontang/ledisdb/config"
|
||||
"os"
|
||||
"testing"
|
||||
|
@ -22,10 +22,8 @@ func TestScan(t *testing.T) {
|
|||
go s.Run()
|
||||
defer s.Close()
|
||||
|
||||
cc := new(ledis.Config)
|
||||
cc.Addr = cfg.Addr
|
||||
cc.MaxIdleConns = 1
|
||||
c := ledis.NewClient(cc)
|
||||
c := goredis.NewClient(cfg.Addr, "")
|
||||
c.SetMaxIdleConns(1)
|
||||
defer c.Close()
|
||||
|
||||
testKVScan(t, c)
|
||||
|
@ -37,7 +35,7 @@ func TestScan(t *testing.T) {
|
|||
}
|
||||
|
||||
func checkScanValues(t *testing.T, ay interface{}, values ...interface{}) {
|
||||
a, err := ledis.Strings(ay, nil)
|
||||
a, err := goredis.Strings(ay, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -53,8 +51,8 @@ func checkScanValues(t *testing.T, ay interface{}, values ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func checkScan(t *testing.T, c *ledis.Client, tp string) {
|
||||
if ay, err := ledis.Values(c.Do("XSCAN", tp, "", "count", 5)); err != nil {
|
||||
func checkScan(t *testing.T, c *goredis.Client, tp string) {
|
||||
if ay, err := goredis.Values(c.Do("XSCAN", tp, "", "count", 5)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(ay) != 2 {
|
||||
t.Fatal(len(ay))
|
||||
|
@ -64,7 +62,7 @@ func checkScan(t *testing.T, c *ledis.Client, tp string) {
|
|||
checkScanValues(t, ay[1], 0, 1, 2, 3, 4)
|
||||
}
|
||||
|
||||
if ay, err := ledis.Values(c.Do("XSCAN", tp, "4", "count", 6)); err != nil {
|
||||
if ay, err := goredis.Values(c.Do("XSCAN", tp, "4", "count", 6)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(ay) != 2 {
|
||||
t.Fatal(len(ay))
|
||||
|
@ -76,7 +74,7 @@ func checkScan(t *testing.T, c *ledis.Client, tp string) {
|
|||
|
||||
}
|
||||
|
||||
func testKVScan(t *testing.T, c *ledis.Client) {
|
||||
func testKVScan(t *testing.T, c *goredis.Client) {
|
||||
for i := 0; i < 10; i++ {
|
||||
if _, err := c.Do("set", fmt.Sprintf("%d", i), []byte("value")); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -86,7 +84,7 @@ func testKVScan(t *testing.T, c *ledis.Client) {
|
|||
checkScan(t, c, "KV")
|
||||
}
|
||||
|
||||
func testHashKeyScan(t *testing.T, c *ledis.Client) {
|
||||
func testHashKeyScan(t *testing.T, c *goredis.Client) {
|
||||
for i := 0; i < 10; i++ {
|
||||
if _, err := c.Do("hset", fmt.Sprintf("%d", i), fmt.Sprintf("%d", i), []byte("value")); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -96,7 +94,7 @@ func testHashKeyScan(t *testing.T, c *ledis.Client) {
|
|||
checkScan(t, c, "HASH")
|
||||
}
|
||||
|
||||
func testListKeyScan(t *testing.T, c *ledis.Client) {
|
||||
func testListKeyScan(t *testing.T, c *goredis.Client) {
|
||||
for i := 0; i < 10; i++ {
|
||||
if _, err := c.Do("lpush", fmt.Sprintf("%d", i), fmt.Sprintf("%d", i)); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -106,7 +104,7 @@ func testListKeyScan(t *testing.T, c *ledis.Client) {
|
|||
checkScan(t, c, "LIST")
|
||||
}
|
||||
|
||||
func testZSetKeyScan(t *testing.T, c *ledis.Client) {
|
||||
func testZSetKeyScan(t *testing.T, c *goredis.Client) {
|
||||
for i := 0; i < 10; i++ {
|
||||
if _, err := c.Do("zadd", fmt.Sprintf("%d", i), i, []byte("value")); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -116,7 +114,7 @@ func testZSetKeyScan(t *testing.T, c *ledis.Client) {
|
|||
checkScan(t, c, "ZSET")
|
||||
}
|
||||
|
||||
func testSetKeyScan(t *testing.T, c *ledis.Client) {
|
||||
func testSetKeyScan(t *testing.T, c *goredis.Client) {
|
||||
for i := 0; i < 10; i++ {
|
||||
if _, err := c.Do("sadd", fmt.Sprintf("%d", i), fmt.Sprintf("%d", i)); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -133,7 +131,7 @@ func TestHashScan(t *testing.T) {
|
|||
key := "scan_hash"
|
||||
c.Do("HMSET", key, "a", 1, "b", 2)
|
||||
|
||||
if ay, err := ledis.Values(c.Do("XHSCAN", key, "")); err != nil {
|
||||
if ay, err := goredis.Values(c.Do("XHSCAN", key, "")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(ay) != 2 {
|
||||
t.Fatal(len(ay))
|
||||
|
@ -149,7 +147,7 @@ func TestSetScan(t *testing.T) {
|
|||
key := "scan_set"
|
||||
c.Do("SADD", key, "a", "b")
|
||||
|
||||
if ay, err := ledis.Values(c.Do("XSSCAN", key, "")); err != nil {
|
||||
if ay, err := goredis.Values(c.Do("XSSCAN", key, "")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(ay) != 2 {
|
||||
t.Fatal(len(ay))
|
||||
|
@ -166,7 +164,7 @@ func TestZSetScan(t *testing.T) {
|
|||
key := "scan_zset"
|
||||
c.Do("ZADD", key, 1, "a", 2, "b")
|
||||
|
||||
if ay, err := ledis.Values(c.Do("XZSCAN", key, "")); err != nil {
|
||||
if ay, err := goredis.Values(c.Do("XZSCAN", key, "")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(ay) != 2 {
|
||||
t.Fatal(len(ay))
|
||||
|
|
|
@ -4,7 +4,7 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
@ -13,13 +13,13 @@ func TestCmdEval(t *testing.T) {
|
|||
c := getTestConn()
|
||||
defer c.Close()
|
||||
|
||||
if v, err := ledis.Strings(c.Do("eval", "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "key1", "key2", "first", "second")); err != nil {
|
||||
if v, err := goredis.Strings(c.Do("eval", "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "key1", "key2", "first", "second")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(v, []string{"key1", "key2", "first", "second"}) {
|
||||
t.Fatal(fmt.Sprintf("%v", v))
|
||||
}
|
||||
|
||||
if v, err := ledis.Strings(c.Do("eval", "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "key1", "key2", "first", "second")); err != nil {
|
||||
if v, err := goredis.Strings(c.Do("eval", "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "key1", "key2", "first", "second")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(v, []string{"key1", "key2", "first", "second"}) {
|
||||
t.Fatal(fmt.Sprintf("%v", v))
|
||||
|
@ -27,31 +27,31 @@ func TestCmdEval(t *testing.T) {
|
|||
|
||||
var sha1 string
|
||||
var err error
|
||||
if sha1, err = ledis.String(c.Do("script", "load", "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}")); err != nil {
|
||||
if sha1, err = goredis.String(c.Do("script", "load", "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(sha1) != 40 {
|
||||
t.Fatal(sha1)
|
||||
}
|
||||
|
||||
if v, err := ledis.Strings(c.Do("evalsha", sha1, 2, "key1", "key2", "first", "second")); err != nil {
|
||||
if v, err := goredis.Strings(c.Do("evalsha", sha1, 2, "key1", "key2", "first", "second")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(v, []string{"key1", "key2", "first", "second"}) {
|
||||
t.Fatal(fmt.Sprintf("%v", v))
|
||||
}
|
||||
|
||||
if ay, err := ledis.Values(c.Do("script", "exists", sha1, "01234567890123456789")); err != nil {
|
||||
if ay, err := goredis.Values(c.Do("script", "exists", sha1, "01234567890123456789")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(ay, []interface{}{int64(1), int64(0)}) {
|
||||
t.Fatal(fmt.Sprintf("%v", ay))
|
||||
}
|
||||
|
||||
if ok, err := ledis.String(c.Do("script", "flush")); err != nil {
|
||||
if ok, err := goredis.String(c.Do("script", "flush")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if ok != "OK" {
|
||||
t.Fatal(ok)
|
||||
}
|
||||
|
||||
if ay, err := ledis.Values(c.Do("script", "exists", sha1)); err != nil {
|
||||
if ay, err := goredis.Values(c.Do("script", "exists", sha1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(ay, []interface{}{int64(0)}) {
|
||||
t.Fatal(fmt.Sprintf("%v", ay))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -12,91 +12,91 @@ func TestSet(t *testing.T) {
|
|||
key1 := "testdb_cmd_set_1"
|
||||
key2 := "testdb_cmd_set_2"
|
||||
|
||||
if n, err := ledis.Int(c.Do("skeyexists", key1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("skeyexists", key1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("sadd", key1, 0, 1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("sadd", key1, 0, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("skeyexists", key1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("skeyexists", key1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("sadd", key2, 0, 1, 2, 3)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("sadd", key2, 0, 1, 2, 3)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 4 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("scard", key1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("scard", key1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.MultiBulk(c.Do("sdiff", key2, key1)); err != nil {
|
||||
if n, err := goredis.MultiBulk(c.Do("sdiff", key2, key1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(n) != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("sdiffstore", []byte("cmd_set_em1"), key2, key1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("sdiffstore", []byte("cmd_set_em1"), key2, key1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.MultiBulk(c.Do("sunion", key1, key2)); err != nil {
|
||||
if n, err := goredis.MultiBulk(c.Do("sunion", key1, key2)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(n) != 4 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("sunionstore", []byte("cmd_set_em2"), key1, key2)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("sunionstore", []byte("cmd_set_em2"), key1, key2)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 4 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.MultiBulk(c.Do("sinter", key1, key2)); err != nil {
|
||||
if n, err := goredis.MultiBulk(c.Do("sinter", key1, key2)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(n) != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("sinterstore", []byte("cmd_set_em3"), key1, key2)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("sinterstore", []byte("cmd_set_em3"), key1, key2)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("srem", key1, 0, 1)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("srem", key1, 0, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("sismember", key2, 0)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("sismember", key2, 0)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.MultiBulk(c.Do("smembers", key2)); err != nil {
|
||||
if n, err := goredis.MultiBulk(c.Do("smembers", key2)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(n) != 4 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("sclear", key2)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("sclear", key2)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 4 {
|
||||
t.Fatal(n)
|
||||
|
@ -104,7 +104,7 @@ func TestSet(t *testing.T) {
|
|||
|
||||
c.Do("sadd", key1, 0)
|
||||
c.Do("sadd", key2, 1)
|
||||
if n, err := ledis.Int(c.Do("smclear", key1, key2)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("smclear", key1, key2)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
|
|
|
@ -2,7 +2,7 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
goledis "github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -79,7 +79,7 @@ func TestSort(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n, err := goledis.Int(c.Do("XLSORT", key, "STORE", storeKey)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("XLSORT", key, "STORE", storeKey)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 3 {
|
||||
t.Fatalf("invalid return store sort number, %d != 3", n)
|
||||
|
|
|
@ -2,7 +2,7 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
@ -63,13 +63,13 @@ func TestExpire(t *testing.T) {
|
|||
}
|
||||
// expire + ttl
|
||||
exp := int64(10)
|
||||
if n, err := ledis.Int(c.Do(expire, key, exp)); err != nil {
|
||||
if n, err := goredis.Int(c.Do(expire, key, exp)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if ttl, err := ledis.Int64(c.Do(ttl, key)); err != nil {
|
||||
if ttl, err := goredis.Int64(c.Do(ttl, key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if ttl == -1 {
|
||||
t.Fatal("no ttl")
|
||||
|
@ -77,13 +77,13 @@ func TestExpire(t *testing.T) {
|
|||
|
||||
// expireat + ttl
|
||||
tm := now() + 3
|
||||
if n, err := ledis.Int(c.Do(expireat, key, tm)); err != nil {
|
||||
if n, err := goredis.Int(c.Do(expireat, key, tm)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if ttl, err := ledis.Int64(c.Do(ttl, key)); err != nil {
|
||||
if ttl, err := goredis.Int64(c.Do(ttl, key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if ttl == -1 {
|
||||
t.Fatal("no ttl")
|
||||
|
@ -92,31 +92,31 @@ func TestExpire(t *testing.T) {
|
|||
kErr := "not_exist_ttl"
|
||||
|
||||
// err - expire, expireat
|
||||
if n, err := ledis.Int(c.Do(expire, kErr, tm)); err != nil || n != 0 {
|
||||
if n, err := goredis.Int(c.Do(expire, kErr, tm)); err != nil || n != 0 {
|
||||
t.Fatal(false)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do(expireat, kErr, tm)); err != nil || n != 0 {
|
||||
if n, err := goredis.Int(c.Do(expireat, kErr, tm)); err != nil || n != 0 {
|
||||
t.Fatal(false)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do(ttl, kErr)); err != nil || n != -1 {
|
||||
if n, err := goredis.Int(c.Do(ttl, kErr)); err != nil || n != -1 {
|
||||
t.Fatal(false)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do(persist, key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do(persist, key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do(expire, key, 10)); err != nil {
|
||||
if n, err := goredis.Int(c.Do(expire, key, 10)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do(persist, key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do(persist, key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
|
|
|
@ -2,7 +2,7 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
@ -14,103 +14,103 @@ func TestZSet(t *testing.T) {
|
|||
|
||||
key := []byte("myzset")
|
||||
|
||||
if n, err := ledis.Int(c.Do("zkeyexists", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zkeyexists", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zadd", key, 3, "a", 4, "b")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zadd", key, 3, "a", 4, "b")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zkeyexists", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zkeyexists", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcard", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcard", key)); err != nil {
|
||||
t.Fatal(n)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zadd", key, 1, "a", 2, "b")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zadd", key, 1, "a", 2, "b")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcard", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcard", key)); err != nil {
|
||||
t.Fatal(n)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zadd", key, 3, "c", 4, "d")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zadd", key, 3, "c", 4, "d")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcard", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcard", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 4 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if s, err := ledis.Int(c.Do("zscore", key, "c")); err != nil {
|
||||
if s, err := goredis.Int(c.Do("zscore", key, "c")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if s != 3 {
|
||||
t.Fatal(s)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zrem", key, "d", "e")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zrem", key, "d", "e")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcard", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcard", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 3 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zincrby", key, 4, "c")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zincrby", key, 4, "c")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 7 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zincrby", key, -4, "c")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zincrby", key, -4, "c")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 3 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zincrby", key, 4, "d")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zincrby", key, 4, "d")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 4 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcard", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcard", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 4 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zrem", key, "a", "b", "c", "d")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zrem", key, "a", "b", "c", "d")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 4 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcard", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcard", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
|
@ -123,47 +123,47 @@ func TestZSetCount(t *testing.T) {
|
|||
defer c.Close()
|
||||
|
||||
key := []byte("myzset")
|
||||
if _, err := ledis.Int(c.Do("zadd", key, 1, "a", 2, "b", 3, "c", 4, "d")); err != nil {
|
||||
if _, err := goredis.Int(c.Do("zadd", key, 1, "a", 2, "b", 3, "c", 4, "d")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcount", key, 2, 4)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcount", key, 2, 4)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 3 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcount", key, 4, 4)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcount", key, 4, 4)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcount", key, 4, 3)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcount", key, 4, 3)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcount", key, "(2", 4)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcount", key, "(2", 4)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcount", key, "2", "(4")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcount", key, "2", "(4")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcount", key, "(2", "(4")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcount", key, "(2", "(4")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcount", key, "-inf", "+inf")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcount", key, "-inf", "+inf")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 4 {
|
||||
t.Fatal(n)
|
||||
|
@ -171,7 +171,7 @@ func TestZSetCount(t *testing.T) {
|
|||
|
||||
c.Do("zadd", key, 3, "e")
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcount", key, "(2", "(4")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcount", key, "(2", "(4")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
|
@ -185,27 +185,27 @@ func TestZSetRank(t *testing.T) {
|
|||
defer c.Close()
|
||||
|
||||
key := []byte("myzset")
|
||||
if _, err := ledis.Int(c.Do("zadd", key, 1, "a", 2, "b", 3, "c", 4, "d")); err != nil {
|
||||
if _, err := goredis.Int(c.Do("zadd", key, 1, "a", 2, "b", 3, "c", 4, "d")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zrank", key, "c")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zrank", key, "c")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if _, err := ledis.Int(c.Do("zrank", key, "e")); err != ledis.ErrNil {
|
||||
if _, err := goredis.Int(c.Do("zrank", key, "e")); err != goredis.ErrNil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zrevrank", key, "c")); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zrevrank", key, "c")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 1 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if _, err := ledis.Int(c.Do("zrevrank", key, "e")); err != ledis.ErrNil {
|
||||
if _, err := goredis.Int(c.Do("zrevrank", key, "e")); err != goredis.ErrNil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -242,11 +242,11 @@ func TestZSetRangeScore(t *testing.T) {
|
|||
defer c.Close()
|
||||
|
||||
key := []byte("myzset_range")
|
||||
if _, err := ledis.Int(c.Do("zadd", key, 1, "a", 2, "b", 3, "c", 4, "d")); err != nil {
|
||||
if _, err := goredis.Int(c.Do("zadd", key, 1, "a", 2, "b", 3, "c", 4, "d")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrangebyscore", key, 1, 4, "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrangebyscore", key, 1, 4, "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "a", 1, "b", 2, "c", 3, "d", 4); err != nil {
|
||||
|
@ -254,7 +254,7 @@ func TestZSetRangeScore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrangebyscore", key, 1, 4, "withscores", "limit", 1, 2)); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrangebyscore", key, 1, 4, "withscores", "limit", 1, 2)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "b", 2, "c", 3); err != nil {
|
||||
|
@ -262,7 +262,7 @@ func TestZSetRangeScore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrangebyscore", key, "-inf", "+inf", "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrangebyscore", key, "-inf", "+inf", "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "a", 1, "b", 2, "c", 3, "d", 4); err != nil {
|
||||
|
@ -270,7 +270,7 @@ func TestZSetRangeScore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrangebyscore", key, "(1", "(4")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrangebyscore", key, "(1", "(4")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "b", "c"); err != nil {
|
||||
|
@ -278,7 +278,7 @@ func TestZSetRangeScore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrevrangebyscore", key, 4, 1, "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrevrangebyscore", key, 4, 1, "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "d", 4, "c", 3, "b", 2, "a", 1); err != nil {
|
||||
|
@ -286,7 +286,7 @@ func TestZSetRangeScore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrevrangebyscore", key, 4, 1, "withscores", "limit", 1, 2)); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrevrangebyscore", key, 4, 1, "withscores", "limit", 1, 2)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "c", 3, "b", 2); err != nil {
|
||||
|
@ -294,7 +294,7 @@ func TestZSetRangeScore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrevrangebyscore", key, "+inf", "-inf", "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrevrangebyscore", key, "+inf", "-inf", "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "d", 4, "c", 3, "b", 2, "a", 1); err != nil {
|
||||
|
@ -302,7 +302,7 @@ func TestZSetRangeScore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrevrangebyscore", key, "(4", "(1")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrevrangebyscore", key, "(4", "(1")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "c", "b"); err != nil {
|
||||
|
@ -310,19 +310,19 @@ func TestZSetRangeScore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zremrangebyscore", key, 2, 3)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zremrangebyscore", key, 2, 3)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcard", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcard", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrangebyscore", key, 1, 4)); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrangebyscore", key, 1, 4)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "a", "d"); err != nil {
|
||||
|
@ -336,11 +336,11 @@ func TestZSetRange(t *testing.T) {
|
|||
defer c.Close()
|
||||
|
||||
key := []byte("myzset_range_rank")
|
||||
if _, err := ledis.Int(c.Do("zadd", key, 1, "a", 2, "b", 3, "c", 4, "d")); err != nil {
|
||||
if _, err := goredis.Int(c.Do("zadd", key, 1, "a", 2, "b", 3, "c", 4, "d")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrange", key, 0, 3, "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrange", key, 0, 3, "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "a", 1, "b", 2, "c", 3, "d", 4); err != nil {
|
||||
|
@ -348,7 +348,7 @@ func TestZSetRange(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrange", key, 1, 4, "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrange", key, 1, 4, "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "b", 2, "c", 3, "d", 4); err != nil {
|
||||
|
@ -356,7 +356,7 @@ func TestZSetRange(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrange", key, -2, -1, "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrange", key, -2, -1, "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "c", 3, "d", 4); err != nil {
|
||||
|
@ -364,7 +364,7 @@ func TestZSetRange(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrange", key, 0, -1, "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrange", key, 0, -1, "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "a", 1, "b", 2, "c", 3, "d", 4); err != nil {
|
||||
|
@ -372,13 +372,13 @@ func TestZSetRange(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrange", key, -1, -2, "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrange", key, -1, -2, "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(v) != 0 {
|
||||
t.Fatal(len(v))
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrevrange", key, 0, 4, "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrevrange", key, 0, 4, "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "d", 4, "c", 3, "b", 2, "a", 1); err != nil {
|
||||
|
@ -386,7 +386,7 @@ func TestZSetRange(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrevrange", key, 0, -1, "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrevrange", key, 0, -1, "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "d", 4, "c", 3, "b", 2, "a", 1); err != nil {
|
||||
|
@ -394,7 +394,7 @@ func TestZSetRange(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrevrange", key, 2, 3, "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrevrange", key, 2, 3, "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "b", 2, "a", 1); err != nil {
|
||||
|
@ -402,7 +402,7 @@ func TestZSetRange(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrevrange", key, -2, -1, "withscores")); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrevrange", key, -2, -1, "withscores")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "b", 2, "a", 1); err != nil {
|
||||
|
@ -410,19 +410,19 @@ func TestZSetRange(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zremrangebyrank", key, 2, 3)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zremrangebyrank", key, 2, 3)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcard", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcard", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if v, err := ledis.MultiBulk(c.Do("zrange", key, 0, 4)); err != nil {
|
||||
if v, err := goredis.MultiBulk(c.Do("zrange", key, 0, 4)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if err := testZSetRange(v, "a", "b"); err != nil {
|
||||
|
@ -430,13 +430,13 @@ func TestZSetRange(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zclear", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zclear", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int(c.Do("zcard", key)); err != nil {
|
||||
if n, err := goredis.Int(c.Do("zcard", key)); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 0 {
|
||||
t.Fatal(n)
|
||||
|
@ -634,7 +634,7 @@ func TestZUnionStore(t *testing.T) {
|
|||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zunionstore", "out", "2", "k1", "k2", "weights", "1", "2")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zunionstore", "out", "2", "k1", "k2", "weights", "1", "2")); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
if n != 3 {
|
||||
|
@ -642,7 +642,7 @@ func TestZUnionStore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zunionstore", "out", "2", "k1", "k2", "weights", "1", "2", "aggregate", "min")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zunionstore", "out", "2", "k1", "k2", "weights", "1", "2", "aggregate", "min")); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
if n != 3 {
|
||||
|
@ -650,7 +650,7 @@ func TestZUnionStore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zunionstore", "out", "2", "k1", "k2", "aggregate", "max")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zunionstore", "out", "2", "k1", "k2", "aggregate", "max")); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
if n != 3 {
|
||||
|
@ -658,7 +658,7 @@ func TestZUnionStore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zscore", "out", "two")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zscore", "out", "two")); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
if n != 2 {
|
||||
|
@ -687,7 +687,7 @@ func TestZInterStore(t *testing.T) {
|
|||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zinterstore", "out", "2", "k1", "k2", "weights", "1", "2")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zinterstore", "out", "2", "k1", "k2", "weights", "1", "2")); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
if n != 1 {
|
||||
|
@ -695,7 +695,7 @@ func TestZInterStore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zinterstore", "out", "2", "k1", "k2", "aggregate", "min", "weights", "1", "2")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zinterstore", "out", "2", "k1", "k2", "aggregate", "min", "weights", "1", "2")); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
if n != 1 {
|
||||
|
@ -703,7 +703,7 @@ func TestZInterStore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zinterstore", "out", "2", "k1", "k2", "aggregate", "sum")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zinterstore", "out", "2", "k1", "k2", "aggregate", "sum")); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
if n != 1 {
|
||||
|
@ -711,7 +711,7 @@ func TestZInterStore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zscore", "out", "two")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zscore", "out", "two")); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
if n != 3 {
|
||||
|
@ -723,7 +723,7 @@ func TestZInterStore(t *testing.T) {
|
|||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zinterstore", "out", "3", "k1", "k2", "k3", "aggregate", "sum")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zinterstore", "out", "3", "k1", "k2", "k3", "aggregate", "sum")); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
if n != 0 {
|
||||
|
@ -735,7 +735,7 @@ func TestZInterStore(t *testing.T) {
|
|||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zinterstore", "out", "3", "k1", "k2", "k3", "aggregate", "sum", "weights", "3", "2", "2")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zinterstore", "out", "3", "k1", "k2", "k3", "aggregate", "sum", "weights", "3", "2", "2")); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
if n != 1 {
|
||||
|
@ -743,7 +743,7 @@ func TestZInterStore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zscore", "out", "two")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zscore", "out", "two")); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
if n != 14 {
|
||||
|
@ -762,37 +762,37 @@ func TestZSetLex(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ay, err := ledis.Strings(c.Do("zrangebylex", key, "-", "[c")); err != nil {
|
||||
if ay, err := goredis.Strings(c.Do("zrangebylex", key, "-", "[c")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(ay, []string{"a", "b", "c"}) {
|
||||
t.Fatal("must equal")
|
||||
}
|
||||
|
||||
if ay, err := ledis.Strings(c.Do("zrangebylex", key, "-", "(c")); err != nil {
|
||||
if ay, err := goredis.Strings(c.Do("zrangebylex", key, "-", "(c")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(ay, []string{"a", "b"}) {
|
||||
t.Fatal("must equal")
|
||||
}
|
||||
|
||||
if ay, err := ledis.Strings(c.Do("zrangebylex", key, "[aaa", "(g")); err != nil {
|
||||
if ay, err := goredis.Strings(c.Do("zrangebylex", key, "[aaa", "(g")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(ay, []string{"b", "c", "d", "e", "f"}) {
|
||||
t.Fatal("must equal")
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zlexcount", key, "-", "(c")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zlexcount", key, "-", "(c")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zremrangebylex", key, "[aaa", "(g")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zremrangebylex", key, "[aaa", "(g")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 5 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if n, err := ledis.Int64(c.Do("zlexcount", key, "-", "+")); err != nil {
|
||||
if n, err := goredis.Int64(c.Do("zlexcount", key, "-", "+")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n != 2 {
|
||||
t.Fatal(n)
|
||||
|
|
|
@ -34,8 +34,18 @@ const (
|
|||
ZSET = ledis.ZSET
|
||||
)
|
||||
|
||||
const (
|
||||
KVName = ledis.KVName
|
||||
ListName = ledis.ListName
|
||||
HashName = ledis.HashName
|
||||
SetName = ledis.SetName
|
||||
ZSetName = ledis.ZSetName
|
||||
)
|
||||
|
||||
const (
|
||||
GB uint64 = 1024 * 1024 * 1024
|
||||
MB uint64 = 1024 * 1024
|
||||
KB uint64 = 1024
|
||||
)
|
||||
|
||||
var TypeNames = []string{KVName, ListName, HashName, SetName, ZSetName}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/siddontang/go/log"
|
||||
"github.com/siddontang/go/num"
|
||||
"github.com/siddontang/go/sync2"
|
||||
goledis "github.com/siddontang/ledisdb/client/goledis"
|
||||
"github.com/siddontang/goredis"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
"github.com/siddontang/ledisdb/rpl"
|
||||
"net"
|
||||
|
@ -49,7 +49,7 @@ type master struct {
|
|||
sync.Mutex
|
||||
|
||||
connLock sync.Mutex
|
||||
conn *goledis.Conn
|
||||
conn *goredis.Conn
|
||||
|
||||
app *App
|
||||
|
||||
|
@ -108,7 +108,7 @@ func (m *master) checkConn() error {
|
|||
|
||||
var err error
|
||||
if m.conn == nil {
|
||||
m.conn, err = goledis.Connect(m.addr)
|
||||
m.conn, err = goredis.Connect(m.addr)
|
||||
} else {
|
||||
if _, err = m.conn.Do("PING"); err != nil {
|
||||
m.conn.Close()
|
||||
|
@ -227,7 +227,7 @@ func (m *master) replConf() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if s, err := goledis.String(m.conn.Do("replconf", "listening-port", port)); err != nil {
|
||||
if s, err := goredis.String(m.conn.Do("replconf", "listening-port", port)); err != nil {
|
||||
return err
|
||||
} else if strings.ToUpper(s) != "OK" {
|
||||
return fmt.Errorf("not ok but %s", s)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !windows
|
||||
// +build lmdb
|
||||
|
||||
package mdb
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !windows
|
||||
// +build lmdb
|
||||
|
||||
package mdb
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !windows
|
||||
// +build lmdb
|
||||
|
||||
package mdb
|
||||
|
||||
|
|
Loading…
Reference in New Issue